Advertisement
NolanSyKinsley

Untitled

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