Hastwell

EZ-Nuke for pre-1.6CC

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