Advertisement
Guest User

Untitled

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