Advertisement
Kazadaoex

Extreme Reactors Control 2025 Optimized

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