Advertisement
CryptekCoding

Big Reactor | Monitor

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