Advertisement
Guest User

Big Reactors

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