Advertisement
djshadowxm81

ccReactor

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