Advertisement
Kazadaoex

Extreme Reactors Control 2025 Optimized

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