Advertisement
Hastwell

NUKE-DC for pre-CC 1.6

Oct 30th, 2014
227
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 95.25 KB | None | 0 0
  1. --[[
  2. I AM NOT THE ORIGINAL AUTHOR OF THIS PROGRAM. ALL I DID WAS PATCH IT FOR FTB MONSTER and it's old CC version.
  3. Program name: Lolmer's EZ-NUKE reactor control system
  4. Version: v0.3.13 -pre16-0.2
  5. Programmer: Lolmer
  6. Great assistance by Mechaet
  7. Pre-CC 1.6 patch by Hastwell
  8. Last update: 2014-09-24
  9. Pastebin (original unadulterated version): http://pastebin.com/fguScPBQ
  10. Pastebin (patched version): http://pastebin.com/vQy0Bbaz
  11.  
  12. Description:
  13. 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.
  14.  
  15. 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
  16.  
  17. To simplify the code and guesswork, I assume the following monitor layout, where each "monitor" listed below is a collection of 3 wide by two high Advanced Monitors:
  18. 1) One Advanced Monitor for overall status display plus
  19.     one or more Reactors plus
  20.     none or more Turbines.
  21. 2) One Advanced Monitor for overall status display plus (furthest monitor from computer by cable length)
  22.     one Advanced Monitor for each connected Reactor plus (subsequent found monitors)
  23.     one Advanced Monitor for each connected Turbine (last group of monitors found).
  24. If you enable debug mode, add one additional Advanced Monitor for #1 or #2.
  25.  
  26. Notes:
  27.     Only one reactor and one, two, and three turbines have been tested with the above, but IN THEORY any number is supported.
  28.     Devices are found in the reverse order they are plugged in, so monitor_10 will be found before monitor_9.
  29.     Two 15x15x14 Turbines can output 260K RF/t by just one 7^3 (four rods) reactor putting out 4k mB steam.
  30.  
  31. When using actively cooled reactors with turbines, keep the following in mind:
  32.     - 1 mB steam carries up to 10RF of potential energy to extract in a turbine.
  33.     - Actively cooled reactors produce steam, not power.
  34.     - You will need about 10 mB of water for each 1 mB of steam that you want to create in a 7^3 reactor.
  35.  
  36. Features:
  37.     Configurable min/max energy buffer and min/max temperature via ReactorOptions file.
  38.     ReactorOptions is read on start and then current values are saved every program cycle.
  39.     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.
  40.     Auto-adjusts control rods per reactor to maintain temperature.
  41.     Will display reactor data to all attached monitors of correct dimensions.
  42.         For multiple monitors, the first monitor (often last plugged in) is the overall status monitor.
  43.     For multiple monitors, the first monitor (often last plugged in) is the overall status monitor.
  44.     A new cruise mode from mechaet, ONLINE will be "blue" when active, to keep your actively cooled reactors running smoothly.
  45.  
  46. GUI Usage:
  47.     The "<" and ">" buttons, when right-clicked with the mouse, will decrease and increase, respectively, the values assigned to the monitor:
  48.         "Rod (%)" will lower/raise the Reactor Control Rods for that Reactor
  49.         "mB/t" will lower/raise the Turbine Flow Rate maximum for that Turbine
  50.         "RPM" will lower/raise the target Turbine RPM for that Turbine
  51.     Right-clicking between the "<" and ">" (not on them) will disable auto-adjust of that value for attached device.
  52.         Right-clicking on the "Enabled" or "Disabled" text for auto-adjust will do the same.
  53.     Right-clicking on "ONLINE" or "OFFLINE" at the top-right will toggle the state of attached device.
  54.  
  55. Default values:
  56.     Rod Control: 90% (Let's start off safe and then power up as we can)
  57.     Minimum Energy Buffer: 15% (will power on below this value)
  58.     Maximum Energy Buffer: 85% (will power off above this value)
  59.     Minimum Passive Cooling Temperature: 950^C (will raise control rods below this value)
  60.     Maximum Passive Cooling Temperature: 1,400^C (will lower control rods above this value)
  61.     Minimum Active Cooling Temperature: 300^C (will raise the control rods below this value)
  62.     Maximum Active Cooling Temperature: 420^C (will lower control rods above this value)
  63.     Optimal Turbine RPM:  900, 1,800, or 2,700 (divisible by 900)
  64.     New user-controlled option for target speed of turbines, defaults to 2726RPM, which is high-optimal.
  65.  
  66. Requirements:
  67.     Advanced Monitor size is X: 29, Y: 12 with a 3x2 size
  68.     Computer or Advanced Computer
  69.     Modems (not wireless) connecting each of the Computer to both the Advanced Monitor and Reactor Computer Port.
  70.     Big Reactors (http://www.big-reactors.com/) 0.3.2A+
  71.     Computercraft (http://computercraft.info/) 1.63+
  72.     Reset the computer any time number of connected devices change.
  73.  
  74. Resources:
  75. This script is available from:
  76.     http://pastebin.com/fguScPBQ
  77.     https://github.com/sandalle/minecraft_bigreactor_control
  78. Start-up script is available from:
  79.     http://pastebin.com/ZTMzRLez
  80.     https://github.com/sandalle/minecraft_bigreactor_control
  81. Other reactor control program which I based my program on:
  82.     http://pastebin.com/aMAu4X5J (ScatmanJohn)
  83.     http://pastebin.com/HjUVNDau (version ScatmanJohn based his on)
  84. A simpler Big Reactor control program is available from:
  85.     http://pastebin.com/7S5xCvgL (IronClaymore only for passively cooled reactors)
  86.  
  87.     Reactor Computer Port API: http://wiki.technicpack.net/Reactor_Computer_Port
  88.     Computercraft API: http://computercraft.info/wiki/Category:APIs
  89.     Big Reactors Efficiency, Speculation and Questions! http://www.reddit.com/r/feedthebeast/comments/1vzds0/big_reactors_efficiency_speculation_and_questions/
  90.     Big Reactors API code: https://github.com/erogenousbeef/BigReactors/blob/master/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorComputerPort.java
  91.     Big Reactors API: http://big-reactors.com/cc_api.html
  92.  
  93. ChangeLog:
  94. - 0.3.13
  95.     - Fix one reactor and one monitor incorrectly using status display instead of control display (Issue #35)
  96.     - Fix concatenating a string and boolean, see http://stackoverflow.com/questions/6615572/how-to-format-a-lua-string-with-a-boolean-variable
  97.     - Hopefully fix concatenating string and nul in printLog (Issue #3)
  98.  
  99. - 0.3.12
  100.     - Mechaet's changes:
  101.     - Redid some typing to correct a bug where the reactors always started with rod control disabled.
  102.  
  103. - 0.3.11
  104.     - Mechaet's changes:
  105.     - Cleaned up global variables list
  106.     - Added in per-device naming (displays a friendly name on the bottom of the monitor if configured in the device options file)
  107.     - Bigger bypasses of control routines when the control has been overridden
  108.     - Individual config files for turbines and reactors. Persistent between reboots, remembers your last saved settings.
  109.     - Cruise mode override bypass
  110.     - Changing flow rate no longer toggles flow rate override on and off. Changing the flow rate clearly indicates intent, so we put the override flag on and leave it there.
  111.     - Changed the rate at which the regular algorithm adjusts reactor rod control rates. Instead of being 1:1 we now move at 1:5 speed because there is a wide loophole where big adjustments can cause a swinging pendulum effect continually missing the target.
  112.  
  113. - 0.3.10
  114.     - Turbine algorithm pass by Mechaet.
  115.     - Updated turbine GUI.
  116.     - Fix single monitor (again) for Issue #22.
  117.  
  118. - 0.3.9
  119.     - Reactor algorithm pass by Mechaet.
  120.     - Additional user config options by Mechaet.
  121.     - Fix multiple reactors and none or more turbines with only one status monitor.
  122.     - Fix monitor scaling after one was used as debug (or in case of other modifications).
  123.     - Cruise mode implemented, defaults off but is saved between boots.
  124.     - Fix energy/% displays to match Big Reactors' GUI (Issue #9).
  125.     - Always write out found devices on computer terminal.
  126.     - Much improved round() function from mechaet (Issue #14).
  127.     - Refactoring pass/algorithm change on the reactor temperature control. Should now adjust in increments to achieve the desired temperature range quicker and more accurately.
  128.     - Optimal passive-cooled reactor temperature range changed from 850-900 to 950-1400.
  129.     - Fix display Issue #15.
  130.  
  131. - 0.3.8
  132.     - Update to ComputerCraft 1.6 API (only term.restore() -> term.native() required :)).
  133.  
  134. - 0.3.7
  135.     - Fix typo when initializing TurbineNames array.
  136.     - Fix Issue #1, turbine display is using the Reactor buffer size (10M RF) instead of the Turbine buffer size (1M RF).
  137.  
  138. - 0.3.6
  139.     - Fix multi-reactors displaying on the correct monitors (thanks HybridFusion).
  140.     - Fix rod auto-adjust text position.
  141.     - Reactors store 10M RF and Turbines store 1M RF in their buffer.
  142.     - Add more colour to displayAllStatus().
  143.     - Sleep for only two seconds instead of five.
  144.     - Fix getDeviceStoredEnergyBufferPercent() for Reactors storing 10M RF in buffer.
  145.     - Keep actively cooled reactors between 0-300^C (non-configurable for now).
  146.  
  147. - 0.3.5
  148.     - Do not discover connected devices every loop - nicer on servers. Reset computer anytime number of connected devices change.
  149.     - Fix multi-reactor setups to display the additional reactors on monitors, rather than the last one found.
  150.     - Fix passive reactor display having auto-adjust and energy buffer overwrite each other (removes rod count).
  151.  
  152. - 0.3.4
  153.     - Fix arithmetic for checking if we have enough monitors for the number of reactors.
  154.     - Turbines are optimal at 900, 1800, *and* 2700 RPM
  155.     - Increase loop timer from 1 to 5 to be nicer to servers
  156.  
  157. - 0.3.3
  158.     - Add Big Reactors Turbine support.
  159.     - 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)
  160.     - Display monitor number on top left of each monitor as "M#" to help find which monitor is which.
  161.     - Enabling debug will use the last monitor found, if more than one, to print out debug info (also written to file)
  162.     - Only clear monitors when we're about to use them (e.g. turbine monitors no longer clear, then wait for all reactors to update)
  163.     - Fix getDeviceStoredEnergyBufferPercent(), was off by a decimal place
  164.     - Just use first Control Rod level for entire reactor, they are no longer treated individually in BR 0.3
  165.     - Allow for one monitor for n number of reactors and m number of turbines
  166.     - Auto-adjust turbine flow rate by 25 mB to keep rotor speed at 900 or 1,800 RPM.
  167.     - 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)
  168.     - Print monitor name and device (reactor|turbine) name in blue to monitor associated for easier design by users.
  169.     - Remove version number from monitors to free up space for monitor names.
  170.     - Add option of right-clicking on "Enabled"/"Disabled" of auto-adjust to toggle it.
  171.  
  172. - 0.3.2
  173.     - Allow for rod control to override (disable) auto-adjust via UI (Rhonyn)
  174.  
  175. - 0.3.1
  176.     - Add fuel consumption per tick to display
  177.  
  178. - 0.3.0
  179.     - Add multi-monitor support! Sends one reactor's data to all monitors.
  180.     - print function now takes table to support optional specified monitor
  181.     - Set "numRods" every cycle for some people (mechaet)
  182.     - Don't redirect terminal output with multiple monitor support
  183.     - Log troubleshooting data to reactorcontrol.log
  184.     - FC_API no longer used (copied and modified what I needed)
  185.     - Multi-reactor support is theoretically implemented, but it is UNTESTED!
  186.     - Updated for Big Reactor 0.3 (no longer works with 0.2)
  187.     - BR getFuelTemperature() now returns many significant digits, just use math.ceil()
  188.     - BR 0.3 removed individual rod temperatures, now it's only reactor-level temperature
  189.  
  190. - 0.2.4
  191.     - Simplify math, don't divide by a simple large number and then multiply by 100 (#/10000000*100)
  192.     - Fix direct-connected (no modem) devices. getDeviceSide -> FC_API.getDeviceSide (simple as that :))
  193.  
  194. - 0.2.3
  195.     - Check bounds on reactor.setRodControlLevel(#,#), Big Reactor doesn't check for us.
  196.  
  197. - 0.2.2
  198.     - Do not auto-start the reactor if it was manually powered off (autoStart=false)
  199.  
  200. - 0.2.1
  201.     - Lower/raise only the hottest/coldest Control Rod while trying to control the reactor temperature.
  202.     - "<" Rod Control buttons was off by one (to the left)
  203.  
  204. - 0.2.0 - Lolmer Edition :)
  205.     - Add min/max stored energy percentage (default is 15%/85%), configurable via ReactorOptions file.
  206.     - No reason to keep burning fuel if our power output is going nowhere. :)
  207.     - Use variables variable for the title and version.
  208.     - Try to keep the temperature between configured values (default is 850^C-950^C)
  209.     - Add Waste and number of Control/Fuel Rods to displayBards()
  210.  
  211. TODO:
  212. - Save parameters per reactor instead of one global set for all reactors.
  213. - Add min/max RF/t output and have it override temperature concerns (maybe?).
  214. - Add support for wireless modems, see http://computercraft.info/wiki/Modem_%28API%29, will not be secure (anyone can send/listen to your channels)!
  215. - Add support for any sized monitor (minimum 3x3), dynamic allocation/alignment.
  216. - Lookup using pcall for better error handling http://www.computercraft.info/forums2/index.php?/topic/10992-using-pcall/ .
  217. - Update cruise mode to work independently for each actively-cooled reactor.
  218.  
  219. ]]--
  220.  
  221. -- allow chunks to load around us first
  222. print("Sleeping for 5 secs...")
  223. sleep(5.0)
  224.  
  225.  
  226. -- Some global variables
  227. local progVer = "0.3.13-p6"
  228. local progName = "NUKE-DC"
  229. local sideClick, xClick, yClick = nil, 0, 0
  230. local loopTime = 2
  231. local controlRodAdjustAmount = 1 -- Default Reactor Rod Control % adjustment amount
  232. local flowRateAdjustAmount = 25 -- Default Turbine Flow Rate in mB adjustment amount
  233. local debugMode = false
  234. -- End multi-reactor cleanup section
  235. local minStoredEnergyPercent = nil -- Max energy % to store before activate
  236. local maxStoredEnergyPercent = nil -- Max energy % to store before shutdown
  237. local monitorList = {} -- Empty monitor array
  238. local monitorNames = {} -- Empty array of monitor names
  239. local reactorList = {} -- Empty reactor array
  240. local reactorNames = {} -- Empty array of reactor names
  241. local turbineList = {} -- Empty turbine array
  242. local turbineNames = {} -- Empty array of turbine names
  243. local turbineMonitorOffset = 0 -- Turbines are assigned monitors after reactors
  244.  
  245. -- Hastwell's L33T Capbank Extended Buffer Graft [CEBG]
  246. local capBankList = {}
  247. -- local capBankMaxCapacity = 0
  248.  
  249.  
  250. term.clear()
  251. term.setCursorPos(2,1)
  252. write("Initializing program...\n")
  253.  
  254.  
  255. -- File needs to exist for append "a" later and zero it out if it already exists
  256. -- Always initalize this file to avoid confusion with old files and the latest run
  257. local logFile = fs.open("reactorcontrol.log", "w")
  258. if logFile then
  259.     logFile.writeLine("Minecraft time: Day "..os.day().." at "..textutils.formatTime(os.time(),true))
  260.     logFile.close()
  261. else
  262.     error("Could not open file reactorcontrol.log for writing.")
  263. end
  264.  
  265.  
  266. -- Helper functions
  267.  
  268. local function termNative()
  269.     -- term.native()
  270.     term.restore()
  271. end
  272.  
  273.  
  274. local function printLog(printStr)
  275.     if debugMode then
  276.         -- If multiple monitors, use the last monitor for debugging if debug is enabled
  277.         if #monitorList > 1 then
  278.             term.redirect(monitorList[#monitorList]) -- Redirect to last monitor for debugging
  279.             monitorList[#monitorList].setTextScale(0.5) -- Fit more logs on screen
  280.             write(printStr.."\n")   -- May need to use term.scroll(x) if we output too much, not sure
  281.             termNative()
  282.         end -- if #monitorList > 1 then
  283.  
  284.         local logFile = fs.open("reactorcontrol.log", "a") -- See http://computercraft.info/wiki/Fs.open
  285.         if logFile then
  286.             logFile.writeLine(printStr)
  287.             logFile.close()
  288.         else
  289.             error("Cannot open file reactorcontrol.log for appending!")
  290.         end -- if logFile then
  291.     end -- if debugMode then
  292. end -- function printLog(printStr)
  293.  
  294. -- Trim a string
  295. function stringTrim(s)
  296.     assert(s ~= nil, "String can't be nil")
  297.     return(string.gsub(s, "^%s*(.-)%s*$", "%1"))
  298. end
  299.  
  300. config = {}
  301.  
  302. -- Save a table into a config file
  303. -- path: path of the file to write
  304. -- tab: table to save
  305. config.save = function(path, tab)
  306.     printLog("Save function called for config for "..path.." EOL")
  307.     assert(path ~= nil, "Path can't be nil")
  308.     assert(type(tab) == "table", "Second parameter must be a table")
  309.     local f = io.open(path, "w")
  310.     local i = 0
  311.     for key, value in pairs(tab) do
  312.         if i ~= 0 then
  313.             f:write("\n")
  314.         end
  315.         f:write("["..key.."]".."\n")
  316.         for key2, value2 in pairs(tab[key]) do
  317.             key2 = stringTrim(key2)
  318.             --doesn't like boolean values
  319.             if (type(value2) ~= "boolean") then
  320.             value2 = stringTrim(value2)
  321.             else
  322.             value2 = tostring(value2)
  323.             end
  324.             key2 = key2:gsub(";", "\\;")
  325.             key2 = key2:gsub("=", "\\=")
  326.             value2 = value2:gsub(";", "\\;")
  327.             value2 = value2:gsub("=", "\\=")   
  328.             f:write(key2.."="..value2.."\n")
  329.         end
  330.         i = i + 1
  331.     end
  332.     f:close()
  333. end --config.save = function(path, tab)
  334.  
  335. -- Load a config file
  336. -- path: path of the file to read
  337. config.load = function(path)
  338.     printLog("Load function called for config for "..path.." EOL")
  339.     assert(path ~= nil, "Path can't be nil")
  340.     local f = fs.open(path, "r")
  341.     if f ~= nil then
  342.         local tab = {}
  343.         local line = ""
  344.         local newLine
  345.         local i
  346.         local currentTag = nil
  347.         local found = false
  348.         local pos = 0
  349.         while line ~= nil do
  350.             found = false      
  351.             line = line:gsub("\\;", "#_!36!_#") -- to keep \;
  352.             line = line:gsub("\\=", "#_!71!_#") -- to keep \=
  353.             if line ~= "" then
  354.                 -- Delete comments
  355.                 newLine = line
  356.                 line = ""
  357.                 for i=1, string.len(newLine) do            
  358.                     if string.sub(newLine, i, i) ~= ";" then
  359.                         line = line..newLine:sub(i, i)                     
  360.                     else               
  361.                         break
  362.                     end
  363.                 end
  364.                 line = stringTrim(line)
  365.                 -- Find tag        
  366.                 if line:sub(1, 1) == "[" and line:sub(line:len(), line:len()) == "]" then
  367.                     currentTag = stringTrim(line:sub(2, line:len()-1))
  368.                     tab[currentTag] = {}
  369.                     found = true                           
  370.                 end
  371.                 -- Find key and values
  372.                 if not found and line ~= "" then               
  373.                     pos = line:find("=")               
  374.                     if pos == nil then
  375.                         error("Bad INI file structure")
  376.                     end
  377.                     line = line:gsub("#_!36!_#", ";")
  378.                     line = line:gsub("#_!71!_#", "=")
  379.                     tab[currentTag][stringTrim(line:sub(1, pos-1))] = stringTrim(line:sub(pos+1, line:len()))
  380.                     found = true           
  381.                 end        
  382.             end
  383.             line = f.readLine()
  384.         end
  385.        
  386.         f:close()
  387.        
  388.         return tab
  389.     else
  390.         return nil
  391.     end
  392. end --config.load = function(path)
  393.  
  394.  
  395.  
  396. -- round() function from mechaet
  397. local function round(num, places)
  398.     local mult = 10^places
  399.     local addon = nil
  400.     if ((num * mult) < 0) then
  401.         addon = -.5
  402.     else
  403.         addon = .5
  404.     end
  405.  
  406.     local integer, decimal = math.modf(num*mult+addon)
  407.     newNum = integer/mult
  408.     printLog("Called round(num="..num..",places="..places..") returns \""..newNum.."\".")
  409.     return newNum
  410. end -- function round(num, places)
  411.  
  412.  
  413. local function print(printParams)
  414.     -- Default to xPos=1, yPos=1, and first monitor
  415.     setmetatable(printParams,{__index={xPos=1, yPos=1, monitorIndex=1}})
  416.     local printString, xPos, yPos, monitorIndex =
  417.         printParams[1], -- Required parameter
  418.         printParams[2] or printParams.xPos,
  419.         printParams[3] or printParams.yPos,
  420.         printParams[4] or printParams.monitorIndex
  421.  
  422.     local monitor = nil
  423.     monitor = monitorList[monitorIndex]
  424.  
  425.     if not monitor then
  426.         printLog("monitor["..monitorIndex.."] in print() is NOT a valid monitor.")
  427.         return -- Invalid monitorIndex
  428.     end
  429.  
  430.     monitor.setCursorPos(xPos, yPos)
  431.     monitor.write(printString)
  432. end -- function print(printParams)
  433.  
  434.  
  435. -- Replaces the one from FC_API (http://pastebin.com/A9hcbZWe) and adding multi-monitor support
  436. local function printCentered(printString, yPos, monitorIndex)
  437.     local monitor = nil
  438.     monitor = monitorList[monitorIndex]
  439.  
  440.     if not monitor then
  441.         printLog("monitor["..monitorIndex.."] in printCentered() is NOT a valid monitor.")
  442.         return -- Invalid monitorIndex
  443.     end
  444.  
  445.     local width, height = monitor.getSize()
  446.     local monitorNameLength = 0
  447.  
  448.     -- Special changes for title bar
  449.     if yPos == 1 then
  450.         -- Add monitor name to first line
  451.         monitorNameLength = monitorNames[monitorIndex]:len()
  452.  
  453.         -- Leave room for "offline" and "online" on the right except for overall status display
  454.         if (#monitorList ~= 1) and (monitorIndex ~= 1) then
  455.             width = width - 7
  456.         end
  457.     end
  458.  
  459.     monitor.setCursorPos(math.floor(width/2) - math.ceil(printString:len()/2) +  monitorNameLength/2, yPos)
  460.     monitor.clearLine()
  461.     monitor.write(printString)
  462.  
  463.     monitor.setTextColor(colors.blue)
  464.     print{monitorNames[monitorIndex], 1, 1, monitorIndex}
  465.     monitor.setTextColor(colors.white)
  466. end -- function printCentered(printString, yPos, monitorIndex)
  467.  
  468.  
  469. -- Print text padded from the left side
  470. -- Clear the left side of the screen
  471. local function printLeft(printString, yPos, monitorIndex)
  472.     local monitor = nil
  473.     monitor = monitorList[monitorIndex]
  474.  
  475.     if not monitor then
  476.         printLog("monitor["..monitorIndex.."] in printLeft() is NOT a valid monitor.")
  477.         return -- Invalid monitorIndex
  478.     end
  479.  
  480.     local gap = 1
  481.     local width = monitor.getSize()
  482.  
  483.     -- Clear left-half of the monitor
  484.  
  485.     for curXPos = 1, (width / 2) do
  486.         monitor.setCursorPos(curXPos, yPos)
  487.         monitor.write(" ")
  488.     end
  489.  
  490.     -- Write our string left-aligned
  491.     monitor.setCursorPos(1+gap, yPos)
  492.     monitor.write(printString)
  493. end
  494.  
  495.  
  496. -- Print text padded from the right side
  497. -- Clear the right side of the screen
  498. local function printRight(printString, yPos, monitorIndex)
  499.     local monitor = nil
  500.     monitor = monitorList[monitorIndex]
  501.  
  502.     if not monitor then
  503.         printLog("monitor["..monitorIndex.."] in printRight() is NOT a valid monitor.")
  504.         return -- Invalid monitorIndex
  505.     end
  506.  
  507.     -- Make sure printString is a string
  508.     printString = tostring(printString)
  509.  
  510.     local gap = 1
  511.     local width = monitor.getSize()
  512.  
  513.     -- Clear right-half of the monitor
  514.     for curXPos = (width/2), width do
  515.         monitor.setCursorPos(curXPos, yPos)
  516.         monitor.write(" ")
  517.     end
  518.  
  519.     -- Write our string right-aligned
  520.     monitor.setCursorPos(math.floor(width) - math.ceil(printString:len()+gap), yPos)
  521.     monitor.write(printString)
  522. end
  523.  
  524.  
  525. -- Replaces the one from FC_API (http://pastebin.com/A9hcbZWe) and adding multi-monitor support
  526. local function clearMonitor(printString, monitorIndex)
  527.     local monitor = nil
  528.     monitor = monitorList[monitorIndex]
  529.  
  530.     printLog("Called as clearMonitor(printString="..printString..",monitorIndex="..monitorIndex..").")
  531.  
  532.     if not monitor then
  533.         printLog("monitor["..monitorIndex.."] in clearMonitor(printString="..printString..",monitorIndex="..monitorIndex..") is NOT a valid monitor.")
  534.         return -- Invalid monitorIndex
  535.     end
  536.  
  537.     local gap = 2
  538.     monitor.clear()
  539.     local width, height = monitor.getSize()
  540.     monitor.setTextScale(1.0) -- Make sure scale is correct
  541.  
  542.     printCentered(printString, 1, monitorIndex)
  543.     monitor.setTextColor(colors.blue)
  544.     print{monitorNames[monitorIndex], 1, 1, monitorIndex}
  545.     monitor.setTextColor(colors.white)
  546.  
  547.     for i=1, width do
  548.         monitor.setCursorPos(i, gap)
  549.         monitor.write("-")
  550.     end
  551.  
  552.     monitor.setCursorPos(1, gap+1)
  553. end -- function clearMonitor(printString, monitorIndex)
  554.  
  555.  
  556. -- Return a list of all connected (including via wired modems) devices of "deviceType"
  557. local function getDevices(deviceType)
  558.     printLog("Called as getDevices(deviceType="..deviceType..")")
  559.  
  560.     local deviceName = nil
  561.     local deviceIndex = 1
  562.     local deviceList, deviceNames = {}, {} -- Empty array, which grows as we need
  563.     local peripheralList = peripheral.getNames() -- Get table of connected peripherals
  564.  
  565.     deviceType = deviceType:lower() -- Make sure we're matching case here
  566.  
  567.     for peripheralIndex = 1, #peripheralList do
  568.         -- Log every device found
  569.         -- printLog("Found "..peripheral.getType(peripheralList[peripheralIndex]).."["..peripheralIndex.."] attached as \""..peripheralList[peripheralIndex].."\".")
  570.         if (string.lower(peripheral.getType(peripheralList[peripheralIndex])) == deviceType) then
  571.             -- Log devices found which match deviceType and which device index we give them
  572.             printLog("Found "..peripheral.getType(peripheralList[peripheralIndex]).."["..peripheralIndex.."] as index \"["..deviceIndex.."]\" attached as \""..peripheralList[peripheralIndex].."\".")
  573.             write("Found "..peripheral.getType(peripheralList[peripheralIndex]).."["..peripheralIndex.."] as index \"["..deviceIndex.."]\" attached as \""..peripheralList[peripheralIndex].."\".\n")
  574.             deviceNames[deviceIndex] = peripheralList[peripheralIndex]
  575.             deviceList[deviceIndex] = peripheral.wrap(peripheralList[peripheralIndex])
  576.             deviceIndex = deviceIndex + 1
  577.         end
  578.     end -- for peripheralIndex = 1, #peripheralList do
  579.  
  580.     return deviceList, deviceNames
  581. end -- function getDevices(deviceType)
  582.  
  583. -- Draw a line across the entire x-axis
  584. local function drawLine(yPos, monitorIndex)
  585.     local monitor = nil
  586.     monitor = monitorList[monitorIndex]
  587.  
  588.     if not monitor then
  589.         printLog("monitor["..monitorIndex.."] in drawLine() is NOT a valid monitor.")
  590.         return -- Invalid monitorIndex
  591.     end
  592.  
  593.     local width, height = monitor.getSize()
  594.  
  595.     for i=1, width do
  596.         monitor.setCursorPos(i, yPos)
  597.         monitor.write("-")
  598.     end
  599. end -- function drawLine(yPos,monitorIndex)
  600.  
  601.  
  602. -- Display a solid bar of specified color
  603. local function drawBar(startXPos, startYPos, endXPos, endYPos, color, monitorIndex)
  604.     local monitor = nil
  605.     monitor = monitorList[monitorIndex]
  606.  
  607.     if not monitor then
  608.         printLog("monitor["..monitorIndex.."] in drawBar() is NOT a valid monitor.")
  609.         return -- Invalid monitorIndex
  610.     end
  611.  
  612.     -- PaintUtils only outputs to term., not monitor.
  613.     -- See http://www.computercraft.info/forums2/index.php?/topic/15540-paintutils-on-a-monitor/
  614.     term.redirect(monitor)
  615.     paintutils.drawLine(startXPos, startYPos, endXPos, endYPos, color)
  616.     monitor.setBackgroundColor(colors.black) -- PaintUtils doesn't restore the color
  617.     termNative()
  618. end -- function drawBar(startXPos, startYPos,endXPos,endYPos,color,monitorIndex)
  619.  
  620.  
  621. -- Display single pixel color
  622. local function drawPixel(xPos, yPos, color, monitorIndex)
  623.     local monitor = nil
  624.     monitor = monitorList[monitorIndex]
  625.  
  626.     if not monitor then
  627.         printLog("monitor["..monitorIndex.."] in drawPixel() is NOT a valid monitor.")
  628.         return -- Invalid monitorIndex
  629.     end
  630.  
  631.     -- PaintUtils only outputs to term., not monitor.
  632.     -- See http://www.computercraft.info/forums2/index.php?/topic/15540-paintutils-on-a-monitor/
  633.     term.redirect(monitor)
  634.     paintutils.drawPixel(xPos, yPos, color)
  635.     monitor.setBackgroundColor(colors.black) -- PaintUtils doesn't restore the color
  636.     termNative()
  637. end -- function drawPixel(xPos, yPos, color, monitorIndex)
  638.  
  639.  
  640. -- End helper functions
  641.  
  642.  
  643. -- Then initialize the monitors
  644. local function findMonitors()
  645.     -- Empty out old list of monitors
  646.     monitorList = {}
  647.  
  648.     printLog("Finding monitors...")
  649.     monitorList, monitorNames = getDevices("monitor")
  650.  
  651.     if #monitorList == 0 then
  652.         printLog("No monitors found!")
  653.         error("Can't find any monitors!")
  654.     else
  655.         for monitorIndex = 1, #monitorList do
  656.             local monitor, monitorX, monitorY = nil, nil, nil
  657.             monitor = monitorList[monitorIndex]
  658.  
  659.             if not monitor then
  660.                 printLog("monitorList["..monitorIndex.."] in findMonitors() is NOT a valid monitor.")
  661.  
  662.                 table.remove(monitorList, monitorIndex) -- Remove invalid monitor from list
  663.                 if monitorIndex ~= #monitorList then    -- If we're not at the end, clean up
  664.                     monitorIndex = monitorIndex - 1 -- We just removed an element
  665.                 end -- if monitorIndex == #monitorList then
  666.                 break -- Invalid monitorIndex
  667.             else -- valid monitor
  668.                 monitorX, monitorY = monitor.getSize()
  669.                 if (monitorX == nil) or (monitorY == nil) then -- somehow a valid monitor, but non-existent sizes? Maybe fixes Issue #3
  670.                     printLog("monitorList["..monitorIndex.."] in findMonitors() is NOT a valid sized monitor.")
  671.  
  672.                     table.remove(monitorList, monitorIndex) -- Remove invalid monitor from list
  673.                     if monitorIndex ~= #monitorList then    -- If we're not at the end, clean up
  674.                         monitorIndex = monitorIndex - 1 -- We just removed an element
  675.                     end -- if monitorIndex == #monitorList then
  676.                     break -- Invalid monitorIndex
  677.  
  678.                 -- Check for minimum size to allow for monitor.setTextScale(0.5) to work for 3x2 debugging monitor, changes getSize()
  679.                 elseif monitorX < 29 or monitorY < 12 then
  680.                     term.redirect(monitor)
  681.                     monitor.clear()
  682.                     printLog("Removing monitor "..monitorIndex.." for being too small.")
  683.                     monitor.setCursorPos(1,2)
  684.                     write("Monitor is the wrong size!\n")
  685.                     write("Needs to be at least 3x2.")
  686.                     termNative()
  687.  
  688.                     table.remove(monitorList, monitorIndex) -- Remove invalid monitor from list
  689.                     if monitorIndex == #monitorList then    -- If we're at the end already, break from loop
  690.                         break
  691.                     else
  692.                         monitorIndex = monitorIndex - 1 -- We just removed an element
  693.                     end -- if monitorIndex == #monitorList then
  694.  
  695.                 end -- if monitorX < 29 or monitorY < 12 then
  696.             end -- if not monitor then
  697.  
  698.             printLog("Monitor["..monitorIndex.."] named \""..monitorNames[monitorIndex].."\" is a valid monitor of size x:"..monitorX.." by y:"..monitorY..".")
  699.         end -- for monitorIndex = 1, #monitorList do
  700.     end -- if #monitorList == 0 then
  701.  
  702.     printLog("Found "..#monitorList.." monitor(s) in findMonitors().")
  703. end -- local function findMonitors()
  704.  
  705.  
  706. -- Initialize all Big Reactors - Reactors
  707. local function findReactors()
  708.     -- Empty out old list of reactors
  709.     newReactorList = {}
  710.     printLog("Finding reactors...")
  711.     newReactorList, reactorNames = getDevices("BigReactors-Reactor")
  712.  
  713.     if #newReactorList == 0 then
  714.         printLog("No reactors found!")
  715.         error("Can't find any reactors!")
  716.     else  -- Placeholder
  717.         for reactorIndex = 1, #newReactorList do
  718.             local reactor = nil
  719.             reactor = newReactorList[reactorIndex]
  720.  
  721.             if not reactor then
  722.                 printLog("reactorList["..reactorIndex.."] in findReactors() is NOT a valid Big Reactor.")
  723.  
  724.                 table.remove(newReactorList, reactorIndex) -- Remove invalid reactor from list
  725.                 if reactorIndex ~= #newReactorList then    -- If we're not at the end, clean up
  726.                     reactorIndex = reactorIndex - 1 -- We just removed an element
  727.                 end -- reactorIndex ~= #newReactorList then
  728.                 return -- Invalid reactorIndex
  729.             else
  730.                 printLog("reactor["..reactorIndex.."] in findReactors() is a valid Big Reactor.")
  731.                 --initialize the default table
  732.                 _G[reactorNames[reactorIndex]] = {}
  733.                 _G[reactorNames[reactorIndex]]["ReactorOptions"] = {}
  734.                 _G[reactorNames[reactorIndex]]["ReactorOptions"]["baseControlRodLevel"] = 80
  735.                 _G[reactorNames[reactorIndex]]["ReactorOptions"]["lastTempPoll"] = 0
  736.                 _G[reactorNames[reactorIndex]]["ReactorOptions"]["autoStart"] = true
  737.                 _G[reactorNames[reactorIndex]]["ReactorOptions"]["activeCooled"] = true
  738.                 _G[reactorNames[reactorIndex]]["ReactorOptions"]["reactorMaxTemp"] = 1400 --set for passive-cooled, the active-cooled subroutine will correct it
  739.                 _G[reactorNames[reactorIndex]]["ReactorOptions"]["reactorMinTemp"] = 1000
  740.                 _G[reactorNames[reactorIndex]]["ReactorOptions"]["rodOverride"] = false
  741.                 _G[reactorNames[reactorIndex]]["ReactorOptions"]["reactorName"] = reactorNames[reactorIndex]
  742.                 _G[reactorNames[reactorIndex]]["ReactorOptions"]["reactorCruising"] = false
  743.                 if reactor.getConnected() then
  744.                     printLog("reactor["..reactorIndex.."] in findReactors() is connected.")
  745.                 else
  746.                     printLog("reactor["..reactorIndex.."] in findReactors() is NOT connected.")
  747.                     return -- Disconnected reactor
  748.                 end
  749.             end
  750.            
  751.             --failsafe
  752.             local tempTable = _G[reactorNames[reactorIndex]]
  753.            
  754.             --check to make sure we get a valid config
  755.             if (config.load(reactorNames[reactorIndex]..".options")) ~= nil then
  756.                 tempTable = config.load(reactorNames[reactorIndex]..".options")
  757.             else
  758.                 --if we don't have a valid config from disk, make a valid config
  759.                 config.save(reactorNames[reactorIndex]..".options", _G[reactorNames[reactorIndex]])
  760.             end
  761.            
  762.             --load values from tempTable, checking for nil values along the way
  763.             if tempTable["ReactorOptions"]["baseControlRodLevel"] ~= nil then
  764.                 _G[reactorNames[reactorIndex]]["ReactorOptions"]["baseControlRodLevel"] = tempTable["ReactorOptions"]["baseControlRodLevel"]
  765.             end
  766.            
  767.             if tempTable["ReactorOptions"]["lastTempPoll"] ~= nil then
  768.                 _G[reactorNames[reactorIndex]]["ReactorOptions"]["lastTempPoll"] = tempTable["ReactorOptions"]["lastTempPoll"]
  769.             end
  770.            
  771.             if tempTable["ReactorOptions"]["autoStart"] ~= nil then
  772.                 _G[reactorNames[reactorIndex]]["ReactorOptions"]["autoStart"] = tempTable["ReactorOptions"]["autoStart"]
  773.             end
  774.            
  775.             if tempTable["ReactorOptions"]["activeCooled"] ~= nil then
  776.                 _G[reactorNames[reactorIndex]]["ReactorOptions"]["activeCooled"] = tempTable["ReactorOptions"]["activeCooled"]
  777.             end
  778.            
  779.             if tempTable["ReactorOptions"]["reactorMaxTemp"] ~= nil then
  780.                 _G[reactorNames[reactorIndex]]["ReactorOptions"]["reactorMaxTemp"] = tempTable["ReactorOptions"]["reactorMaxTemp"]
  781.             end
  782.            
  783.             if tempTable["ReactorOptions"]["reactorMinTemp"] ~= nil then
  784.                 _G[reactorNames[reactorIndex]]["ReactorOptions"]["reactorMinTemp"] = tempTable["ReactorOptions"]["reactorMinTemp"]
  785.             end
  786.            
  787.             if tempTable["ReactorOptions"]["rodOverride"] ~= nil then
  788.                 printLog("Got value from config file for Rod Override, the value is: "..tostring(tempTable["ReactorOptions"]["rodOverride"]).." EOL")
  789.                 _G[reactorNames[reactorIndex]]["ReactorOptions"]["rodOverride"] = tempTable["ReactorOptions"]["rodOverride"]
  790.             end
  791.            
  792.             if tempTable["ReactorOptions"]["reactorName"] ~= nil then
  793.                 _G[reactorNames[reactorIndex]]["ReactorOptions"]["reactorName"] = tempTable["ReactorOptions"]["reactorName"]
  794.             end
  795.            
  796.             if tempTable["ReactorOptions"]["reactorCruising"] ~= nil then
  797.                 _G[reactorNames[reactorIndex]]["ReactorOptions"]["reactorCruising"] = tempTable["ReactorOptions"]["reactorCruising"]
  798.             end
  799.            
  800.             --stricter typing, let's set these puppies up with the right type of value.
  801.             _G[reactorNames[reactorIndex]]["ReactorOptions"]["baseControlRodLevel"] = tonumber(_G[reactorNames[reactorIndex]]["ReactorOptions"]["baseControlRodLevel"])
  802.            
  803.             _G[reactorNames[reactorIndex]]["ReactorOptions"]["lastTempPoll"] = tonumber(_G[reactorNames[reactorIndex]]["ReactorOptions"]["lastTempPoll"])
  804.            
  805.             if (tostring(_G[reactorNames[reactorIndex]]["ReactorOptions"]["autoStart"]) == "true") then
  806.                 _G[reactorNames[reactorIndex]]["ReactorOptions"]["autoStart"] = true
  807.             else
  808.                 _G[reactorNames[reactorIndex]]["ReactorOptions"]["autoStart"] = false
  809.             end
  810.            
  811.             if (tostring(_G[reactorNames[reactorIndex]]["ReactorOptions"]["activeCooled"]) == "true") then
  812.                 _G[reactorNames[reactorIndex]]["ReactorOptions"]["activeCooled"] = true
  813.             else
  814.                 _G[reactorNames[reactorIndex]]["ReactorOptions"]["activeCooled"] = false
  815.             end
  816.            
  817.             _G[reactorNames[reactorIndex]]["ReactorOptions"]["reactorMaxTemp"] = tonumber(_G[reactorNames[reactorIndex]]["ReactorOptions"]["reactorMaxTemp"])
  818.            
  819.             _G[reactorNames[reactorIndex]]["ReactorOptions"]["reactorMinTemp"] = tonumber(_G[reactorNames[reactorIndex]]["ReactorOptions"]["reactorMinTemp"])
  820.            
  821.             if (tostring(_G[reactorNames[reactorIndex]]["ReactorOptions"]["rodOverride"]) == "true") then
  822.                 printLog("Setting Rod Override for  "..reactorNames[reactorIndex].." to true because value was "..tostring(_G[reactorNames[reactorIndex]]["ReactorOptions"]["rodOverride"]).." EOL")
  823.                 _G[reactorNames[reactorIndex]]["ReactorOptions"]["rodOverride"] = true
  824.             else
  825.                 printLog("Setting Rod Override for  "..reactorNames[reactorIndex].." to false because value was "..tostring(_G[reactorNames[reactorIndex]]["ReactorOptions"]["rodOverride"]).." EOL")
  826.                 _G[reactorNames[reactorIndex]]["ReactorOptions"]["rodOverride"] = false
  827.             end
  828.            
  829.             if (tostring(_G[reactorNames[reactorIndex]]["ReactorOptions"]["reactorCruising"]) == "true") then
  830.                 _G[reactorNames[reactorIndex]]["ReactorOptions"]["reactorCruising"] = true
  831.             else
  832.                 _G[reactorNames[reactorIndex]]["ReactorOptions"]["reactorCruising"] = false
  833.             end
  834.                        
  835.             --save one more time, in case we didn't have a complete config file before
  836.             config.save(reactorNames[reactorIndex]..".options", _G[reactorNames[reactorIndex]])
  837.         end -- for reactorIndex = 1, #newReactorList do
  838.     end -- if #newReactorList == 0 then
  839.  
  840.     -- Overwrite old reactor list with the now updated list
  841.     reactorList = newReactorList
  842.  
  843.     -- Start turbine monitor offset after reactors get monitors
  844.     -- This assumes that there is a monitor for each turbine and reactor, plus the overall monitor display
  845.     turbineMonitorOffset = #reactorList + 1 -- #turbineList will start at "1" if turbines found and move us just beyond #reactorList and status monitor range
  846.  
  847.     printLog("Found "..#reactorList.." reactor(s) in findReactors().")
  848.     printLog("Set turbineMonitorOffset to "..turbineMonitorOffset.." in findReactors().")
  849. end -- function findReactors()
  850.  
  851.  
  852. -- Initialize all Big Reactors - Turbines
  853. local function findTurbines()
  854.     -- Empty out old list of turbines
  855.     newTurbineList = {}
  856.  
  857.     printLog("Finding turbines...")
  858.     newTurbineList, turbineNames = getDevices("BigReactors-Turbine")
  859.  
  860.     if #newTurbineList == 0 then
  861.         printLog("No turbines found") -- Not an error
  862.     else
  863.         for turbineIndex = 1, #newTurbineList do
  864.             local turbine = nil
  865.             turbine = newTurbineList[turbineIndex]
  866.  
  867.             if not turbine then
  868.                 printLog("turbineList["..turbineIndex.."] in findTurbines() is NOT a valid Big Reactors Turbine.")
  869.  
  870.                 table.remove(newTurbineList, turbineIndex) -- Remove invalid turbine from list
  871.                 if turbineIndex ~= #newTurbineList then    -- If we're not at the end, clean up
  872.                     turbineIndex = turbineIndex - 1 -- We just removed an element
  873.                 end -- turbineIndex ~= #newTurbineList then
  874.  
  875.                 return -- Invalid turbineIndex
  876.             else
  877.            
  878.                 _G[turbineNames[turbineIndex]] = {}
  879.                 _G[turbineNames[turbineIndex]]["TurbineOptions"] = {}
  880.                 _G[turbineNames[turbineIndex]]["TurbineOptions"]["LastSpeed"] = 0
  881.                 _G[turbineNames[turbineIndex]]["TurbineOptions"]["BaseSpeed"] = 2726
  882.                 _G[turbineNames[turbineIndex]]["TurbineOptions"]["autoStart"] = true
  883.                 _G[turbineNames[turbineIndex]]["TurbineOptions"]["LastFlow"] = 2000 --open up with all the steam wide open
  884.                 _G[turbineNames[turbineIndex]]["TurbineOptions"]["flowOverride"] = false
  885.                 _G[turbineNames[turbineIndex]]["TurbineOptions"]["turbineName"] = turbineNames[turbineIndex]
  886.                 printLog("turbineList["..turbineIndex.."] in findTurbines() is a valid Big Reactors Turbine.")
  887.                 if turbine.getConnected() then
  888.                     printLog("turbine["..turbineIndex.."] in findTurbines() is connected.")
  889.                 else
  890.                     printLog("turbine["..turbineIndex.."] in findTurbines() is NOT connected.")
  891.                     return -- Disconnected turbine
  892.                 end
  893.             end
  894.            
  895.             --failsafe
  896.             local tempTable = _G[turbineNames[turbineIndex]]
  897.            
  898.             --check to make sure we get a valid config
  899.             if (config.load(turbineNames[turbineIndex]..".options")) ~= nil then
  900.                 tempTable = config.load(turbineNames[turbineIndex]..".options")
  901.             else
  902.                 --if we don't have a valid config from disk, make a valid config
  903.                 config.save(turbineNames[turbineIndex]..".options", _G[turbineNames[turbineIndex]])
  904.             end
  905.            
  906.             --load values from tempTable, checking for nil values along the way
  907.             if tempTable["TurbineOptions"]["LastSpeed"] ~= nil then
  908.                 _G[turbineNames[turbineIndex]]["TurbineOptions"]["LastSpeed"] = tempTable["TurbineOptions"]["LastSpeed"]
  909.             end
  910.            
  911.             if tempTable["TurbineOptions"]["BaseSpeed"] ~= nil then
  912.                 _G[turbineNames[turbineIndex]]["TurbineOptions"]["BaseSpeed"] = tempTable["TurbineOptions"]["BaseSpeed"]
  913.             end
  914.            
  915.             if tempTable["TurbineOptions"]["autoStart"] ~= nil then
  916.                 _G[turbineNames[turbineIndex]]["TurbineOptions"]["autoStart"] = tempTable["TurbineOptions"]["autoStart"]
  917.             end
  918.            
  919.             if tempTable["TurbineOptions"]["LastFlow"] ~= nil then
  920.                 _G[turbineNames[turbineIndex]]["TurbineOptions"]["LastFlow"] = tempTable["TurbineOptions"]["LastFlow"]
  921.             end
  922.            
  923.             if tempTable["TurbineOptions"]["flowOverride"] ~= nil then
  924.                 _G[turbineNames[turbineIndex]]["TurbineOptions"]["flowOverride"] = tempTable["TurbineOptions"]["flowOverride"]
  925.             end
  926.            
  927.             if tempTable["TurbineOptions"]["turbineName"] ~= nil then
  928.                 _G[turbineNames[turbineIndex]]["TurbineOptions"]["turbineName"] = tempTable["TurbineOptions"]["turbineName"]
  929.             end
  930.            
  931.             --save once more just to make sure we got it
  932.             config.save(turbineNames[turbineIndex]..".options", _G[turbineNames[turbineIndex]])
  933.         end -- for turbineIndex = 1, #newTurbineList do
  934.  
  935.         -- Overwrite old turbine list with the now updated list
  936.         turbineList = newTurbineList
  937.     end -- if #newTurbineList == 0 then
  938.  
  939.     printLog("Found "..#turbineList.." turbine(s) in findTurbines().")
  940. end -- function findTurbines()
  941.  
  942. -- Hastwell's Capbank Extended Buffer Graft [CEBG]
  943. local function findCapBanks()
  944.     printLog("Finding capbanks...")
  945.     newCapbankList, capbankNames = getDevices("tile_enderio_blockcapacitorbank_name")
  946.     --capBankMaxCapacity = 0
  947.    
  948.     if #newCapbankList == 0 then
  949.         printLog("No capbanks found") -- Not an error
  950.     --else
  951.     --  for capIndex = 1, #newCapbankList do
  952.     --      capBankMaxCapacity = capBankMaxCapacity + newCapbankList[capIndex].getMaxEnergyStored('')
  953.     --  end
  954.     end
  955.     capBankList = newCapbankList
  956. end
  957.  
  958. local function getCapbanksTotalCharge()
  959.     local currentCharge = 0
  960.     local maxCapacity = 0
  961.     for capIndex = 1, #capBankList do
  962.         currCap = capBankList[capIndex]
  963.         currentCharge = currentCharge + currCap.getEnergyStored('')
  964.         maxCapacity = maxCapacity + currCap.getMaxEnergyStored('')
  965.     end
  966.     return currentCharge, maxCapacity
  967. end
  968.  
  969. -- Return current energy buffer in a specific reactor by %
  970. local function getReactorStoredEnergyBufferPercent(reactor)
  971.     printLog("Called as getReactorStoredEnergyBufferPercent(reactor).")
  972.  
  973.     if not reactor then
  974.         printLog("getReactorStoredEnergyBufferPercent() did NOT receive a valid Big Reactor Reactor.")
  975.         return -- Invalid reactorIndex
  976.     else
  977.         printLog("getReactorStoredEnergyBufferPercent() did receive a valid Big Reactor Reactor.")
  978.     end
  979.  
  980.     local energyBufferStorage = reactor.getEnergyStored()
  981.     local capCharge, capMax = getCapbanksTotalCharge()
  982.     return round( (energyBufferStorage+capCharge) / (10000000+capMax) * 100, 1) -- (buffer/10000000 RF)*100%
  983. end -- function getReactorStoredEnergyBufferPercent(reactor)
  984.  
  985.  
  986. -- Return current energy buffer in a specific Turbine by %
  987. local function getTurbineStoredEnergyBufferPercent(turbine)
  988.     printLog("Called as getTurbineStoredEnergyBufferPercent(turbine)")
  989.  
  990.     if not turbine then
  991.         printLog("getTurbineStoredEnergyBufferPercent() did NOT receive a valid Big Reactor Turbine.")
  992.         return -- Invalid reactorIndex
  993.     else
  994.         printLog("getTurbineStoredEnergyBufferPercent() did receive a valid Big Reactor Turbine.")
  995.     end
  996.  
  997.     local energyBufferStorage = turbine.getEnergyStored()
  998.     local capCharge, capMax = getCapbanksTotalCharge()
  999.     return round( (energyBufferStorage+capCharge) / (1000000+capMax) * 100, 1) -- (buffer/1000000 RF)*100%
  1000. end -- function getTurbineStoredEnergyBufferPercent(turbine)
  1001.  
  1002. local function reactorCruise(cruiseMaxTemp, cruiseMinTemp, reactorIndex)
  1003.     printLog("Called as reactorCruise(cruiseMaxTemp="..cruiseMaxTemp..",cruiseMinTemp="..cruiseMinTemp..",lastPolledTemp=".._G[reactorNames[reactorIndex]]["ReactorOptions"]["lastTempPoll"]..",reactorIndex="..reactorIndex..").")
  1004.    
  1005.     --sanitization
  1006.     local lastPolledTemp = tonumber(_G[reactorNames[reactorIndex]]["ReactorOptions"]["lastTempPoll"])
  1007.     cruiseMaxTemp = tonumber(cruiseMaxTemp)
  1008.     cruiseMinTemp = tonumber(cruiseMinTemp)
  1009.    
  1010.     if ((lastPolledTemp < cruiseMaxTemp) and (lastPolledTemp > cruiseMinTemp)) then
  1011.         local reactor = nil
  1012.         reactor = reactorList[reactorIndex]
  1013.         if not reactor then
  1014.             printLog("reactor["..reactorIndex.."] in reactorCruise(cruiseMaxTemp="..cruiseMaxTemp..",cruiseMinTemp="..cruiseMinTemp..",lastPolledTemp="..lastPolledTemp..",reactorIndex="..reactorIndex..") is NOT a valid Big Reactor.")
  1015.             return -- Invalid reactorIndex
  1016.         else
  1017.             printLog("reactor["..reactorIndex.."] in reactorCruise(cruiseMaxTemp="..cruiseMaxTemp..",cruiseMinTemp="..cruiseMinTemp..",lastPolledTemp="..lastPolledTemp..",reactorIndex="..reactorIndex..") is a valid Big Reactor.")
  1018.             if reactor.getConnected() then
  1019.                 printLog("reactor["..reactorIndex.."] in reactorCruise(cruiseMaxTemp="..cruiseMaxTemp..",cruiseMinTemp="..cruiseMinTemp..",lastPolledTemp="..lastPolledTemp..",reactorIndex="..reactorIndex..") is connected.")
  1020.             else
  1021.                 printLog("reactor["..reactorIndex.."] in reactorCruise(cruiseMaxTemp="..cruiseMaxTemp..",cruiseMinTemp="..cruiseMinTemp..",lastPolledTemp="..lastPolledTemp..",reactorIndex="..reactorIndex..") is NOT connected.")
  1022.                 return -- Disconnected reactor
  1023.             end -- if reactor.getConnected() then
  1024.         end -- if not reactor then
  1025.  
  1026.         local rodPercentage = math.ceil(reactor.getControlRodLevel(0))
  1027.         local reactorTemp = math.ceil(reactor.getFuelTemperature())
  1028.         _G[reactorNames[reactorIndex]]["ReactorOptions"]["baseControlRodLevel"] = rodPercentage
  1029.        
  1030.         if ((reactorTemp < cruiseMaxTemp) and (reactorTemp > cruiseMinTemp)) then
  1031.             if (reactorTemp < lastPolledTemp) then
  1032.                 rodPercentage = (rodPercentage - 1)
  1033.                 --Boundary check
  1034.                 if rodPercentage < 0 then
  1035.                     reactor.setAllControlRodLevels(0)
  1036.                 else
  1037.                     reactor.setAllControlRodLevels(rodPercentage)
  1038.                 end
  1039.             else
  1040.                 rodPercentage = (rodPercentage + 1)
  1041.                 --Boundary check
  1042.                 if rodPercentage > 99 then
  1043.                     reactor.setAllControlRodLevels(99)
  1044.                 else
  1045.                     reactor.setAllControlRodLevels(rodPercentage)
  1046.                 end
  1047.             end -- if (reactorTemp > lastPolledTemp) then
  1048.         else
  1049.             --disengage cruise, we've fallen out of the ideal temperature range
  1050.             _G[reactorNames[reactorIndex]]["ReactorOptions"]["reactorCruising"] = false
  1051.         end -- if ((reactorTemp < cruiseMaxTemp) and (reactorTemp > cruiseMinTemp)) then
  1052.     else
  1053.         --I don't know how we'd get here, but let's turn the cruise mode off
  1054.         _G[reactorNames[reactorIndex]]["ReactorOptions"]["reactorCruising"] = false
  1055.     end -- if ((lastPolledTemp < cruiseMaxTemp) and (lastPolledTemp > cruiseMinTemp)) then
  1056.     _G[reactorNames[reactorIndex]]["ReactorOptions"]["lastTempPoll"] = reactorTemp
  1057.     _G[reactorNames[reactorIndex]]["ReactorOptions"]["activeCooled"] = true
  1058.     _G[reactorNames[reactorIndex]]["ReactorOptions"]["reactorMaxTemp"] = cruiseMaxTemp
  1059.     _G[reactorNames[reactorIndex]]["ReactorOptions"]["reactorMinTemp"] = cruiseMinTemp
  1060.     config.save(reactorNames[reactorIndex]..".options", _G[reactorNames[reactorIndex]])
  1061. end -- function reactorCruise(cruiseMaxTemp, cruiseMinTemp, lastPolledTemp, reactorIndex)
  1062.  
  1063. -- Modify reactor control rod levels to keep temperature with defined parameters, but
  1064. -- wait an in-game half-hour for the temperature to stabalize before modifying again
  1065. local function temperatureControl(reactorIndex)
  1066.     printLog("Called as temperatureControl(reactorIndex="..reactorIndex..")")
  1067.  
  1068.     local reactor = nil
  1069.     reactor = reactorList[reactorIndex]
  1070.     if not reactor then
  1071.         printLog("reactor["..reactorIndex.."] in temperatureControl(reactorIndex="..reactorIndex..") is NOT a valid Big Reactor.")
  1072.         return -- Invalid reactorIndex
  1073.     else
  1074.         printLog("reactor["..reactorIndex.."] in temperatureControl(reactorIndex="..reactorIndex..") is a valid Big Reactor.")
  1075.  
  1076.         if reactor.getConnected() then
  1077.             printLog("reactor["..reactorIndex.."] in temperatureControl(reactorIndex="..reactorIndex..") is connected.")
  1078.         else
  1079.             printLog("reactor["..reactorIndex.."] in temperatureControl(reactorIndex="..reactorIndex..") is NOT connected.")
  1080.             return -- Disconnected reactor
  1081.         end -- if reactor.getConnected() then
  1082.     end
  1083.  
  1084.     local reactorNum = reactorIndex
  1085.     local rodPercentage = math.ceil(reactor.getControlRodLevel(0))
  1086.     local reactorTemp = math.ceil(reactor.getFuelTemperature())
  1087.     local localMinReactorTemp, localMaxReactorTemp = _G[reactorNames[reactorIndex]]["ReactorOptions"]["reactorMinTemp"], _G[reactorNames[reactorIndex]]["ReactorOptions"]["reactorMaxTemp"]
  1088.  
  1089.     --bypass if the reactor itself is set to not be auto-controlled
  1090.     if ((not _G[reactorNames[reactorIndex]]["ReactorOptions"]["rodOverride"]) or (_G[reactorNames[reactorIndex]]["ReactorOptions"]["rodOverride"] == "false")) then
  1091.         -- No point modifying control rod levels for temperature if the reactor is offline
  1092.         if reactor.getActive() then
  1093.             -- Actively cooled reactors should range between 0^C-300^C
  1094.             -- Actually, active-cooled reactors should range between 300 and 420C (Mechaet)
  1095.             -- Accordingly I changed the below lines
  1096.             if reactor.isActivelyCooled() then
  1097.                 -- below was 0
  1098.                 localMinReactorTemp = 300
  1099.                 -- below was 300
  1100.                 localMaxReactorTemp = 420
  1101.             else
  1102.                 localMinReactorTemp = _G[reactorNames[reactorIndex]]["ReactorOptions"]["reactorMinTemp"]
  1103.                 localMaxReactorTemp = _G[reactorNames[reactorIndex]]["ReactorOptions"]["reactorMaxTemp"]
  1104.             end
  1105.             local lastTempPoll = _G[reactorNames[reactorIndex]]["ReactorOptions"]["lastTempPoll"]
  1106.             if _G[reactorNames[reactorIndex]]["ReactorOptions"]["reactorCruising"] then
  1107.                 --let's bypass all this math and hit the much-more-subtle cruise feature
  1108.                 --printLog("min: "..localMinReactorTemp..", max: "..localMaxReactorTemp..", lasttemp: "..lastTempPoll..", ri: "..reactorIndex.."  EOL")
  1109.                 reactorCruise(localMaxReactorTemp, localMinReactorTemp, reactorIndex)
  1110.             else
  1111.                 -- Don't bring us to 100, that's effectively a shutdown
  1112.                 if (reactorTemp > localMaxReactorTemp) and (rodPercentage ~= 99) then
  1113.                     --increase the rods, but by how much?
  1114.                     if (reactorTemp > lastTempPoll) then
  1115.                         --we're climbing, we need to get this to decrease
  1116.                         if ((reactorTemp - lastTempPoll) > 100) then
  1117.                             --we're climbing really fast, arrest it
  1118.                             if (rodPercentage + (10 * controlRodAdjustAmount)) > 99 then
  1119.                                 reactor.setAllControlRodLevels(99)
  1120.                             else
  1121.                                 reactor.setAllControlRodLevels(rodPercentage + (10 * controlRodAdjustAmount))
  1122.                             end
  1123.                         else
  1124.                             --we're not climbing by leaps and bounds, let's give it a rod adjustment based on temperature increase
  1125.                             local diffAmount = reactorTemp - lastTempPoll
  1126.                             diffAmount = (round(diffAmount/10, 0))/5
  1127.                             controlRodAdjustAmount = diffAmount
  1128.                             if (rodPercentage + controlRodAdjustAmount) > 99 then
  1129.                                 reactor.setAllControlRodLevels(99)
  1130.                             else
  1131.                                 reactor.setAllControlRodLevels(rodPercentage + controlRodAdjustAmount)
  1132.                             end
  1133.                         end --if ((reactorTemp - lastTempPoll) > 100) then
  1134.                     elseif (reactorTemp == lastTempPoll) then
  1135.                         --temperature has stagnated, kick it very lightly
  1136.                         local controlRodAdjustment = 1
  1137.                         if (rodPercentage + controlRodAdjustment) > 99 then
  1138.                             reactor.setAllControlRodLevels(99)
  1139.                         else
  1140.                             reactor.setAllControlRodLevels(rodPercentage + controlRodAdjustment)
  1141.                         end
  1142.                     end --if (reactorTemp > lastTempPoll) then
  1143.                         --worth noting that if we're above temp but decreasing, we do nothing. let it continue decreasing.
  1144.  
  1145.                 elseif (reactorTemp < localMinReactorTemp) and (rodPercentage ~=0) then
  1146.                     --we're too cold. time to warm up, but by how much?
  1147.                     if (reactorTemp < lastTempPoll) then
  1148.                         --we're descending, let's stop that.
  1149.                         if ((lastTempPoll - reactorTemp) > 100) then
  1150.                             --we're headed for a new ice age, bring the heat
  1151.                             if (rodPercentage - (10 * controlRodAdjustAmount)) < 0 then
  1152.                                 reactor.setAllControlRodLevels(0)
  1153.                             else
  1154.                                 reactor.setAllControlRodLevels(rodPercentage - (10 * controlRodAdjustAmount))
  1155.                             end
  1156.                         else
  1157.                             --we're not descending quickly, let's bump it based on descent rate
  1158.                             local diffAmount = lastTempPoll - reactorTemp
  1159.                             diffAmount = (round(diffAmount/10, 0))/5
  1160.                             controlRodAdjustAmount = diffAmount
  1161.                             if (rodPercentage - controlRodAdjustAmount) < 0 then
  1162.                                 reactor.setAllControlRodLevels(0)
  1163.                             else
  1164.                                 reactor.setAllControlRodLevels(rodPercentage - controlRodAdjustAmount)
  1165.                             end
  1166.                         end --if ((lastTempPoll - reactorTemp) > 100) then
  1167.                     elseif (reactorTemp == lastTempPoll) then
  1168.                         --temperature has stagnated, kick it very lightly
  1169.                         local controlRodAdjustment = 1
  1170.                         if (rodPercentage - controlRodAdjustment) < 0 then
  1171.                             reactor.setAllControlRodLevels(0)
  1172.                         else
  1173.                             reactor.setAllControlRodLevels(rodPercentage - controlRodAdjustment)
  1174.                         end --if (rodPercentage - controlRodAdjustment) < 0 then
  1175.  
  1176.                     end --if (reactorTemp < lastTempPoll) then
  1177.                     --if we're below temp but increasing, do nothing and let it continue to rise.
  1178.                 end --if (reactorTemp > localMaxReactorTemp) and (rodPercentage ~= 99) then
  1179.  
  1180.                 if ((reactorTemp > localMinReactorTemp) and (reactorTemp < localMaxReactorTemp)) then
  1181.                     --engage cruise mode
  1182.                     _G[reactorNames[reactorIndex]]["ReactorOptions"]["reactorCruising"] = true
  1183.                 end -- if ((reactorTemp > localMinReactorTemp) and (reactorTemp < localMaxReactorTemp)) then
  1184.             end -- if reactorCruising then
  1185.             --always set this number
  1186.             _G[reactorNames[reactorIndex]]["ReactorOptions"]["lastTempPoll"] = reactorTemp
  1187.             config.save(reactorNames[reactorIndex]..".options", _G[reactorNames[reactorIndex]])
  1188.         end -- if reactor.getActive() then
  1189.     else
  1190.         printLog("Bypassed temperature control due to rodOverride being "..tostring(_G[reactorNames[reactorIndex]]["ReactorOptions"]["rodOverride"]).." EOL")
  1191.     end -- if not _G[reactorNames[reactorIndex]]["ReactorOptions"]["rodOverride"] then
  1192. end -- function temperatureControl(reactorIndex)
  1193.  
  1194. -- Load saved reactor parameters if ReactorOptions file exists
  1195. local function loadReactorOptions()
  1196.     local reactorOptions = fs.open("ReactorOptions", "r") -- See http://computercraft.info/wiki/Fs.open
  1197.  
  1198.     if reactorOptions then
  1199.         -- The following values were added by Lolmer
  1200.         minStoredEnergyPercent = reactorOptions.readLine()
  1201.         maxStoredEnergyPercent = reactorOptions.readLine()
  1202.         --added by Mechaet
  1203.         -- If we succeeded in reading a string, convert it to a number
  1204.  
  1205.         if minStoredEnergyPercent ~= nil then
  1206.             minStoredEnergyPercent = tonumber(minStoredEnergyPercent)
  1207.         end
  1208.  
  1209.         if maxStoredEnergyPercent ~= nil then
  1210.             maxStoredEnergyPercent = tonumber(maxStoredEnergyPercent)
  1211.         end
  1212.  
  1213.         reactorOptions.close()
  1214.     end -- if reactorOptions then
  1215.  
  1216.     -- Set default values if we failed to read any of the above
  1217.     if minStoredEnergyPercent == nil then
  1218.         minStoredEnergyPercent = 15
  1219.     end
  1220.  
  1221.     if maxStoredEnergyPercent == nil then
  1222.         maxStoredEnergyPercent = 85
  1223.     end
  1224.  
  1225. end -- function loadReactorOptions()
  1226.  
  1227.  
  1228. -- Save our reactor parameters
  1229. local function saveReactorOptions()
  1230.     local reactorOptions = fs.open("ReactorOptions", "w") -- See http://computercraft.info/wiki/Fs.open
  1231.  
  1232.     -- If we can save the files, save them
  1233.     if reactorOptions then
  1234.         local reactorIndex = 1
  1235.         -- The following values were added by Lolmer
  1236.         reactorOptions.writeLine(minStoredEnergyPercent)
  1237.         reactorOptions.writeLine(maxStoredEnergyPercent)
  1238.         reactorOptions.close()
  1239.     else
  1240.         printLog("Failed to open file ReactorOptions for writing!")
  1241.     end -- if reactorOptions then
  1242. end -- function saveReactorOptions()
  1243.  
  1244.  
  1245. local function displayReactorBars(barParams)
  1246.     -- Default to first reactor and first monitor
  1247.     setmetatable(barParams,{__index={reactorIndex=1, monitorIndex=1}})
  1248.     local reactorIndex, monitorIndex =
  1249.         barParams[1] or barParams.reactorIndex,
  1250.         barParams[2] or barParams.monitorIndex
  1251.  
  1252.     printLog("Called as displayReactorBars(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..").")
  1253.  
  1254.     -- Grab current monitor
  1255.     local monitor = nil
  1256.     monitor = monitorList[monitorIndex]
  1257.     if not monitor then
  1258.         printLog("monitor["..monitorIndex.."] in displayReactorBars(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..") is NOT a valid monitor.")
  1259.         return -- Invalid monitorIndex
  1260.     end
  1261.  
  1262.     -- Grab current reactor
  1263.     local reactor = nil
  1264.     reactor = reactorList[reactorIndex]
  1265.     if not reactor then
  1266.         printLog("reactor["..reactorIndex.."] in displayReactorBars(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..") is NOT a valid Big Reactor.")
  1267.         return -- Invalid reactorIndex
  1268.     else
  1269.         printLog("reactor["..reactorIndex.."] in displayReactorBars(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..") is a valid Big Reactor.")
  1270.         if reactor.getConnected() then
  1271.             printLog("reactor["..reactorIndex.."] in displayReactorBars(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..") is connected.")
  1272.         else
  1273.             printLog("reactor["..reactorIndex.."] in displayReactorBars(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..") is NOT connected.")
  1274.             return -- Disconnected reactor
  1275.         end -- if reactor.getConnected() then
  1276.     end -- if not reactor then
  1277.  
  1278.     -- Draw border lines
  1279.     local width, height = monitor.getSize()
  1280.     printLog("Size of monitor is "..width.."w x"..height.."h in displayReactorBars(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..")")
  1281.  
  1282.     for i=3, 5 do
  1283.         monitor.setCursorPos(22, i)
  1284.         monitor.write("|")
  1285.     end
  1286.  
  1287.     drawLine(2, monitorIndex)
  1288.     drawLine(6, monitorIndex)
  1289.  
  1290.     -- Draw some text
  1291.     local fuelString = "Fuel: "
  1292.     local tempString = "Temp: "
  1293.     local energyBufferString = ""
  1294.  
  1295.     if reactor.isActivelyCooled() then
  1296.         energyBufferString = "Steam: "
  1297.     else
  1298.         energyBufferString = "Energy: "
  1299.     end
  1300.  
  1301.     local padding = math.max(string.len(fuelString), string.len(tempString), string.len(energyBufferString))
  1302.  
  1303.     local fuelPercentage = round(reactor.getFuelAmount()/reactor.getFuelAmountMax()*100,1)
  1304.     print{fuelString,2,3,monitorIndex}
  1305.     print{fuelPercentage.." %",padding+2,3,monitorIndex}
  1306.  
  1307.     local reactorTemp = math.ceil(reactor.getFuelTemperature())
  1308.     print{tempString,2,5,monitorIndex}
  1309.     print{reactorTemp.." C",padding+2,5,monitorIndex}
  1310.  
  1311.     local rodPercentage = math.ceil(reactor.getControlRodLevel(0))
  1312.     printLog("Current Rod Percentage for reactor["..reactorIndex.."] is "..rodPercentage.."% in displayReactorBars(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..").")
  1313.     -- Allow controlling Reactor Control Rod Level from GUI
  1314.     -- Decrease rod button: 23X, 4Y
  1315.     -- Increase rod button: 28X, 4Y
  1316.     if (xClick == 23) and (yClick == 4) and (sideClick == monitorNames[monitorIndex]) then
  1317.         printLog("Decreasing Rod Levels in displayReactorBars(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..").")
  1318.         --Decrease rod level by amount
  1319.         newRodPercentage = rodPercentage - (5 * controlRodAdjustAmount)
  1320.         if newRodPercentage < 0 then
  1321.             newRodPercentage = 0
  1322.         end
  1323.         sideClick, xClick, yClick = 0, 0, 0
  1324.  
  1325.         printLog("Setting reactor["..reactorIndex.."] Rod Levels to "..newRodPercentage.."% in displayReactorBars(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..").")
  1326.         reactor.setAllControlRodLevels(newRodPercentage)
  1327.         _G[reactorNames[reactorIndex]]["ReactorOptions"]["baseControlRodLevel"] = newRodPercentage
  1328.  
  1329.         -- Save updated rod percentage
  1330.         config.save(reactorNames[reactorIndex]..".options", _G[reactorNames[reactorIndex]])
  1331.         rodPercentage = newRodPercentage
  1332.     elseif (xClick == 29) and (yClick == 4) and (sideClick == monitorNames[monitorIndex]) then
  1333.         printLog("Increasing Rod Levels in displayReactorBars(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..").")
  1334.         --Increase rod level by amount
  1335.         newRodPercentage = rodPercentage + (5 * controlRodAdjustAmount)
  1336.         if newRodPercentage > 100 then
  1337.             newRodPercentage = 100
  1338.         end
  1339.         sideClick, xClick, yClick = 0, 0, 0
  1340.  
  1341.         printLog("Setting reactor["..reactorIndex.."] Rod Levels to "..newRodPercentage.."% in displayReactorBars(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..").")
  1342.         reactor.setAllControlRodLevels(newRodPercentage)
  1343.         _G[reactorNames[reactorIndex]]["ReactorOptions"]["baseControlRodLevel"] = newRodPercentage
  1344.        
  1345.         -- Save updated rod percentage
  1346.         config.save(reactorNames[reactorIndex]..".options", _G[reactorNames[reactorIndex]])
  1347.         rodPercentage = round(newRodPercentage,0)
  1348.     else
  1349.         printLog("No change to Rod Levels requested by "..progName.." GUI in displayReactorBars(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..").")
  1350.     end -- if (xClick == 29) and (yClick == 4) and (sideClick == monitorNames[monitorIndex]) then
  1351.  
  1352.     print{"Rod (%)",23,3,monitorIndex}
  1353.     print{"<     >",23,4,monitorIndex}
  1354.     print{stringTrim(rodPercentage),25,4,monitorIndex}
  1355.  
  1356.  
  1357.     -- getEnergyProducedLastTick() is used for both RF/t (passively cooled) and mB/t (actively cooled)
  1358.     local energyBuffer = reactor.getEnergyProducedLastTick()
  1359.     if reactor.isActivelyCooled() then
  1360.         printLog("reactor["..reactorIndex.."] produced "..energyBuffer.." mB last tick in displayReactorBars(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..").")
  1361.     else
  1362.         printLog("reactor["..reactorIndex.."] produced "..energyBuffer.." RF last tick in displayReactorBars(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..").")
  1363.     end
  1364.  
  1365.     print{energyBufferString,2,4,monitorIndex}
  1366.  
  1367.     -- Actively cooled reactors do not produce energy, only hot fluid mB/t to be used in a turbine
  1368.     -- still uses getEnergyProducedLastTick for mB/t of hot fluid generated
  1369.     if not reactor.isActivelyCooled() then
  1370.         printLog("reactor["..reactorIndex.."] in displayReactorBars(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..") is NOT an actively cooled reactor.")
  1371.  
  1372.         -- Draw stored energy buffer bar
  1373.         drawBar(2,8,28,8,colors.gray,monitorIndex)
  1374.  
  1375.         local curStoredEnergyPercent = getReactorStoredEnergyBufferPercent(reactor)
  1376.         if curStoredEnergyPercent > 4 then
  1377.             drawBar(2, 8, math.floor(26*curStoredEnergyPercent/100)+2, 8, colors.yellow, monitorIndex)
  1378.         elseif curStoredEnergyPercent > 0 then
  1379.             drawPixel(2, 8, colors.yellow, monitorIndex)
  1380.         end -- if curStoredEnergyPercent > 4 then
  1381.  
  1382.         print{"Energy Buffer",2,7,monitorIndex}
  1383.         print{curStoredEnergyPercent, width-(string.len(curStoredEnergyPercent)+2),7,monitorIndex}
  1384.         print{"%",28,7,monitorIndex}
  1385.  
  1386.         print{math.ceil(energyBuffer).." RF/t",padding+2,4,monitorIndex}
  1387.     else
  1388.         printLog("reactor["..reactorIndex.."] in displayReactorBars(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..") is an actively cooled reactor.")
  1389.         print{math.ceil(energyBuffer).." mB/t",padding+2,4,monitorIndex}
  1390.     end -- if not reactor.isActivelyCooled() then
  1391.  
  1392.     -- Print rod override status
  1393.     local reactorRodOverrideStatus = ""
  1394.  
  1395.     print{"Rod Auto-adjust:",2,9,monitorIndex}
  1396.  
  1397.     if not _G[reactorNames[reactorIndex]]["ReactorOptions"]["rodOverride"] then
  1398.         printLog("Reactor Rod Override status is: "..tostring(_G[reactorNames[reactorIndex]]["ReactorOptions"]["rodOverride"]).." EOL")
  1399.         reactorRodOverrideStatus = "Enabled"
  1400.         monitor.setTextColor(colors.green)
  1401.     else
  1402.         printLog("Reactor Rod Override status is: "..tostring(_G[reactorNames[reactorIndex]]["ReactorOptions"]["rodOverride"]).." EOL")
  1403.         reactorRodOverrideStatus = "Disabled"
  1404.         monitor.setTextColor(colors.red)
  1405.     end -- if not reactorRodOverride then
  1406.     printLog("reactorRodOverrideStatus is \""..reactorRodOverrideStatus.."\" in displayReactorBars(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..").")
  1407.  
  1408.     print{reactorRodOverrideStatus, width - string.len(reactorRodOverrideStatus) - 1, 9, monitorIndex}
  1409.     monitor.setTextColor(colors.white)
  1410.  
  1411.     print{"Reactivity: "..math.ceil(reactor.getFuelReactivity()).." %", 2, 10, monitorIndex}
  1412.     print{"Fuel: "..round(reactor.getFuelConsumedLastTick(),3).." mB/t", 2, 11, monitorIndex}
  1413.     print{"Waste: "..reactor.getWasteAmount().." mB", width-(string.len(reactor.getWasteAmount())+10), 11, monitorIndex}
  1414.  
  1415.     monitor.setTextColor(colors.blue)
  1416.     printCentered(_G[reactorNames[reactorIndex]]["ReactorOptions"]["reactorName"],12,monitorIndex)
  1417.     monitor.setTextColor(colors.white)
  1418. end -- function displayReactorBars(barParams)
  1419.  
  1420.  
  1421. local function reactorStatus(statusParams)
  1422.     -- Default to first reactor and first monitor
  1423.     setmetatable(statusParams,{__index={reactorIndex=1, monitorIndex=1}})
  1424.     local reactorIndex, monitorIndex =
  1425.         statusParams[1] or statusParams.reactorIndex,
  1426.         statusParams[2] or statusParams.monitorIndex
  1427.     printLog("Called as reactorStatus(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..")")
  1428.  
  1429.     -- Grab current monitor
  1430.     local monitor = nil
  1431.     monitor = monitorList[monitorIndex]
  1432.     if not monitor then
  1433.         printLog("monitor["..monitorIndex.."] in reactorStatus(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..") is NOT a valid monitor.")
  1434.         return -- Invalid monitorIndex
  1435.     end
  1436.  
  1437.     -- Grab current reactor
  1438.     local reactor = nil
  1439.     reactor = reactorList[reactorIndex]
  1440.     if not reactor then
  1441.         printLog("reactor["..reactorIndex.."] in reactorStatus(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..") is NOT a valid Big Reactor.")
  1442.         return -- Invalid reactorIndex
  1443.     else
  1444.         printLog("reactor["..reactorIndex.."] in reactorStatus(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..") is a valid Big Reactor.")
  1445.     end
  1446.  
  1447.     local width, height = monitor.getSize()
  1448.     local reactorStatus = ""
  1449.  
  1450.     if reactor.getConnected() then
  1451.         printLog("reactor["..reactorIndex.."] in reactorStatus(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..") is connected.")
  1452.  
  1453.         if reactor.getActive() then
  1454.             reactorStatus = "ONLINE"
  1455.  
  1456.             -- Set "ONLINE" to blue if the actively cooled reactor is both in cruise mode and online
  1457.             if _G[reactorNames[reactorIndex]]["ReactorOptions"]["reactorCruising"] and reactor.isActivelyCooled() then
  1458.                 monitor.setTextColor(colors.blue)
  1459.             else
  1460.                 monitor.setTextColor(colors.green)
  1461.             end -- if reactorCruising and reactor.isActivelyCooled() then
  1462.         else
  1463.             reactorStatus = "OFFLINE"
  1464.             monitor.setTextColor(colors.red)
  1465.         end -- if reactor.getActive() then
  1466.  
  1467.         if xClick >= (width - string.len(reactorStatus) - 1) and xClick <= (width-1) and (sideClick == monitorNames[monitorIndex]) then
  1468.             if yClick == 1 then
  1469.                 reactor.setActive(not reactor.getActive()) -- Toggle reactor status
  1470.                 _G[reactorNames[reactorIndex]]["ReactorOptions"]["autoStart"] = reactor.getActive()
  1471.                 config.save(reactorNames[reactorIndex]..".options", _G[reactorNames[reactorIndex]])
  1472.                 sideClick, xClick, yClick = 0, 0, 0 -- Reset click after we register it
  1473.  
  1474.                 -- If someone offlines the reactor (offline after a status click was detected), then disable autoStart
  1475.                 if not reactor.getActive() then
  1476.                     _G[reactorNames[reactorIndex]]["ReactorOptions"]["autoStart"] = false
  1477.                 end
  1478.             end -- if yClick == 1 then
  1479.         end -- if (xClick >= (width - string.len(reactorStatus) - 1) and xClick <= (width-1)) and (sideClick == monitorNames[monitorIndex]) then
  1480.  
  1481.         -- Allow disabling rod level auto-adjust and only manual rod level control
  1482.         if ((xClick > 23 and xClick < 28 and yClick == 4)
  1483.                 or (xClick > 20 and xClick < 27 and yClick == 9))
  1484.                 and (sideClick == monitorNames[monitorIndex]) then
  1485.             _G[reactorNames[reactorIndex]]["ReactorOptions"]["rodOverride"] = not _G[reactorNames[reactorIndex]]["ReactorOptions"]["rodOverride"]
  1486.             config.save(reactorNames[reactorIndex]..".options", _G[reactorNames[reactorIndex]])
  1487.             sideClick, xClick, yClick = 0, 0, 0 -- Reset click after we register it
  1488.         end -- if (xClick > 23) and (xClick < 28) and (yClick == 4) and (sideClick == monitorNames[monitorIndex]) then
  1489.  
  1490.     else
  1491.         printLog("reactor["..reactorIndex.."] in reactorStatus(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..") is NOT connected.")
  1492.         reactorStatus = "DISCONNECTED"
  1493.         monitor.setTextColor(colors.red)
  1494.     end -- if reactor.getConnected() then
  1495.  
  1496.     print{reactorStatus, width - string.len(reactorStatus) - 1, 1, monitorIndex}
  1497.     monitor.setTextColor(colors.white)
  1498. end -- function reactorStatus(statusParams)
  1499.  
  1500.  
  1501. -- Display all found reactors' status to monitor 1
  1502. -- This is only called if multiple reactors and/or a reactor plus at least one turbine are found
  1503. local function displayAllStatus()
  1504.     local reactor, turbine = nil, nil
  1505.     local onlineReactor, onlineTurbine = 0, 0
  1506.     local totalReactorRF, totalReactorSteam, totalTurbineRF = 0, 0, 0
  1507.     local totalReactorFuelConsumed = 0
  1508.     local capStored, capMax = getCapbanksTotalCharge()
  1509.     local totalCoolantStored, totalSteamStored, totalEnergy, totalMaxEnergyStored = 0, 0, capStored, capMax -- Total turbine and reactor energy buffer and overall capacity
  1510.     local maxSteamStored = (2000*#turbineList)+(5000*#reactorList)
  1511.     local maxCoolantStored = (2000*#turbineList)+(5000*#reactorList)
  1512.  
  1513.     local monitor, monitorIndex = nil, 1
  1514.     monitor = monitorList[monitorIndex]
  1515.     if not monitor then
  1516.         printLog("monitor["..monitorIndex.."] in displayAllStatus() is NOT a valid monitor.")
  1517.         return -- Invalid monitorIndex
  1518.     end
  1519.  
  1520.     for reactorIndex = 1, #reactorList do
  1521.         reactor = reactorList[reactorIndex]
  1522.         if not reactor then
  1523.             printLog("reactor["..reactorIndex.."] in displayAllStatus() is NOT a valid Big Reactor.")
  1524.             break -- Invalid reactorIndex
  1525.         else
  1526.             printLog("reactor["..reactorIndex.."] in displayAllStatus() is a valid Big Reactor.")
  1527.         end -- if not reactor then
  1528.  
  1529.         if reactor.getConnected() then
  1530.             printLog("reactor["..reactorIndex.."] in displayAllStatus() is connected.")
  1531.             if reactor.getActive() then
  1532.                 onlineReactor = onlineReactor + 1
  1533.                 totalReactorFuelConsumed = totalReactorFuelConsumed + reactor.getFuelConsumedLastTick()
  1534.             end -- reactor.getActive() then
  1535.  
  1536.             -- Actively cooled reactors do not produce or store energy
  1537.             if not reactor.isActivelyCooled() then
  1538.                 totalMaxEnergyStored = totalMaxEnergyStored + 10000000 -- Reactors store 10M RF
  1539.                 totalEnergy = totalEnergy + reactor.getEnergyStored()
  1540.                 totalReactorRF = totalReactorRF + reactor.getEnergyProducedLastTick()
  1541.             else
  1542.                 totalReactorSteam = totalReactorSteam + reactor.getEnergyProducedLastTick()
  1543.                 totalSteamStored = totalSteamStored + reactor.getHotFluidAmount()
  1544.                 totalCoolantStored = totalCoolantStored + reactor.getCoolantAmount()
  1545.             end -- if not reactor.isActivelyCooled() then
  1546.         else
  1547.             printLog("reactor["..reactorIndex.."] in displayAllStatus() is NOT connected.")
  1548.         end -- if reactor.getConnected() then
  1549.     end -- for reactorIndex = 1, #reactorList do
  1550.  
  1551.     for turbineIndex = 1, #turbineList do
  1552.         turbine = turbineList[turbineIndex]
  1553.         if not turbine then
  1554.             printLog("turbine["..turbineIndex.."] in displayAllStatus() is NOT a valid Turbine.")
  1555.             break -- Invalid turbineIndex
  1556.         else
  1557.             printLog("turbine["..turbineIndex.."] in displayAllStatus() is a valid Turbine.")
  1558.         end -- if not turbine then
  1559.  
  1560.         if turbine.getConnected() then
  1561.             printLog("turbine["..turbineIndex.."] in displayAllStatus() is connected.")
  1562.             if turbine.getActive() then
  1563.                 onlineTurbine = onlineTurbine + 1
  1564.             end
  1565.  
  1566.             totalMaxEnergyStored = totalMaxEnergyStored + 1000000 -- Turbines store 1M RF
  1567.             totalEnergy = totalEnergy + turbine.getEnergyStored()
  1568.             totalTurbineRF = totalTurbineRF + turbine.getEnergyProducedLastTick()
  1569.             totalSteamStored = totalSteamStored + turbine.getInputAmount()
  1570.             totalCoolantStored = totalCoolantStored + turbine.getOutputAmount()
  1571.         else
  1572.             printLog("turbine["..turbineIndex.."] in displayAllStatus() is NOT connected.")
  1573.         end -- if turbine.getConnected() then
  1574.     end -- for turbineIndex = 1, #turbineList do
  1575.  
  1576.     print{"Reactors online/found: "..onlineReactor.."/"..#reactorList, 2, 3, monitorIndex}
  1577.     print{"Turbines online/found: "..onlineTurbine.."/"..#turbineList, 2, 4, monitorIndex}
  1578.  
  1579.     if totalReactorRF ~= 0 then
  1580.         monitor.setTextColor(colors.blue)
  1581.         printRight("Reactor", 9, monitorIndex)
  1582.         monitor.setTextColor(colors.white)
  1583.         printRight(math.ceil(totalReactorRF).." (RF/t)", 10, monitorIndex)
  1584.     end
  1585.  
  1586.     if #turbineList then
  1587.         -- Display liquids
  1588.         monitor.setTextColor(colors.blue)
  1589.         printLeft("Steam (mB)", 6, monitorIndex)
  1590.         monitor.setTextColor(colors.white)
  1591.         printLeft(math.ceil(totalSteamStored).."/"..maxSteamStored, 7, monitorIndex)
  1592.         printLeft(math.ceil(totalReactorSteam).." mB/t", 8, monitorIndex)
  1593.         monitor.setTextColor(colors.blue)
  1594.         printRight("Coolant (mB)", 6, monitorIndex)
  1595.         monitor.setTextColor(colors.white)
  1596.         printRight(math.ceil(totalCoolantStored).."/"..maxCoolantStored, 7, monitorIndex)
  1597.  
  1598.         monitor.setTextColor(colors.blue)
  1599.         printLeft("Turbine", 9, monitorIndex)
  1600.         monitor.setTextColor(colors.white)
  1601.         printLeft(math.ceil(totalTurbineRF).." RF/t", 10, monitorIndex)
  1602.     end -- if #turbineList then
  1603.  
  1604.     printCentered("Fuel: "..round(totalReactorFuelConsumed,3).." mB/t", 11, monitorIndex)
  1605.     --print{"Buffer: "..math.ceil(totalEnergy,3).."/"..totalMaxEnergyStored.." RF", 2, 12, monitorIndex}
  1606.     print{"Buffer: "..round(totalEnergy/1000000,3).."/"..round(totalMaxEnergyStored/1000000,3).." MRF", 2, 12, monitorIndex}
  1607. end -- function displayAllStatus()
  1608.  
  1609.  
  1610. -- Get turbine status
  1611. local function displayTurbineBars(turbineIndex, monitorIndex)
  1612.     printLog("Called as displayTurbineBars(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..").")
  1613.  
  1614.     -- Grab current monitor
  1615.     local monitor = nil
  1616.     monitor = monitorList[monitorIndex]
  1617.     if not monitor then
  1618.         printLog("monitor["..monitorIndex.."] in displayTurbineBars(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..") is NOT a valid monitor.")
  1619.         return -- Invalid monitorIndex
  1620.     end
  1621.  
  1622.     -- Grab current turbine
  1623.     local turbine = nil
  1624.     turbine = turbineList[turbineIndex]
  1625.     if not turbine then
  1626.         printLog("turbine["..turbineIndex.."] in displayTurbineBars(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..") is NOT a valid Big Turbine.")
  1627.         return -- Invalid turbineIndex
  1628.     else
  1629.         printLog("turbine["..turbineIndex.."] in displayTurbineBars(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..") is a valid Big Turbine.")
  1630.         if turbine.getConnected() then
  1631.             printLog("turbine["..turbineIndex.."] in displayTurbineBars(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..") is connected.")
  1632.         else
  1633.             printLog("turbine["..turbineIndex.."] in displayTurbineBars(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..") is NOT connected.")
  1634.             return -- Disconnected turbine
  1635.         end -- if turbine.getConnected() then
  1636.     end -- if not turbine then
  1637.  
  1638.     --local variable to match the view on the monitor
  1639.     local turbineBaseSpeed = tonumber(_G[turbineNames[turbineIndex]]["TurbineOptions"]["BaseSpeed"])
  1640.  
  1641.     -- Draw border lines
  1642.     local width, height = monitor.getSize()
  1643.  
  1644.     for i=3, 6 do
  1645.         monitor.setCursorPos(21, i)
  1646.         monitor.write("|")
  1647.     end
  1648.  
  1649.     drawLine(2,monitorIndex)
  1650.     drawLine(7,monitorIndex)
  1651.  
  1652.     -- Allow controlling Turbine Flow Rate from GUI
  1653.     -- Decrease flow rate button: 22X, 4Y
  1654.     -- Increase flow rate button: 28X, 4Y
  1655.     local turbineFlowRate = tonumber(_G[turbineNames[turbineIndex]]["TurbineOptions"]["LastFlow"])
  1656.     if (xClick == 22) and (yClick == 4) and (sideClick == monitorNames[monitorIndex]) then
  1657.         printLog("Decrease to Flow Rate requested by "..progName.." GUI in displayTurbineBars(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..").")
  1658.         --Decrease rod level by amount
  1659.         newTurbineFlowRate = turbineFlowRate - flowRateAdjustAmount
  1660.         if newTurbineFlowRate < 0 then
  1661.             newTurbineFlowRate = 0
  1662.         end
  1663.         sideClick, xClick, yClick = 0, 0, 0
  1664.  
  1665.         -- Check bounds [0,2000]
  1666.         if newTurbineFlowRate > 2000 then
  1667.             newTurbineFlowRate = 2000
  1668.         elseif newTurbineFlowRate < 0 then
  1669.             newTurbineFlowRate = 25 -- Don't go to zero, might as well power off
  1670.         end
  1671.  
  1672.         turbine.setFluidFlowRateMax(newTurbineFlowRate)
  1673.         _G[turbineNames[turbineIndex]]["TurbineOptions"]["LastFlow"] = newTurbineFlowRate
  1674.         -- Save updated Turbine Flow Rate
  1675.         turbineFlowRate = newTurbineFlowRate
  1676.         config.save(turbineNames[turbineIndex]..".options", _G[turbineNames[turbineIndex]])
  1677.     elseif (xClick == 29) and (yClick == 4) and (sideClick == monitorNames[monitorIndex]) then
  1678.         printLog("Increase to Flow Rate requested by "..progName.." GUI in displayTurbineBars(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..").")
  1679.         --Increase rod level by amount
  1680.         newTurbineFlowRate = turbineFlowRate + flowRateAdjustAmount
  1681.         if newTurbineFlowRate > 2000 then
  1682.             newTurbineFlowRate = 2000
  1683.         end
  1684.         sideClick, xClick, yClick = 0, 0, 0
  1685.  
  1686.         -- Check bounds [0,2000]
  1687.         if newTurbineFlowRate > 2000 then
  1688.             newTurbineFlowRate = 2000
  1689.         elseif newTurbineFlowRate < 0 then
  1690.             newTurbineFlowRate = 25 -- Don't go to zero, might as well power off
  1691.         end
  1692.  
  1693.         turbine.setFluidFlowRateMax(newTurbineFlowRate)
  1694.        
  1695.         -- Save updated Turbine Flow Rate
  1696.         turbineFlowRate = math.ceil(newTurbineFlowRate)
  1697.         _G[turbineNames[turbineIndex]]["TurbineOptions"]["LastFlow"] = turbineFlowRate
  1698.         config.save(turbineNames[turbineIndex]..".options", _G[turbineNames[turbineIndex]])
  1699.     else
  1700.         printLog("No change to Flow Rate requested by "..progName.." GUI in displayTurbineBars(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..").")
  1701.     end -- if (xClick == 29) and (yClick == 4) and (sideClick == monitorNames[monitorIndex]) then
  1702.  
  1703.     if (xClick == 22) and (yClick == 6) and (sideClick == monitorNames[monitorIndex]) then
  1704.         printLog("Decrease to Turbine RPM requested by "..progName.." GUI in displayTurbineBars(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..").")
  1705.         rpmRateAdjustment = 909
  1706.         newTurbineBaseSpeed = turbineBaseSpeed - rpmRateAdjustment
  1707.         if newTurbineBaseSpeed < 908 then
  1708.             newTurbineBaseSpeed = 908
  1709.         end
  1710.         sideClick, xClick, yClick = 0, 0, 0
  1711.         _G[turbineNames[turbineIndex]]["TurbineOptions"]["BaseSpeed"] = newTurbineBaseSpeed
  1712.         config.save(turbineNames[turbineIndex]..".options", _G[turbineNames[turbineIndex]])
  1713.     elseif (xClick == 29) and (yClick == 6) and (sideClick == monitorNames[monitorIndex]) then
  1714.         printLog("Increase to Turbine RPM requested by "..progName.." GUI in displayTurbineBars(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..").")
  1715.         rpmRateAdjustment = 909
  1716.         newTurbineBaseSpeed = turbineBaseSpeed + rpmRateAdjustment
  1717.         if newTurbineBaseSpeed > 2726 then
  1718.             newTurbineBaseSpeed = 2726
  1719.         end
  1720.         sideClick, xClick, yClick = 0, 0, 0
  1721.         _G[turbineNames[turbineIndex]]["TurbineOptions"]["BaseSpeed"] = newTurbineBaseSpeed
  1722.         config.save(turbineNames[turbineIndex]..".options", _G[turbineNames[turbineIndex]])
  1723.     else
  1724.         printLog("No change to Turbine RPM requested by "..progName.." GUI in displayTurbineBars(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..").")
  1725.     end -- if (xClick == 29) and (yClick == 4) and (sideClick == monitorNames[monitorIndex]) then
  1726.     print{"  mB/t",22,3,monitorIndex}
  1727.     print{"<      >",22,4,monitorIndex}
  1728.     print{stringTrim(turbineFlowRate),24,4,monitorIndex}
  1729.     print{"  RPM",22,5,monitorIndex}
  1730.     print{"<      >",22,6,monitorIndex}
  1731.     print{stringTrim(tonumber(_G[turbineNames[turbineIndex]]["TurbineOptions"]["BaseSpeed"])),24,6,monitorIndex}
  1732.     local rotorSpeedString = "Speed: "
  1733.     local energyBufferString = "Energy: "
  1734.     local padding = math.max(string.len(rotorSpeedString), string.len(energyBufferString))
  1735.  
  1736.     local energyBuffer = turbine.getEnergyProducedLastTick()
  1737.     print{energyBufferString,1,4,monitorIndex}
  1738.     print{math.ceil(energyBuffer).." RF/t",padding+1,4,monitorIndex}
  1739.  
  1740.     local rotorSpeed = math.ceil(turbine.getRotorSpeed())
  1741.     print{rotorSpeedString,1,5,monitorIndex}
  1742.     print{rotorSpeed.." RPM",padding+1,5,monitorIndex}
  1743.  
  1744.     -- PaintUtils only outputs to term., not monitor.
  1745.     -- See http://www.computercraft.info/forums2/index.php?/topic/15540-paintutils-on-a-monitor/
  1746.  
  1747.     -- Draw stored energy buffer bar
  1748.     drawBar(1,9,28,9,colors.gray,monitorIndex)
  1749.  
  1750.     local curStoredEnergyPercent = getTurbineStoredEnergyBufferPercent(turbine)
  1751.     if curStoredEnergyPercent > 4 then
  1752.         drawBar(1, 9, math.floor(26*curStoredEnergyPercent/100)+2, 9, colors.yellow,monitorIndex)
  1753.     elseif curStoredEnergyPercent > 0 then
  1754.         drawPixel(1, 9, colors.yellow, monitorIndex)
  1755.     end -- if curStoredEnergyPercent > 4 then
  1756.  
  1757.     print{"Energy Buffer",1,8,monitorIndex}
  1758.     print{curStoredEnergyPercent, width-(string.len(curStoredEnergyPercent)+2),8,monitorIndex}
  1759.     print{"%",28,8,monitorIndex}
  1760.  
  1761.     -- Print rod override status
  1762.     local turbineFlowRateOverrideStatus = ""
  1763.  
  1764.     print{"Flow Auto-adjust:",2,10,monitorIndex}
  1765.  
  1766.     if ((not _G[turbineNames[turbineIndex]]["TurbineOptions"]["flowOverride"]) or (_G[turbineNames[turbineIndex]]["TurbineOptions"]["flowOverride"] == "false")) then
  1767.         turbineFlowRateOverrideStatus = "Enabled"
  1768.         monitor.setTextColor(colors.green)
  1769.     else
  1770.         turbineFlowRateOverrideStatus = "Disabled"
  1771.         monitor.setTextColor(colors.red)
  1772.     end -- if not reactorRodOverride then
  1773.  
  1774.     print{turbineFlowRateOverrideStatus, width - string.len(turbineFlowRateOverrideStatus) - 1, 10, monitorIndex}
  1775.     monitor.setTextColor(colors.white)
  1776.  
  1777.     monitor.setTextColor(colors.blue)
  1778.     printCentered(_G[turbineNames[turbineIndex]]["TurbineOptions"]["turbineName"],12,monitorIndex)
  1779.     monitor.setTextColor(colors.white)
  1780.  
  1781.     -- Need equation to figure out rotor efficiency and display
  1782. end -- function displayTurbineBars(statusParams)
  1783.  
  1784.  
  1785. -- Display turbine status
  1786. local function turbineStatus(turbineIndex, monitorIndex)
  1787.     -- Grab current monitor
  1788.     local monitor = nil
  1789.  
  1790.     printLog("Called as turbineStatus(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..").")
  1791.  
  1792.     monitor = monitorList[monitorIndex]
  1793.     if not monitor then
  1794.         printLog("monitor["..monitorIndex.."] in turbineStatus(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..") is NOT a valid monitor.")
  1795.         return -- Invalid monitorIndex
  1796.     end
  1797.  
  1798.     -- Grab current turbine
  1799.     local turbine = nil
  1800.     turbine = turbineList[turbineIndex]
  1801.     if not turbine then
  1802.         printLog("turbine["..turbineIndex.."] in turbineStatus(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..") is NOT a valid Big Turbine.")
  1803.         return -- Invalid turbineIndex
  1804.     else
  1805.         printLog("turbine["..turbineIndex.."] in turbineStatus(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..") is a valid Big Turbine.")
  1806.     end
  1807.  
  1808.     local width, height = monitor.getSize()
  1809.     local turbineStatus = ""
  1810.  
  1811.     if turbine.getConnected() then
  1812.         printLog("turbine["..turbineIndex.."] in turbineStatus(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..") is connected.")
  1813.         if turbine.getActive() then
  1814.             turbineStatus = "ONLINE"
  1815.             monitor.setTextColor(colors.green)
  1816.         else
  1817.             turbineStatus = "OFFLINE"
  1818.             monitor.setTextColor(colors.red)
  1819.         end -- if turbine.getActive() then
  1820.  
  1821.         if (xClick >= (width - string.len(turbineStatus) - 1)) and (xClick <= (width-1)) and (sideClick == monitorNames[monitorIndex]) then
  1822.             if yClick == 1 then
  1823.                 turbine.setActive(not turbine.getActive()) -- Toggle turbine status
  1824.                 _G[turbineNames[turbineIndex]]["TurbineOptions"]["autoStart"] = turbine.getActive()
  1825.                 config.save(turbineNames[turbineIndex]..".options", _G[turbineNames[turbineIndex]])
  1826.                 sideClick, xClick, yClick = 0, 0, 0 -- Reset click after we register it
  1827.             end -- if yClick == 1 then
  1828.         end -- if (xClick >= (width - string.len(turbineStatus) - 1)) and (xClick <= (width-1)) and (sideClick == monitorNames[monitorIndex]) then
  1829.  
  1830.         -- Allow disabling/enabling flow rate auto-adjust
  1831.         if (xClick > 23 and xClick < 28 and yClick == 4) and (sideClick == monitorNames[monitorIndex]) then
  1832.             _G[turbineNames[turbineIndex]]["TurbineOptions"]["flowOverride"] = true
  1833.             sideClick, xClick, yClick = 0, 0, 0 -- Reset click after we register it
  1834.         elseif (xClick > 20 and xClick < 27 and yClick == 10) and (sideClick == monitorNames[monitorIndex]) then
  1835.            
  1836.             if ((_G[turbineNames[turbineIndex]]["TurbineOptions"]["flowOverride"]) or (_G[turbineNames[turbineIndex]]["TurbineOptions"]["flowOverride"] == "true")) then
  1837.                 _G[turbineNames[turbineIndex]]["TurbineOptions"]["flowOverride"] = false
  1838.             else
  1839.                 _G[turbineNames[turbineIndex]]["TurbineOptions"]["flowOverride"] = true
  1840.             end
  1841.             sideClick, xClick, yClick = 0, 0, 0 -- Reset click after we register it
  1842.         end
  1843.         config.save(turbineNames[turbineIndex]..".options", _G[turbineNames[turbineIndex]])
  1844.  
  1845.     else
  1846.         printLog("turbine["..turbineIndex.."] in turbineStatus(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..") is NOT connected.")
  1847.         turbineStatus = "DISCONNECTED"
  1848.         monitor.setTextColor(colors.red)
  1849.     end -- if turbine.getConnected() then
  1850.  
  1851.     print{turbineStatus, width - string.len(turbineStatus) - 1, 1, monitorIndex}
  1852.     monitor.setTextColor(colors.white)
  1853. end -- function function turbineStatus(turbineIndex, monitorIndex)
  1854.  
  1855.  
  1856. -- Maintain Turbine flow rate at 900 or 1,800 RPM
  1857. local function flowRateControl(turbineIndex)
  1858.     if ((not _G[turbineNames[turbineIndex]]["TurbineOptions"]["flowOverride"]) or (_G[turbineNames[turbineIndex]]["TurbineOptions"]["flowOverride"] == "false")) then
  1859.        
  1860.         printLog("Called as flowRateControl(turbineIndex="..turbineIndex..").")
  1861.  
  1862.         -- Grab current turbine
  1863.         local turbine = nil
  1864.         turbine = turbineList[turbineIndex]
  1865.  
  1866.         -- assign for the duration of this run
  1867.         local lastTurbineSpeed = tonumber(_G[turbineNames[turbineIndex]]["TurbineOptions"]["LastSpeed"])
  1868.         local turbineBaseSpeed = tonumber(_G[turbineNames[turbineIndex]]["TurbineOptions"]["BaseSpeed"])
  1869.  
  1870.         if not turbine then
  1871.             printLog("turbine["..turbineIndex.."] in flowRateControl(turbineIndex="..turbineIndex..") is NOT a valid Big Turbine.")
  1872.             return -- Invalid turbineIndex
  1873.         else
  1874.             printLog("turbine["..turbineIndex.."] in flowRateControl(turbineIndex="..turbineIndex..") is a valid Big Turbine.")
  1875.  
  1876.             if turbine.getConnected() then
  1877.                 printLog("turbine["..turbineIndex.."] in flowRateControl(turbineIndex="..turbineIndex..") is connected.")
  1878.             else
  1879.                 printLog("turbine["..turbineIndex.."] in flowRateControl(turbineIndex="..turbineIndex..") is NOT connected.")
  1880.             end -- if turbine.getConnected() then
  1881.         end -- if not turbine then
  1882.  
  1883.         -- No point modifying control rod levels for temperature if the turbine is offline
  1884.         if turbine.getActive() then
  1885.             printLog("turbine["..turbineIndex.."] in flowRateControl(turbineIndex="..turbineIndex..") is active.")
  1886.  
  1887.             local flowRate = tonumber(_G[turbineNames[turbineIndex]]["TurbineOptions"]["LastFlow"])
  1888.             local flowRateUserMax = math.ceil(turbine.getFluidFlowRateMax())
  1889.             local rotorSpeed = math.ceil(turbine.getRotorSpeed())
  1890.             local newFlowRate = 0
  1891.  
  1892.             -- Going to control the turbine based on target RPM since changing the target flow rate bypasses this function
  1893.             if (rotorSpeed < turbineBaseSpeed) then
  1894.                 printLog("BELOW COMMANDED SPEED")
  1895.                 if (rotorSpeed > lastTurbineSpeed) then
  1896.                     --we're still increasing, let's let it level off
  1897.                     --also lets the first control pass go by on startup
  1898.                 elseif (rotorSpeed < lastTurbineSpeed) then
  1899.                     --we're decreasing where we should be increasing, do something
  1900.                     if ((lastTurbineSpeed - rotorSpeed) > 100) then
  1901.                         --kick it harder
  1902.                         newFlowRate = 2000
  1903.                         printLog("HARD KICK")
  1904.                     else
  1905.                         --let's adjust based on proximity
  1906.                         flowAdjustment = (turbineBaseSpeed - rotorSpeed)/5
  1907.                         newFlowRate = flowRate + flowAdjustment
  1908.                         printLog("Light Kick: new flow rate is "..newFlowRate.." mB/t and flowAdjustment was "..flowAdjustment.." EOL")
  1909.                     end
  1910.                 else
  1911.                     --we've stagnated, kick it.
  1912.                     flowAdjustment = (turbineBaseSpeed - lastTurbineSpeed)
  1913.                     newFlowRate = flowRate + flowAdjustment
  1914.                     printLog("Stagnated: new flow rate is "..newFlowRate.." mB/t and flowAdjustment was "..flowAdjustment.." EOL")
  1915.                 end --if (rotorSpeed > lastTurbineSpeed) then
  1916.             else
  1917.                 --we're above commanded turbine speed
  1918.                 printLog("ABOVE COMMANDED SPEED")
  1919.                 if (rotorSpeed < lastTurbineSpeed) then
  1920.                 --we're decreasing, let it level off
  1921.                 --also bypasses first control pass on startup
  1922.                 elseif (rotorSpeed > lastTurbineSpeed) then
  1923.                     --we're above and ascending.
  1924.                     if ((rotorSpeed - lastTurbineSpeed) > 100) then
  1925.                         --halt
  1926.                         newFlowRate = 25
  1927.                     else
  1928.                         --let's adjust based on proximity
  1929.                         flowAdjustment = (rotorSpeed - turbineBaseSpeed)/5
  1930.                         newFlowRate = flowRate - flowAdjustment
  1931.                         printLog("Light Kick: new flow rate is "..newFlowRate.." mB/t and flowAdjustment was "..flowAdjustment.." EOL")
  1932.                     end
  1933.                 else
  1934.                     --we've stagnated, kick it.
  1935.                     flowAdjustment = (lastTurbineSpeed - turbineBaseSpeed)
  1936.                     newFlowRate = flowRate - flowAdjustment
  1937.                     printLog("Stagnated: new flow rate is "..newFlowRate.." mB/t and flowAdjustment was "..flowAdjustment.." EOL")
  1938.                 end --if (rotorSpeed < lastTurbineSpeed) then
  1939.             end --if (rotorSpeed < turbineBaseSpeed)
  1940.  
  1941.             --check to make sure an adjustment was made
  1942.             if (newFlowRate == 0) then
  1943.                 --do nothing, we didn't ask for anything this pass
  1944.             else
  1945.                 --boundary check
  1946.                 if newFlowRate > 2000 then
  1947.                     newFlowRate = 2000
  1948.                 elseif newFlowRate < 25 then
  1949.                     newFlowRate = 25 -- Don't go to zero, might as well power off
  1950.                 end -- if newFlowRate > 2000 then
  1951.                 --no sense running an adjustment if it's not necessary
  1952.                 if ((newFlowRate < flowRate) or (newFlowRate > flowRate)) then
  1953.                     printLog("turbine["..turbineIndex.."] in flowRateControl(turbineIndex="..turbineIndex..") is being commanded to "..newFlowRate.." mB/t flow")
  1954.                     newFlowRate = round(newFlowRate, 0)
  1955.                     turbine.setFluidFlowRateMax(newFlowRate)
  1956.                     _G[turbineNames[turbineIndex]]["TurbineOptions"]["LastFlow"] = newFlowRate
  1957.                     config.save(turbineNames[turbineIndex]..".options", _G[turbineNames[turbineIndex]])
  1958.                 end
  1959.             end
  1960.             --always set this
  1961.             _G[turbineNames[turbineIndex]]["TurbineOptions"]["LastSpeed"] = rotorSpeed
  1962.             config.save(turbineNames[turbineIndex]..".options", _G[turbineNames[turbineIndex]])
  1963.         else
  1964.             printLog("turbine["..turbineIndex.."] in flowRateControl(turbineIndex="..turbineIndex..") is NOT active.")
  1965.         end -- if turbine.getActive() then
  1966.     else
  1967.         printLog("turbine["..turbineIndex.."] has flow override set to "..tostring(_G[turbineNames[turbineIndex]]["TurbineOptions"]["flowOverride"])..", bypassing flow control.")
  1968.     end -- if not _G[turbineNames[turbineIndex]]["TurbineOptions"]["flowOverride"] then
  1969. end -- function flowRateControl(turbineIndex)
  1970.  
  1971.  
  1972. function main()
  1973.     -- Load reactor parameters and initialize systems
  1974.     loadReactorOptions()
  1975.  
  1976.     -- Get our initial list of connected monitors and reactors
  1977.     -- and initialize every cycle in case the connected devices change
  1978.     findMonitors()
  1979.     findReactors()
  1980.     findTurbines()
  1981.     findCapBanks()
  1982.  
  1983.     while not finished do
  1984.         local reactor = nil
  1985.         local monitorIndex = 1
  1986.  
  1987.         -- For multiple reactors/monitors, monitor #1 is reserved for overall status
  1988.         -- or for multiple reactors/turbines and only one monitor
  1989.         if ( ( ((#reactorList + #turbineList) > 1) and (#monitorList >= 1) )   or
  1990.              ( ((#reactorList + #turbineList) >=1) and (#monitorList >  1) ) ) then
  1991.             local monitor = nil
  1992.             monitor = monitorList[monitorIndex]
  1993.             if not monitor then
  1994.                 printLog("monitor["..monitorIndex.."] in main() is NOT a valid monitor.")
  1995.                 return -- Invalid monitorIndex
  1996.             end
  1997.  
  1998.             clearMonitor(progName.." "..progVer, monitorIndex) -- Clear monitor and draw borders
  1999.             printCentered(progName.." "..progVer, 1, monitorIndex)
  2000.             displayAllStatus()
  2001.             monitorIndex = 2 -- Next monitor, #1 is reserved for overall status
  2002.         end
  2003.  
  2004.         -- Iterate through reactors, continue to run even if not enough monitors are connected
  2005.         for reactorIndex = 1, #reactorList do
  2006.             local monitor = nil
  2007.             local reactorMonitorIndex = monitorIndex + reactorIndex - 1 -- reactorIndex starts at 1
  2008.  
  2009.             printLog("Attempting to display reactor["..reactorIndex.."] on monitor["..reactorMonitorIndex.."]...")
  2010.  
  2011.             reactor = reactorList[reactorIndex]
  2012.             if not reactor then
  2013.                 printLog("reactor["..reactorIndex.."] in main() is NOT a valid Big Reactor.")
  2014.                 break -- Invalid reactorIndex
  2015.             else
  2016.                 printLog("reactor["..reactorIndex.."] in main() is a valid Big Reactor.")
  2017.             end --  if not reactor then
  2018.  
  2019.             -- Only attempt to assign a monitor if we have a monitor for this reactor
  2020.             if (reactorMonitorIndex <= #monitorList) then
  2021.                 printLog("Displaying reactor["..reactorIndex.."] on monitor["..reactorMonitorIndex.."].")
  2022.                 monitor = monitorList[reactorMonitorIndex]
  2023.  
  2024.                 if not monitor then
  2025.                     printLog("monitor["..reactorMonitorIndex.."] in main() is NOT a valid monitor.")
  2026.                 else
  2027.                     clearMonitor(progName, reactorMonitorIndex) -- Clear monitor and draw borders
  2028.                     printCentered(progName, 1, reactorMonitorIndex)
  2029.  
  2030.                     -- Display reactor status, includes "Disconnected" but found reactors
  2031.                     reactorStatus{reactorIndex, reactorMonitorIndex}
  2032.  
  2033.                     -- Draw the borders and bars for the current reactor on the current monitor
  2034.                     displayReactorBars{reactorIndex, reactorMonitorIndex}
  2035.                 end -- if not monitor
  2036.             else
  2037.                 printLog("You may want "..(#reactorList + #turbineList + 1).." monitors for your "..#reactorList.." connected reactors and "..#turbineList.." connected turbines.")
  2038.             end -- if (#monitorList ~= 1) and (reactorMonitorIndex < #monitorList) then
  2039.  
  2040.             if reactor.getConnected() then
  2041.                 printLog("reactor["..reactorIndex.."] is connected.")
  2042.                 local curStoredEnergyPercent = getReactorStoredEnergyBufferPercent(reactor)
  2043.  
  2044.                 -- Shutdown reactor if current stored energy % is >= desired level, otherwise activate
  2045.                 -- First pass will have curStoredEnergyPercent=0 until displayBars() is run once
  2046.                 if curStoredEnergyPercent >= maxStoredEnergyPercent then
  2047.                     reactor.setActive(false)
  2048.                 -- Do not auto-start the reactor if it was manually powered off (autoStart=false)
  2049.                 elseif (curStoredEnergyPercent <= minStoredEnergyPercent) and (_G[reactorNames[reactorIndex]]["ReactorOptions"]["autoStart"] == true) then
  2050.                     reactor.setActive(true)
  2051.                 end -- if curStoredEnergyPercent >= maxStoredEnergyPercent then
  2052.  
  2053.                 -- Don't try to auto-adjust control rods if manual control is requested
  2054.                 if not _G[reactorNames[reactorIndex]]["ReactorOptions"]["rodOverride"] then
  2055.                     temperatureControl(reactorIndex)
  2056.                 end -- if not reactorRodOverride then
  2057.             else
  2058.                 printLog("reactor["..reactorIndex.."] is NOT connected.")
  2059.             end -- if reactor.getConnected() then
  2060.         end -- for reactorIndex = 1, #reactorList do
  2061.  
  2062.         -- Monitors for turbines start after turbineMonitorOffset
  2063.         for turbineIndex = 1, #turbineList do
  2064.             local monitor = nil
  2065.             local turbineMonitorIndex = turbineIndex + turbineMonitorOffset
  2066.  
  2067.             printLog("Attempting to display turbine["..turbineIndex.."] on monitor["..turbineMonitorIndex.."]...")
  2068.  
  2069.             -- Only attempt to assign a monitor if we found a monitor for this turbine
  2070.             if (turbineMonitorIndex <= #monitorList) then
  2071.                 printLog("Displaying turbine["..turbineIndex.."] on monitor["..turbineMonitorIndex.."].")
  2072.                 monitor = monitorList[turbineMonitorIndex]
  2073.                 if not monitor then
  2074.                     printLog("monitor["..turbineMonitorIndex.."] in main() is NOT a valid monitor.")
  2075.                 else
  2076.                     clearMonitor(progName, turbineMonitorIndex) -- Clear monitor and draw borders
  2077.                     printCentered(progName, 1, turbineMonitorIndex)
  2078.  
  2079.                     -- Display turbine status, includes "Disconnected" but found turbines
  2080.                     turbineStatus(turbineIndex, turbineMonitorIndex)
  2081.  
  2082.                     -- Draw the borders and bars for the current turbine on the current monitor
  2083.                     displayTurbineBars(turbineIndex, turbineMonitorIndex)
  2084.                 end -- if not monitor
  2085.             else
  2086.                 printLog("You may want "..(#reactorList + #turbineList + 1).." monitors for your "..#reactorList.." connected reactors and "..#turbineList.." connected turbines.")
  2087.             end -- if (#monitorList ~= 1) and (turbineMonitorIndex < #monitorList) then
  2088.  
  2089.             turbine = turbineList[turbineIndex]
  2090.             if not turbine then
  2091.                 printLog("turbine["..turbineIndex.."] in main() is NOT a valid Big Turbine.")
  2092.                 break -- Invalid turbineIndex
  2093.             else
  2094.                 printLog("turbine["..turbineIndex.."] in main() is a valid Big Turbine.")
  2095.             end -- if not turbine then
  2096.  
  2097.             if turbine.getConnected() then
  2098.                 printLog("turbine["..turbineIndex.."] is connected.")
  2099.  
  2100.                 if not _G[turbineNames[turbineIndex]]["TurbineOptions"]["flowOverride"] then
  2101.                     flowRateControl(turbineIndex)
  2102.                 end -- if not turbineFlowRateOverride[turbineIndex] then
  2103.             else
  2104.                 printLog("turbine["..turbineIndex.."] is NOT connected.")
  2105.             end -- if turbine.getConnected() then
  2106.         end -- for reactorIndex = 1, #reactorList do
  2107.  
  2108.         sleep(loopTime) -- Sleep
  2109.         saveReactorOptions()
  2110.     end -- while not finished do
  2111. end -- main()
  2112.  
  2113.  
  2114. local function eventHandler()
  2115.     while not finished do
  2116.         -- http://computercraft.info/wiki/Os.pullEvent
  2117.         -- http://www.computercraft.info/forums2/index.php?/topic/1516-ospullevent-what-is-it-and-how-is-it-useful/
  2118.         event, arg1, arg2, arg3 = os.pullEvent()
  2119.  
  2120.         if event == "monitor_touch" then
  2121.             sideClick, xClick, yClick = arg1, math.floor(arg2), math.floor(arg3)
  2122.             printLog("Side: "..arg1.." Monitor touch X: "..xClick.." Y: "..yClick)
  2123.         elseif event == "char" and not inManualMode then
  2124.             local ch = string.lower(arg1)
  2125.             if ch == "q" then
  2126.                 finished = true
  2127.             elseif ch == "r" then
  2128.                 finished = true
  2129.                 os.reboot()
  2130.             end -- if ch == "q" then
  2131.         end -- if event == "monitor_touch" then
  2132.     end -- while not finished do
  2133. end -- function eventHandler()
  2134.  
  2135.  
  2136. while not finished do
  2137.     parallel.waitForAny(eventHandler, main)
  2138.     sleep(loopTime)
  2139. end -- while not finished do
  2140.  
  2141.  
  2142. -- Clear up after an exit
  2143. term.clear()
  2144. term.setCursorPos(1,1)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement