Advertisement
Guest User

startup

a guest
Aug 22nd, 2014
235
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 56.97 KB | None | 0 0
  1. --[[
  2. Program name: Lolmer's EZ-NUKE reactor control system
  3. Version: v0.3.8
  4. Programmer: Lolmer
  5. Last update: 2014-04-18
  6. Pastebin: http://pastebin.com/fguScPBQ
  7.  
  8. Description:
  9. This program controls a Big Reactors nuclear reactor in Minecraft with a Computercraft computer, using Computercraft's own wired modem connected to the reactors computer control port.
  10.  
  11. This program was designed to work with the mods and versions installed on Never Stop Toasting (NST) Diet http://www.technicpack.net/modpack/details/never-stop-toasting-diet.254882 Endeavour: Never Stop Toasting: Diet official Minecraft server http://forums.somethingawful.com/showthread.php?threadid=3603757
  12.  
  13. To simplify the code and guesswork, I assume the following monitor layout:
  14. 1) One Advanced Monitor for overall status display plus
  15.     one or more Reactors plus
  16.     none or more Turbines.
  17. 2) One Advanced Monitor for overall status display plus (first found monitor)
  18.     one Advanced Monitor for each connected Reactor plus (subsequent found monitors)
  19.     one Advanced Monitor for each connected Turbine (last group of monitors found).
  20. If you enable debug mode, add one additional Advanced Monitor for #1 or #2.
  21.  
  22. Notes:
  23.     Only one reactor and one, two, and three turbines have been tested with the above, but IN THEORY any number is supported.
  24.     Devices are found in the reverse order they are plugged in, so monitor_10 will be found before monitor_9.
  25.     Two 15x15x14 Turbines can output 260K RF/t by just one 7^3 (four rods) reactor putting out 4k mB steam
  26.  
  27. When using actively cooled reactors with turbines, keep the following in mind:
  28.     - 1 mB steam carries up to 10RF of potential energy to extract in a turbine.
  29.     - Actively cooled reactors produce steam, not power.
  30.     - You will need about 10 mB of water for each 1 mB of steam that you want to create in a 7^3 reactor.
  31.  
  32. Features:
  33.     Configurable min/max energy buffer and min/max temperature via ReactorOptions file.
  34.     ReactorOptions is read on start and then current values are saved every program cycle.
  35.     Rod Control value in ReactorOptions is only useful for initial start, after that the program saves the current Rod Control average over all Fuel Rods for next boot.
  36.     Auto-adjusts control rods per reactor to maintain temperature.
  37.     Will display reactor data to all attached monitors of correct dimensions.
  38.         For multiple monitors, the first monitor (often last plugged in) is the overall status monitor.
  39.     For multiple monitors, the first monitor (often last plugged in) is the overall status monitor.
  40.  
  41. GUI Usage:
  42.     The "<" and ">" buttons, when right-clicked with the mouse, will decrease and increase, respectively, the values assigned to the monitor:
  43.         "Rod (%)" will lower/raise the Reactor Control Rods for that Reactor
  44.         "Flow mB/t" will lower/raise the Turbine Flow Rate maximum for that Turbine
  45.     Right-clicking between the "<" and ">" (not on them) will disable auto-adjust of that value for attached device.
  46.         Right-clicking on the "Enabled" or "Disabled" text for auto-adjust will do the same.
  47.     Right-clicking on "ONLINE" or "OFFLINE" at the top-right will toggle the state of attached device.
  48.  
  49. Default values:
  50.     Rod Control: 90% (Let's start off safe and then power up as we can)
  51.     Minimum Energy Buffer: 15% (will power on below this value)
  52.     Maximum Energy Buffer: 85% (will power off above this value)
  53.     Minimum Passive Cooling Temperature: 850^C (will raise control rods below this value)
  54.     Maximum Passive Temperature: 950^C (will lower control rods above this value)
  55.     Optimal Turbine RPM: 900 or 1,800
  56.  
  57. Requirements:
  58.     Advanced Monitor size is X: 29, Y: 12 with a 3x2 size
  59.     Computer or Advanced Computer
  60.     Modems (not wireless) connecting each of the Computer to both the Advanced Monitor and Reactor Computer Port.
  61.     Big Reactors (http://www.big-reactors.com/) 0.3.2A+
  62.     Computercraft (http://computercraft.info/) 1.63+
  63.     Reset the computer any time number of connected devices change.
  64.  
  65. Resources:
  66. This script is available from:
  67.     http://pastebin.com/fguScPBQ
  68.     https://github.com/sandalle/minecraft_bigreactor_control
  69. Start-up script is available from:
  70.     http://pastebin.com/ZTMzRLez
  71.     https://github.com/sandalle/minecraft_bigreactor_control
  72. Other reactor control program which I based my program on:
  73.     http://pastebin.com/aMAu4X5J (ScatmanJohn)
  74.     http://pastebin.com/HjUVNDau (version ScatmanJohn based his on)
  75. A simpler Big Reactor control program is available from:
  76.     http://pastebin.com/7S5xCvgL (IronClaymore only for passively cooled reactors)
  77.  
  78. Reactor Computer Port API: http://wiki.technicpack.net/Reactor_Computer_Port
  79. Computercraft API: http://computercraft.info/wiki/Category:APIs
  80. Big Reactors Efficiency, Speculation and Questions! http://www.reddit.com/r/feedthebeast/comments/1vzds0/big_reactors_efficiency_speculation_and_questions/
  81. Big Reactors API code: https://github.com/erogenousbeef/BigReactors/blob/master/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorComputerPort.java
  82. Big Reactors API: http://big-reactors.com/cc_api.html
  83.  
  84. ChangeLog:
  85. 0.3.8 - Update to ComputerCraft 1.6 API.
  86. 0.3.7 - Fix typo when initializing TurbineNames array.
  87.     Fix Issue #1, turbine display is using the Reactor buffer size (10M RF) instead of the Turbine buffer size (1M RF).
  88. 0.3.6 - Fix multi-reactors displaying on the correct monitors (thanks HybridFusion).
  89.     Fix rod auto-adjust text position.
  90.     Reactors store 10M RF and Turbines store 1M RF in their buffer.
  91.     Add more colour to displayAllStatus().
  92.     Sleep for only two seconds instead of five.
  93.     Fix getDeviceStoredEnergyBufferPercent() for Reactors storing 10M RF in buffer.
  94.     Keep actively cooled reactors between 0-300^C (non-configurable for now).
  95. 0.3.5 - Do not discover connected devices every loop - nicer on servers. Reset computer anytime number of connected devices change.
  96.     Fix multi-reactor setups to display the additional reactors on monitors, rather than the last one found.
  97.     Fix passive reactor display having auto-adjust and energy buffer overwrite each other (removes rod count).
  98. 0.3.4 - Fix arithmetic for checking if we have enough monitors for the number of reactors.
  99.     Turbines are optimal at 900, 1800, *and* 2700 RPM
  100.     Increase loop timer from 1 to 5 to be nicer to servers
  101. 0.3.3 - Add Big Reactor Turbine support
  102.     First found monitor (appears to be last connected monitor) is used to display status of all found devices (if more than one valid monitor is found)
  103.     Display monitor number on top left of each monitor as "M#" to help find which monitor is which.
  104.     Enabling debug will use the last monitor found, if more than one, to print out debug info (also written to file)
  105.     Add monitor layout requirements to simplify code
  106.     Only clear monitors when we're about to use them (e.g. turbine monitors no longer clear, then wait for all reactors to update)
  107.     Fix getDeviceStoredEnergyBufferPercent(), was off by a decimal place
  108.     Just use first Control Rod level for entire reactor, they are no longer treated individually in BR 0.3
  109.     Allow for one monitor for n number of reactors and m number of turbines
  110.     Auto-adjust turbine flow rate by 25 mB to keep rotor speed at 900 or 1,800 RPM.
  111.     Clicks on monitors relate to what the monitor is showing (e.g. clicking on reactor 1's display won't modify turbine 1's nor reactor 2's values)
  112.     Print monitor name and device (reactor|turbine) name in blue to monitor associated for easier design by users.
  113.     Remove version number from monitors to free up space for monitor names.
  114.     Add option of right-clicking on "Enabled"/"Disabled" of auto-adjust to toggle it.
  115. 0.3.2 - Allow for rod control to override (disable) auto-adjust via UI (Rhonyn)
  116. 0.3.1 - Add fuel consumption per tick to display
  117. 0.3.0 - Add multi-monitor support! Sends one reactor's data to all monitors.
  118.     print function now takes table to support optional specified monitor
  119.     Set "numRods" every cycle for some people (mechaet)
  120.     Don't redirect terminal output with multiple monitor support
  121.     Log troubleshooting data to reactorcontrol.log
  122.     FC_API no longer used (copied and modified what I needed)
  123.     Multi-reactor support is theoretically implemented, but it is UNTESTED!
  124.     Updated for Big Reactor 0.3 (no longer works with 0.2)
  125.     BR getFuelTemperature() now returns many significant digits, just use math.ceil()
  126.     BR 0.3 removed individual rod temperatures, now it's only reactor-level temperature
  127. 0.2.4 - Simplify math, don't divide by a simple large number and then multiply by 100 (#/10000000*100)
  128.     Fix direct-connected (no modem) devices. getDeviceSide -> FC_API.getDeviceSide (simple as that :))
  129. 0.2.3 - Check bounds on reactor.setRodControlLevel(#,#), Big Reactor doesn't check for us.
  130. 0.2.2 - Do not auto-start the reactor if it was manually powered off (autoStart=false)
  131. 0.2.1 - Lower/raise only the hottest/coldest Control Rod while trying to control the reactor temperature.
  132.     "<" Rod Control buttons was off by one (to the left)
  133. 0.2.0 - Lolmer Edition :)
  134.     Add min/max stored energy percentage (default is 15%/85%), configurable via ReactorOptions file.
  135.     No reason to keep burning fuel if our power output is going nowhere. :)
  136.     Use variables variable for the title and version.
  137.     Try to keep the temperature between configured values (default is 850^C-950^C)
  138.     Add Waste and number of Control/Fuel Rods to displayBards()
  139.  
  140. TODO:
  141. - Save parameters per reactor instead of one global set for all reactors
  142. - Add min/max RF/t output and have it override temperature concerns (maybe?)
  143. - Add support for wireless modems, see http://computercraft.info/wiki/Modem_%28API%29, will not be secure (anyone can send/listen to your channels)!
  144. - Add support for any sized monitor (minimum 3x3), dynamic allocation/alignment
  145. - Lookup using pcall for better error handling http://www.computercraft.info/forums2/index.php?/topic/10992-using-pcall/
  146.  
  147. ]]--
  148.  
  149.  
  150. -- Some global variables
  151. local progVer = "0.3.8"
  152. local progName = "Reactor "
  153. local sideClick, xClick, yClick = nil, 0, 0
  154. local loopTime = 2
  155. local controlRodAdjustAmount = 1 -- Default Reactor Rod Control % adjustment amount
  156. local flowRateAdjustAmount = 25 -- Default Turbine Flow Rate in mB adjustment amount
  157. local debugMode = false
  158. -- These need to be updated for multiple reactors
  159. local baseControlRodLevel = nil
  160. local reactorRodOverride = false -- Rod override for Reactors
  161. -- End multi-reactor cleanup section
  162. local minStoredEnergyPercent = nil -- Max energy % to store before activate
  163. local maxStoredEnergyPercent = nil -- Max energy % to store before shutdown
  164. local minReactorTemp = nil -- Minimum reactor temperature (^C) to maintain
  165. local maxReactorTemp = nil -- Maximum reactor temperature (^C) to maintain
  166. local autoStart = {} -- Array for automatically starting reactors
  167. local monitorList = {} -- Empty monitor array
  168. local monitorNames = {} -- Empty array of monitor names
  169. local reactorList = {} -- Empty reactor array
  170. local reactorNames = {} -- Empty array of reactor names
  171. local turbineList = {} -- Empty turbine array
  172. local turbineNames = {} -- Empty array of turbine names
  173. local turbineFlowRateOverride = {} -- Flow rate override for each Turbine
  174. local turbineMonitorOffset = 3 -- Turbines are assigned monitors after reactors
  175.  
  176. term.clear()
  177. term.setCursorPos(2,1)
  178. term.write("Initializing program...")
  179.  
  180.  
  181. -- File needs to exist for append "a" later and zero it out if it already exists
  182. -- Always initalize this file to avoid confusion with old files and the latest run
  183. local logFile = fs.open("reactorcontrol.log", "w")
  184. if logFile then
  185.     logFile.writeLine("Minecraft time: Day "..os.day().." at "..textutils.formatTime(os.time(),true))
  186.     logFile.close()
  187. else
  188.     error("Could not open file reactorcontrol.log for writing")
  189. end
  190.  
  191.  
  192. -- Helper functions
  193.  
  194.  
  195. -- round() function from
  196. -- http://www.computercraft.info/forums2/index.php?/topic/4023-lua-printformat-with-floating-point-numbers/page__view__findpost__p__31037
  197. local function round(num, places)
  198.     num = tostring(num)
  199.     local inc = false
  200.  
  201.     -- Make sure decimal is a valid integer for later arithmetic
  202.     local decimal = string.find(num, "%.") or 0
  203.  
  204.     if (num:len() - decimal) <= places then
  205.         return tonumber(num)
  206.     end --already rounded, nothing to do.
  207.  
  208.     local digit = tonumber(num:sub(decimal + places + 1))
  209.     num = num:sub(1, decimal + places)
  210.  
  211.     if digit <= 4 then
  212.         return tonumber(num)
  213.     end --no incrementation needed, return truncated number
  214.  
  215.     local newNum = ""
  216.     for i=num:len(), 1, -1 do
  217.             digit = tonumber(num:sub(i))
  218.             if digit == 9 then
  219.                     if i > 1 then
  220.                             newNum = "0"..newNum
  221.                     else
  222.                             newNum = "10"..newNum
  223.                     end
  224.             elseif digit == nil then
  225.                     newNum = "."..newNum
  226.             else
  227.                     if i > 1 then
  228.                             newNum = num:sub(1,i-1)..(digit + 1)..newNum
  229.                     else
  230.                             newNum = (digit + 1)..newNum
  231.                     end
  232.                     return tonumber(newNum) --No more 9s found, so we are done incrementing. Copy remaining digits, then return number.
  233.             end -- if digit == 9 then
  234.     end -- for i=num:len(), 1, -1 do
  235.     return tonumber(newNum)
  236. end -- function round(num, places
  237.  
  238.  
  239. local function printLog(printStr)
  240.     if debugMode then
  241.         -- If multiple monitors, use the last monitor for debugging if debug is enabled
  242.         if #monitorList > 1 then
  243.             term.redirect(monitorList[#monitorList]) -- Redirect to last monitor for debugging
  244.             monitorList[#monitorList].setTextScale(0.5) -- Fit more logs on screen
  245.             write(printStr.."\n")   -- May need to use term.scroll(x) if we output too much, not sure
  246.             term.native()
  247.         end -- if #monitorList > 1 then
  248.  
  249.         local logFile = fs.open("reactorcontrol.log", "a") -- See http://computercraft.info/wiki/Fs.open
  250.         if logFile then
  251.             logFile.writeLine(printStr)
  252.             logFile.close()
  253.         else
  254.             error("Cannot open file reactorcontrol.log for appending!")
  255.         end -- if logFile then
  256.     end -- if debugMode then
  257. end -- function printLog(printStr)
  258.  
  259.  
  260. local function print(printParams)
  261.     -- Default to xPos=1, yPos=1, and first monitor
  262.     setmetatable(printParams,{__index={xPos=1, yPos=1, monitorIndex=1}})
  263.     local printString, xPos, yPos, monitorIndex =
  264.         printParams[1], -- Required parameter
  265.         printParams[2] or printParams.xPos,
  266.         printParams[3] or printParams.yPos,
  267.         printParams[4] or printParams.monitorIndex
  268.  
  269.     local monitor = nil
  270.     monitor = monitorList[monitorIndex]
  271.  
  272.     if not monitor then
  273.         printLog("monitorList["..monitorIndex.."] in print() was not a valid monitor")
  274.         return -- Invalid monitorIndex
  275.     end
  276.  
  277.     monitor.setCursorPos(xPos, yPos)
  278.     monitor.write(printString)
  279. end -- function print(printParams)
  280.  
  281.  
  282. -- Replaces the one from FC_API (http://pastebin.com/A9hcbZWe) and adding multi-monitor support
  283. local function printCentered(printString, yPos, monitorIndex)
  284.     local monitor = nil
  285.     monitor = monitorList[monitorIndex]
  286.  
  287.     if not monitor then
  288.         printLog("monitorList["..monitorIndex.."] in printCentered() was not a valid monitor")
  289.         return -- Invalid monitorIndex
  290.     end
  291.  
  292.     local width, height = monitor.getSize()
  293.     local monitorNameLength = 0
  294.  
  295.     -- Special changes for title bar
  296.     if yPos == 1 then
  297.         -- Add monitor name to first line
  298.         monitorNameLength = monitorNames[monitorIndex]:len()
  299.  
  300.         -- Leave room for "offline" and "online" on the right except for overall status display
  301.         if (#monitorList ~= 1) and (monitorIndex ~= 1) then
  302.             width = width - 7
  303.         end
  304.     end
  305.  
  306.     monitor.setCursorPos(math.floor(width/2) - math.ceil(printString:len()/2) +  monitorNameLength/2, yPos)
  307.     monitor.clearLine()
  308.     monitor.write(printString)
  309.  
  310.     monitor.setTextColor(colors.blue)
  311.     print{monitorNames[monitorIndex], 1, 1, monitorIndex}
  312.     monitor.setTextColor(colors.white)
  313. end -- function printCentered(printString, yPos, monitorIndex)
  314.  
  315.  
  316. -- Print text padded from the left side
  317. -- Clear the left side of the screen
  318. local function printLeft(printString, yPos, monitorIndex)
  319.     local monitor = nil
  320.     monitor = monitorList[monitorIndex]
  321.  
  322.     if not monitor then
  323.         printLog("monitorList["..monitorIndex.."] in printLeft() was not a valid monitor")
  324.         return -- Invalid monitorIndex
  325.     end
  326.  
  327.     local gap = 1
  328.     local width = monitor.getSize()
  329.  
  330.     -- Clear left-half of the monitor
  331.  
  332.     for curXPos = 1, (width / 2) do
  333.         monitor.setCursorPos(curXPos, yPos)
  334.         monitor.write(" ")
  335.     end
  336.  
  337.     -- Write our string left-aligned
  338.     monitor.setCursorPos(1+gap, yPos)
  339.     monitor.write(printString)
  340. end
  341.  
  342.  
  343. -- Print text padded from the right side
  344. -- Clear the right side of the screen
  345. local function printRight(printString, yPos, monitorIndex)
  346.     local monitor = nil
  347.     monitor = monitorList[monitorIndex]
  348.  
  349.     if not monitor then
  350.         printLog("monitorList["..monitorIndex.."] in printRight() was not a valid monitor")
  351.         return -- Invalid monitorIndex
  352.     end
  353.  
  354.     -- Make sure printString is a string
  355.     printString = tostring(printString)
  356.  
  357.     local gap = 1
  358.     local width = monitor.getSize()
  359.  
  360.     -- Clear right-half of the monitor
  361.     for curXPos = (width/2), width do
  362.         monitor.setCursorPos(curXPos, yPos)
  363.         monitor.write(" ")
  364.     end
  365.  
  366.     -- Write our string right-aligned
  367.     monitor.setCursorPos(math.floor(width) - math.ceil(printString:len()+gap), yPos)
  368.     monitor.write(printString)
  369. end
  370.  
  371.  
  372. -- Replaces the one from FC_API (http://pastebin.com/A9hcbZWe) and adding multi-monitor support
  373. local function clearMonitor(printString, monitorIndex)
  374.     local monitor = nil
  375.     monitor = monitorList[monitorIndex]
  376.  
  377.     if not monitor then
  378.         printLog("monitorList["..monitorIndex.."] in clearMonitor() was not a valid monitor")
  379.         return -- Invalid monitorIndex
  380.     end
  381.  
  382.     local gap = 2
  383.     monitor.clear()
  384.     local width, height = monitor.getSize()
  385.  
  386.     printCentered(printString, 1, monitorIndex)
  387.     monitor.setTextColor(colors.blue)
  388.     print{monitorNames[monitorIndex], 1, 1, monitorIndex}
  389.     monitor.setTextColor(colors.white)
  390.  
  391.     for i=1, width do
  392.         monitor.setCursorPos(i, gap)
  393.         monitor.write("-")
  394.     end
  395.  
  396.     monitor.setCursorPos(1, gap+1)
  397. end -- function clearMonitor(printString, monitorIndex)
  398.  
  399.  
  400. -- Return a list of all connected (including via wired modems) devices of "deviceType"
  401. local function getDevices(deviceType)
  402.     local deviceName = nil
  403.     local deviceIndex = 1
  404.     local deviceList, deviceNames = {}, {} -- Empty array, which grows as we need
  405.     local peripheralList = peripheral.getNames() -- Get table of connected peripherals
  406.  
  407.     deviceType = deviceType:lower() -- Make sure we're matching case here
  408.  
  409.     for peripheralIndex = 1, #peripheralList do
  410.         -- Log every device found
  411.         -- printLog("Found "..peripheral.getType(peripheralList[peripheralIndex]).."["..peripheralIndex.."] attached as \""..peripheralList[peripheralIndex].."\".")
  412.         if (string.lower(peripheral.getType(peripheralList[peripheralIndex])) == deviceType) then
  413.             -- Log devices found which match deviceType and which device index we give them
  414.             printLog("Found "..peripheral.getType(peripheralList[peripheralIndex]).."["..peripheralIndex.."] as index \"["..deviceIndex.."]\" attached as \""..peripheralList[peripheralIndex].."\".")
  415.             deviceNames[deviceIndex] = peripheralList[peripheralIndex]
  416.             deviceList[deviceIndex] = peripheral.wrap(peripheralList[peripheralIndex])
  417.             deviceIndex = deviceIndex + 1
  418.         end
  419.     end -- for peripheralIndex = 1, #peripheralList do
  420.  
  421.     return deviceList, deviceNames
  422. end -- function getDevices(deviceType)
  423.  
  424. -- Draw a line across the entire x-axis
  425. local function drawLine(yPos, monitorIndex)
  426.     local monitor = nil
  427.     monitor = monitorList[monitorIndex]
  428.  
  429.     if not monitor then
  430.         printLog("monitorList["..monitorIndex.."] in drawLine() was not a valid monitor")
  431.         return -- Invalid monitorIndex
  432.     end
  433.  
  434.     local width, height = monitor.getSize()
  435.  
  436.     for i=1, width do
  437.         monitor.setCursorPos(i, yPos)
  438.         monitor.write("-")
  439.     end
  440. end -- function drawLine(yPos,monitorIndex)
  441.  
  442.  
  443. -- Display a solid bar of specified color
  444. local function drawBar(startXPos, startYPos, endXPos, endYPos, color, monitorIndex)
  445.     local monitor = nil
  446.     monitor = monitorList[monitorIndex]
  447.  
  448.     if not monitor then
  449.         printLog("monitorList["..monitorIndex.."] in drawBar() was not a valid monitor")
  450.         return -- Invalid monitorIndex
  451.     end
  452.  
  453.     -- PaintUtils only outputs to term., not monitor.
  454.     -- See http://www.computercraft.info/forums2/index.php?/topic/15540-paintutils-on-a-monitor/
  455.     term.redirect(monitor)
  456.     --term.restore()
  457.     paintutils.drawLine(startXPos, startYPos, endXPos, endYPos, color)
  458.     monitor.setBackgroundColor(colors.black) -- PaintUtils doesn't restore the color
  459.     term.restore()
  460. end -- function drawBar(startXPos, startYPos,endXPos,endYPos,color,monitorIndex)
  461.  
  462.  
  463. -- Display single pixel color
  464. local function drawPixel(xPos, yPos, color, monitorIndex)
  465.     local monitor = nil
  466.     monitor = monitorList[monitorIndex]
  467.  
  468.     if not monitor then
  469.         printLog("monitorList["..monitorIndex.."] in drawPixel() was not a valid monitor")
  470.         return -- Invalid monitorIndex
  471.     end
  472.  
  473.     -- PaintUtils only outputs to term., not monitor.
  474.     -- See http://www.computercraft.info/forums2/index.php?/topic/15540-paintutils-on-a-monitor/
  475.     term.redirect(monitor)
  476.     --term.restore()
  477.     paintutils.drawPixel(xPos, yPos, color)
  478.     monitor.setBackgroundColor(colors.black) -- PaintUtils doesn't restore the color
  479.     term.restore()
  480. end -- function drawPixel(xPos, yPos, color, monitorIndex)
  481.  
  482.  
  483. -- End helper functions
  484.  
  485.  
  486. -- Then initialize the monitors
  487. local function findMonitors()
  488.     -- Empty out old list of monitors
  489.     monitorList = {}
  490.  
  491.     printLog("Finding monitors...")
  492.     monitorList, monitorNames = getDevices("monitor")
  493.  
  494.     if #monitorList == 0 then
  495.         printLog("No monitors found!")
  496.         error("Can't find any monitors!")
  497.     else
  498.         for monitorIndex = 1, #monitorList do
  499.             local monitor = nil
  500.             monitor = monitorList[monitorIndex]
  501.  
  502.             if not monitor then
  503.                 printLog("monitorList["..monitorIndex.."] in findMonitors() was not a valid monitor")
  504.                 break -- Invalid monitorIndex
  505.             end
  506.  
  507.             local monitorX, monitorY = monitor.getSize()
  508.             printLog("Verifying monitor["..monitorIndex.."] is of size x:"..monitorX.." by y:"..monitorY)
  509.  
  510.             -- Check for minimum size to allow for monitor.setTextScale(0.5) to work for 3x2 debugging monitor, changes getSize()
  511.             if monitorX < 29 or monitorY < 12 then
  512.                 term.redirect(monitor)
  513.                 monitor.clear()
  514.                 printLog("Removing monitor "..monitorIndex.." for incorrect size")
  515.                 monitor.setCursorPos(1,2)
  516.                 write("Monitor is the wrong size!\n")
  517.                 write("Needs to be 3x2.")
  518.                 term.native()
  519.  
  520.                 table.remove(monitorList, monitorIndex) -- Remove invalid monitor from list
  521.                 if monitorIndex == #monitorList then    -- If we're at the end already, break from loop
  522.                     break
  523.                 else
  524.                     monitorIndex = monitorIndex - 1 -- We just removed an element
  525.                 end -- if monitorIndex == #monitorList then
  526.  
  527.             end -- if monitorX ~= 29 or monitorY ~= 12 then
  528.         end -- for monitorIndex = 1, #monitorList do
  529.     end -- if #monitorList == 0 then
  530. end -- local function findMonitors()
  531.  
  532.  
  533. -- Initialize all Big Reactors - Reactors
  534. local function findReactors()
  535.     -- Empty out old list of reactors
  536.     newReactorList = {}
  537.  
  538.     printLog("Finding reactors...")
  539.     newReactorList, reactorNames = getDevices("BigReactors-Reactor")
  540.  
  541.     if #newReactorList == 0 then
  542.         printLog("No reactors found!")
  543.         error("Can't find any reactors!")
  544.     else  -- Placeholder
  545.         for reactorIndex = 1, #newReactorList do
  546.             local reactor = nil
  547.             reactor = newReactorList[reactorIndex]
  548.  
  549.             if not reactor then
  550.                 printLog("reactorList["..reactorIndex.."] in findReactors() was not a valid Big Reactor")
  551.                 return -- Invalid reactorIndex
  552.             end
  553.  
  554.             -- If number of found reactors changed, re-initialize them all for now
  555.             -- For now, initialize reactors to the same baseControlRodLevel
  556.             if #newReactorList ~= #reactorList then
  557.                 reactor.setAllControlRodLevels(baseControlRodLevel)
  558.  
  559.                 -- Auto-start reactor when needed (e.g. program startup) by default, or use existing value
  560.                 autoStart[reactorIndex] = true
  561.             end --if #newReactorList ~= #reactorList then
  562.         end --for reactorIndex = 1, #newReactorList do
  563.      end --if #newReactorList == 0 then
  564.      
  565.      
  566.  
  567.     -- Overwrite old reactor list with the now updated list
  568.     reactorList = newReactorList
  569.  
  570.     -- Check if we have enough monitors for the number of reactors
  571.     if (#reactorList ~= 1) and ((#turbineList + #reactorList) + 1 < #monitorList) then
  572.         printLog("You need "..(#reactorList + 1).." monitors for your "..#reactorList.." connected reactors")
  573.     end
  574.  
  575.     -- Start turbine monitor offset after reactors get monitors
  576.     -- This assumes that there is a monitor for each turbine and reactor, plus the overall monitor display
  577.     turbineMonitorOffset = #reactorList + 1 -- #turbineList will start at "1" if turbines found and move us just beyond #reactorList and status monitor range
  578. end -- function findReactors()
  579.  
  580.  
  581. -- Initialize all Big Reactors - Turbines
  582. local function findTurbines()
  583.     -- Empty out old list of turbines
  584.     newTurbineList = {}
  585.  
  586.     printLog("Finding turbines...")
  587.     newTurbineList, turbineNames = getDevices("BigReactors-Turbine")
  588.  
  589.     if #newTurbineList == 0 then
  590.         printLog("No turbines found") -- Not an error
  591.     else
  592.         for turbineIndex = 1, #newTurbineList do
  593.             local turbine = nil
  594.             turbine = newTurbineList[turbineIndex]
  595.  
  596.             if not turbine then
  597.                 printLog("turbineList["..turbineIndex.."] is not a valid Big Reactors Turbine")
  598.                 return -- Invalid turbineIndex
  599.             end
  600.  
  601.             -- If number of found turbines changed, re-initialize them all for now
  602.             if #newTurbineList ~= #turbineList then
  603.                 -- Default is to allow flow rate auto-adjust
  604.                 turbineFlowRateOverride[turbineIndex] = false
  605.             end -- if #newTurbineList ~= #turbineList then
  606.         end -- for turbineIndex = 1, #newTurbineList do
  607.  
  608.         -- Overwrite old turbine list with the now updated list
  609.         turbineList = newTurbineList
  610.  
  611.         -- Check if we have enough monitors for the number of turbines
  612.         if #monitorList < (#reactorList + #turbineList + 1) then
  613.             printLog("You need "..(#reactorList + #turbineList + 1).." monitors for your "..#reactorList.." connected reactors and "..#turbineList.." connected turbines")
  614.         end
  615.     end -- if #newTurbineList == 0 then
  616. end -- function findTurbines()
  617.  
  618.  
  619. -- Return current energy buffer in a specific reactor by %
  620. local function getReactorStoredEnergyBufferPercent(reactor)
  621.     if not reactor then
  622.         printLog("getReactorStoredEnergyBufferPercent() did not receive a valid Big Reactor Reactor")
  623.         return -- Invalid reactorIndex
  624.     end
  625.  
  626.     local energyBufferStorage = reactor.getEnergyStored()
  627.     return (math.floor(energyBufferStorage/100000)) -- (buffer/10000000 RF)*100%
  628. end -- function getReactorStoredEnergyBufferPercent(reactor)
  629.  
  630.  
  631. -- Return current energy buffer in a specific Turbine by %
  632. local function getTurbineStoredEnergyBufferPercent(turbine)
  633.     if not turbine then
  634.         printLog("getTurbineStoredEnergyBufferPercent() did not receive a valid Big Reactor Turbine")
  635.         return -- Invalid reactorIndex
  636.     end
  637.  
  638.     local energyBufferStorage = turbine.getEnergyStored()
  639.     return (math.floor(energyBufferStorage/10000)) -- (buffer/1000000 RF)*100%
  640. end -- function getTurbineStoredEnergyBufferPercent(turbine)
  641.  
  642.  
  643. -- Modify reactor control rod levels to keep temperature with defined parameters, but
  644. -- wait an in-game half-hour for the temperature to stabalize before modifying again
  645. local function temperatureControl(reactorIndex)
  646.     local reactor = nil
  647.     reactor = reactorList[reactorIndex]
  648.     if not reactor then
  649.         printLog("reactorList["..reactorIndex.."] in temperatureControl() was not a valid Big Reactor")
  650.         return -- Invalid reactorIndex
  651.     end
  652.  
  653.     local rodPercentage = math.ceil(reactor.getControlRodLevel(0))
  654.     local reactorTemp = math.ceil(reactor.getFuelTemperature())
  655.     local localMinReactorTemp, localMaxReactorTemp = minReactorTemp, maxReactorTemp
  656.  
  657.     -- No point modifying control rod levels for temperature if the reactor is offline
  658.     if reactor.getActive() then
  659.         -- Actively cooled reactors should range between 0^C-300^C
  660.         if reactor.isActivelyCooled() then
  661.             localMinReactorTemp = 0
  662.             localMaxReactorTemp = 300
  663.         end
  664.  
  665.         -- Don't bring us to 100, that's effectively a shutdown
  666.         if (reactorTemp > localMaxReactorTemp) and (rodPercentage ~= 99) then
  667.             -- If more than double our maximum temperature, increase rodPercentage faster
  668.             if reactorTemp > (2 * localMaxReactorTemp) then
  669.                 -- Check bounds, Big Reactor doesn't do this for us. :)
  670.                 if (rodPercentage + (10 * controlRodAdjustAmount)) > 99 then
  671.                     reactor.setAllControlRodLevels(99)
  672.                 else
  673.                     reactor.setAllControlRodLevels(rodPercentage + (10 * controlRodAdjustAmount))
  674.                 end
  675.             else
  676.                 -- Check bounds, Big Reactor doesn't do this for us. :)
  677.                 if (rodPercentage + controlRodAdjustAmount) > 99 then
  678.                     reactor.setAllControlRodLevels(99)
  679.                 else
  680.                     reactor.setAllControlRodLevels(rodPercentage + controlRodAdjustAmount)
  681.                 end
  682.             end -- if reactorTemp > (2 * localMaxReactorTemp) then
  683.         elseif (reactorTemp < localMinReactorTemp) and (rodPercentage ~= 0) then
  684.             -- If less than half our minimum temperature, decrease rodPercentage faster
  685.             if reactorTemp < (localMinReactorTemp / 2) then
  686.                 -- Check bounds, Big Reactor doesn't do this for us. :)
  687.                 if (rodPercentage - (10 * controlRodAdjustAmount)) < 0 then
  688.                     reactor.setAllControlRodLevels(0)
  689.                 else
  690.                     reactor.setAllControlRodLevels(rodPercentage - (10 * controlRodAdjustAmount))
  691.                 end
  692.             else
  693.                 -- Check bounds, Big Reactor doesn't do this for us. :)
  694.                 if (rodPercentage - controlRodAdjustAmount) < 0 then
  695.                     reactor.setAllControlRodLevels(0)
  696.                 else
  697.                     reactor.setAllControlRodLevels(rodPercentage - controlRodAdjustAmount)
  698.                 end
  699.             end -- if reactorTemp < (localMinReactorTemp / 2) then
  700.  
  701.             baseControlRodLevel = rodPercentage
  702.         end -- if (reactorTemp > localMaxReactorTemp) and (rodPercentage < 99) then
  703.     end -- if reactor.getActive() then
  704. end -- function temperatureControl(reactorIndex)
  705.  
  706.  
  707. -- Load saved reactor parameters if ReactorOptions file exists
  708. local function loadReactorOptions()
  709.     local reactorOptions = fs.open("ReactorOptions", "r") -- See http://computercraft.info/wiki/Fs.open
  710.  
  711.     if reactorOptions then
  712.         baseControlRodLevel = reactorOptions.readLine()
  713.         -- The following values were added by Lolmer
  714.         minStoredEnergyPercent = reactorOptions.readLine()
  715.         maxStoredEnergyPercent = reactorOptions.readLine()
  716.         minReactorTemp = reactorOptions.readLine()
  717.         maxReactorTemp = reactorOptions.readLine()
  718.         reactorRodOverride = reactorOptions.readLine() -- Should be string "true" or "false"
  719.  
  720.         -- If we succeeded in reading a string, convert it to a number
  721.         if baseControlRodLevel ~= nil then
  722.             baseControlRodLevel = tonumber(baseControlRodLevel)
  723.         end
  724.  
  725.         if minStoredEnergyPercent ~= nil then
  726.             minStoredEnergyPercent = tonumber(minStoredEnergyPercent)
  727.         end
  728.  
  729.         if maxStoredEnergyPercent ~= nil then
  730.             maxStoredEnergyPercent = tonumber(maxStoredEnergyPercent)
  731.         end
  732.  
  733.         if minReactorTemp ~= nil then
  734.             minReactorTemp = tonumber(minReactorTemp)
  735.         end
  736.  
  737.         if maxReactorTemp ~= nil then
  738.             maxReactorTemp = tonumber(maxReactorTemp)
  739.         end
  740.  
  741.         if reactorRodOverride == "true" then
  742.             reactorRodOverride = true
  743.         else
  744.             reactorRodOverride = false
  745.         end
  746.  
  747.         reactorOptions.close()
  748.     end -- if reactorOptions then
  749.  
  750.     -- Set default values if we failed to read any of the above
  751.     if baseControlRodLevel == nil then
  752.         baseControlRodLevel = 90
  753.     end
  754.  
  755.     if minStoredEnergyPercent == nil then
  756.         minStoredEnergyPercent = 15
  757.     end
  758.  
  759.     if maxStoredEnergyPercent == nil then
  760.         maxStoredEnergyPercent = 85
  761.     end
  762.  
  763.     if minReactorTemp == nil then
  764.         minReactorTemp = 850
  765.     end
  766.  
  767.     if maxReactorTemp == nil then
  768.         maxReactorTemp = 950
  769.     end
  770. end -- function loadReactorOptions()
  771.  
  772.  
  773. -- Save our reactor parameters
  774. local function saveReactorOptions()
  775.     local reactorOptions = fs.open("ReactorOptions", "w") -- See http://computercraft.info/wiki/Fs.open
  776.  
  777.     -- If we can save the files, save them
  778.     if reactorOptions then
  779.         local reactorIndex = 1
  780.         reactorOptions.writeLine(math.ceil(reactorList[1].getControlRodLevel(0))) -- Store just the first reactor for now
  781.         -- The following values were added by Lolmer
  782.         reactorOptions.writeLine(minStoredEnergyPercent)
  783.         reactorOptions.writeLine(maxStoredEnergyPercent)
  784.         reactorOptions.writeLine(minReactorTemp)
  785.         reactorOptions.writeLine(maxReactorTemp)
  786.         reactorOptions.writeLine(reactorRodOverride)
  787.         reactorOptions.close()
  788.     else
  789.         printLog("Failed to open file ReactorOptions for writing!")
  790.     end -- if reactorOptions then
  791. end -- function saveReactorOptions()
  792.  
  793.  
  794. local function displayReactorBars(barParams)
  795.     -- Default to first reactor and first monitor
  796.     setmetatable(barParams,{__index={reactorIndex=1, monitorIndex=1}})
  797.     local reactorIndex, monitorIndex =
  798.         barParams[1] or barParams.reactorIndex,
  799.         barParams[2] or barParams.monitorIndex
  800.  
  801.     -- Grab current monitor
  802.     local monitor = nil
  803.     monitor = monitorList[monitorIndex]
  804.     if not monitor then
  805.         printLog("monitorList["..monitorIndex.."] in displayReactorBars() was not a valid monitor")
  806.         return -- Invalid monitorIndex
  807.     end
  808.  
  809.     -- Grab current reactor
  810.     local reactor = nil
  811.     reactor = reactorList[reactorIndex]
  812.     if not reactor then
  813.         printLog("reactorList["..reactorIndex.."] in displayReactorBars() was not a valid Big Reactor")
  814.         return -- Invalid reactorIndex
  815.     end
  816.  
  817.     -- Draw border lines
  818.     local width, height = monitor.getSize()
  819.  
  820.     for i=3, 5 do
  821.         monitor.setCursorPos(22, i)
  822.         monitor.write("|")
  823.     end
  824.  
  825.     drawLine(2, monitorIndex)
  826.     drawLine(6, monitorIndex)
  827.  
  828.     -- Draw some text
  829.     local fuelString = "Fuel: "
  830.     local tempString = "Temp: "
  831.     local energyBufferString = "Production: "
  832.  
  833.     local padding = math.max(string.len(fuelString), string.len(tempString), string.len(energyBufferString))
  834.  
  835.     local fuelPercentage = math.ceil(reactor.getFuelAmount()/reactor.getFuelAmountMax()*100)
  836.     print{fuelString,2,3,monitorIndex}
  837.     print{fuelPercentage.." %",padding+2,3,monitorIndex}
  838.  
  839.     local reactorTemp = math.ceil(reactor.getFuelTemperature())
  840.     print{tempString,2,5,monitorIndex}
  841.     print{reactorTemp.." C",padding+2,5,monitorIndex}
  842.  
  843.     local rodPercentage = math.ceil(reactor.getControlRodLevel(0))
  844.     -- Allow controlling Reactor Control Rod Level from GUI
  845.     -- Decrease rod button: 23X, 4Y
  846.     -- Increase rod button: 28X, 4Y
  847.     if (xClick == 23) and (yClick == 4) and (sideClick == monitorNames[monitorIndex]) then
  848.         --Decrease rod level by amount
  849.         newRodPercentage = rodPercentage - (5 * controlRodAdjustAmount)
  850.         if newRodPercentage < 0 then
  851.             newRodPercentage = 0
  852.         end
  853.         sideClick, xClick, yClick = 0, 0, 0
  854.  
  855.         reactor.setAllControlRodLevels(newRodPercentage)
  856.  
  857.         -- Save updated rod percentage
  858.         baseControlRodLevel = newRodPercentage
  859.         rodPercentage = newRodPercentage
  860.     end -- if (xClick == 23) and (yClick == 4) and (sideClick == monitorNames[monitorIndex]) then
  861.  
  862.     if (xClick == 29) and (yClick == 4) and (sideClick == monitorNames[monitorIndex]) then
  863.         --Increase rod level by amount
  864.         newRodPercentage = rodPercentage + (5 * controlRodAdjustAmount)
  865.         if newRodPercentage > 100 then
  866.             newRodPercentage = 100
  867.         end
  868.         sideClick, xClick, yClick = 0, 0, 0
  869.  
  870.         reactor.setAllControlRodLevels(newRodPercentage)
  871.  
  872.         -- Save updated rod percentage
  873.         baseControlRodLevel = newRodPercentage
  874.         rodPercentage = newRodPercentage
  875.     end -- if (xClick == 29) and (yClick == 4) and (sideClick == monitorNames[monitorIndex]) then
  876.  
  877.     print{"Rod (%)",23,3,monitorIndex}
  878.     print{"<     >",23,4,monitorIndex}
  879.     print{rodPercentage,25,4,monitorIndex}
  880.  
  881.     -- getEnergyProducedLastTick() is used for both RF/t (passively cooled) and mB/t (actively cooled)
  882.     local energyBuffer = reactor.getEnergyProducedLastTick()
  883.     print{energyBufferString,2,4,monitorIndex}
  884.  
  885.     -- Actively cooled reactors do not produce energy, only hot fluid mB/t to be used in a turbine
  886.     -- still uses getEnergyProducedLastTick for mB/t of hot fluid generated
  887.     if not reactor.isActivelyCooled() then
  888.         -- Draw stored energy buffer bar
  889.         drawBar(2,8,28,8,colors.gray,monitorIndex)
  890.  
  891.         local curStoredEnergyPercent = getReactorStoredEnergyBufferPercent(reactor)
  892.         if curStoredEnergyPercent > 4 then
  893.             drawBar(2, 8, math.floor(26*curStoredEnergyPercent/100)+2, 8, colors.yellow, monitorIndex)
  894.         elseif curStoredEnergyPercent > 0 then
  895.             drawPixel(2, 8, colors.yellow, monitorIndex)
  896.         end -- if curStoredEnergyPercent > 4 then
  897.  
  898.         print{"Energy Buffer",2,7,monitorIndex}
  899.         print{curStoredEnergyPercent, width-(string.len(curStoredEnergyPercent)+3),7,monitorIndex}
  900.         print{"%",28,7,monitorIndex}
  901.  
  902.         print{math.ceil(energyBuffer).." RF/t",padding+2,4,monitorIndex}
  903.     else
  904.         print{math.ceil(energyBuffer).." mB/t",padding+2,4,monitorIndex}
  905.     end -- if not reactor.isActivelyCooled() then
  906.  
  907.     -- Print rod override status
  908.     local reactorRodOverrideStatus = ""
  909.  
  910.     print{"Rod Auto-adjust:",2,9,monitorIndex}
  911.  
  912.     if not reactorRodOverride then
  913.         reactorRodOverrideStatus = "Enabled"
  914.         monitor.setTextColor(colors.green)
  915.     else
  916.         reactorRodOverrideStatus = "Disabled"
  917.         monitor.setTextColor(colors.red)
  918.     end -- if not reactorRodOverride then
  919.  
  920.     print{reactorRodOverrideStatus, width - string.len(reactorRodOverrideStatus) - 1, 9, monitorIndex}
  921.     monitor.setTextColor(colors.white)
  922.  
  923.     local numRods = reactor.getNumberOfControlRods() - 1 -- Call every time as some people modify their reactor without rebooting the computer
  924.  
  925.     print{"Reactivity: "..math.ceil(reactor.getFuelReactivity()).." %", 2, 10, monitorIndex}
  926.     print{"Fuel: "..round(reactor.getFuelConsumedLastTick(),3).." mB/t", 2, 11, monitorIndex}
  927.     print{"Waste: "..reactor.getWasteAmount().." mB", width-(string.len(reactor.getWasteAmount())+10), 11, monitorIndex}
  928.  
  929.     monitor.setTextColor(colors.blue)
  930.     printCentered(reactorNames[reactorIndex],12,monitorIndex)
  931.     monitor.setTextColor(colors.white)
  932. end -- function displayReactorBars(barParams)
  933.  
  934.  
  935. local function reactorStatus(statusParams)
  936.     -- Default to first reactor and first monitor
  937.     setmetatable(statusParams,{__index={reactorIndex=1, monitorIndex=1}})
  938.     local reactorIndex, monitorIndex =
  939.         statusParams[1] or statusParams.reactorIndex,
  940.         statusParams[2] or statusParams.monitorIndex
  941.  
  942.     -- Grab current monitor
  943.     local monitor = nil
  944.     monitor = monitorList[monitorIndex]
  945.     if not monitor then
  946.         printLog("monitorList["..monitorIndex.."] in reactorStatus() was not a valid monitor")
  947.         return -- Invalid monitorIndex
  948.     end
  949.  
  950.     -- Grab current reactor
  951.     local reactor = nil
  952.     reactor = reactorList[reactorIndex]
  953.     if not reactor then
  954.         printLog("reactorList["..reactorIndex.."] in reactorStatus() was not a valid Big Reactor")
  955.         return -- Invalid reactorIndex
  956.     end
  957.  
  958.     local width, height = monitor.getSize()
  959.     local reactorStatus = ""
  960.  
  961.     if reactor.getConnected() then
  962.         if reactor.getActive() then
  963.             reactorStatus = "Activer"
  964.             monitor.setTextColor(colors.green)
  965.         else
  966.             reactorStatus = "Desactiver"
  967.             monitor.setTextColor(colors.red)
  968.         end -- if reactor.getActive() then
  969.  
  970.         if xClick >= (width - string.len(reactorStatus) - 1) and xClick <= (width-1) and (sideClick == monitorNames[monitorIndex]) then
  971.             if yClick == 1 then
  972.                 reactor.setActive(not reactor.getActive()) -- Toggle reactor status
  973.                 sideClick, xClick, yClick = 0, 0, 0 -- Reset click after we register it
  974.  
  975.                 -- If someone offlines the reactor (offline after a status click was detected), then disable autoStart
  976.                 if not reactor.getActive() then
  977.                     autoStart[reactorIndex] = false
  978.                 end
  979.             end -- if yClick == 1 then
  980.         end -- if (xClick >= (width - string.len(reactorStatus) - 1) and xClick <= (width-1)) and (sideClick == monitorNames[monitorIndex]) then
  981.  
  982.         -- Allow disabling rod level auto-adjust and only manual rod level control
  983.         if ((xClick > 23 and xClick < 28 and yClick == 4)
  984.                 or (xClick > 20 and xClick < 27 and yClick == 9))
  985.                 and (sideClick == monitorNames[monitorIndex]) then
  986.             reactorRodOverride = not reactorRodOverride -- Toggle reactor rod override status
  987.             sideClick, xClick, yClick = 0, 0, 0 -- Reset click after we register it
  988.         end -- if (xClick > 23) and (xClick < 28) and (yClick == 4) and (sideClick == monitorNames[monitorIndex]) then
  989.  
  990.     else
  991.         reactorStatus = "DISCONNECTED"
  992.         monitor.setTextColor(colors.red)
  993.     end -- if reactor.getConnected() then
  994.  
  995.     print{reactorStatus, width - string.len(reactorStatus) - 1, 1, monitorIndex}
  996.     monitor.setTextColor(colors.white)
  997. end -- function reactorStatus(statusParams)
  998.  
  999.  
  1000. -- Display all found reactors' status to monitor 1
  1001. -- This is only called if multiple reactors and/or a reactor plus at least one turbine are found
  1002. local function displayAllStatus()
  1003.     local reactor, turbine = nil, nil
  1004.     local onlineReactor, onlineTurbine = 0, 0
  1005.     local totalReactorRF, totalReactorSteam, totalTurbineRF = 0, 0, 0
  1006.     local totalReactorFuelConsumed = 0
  1007.     local totalCoolantStored, totalSteamStored, totalEnergy, totalMaxEnergyStored = 0, 0, 0, 0 -- Total turbine and reactor energy buffer and overall capacity
  1008.     local maxSteamStored = (2000*#turbineList)+(5000*#reactorList)
  1009.     local maxCoolantStored = (2000*#turbineList)+(5000*#reactorList)
  1010.  
  1011.     local monitor, monitorIndex = nil, 1
  1012.     monitor = monitorList[monitorIndex]
  1013.     if not monitor then
  1014.         printLog("monitorList["..monitorIndex.."] in reactorStatus() was not a valid monitor")
  1015.         return -- Invalid monitorIndex
  1016.     end
  1017.  
  1018.     for reactorIndex = 1, #reactorList do
  1019.         reactor = reactorList[reactorIndex]
  1020.         if not reactor then
  1021.             printLog("reactorList["..reactorIndex.."] in main() was not a valid Big Reactor")
  1022.             break -- Invalid reactorIndex
  1023.         end -- if not reactor then
  1024.  
  1025.         if reactor.getConnected() then
  1026.             if reactor.getActive() then
  1027.                 onlineReactor = onlineReactor + 1
  1028.                 totalReactorFuelConsumed = totalReactorFuelConsumed + reactor.getFuelConsumedLastTick()
  1029.             end -- reactor.getActive() then
  1030.  
  1031.             -- Actively cooled reactors do not produce or store energy
  1032.             if not reactor.isActivelyCooled() then
  1033.                 totalMaxEnergyStored = totalMaxEnergyStored + 10000000 -- Reactors store 10M RF
  1034.                 totalEnergy = totalEnergy + reactor.getEnergyStored()
  1035.                 totalReactorRF = totalReactorRF + reactor.getEnergyProducedLastTick()
  1036.             else
  1037.                 totalReactorSteam = totalReactorSteam + reactor.getEnergyProducedLastTick()
  1038.                 totalSteamStored = totalSteamStored + reactor.getHotFluidAmount()
  1039.                 totalCoolantStored = totalCoolantStored + reactor.getCoolantAmount()
  1040.             end -- if not reactor.isActivelyCooled() then
  1041.         end -- if reactor.getConnected() then
  1042.     end -- for reactorIndex = 1, #reactorList do
  1043.  
  1044.     for turbineIndex = 1, #turbineList do
  1045.         turbine = turbineList[turbineIndex]
  1046.         if not turbine then
  1047.             printLog("turbineList["..turbineIndex.."] in main() was not a valid Big Reactor")
  1048.             break -- Invalid turbineIndex
  1049.         end -- if not turbine then
  1050.  
  1051.         if turbine.getConnected() then
  1052.             if turbine.getActive() then
  1053.                 onlineTurbine = onlineTurbine + 1
  1054.             end
  1055.  
  1056.             totalMaxEnergyStored = totalMaxEnergyStored + 1000000 -- Turbines store 1M RF
  1057.             totalEnergy = totalEnergy + turbine.getEnergyStored()
  1058.             totalTurbineRF = totalTurbineRF + turbine.getEnergyProducedLastTick()
  1059.             totalSteamStored = totalSteamStored + turbine.getInputAmount()
  1060.             totalCoolantStored = totalCoolantStored + turbine.getOutputAmount()
  1061.         end -- if turbine.getConnected() then
  1062.     end -- for turbineIndex = 1, #turbineList do
  1063.  
  1064.     print{"Reactors online/found: "..onlineReactor.."/"..#reactorList, 2, 3, monitorIndex}
  1065.     print{"Turbines online/found: "..onlineTurbine.."/"..#turbineList, 2, 4, monitorIndex}
  1066.  
  1067.     if totalReactorRF ~= 0 then
  1068.         monitor.setTextColor(colors.blue)
  1069.         printRight("Reactor", 9, monitorIndex)
  1070.         monitor.setTextColor(colors.white)
  1071.         printRight(math.ceil(totalReactorRF).." (RF/t)", 10, monitorIndex)
  1072.     end
  1073.  
  1074.     if #turbineList then
  1075.         -- Display liquids
  1076.         monitor.setTextColor(colors.blue)
  1077.         printLeft("Steam (mB)", 6, monitorIndex)
  1078.         monitor.setTextColor(colors.white)
  1079.         printLeft(math.ceil(totalSteamStored).."/"..maxSteamStored, 7, monitorIndex)
  1080.         printLeft(math.ceil(totalReactorSteam).." mB/t", 8, monitorIndex)
  1081.         monitor.setTextColor(colors.blue)
  1082.         printRight("Coolant (mB)", 6, monitorIndex)
  1083.         monitor.setTextColor(colors.white)
  1084.         printRight(math.ceil(totalCoolantStored).."/"..maxCoolantStored, 7, monitorIndex)
  1085.  
  1086.         monitor.setTextColor(colors.blue)
  1087.         printLeft("Turbine", 9, monitorIndex)
  1088.         monitor.setTextColor(colors.white)
  1089.         printLeft(math.ceil(totalTurbineRF).." RF/t", 10, monitorIndex)
  1090.     end -- if #turbineList then
  1091.  
  1092.     printRight("Fuel: "..round(totalReactorFuelConsumed,3).." mB/t", 11, monitorIndex)
  1093.     print{"Buffer: "..math.ceil(totalEnergy,3).."/"..totalMaxEnergyStored.." RF", 2, 12, monitorIndex}
  1094. end -- function displayAllStatus()
  1095.  
  1096.  
  1097. -- Get turbine status
  1098. local function displayTurbineBars(turbineIndex, monitorIndex)
  1099.     -- Grab current monitor
  1100.     local monitor = nil
  1101.     monitor = monitorList[monitorIndex]
  1102.     if not monitor then
  1103.         printLog("monitorList["..monitorIndex.."] in displayTurbineBars() was not a valid monitor")
  1104.         return -- Invalid monitorIndex
  1105.     end
  1106.  
  1107.     -- Grab current turbine
  1108.     local turbine = nil
  1109.     turbine = turbineList[turbineIndex]
  1110.     if not turbine then
  1111.         printLog("turbineList["..turbineIndex.."] in displayTurbineBars() was not a valid Big Turbine")
  1112.         return -- Invalid turbineIndex
  1113.     end
  1114.  
  1115.     -- Draw border lines
  1116.     local width, height = monitor.getSize()
  1117.  
  1118.     for i=3, 5 do
  1119.         monitor.setCursorPos(21, i)
  1120.         monitor.write("|")
  1121.     end
  1122.  
  1123.     drawLine(2,monitorIndex)
  1124.     drawLine(6,monitorIndex)
  1125.  
  1126.     -- Allow controlling Turbine Flow Rate from GUI
  1127.     -- Decrease flow rate button: 22X, 4Y
  1128.     -- Increase flow rate button: 28X, 4Y
  1129.     local turbineFlowRate = math.ceil(turbine.getFluidFlowRateMax())
  1130.     if (xClick == 22) and (yClick == 4) and (sideClick == monitorNames[monitorIndex]) then
  1131.         --Decrease rod level by amount
  1132.         newTurbineFlowRate = turbineFlowRate - flowRateAdjustAmount
  1133.         if newTurbineFlowRate < 0 then
  1134.             newTurbineFlowRate = 0
  1135.         end
  1136.         sideClick, xClick, yClick = 0, 0, 0
  1137.  
  1138.         -- Check bounds [0,2000]
  1139.         if newTurbineFlowRate > 2000 then
  1140.             newTurbineFlowRate = 2000
  1141.         elseif newTurbineFlowRate < 0 then
  1142.             newTurbineFlowRate = 25 -- Don't go to zero, might as well power off
  1143.         end
  1144.  
  1145.         turbine.setFluidFlowRateMax(newTurbineFlowRate)
  1146.  
  1147.         -- Save updated Turbine Flow Rate
  1148.         turbineFlowRate = newTurbineFlowRate
  1149.     end -- if (xClick == 22) and (yClick == 4) and (sideClick == monitorNames[monitorIndex]) then
  1150.  
  1151.     if (xClick == 29) and (yClick == 4) and (sideClick == monitorNames[monitorIndex]) then
  1152.         --Increase rod level by amount
  1153.         newTurbineFlowRate = turbineFlowRate + flowRateAdjustAmount
  1154.         if newTurbineFlowRate > 2000 then
  1155.             newTurbineFlowRate = 2000
  1156.         end
  1157.         sideClick, xClick, yClick = 0, 0, 0
  1158.  
  1159.         -- Check bounds [0,2000]
  1160.         if newTurbineFlowRate > 2000 then
  1161.             newTurbineFlowRate = 2000
  1162.         elseif newTurbineFlowRate < 0 then
  1163.             newTurbineFlowRate = 25 -- Don't go to zero, might as well power off
  1164.         end
  1165.  
  1166.         turbine.setFluidFlowRateMax(newTurbineFlowRate)
  1167.  
  1168.         -- Save updated Turbine Flow Rate
  1169.         turbineFlowRate = newTurbineFlowRate
  1170.     end -- if (xClick == 29) and (yClick == 4) and (sideClick == monitorNames[monitorIndex]) then
  1171.  
  1172.     print{"  Flow",22,3,monitorIndex}
  1173.     print{"<      >",22,4,monitorIndex}
  1174.     print{turbineFlowRate,23,4,monitorIndex}
  1175.     print{"  mB/t",22,5,monitorIndex}
  1176.  
  1177.     local rotorSpeedString = "Speed: "
  1178.     local energyBufferString = "Producing: "
  1179.  
  1180.     local padding = math.max(string.len(rotorSpeedString), string.len(energyBufferString))
  1181.  
  1182.     local energyBuffer = turbine.getEnergyProducedLastTick()
  1183.     print{energyBufferString,1,4,monitorIndex}
  1184.     print{math.ceil(energyBuffer).." RF/t",padding+1,4,monitorIndex}
  1185.  
  1186.     local rotorSpeed = math.ceil(turbine.getRotorSpeed())
  1187.     print{rotorSpeedString,1,5,monitorIndex}
  1188.     print{rotorSpeed.." RPM",padding+1,5,monitorIndex}
  1189.  
  1190.     -- PaintUtils only outputs to term., not monitor.
  1191.     -- See http://www.computercraft.info/forums2/index.php?/topic/15540-paintutils-on-a-monitor/
  1192.  
  1193.     -- Draw stored energy buffer bar
  1194.     drawBar(1,8,28,8,colors.gray,monitorIndex)
  1195.     --paintutils.drawLine(2, 8, 28, 8, colors.gray)
  1196.  
  1197.     local curStoredEnergyPercent = getTurbineStoredEnergyBufferPercent(turbine)
  1198.     if curStoredEnergyPercent > 4 then
  1199.         drawBar(1, 8, math.floor(26*curStoredEnergyPercent/100)+2, 8, colors.yellow,monitorIndex)
  1200.     elseif curStoredEnergyPercent > 0 then
  1201.         drawPixel(1, 8, colors.yellow, monitorIndex)
  1202.     end -- if curStoredEnergyPercent > 4 then
  1203.  
  1204.     print{"Energy Buffer",1,7,monitorIndex}
  1205.     print{curStoredEnergyPercent, width-(string.len(curStoredEnergyPercent)+3),7,monitorIndex}
  1206.     print{"%",28,7,monitorIndex}
  1207.  
  1208.     -- Print rod override status
  1209.     local turbineFlowRateOverrideStatus = ""
  1210.  
  1211.     print{"Flow Auto-adjust:",2,10,monitorIndex}
  1212.  
  1213.     if not turbineFlowRateOverride[turbineIndex] then
  1214.         turbineFlowRateOverrideStatus = "Enabled"
  1215.         monitor.setTextColor(colors.green)
  1216.     else
  1217.         turbineFlowRateOverrideStatus = "Disabled"
  1218.         monitor.setTextColor(colors.red)
  1219.     end -- if not reactorRodOverride then
  1220.  
  1221.     print{turbineFlowRateOverrideStatus, width - string.len(turbineFlowRateOverrideStatus) - 1, 10, monitorIndex}
  1222.     monitor.setTextColor(colors.white)
  1223.  
  1224.     monitor.setTextColor(colors.blue)
  1225.     printCentered(turbineNames[turbineIndex],12,monitorIndex)
  1226.     monitor.setTextColor(colors.white)
  1227.  
  1228.     -- Need equation to figure out rotor efficiency and display
  1229. end -- function displayTurbineBars(statusParams)
  1230.  
  1231.  
  1232. -- Display turbine status
  1233. local function turbineStatus(turbineIndex, monitorIndex)
  1234.     -- Grab current monitor
  1235.     local monitor = nil
  1236.     monitor = monitorList[monitorIndex]
  1237.     if not monitor then
  1238.         printLog("monitorList["..monitorIndex.."] in turbineStatus() was not a valid monitor")
  1239.         return -- Invalid monitorIndex
  1240.     end
  1241.  
  1242.     -- Grab current turbine
  1243.     local turbine = nil
  1244.     turbine = turbineList[turbineIndex]
  1245.     if not turbine then
  1246.         printLog("turbineList["..turbineIndex.."] in turbineStatus() was not a valid Big Turbine")
  1247.         return -- Invalid turbineIndex
  1248.     end
  1249.  
  1250.     local width, height = monitor.getSize()
  1251.     local turbineStatus = ""
  1252.  
  1253.     if turbine.getConnected() then
  1254.         if turbine.getActive() then
  1255.             turbineStatus = "ONLINE"
  1256.             monitor.setTextColor(colors.green)
  1257.         else
  1258.             turbineStatus = "OFFLINE"
  1259.             monitor.setTextColor(colors.red)
  1260.         end -- if turbine.getActive() then
  1261.  
  1262.         if (xClick >= (width - string.len(turbineStatus) - 1)) and (xClick <= (width-1)) and (sideClick == monitorNames[monitorIndex]) then
  1263.             if yClick == 1 then
  1264.                 turbine.setActive(not turbine.getActive()) -- Toggle turbine status
  1265.                 sideClick, xClick, yClick = 0, 0, 0 -- Reset click after we register it
  1266.             end -- if yClick == 1 then
  1267.         end -- if (xClick >= (width - string.len(turbineStatus) - 1)) and (xClick <= (width-1)) and (sideClick == monitorNames[monitorIndex]) then
  1268.  
  1269.         -- Allow disabling/enabling flow rate auto-adjust
  1270.         if ((xClick > 23 and xClick < 28 and yClick == 4)
  1271.                 or (xClick > 20 and xClick < 27 and yClick == 10))
  1272.                 and (sideClick == monitorNames[monitorIndex]) then
  1273.             turbineFlowRateOverride[turbineIndex] = not turbineFlowRateOverride[turbineIndex] -- Toggle turbine rod override status
  1274.             sideClick, xClick, yClick = 0, 0, 0 -- Reset click after we register it
  1275.         end
  1276.  
  1277.     else
  1278.         turbineStatus = "DISCONNECTED"
  1279.         monitor.setTextColor(colors.red)
  1280.     end -- if turbine.getConnected() then
  1281.  
  1282.     print{turbineStatus, width - string.len(turbineStatus) - 1, 1, monitorIndex}
  1283.     monitor.setTextColor(colors.white)
  1284. end -- function function turbineStatus(turbineIndex, monitorIndex)
  1285.  
  1286.  
  1287. -- Maintain Turbine flow rate at 900 or 1,800 RPM
  1288. local function flowRateControl(turbineIndex)
  1289.     -- Grab current turbine
  1290.     local turbine = nil
  1291.     turbine = turbineList[turbineIndex]
  1292.     if not turbine then
  1293.         printLog("turbineList["..turbineIndex.."] in flowRateControl() was not a valid Big Turbine")
  1294.         return -- Invalid turbineIndex
  1295.     end
  1296.  
  1297.     -- No point modifying control rod levels for temperature if the turbine is offline
  1298.     if turbine.getActive() then
  1299.         local flowRate = turbine.getFluidFlowRate()
  1300.         local flowRateUserMax = math.ceil(turbine.getFluidFlowRateMax())
  1301.         local rotorSpeed = math.ceil(turbine.getRotorSpeed())
  1302.         local newFlowRate = 0
  1303.  
  1304.         -- If we're not at max flow-rate and an optimal RPM, let's do something
  1305.         -- also don't do anything if the current flow rate hasn't caught up to the user defined flow rate maximum
  1306.         if (((rotorSpeed % 900) ~= 0) and (flowRate ~= 2000) and (flowRate == flowRateUserMax))
  1307.             or (flowRate == 0) then
  1308.             -- Make sure we are not going too fast
  1309.             if rotorSpeed > 2700 then
  1310.                 newFlowRate = flowRateUserMax - flowRateAdjustAmount
  1311.             -- Make sure we're not going too slow
  1312.             elseif rotorSpeed < 900 then
  1313.                 newFlowRate = flowRateUserMax + flowRateAdjustAmount
  1314.             -- We're not at optimal RPM or flow-rate and we're not out-of-bounds
  1315.             else
  1316.                 return
  1317.             end
  1318.  
  1319.             -- Check bounds [0,2000]
  1320.             if newFlowRate > 2000 then
  1321.                 newFlowRate = 2000
  1322.             elseif newFlowRate < 0 then
  1323.                 newFlowRate = 25 -- Don't go to zero, might as well power off
  1324.             end
  1325.  
  1326.             turbine.setFluidFlowRateMax(newFlowRate)
  1327.         end -- if ((rotorSpeed % 900) ~= 0) and (flowRate ~= 2000) and (flowRate == flowRateUserMax) then
  1328.     end -- if turbine.getActive() then
  1329. end -- function flowRateControl(turbineIndex)
  1330.  
  1331.  
  1332. function main()
  1333.     -- Load reactor parameters and initialize systems
  1334.     loadReactorOptions()
  1335.  
  1336.     -- Get our initial list of connected monitors and reactors
  1337.     -- and initialize every cycle in case the connected devices change
  1338.     findMonitors()
  1339.     findReactors()
  1340.     findTurbines()
  1341.  
  1342.     while not finished do
  1343.         local reactor = nil
  1344.         local monitorIndex = 1
  1345.  
  1346.         -- For multiple reactors/monitors, monitor #1 is reserved for overall status
  1347.         -- or for multiple reactors/turbines and only one monitor
  1348.         if (((#reactorList + #turbineList) > 1) and (#monitorList > 1)) or
  1349.             (((#reactorList + #turbineList) > 1) and (#monitorList == 1)) then
  1350.                 local monitor = nil
  1351.                 monitor = monitorList[monitorIndex]
  1352.                 if not monitor then
  1353.                     printLog("monitorList["..monitorIndex.."] in turbineStatus() was not a valid monitor")
  1354.                     return -- Invalid monitorIndex
  1355.                 end
  1356.  
  1357.             clearMonitor(progName.." "..progVer, monitorIndex) -- Clear monitor and draw borders
  1358.             printCentered(progName.." "..progVer, 1, monitorIndex)
  1359.             displayAllStatus()
  1360.             monitorIndex = 2
  1361.         end
  1362.  
  1363.         -- Iterate through reactors
  1364.         for reactorIndex = 1, #reactorList do
  1365.             local monitor = nil
  1366.             monitor = monitorList[monitorIndex]
  1367.             if not monitor then
  1368.                 printLog("monitorList["..monitorIndex.."] in turbineStatus() was not a valid monitor")
  1369.                 return -- Invalid monitorIndex
  1370.             end
  1371.  
  1372.             local reactorMonitorIndex = monitorIndex + reactorIndex - 1 -- reactorIndex starts at 1
  1373.  
  1374.             clearMonitor(progName, reactorMonitorIndex) -- Clear monitor and draw borders
  1375.             printCentered(progName, 1, reactorMonitorIndex)
  1376.  
  1377.             -- Display reactor status, includes "Disconnected" but found reactors
  1378.             reactorStatus{reactorIndex, reactorMonitorIndex}
  1379.  
  1380.             reactor = reactorList[reactorIndex]
  1381.             if not reactor then
  1382.                 printLog("reactorList["..reactorIndex.."] in main() was not a valid Big Reactor")
  1383.                 break -- Invalid reactorIndex
  1384.             end
  1385.  
  1386.             if reactor.getConnected() then
  1387.                 local curStoredEnergyPercent = getReactorStoredEnergyBufferPercent(reactor)
  1388.  
  1389.                 -- Shutdown reactor if current stored energy % is >= desired level, otherwise activate
  1390.                 -- First pass will have curStoredEnergyPercent=0 until displayBars() is run once
  1391.                 if curStoredEnergyPercent >= 95 then
  1392.                     reactor.setActive(false)
  1393.                 -- Do not auto-start the reactor if it was manually powered off (autoStart=false)
  1394.                 elseif (curStoredEnergyPercent <= 60) and (autoStart[reactorIndex] == true) then
  1395.                     reactor.setActive(true)
  1396.                 end
  1397.  
  1398.                 -- Don't try to auto-adjust control rods if manual control is requested
  1399.                 if not reactorRodOverride then
  1400.                     temperatureControl(reactorIndex)
  1401.                 end
  1402.  
  1403.                 displayReactorBars{reactorIndex,reactorMonitorIndex}
  1404.             end -- if reactor.getConnected() then
  1405.         end -- for reactorIndex = 1, #reactorList do
  1406.  
  1407.         -- Monitors for turbines start after turbineMonitorOffset
  1408.         for turbineIndex = 1, #turbineList do
  1409.             local monitor = nil
  1410.             monitor = monitorList[monitorIndex]
  1411.             if not monitor then
  1412.                 printLog("monitorList["..monitorIndex.."] in turbineStatus() was not a valid monitor")
  1413.                 return -- Invalid monitorIndex
  1414.             end
  1415.  
  1416.             local turbineMonitorIndex = turbineIndex+turbineMonitorOffset
  1417.             clearMonitor(progName, turbineMonitorIndex) -- Clear monitor and draw borders
  1418.             printCentered(progName, 1, turbineMonitorIndex)
  1419.  
  1420.             -- Display turbine status, includes "Disconnected" but found turbines
  1421.             turbineStatus(turbineIndex, turbineMonitorIndex)
  1422.  
  1423.             turbine = turbineList[turbineIndex]
  1424.             if not turbine then
  1425.                 printLog("turbineList["..turbineIndex.."] in main() was not a valid Big Turbine")
  1426.                 break -- Invalid turbineIndex
  1427.             end
  1428.  
  1429.             if turbine.getConnected() then
  1430.                 if not turbineFlowRateOverride[turbineIndex] then
  1431.                     flowRateControl(turbineIndex)
  1432.                 end
  1433.  
  1434.                 displayTurbineBars(turbineIndex,turbineMonitorIndex)
  1435.             end
  1436.         end -- for reactorIndex = 1, #reactorList do
  1437.  
  1438.         sleep(loopTime) -- Sleep
  1439.         saveReactorOptions()
  1440.     end -- while not finished do
  1441. end -- main()
  1442.  
  1443.  
  1444. local function eventHandler()
  1445.     while not finished do
  1446.         -- http://computercraft.info/wiki/Os.pullEvent
  1447.         -- http://www.computercraft.info/forums2/index.php?/topic/1516-ospullevent-what-is-it-and-how-is-it-useful/
  1448.         event, arg1, arg2, arg3 = os.pullEvent()
  1449.  
  1450.         if event == "monitor_touch" then
  1451.             sideClick, xClick, yClick = arg1, math.floor(arg2), math.floor(arg3)
  1452.             printLog("Side: "..arg1.." Monitor touch X: "..xClick.." Y: "..yClick)
  1453.         elseif event == "char" and not inManualMode then
  1454.             local ch = string.lower(arg1)
  1455.             if ch == "q" then
  1456.                 finished = true
  1457.             elseif ch == "r" then
  1458.                 finished = true
  1459.                 os.reboot()
  1460.             end -- if ch == "q" then
  1461.         end -- if event == "monitor_touch" then
  1462.     end -- while not finished do
  1463. end -- function eventHandler()
  1464.  
  1465.  
  1466. while not finished do
  1467.     parallel.waitForAny(eventHandler, main)
  1468.     sleep(loopTime)
  1469. end -- while not finished do
  1470.  
  1471.  
  1472. -- Clear up after an exit
  1473. term.clear()
  1474. term.setCursorPos(1,1)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement