asteroidsteam

Extreme Reactors Control Program

Jul 12th, 2022 (edited)
342
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 6.25 KB | None | 0 0
  1. local reactor = peripheral.wrap("BigReactors-Reactor_0")
  2. local monitor = peripheral.wrap("monitor_0")
  3. rednet.open("top")
  4.  
  5. controllers = {}
  6.  
  7. controllers[1] = true -- Allow computer ID#1 to access reactor control
  8.  
  9. local target_power = 5000 -- RF/Tick
  10. local control_rod_level = 50
  11.  
  12. function clamp(val, min, max)
  13.     if val > max then
  14.         return max
  15.     elseif val < min then
  16.         return min
  17.     else
  18.         return val
  19.     end
  20. end
  21.  
  22. function drawBar(x, y, size, perc)
  23.     local bgColor = monitor.getBackgroundColor()
  24.     local ox, oy = monitor.getCursorPos()
  25.  
  26.     monitor.setCursorPos(x, y)
  27.     monitor.setBackgroundColor(colors.green)
  28.  
  29.     local percGreen = clamp(math.floor(perc * size), 0, size)
  30.     local percGray = clamp(size - percGreen, 0, size - percGreen)
  31.     if percGray < 0 then
  32.         percGray = 0
  33.     end
  34.  
  35.     for i = percGreen,1,-1 do
  36.         monitor.write(" ")
  37.     end
  38.     monitor.setBackgroundColor(colors.lightGray)
  39.     for i = percGray,1,-1 do
  40.         monitor.write(" ")
  41.     end
  42.  
  43.     monitor.setBackgroundColor(bgColor)
  44.     monitor.setCursorPos(ox, oy)
  45. end
  46.  
  47. function getControlRodDiff(RFDiff)
  48.     if RFDiff > 10000 then
  49.         return 5
  50.     elseif RFDiff > 5000 then
  51.         return 3
  52.     elseif RFDiff > 1000 then
  53.         return 1
  54.     elseif RFDiff > 500 then
  55.         return 0.5
  56.     elseif RFDiff > 100 then
  57.         return 0.1
  58.     else
  59.         return 0.05
  60.     end
  61. end
  62.  
  63. function formatRF(rf)
  64.     if rf >= 1000000 then
  65.         return round(rf/1000000, 2) .. " MiRF"
  66.     elseif rf >= 1000 then
  67.         return round(rf/1000, 2) .. " KiRF"
  68.     else
  69.         return math.floor(rf) .. " RF"
  70.     end
  71. end
  72.  
  73. function round(num, numDecimalPlaces)
  74.     local mult = 10^(numDecimalPlaces or 0)
  75.     return math.floor(num * mult + 0.5) / mult
  76. end
  77.  
  78. function drawBoxWithCenteredText(x,y,w,h,text,color)
  79.     local ox,oy = monitor.getCursorPos()
  80.     local bgColor = monitor.getBackgroundColor()
  81.  
  82.     monitor.setBackgroundColor(color)
  83.     for cy=1,h,1 do
  84.         for cx=1,w,1 do
  85.             monitor.setCursorPos(x+cx,y+cy)
  86.             monitor.write(" ")
  87.         end
  88.     end
  89.  
  90.     local cx = math.floor(w / 2 + x - string.len(text) / 2 + 1)
  91.     local cy = math.floor(h / 2 + y + 1)
  92.  
  93.     monitor.setCursorPos(cx, cy)
  94.     monitor.write(text)
  95.  
  96.     monitor.setBackgroundColor(bgColor)
  97.     monitor.setCursorPos(ox, oy)
  98. end
  99.  
  100. monitor.setBackgroundColor(colors.black)
  101. monitor.clear()
  102. local mw, mh = monitor.getSize()
  103. local reactor_enabled = false
  104.  
  105. local buttons = {}
  106.  
  107. function renderButtons()
  108.     for i = 1, #buttons do
  109.         local button = buttons[i]
  110.         if not reactor_enabled then
  111.             if button.drod then
  112.                 drawBoxWithCenteredText(button.x,button.y,button.w,button.h,button.text,button.color)
  113.             end
  114.         else
  115.             drawBoxWithCenteredText(button.x,button.y,button.w,button.h,button.text,button.color)
  116.         end
  117.     end
  118. end
  119.  
  120. function inBounds(n, min, max)
  121.     return n <= max and n >= min
  122. end
  123.  
  124. function addButton(x,y,w,h,text,color,doRenderOnDisable, executor)
  125.     local button = {
  126.         x = x,
  127.         y = y,
  128.         w = w,
  129.         h = h,
  130.         text = text,
  131.         color = color,
  132.         drod = doRenderOnDisable,
  133.         executor = executor
  134.     }
  135.     buttons[#buttons+1] = button
  136. end
  137.  
  138. function startReactor(btn)
  139.     monitor.clear()
  140.     reactor_enabled = true
  141. end
  142.  
  143. function stopReactor(btn)
  144.     monitor.clear()
  145.     reactor_enabled = false
  146. end
  147.  
  148. function changeTargetPower(btn)
  149.     local num = btn.text:sub(2)
  150.     num = tonumber(num)
  151.     if btn.color == colours.red then
  152.         num = num * -1
  153.     end
  154.  
  155.     target_power = target_power + num
  156. end
  157.  
  158. addButton(2,mh - 8,15,5,"SHUT DOWN",colours.red, true, stopReactor)
  159. addButton(19,mh - 8,15,5,"START",colours.green, true, startReactor)
  160.  
  161. addButton(2, 9, 7, 3, "-10", colours.red, false, changeTargetPower)
  162. addButton(11, 9, 7, 3, "-100", colours.red, false, changeTargetPower)
  163. addButton(20, 9, 7, 3, "-1000", colours.red, false, changeTargetPower)
  164.  
  165. addButton(29, 9, 7, 3, "+1000", colours.green, false, changeTargetPower)
  166. addButton(38, 9, 7, 3, "+100", colours.green, false, changeTargetPower)
  167. addButton(47, 9, 7, 3, "+10", colours.green, false, changeTargetPower)
  168. local cur_power_gen = 0
  169.  
  170. function controlReactor()
  171.     while true do
  172.         cur_power_gen = reactor.getEnergyProducedLastTick()
  173.         reactor.setActive(reactor_enabled)
  174.  
  175.         if cur_power_gen ~= 0 and reactor_enabled then
  176.             local diff = getControlRodDiff(math.abs(cur_power_gen - target_power))
  177.  
  178.             if cur_power_gen > target_power then
  179.                 control_rod_level = clamp(control_rod_level + diff, 0, 100)
  180.             elseif cur_power_gen < target_power then
  181.                 control_rod_level = clamp(control_rod_level - diff, 0, 100)
  182.             end
  183.  
  184.             reactor.setAllControlRodLevels(control_rod_level)
  185.  
  186.  
  187.             monitor.setCursorPos(2,2)
  188.             monitor.write("Control Rod Level: ")
  189.             drawBar(22,2,40,control_rod_level/100)
  190.             monitor.setCursorPos(22,3)
  191.             monitor.write(math.floor(control_rod_level) .. "\%  ")
  192.  
  193.             monitor.setCursorPos(2,5)
  194.             monitor.write("Power Generation: ")
  195.             drawBar(22,5,40,cur_power_gen/target_power)
  196.             monitor.setCursorPos(22,6)
  197.             monitor.write(formatRF(cur_power_gen) .. "/t        ")
  198.  
  199.             monitor.setCursorPos(2,8)
  200.             monitor.write("Target power generation: " .. formatRF(target_power) .. "/t")
  201.         end
  202.         if not reactor_enabled then
  203.             monitor.setCursorPos(2,2)
  204.             monitor.write("Reactor is offline")
  205.         end
  206.         renderButtons()
  207.         sleep(0.1)
  208.     end
  209. end
  210.  
  211. function pullEvents()
  212.     while true do
  213.         event, side, x, y = os.pullEvent("monitor_touch")
  214.         for i=1, #buttons do
  215.             local button = buttons[i]
  216.             if inBounds(x, button.x, button.x + button.w) and inBounds(y, button.y, button.y + button.h) then
  217.                 button.executor(button)
  218.                 break
  219.             end
  220.         end
  221.     end
  222. end
  223.  
  224. function waitForRednetCommand()
  225.     while true do
  226.         local senderId, command, protocol = rednet.receive("reactor_control")
  227.         command = textutils.unserialize(command)
  228.  
  229.         if controllers[senderId] ~= nil and controllers[senderId] then
  230.             print("Received rednet command from " .. senderId)
  231.             print(command)
  232.             local reactorStatus = {
  233.                 control_rod_level = control_rod_level,
  234.                 cur_power_gen = cur_power_gen,
  235.                 target_power = target_power,
  236.                 reactor_enabled = reactor_enabled,
  237.                 command_executed = false
  238.             }
  239.  
  240.             for i=1, #buttons do
  241.                 local button = buttons[i]
  242.                 if command.button == button.text then
  243.                     button.executor(button)
  244.                     reactorStatus.command_executed = true
  245.                     break
  246.                 end
  247.             end
  248.  
  249.             rednet.send(senderId, textutils.serialize(reactorStatus), "reactor_response")
  250.         end
  251.     end
  252. end
  253.  
  254. parallel.waitForAny(pullEvents, controlReactor, waitForRednetCommand)
Add Comment
Please, Sign In to add comment