EllipsiaLePoulet

Untitled

Dec 1st, 2022 (edited)
287
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 6.75 KB | None | 0 0
  1. local state, data, reactor, turbine, info_window, rules_window
  2.  
  3. local STATES = {
  4.     READY = 1, -- Reactor is off and can be started with the lever
  5.     RUNNING = 2, -- Reactor is running and all rules are met
  6.     ESTOP = 3, -- Reactor is stopped due to rule(s) being violated
  7.     UNKNOWN = 4, -- Reactor or turbine peripherals are missing
  8. }
  9.  
  10. ------------------------------------------------
  11.  
  12. local rules = {}
  13.  
  14. local function add_rule(name, fn)
  15.     table.insert(rules, function()
  16.         local ok, rule_met, value = pcall(fn)
  17.         if ok then
  18.             return rule_met, string.format("%s (%s)", name, value)
  19.         else
  20.             return false, name
  21.         end
  22.     end)
  23. end
  24.  
  25. add_rule("REACTOR TEMPERATURE   <= 745K", function()
  26.     local value = string.format("%3dK", math.ceil(data.reactor_temp))
  27.     return data.reactor_temp <= 745, value
  28. end)
  29.  
  30. add_rule("REACTOR DAMAGE        <=  10%", function()
  31.     local value = string.format("%3d%%", math.ceil(data.reactor_damage * 100))
  32.     return data.reactor_damage <= 0.10, value
  33. end)
  34.  
  35. add_rule("REACTOR COOLANT LEVEL >=  95%", function()
  36.     local value = string.format("%3d%%", math.floor(data.reactor_coolant * 100))
  37.     return data.reactor_coolant >= 0.95, value
  38. end)
  39.  
  40. add_rule("REACTOR WASTE LEVEL   <=  90%", function()
  41.     local value = string.format("%3d%%", math.ceil(data.reactor_waste * 100))
  42.     return data.reactor_waste <= 0.90, value
  43. end)
  44.  
  45. add_rule("TURBINE ENERGY LEVEL  <=  95%", function()
  46.     local value = string.format("%3d%%", math.ceil(data.turbine_energy * 100))
  47.     return data.turbine_energy <= 0.95, value
  48. end)
  49.  
  50. local function all_rules_met()
  51.     for i, rule in ipairs(rules) do
  52.         if not rule() then
  53.             return false
  54.         end
  55.     end
  56.     -- Allow manual emergency stop with SCRAM button
  57.     return state ~= STATES.RUNNING or data.reactor_on
  58. end
  59.  
  60. ------------------------------------------------
  61.  
  62. local function update_data()
  63.     data = {
  64.         lever_on = redstone.getInput("top"),
  65.  
  66.         reactor_on = reactor.getStatus(),
  67.         reactor_burn_rate = reactor.getBurnRate(),
  68.         reactor_max_burn_rate = reactor.getMaxBurnRate(),
  69.         reactor_temp = reactor.getTemperature(),
  70.         reactor_damage = reactor.getDamagePercent(),
  71.         reactor_coolant = reactor.getCoolantFilledPercentage(),
  72.         reactor_waste = reactor.getWasteFilledPercentage(),
  73.  
  74.         turbine_energy = turbine.getEnergyFilledPercentage(),
  75.     }
  76. end
  77.  
  78. ------------------------------------------------
  79.  
  80. local function colored(text, fg, bg)
  81.     term.setTextColor(fg or colors.white)
  82.     term.setBackgroundColor(bg or colors.black)
  83.     term.write(text)
  84. end
  85.  
  86. local function make_section(name, x, y, w, h)
  87.     for row = 1, h do
  88.         term.setCursorPos(x, y + row - 1)
  89.         local char = (row == 1 or row == h) and "\127" or " "
  90.         colored("\127" .. string.rep(char, w - 2) .. "\127", colors.gray)
  91.     end
  92.  
  93.     term.setCursorPos(x + 2, y)
  94.     colored(" " .. name .. " ")
  95.  
  96.     return window.create(term.current(), x + 2, y + 2, w - 4, h - 4)
  97. end
  98.  
  99. local function update_info()
  100.     local prev_term = term.redirect(info_window)
  101.  
  102.     term.clear()
  103.     term.setCursorPos(1, 1)
  104.  
  105.     if state == STATES.UNKNOWN then
  106.         colored("ERROR RETRIEVING DATA", colors.red)
  107.         return
  108.     end
  109.  
  110.     colored("REACTOR: ")
  111.     colored(data.reactor_on and "ON " or "OFF", data.reactor_on and colors.green or colors.red)
  112.     colored("  LEVER: ")
  113.     colored(data.lever_on and "ON " or "OFF", data.lever_on and colors.green or colors.red)
  114.     colored("  R. LIMIT: ")
  115.     colored(string.format("%4.1f", data.reactor_burn_rate), colors.blue)
  116.     colored("/", colors.lightGray)
  117.     colored(string.format("%4.1f", data.reactor_max_burn_rate), colors.blue)
  118.  
  119.     term.setCursorPos(1, 3)
  120.  
  121.     colored("STATUS: ")
  122.     if state == STATES.READY then
  123.         colored("READY, flip lever to start", colors.blue)
  124.     elseif state == STATES.RUNNING then
  125.         colored("RUNNING, flip lever to stop", colors.green)
  126.     elseif state == STATES.ESTOP and not all_rules_met() then
  127.         colored("EMERGENCY STOP, safety rules violated", colors.red)
  128.     elseif state == STATES.ESTOP then
  129.         colored("EMERGENCY STOP, toggle lever to reset", colors.red)
  130.     end -- STATES.UNKNOWN cases handled above
  131.  
  132.     term.redirect(prev_term)
  133. end
  134.  
  135. local estop_reasons = {}
  136.  
  137. local function update_rules()
  138.     local prev_term = term.redirect(rules_window)
  139.  
  140.     term.clear()
  141.  
  142.     if state ~= STATES.ESTOP then
  143.         estop_reasons = {}
  144.     end
  145.  
  146.     for i, rule in ipairs(rules) do
  147.         local ok, text = rule()
  148.         term.setCursorPos(1, i)
  149.         if ok and not estop_reasons[i] then
  150.             colored("[  OK  ] ", colors.green)
  151.             colored(text, colors.lightGray)
  152.         else
  153.             colored("[ FAIL ] ", colors.red)
  154.             colored(text, colors.red)
  155.             estop_reasons[i] = true
  156.         end
  157.     end
  158.  
  159.     term.redirect(prev_term)
  160. end
  161.  
  162. ------------------------------------------------
  163.  
  164. local function main_loop()
  165.     -- Search for peripherals again if one or both are missing
  166.     if not state or state == STATES.UNKNOWN then
  167.         reactor = peripheral.find("fissionReactorLogicAdapter")
  168.         turbine = peripheral.find("turbineValve")
  169.     end
  170.  
  171.     if not pcall(update_data) then
  172.         -- Error getting data (either reactor or turbine is nil?)
  173.         data = {}
  174.         state = STATES.UNKNOWN
  175.     elseif data.reactor_on == nil then
  176.         -- Reactor is not connected
  177.         state = STATES.UNKNOWN
  178.     elseif data.turbine_energy == nil then
  179.         -- Turbine is not connected
  180.         state = STATES.UNKNOWN
  181.     elseif not state then
  182.         -- Program just started, get current state from lever
  183.         state = data.lever_on and STATES.RUNNING or STATES.READY
  184.     elseif state == STATES.READY and data.lever_on then
  185.         -- READY -> RUNNING
  186.         state = STATES.RUNNING
  187.         -- Activate reactor
  188.         pcall(reactor.activate)
  189.         data.reactor_on = true
  190.     elseif state == STATES.RUNNING and not data.lever_on then
  191.         -- RUNNING -> READY
  192.         state = STATES.READY
  193.     elseif state == STATES.ESTOP and not data.lever_on then
  194.         -- ESTOP -> READY
  195.         state = STATES.READY
  196.     elseif state == STATES.UNKNOWN then
  197.         -- UNKNOWN -> ESTOP
  198.         state = data.lever_on and STATES.ESTOP or STATES.READY
  199.         estop_reasons = {}
  200.     end
  201.  
  202.     -- Always enter ESTOP if safety rules are not met
  203.     if state ~= STATES.UNKNOWN and not all_rules_met() then
  204.         state = STATES.ESTOP
  205.     end
  206.  
  207.     -- SCRAM reactor if not running
  208.     if state ~= STATES.RUNNING and reactor then
  209.         pcall(reactor.scram)
  210.     end
  211.  
  212.     -- Update info and rules windows
  213.     pcall(update_info)
  214.     pcall(update_rules)
  215.  
  216.     sleep() -- Other calls should already yield, this is just in case
  217.     return main_loop()
  218. end
  219.  
  220. term.setPaletteColor(colors.black, 0x000000)
  221. term.setPaletteColor(colors.gray, 0x343434)
  222. term.setPaletteColor(colors.lightGray, 0xababab)
  223. term.setPaletteColor(colors.red, 0xdb2d20)
  224. term.setPaletteColor(colors.green, 0x01a252)
  225. term.setPaletteColor(colors.blue, 0x01a0e4)
  226.  
  227. term.clear()
  228. local width = term.getSize()
  229. info_window = make_section("INFORMATION", 2, 2, width - 2, 7)
  230. rules_window = make_section("SAFETY RULES", 2, 10, width - 2, 9)
  231.  
  232. parallel.waitForAny(main_loop, function()
  233.     os.pullEventRaw("terminate")
  234. end)
  235.  
  236. os.reboot()
Add Comment
Please, Sign In to add comment