Advertisement
Kodos

Fancy Reactor Control

Jul 8th, 2015
353
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. --[[
  2. This program lets you monitor and actively control a Big Reactors reactor and turbines with an OpenComputers computer.
  3.  
  4. This program was tested on and designed to work with the mod versions and configurations installed on Flawedspirit's Mental Instability Pack, though as the pack uses default settings for both Big Reactors and OpenComputers, there should be no issues using a different modpack, or even a modpack that makes changes to how BR works.
  5.  
  6. - http://technicpack.net/modpack/mi-reloaded.604813
  7. - https://flawedspirit.com/minecraft/#pack
  8.  
  9. Computer Design
  10. ------------------------
  11. Please note that to keep the code (relatively) simple, the program makes a few assumptions; those being:
  12.  
  13. - A Tier 3 Computer
  14. - A Tier 2 or better Graphics Card
  15. - An Internet Card
  16. - One Tier 2 monitor of dimensions 5 wide by 3 tall
  17. - One reactor
  18. - Any number of (or none at all) turbines
  19.  
  20. Notes
  21. ------------------------
  22. - Only one reactor has been tested with this program (additional reactors added AT OWN RISK)
  23. - Data for only 6 turbines will display onscreen
  24. - Data for ALL turbines will still be tallied in the 'totals' row
  25. - By default, the program updates once every 2 seconds, though the rate is adjustable
  26.  
  27. Features
  28. ------------------------
  29. - Dynamic tracking of reactor information, like temperature, fuel/waste levels, coolant levels*, steam output*, or RF storage*
  30. - Dynamic tracking of up to 6 turbines, including speed, steam input, RF generation, and RF storage
  31. - In-program control of reactor power and control rod settings
  32. - Real-time warning if certain parameters indicate abnormal or non-optimal operation of reactors/turbines
  33.  
  34. * If applicable
  35.  
  36. Usage
  37. ------------------------
  38. - Press the left and right arrow keys to toggle between page 1 (turbine/RF storage information) or 2 (control rod configuration)
  39. - Press L or , to lower/raise control rods by 1%
  40. - Press ; or . to lower/raise control rods by 5%
  41. - Press ' or / to lower/raise control rods by 10%
  42. - Press P to toggle reactor power
  43. - Press Q to exit the program and return to your computer's terminal prompt
  44.  
  45. Resources
  46. ------------------------
  47. - This script is available from:
  48.   = http://pastebin.com/zWju7H0z
  49. - Official OpenComputers Site: http://ocdoc.cil.li/
  50. - Official Big Reactors Site: http://www.big-reactors.com/#/
  51. - Big Reactors API: http://wiki.technicpack.net/Reactor_Computer_Port
  52.  
  53. Changelog
  54. ------------------------
  55. - 0.1.4
  56.   - First release to Github! :D
  57.  
  58. TODO
  59. ------------------------
  60. - See https://github.com/Flawedspirit/FlawedspiritOC/issues for any outstanding issues.
  61. - Fix screen flickering issue on Page 1 (may not be possible at the moment)
  62. - Find a way to display information on ALL turbines that isn't confusing or illogical for the user.
  63. ]]
  64.  
  65. local component = require("component")
  66. local event = require("event")
  67. local keyboard = require("keyboard")
  68. local os = require("os")
  69. local term = require("term")
  70.  
  71. local pollRate = 2
  72. local active = true
  73. local currentPage = 1
  74.  
  75. -- Static Text Elements
  76. local header = "Reactor: "
  77. local headerOutput = "Running at %d%% max rated output"
  78. local version = "v0.1.4"
  79.  
  80. -- Components
  81. local gpu = component.gpu
  82. local reactor = component.br_reactor
  83. local w, h = gpu.getResolution()
  84.  
  85. local turbine = {}
  86. local i = 1
  87. for address, type in component.list("br_turbine") do
  88.   turbine[i] = component.proxy(address)
  89.   i = i + 1
  90. end
  91.  
  92. -- Reactor/turbine Data
  93. local totalControlRodLevel = 0
  94. local turbineMaxSteamIn = 0
  95. local controlRods = {}
  96. local reactorStatus = {}
  97.  
  98. -- Colors Helper
  99. local colors = {}
  100. colors.white      = 0xFFFFFF
  101. colors.orange     = 0xFFA500
  102. colors.magenta    = 0xFF00FF
  103. colors.lightblue  = 0x00AEEF
  104. colors.yellow     = 0xFFFF00
  105. colors.lime       = 0x00FF00
  106. colors.pink       = 0xFFC0CB
  107. colors.gray       = 0x555555
  108. colors.grey       = 0x555555
  109. colors.silver     = 0xAAAAAA
  110. colors.cyan       = 0x00FFFF
  111. colors.purple     = 0x800080
  112. colors.blue       = 0x0000FF
  113. colors.brown      = 0x603913
  114. colors.green      = 0x008000
  115. colors.red        = 0xFF0000
  116. colors.black      = 0x000000
  117.  
  118. -- Returns a whole number expressing a percentage
  119. -- out of 100 e.g. 90 is 90%
  120. function percent(val, max)
  121.   return (val / max) * 100
  122. end
  123.  
  124. function hLine(row)
  125.   gpu.fill(1, row, w, 1, "─")
  126. end
  127.  
  128. function label(x, y, message, color, ...)
  129.   local color = color or gpu.getForeground()
  130.   local oldColor = gpu.getForeground()
  131.  
  132.   gpu.setForeground(color)
  133.   term.setCursor(x, y)
  134.   print(string.format(message, ...))
  135.   gpu.setForeground(oldColor)
  136. end
  137.  
  138. function box(row, message, color)
  139.   --gpu.fill(1, row, w, row + 3, " ")
  140.   local color = color or gpu.getForeground()
  141.   local oldColor = gpu.getForeground()
  142.  
  143.   term.setCursor(1, row)
  144.   gpu.setForeground(color)
  145.  
  146.   -- Corners
  147.   gpu.set(1, row, "╒")
  148.   gpu.set(w, row, "╕")
  149.   gpu.set(1, row + 2, "└")
  150.   gpu.set(w, row + 2, "┘")
  151.  
  152.   -- Left and right
  153.   gpu.set(1, row + 1, "│")
  154.   gpu.set(w, row + 1, "│")
  155.  
  156.   -- Top and bottom
  157.   gpu.fill(2, row, w - 2, 1, "═")
  158.   gpu.fill(2, row + 2, w - 2, 1, "─")  
  159.  
  160.   gpu.set(3, row + 1, message)
  161.   gpu.setForeground(oldColor)
  162. end
  163.  
  164. -- Displayed if a reactor cannot be found at all
  165. -- and this program is rendered useless
  166. function printNoSignal()
  167.   icon = "[ ! ] "
  168.   message = "No Signal"
  169.  
  170.   gpu.setBackground(colors.black)
  171.   gpu.fill(1, 1, w, h, " ")
  172.  
  173.   gpu.setForeground(colors.red)
  174.   gpu.set(w / 2 - (string.len(icon) + string.len(message)) / 2 + 1, (h / 2) + 1, "[ ! ]")
  175.  
  176.   gpu.setForeground(colors.white)
  177.   gpu.set((w / 2) - 1, (h / 2) + 1, message)
  178. end
  179.  
  180. -- Event handler for when a key is pressed
  181. function onKeyDown(key)
  182.   local event, address, _, key, _ = event.pull()
  183.   if key == keyboard.keys.right then
  184.     currentPage = 2
  185.     gpu.fill(1, 1, w, h, " ")
  186.   elseif key == keyboard.keys.left then
  187.     currentPage = 1
  188.     gpu.fill(1, 1, w, h, " ")
  189.   elseif key == keyboard.keys.l then
  190.     reactor.setAllControlRodLevels(totalControlRodLevel + 1)
  191.   elseif key == keyboard.keys.comma then
  192.     reactor.setAllControlRodLevels(totalControlRodLevel - 1)
  193.   elseif key == keyboard.keys.semicolon then
  194.     reactor.setAllControlRodLevels(totalControlRodLevel + 5)
  195.   elseif key == keyboard.keys.period then
  196.     reactor.setAllControlRodLevels(totalControlRodLevel -5)
  197.   elseif key == keyboard.keys.apostrophe then
  198.     reactor.setAllControlRodLevels(totalControlRodLevel + 10)
  199.   elseif key == keyboard.keys.slash then
  200.     reactor.setAllControlRodLevels(totalControlRodLevel - 10)
  201.   elseif key == keyboard.keys.p then
  202.     reactor.setActive(not reactor.getActive())
  203.   elseif key == keyboard.keys.q then
  204.     active = false
  205.   end
  206. end
  207.  
  208. -- Listen for "key_down" event to control program flow
  209. event.listen("key_down", onKeyDown)
  210.  
  211. while active do
  212.   gpu.fill(1, 1, w, h, " ")
  213.   if component.isAvailable("br_reactor") then
  214.     label(w - (string.len(version) + 1), h - 1, version, colors.gray)
  215.     box(1, header, nil)
  216.  
  217.     -- Get and update values of each control rod
  218.     for i = 1, reactor.getNumberOfControlRods() - 1 do
  219.       controlRods[i] = reactor.getControlRodLevel(i)
  220.     end
  221.  
  222.     -- Iterate through and take the sum of each control rod level
  223.     -- Average it to get total control rod level
  224.     totalControlRodLevel = 0
  225.     for i = 1, #controlRods do
  226.       totalControlRodLevel = totalControlRodLevel + controlRods[i]
  227.     end
  228.     totalControlRodLevel = totalControlRodLevel / #controlRods
  229.  
  230.     -- Update reactor data
  231.     reactorStatus.temperature      = {"Temp", reactor.getCasingTemperature()}
  232.     reactorStatus.fuel             = {"Fuel", reactor.getFuelAmount()}
  233.     reactorStatus.waste            = {"Waste", reactor.getWasteAmount()}
  234.     reactorStatus.fuelMax          = {"Max Fuel", reactor.getFuelAmountMax()}
  235.     reactorStatus.burnRate         = {"Burn Rate", reactor.getFuelConsumedLastTick()}
  236.     reactorStatus.reactivity       = {"Reactivity", reactor.getFuelReactivity()}
  237.     reactorStatus.coolant          = {"Coolant", reactor.getCoolantAmount()}
  238.     reactorStatus.coolantMax       = {"Max Coolant", reactor.getCoolantAmountMax()}
  239.     reactorStatus.steam            = {"Steam Out", reactor.getHotFluidProducedLastTick()}
  240.     reactorStatus.steamMax         = {"Max Steam", reactor.getHotFluidAmountMax()}
  241.     reactorStatus.storedRF         = {"Stored Power", reactor.getEnergyStored()}
  242.  
  243.     label(1, 4, "%s: %.3f mB/t (%s: %d%%)", nil, reactorStatus.burnRate[1], reactorStatus.burnRate[2], reactorStatus.reactivity[1], reactorStatus.reactivity[2])
  244.  
  245.     -- REACTOR TABLE
  246.     -- Table header
  247.     label(1, 6, "%s", nil, reactorStatus.temperature[1])
  248.     label(16, 6, "%s", nil, reactorStatus.fuel[1])
  249.     label(32, 6, "%s", nil, reactorStatus.waste[1])
  250.     label(48, 6, "%s", nil, reactorStatus.coolant[1])
  251.     label(64, 6, "%s", nil, reactorStatus.steam[1])
  252.     hLine(7)
  253.  
  254.     -- Table body
  255.     label(1, 8, "%d °C", colors.red, reactorStatus.temperature[2])
  256.  
  257.     if percent(reactorStatus.fuel[2], reactorStatus.fuelMax[2]) > 10 then
  258.       label(16, 8, "%d mB", nil, reactorStatus.fuel[2])
  259.     else
  260.       label(16, 8, "%d mB [!]", colors.red, reactorStatus.fuel[2])
  261.     end
  262.  
  263.     if percent(reactorStatus.waste[2], reactorStatus.fuelMax[2]) < 90 then
  264.       label(32, 8, "%d mB", nil, reactorStatus.waste[2])
  265.     else
  266.       label(32, 8, "%d mB [!]", colors.red, reactorStatus.waste[2])
  267.     end
  268.  
  269.     if percent(reactorStatus.coolant[2], reactorStatus.coolantMax[2]) > 10 then
  270.       label(48, 8, "%d mB", nil, reactorStatus.fuel[2])
  271.     else
  272.       label(48, 8, "%d mB [!]", colors.red, reactorStatus.coolant[2])
  273.     end
  274.    
  275.     if reactorStatus.steam[2] >= turbineMaxSteamIn then
  276.       label(64, 8, "%d mB/t", nil, reactorStatus.steam[2])
  277.     else
  278.       label(64, 8, "%d mB/t [!]", colors.red, reactorStatus.steam[2])
  279.     end
  280.  
  281.     -- Percentages
  282.     label(16, 9, "(%.1f%%)", colors.gray, percent(reactorStatus.fuel[2], reactorStatus.fuelMax[2]))
  283.     label(32, 9, "(%.1f%%)", colors.gray, percent(reactorStatus.waste[2], reactorStatus.fuelMax[2]))
  284.     label(48, 9, "(%.1f%%)", colors.gray, percent(reactorStatus.coolant[2], reactorStatus.coolantMax[2]))
  285.     label(64, 9, "(%.1f%%)", colors.gray, percent(reactorStatus.steam[2], reactorStatus.steamMax[2]))
  286.  
  287.     if reactor.getActive() then
  288.       label(string.len(header) + 3, 2, "ON", colors.lime)
  289.       label(w - string.len(headerOutput), 2, headerOutput, nil, (100 - totalControlRodLevel))
  290.     else
  291.       label(string.len(header) + 3, 2, "OFF", colors.red)
  292.       label((w + 1) - string.len(headerOutput), 2, headerOutput, nil, 0)
  293.     end
  294.  
  295.     if currentPage == 1 then
  296.       box(h - 2, "Press [→] to go to page 2", nil)
  297.  
  298.       if component.isAvailable("br_turbine") then
  299.         -- TURBINE TABLE
  300.         -- Table header
  301.         label(1, 11, "%s", nil, "Turbine #")
  302.         label(16, 11, "%s", nil, "Speed")
  303.         label(32, 11, "%s", nil, "Steam In")
  304.         label(48, 11, "%s", nil, "RF Out")
  305.         label(64, 11, "%s", nil, "Stored RF")
  306.         hLine(12)
  307.  
  308.         -- Table body
  309.         local turbineTotalSteamIn = 0
  310.               turbineMaxSteamIn = 0
  311.         local turbineTotalRFOut = 0
  312.         local turbineStoredRF = 0
  313.  
  314.         -- by default, only 6 turbines will fit on the screen
  315.         local maxTurbines = 0
  316.         if #turbine > 6 then
  317.           maxTurbines = 6
  318.           label(1, h - 6, "...", colors.orange)
  319.           label(16, h - 6, "%d %s", colors.orange, (#turbine - 6), "turbine(s) not shown.")
  320.         else
  321.           maxTurbines = #turbine
  322.         end
  323.  
  324.         for i = 1, maxTurbines do
  325.           label(1, 12 + i, "%d", nil, i)
  326.           if turbine[i].getRotorSpeed() >= 1780 or turbine[i].getRotorSpeed() <= 1820 then
  327.             label(16, 12 + i, "%.1f RPM", colors.lime, turbine[i].getRotorSpeed())
  328.           elseif turbine[i].getRotorSpeed() > 1820 then
  329.             label(16, 12 + i, "%.1f RPM [!]", colors.red, turbine[i].getRotorSpeed())
  330.           else
  331.             label(16, 12 + i, "%.1f RPM", colors.orange, turbine[i].getRotorSpeed())
  332.           end
  333.           label(32, 12 + i, "%d mB/t", nil, turbine[i].getFluidFlowRate())
  334.           label(48, 12 + i, "%d RF/t", nil, turbine[i].getEnergyProducedLastTick())
  335.           label(64, 12 + i, "%d RF", nil, turbine[i].getEnergyStored())
  336.         end
  337.  
  338.         for i = 1, #turbine do
  339.           turbineTotalSteamIn = turbineTotalSteamIn + turbine[i].getFluidFlowRate()
  340.           turbineMaxSteamIn = turbineMaxSteamIn + turbine[i].getFluidFlowRateMax()
  341.           turbineTotalRFOut = turbineTotalRFOut + turbine[i].getEnergyProducedLastTick()
  342.           turbineStoredRF = turbineStoredRF + turbine[i].getEnergyStored()
  343.         end
  344.  
  345.         hLine(h - 5)
  346.         label(1, h - 4, "%s", nil, "TOTAL")
  347.         label(16, h - 4, "%s", nil, "--")
  348.         label(32, h - 4, "%d mB/t", nil, turbineTotalSteamIn)
  349.         label(48, h - 4, "%d RF/t", nil, turbineTotalRFOut)
  350.         label(64, h - 4, "%d RF", nil, turbineStoredRF)
  351.       else
  352.         label(1, 11, "%s: %d RF", nil, reactorStatus.storedRF[1], reactorStatus.storedRF[2])
  353.         label(1, 13, "%s", nil, "No turbines were detected.")
  354.       end
  355.  
  356.       os.sleep(pollRate)
  357.     elseif currentPage == 2 then
  358.       local maxBarLength = (w - 11) - 11
  359.  
  360.       box(h - 2, "Press [←] to go to page 1", nil)
  361.       label(1, 11, "%s", nil, "Control Rods")
  362.       hLine(12)
  363.  
  364.       gpu.fill(11, 13, math.ceil(maxBarLength * (totalControlRodLevel / 100) + 0.5), 1, "=")
  365.       label(1, 13, "%s", nil, "ALL RODS [")
  366.       label(w - 10, 13, "%s %d%%", nil, "]", totalControlRodLevel)
  367.  
  368.       hLine(h - 7)
  369.       label(1, h - 6, "%s", nil, "l / ,")
  370.       label(16, h - 6, "%s", nil, "; / .")
  371.       label(32, h - 6, "%s", nil, "' / /")
  372.       label(48, h - 6, "%s", nil, "p")
  373.  
  374.       label(1, h - 5, "%s", colors.gray, "Rods +1/-1")
  375.       label(16, h - 5, "%s", colors.gray, "Rods +5/-5")
  376.       label(32, h - 5, "%s", colors.gray, "Rods +10/-10")
  377.       label(48, h - 5, "%s", colors.gray, "Reactor Power")
  378.  
  379.       os.sleep(pollRate)
  380.     end
  381.   else
  382.     printNoSignal()
  383.   end
  384. end
  385.  
  386. -- Unregister key_down event on program exit or things get... serious...
  387. event.ignore("key_down", onKeyDown)
  388. term.clear()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement