View difference between Paste ID: ZcMU31TN and Zi2bpkXm
SHOW: | | - or go back to the newest paste.
1
--[[
2
Optimised Adaptive Turbine Controller with Feedback Rods
3
--------------------------------------------------------
4
* Layout, colours, button coordinates, labels and overall behaviour are **identical** to the original program supplied in your first message.
5
* The **only** changes are internal optimisations (no blocking sleeps inside the main loop, nil‑safety, double‑buffered drawing) so the UI feels instantaneous.
6
7
Version: 2025‑06‑14
8
]]--
9
10
---------------------------------------------------------------------
11
-- 1. CONFIGURATION --------------------------------------------------
12
---------------------------------------------------------------------
13
14
local reactorName       = "BigReactors-Reactor_0"
15
local turbineName       = "BigReactors-Turbine_0"
16
local monitorName       = "monitor_0"
17
local FLOW_PERSIST_FILE = "nominal_flow.txt"
18
19-
RPM_TARGET, RPM_TOLERANCE = 1800, 5
19+
local RPM_TARGET, RPM_TOLERANCE = 1800, 5
20-
local COIL_ON_RPM    = RPM_TARGET					-- engage inductor when at or above
20+
local COIL_ON_RPM    = RPM_TARGET -- engage inductor when at or above
21-
local COIL_OFF_RPM   = RPM_TARGET - RPM_TOLERANCE 	-- disengage when below
21+
local COIL_OFF_RPM   = RPM_TARGET -- RPM_TOLERANCE -- disengage when below
22
23
local FLOW_TUNE_LOWER, FLOW_TUNE_UPPER = 100, 2000 -- hard bounds
24
local MAX_TUNE_ITER  = 7                              -- binary-search passes
25
26
-- Fuel/control bar geometry (unchanged)
27-
local CTRLBAR_X, CTRLBAR_Y, CTRLBAR_WD, CTRLBAR_HT, CTRLBAR_SPC = 76, 6, 3, 29, 3
27+
local CTRLBAR_X, CTRLBAR_Y, CTRLBAR_WD, CTRLBAR_HT, CTRLBAR_SPC = 76, 6, 3, 30, 3
28-
local TURBAR_X, TURBAR_Y, TURBAR_WD, TURBAR_HT, TURBAR_SPC = 88, 6, 3, 29, 3
28+
local TURBAR_X, TURBAR_Y, TURBAR_WD, TURBAR_HT, TURBAR_SPC = 88, 6, 3, 30, 3
29
30
-- RPM progress bar geometry
31-
local RPMBAR_X, RPMBAR_Y, RPMBAR_H, RPMBAR_W = 3, 21, 2, 70
31+
local RPMBAR_X, RPMBAR_Y, RPMBAR_H, RPMBAR_W = 3, 21, 3, 70
32
33
-- Dynamics
34
local FLOW_BUFFER      = 0.10  -- % extra flow when we are too slow
35
local DECEL_FRACTION   = 0.25  -- fraction of flow to keep when too fast
36
local FLOW_LEARN_STEP  = 2     -- learning granularity (mB/t per loop)
37
38
-- UI refresh cadence (seconds).  0.25 s ⇒ 4 FPS; change if needed.
39
local UPDATE_PERIOD    = 0.25
40
41
---------------------------------------------------------------------
42
-- 2. UTILITY HELPERS ------------------------------------------------
43
---------------------------------------------------------------------
44
45
--- Return numeric `v` or fallback `d` if v is nil.
46
local function num(v, d) if v == nil then return d end; return v end
47
48
--- Pad a string on the right so residual characters are overwritten.
49
local function pad(str, width)
50
  if #str < width then str = str .. string.rep(" ", width-#str) end
51
  return str
52
end
53
54
---------------------------------------------------------------------
55
-- 3. UI PRIMITIVES (unchanged API) ---------------------------------
56
---------------------------------------------------------------------
57
58
UI = {}
59
60
function UI.rectangle(wd,x,y,w,h,color)
61
  local win = window.create(wd,x,y,w,h,true)
62
  win.setBackgroundColor(color); win.clear(); return win
63
end
64
65
function UI.bar(wd,x,y,w,h,bg,segments,max)
66
  local bar = UI.rectangle(wd,x,y,w,h,bg)
67
  local total = max or 100
68
  if h < w then -- horizontal
69
    local px = 1
70
    for _,s in ipairs(segments) do
71
      local segW = math.floor((s.p/total)*w + 0.5)
72
      UI.rectangle(bar,px,1,segW,h,s.color); px = px+segW
73
    end
74
  else           -- vertical (bottom‑up fill)
75
    local py = h
76
    for _,s in ipairs(segments) do
77
      local segH = math.floor((s.p/total)*h + 0.5)
78
      UI.rectangle(bar,1,py-segH+1,w,segH,s.color); py = py-segH
79
    end
80
  end
81
end
82
83
function UI.progress_bar(wd,x,y,w,h,p,bg,fg)
84
  UI.bar(wd,x,y,w,h,bg,{{p=p,color=fg}},100)
85
end
86
87
function UI.drawRect(wd,x,y,w,h,color)
88
  wd.setTextColor(color or colors.white)
89
  wd.setCursorPos(x,y);   wd.write("+" .. string.rep("-",w-2) .. "+")
90
  for i=1,h-2 do wd.setCursorPos(x,y+i); wd.write("|" .. string.rep(" ",w-2) .. "|") end
91
  wd.setCursorPos(x,y+h-1); wd.write("+" .. string.rep("-",w-2) .. "+")
92
end
93
94
function UI.drawTable(wd,x,y,cols,rows,cellW,cellH,color)
95
  wd.setTextColor(color or colors.white)
96
  local tW,tH=cols*cellW+1,rows*cellH+1
97
  for dy=0,tH-1 do
98
    for dx=0,tW-1 do
99
      local cx,cy=x+dx,y+dy
100
      local rowLine=(dy%cellH==0); local colLine=(dx%cellW==0)
101
      local ch = (rowLine and colLine) and "+" or rowLine and "-" or colLine and "|" or " "
102
      wd.setCursorPos(cx,cy); wd.write(ch)
103
    end
104
  end
105
end
106
107
local function UIHeader(wd,x,y,w,h,text,bg,fg)
108
  local hdr=UI.rectangle(wd,x,y,w,h,bg)
109
  wd.setTextColor(fg)
110
  wd.setCursorPos(x+math.floor(w/2-#text/2),y+math.floor(h/2))
111
  wd.write(text)
112
end
113
114
---------------------------------------------------------------------
115
-- 4. PERIPHERAL SET‑UP ---------------------------------------------
116
---------------------------------------------------------------------
117
118
local reactor = peripheral.wrap(reactorName)  or error("Reactor not found")
119
local turbine = peripheral.wrap(turbineName)  or error("Turbine not found")
120
local monitor = peripheral.wrap(monitorName) or peripheral.find("monitor") or error("Monitor not found")
121
122
monitor.setTextScale(0.5)
123
monitor.setBackgroundColor(colors.black)
124
monitor.setTextColor(colors.white)
125
monitor.clear()
126
127
---------------------------------------------------------------------
128
-- 5. FLOW AUTOTUNE (runs once) -------------------------------------
129
---------------------------------------------------------------------
130
131-
local function setRPMTarget(val)
131+
132-
  RPM_TARGET = val
132+
133-
  COIL_ON_RPM  = RPM_TARGET
133+
134-
  COIL_OFF_RPM = RPM_TARGET - RPM_TOLERANCE
134+
135
  end
136
end
137
138
local function writeFlow(v)
139
  local file=fs.open(FLOW_PERSIST_FILE,"w"); file.write(tostring(v)); file.close()
140
end
141
142
local function tuneFlow()
143
  local best, bestDelta=nil, math.huge
144
  local lo,hi=FLOW_TUNE_LOWER,FLOW_TUNE_UPPER
145
  for _=1,MAX_TUNE_ITER do
146
    local tf=math.floor((lo+hi)/2)
147
    turbine.setFluidFlowRateMax(tf)
148
    os.sleep(1)
149
    local r1=turbine.getRotorSpeed(); os.sleep(2); local r2=turbine.getRotorSpeed()
150
    local d=math.abs(r2-r1)
151
    if     r2>RPM_TARGET+RPM_TOLERANCE then hi=tf-1
152
    elseif r2<RPM_TARGET-RPM_TOLERANCE then lo=tf+1
153
    else  if d<bestDelta then best,bestDelta=tf,d end; if d<=1 then break end end
154
  end
155
  best = best or FLOW_TUNE_UPPER; writeFlow(best); return best
156
end
157
158
---------------------------------------------------------------------
159
-- 6. FAST, NON‑BLOCKING CONTROL RODS -------------------------------
160
---------------------------------------------------------------------
161
162
local function adjustRodsForSteam(targetSteam, margin)
163
  local produced = num(reactor.getHotFluidProducedLastTick(),0)
164
  local diff=targetSteam-produced; if math.abs(diff)<=margin then return end
165
  local lvl=num(reactor.getControlRodLevel(0),0)
166
  if diff>0 then lvl=math.max(0,lvl-2) else lvl=math.min(100,lvl+2) end
167
  reactor.setAllControlRodLevels(lvl)
168
end
169
170
---------------------------------------------------------------------
171
-- 7. BUTTONS & INTERACTION -----------------------------------------
172
---------------------------------------------------------------------
173
174
local TBL_X,TBL_Y=42,26 -- status LED table origin
175
local ADJ_BTN_X_LEFT,ADJ_BTN_Y,ADJ_BTN_W,ADJ_BTN_H=24,27,7,3
176
local ADJ_BTN_X_RIGHT=ADJ_BTN_X_LEFT+ADJ_BTN_W+1
177
local ADJ_ROW_SPACING=1
178
local ADJ_OFFSETS={-10,10,-2,2,-1,1}
179
local ADJ_LABELS={"-10","+10","-2","+2","-1","+1"}
180-
local TBL_X,TBL_Y=42,24 -- status LED table origin
180+
181-
local ADJ_BTN_X_LEFT,ADJ_BTN_Y,ADJ_BTN_W,ADJ_BTN_H=24,25,7,3
181+
182
learnedFlow = readFlow() or tuneFlow() -- forward declaration
183
184
local function drawAdjButtons()
185
  for row=0,2 do
186
    local y=ADJ_BTN_Y+row*(ADJ_BTN_H+ADJ_ROW_SPACING)
187
    UI.rectangle(monitor,ADJ_BTN_X_LEFT ,y,ADJ_BTN_W,ADJ_BTN_H,ADJ_CLR)
188
    UI.rectangle(monitor,ADJ_BTN_X_RIGHT,y,ADJ_BTN_W,ADJ_BTN_H,ADJ_CLR)
189-
-- Horizontal buttons (row of 4)
189+
190-
local H_BTN_X1      = 3
190+
191-
local H_BTN_Y      = 40
191+
192-
local H_BTN_H      = 7
192+
193-
local H_BTN_W      = 16
193+
194-
local H_BTN_SPAC   = 2
194+
195-
local H_BTN_LABELS = {
195+
196-
  "REACTOR ON/OFF",
196+
197-
  "TURBINE ON/OFF",
197+
198-
  "EJECT WASTE",
198+
199-
  "EJECT FUEL"
199+
200-
}
200+
201
      if x>=ADJ_BTN_X_LEFT and x<ADJ_BTN_X_LEFT+ADJ_BTN_W then
202-
-- compute even X-Distribution
202+
203-
local H_BTN_X = {}
203+
204-
do
204+
205-
  local startX = H_BTN_X1
205+
206-
  for i = 1, #H_BTN_LABELS do
206+
207-
    H_BTN_X[i] = startX + (i - 1) * (H_BTN_W + H_BTN_SPAC)
207+
208
    end
209
  end
210
end
211-
-- Vertical RPM target buttons (stack of 2)
211+
212-
local V_BTN_X      = H_BTN_X[#H_BTN_X] + H_BTN_W + H_BTN_SPAC
212+
213-
local V_BTN_Y      = H_BTN_Y      -- align top with the horizontal row
213+
214-
local V_BTN_H      = 3
214+
215-
local V_BTN_W      = H_BTN_W
215+
216-
local V_BTN_LABELS = { "900", "1800" }
216+
217
local function drawFuelRod()
218-
-- Draw Toggle and Speed Selector buttons
218+
219-
local function drawControlButtons()
219+
220-
  -- Horizontal
220+
221-
  for i, label in ipairs(H_BTN_LABELS) do
221+
222-
    local x = H_BTN_X[i]
222+
223-
    UI.rectangle(monitor, x, H_BTN_Y, H_BTN_W, H_BTN_H, colors.gray)
223+
224-
    monitor.setTextColor(colors.white)
224+
225-
    local tx = x + math.floor((H_BTN_W - #label) / 2)
225+
226-
    local ty = H_BTN_Y + math.floor(H_BTN_H / 2)
226+
227-
    monitor.setCursorPos(tx, ty)
227+
228-
    monitor.write(label)
228+
229
  UI.rectangle(monitor,CTRLBAR_X+CTRLBAR_SPC+CTRLBAR_WD+1,CTRLBAR_Y+1+CTRLBAR_HT-fht,CTRLBAR_WD,fht,colors.orange)
230-
  -- Vertical
230+
231-
  for i, label in ipairs(V_BTN_LABELS) do
231+
232-
    local y = V_BTN_Y + (i - 1) * V_BTN_H
232+
233-
    UI.rectangle(monitor, V_BTN_X, y + (i - 1), V_BTN_W, V_BTN_H, colors.gray)
233+
234-
    monitor.setTextColor(colors.white)
234+
235-
    local tx = V_BTN_X + math.floor((V_BTN_W - #label) / 2)
235+
236-
    local ty = y + math.floor(V_BTN_H / 2) + (i-1)
236+
237-
    monitor.setCursorPos(tx, ty)
237+
238-
    monitor.write(label)
238+
239
  local clntPercent=clntAmt/clntMax;
240
  local clntht=math.floor(clntPercent*TURBAR_HT+0.5)
241
242-
-- Handle touches on those buttons
242+
243-
local function handleControlTouch(x, y)
243+
244-
  -- Horizontal row
244+
245-
  if y >= H_BTN_Y and y < H_BTN_Y + H_BTN_H then
245+
246-
    for i = 1, #H_BTN_X do
246+
247-
      local x0 = H_BTN_X[i]
247+
248-
      if x >= x0 and x < x0 + H_BTN_W then
248+
249-
        if     i == 1 then reactor.setActive(not reactor.getActive())
249+
250-
        elseif i == 2 then turbine.setActive(not turbine.getActive())
250+
251-
        elseif i == 3 then reactor.doEjectWaste()
251+
252-
        elseif i == 4 then reactor.doEjectFuel()
252+
253-
        end
253+
254-
        return
254+
255
local function drawRPMgraph(rpm)
256
  local percent=math.min(1,rpm/(RPM_TARGET+200))*100
257
  UI.drawRect(monitor,RPMBAR_X-1,RPMBAR_Y-1,72,RPMBAR_H+2,colors.orange)
258
  monitor.setTextColor(colors.orange)
259-
  -- Vertical RPM presets
259+
260-
  if x >= V_BTN_X and x < V_BTN_X + V_BTN_W then
260+
261-
    for i = 1, #V_BTN_LABELS do
261+
262-
      local y0 = V_BTN_Y + (i - 1) * V_BTN_H
262+
263-
      if y >= y0 and y < y0 + V_BTN_H then
263+
264-
        if     i == 1 then RPM_TARGET = 900
264+
265-
				setRPMTarget(900)
265+
266-
        elseif i == 2 then RPM_TARGET = 1800
266+
267-
				setRPMTarget(1800)
267+
268-
        end
268+
269-
        return
269+
270
  }
271
  local s=labels[state] or labels[0]
272
  UI.drawRect(monitor,2,26,19,13,colors.orange) -- outline already static but redraw to clear old label
273
  UI.drawRect(monitor,2,29,19,7,colors.orange)
274
  UIHeader(monitor,3,30,17,5,s[1],s[2],s[3])
275
  monitor.setTextColor(colors.white)
276
end
277
278
---------------------------------------------------------------------
279
-- 9. STATIC CHROME (draw once) -------------------------------------
280
---------------------------------------------------------------------
281
282
local function drawChrome()
283
  UIHeader(monitor,1,1,164,3,"MAIN SYSTEMS INFORMATION PANEL - BLOCK A",colors.lightBlue,colors.orange)
284
  -- static frames
285
  UI.drawRect(monitor,2,26,19,13,colors.orange)
286
  UI.drawRect(monitor,2,29,19,7,colors.orange)
287
  UI.drawRect(monitor,ADJ_BTN_X_LEFT-1,ADJ_BTN_Y-1,17,13,colors.orange)
288
  UI.drawTable(monitor,TBL_X,TBL_Y,1,4,17,3,colors.orange)
289
  UI.drawTable(monitor,TBL_X+17,TBL_Y,2,4,7,3,colors.orange)
290
  UI.drawTable(monitor,2,6,1,4,31,3,colors.orange)  -- fluid info frame
291
  UI.drawTable(monitor,42,6,1,4,31,3,colors.orange) -- fuel info frame
292
  UI.drawTable(monitor,101,6,1,10,31,3,colors.orange) -- general info frame
293
  UI.drawTable(monitor,135,6,2,5,13,6,colors.orange) -- general info LED
294
295
  drawAdjButtons()
296
end
297
298
---------------------------------------------------------------------
299
-- 10. INITIALISATION ------------------------------------------------
300
---------------------------------------------------------------------
301
302
learnedFlow = readFlow() or tuneFlow()
303
local lastRPM=num(turbine.getRotorSpeed(),0)
304
local coilEngaged=turbine.getInductorEngaged()
305
local stableTicks=0
306
local RPMSTATUS=0 -- 0 low, 1 high, 2 nominal
307
308
monitor.clear(); drawChrome()
309
310
---------------------------------------------------------------------
311
-- 11. MAIN LOOP -----------------------------------------------------
312
---------------------------------------------------------------------
313
while true do
314
  -------------------------------------------------------------------
315
  -- schedule next UI tick
316
  local timer=os.startTimer(UPDATE_PERIOD)
317
318
  -------------------------------------------------------------------
319
  -- SENSOR READ -----------------------------------------------------
320
  local rpm=num(turbine.getRotorSpeed(),0)
321
  local drift=rpm-lastRPM; lastRPM=rpm
322
323
  -------------------------------------------------------------------
324
  -- INDUCTOR COIL LOGIC --------------------------------------------
325
  if not coilEngaged and rpm>=COIL_ON_RPM   then coilEngaged=true end
326
  if coilEngaged     and rpm<=COIL_OFF_RPM then coilEngaged=false end
327
328
  -------------------------------------------------------------------
329
  -- ADAPTIVE FLOW LOGIC --------------------------------------------
330
  local flow; local ventMsg
331
  if rpm<RPM_TARGET-RPM_TOLERANCE then
332
    flow=math.floor(learnedFlow*(1+FLOW_BUFFER)); ventMsg="OVERFLOW"; RPMSTATUS=0; turbine.setVentOverflow()
333
    learnedFlow=math.min(FLOW_TUNE_UPPER,learnedFlow+FLOW_LEARN_STEP); writeFlow(learnedFlow); stableTicks=0
334
  elseif rpm>RPM_TARGET+RPM_TOLERANCE then
335
    flow=math.max(1,math.floor(learnedFlow*DECEL_FRACTION)); ventMsg="ALL"; RPMSTATUS=1; turbine.setVentAll()
336
    learnedFlow=math.max(FLOW_TUNE_LOWER,learnedFlow-FLOW_LEARN_STEP); writeFlow(learnedFlow); stableTicks=0
337
  else
338
    flow=learnedFlow; ventMsg="OVERFLOW"; RPMSTATUS=2; turbine.setVentOverflow(); stableTicks=stableTicks+1
339
    if stableTicks>=4 then
340
      if rpm<RPM_TARGET then learnedFlow=math.min(FLOW_TUNE_UPPER,learnedFlow+1)
341
      else                    learnedFlow=math.max(FLOW_TUNE_LOWER,learnedFlow-1) end
342
      writeFlow(learnedFlow); stableTicks=0
343
    end
344
  end
345
346
  -------------------------------------------------------------------
347
  -- APPLY CONTROLS --------------------------------------------------
348-
  local percent=math.min(1,rpm/(2000))*100
348+
349
  turbine.setInductorEngaged(coilEngaged)
350
  adjustRodsForSteam(math.floor(flow*1.03),2)
351
352
  -------------------------------------------------------------------
353
  -- DYNAMIC UI UPDATE ----------------------------------------------
354
  drawRPMgraph(rpm)
355
  drawFuelRod()
356
  -- drawFluidAmount()
357
  drawRPMStatus(RPMSTATUS)
358
359
  local function w(x,y,str) monitor.setCursorPos(x,y); monitor.write(pad(str,28)) end
360
  -- high‑frequency numeric/status strings
361
  w(102,10,"Inductors: " .. (coilEngaged and "ENGAGED" or "DISENGAGED"))
362
  w(102,13,"Vent Mode: " .. ventMsg)
363
364-
  UI.drawRect(monitor,2,ADJ_BTN_Y-1,19,13,colors.orange) -- outline already static but redraw to clear old label
364+
365-
  UI.drawRect(monitor,2,ADJ_BTN_Y+2,19,7,colors.orange)
365+
366-
  UIHeader(monitor,3,ADJ_BTN_Y+3,17,5,s[1],s[2],s[3])
366+
367
  monitor.setCursorPos(102,31); monitor.write(pad(string.format("Fuel   Temp   : %6.1f °C",num(reactor.getFuelTemperature(),0)),28))
368
  monitor.setCursorPos(102,34); monitor.write(pad(string.format("Fuel Consumed : %6.1f mB/t",num(reactor.getFuelConsumedLastTick(),0)),28))
369
370
  monitor.setCursorPos(3,36); monitor.write(pad(string.format("RPM  : %.1f rpm", rpm), 17))
371
  monitor.setCursorPos(3,37); monitor.write(pad(string.format("Drift: %.1f rpm", drift), 17))
372
373
  -- fuel & fluid info (these rarely change but we update each tick for safety)
374
  monitor.setCursorPos(4,10); monitor.write(pad("Target  Flow: " .. learnedFlow .. " mB/t",28))
375
  monitor.setCursorPos(4,13); monitor.write(pad("Current Flow: " .. flow        .. " mB/t",28))
376
  monitor.setCursorPos(4,16); monitor.write(pad("Fluid/t     : " .. num(reactor.getHotFluidProducedLastTick(),0) .. " mB/t",28))
377-
--  UI.drawRect(monitor,2,26,19,13,colors.orange)
377+
378-
--  UI.drawRect(monitor,2,27,19,7,colors.orange)
378+
379
  monitor.setCursorPos(44,13); monitor.write(pad("Available Fuel(mB) : " .. num(reactor.getFuelAmount(),0),28))
380-
  UI.drawRect(monitor,H_BTN_X1-1,H_BTN_Y-1, 2 + 5 * H_BTN_W + 4 * H_BTN_SPAC ,H_BTN_H + 2,colors.orange)
380+
381
382
  -- ON/OFF LEDs -----------------------------------------------------
383
  local function led(state,onX,offX,y)
384
    if state then
385
      UI.rectangle(monitor,onX ,y,4,2,colors.green)
386
      UI.rectangle(monitor,offX,y,4,2,colors.black)
387
    else
388
      UI.rectangle(monitor,onX ,y,4,2,colors.black)
389-
  drawControlButtons()
389+
390
    end
391
  end
392
  led(reactor.getActive(),        TBL_X+26,TBL_X+19,TBL_Y+4)
393
  led(turbine.getActive(),        TBL_X+26,TBL_X+19,TBL_Y+7)
394
  led(turbine.getInductorEngaged(),TBL_X+26,TBL_X+19,TBL_Y+10)
395
396
 -- LED Table -----------------------------------------------------
397
398
399
  -- static labels (do once, but cheap to overwrite)
400
  monitor.setCursorPos(10,27); monitor.write("RPM")
401
  monitor.setCursorPos(8,28);  monitor.write("Status:")
402
  monitor.setCursorPos(TBL_X+20,TBL_Y+1); monitor.write("OFF")
403
  monitor.setCursorPos(TBL_X+27,TBL_Y+1); monitor.write("ON")
404
  monitor.setCursorPos(TBL_X+1,TBL_Y+4);  monitor.write("REACTOR:")
405
  monitor.setCursorPos(TBL_X+1,TBL_Y+7);  monitor.write("TURBINE:")
406
  monitor.setCursorPos(TBL_X+1,TBL_Y+10); monitor.write("INDUCTORS:")
407
  monitor.setBackgroundColor(colors.lightGray)
408
  monitor.setTextColor(colors.black)
409
  monitor.setCursorPos(77,6); monitor.write("ROD")
410
  monitor.setCursorPos(83,6); monitor.write("FUL")
411
412
  local fpercent=math.floor(num(reactor.getFuelAmount(),0)/num(reactor.getFuelAmountMax(),1)*100+0.5)
413
  local fldpercent=math.floor(num(turbine.getInputAmount(),0)/num(turbine.getFluidAmountMax(),1)*100+0.5)
414
  local cntpercent=math.floor(num(reactor.getCoolantAmount(),0)/num(reactor.getCoolantAmountMax(),1)*100+0.5)
415
  local wpercent=math.floor(num(reactor.getWasteAmount(),0)/num(reactor.getFuelAmountMax(),1)*100+0.5)
416
417
  monitor.setCursorPos(77,37); monitor.write(string.format("%3d",num(reactor.getControlRodLevel(0),0)))
418
  monitor.setCursorPos(83,37); monitor.write(string.format("%3d",fpercent))
419
  monitor.setCursorPos(89,6); monitor.write("FLD")
420
  monitor.setCursorPos(95,6); monitor.write("CNT")
421
  monitor.setCursorPos(89,37); monitor.write(string.format("%3d",fldpercent))
422
  monitor.setCursorPos(95,37); monitor.write(pad(string.format("%d", num((100/reactor.getCoolantAmountMax()*reactor.getCoolantAmount()),0)),4))
423
  monitor.setBackgroundColor(colors.black)
424
  monitor.setTextColor(colors.white)
425
  UI.rectangle(monitor, 3, 7, 30, 2, colors.blue)  -- FLUID INFORMATION
426
  UI.rectangle(monitor, 43, 7, 30, 2, colors.blue)  -- FUEL INFORMATION
427
  UI.rectangle(monitor, 102, 7, 30, 2, colors.blue)  -- TURBINE STATUS   
428
  UI.rectangle(monitor, 102, 16, 30, 2, colors.blue)  -- ENERGY STATS          
429
  UI.rectangle(monitor, 102, 25, 30, 2, colors.blue)  -- CORE STATUS         
430
  monitor.setBackgroundColor(colors.blue)
431
  monitor.setTextColor(colors.white)
432
  monitor.setCursorPos(3,7); monitor.write("      FLUID INFORMATION       ")
433
  monitor.setCursorPos(43,7); monitor.write("       FUEL INFORMATION       ")
434
  monitor.setCursorPos(102,7); monitor.write("       TURBINE STATUS        ")
435
  monitor.setCursorPos(102,16); monitor.write("        ENERGY STATS          ")
436
  monitor.setCursorPos(102,25); monitor.write("        CORE STATUS         ")
437
  monitor.setBackgroundColor(colors.black)
438
439
local colorOK = colors.lightBlue
440
local colorER = colors.orange
441
442
if reactor.getActive() then
443
  UIHeader(monitor,  136, 7, 12, 5, "REACTOR",  colorOK , colorOK )
444
else
445
  UIHeader(monitor,  136, 7, 12, 5, "REACTORREAC OFF", colorER , colorER )
446
end
447
448
if turbine.getActive() then
449
  UIHeader(monitor,  149, 7, 12, 5, "TURBINE",  colorOK , colorOK )
450
else
451
  UIHeader(monitor,  149, 7, 12, 5, "TURBINE", colorER , colorER )
452
end
453
454
if cntpercent > 10 then
455
  UIHeader(monitor,  136, 13, 12, 5, "COOLANT",  colorOK , colorOK )
456
else
457
  UIHeader(monitor,  136, 13, 12, 5, "COOLANT", colorER , colorER )
458
end
459
460
if fldpercent > 10 then
461
  UIHeader(monitor,  149, 13, 12, 5, "STEAM",  colorOK , colorOK )
462
else
463
  UIHeader(monitor,  149, 13, 12, 5, "STEAM", colorER , colorER )
464-
  monitor.setCursorPos(3,34); monitor.write(pad(string.format("RPM  : %.1f rpm", rpm), 17))
464+
465-
  monitor.setCursorPos(3,35); monitor.write(pad(string.format("Drift: %.1f rpm", drift), 17))
465+
466
if fpercent > 10 then
467
  UIHeader(monitor,  136, 19, 12, 5, "FUEL",  colorOK , colorOK )
468
else
469
  UIHeader(monitor,  136, 19, 12, 5, "FUEL", colorER , colorER )
470
end
471
472
if wpercent < 10 then
473
  UIHeader(monitor,  149, 19, 12, 5, "WASTE",  colorOK , colorOK )
474
else
475
  UIHeader(monitor,  149, 19, 12, 5, "WASTE", colorER , colorER )
476
end
477
478
if turbine.getEnergyStored() > 100 then
479
  UIHeader(monitor,  136, 25, 12, 5, "BATTERY",  colorOK , colorOK )
480
else
481
  UIHeader(monitor,  136, 25, 12, 5, "BATTERY", colorER , colorER )
482
end
483
484
if turbine.getEnergyProducedLastTick() > 15000 then
485
  UIHeader(monitor,  149, 25, 12, 5, "GENERATOR",  colorOK , colorOK )
486
else
487
  UIHeader(monitor,  149, 25, 12, 5, "GENERATOR", colorER , colorER )
488
end
489
490
if turbine.getFluidFlowRate() > 250 then
491
  UIHeader(monitor,  136, 31, 12, 5, "FLOW",  colorOK , colorOK )
492
else
493
  UIHeader(monitor,  136, 31, 12, 5, "FLOW", colorER , colorER )
494-
  monitor.setCursorPos(10,25); monitor.write("RPM")
494+
495-
  monitor.setCursorPos(8,26);  monitor.write("Status:")
495+
496
if reactor.getHotFluidProducedLastTick() > 250 then
497
  UIHeader(monitor,  149, 31, 12, 5, "FLUID",  colorOK , colorOK )
498
else
499
  UIHeader(monitor,  149, 31, 12, 5, "FLUID", colorER , colorER )
500
end
501
502
  -------------------------------------------------------------------
503
  -- EVENT HANDLING --------------------------------------------------
504
  repeat
505
    local ev={os.pullEvent()}
506
    if ev[1]=="monitor_touch" then handleTouch(ev[3],ev[4]) end
507
  until ev[1]=="timer" and ev[2]==timer
508
end
509-
  monitor.setCursorPos(77,36); monitor.write(string.format("%3d",num(reactor.getControlRodLevel(0),0)))
509+