Advertisement
craftyoyo

reactor

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