Advertisement
Evdev

bullshit

Jul 16th, 2019
96
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 100.58 KB | None | 0 0
  1. --[[
  2. Program name: Lolmer's EZ-NUKE reactor control system
  3. Version: v0.3.18
  4. Programmer: Lolmer
  5. With great assistance from @mechaet and @thetaphi
  6. Last update: 2015-05-11
  7. Pastebin: http://pastebin.com/fguScPBQ
  8. GitHub: https://github.com/sandalle/minecraft_bigreactor_control
  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. These scripts are known to run on:
  12. - Minecraft 1.6.4
  13. - NST Diet (https://www.technicpack.net/modpack/never-stop-toasting-diet.254882)
  14. - NST Maxx (https://www.technicpack.net/modpack/nstmaxx.398172)
  15. - Minecraft 1.7.10
  16. - FTB Infinity (http://www.feed-the-beast.com/modpacks/FTBInfinity)
  17. - Modderation: Permabanned (https://www.technicpack.net/modpack/modderation-permabanned-edition.449941)
  18. - Modderation: FYAD (https://www.technicpack.net/modpack/modderation-fyad-edition.696257)
  19. - Minecraft 1.12:
  20. - All the Mods 3 (https://minecraft.curseforge.com/projects/all-the-mods-3)
  21. To simplify the code and guesswork, I assume the following monitor layout, where each "monitor" listed below is a collection of three wide by two high Advanced Monitors:
  22. 1) One Advanced Monitor for overall status display plus
  23. one or more Reactors plus
  24. none or more Turbines.
  25. 2) One Advanced Monitor for overall status display plus (furthest monitor from computer by cable length)
  26. one Advanced Monitor for each connected Reactor plus (subsequent found monitors)
  27. one Advanced Monitor for each connected Turbine (last group of monitors found).
  28. If you enable debug mode, add one additional Advanced Monitor for #1 or #2.
  29. Notes
  30. ----------------------------
  31. - Only one reactor and one, two, and three turbines have been tested with the above, but IN THEORY any number is supported.
  32. - Devices are found in the reverse order they are plugged in, so monitor_10 will be found before monitor_9.
  33. When using actively cooled reactors with turbines, keep the following in mind:
  34. - 1 mB steam carries up to 10RF of potential energy to extract in a turbine.
  35. - Actively cooled reactors produce steam, not power.
  36. - You will need about 10 mB of water for each 1 mB of steam that you want to create in a 7^3 reactor.
  37. - Two 15x15x14 Turbines can output 260K RF/t by just one 7^3 (four rods) reactor putting out 4k mB steam.
  38. Features
  39. ----------------------------
  40. - Configurable min/max energy buffer and min/max temperature via ReactorOptions file.
  41. - Disengages coils and minimizes flow for turbines over max energy buffer.
  42. - ReactorOptions is read on start and then current values are saved every program cycle.
  43. - 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.
  44. - Auto-adjusts control rods per reactor to maintain temperature.
  45. - Will display reactor data to all attached monitors of correct dimensions.
  46. - For multiple monitors, the first monitor (often last plugged in) is the overall status monitor.
  47. - For multiple monitors, the first monitor (often last plugged in) is the overall status monitor.
  48. - A new cruise mode from mechaet, ONLINE will be "blue" when active, to keep your actively cooled reactors running smoothly.
  49. GUI Usage
  50. ----------------------------
  51. - Right-clicking between "< * >" of the last row of a monitor alternates the device selection between Reactor, Turbine, and Status output.
  52. - Right-clicking "<" and ">" switches between connected devices, starting with the currently selected type, but not limited to them.
  53. - The other "<" and ">" buttons, when right-clicked with the mouse, will decrease and increase, respectively, the values assigned to the monitor:
  54. - "Rod (%)" will lower/raise the Reactor Control Rods for that Reactor
  55. - "mB/t" will lower/raise the Turbine Flow Rate maximum for that Turbine
  56. - "RPM" will lower/raise the target Turbine RPM for that Turbine
  57. - Right-clicking between the "<" and ">" (not on them) will disable auto-adjust of that value for attached device.
  58. - Right-clicking on the "Enabled" or "Disabled" text for auto-adjust will do the same.
  59. - Right-clicking on "ONLINE" or "OFFLINE" at the top-right will toggle the state of attached device.
  60. Default values
  61. ----------------------------
  62. - Rod Control: 90% (Let's start off safe and then power up as we can)
  63. - Minimum Energy Buffer: 15% (will power on below this value)
  64. - Maximum Energy Buffer: 85% (will power off above this value)
  65. - Minimum Passive Cooling Temperature: 950^C (will raise control rods below this value)
  66. - Maximum Passive Cooling Temperature: 1,400^C (will lower control rods above this value)
  67. - Minimum Active Cooling Temperature: 300^C (will raise the control rods below this value)
  68. - Maximum Active Cooling Temperature: 420^C (will lower control rods above this value)
  69. - Optimal Turbine RPM: 900, 1,800, or 2,700 (divisible by 900)
  70. - New user-controlled option for target speed of turbines, defaults to 2726RPM, which is high-optimal.
  71. Requirements
  72. ----------------------------
  73. - Advanced Monitor size is X: 29, Y: 12 with a 3x2 size
  74. - Computer or Advanced Computer
  75. - Modems (not wireless) connecting each of the Computer to both the Advanced Monitor and Reactor Computer Port.
  76. - Big Reactors (http://www.big-reactors.com/) 0.3.2A+ or Extreme Reactors (https://minecraft.curseforge.com/projects/extreme-reactors)
  77. - Computercraft (http://computercraft.info/) 1.58, 1.63+, 1.73+, or 1.80pr1+
  78. - Reset the computer any time number of connected devices change.
  79. Resources
  80. ----------------------------
  81. - This script is available from:
  82. - http://pastebin.com/fguScPBQ
  83. - https://github.com/sandalle/minecraft_bigreactor_control
  84. - Start-up script is available from:
  85. - http://pastebin.com/ZTMzRLez
  86. - https://github.com/sandalle/minecraft_bigreactor_control
  87. - Other reactor control program which I based my program on:
  88. - http://pastebin.com/aMAu4X5J (ScatmanJohn)
  89. - http://pastebin.com/HjUVNDau (version ScatmanJohn based his on)
  90. - A simpler Big Reactor control program is available from:
  91. - http://pastebin.com/7S5xCvgL (IronClaymore only for passively cooled reactors)
  92. - Reactor Computer Port API: http://wiki.technicpack.net/Reactor_Computer_Port
  93. - Computercraft API: http://computercraft.info/wiki/Category:APIs
  94. - Big Reactors Efficiency, Speculation and Questions! http://www.reddit.com/r/feedthebeast/comments/1vzds0/big_reactors_efficiency_speculation_and_questions/
  95. - Big Reactors API code: https://github.com/erogenousbeef/BigReactors/blob/master/erogenousbeef/bigreactors/common/multiblock/tileentity/TileEntityReactorComputerPort.java
  96. - Big Reactors API: http://big-reactors.com/cc_api.html
  97. - Big Reactor Simulator from http://reddit.com/r/feedthebeast : http://br.sidoh.org/
  98. - A tutorial from FTB's rhn : http://forum.feed-the-beast.com/threads/rhns-continued-adventures-a-build-journal-guide-collection-etc.42664/page-10#post-657819
  99. ChangeLog
  100. ============================
  101. - 0.3.18
  102. Fix Issue #61 (Reactor Online/Offline input non-responsive when reactor is converted from passive to active cooled).
  103. Prior ChangeLogs are posted at https://github.com/sandalle/minecraft_bigreactor_control/releases
  104. TODO
  105. ============================
  106. See https://github.com/sandalle/minecraft_bigreactor_control/issues?q=is%3Aopen+is%3Aissue+label%3Aenhancement :)
  107. ]]--
  108.  
  109.  
  110. -- Some global variables
  111. local progVer = "0.3.18"
  112. local progName = "EZ-NUKE"
  113. local sideClick, xClick, yClick = nil, 0, 0
  114. local loopTime = 2
  115. local controlRodAdjustAmount = 1 -- Default Reactor Rod Control % adjustment amount
  116. local flowRateAdjustAmount = 25 -- Default Turbine Flow Rate in mB adjustment amount
  117. local debugMode = false
  118. -- End multi-reactor cleanup section
  119. local minStoredEnergyPercent = nil -- Max energy % to store before activate
  120. local maxStoredEnergyPercent = nil -- Max energy % to store before shutdown
  121. local monitorList = {} -- Empty monitor array
  122. local monitorNames = {} -- Empty array of monitor names
  123. local reactorList = {} -- Empty reactor array
  124. local reactorNames = {} -- Empty array of reactor names
  125. local turbineList = {} -- Empty turbine array
  126. local turbineNames = {} -- Empty array of turbine names
  127. local monitorAssignments = {} -- Empty array of monitor - "what to display" assignments
  128. local monitorOptionFileName = "monitors.options" -- File for saving the monitor assignments
  129. local knowlinglyOverride = false -- Issue #39 Allow the user to override safe values, currently only enabled for actively cooled reactor min/max temperature
  130. local steamRequested = 0 -- Sum of Turbine Flow Rate in mB
  131. local steamDelivered = 0 -- Sum of Active Reactor steam output in mB
  132.  
  133. -- Log levels
  134. local FATAL = 16
  135. local ERROR = 8
  136. local WARN = 4
  137. local INFO = 2
  138. local DEBUG = 1
  139.  
  140. term.clear()
  141. term.setCursorPos(2,1)
  142. write("Initializing program...\n")
  143.  
  144.  
  145. -- File needs to exist for append "a" later and zero it out if it already exists
  146. -- Always initalize this file to avoid confusion with old files and the latest run
  147. local logFile = fs.open("reactorcontrol.log", "w")
  148. if logFile then
  149. logFile.writeLine("Minecraft time: Day "..os.day().." at "..textutils.formatTime(os.time(),true))
  150. logFile.close()
  151. else
  152. error("Could not open file reactorcontrol.log for writing.")
  153. end
  154.  
  155.  
  156. -- Helper functions
  157.  
  158. local function termRestore()
  159. local ccVersion = nil
  160. ccVersion = os.version()
  161.  
  162. if ccVersion == "CraftOS 1.6" or "CraftOS 1.7" then
  163. term.redirect(term.native())
  164. elseif ccVersion == "CraftOS 1.5" then
  165. term.restore()
  166. else -- Default to older term.restore
  167. printLog("Unsupported CraftOS found. Reported version is \""..ccVersion.."\".")
  168. term.restore()
  169. end -- if ccVersion
  170. end -- function termRestore()
  171.  
  172. local function printLog(printStr, logLevel)
  173. logLevel = logLevel or INFO
  174. -- No, I'm not going to write full syslog style levels. But this makes it a little easier filtering and finding stuff in the logfile.
  175. -- Since you're already looking at it, you can adjust your preferred log level right here.
  176. if debugMode and (logLevel >= WARN) then
  177. -- If multiple monitors, print to all of them
  178. for monitorName, deviceData in pairs(monitorAssignments) do
  179. if deviceData.type == "Debug" then
  180. debugMonitor = monitorList[deviceData.index]
  181. if(not debugMonitor) or (not debugMonitor.getSize()) then
  182. term.write("printLog(): debug monitor "..monitorName.." failed")
  183. else
  184. term.redirect(debugMonitor) -- Redirect to selected monitor
  185. debugMonitor.setTextScale(0.5) -- Fit more logs on screen
  186. local color = colors.lightGray
  187. if (logLevel == WARN) then
  188. color = colors.white
  189. elseif (logLevel == ERROR) then
  190. color = colors.red
  191. elseif (logLevel == FATAL) then
  192. color = colors.black
  193. debugMonitor.setBackgroundColor(colors.red)
  194. end
  195. debugMonitor.setTextColor(color)
  196. write(printStr.."\n") -- May need to use term.scroll(x) if we output too much, not sure
  197. debugMonitor.setBackgroundColor(colors.black)
  198. termRestore()
  199. end
  200. end
  201. end -- for
  202.  
  203. local logFile = fs.open("reactorcontrol.log", "a") -- See http://computercraft.info/wiki/Fs.open
  204. if logFile then
  205. logFile.writeLine(printStr)
  206. logFile.close()
  207. else
  208. error("Cannot open file reactorcontrol.log for appending!")
  209. end -- if logFile then
  210. end -- if debugMode then
  211. end -- function printLog(printStr)
  212.  
  213.  
  214.  
  215. -- Trim a string
  216. function stringTrim(s)
  217. assert(s ~= nil, "String can't be nil")
  218. return(string.gsub(s, "^%s*(.-)%s*$", "%1"))
  219. end
  220.  
  221.  
  222.  
  223. -- Format number with [k,M,G,T,P,E] postfix or exponent, depending on how large it is
  224. local function formatReadableSIUnit(num)
  225. printLog("formatReadableSIUnit("..num..")", DEBUG)
  226. num = tonumber(num)
  227. if(num < 1000) then return tostring(num) end
  228. local sizes = {"", "k", "M", "G", "T", "P", "E"}
  229. local exponent = math.floor(math.log10(num))
  230. local group = math.floor(exponent / 3)
  231. if group > #sizes then
  232. return string.format("%e", num)
  233. else
  234. local divisor = math.pow(10, (group - 1) * 3)
  235. return string.format("%i%s", num / divisor, sizes[group])
  236. end
  237. end -- local function formatReadableSIUnit(num)
  238.  
  239. -- pretty printLog() a table
  240. local function tprint (tbl, loglevel, indent)
  241. if not loglevel then loglevel = DEBUG end
  242. if not indent then indent = 0 end
  243. for k, v in pairs(tbl) do
  244. local formatting = string.rep(" ", indent) .. k .. ": "
  245. if type(v) == "table" then
  246. printLog(formatting, loglevel)
  247. tprint(v, loglevel, indent+1)
  248. elseif type(v) == 'boolean' or type(v) == "function" then
  249. printLog(formatting .. tostring(v), loglevel)
  250. else
  251. printLog(formatting .. v, loglevel)
  252. end
  253. end
  254. end -- function tprint()
  255.  
  256. config = {}
  257.  
  258. -- Save a table into a config file
  259. -- path: path of the file to write
  260. -- tab: table to save
  261. config.save = function(path, tab)
  262. printLog("Save function called for config for "..path.." EOL")
  263. assert(path ~= nil, "Path can't be nil")
  264. assert(type(tab) == "table", "Second parameter must be a table")
  265. local f = io.open(path, "w")
  266. local i = 0
  267. for key, value in pairs(tab) do
  268. if i ~= 0 then
  269. f:write("\n")
  270. end
  271. f:write("["..key.."]".."\n")
  272. for key2, value2 in pairs(tab[key]) do
  273. key2 = stringTrim(key2)
  274. --doesn't like boolean values
  275. if (type(value2) ~= "boolean") then
  276. value2 = stringTrim(value2)
  277. else
  278. value2 = tostring(value2)
  279. end
  280. key2 = key2:gsub(";", "\\;")
  281. key2 = key2:gsub("=", "\\=")
  282. value2 = value2:gsub(";", "\\;")
  283. value2 = value2:gsub("=", "\\=")
  284. f:write(key2.."="..value2.."\n")
  285. end
  286. i = i + 1
  287. end
  288. f:close()
  289. end --config.save = function(path, tab)
  290.  
  291. -- Load a config file
  292. -- path: path of the file to read
  293. config.load = function(path)
  294. printLog("Load function called for config for "..path.." EOL")
  295. assert(path ~= nil, "Path can't be nil")
  296. local f = fs.open(path, "r")
  297. if f ~= nil then
  298. printLog("Successfully opened "..path.." for reading EOL")
  299. local tab = {}
  300. local line = ""
  301. local newLine
  302. local i
  303. local currentTag = nil
  304. local found = false
  305. local pos = 0
  306. while line ~= nil do
  307. found = false
  308. line = line:gsub("\\;", "#_!36!_#") -- to keep \;
  309. line = line:gsub("\\=", "#_!71!_#") -- to keep \=
  310. if line ~= "" then
  311. -- Delete comments
  312. newLine = line
  313. line = ""
  314. for i=1, string.len(newLine) do
  315. if string.sub(newLine, i, i) ~= ";" then
  316. line = line..newLine:sub(i, i)
  317. else
  318. break
  319. end
  320. end
  321. line = stringTrim(line)
  322. -- Find tag
  323. if line:sub(1, 1) == "[" and line:sub(line:len(), line:len()) == "]" then
  324. currentTag = stringTrim(line:sub(2, line:len()-1))
  325. tab[currentTag] = {}
  326. found = true
  327. end
  328. -- Find key and values
  329. if not found and line ~= "" then
  330. pos = line:find("=")
  331. if pos == nil then
  332. error("Bad INI file structure")
  333. end
  334. line = line:gsub("#_!36!_#", ";")
  335. line = line:gsub("#_!71!_#", "=")
  336. tab[currentTag][stringTrim(line:sub(1, pos-1))] = stringTrim(line:sub(pos+1, line:len()))
  337. found = true
  338. end
  339. end
  340. line = f.readLine()
  341. end
  342.  
  343. f:close()
  344.  
  345. return tab
  346. else
  347. printLog("Could NOT opened "..path.." for reading! EOL")
  348. return nil
  349. end
  350. end --config.load = function(path)
  351.  
  352.  
  353.  
  354. -- round() function from mechaet
  355. local function round(num, places)
  356. local mult = 10^places
  357. local addon = nil
  358. if ((num * mult) < 0) then
  359. addon = -.5
  360. else
  361. addon = .5
  362. end
  363.  
  364. local integer, decimal = math.modf(num*mult+addon)
  365. local newNum = integer/mult
  366. printLog("Called round(num="..num..",places="..places..") returns \""..newNum.."\".")
  367. return newNum
  368. end -- function round(num, places)
  369.  
  370.  
  371. local function print(printParams)
  372. -- Default to xPos=1, yPos=1, and first monitor
  373. setmetatable(printParams,{__index={xPos=1, yPos=1, monitorIndex=1}})
  374. local printString, xPos, yPos, monitorIndex =
  375. printParams[1], -- Required parameter
  376. printParams[2] or printParams.xPos,
  377. printParams[3] or printParams.yPos,
  378. printParams[4] or printParams.monitorIndex
  379.  
  380. local monitor = nil
  381. monitor = monitorList[monitorIndex]
  382.  
  383. if not monitor then
  384. printLog("monitor["..monitorIndex.."] in print() is NOT a valid monitor.")
  385. return -- Invalid monitorIndex
  386. end
  387.  
  388. monitor.setCursorPos(xPos, yPos)
  389. monitor.write(printString)
  390. end -- function print(printParams)
  391.  
  392.  
  393. -- Replaces the one from FC_API (http://pastebin.com/A9hcbZWe) and adding multi-monitor support
  394. local function printCentered(printString, yPos, monitorIndex)
  395. local monitor = nil
  396. monitor = monitorList[monitorIndex]
  397.  
  398. if not monitor then
  399. printLog("monitor["..monitorIndex.."] in printCentered() is NOT a valid monitor.", ERROR)
  400. return -- Invalid monitorIndex
  401. end
  402.  
  403. local width, height = monitor.getSize()
  404. local monitorNameLength = 0
  405.  
  406. -- Special changes for title bar
  407. if yPos == 1 then
  408. -- Add monitor name to first line
  409. monitorNameLength = monitorNames[monitorIndex]:len()
  410. width = width - monitorNameLength -- add a space
  411.  
  412. -- Leave room for "offline" and "online" on the right except for overall status display
  413. if monitorAssignments[monitorNames[monitorIndex]].type ~= "Status" then
  414. width = width - 7
  415. end
  416. end
  417.  
  418. monitor.setCursorPos(monitorNameLength + math.ceil((1 + width - printString:len())/2), yPos)
  419. monitor.write(printString)
  420. end -- function printCentered(printString, yPos, monitorIndex)
  421.  
  422.  
  423. -- Print text padded from the left side
  424. -- Clear the left side of the screen
  425. local function printLeft(printString, yPos, monitorIndex)
  426. local monitor = nil
  427. monitor = monitorList[monitorIndex]
  428.  
  429. if not monitor then
  430. printLog("monitor["..monitorIndex.."] in printLeft() is NOT a valid monitor.", ERROR)
  431. return -- Invalid monitorIndex
  432. end
  433.  
  434. local gap = 1
  435. local width = monitor.getSize()
  436.  
  437. -- Clear left-half of the monitor
  438.  
  439. for curXPos = 1, (width / 2) do
  440. monitor.setCursorPos(curXPos, yPos)
  441. monitor.write(" ")
  442. end
  443.  
  444. -- Write our string left-aligned
  445. monitor.setCursorPos(1+gap, yPos)
  446. monitor.write(printString)
  447. end
  448.  
  449.  
  450. -- Print text padded from the right side
  451. -- Clear the right side of the screen
  452. local function printRight(printString, yPos, monitorIndex)
  453. local monitor = nil
  454. monitor = monitorList[monitorIndex]
  455.  
  456. if not monitor then
  457. printLog("monitor["..monitorIndex.."] in printRight() is NOT a valid monitor.", ERROR)
  458. return -- Invalid monitorIndex
  459. end
  460.  
  461. -- Make sure printString is a string
  462. printString = tostring(printString)
  463.  
  464. local gap = 1
  465. local width = monitor.getSize()
  466.  
  467. -- Clear right-half of the monitor
  468. for curXPos = (width/2), width do
  469. monitor.setCursorPos(curXPos, yPos)
  470. monitor.write(" ")
  471. end
  472.  
  473. -- Write our string right-aligned
  474. monitor.setCursorPos(math.floor(width) - math.ceil(printString:len()+gap), yPos)
  475. monitor.write(printString)
  476. end
  477.  
  478.  
  479. -- Replaces the one from FC_API (http://pastebin.com/A9hcbZWe) and adding multi-monitor support
  480. local function clearMonitor(printString, monitorIndex)
  481. local monitor = nil
  482. monitor = monitorList[monitorIndex]
  483.  
  484. printLog("Called as clearMonitor(printString="..printString..",monitorIndex="..monitorIndex..").")
  485.  
  486. if not monitor then
  487. printLog("monitor["..monitorIndex.."] in clearMonitor(printString="..printString..",monitorIndex="..monitorIndex..") is NOT a valid monitor.", ERROR)
  488. return -- Invalid monitorIndex
  489. end
  490.  
  491. local gap = 2
  492. monitor.clear()
  493. local width, height = monitor.getSize()
  494.  
  495. printCentered(printString, 1, monitorIndex)
  496. monitor.setTextColor(colors.blue)
  497. print{monitorNames[monitorIndex], 1, 1, monitorIndex}
  498. monitor.setTextColor(colors.white)
  499.  
  500. for i=1, width do
  501. monitor.setCursorPos(i, gap)
  502. monitor.write("-")
  503. end
  504.  
  505. monitor.setCursorPos(1, gap+1)
  506. end -- function clearMonitor(printString, monitorIndex)
  507.  
  508.  
  509. -- Return a list of all connected (including via wired modems) devices of "deviceType"
  510. local function getDevices(deviceType)
  511. printLog("Called as getDevices(deviceType="..deviceType..")")
  512.  
  513. local deviceName = nil
  514. local deviceIndex = 1
  515. local deviceList, deviceNames = {}, {} -- Empty array, which grows as we need
  516. local peripheralList = peripheral.getNames() -- Get table of connected peripherals
  517.  
  518. deviceType = deviceType:lower() -- Make sure we're matching case here
  519.  
  520. for peripheralIndex = 1, #peripheralList do
  521. -- Log every device found
  522. -- printLog("Found "..peripheral.getType(peripheralList[peripheralIndex]).."["..peripheralIndex.."] attached as \""..peripheralList[peripheralIndex].."\".")
  523. if (string.lower(peripheral.getType(peripheralList[peripheralIndex])) == deviceType) then
  524. -- Log devices found which match deviceType and which device index we give them
  525. printLog("Found "..peripheral.getType(peripheralList[peripheralIndex]).."["..peripheralIndex.."] as index \"["..deviceIndex.."]\" attached as \""..peripheralList[peripheralIndex].."\".")
  526. write("Found "..peripheral.getType(peripheralList[peripheralIndex]).."["..peripheralIndex.."] as index \"["..deviceIndex.."]\" attached as \""..peripheralList[peripheralIndex].."\".\n")
  527. deviceNames[deviceIndex] = peripheralList[peripheralIndex]
  528. deviceList[deviceIndex] = peripheral.wrap(peripheralList[peripheralIndex])
  529. deviceIndex = deviceIndex + 1
  530. end
  531. end -- for peripheralIndex = 1, #peripheralList do
  532.  
  533. return deviceList, deviceNames
  534. end -- function getDevices(deviceType)
  535.  
  536. -- Draw a line across the entire x-axis
  537. local function drawLine(yPos, monitorIndex)
  538. local monitor = nil
  539. monitor = monitorList[monitorIndex]
  540.  
  541. if not monitor then
  542. printLog("monitor["..monitorIndex.."] in drawLine() is NOT a valid monitor.")
  543. return -- Invalid monitorIndex
  544. end
  545.  
  546. local width, height = monitor.getSize()
  547.  
  548. for i=1, width do
  549. monitor.setCursorPos(i, yPos)
  550. monitor.write("-")
  551. end
  552. end -- function drawLine(yPos,monitorIndex)
  553.  
  554.  
  555. -- Display a solid bar of specified color
  556. local function drawBar(startXPos, startYPos, endXPos, endYPos, color, monitorIndex)
  557. local monitor = nil
  558. monitor = monitorList[monitorIndex]
  559.  
  560. if not monitor then
  561. printLog("monitor["..monitorIndex.."] in drawBar() is NOT a valid monitor.")
  562. return -- Invalid monitorIndex
  563. end
  564.  
  565. -- PaintUtils only outputs to term., not monitor.
  566. -- See http://www.computercraft.info/forums2/index.php?/topic/15540-paintutils-on-a-monitor/
  567. term.redirect(monitor)
  568. paintutils.drawLine(startXPos, startYPos, endXPos, endYPos, color)
  569. monitor.setBackgroundColor(colors.black) -- PaintUtils doesn't restore the color
  570. termRestore()
  571. end -- function drawBar(startXPos, startYPos,endXPos,endYPos,color,monitorIndex)
  572.  
  573.  
  574. -- Display single pixel color
  575. local function drawPixel(xPos, yPos, color, monitorIndex)
  576. local monitor = nil
  577. monitor = monitorList[monitorIndex]
  578.  
  579. if not monitor then
  580. printLog("monitor["..monitorIndex.."] in drawPixel() is NOT a valid monitor.")
  581. return -- Invalid monitorIndex
  582. end
  583.  
  584. -- PaintUtils only outputs to term., not monitor.
  585. -- See http://www.computercraft.info/forums2/index.php?/topic/15540-paintutils-on-a-monitor/
  586. term.redirect(monitor)
  587. paintutils.drawPixel(xPos, yPos, color)
  588. monitor.setBackgroundColor(colors.black) -- PaintUtils doesn't restore the color
  589. termRestore()
  590. end -- function drawPixel(xPos, yPos, color, monitorIndex)
  591.  
  592. local function saveMonitorAssignments()
  593. local assignments = {}
  594. for monitor, data in pairs(monitorAssignments) do
  595. local name = nil
  596. if (data.type == "Reactor") then
  597. name = data.reactorName
  598. elseif (data.type == "Turbine") then
  599. name = data.turbineName
  600. else
  601. name = data.type
  602. end
  603. assignments[monitor] = name
  604. end
  605. config.save(monitorOptionFileName, {Monitors = assignments})
  606. end
  607.  
  608. UI = {
  609. monitorIndex = 1,
  610. reactorIndex = 1,
  611. turbineIndex = 1
  612. }
  613.  
  614. UI.handlePossibleClick = function(self)
  615. local monitorData = monitorAssignments[sideClick]
  616. if monitorData == nil then
  617. printLog("UI.handlePossibleClick(): "..sideClick.." is unassigned, can't handle click", WARN)
  618. return
  619. end
  620.  
  621. self.monitorIndex = monitorData.index
  622. local width, height = monitorList[self.monitorIndex].getSize()
  623. -- All the last line are belong to us
  624. if (yClick == height) then
  625. if (monitorData.type == "Reactor") then
  626. if (xClick == 1) then
  627. self:selectPrevReactor()
  628. elseif (xClick == width) then
  629. self:selectNextReactor()
  630. elseif (3 <= xClick and xClick <= width - 2) then
  631. if (#turbineList > 0) then
  632. self:selectTurbine()
  633. else
  634. self:selectStatus()
  635. end
  636. end
  637. elseif (monitorData.type == "Turbine") then
  638. if (xClick == 1) then
  639. self:selectPrevTurbine()
  640. elseif (xClick == width) then
  641. self:selectNextTurbine()
  642. elseif (3 <= xClick and xClick <= width - 2) then
  643. self:selectStatus()
  644. end
  645. elseif (monitorData.type == "Status") then
  646. if (xClick == 1) then
  647. if (#turbineList > 0) then
  648. self.turbineIndex = #turbineList
  649. self:selectTurbine()
  650. else
  651. self.reactorIndex = 1
  652. self:selectReactor()
  653. end
  654. elseif (xClick == width) then
  655. self.reactorIndex = 1
  656. self:selectReactor()
  657. elseif (3 <= xClick and xClick <= width - 2) then
  658. self:selectReactor()
  659. end
  660. else
  661. self:selectStatus()
  662. end
  663. -- Yes, that means we're skipping Debug. I figure everyone who wants that is
  664. -- bound to use the console key commands anyway, and that way we don't have
  665. -- it interfere with regular use.
  666.  
  667. sideClick, xClick, yClick = 0, 0, 0
  668. else
  669. if (monitorData.type == "Turbine") then
  670. self:handleTurbineMonitorClick(monitorData.turbineIndex, monitorData.index)
  671. elseif (monitorData.type == "Reactor") then
  672. self:handleReactorMonitorClick(monitorData.reactorIndex, monitorData.index)
  673. end
  674. end
  675. end -- UI.handlePossibleClick()
  676.  
  677. UI.logChange = function(self, messageText)
  678. printLog("UI: "..messageText)
  679. termRestore()
  680. write(messageText.."\n")
  681. end
  682.  
  683. UI.selectNextMonitor = function(self)
  684. self.monitorIndex = self.monitorIndex + 1
  685. if self.monitorIndex > #monitorList then
  686. self.monitorIndex = 1
  687. end
  688. local messageText = "Selected monitor "..monitorNames[self.monitorIndex]
  689. self:logChange(messageText)
  690. end -- UI.selectNextMonitor()
  691.  
  692.  
  693. UI.selectReactor = function(self)
  694. monitorAssignments[monitorNames[self.monitorIndex]] = {type="Reactor", index=self.monitorIndex, reactorName=reactorNames[self.reactorIndex], reactorIndex=self.reactorIndex}
  695. saveMonitorAssignments()
  696. local messageText = "Selected reactor "..reactorNames[self.reactorIndex].." for display on "..monitorNames[self.monitorIndex]
  697. self:logChange(messageText)
  698. end -- UI.selectReactor()
  699.  
  700. UI.selectPrevReactor = function(self)
  701. if self.reactorIndex <= 1 then
  702. self.reactorIndex = #reactorList
  703. self:selectStatus()
  704. else
  705. self.reactorIndex = self.reactorIndex - 1
  706. self:selectReactor()
  707. end
  708. end -- UI.selectPrevReactor()
  709.  
  710. UI.selectNextReactor = function(self)
  711. if self.reactorIndex >= #reactorList then
  712. self.reactorIndex = 1
  713. self.turbineIndex = 1
  714. self:selectTurbine()
  715. else
  716. self.reactorIndex = self.reactorIndex + 1
  717. self:selectReactor()
  718. end
  719. end -- UI.selectNextReactor()
  720.  
  721.  
  722. UI.selectTurbine = function(self)
  723. monitorAssignments[monitorNames[self.monitorIndex]] = {type="Turbine", index=self.monitorIndex, turbineName=turbineNames[self.turbineIndex], turbineIndex=self.turbineIndex}
  724. saveMonitorAssignments()
  725. local messageText = "Selected turbine "..turbineNames[self.turbineIndex].." for display on "..monitorNames[self.monitorIndex]
  726. self:logChange(messageText)
  727. end -- UI.selectTurbine()
  728.  
  729. UI.selectPrevTurbine = function(self)
  730. if self.turbineIndex <= 1 then
  731. self.turbineIndex = #turbineList
  732. self.reactorIndex = #reactorList
  733. self:selectReactor()
  734. else
  735. self.turbineIndex = self.turbineIndex - 1
  736. self:selectTurbine()
  737. end
  738. end -- UI.selectPrevTurbine()
  739.  
  740. UI.selectNextTurbine = function(self)
  741. if self.turbineIndex >= #turbineList then
  742. self.turbineIndex = 1
  743. self:selectStatus()
  744. else
  745. self.turbineIndex = self.turbineIndex + 1
  746. self:selectTurbine()
  747. end
  748. end -- UI.selectNextTurbine()
  749.  
  750.  
  751. UI.selectStatus = function(self)
  752. monitorAssignments[monitorNames[self.monitorIndex]] = {type="Status", index=self.monitorIndex}
  753. saveMonitorAssignments()
  754. local messageText = "Selected status summary for display on "..monitorNames[self.monitorIndex]
  755. self:logChange(messageText)
  756. end -- UI.selectStatus()
  757.  
  758. UI.selectDebug = function(self)
  759. monitorAssignments[monitorNames[self.monitorIndex]] = {type="Debug", index=self.monitorIndex}
  760. saveMonitorAssignments()
  761. monitorList[self.monitorIndex].clear()
  762. local messageText = "Selected debug output for display on "..monitorNames[self.monitorIndex]
  763. self:logChange(messageText)
  764. end -- UI.selectDebug()
  765.  
  766. -- Allow controlling Reactor Control Rod Level from GUI
  767. UI.handleReactorMonitorClick = function(self, reactorIndex, monitorIndex)
  768.  
  769. -- Decrease rod button: 23X, 4Y
  770. -- Increase rod button: 28X, 4Y
  771.  
  772. -- Grab current monitor
  773. local monitor = nil
  774. monitor = monitorList[monitorIndex]
  775. if not monitor then
  776. printLog("monitor["..monitorIndex.."] in turbineStatus(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..") is NOT a valid monitor.")
  777. return -- Invalid monitorIndex
  778. end
  779.  
  780. -- Grab current reactor
  781. local reactor = nil
  782. reactor = reactorList[reactorIndex]
  783. if not reactor then
  784. printLog("reactor["..reactorIndex.."] in handleReactorMonitorClick(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..") is NOT a valid Big Reactor.")
  785. return -- Invalid reactorIndex
  786. else
  787. printLog("reactor["..reactorIndex.."] in handleReactorMonitorClick(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..") is a valid Big Reactor.")
  788. if reactor.getConnected() then
  789. printLog("reactor["..reactorIndex.."] in handleReactorMonitorClick(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..") is connected.")
  790. else
  791. printLog("reactor["..reactorIndex.."] in handleReactorMonitorClick(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..") is NOT connected.")
  792. return -- Disconnected reactor
  793. end -- if reactor.getConnected() then
  794. end -- if not reactor then
  795.  
  796. local reactorStatus = _G[reactorNames[reactorIndex]]["ReactorOptions"]["Status"]
  797.  
  798. local width, height = monitor.getSize()
  799. if xClick >= (width - string.len(reactorStatus) - 1) and xClick <= (width-1) and (sideClick == monitorNames[monitorIndex]) then
  800. if yClick == 1 then
  801. reactor.setActive(not reactor.getActive()) -- Toggle reactor status
  802. _G[reactorNames[reactorIndex]]["ReactorOptions"]["autoStart"] = reactor.getActive()
  803. config.save(reactorNames[reactorIndex]..".options", _G[reactorNames[reactorIndex]])
  804. sideClick, xClick, yClick = 0, 0, 0 -- Reset click after we register it
  805.  
  806. -- If someone offlines the reactor (offline after a status click was detected), then disable autoStart
  807. if not reactor.getActive() then
  808. _G[reactorNames[reactorIndex]]["ReactorOptions"]["autoStart"] = false
  809. end
  810. end -- if yClick == 1 then
  811. end -- if (xClick >= (width - string.len(reactorStatus) - 1) and xClick <= (width-1)) and (sideClick == monitorNames[monitorIndex]) then
  812.  
  813. -- Allow disabling rod level auto-adjust and only manual rod level control
  814. if ((xClick > 20 and xClick < 27 and yClick == 9))
  815. and (sideClick == monitorNames[monitorIndex]) then
  816. _G[reactorNames[reactorIndex]]["ReactorOptions"]["rodOverride"] = not _G[reactorNames[reactorIndex]]["ReactorOptions"]["rodOverride"]
  817. config.save(reactorNames[reactorIndex]..".options", _G[reactorNames[reactorIndex]])
  818. sideClick, xClick, yClick = 0, 0, 0 -- Reset click after we register it
  819. end -- if (xClick > 23) and (xClick < 28) and (yClick == 4) and (sideClick == monitorNames[monitorIndex]) then
  820.  
  821.  
  822. local targetTemp = _G[reactorNames[reactorIndex]]["ReactorOptions"]["reactorTargetTemp"]
  823. local newTargetTemp = targetTemp
  824. -- temporary:
  825. local targetTempAdjustAmount = 50
  826. if (xClick == 21) and (yClick == 4) and (sideClick == monitorNames[monitorIndex]) then
  827. printLog("Decreasing Target Temperature in handleReactorMonitorClick(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..").")
  828. --Decrease target temp by amount
  829. newTargetTemp = targetTemp - targetTempAdjustAmount
  830. if newTargetTemp < 0 then
  831. newTargetTemp = 0
  832. end
  833. sideClick, xClick, yClick = 0, 0, 0
  834.  
  835. printLog("Setting reactor["..reactorIndex.."] Target Temperature to "..newTargetTemp.."% in handleReactorMonitorClick(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..").")
  836. _G[reactorNames[reactorIndex]]["ReactorOptions"]["reactorTargetTemp"] = newTargetTemp
  837.  
  838. -- Save updated target temp
  839. config.save(reactorNames[reactorIndex]..".options", _G[reactorNames[reactorIndex]])
  840. targetTemp = newTargetTemp
  841. elseif (xClick == 29) and (yClick == 4) and (sideClick == monitorNames[monitorIndex]) then
  842. printLog("Increasing Target Temperature in handleReactorMonitorClick(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..").")
  843. --Increase Target Temperature by amount
  844. newTargetTemp = targetTemp + targetTempAdjustAmount
  845.  
  846. sideClick, xClick, yClick = 0, 0, 0
  847.  
  848. printLog("Setting reactor["..reactorIndex.."] Target Temperature to "..newTargetTemp.."% in handleReactorMonitorClick(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..").")
  849. _G[reactorNames[reactorIndex]]["ReactorOptions"]["reactorTargetTemp"] = newTargetTemp
  850.  
  851. -- Save updated target temp
  852. config.save(reactorNames[reactorIndex]..".options", _G[reactorNames[reactorIndex]])
  853. targetTemp = newTargetTemp
  854. else
  855. printLog("No change to Target Temp requested by "..progName.." GUI in handleReactorMonitorClick(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..").")
  856. end -- if (xClick == 29) and (yClick == 4) and (sideClick == monitorNames[monitorIndex]) then
  857. end -- UI.handleReactorMonitorClick = function(self, reactorIndex, monitorIndex)
  858.  
  859. -- Allow controlling Turbine Flow Rate from GUI
  860. UI.handleTurbineMonitorClick = function(self, turbineIndex, monitorIndex)
  861.  
  862. -- Decrease flow rate button: 22X, 4Y
  863. -- Increase flow rate button: 28X, 4Y
  864.  
  865. -- Grab current monitor
  866. local monitor = nil
  867. monitor = monitorList[monitorIndex]
  868. if not monitor then
  869. printLog("monitor["..monitorIndex.."] in turbineStatus(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..") is NOT a valid monitor.")
  870. return -- Invalid monitorIndex
  871. end
  872.  
  873. -- Grab current turbine
  874. local turbine = nil
  875. turbine = turbineList[turbineIndex]
  876. if not turbine then
  877. printLog("turbine["..turbineIndex.."] in handleTurbineMonitorClick(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..") is NOT a valid Big Turbine.")
  878. return -- Invalid turbineIndex
  879. else
  880. printLog("turbine["..turbineIndex.."] in handleTurbineMonitorClick(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..") is a valid Big Turbine.")
  881. if turbine.getConnected() then
  882. printLog("turbine["..turbineIndex.."] in handleTurbineMonitorClick(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..") is connected.")
  883. else
  884. printLog("turbine["..turbineIndex.."] in handleTurbineMonitorClick(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..") is NOT connected.")
  885. return -- Disconnected turbine
  886. end -- if turbine.getConnected() then
  887. end
  888.  
  889. local turbineBaseSpeed = tonumber(_G[turbineNames[turbineIndex]]["TurbineOptions"]["BaseSpeed"])
  890. local turbineFlowRate = tonumber(_G[turbineNames[turbineIndex]]["TurbineOptions"]["LastFlow"])
  891. local turbineStatus = _G[turbineNames[turbineIndex]]["TurbineOptions"]["Status"]
  892. local width, height = monitor.getSize()
  893.  
  894. if (xClick >= (width - string.len(turbineStatus) - 1)) and (xClick <= (width-1)) and (sideClick == monitorNames[monitorIndex]) then
  895. if yClick == 1 then
  896. turbine.setActive(not turbine.getActive()) -- Toggle turbine status
  897. _G[turbineNames[turbineIndex]]["TurbineOptions"]["autoStart"] = turbine.getActive()
  898. config.save(turbineNames[turbineIndex]..".options", _G[turbineNames[turbineIndex]])
  899. sideClick, xClick, yClick = 0, 0, 0 -- Reset click after we register it
  900. config.save(turbineNames[turbineIndex]..".options", _G[turbineNames[turbineIndex]])
  901. end -- if yClick == 1 then
  902. end -- if (xClick >= (width - string.len(turbineStatus) - 1)) and (xClick <= (width-1)) and (sideClick == monitorNames[monitorIndex]) then
  903.  
  904. -- Allow disabling/enabling flow rate auto-adjust
  905. if (xClick > 23 and xClick < 28 and yClick == 4) and (sideClick == monitorNames[monitorIndex]) then
  906. _G[turbineNames[turbineIndex]]["TurbineOptions"]["flowOverride"] = true
  907. sideClick, xClick, yClick = 0, 0, 0 -- Reset click after we register it
  908. elseif (xClick > 20 and xClick < 27 and yClick == 10) and (sideClick == monitorNames[monitorIndex]) then
  909.  
  910. if ((_G[turbineNames[turbineIndex]]["TurbineOptions"]["flowOverride"]) or (_G[turbineNames[turbineIndex]]["TurbineOptions"]["flowOverride"] == "true")) then
  911. _G[turbineNames[turbineIndex]]["TurbineOptions"]["flowOverride"] = false
  912. else
  913. _G[turbineNames[turbineIndex]]["TurbineOptions"]["flowOverride"] = true
  914. end
  915. sideClick, xClick, yClick = 0, 0, 0 -- Reset click after we register it
  916. config.save(turbineNames[turbineIndex]..".options", _G[turbineNames[turbineIndex]])
  917. end
  918.  
  919. if (xClick == 22) and (yClick == 4) and (sideClick == monitorNames[monitorIndex]) then
  920. printLog("Decrease to Flow Rate requested by "..progName.." GUI in handleTurbineMonitorClick(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..").")
  921. --Decrease rod level by amount
  922. local newTurbineFlowRate = turbineFlowRate - flowRateAdjustAmount
  923. if newTurbineFlowRate < 0 then
  924. newTurbineFlowRate = 0
  925. end
  926. sideClick, xClick, yClick = 0, 0, 0
  927.  
  928. -- Check bounds [0,2000]
  929. if newTurbineFlowRate > 2000 then
  930. newTurbineFlowRate = 2000
  931. elseif newTurbineFlowRate < 0 then
  932. newTurbineFlowRate = 0
  933. end
  934.  
  935. turbine.setFluidFlowRateMax(newTurbineFlowRate)
  936. _G[turbineNames[turbineIndex]]["TurbineOptions"]["LastFlow"] = newTurbineFlowRate
  937. -- Save updated Turbine Flow Rate
  938. turbineFlowRate = newTurbineFlowRate
  939. config.save(turbineNames[turbineIndex]..".options", _G[turbineNames[turbineIndex]])
  940. elseif (xClick == 29) and (yClick == 4) and (sideClick == monitorNames[monitorIndex]) then
  941. printLog("Increase to Flow Rate requested by "..progName.." GUI in handleTurbineMonitorClick(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..").")
  942. --Increase rod level by amount
  943. local newTurbineFlowRate = turbineFlowRate + flowRateAdjustAmount
  944. if newTurbineFlowRate > 2000 then
  945. newTurbineFlowRate = 2000
  946. end
  947. sideClick, xClick, yClick = 0, 0, 0
  948.  
  949. -- Check bounds [0,2000]
  950. if newTurbineFlowRate > 2000 then
  951. newTurbineFlowRate = 2000
  952. elseif newTurbineFlowRate < 0 then
  953. newTurbineFlowRate = 0
  954. end
  955.  
  956. turbine.setFluidFlowRateMax(newTurbineFlowRate)
  957.  
  958. -- Save updated Turbine Flow Rate
  959. turbineFlowRate = math.ceil(newTurbineFlowRate)
  960. _G[turbineNames[turbineIndex]]["TurbineOptions"]["LastFlow"] = turbineFlowRate
  961. config.save(turbineNames[turbineIndex]..".options", _G[turbineNames[turbineIndex]])
  962. else
  963. printLog("No change to Flow Rate requested by "..progName.." GUI in handleTurbineMonitorClick(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..").")
  964. end -- if (xClick == 29) and (yClick == 4) and (sideClick == monitorNames[monitorIndex]) then
  965.  
  966. if (xClick == 22) and (yClick == 6) and (sideClick == monitorNames[monitorIndex]) then
  967. printLog("Decrease to Turbine RPM requested by "..progName.." GUI in handleTurbineMonitorClick(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..").")
  968. local rpmRateAdjustment = 909
  969. local newTurbineBaseSpeed = turbineBaseSpeed - rpmRateAdjustment
  970. if newTurbineBaseSpeed < 908 then
  971. newTurbineBaseSpeed = 908
  972. end
  973. sideClick, xClick, yClick = 0, 0, 0
  974. _G[turbineNames[turbineIndex]]["TurbineOptions"]["BaseSpeed"] = newTurbineBaseSpeed
  975. config.save(turbineNames[turbineIndex]..".options", _G[turbineNames[turbineIndex]])
  976. elseif (xClick == 29) and (yClick == 6) and (sideClick == monitorNames[monitorIndex]) then
  977. printLog("Increase to Turbine RPM requested by "..progName.." GUI in handleTurbineMonitorClick(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..").")
  978. local rpmRateAdjustment = 909
  979. local newTurbineBaseSpeed = turbineBaseSpeed + rpmRateAdjustment
  980. if newTurbineBaseSpeed > 2726 then
  981. newTurbineBaseSpeed = 2726
  982. end
  983. sideClick, xClick, yClick = 0, 0, 0
  984. _G[turbineNames[turbineIndex]]["TurbineOptions"]["BaseSpeed"] = newTurbineBaseSpeed
  985. config.save(turbineNames[turbineIndex]..".options", _G[turbineNames[turbineIndex]])
  986. else
  987. printLog("No change to Turbine RPM requested by "..progName.." GUI in handleTurbineMonitorClick(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..").")
  988. end -- if (xClick == 29) and (yClick == 4) and (sideClick == monitorNames[monitorIndex]) then
  989. end -- function handleTurbineMonitorClick(turbineIndex, monitorIndex)
  990.  
  991.  
  992. -- End helper functions
  993.  
  994.  
  995. -- Then initialize the monitors
  996. local function findMonitors()
  997. -- Empty out old list of monitors
  998. monitorList = {}
  999.  
  1000. printLog("Finding monitors...")
  1001. monitorList, monitorNames = getDevices("monitor")
  1002.  
  1003. if #monitorList == 0 then
  1004. printLog("No monitors found, continuing headless")
  1005. else
  1006. for monitorIndex = 1, #monitorList do
  1007. local monitor, monitorX, monitorY = nil, nil, nil
  1008. monitor = monitorList[monitorIndex]
  1009.  
  1010. if not monitor then
  1011. printLog("monitorList["..monitorIndex.."] in findMonitors() is NOT a valid monitor.")
  1012.  
  1013. table.remove(monitorList, monitorIndex) -- Remove invalid monitor from list
  1014. if monitorIndex ~= #monitorList then -- If we're not at the end, clean up
  1015. monitorIndex = monitorIndex - 1 -- We just removed an element
  1016. end -- if monitorIndex == #monitorList then
  1017. break -- Invalid monitorIndex
  1018. else -- valid monitor
  1019. monitor.setTextScale(2) -- Reset scale, see Issue #68
  1020. monitor.setTextScale(1.0) -- Make sure scale is correct
  1021. monitorX, monitorY = monitor.getSize()
  1022.  
  1023. if (monitorX == nil) or (monitorY == nil) then -- somehow a valid monitor, but non-existent sizes? Maybe fixes Issue #3
  1024. printLog("monitorList["..monitorIndex.."] in findMonitors() is NOT a valid sized monitor.")
  1025.  
  1026. table.remove(monitorList, monitorIndex) -- Remove invalid monitor from list
  1027. if monitorIndex ~= #monitorList then -- If we're not at the end, clean up
  1028. monitorIndex = monitorIndex - 1 -- We just removed an element
  1029. end -- if monitorIndex == #monitorList then
  1030. break -- Invalid monitorIndex
  1031.  
  1032. -- Check for minimum size to allow for monitor.setTextScale(0.5) to work for 3x2 debugging monitor, changes getSize()
  1033. elseif monitorX < 29 or monitorY < 12 then
  1034. term.redirect(monitor)
  1035. monitor.clear()
  1036. printLog("Removing monitor "..monitorIndex.." for being too small.")
  1037. monitor.setCursorPos(1,2)
  1038. write("Monitor is the wrong size!\n")
  1039. write("Needs to be at least 3x2.")
  1040. termRestore()
  1041.  
  1042. table.remove(monitorList, monitorIndex) -- Remove invalid monitor from list
  1043. if monitorIndex == #monitorList then -- If we're at the end already, break from loop
  1044. break
  1045. else
  1046. monitorIndex = monitorIndex - 1 -- We just removed an element
  1047. end -- if monitorIndex == #monitorList then
  1048.  
  1049. end -- if monitorX < 29 or monitorY < 12 then
  1050. end -- if not monitor then
  1051.  
  1052. printLog("Monitor["..monitorIndex.."] named \""..monitorNames[monitorIndex].."\" is a valid monitor of size x:"..monitorX.." by y:"..monitorY..".")
  1053. end -- for monitorIndex = 1, #monitorList do
  1054. end -- if #monitorList == 0 then
  1055.  
  1056. printLog("Found "..#monitorList.." monitor(s) in findMonitors().")
  1057. end -- local function findMonitors()
  1058.  
  1059.  
  1060. -- Initialize all Big Reactors - Reactors
  1061. local function findReactors()
  1062. -- Empty out old list of reactors
  1063. local newReactorList = {}
  1064. printLog("Finding reactors...")
  1065. newReactorList, reactorNames = getDevices("BigReactors-Reactor")
  1066.  
  1067. if #newReactorList == 0 then
  1068. printLog("No reactors found!")
  1069. error("Can't find any reactors!")
  1070. else -- Placeholder
  1071. for reactorIndex = 1, #newReactorList do
  1072. local reactor = nil
  1073. reactor = newReactorList[reactorIndex]
  1074.  
  1075. if not reactor then
  1076. printLog("reactorList["..reactorIndex.."] in findReactors() is NOT a valid Big Reactor.")
  1077.  
  1078. table.remove(newReactorList, reactorIndex) -- Remove invalid reactor from list
  1079. if reactorIndex ~= #newReactorList then -- If we're not at the end, clean up
  1080. reactorIndex = reactorIndex - 1 -- We just removed an element
  1081. end -- reactorIndex ~= #newReactorList then
  1082. return -- Invalid reactorIndex
  1083. else
  1084. printLog("reactor["..reactorIndex.."] in findReactors() is a valid Big Reactor.")
  1085. --initialize the default table
  1086. _G[reactorNames[reactorIndex]] = {}
  1087. _G[reactorNames[reactorIndex]]["ReactorOptions"] = {}
  1088. _G[reactorNames[reactorIndex]]["ReactorOptions"]["baseControlRodLevel"] = 80
  1089. _G[reactorNames[reactorIndex]]["ReactorOptions"]["lastTempPoll"] = 0
  1090. _G[reactorNames[reactorIndex]]["ReactorOptions"]["lastSteamPoll"] = 0
  1091. _G[reactorNames[reactorIndex]]["ReactorOptions"]["autoStart"] = true
  1092. _G[reactorNames[reactorIndex]]["ReactorOptions"]["activeCooled"] = true
  1093. _G[reactorNames[reactorIndex]]["ReactorOptions"]["rodOverride"] = false
  1094. _G[reactorNames[reactorIndex]]["ReactorOptions"]["controlRodAdjustAmount"] = controlRodAdjustAmount
  1095. _G[reactorNames[reactorIndex]]["ReactorOptions"]["reactorName"] = reactorNames[reactorIndex]
  1096. _G[reactorNames[reactorIndex]]["ReactorOptions"]["reactorCruising"] = false
  1097. _G[reactorNames[reactorIndex]]["ReactorOptions"]["integratedError"] = 0
  1098. _G[reactorNames[reactorIndex]]["ReactorOptions"]["proportionalGain"] = 0.05
  1099. _G[reactorNames[reactorIndex]]["ReactorOptions"]["integralGain"] = 0.00
  1100. _G[reactorNames[reactorIndex]]["ReactorOptions"]["derivativeGain"] = 0.05
  1101. _G[reactorNames[reactorIndex]]["ReactorOptions"]["integralMax"] = 200
  1102. _G[reactorNames[reactorIndex]]["ReactorOptions"]["integralMin"] = -200
  1103. _G[reactorNames[reactorIndex]]["ReactorOptions"]["reactorTargetTemp"] = 200
  1104. _G[reactorNames[reactorIndex]]["ReactorOptions"]["targetForSteam"] = false
  1105.  
  1106. if reactor.getConnected() then
  1107. printLog("reactor["..reactorIndex.."] in findReactors() is connected.")
  1108. else
  1109. printLog("reactor["..reactorIndex.."] in findReactors() is NOT connected.")
  1110. return -- Disconnected reactor
  1111. end
  1112. end
  1113.  
  1114. --failsafe
  1115. local tempTable = _G[reactorNames[reactorIndex]]
  1116.  
  1117. --check to make sure we get a valid config
  1118. if (config.load(reactorNames[reactorIndex]..".options")) ~= nil then
  1119. tempTable = config.load(reactorNames[reactorIndex]..".options")
  1120. else
  1121. --if we don't have a valid config from disk, make a valid config
  1122. config.save(reactorNames[reactorIndex]..".options", _G[reactorNames[reactorIndex]]) end
  1123.  
  1124. --load values from tempTable, checking for nil values along the way
  1125.  
  1126. for k, v in pairs(_G[reactorNames[reactorIndex]]["ReactorOptions"]) do
  1127. if tempTable["ReactorOptions"][k] ~= nil then
  1128. _G[reactorNames[reactorIndex]]["ReactorOptions"][k] = tempTable["ReactorOptions"][k]
  1129. end
  1130. end
  1131.  
  1132.  
  1133.  
  1134.  
  1135. --stricter typing, let's set these puppies up with the right type of value.
  1136. _G[reactorNames[reactorIndex]]["ReactorOptions"]["baseControlRodLevel"] = tonumber(_G[reactorNames[reactorIndex]]["ReactorOptions"]["baseControlRodLevel"])
  1137.  
  1138. _G[reactorNames[reactorIndex]]["ReactorOptions"]["lastTempPoll"] = tonumber(_G[reactorNames[reactorIndex]]["ReactorOptions"]["lastTempPoll"])
  1139.  
  1140. if (tostring(_G[reactorNames[reactorIndex]]["ReactorOptions"]["autoStart"]) == "true") then
  1141. _G[reactorNames[reactorIndex]]["ReactorOptions"]["autoStart"] = true
  1142. else
  1143. _G[reactorNames[reactorIndex]]["ReactorOptions"]["autoStart"] = false
  1144. end
  1145.  
  1146. if (tostring(_G[reactorNames[reactorIndex]]["ReactorOptions"]["activeCooled"]) == "true") then
  1147. _G[reactorNames[reactorIndex]]["ReactorOptions"]["activeCooled"] = true
  1148. else
  1149. _G[reactorNames[reactorIndex]]["ReactorOptions"]["activeCooled"] = false
  1150. end
  1151.  
  1152. if (tostring(_G[reactorNames[reactorIndex]]["ReactorOptions"]["rodOverride"]) == "true") then
  1153. printLog("Setting Rod Override for "..reactorNames[reactorIndex].." to true because value was "..tostring(_G[reactorNames[reactorIndex]]["ReactorOptions"]["rodOverride"]).." EOL")
  1154. _G[reactorNames[reactorIndex]]["ReactorOptions"]["rodOverride"] = true
  1155. else
  1156. printLog("Setting Rod Override for "..reactorNames[reactorIndex].." to false because value was "..tostring(_G[reactorNames[reactorIndex]]["ReactorOptions"]["rodOverride"]).." EOL")
  1157. _G[reactorNames[reactorIndex]]["ReactorOptions"]["rodOverride"] = false
  1158. end
  1159.  
  1160. _G[reactorNames[reactorIndex]]["ReactorOptions"]["controlRodAdjustAmount"] = tonumber(_G[reactorNames[reactorIndex]]["ReactorOptions"]["controlRodAdjustAmount"])
  1161.  
  1162. if (tostring(_G[reactorNames[reactorIndex]]["ReactorOptions"]["reactorCruising"]) == "true") then
  1163. _G[reactorNames[reactorIndex]]["ReactorOptions"]["reactorCruising"] = true
  1164. else
  1165. _G[reactorNames[reactorIndex]]["ReactorOptions"]["reactorCruising"] = false
  1166. end
  1167. if (tostring(_G[reactorNames[reactorIndex]]["ReactorOptions"]["targetForSteam"]) == "true") then
  1168. _G[reactorNames[reactorIndex]]["ReactorOptions"]["targetForSteam"] = true
  1169. else
  1170. _G[reactorNames[reactorIndex]]["ReactorOptions"]["targetForSteam"] = false
  1171. end
  1172.  
  1173. local number_configs = {"integratedError", "proportionalGain", "integralGain", "derivativeGain", "integralMax", "integralMin", "reactorTargetTemp"}
  1174. for k, v in pairs(number_configs) do
  1175. _G[reactorNames[reactorIndex]]["ReactorOptions"][v] = tonumber(_G[reactorNames[reactorIndex]]["ReactorOptions"][v])
  1176. end
  1177.  
  1178. --save one more time, in case we didn't have a complete config file before
  1179. config.save(reactorNames[reactorIndex]..".options", _G[reactorNames[reactorIndex]])
  1180. end -- for reactorIndex = 1, #newReactorList do
  1181. end -- if #newReactorList == 0 then
  1182.  
  1183. -- Overwrite old reactor list with the now updated list
  1184. reactorList = newReactorList
  1185.  
  1186. printLog("Found "..#reactorList.." reactor(s) in findReactors().")
  1187. end -- function findReactors()
  1188.  
  1189.  
  1190. -- Initialize all Big Reactors - Turbines
  1191. local function findTurbines()
  1192. -- Empty out old list of turbines
  1193. local newTurbineList = {}
  1194.  
  1195. printLog("Finding turbines...")
  1196. newTurbineList, turbineNames = getDevices("BigReactors-Turbine")
  1197.  
  1198. if #newTurbineList == 0 then
  1199. printLog("No turbines found") -- Not an error
  1200. else
  1201. for turbineIndex = 1, #newTurbineList do
  1202. local turbine = nil
  1203. turbine = newTurbineList[turbineIndex]
  1204.  
  1205. if not turbine then
  1206. printLog("turbineList["..turbineIndex.."] in findTurbines() is NOT a valid Big Reactors Turbine.")
  1207.  
  1208. table.remove(newTurbineList, turbineIndex) -- Remove invalid turbine from list
  1209. if turbineIndex ~= #newTurbineList then -- If we're not at the end, clean up
  1210. turbineIndex = turbineIndex - 1 -- We just removed an element
  1211. end -- turbineIndex ~= #newTurbineList then
  1212.  
  1213. return -- Invalid turbineIndex
  1214. else
  1215.  
  1216. _G[turbineNames[turbineIndex]] = {}
  1217. _G[turbineNames[turbineIndex]]["TurbineOptions"] = {}
  1218. _G[turbineNames[turbineIndex]]["TurbineOptions"]["LastSpeed"] = 0
  1219. _G[turbineNames[turbineIndex]]["TurbineOptions"]["BaseSpeed"] = 1817
  1220. _G[turbineNames[turbineIndex]]["TurbineOptions"]["autoStart"] = true
  1221. _G[turbineNames[turbineIndex]]["TurbineOptions"]["LastFlowCoilsEngaged"] = 2000
  1222. _G[turbineNames[turbineIndex]]["TurbineOptions"]["LastFlow"] = 2000
  1223. _G[turbineNames[turbineIndex]]["TurbineOptions"]["LastFlowCoilsDisengaged"] = 2000
  1224. _G[turbineNames[turbineIndex]]["TurbineOptions"]["flowOverride"] = false
  1225. _G[turbineNames[turbineIndex]]["TurbineOptions"]["turbineName"] = turbineNames[turbineIndex]
  1226. _G[turbineNames[turbineIndex]]["TurbineOptions"]["integratedError"] = 0
  1227. _G[turbineNames[turbineIndex]]["TurbineOptions"]["proportionalGain"] = 10
  1228. _G[turbineNames[turbineIndex]]["TurbineOptions"]["integralGain"] = 0.00
  1229. _G[turbineNames[turbineIndex]]["TurbineOptions"]["derivativeGain"] = 5
  1230. _G[turbineNames[turbineIndex]]["TurbineOptions"]["integralMax"] = 200
  1231. _G[turbineNames[turbineIndex]]["TurbineOptions"]["integralMin"] = -200
  1232.  
  1233.  
  1234. printLog("turbineList["..turbineIndex.."] in findTurbines() is a valid Big Reactors Turbine.")
  1235. if turbine.getConnected() then
  1236. printLog("turbine["..turbineIndex.."] in findTurbines() is connected.")
  1237. else
  1238. printLog("turbine["..turbineIndex.."] in findTurbines() is NOT connected.")
  1239. return -- Disconnected turbine
  1240. end
  1241. end
  1242.  
  1243. --failsafe
  1244. local tempTable = _G[turbineNames[turbineIndex]]
  1245.  
  1246. --check to make sure we get a valid config
  1247. if (config.load(turbineNames[turbineIndex]..".options")) ~= nil then
  1248. tempTable = config.load(turbineNames[turbineIndex]..".options")
  1249. else
  1250. --if we don't have a valid config from disk, make a valid config
  1251. config.save(turbineNames[turbineIndex]..".options", _G[turbineNames[turbineIndex]])
  1252. end
  1253.  
  1254.  
  1255. for k, v in pairs(_G[turbineNames[turbineIndex]]["TurbineOptions"]) do
  1256. if tempTable["TurbineOptions"][k] ~= nil then
  1257. _G[turbineNames[turbineIndex]]["TurbineOptions"][k] = tempTable["TurbineOptions"][k]
  1258. end
  1259. end
  1260.  
  1261.  
  1262.  
  1263.  
  1264.  
  1265. local number_configs = {"integratedError", "proportionalGain", "integralGain", "derivativeGain", "integralMax", "integralMin"}
  1266. for k, v in pairs(number_configs) do
  1267. _G[turbineNames[turbineIndex]]["TurbineOptions"][v] = tonumber(_G[turbineNames[turbineIndex]]["TurbineOptions"][v])
  1268. end
  1269.  
  1270.  
  1271. --save once more just to make sure we got it
  1272. config.save(turbineNames[turbineIndex]..".options", _G[turbineNames[turbineIndex]])
  1273. end -- for turbineIndex = 1, #newTurbineList do
  1274.  
  1275. -- Overwrite old turbine list with the now updated list
  1276. turbineList = newTurbineList
  1277. end -- if #newTurbineList == 0 then
  1278.  
  1279. printLog("Found "..#turbineList.." turbine(s) in findTurbines().")
  1280. end -- function findTurbines()
  1281.  
  1282. -- Assign status, reactors, turbines and debug output to the monitors that shall display them
  1283. -- Depends on the [monitor,reactor,turbine]Lists being populated already
  1284. local function assignMonitors()
  1285.  
  1286. local monitors = {}
  1287. monitorAssignments = {}
  1288.  
  1289. printLog("Assigning monitors...")
  1290.  
  1291. local m = config.load(monitorOptionFileName)
  1292. if (m ~= nil) then
  1293. -- first, merge the detected and the configured monitor lists
  1294. -- this is to ensure we pick up new additions to the network
  1295. for monitorIndex, monitorName in ipairs(monitorNames) do
  1296. monitors[monitorName] = m.Monitors[monitorName] or ""
  1297. end
  1298. -- then, go through all of it again to build our runtime data structure
  1299. for monitorName, assignedName in pairs(monitors) do
  1300. printLog("Looking for monitor and device named "..monitorName.." and "..assignedName)
  1301. for monitorIndex = 1, #monitorNames do
  1302. printLog("if "..monitorName.." == "..monitorNames[monitorIndex].." then", DEBUG)
  1303.  
  1304. if monitorName == monitorNames[monitorIndex] then
  1305. printLog("Found "..monitorName.." at index "..monitorIndex, DEBUG)
  1306. if assignedName == "Status" then
  1307. monitorAssignments[monitorName] = {type="Status", index=monitorIndex}
  1308. elseif assignedName == "Debug" then
  1309. monitorAssignments[monitorName] = {type="Debug", index=monitorIndex}
  1310. else
  1311. local maxListLen = math.max(#reactorNames, #turbineNames)
  1312. for i = 1, maxListLen do
  1313. if assignedName == reactorNames[i] then
  1314. monitorAssignments[monitorName] = {type="Reactor", index=monitorIndex, reactorName=reactorNames[i], reactorIndex=i}
  1315. break
  1316. elseif assignedName == turbineNames[i] then
  1317. monitorAssignments[monitorName] = {type="Turbine", index=monitorIndex, turbineName=turbineNames[i], turbineIndex=i}
  1318. break
  1319. elseif i == maxListLen then
  1320. printLog("assignMonitors(): Monitor "..monitorName.." was configured to display nonexistant device "..assignedName..". Setting inactive.", WARN)
  1321. monitorAssignments[monitorName] = {type="Inactive", index=monitorIndex}
  1322. end
  1323. end
  1324. end
  1325. break
  1326. elseif monitorIndex == #monitorNames then
  1327. printLog("assignMonitors(): Monitor "..monitorName.." not found. It was configured to display device "..assignedName..". Discarding.", WARN)
  1328. end
  1329. end
  1330. end
  1331. else
  1332. printLog("No valid monitor configuration found, generating...")
  1333. --print(tostring(monitorNames))
  1334. -- create assignments that reflect the setup before 0.3.17
  1335. local monitorIndex = 1
  1336. monitorAssignments[monitorNames[1]] = {type="Status", index=1}
  1337. monitorIndex = monitorIndex + 1
  1338. for reactorIndex = 1, #reactorList do
  1339. if monitorIndex > #monitorList then
  1340. break
  1341. end
  1342. monitorAssignments[monitorNames[monitorIndex]] = {type="Reactor", index=monitorIndex, reactorName=reactorNames[reactorIndex], reactorIndex=reactorIndex}
  1343. printLog(monitorNames[monitorIndex].." -> "..reactorNames[reactorIndex])
  1344.  
  1345. monitorIndex = monitorIndex + 1
  1346. end
  1347. for turbineIndex = 1, #turbineList do
  1348. if monitorIndex > #monitorList then
  1349. break
  1350. end
  1351. monitorAssignments[monitorNames[monitorIndex]] = {type="Turbine", index=monitorIndex, turbineName=turbineNames[turbineIndex], turbineIndex=turbineIndex}
  1352. printLog(monitorNames[monitorIndex].." -> "..turbineNames[turbineIndex])
  1353.  
  1354. monitorIndex = monitorIndex + 1
  1355. end
  1356. if monitorIndex <= #monitorList then
  1357. monitorAssignments[monitorNames[#monitorList]] = {type="Debug", index=#monitorList}
  1358. end
  1359. end
  1360.  
  1361. tprint(monitorAssignments)
  1362.  
  1363. saveMonitorAssignments()
  1364.  
  1365. end -- function assignMonitors()
  1366.  
  1367. local eventHandler
  1368. -- Replacement for sleep, which passes on events instead of dropping themo
  1369. -- Straight from http://computercraft.info/wiki/Os.sleep
  1370. local function wait(time)
  1371. local timer = os.startTimer(time)
  1372.  
  1373. while true do
  1374. local event = {os.pullEvent()}
  1375.  
  1376. if (event[1] == "timer" and event[2] == timer) then
  1377. break
  1378. else
  1379. eventHandler(event[1], event[2], event[3], event[4])
  1380. end
  1381. end
  1382. end
  1383.  
  1384.  
  1385. -- Return current energy buffer in a specific reactor by %
  1386. local function getReactorStoredEnergyBufferPercent(reactor)
  1387. printLog("Called as getReactorStoredEnergyBufferPercent(reactor).")
  1388.  
  1389. if not reactor then
  1390. printLog("getReactorStoredEnergyBufferPercent() did NOT receive a valid Big Reactor Reactor.")
  1391. return -- Invalid reactorIndex
  1392. else
  1393. printLog("getReactorStoredEnergyBufferPercent() did receive a valid Big Reactor Reactor.")
  1394. end
  1395.  
  1396. local energyBufferStorage = reactor.getEnergyStored()
  1397. return round(energyBufferStorage/100000, 1) -- (buffer/10000000 RF)*100%
  1398. end -- function getReactorStoredEnergyBufferPercent(reactor)
  1399.  
  1400.  
  1401. -- Return current energy buffer in a specific Turbine by %
  1402. local function getTurbineStoredEnergyBufferPercent(turbine)
  1403. printLog("Called as getTurbineStoredEnergyBufferPercent(turbine)")
  1404.  
  1405. if not turbine then
  1406. printLog("getTurbineStoredEnergyBufferPercent() did NOT receive a valid Big Reactor Turbine.")
  1407. return -- Invalid reactorIndex
  1408. else
  1409. printLog("getTurbineStoredEnergyBufferPercent() did receive a valid Big Reactor Turbine.")
  1410. end
  1411.  
  1412. local energyBufferStorage = turbine.getEnergyStored()
  1413. return round(energyBufferStorage/10000, 1) -- (buffer/1000000 RF)*100%
  1414. end -- function getTurbineStoredEnergyBufferPercent(turbine)
  1415.  
  1416.  
  1417. -- Modify reactor control rod levels to keep temperature with defined parameters
  1418. local function temperatureControl(reactorIndex)
  1419. printLog("Called as temperatureControl(reactorIndex="..reactorIndex..")")
  1420.  
  1421. local reactor = nil
  1422. reactor = reactorList[reactorIndex]
  1423. if not reactor then
  1424. printLog("reactor["..reactorIndex.."] in temperatureControl(reactorIndex="..reactorIndex..") is NOT a valid Big Reactor.")
  1425. return -- Invalid reactorIndex
  1426. else
  1427. printLog("reactor["..reactorIndex.."] in temperatureControl(reactorIndex="..reactorIndex..") is a valid Big Reactor.")
  1428.  
  1429. if reactor.getConnected() then
  1430. printLog("reactor["..reactorIndex.."] in temperatureControl(reactorIndex="..reactorIndex..") is connected.")
  1431. else
  1432. printLog("reactor["..reactorIndex.."] in temperatureControl(reactorIndex="..reactorIndex..") is NOT connected.")
  1433. return -- Disconnected reactor
  1434. end -- if reactor.getConnected() then
  1435. end
  1436.  
  1437. local reactorNum = reactorIndex
  1438. local rodPercentage = math.ceil(reactor.getControlRodLevel(0))
  1439. local reactorTemp = math.ceil(reactor.getFuelTemperature())
  1440.  
  1441. --bypass if the reactor itself is set to not be auto-controlled
  1442. if ((not _G[reactorNames[reactorIndex]]["ReactorOptions"]["rodOverride"]) or (_G[reactorNames[reactorIndex]]["ReactorOptions"]["rodOverride"] == "false")) then
  1443. -- No point modifying control rod levels for temperature if the reactor is offline
  1444. if reactor.getActive() then
  1445. -- Actively cooled reactors should range between 0^C-300^C
  1446. -- Actually, active-cooled reactors should range between 300 and 420C (Mechaet)
  1447. -- Accordingly I changed the below lines
  1448. -- if reactor.isActivelyCooled() and not knowlinglyOverride then
  1449. -- -- below was 0
  1450. -- localMinReactorTemp = 300
  1451. -- -- below was 300
  1452. -- localMaxReactorTemp = 420
  1453. -- end
  1454. -- and I (matthew) got rid of them because of the new control algorithm
  1455. local lastTempPoll = _G[reactorNames[reactorIndex]]["ReactorOptions"]["lastTempPoll"]
  1456.  
  1457. local target
  1458. local Error
  1459. local derivedError
  1460.  
  1461. if _G[reactorNames[reactorIndex]]["ReactorOptions"]["targetForSteam"] then
  1462. printLog("Targeting for steam", WARN)
  1463. target = steamRequested
  1464. Error = steamDelivered - target
  1465. derivedError = reactor.getHotFluidProducedLastTick() - _G[reactorNames[reactorIndex]]["ReactorOptions"]["lastSteamPoll"]
  1466.  
  1467. else
  1468. target = _G[reactorNames[reactorIndex]]["ReactorOptions"]["reactorTargetTemp"] -- target is the setpoint
  1469. Error = reactorTemp - target
  1470. derivedError = reactorTemp - lastTempPoll
  1471. end
  1472.  
  1473. local integratedError = _G[reactorNames[reactorIndex]]["ReactorOptions"]["integratedError"] + Error
  1474.  
  1475. if integratedError > _G[reactorNames[reactorIndex]]["ReactorOptions"]["integralMax"] then
  1476. integratedError = _G[reactorNames[reactorIndex]]["ReactorOptions"]["integralMax"]
  1477. end
  1478.  
  1479. if integratedError < _G[reactorNames[reactorIndex]]["ReactorOptions"]["integralMin"] then
  1480. integratedError = _G[reactorNames[reactorIndex]]["ReactorOptions"]["integralMin"]
  1481. end
  1482.  
  1483. _G[reactorNames[reactorIndex]]["ReactorOptions"]["integratedError"] = integratedError
  1484.  
  1485.  
  1486. -- Coefficients (gains)
  1487. local Kp = _G[reactorNames[reactorIndex]]["ReactorOptions"]["proportionalGain"]
  1488. local Ki = _G[reactorNames[reactorIndex]]["ReactorOptions"]["integralGain"]
  1489. local Kd = _G[reactorNames[reactorIndex]]["ReactorOptions"]["derivativeGain"]
  1490.  
  1491.  
  1492. local adjustAmount = round(Kp * Error + Ki * integratedError + Kd * derivedError, 0) -- for the control rods
  1493. local coefficientsString = "Kp:" .. tostring(Kp) .. " Ki:" .. tostring(Ki) .. " Kd:" .. tostring(Kd)
  1494. local errorsString = "Ep:" .. tostring(Error) .. " Ei:" .. tostring(integratedError) .. " Ed:" .. tostring(derivedError) .. " AA:" .. tostring(adjustAmount)
  1495.  
  1496. printLog(coefficientsString, INFO)
  1497. printLog(errorsString, INFO)
  1498.  
  1499. local setLevel = rodPercentage + adjustAmount
  1500.  
  1501. if setLevel > 100 then
  1502. setLevel = 100
  1503. end
  1504. if setLevel < 0 then
  1505. setLevel = 0
  1506. end
  1507.  
  1508. -- Prevent Runaway
  1509. printLog("running temperatureControl Reactor Temp: "..reactorTemp.." Target Temp: "..target, WARN)
  1510. if reactorTemp > 2 * target then
  1511. printLog("preventing runaway", WARN)
  1512. setLevel = 100
  1513. end
  1514.  
  1515. reactor.setAllControlRodLevels(setLevel)
  1516.  
  1517.  
  1518. --always set this number
  1519. _G[reactorNames[reactorIndex]]["ReactorOptions"]["lastTempPoll"] = reactorTemp
  1520. _G[reactorNames[reactorIndex]]["ReactorOptions"]["lastSteamPoll"] = reactor.getHotFluidProducedLastTick()
  1521.  
  1522. config.save(reactorNames[reactorIndex]..".options", _G[reactorNames[reactorIndex]])
  1523. end -- if reactor.getActive() then
  1524. else
  1525. printLog("Bypassed temperature control due to rodOverride being "..tostring(_G[reactorNames[reactorIndex]]["ReactorOptions"]["rodOverride"]).." EOL")
  1526. end -- if not _G[reactorNames[reactorIndex]]["ReactorOptions"]["rodOverride"] then
  1527. end -- function temperatureControl(reactorIndex)
  1528.  
  1529. -- Load saved reactor parameters if ReactorOptions file exists
  1530. local function loadReactorOptions()
  1531. local reactorOptions = fs.open("ReactorOptions", "r") -- See http://computercraft.info/wiki/Fs.open
  1532.  
  1533. if reactorOptions then
  1534. -- The following values were added by Lolmer
  1535. minStoredEnergyPercent = tonumber(reactorOptions.readLine())
  1536. maxStoredEnergyPercent = tonumber(reactorOptions.readLine())
  1537. --added by Mechaet
  1538. -- If we succeeded in reading a string, convert it to a number
  1539.  
  1540. reactorOptions.close()
  1541. end -- if reactorOptions then
  1542.  
  1543. -- Set default values if we failed to read any of the above
  1544. if minStoredEnergyPercent == nil then
  1545. minStoredEnergyPercent = 15
  1546. end
  1547.  
  1548. if maxStoredEnergyPercent == nil then
  1549. maxStoredEnergyPercent = 85
  1550. end
  1551.  
  1552. end -- function loadReactorOptions()
  1553.  
  1554.  
  1555. -- Save our reactor parameters
  1556. local function saveReactorOptions()
  1557. local reactorOptions = fs.open("ReactorOptions", "w") -- See http://computercraft.info/wiki/Fs.open
  1558.  
  1559. -- If we can save the files, save them
  1560. if reactorOptions then
  1561. local reactorIndex = 1
  1562. -- The following values were added by Lolmer
  1563. reactorOptions.writeLine(minStoredEnergyPercent)
  1564. reactorOptions.writeLine(maxStoredEnergyPercent)
  1565. reactorOptions.close()
  1566. else
  1567. printLog("Failed to open file ReactorOptions for writing!")
  1568. end -- if reactorOptions then
  1569. end -- function saveReactorOptions()
  1570.  
  1571.  
  1572. local function displayReactorBars(barParams)
  1573. -- Default to first reactor and first monitor
  1574. setmetatable(barParams,{__index={reactorIndex=1, monitorIndex=1}})
  1575. local reactorIndex, monitorIndex =
  1576. barParams[1] or barParams.reactorIndex,
  1577. barParams[2] or barParams.monitorIndex
  1578.  
  1579. printLog("Called as displayReactorBars(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..").")
  1580.  
  1581. -- Grab current monitor
  1582. local monitor = nil
  1583. monitor = monitorList[monitorIndex]
  1584. if not monitor then
  1585. printLog("monitor["..monitorIndex.."] in displayReactorBars(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..") is NOT a valid monitor.")
  1586. return -- Invalid monitorIndex
  1587. end
  1588.  
  1589. -- Grab current reactor
  1590. local reactor = nil
  1591. reactor = reactorList[reactorIndex]
  1592. local reactorInfo = _G[reactorNames[reactorIndex]]
  1593. if not reactor then
  1594. printLog("reactor["..reactorIndex.."] in displayReactorBars(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..") is NOT a valid Big Reactor.")
  1595. return -- Invalid reactorIndex
  1596. else
  1597. printLog("reactor["..reactorIndex.."] in displayReactorBars(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..") is a valid Big Reactor.")
  1598. if reactor.getConnected() then
  1599. printLog("reactor["..reactorIndex.."] in displayReactorBars(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..") is connected.")
  1600. else
  1601. printLog("reactor["..reactorIndex.."] in displayReactorBars(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..") is NOT connected.")
  1602. return -- Disconnected reactor
  1603. end -- if reactor.getConnected() then
  1604. end -- if not reactor then
  1605.  
  1606. -- Draw border lines
  1607. local width, height = monitor.getSize()
  1608. printLog("Size of monitor is "..width.."w x"..height.."h in displayReactorBars(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..")")
  1609.  
  1610. for i=3, 5 do
  1611. monitor.setCursorPos(20, i)
  1612. monitor.write("|")
  1613. end
  1614.  
  1615. drawLine(6, monitorIndex)
  1616. monitor.setCursorPos(1, height)
  1617. monitor.write("< ")
  1618. monitor.setCursorPos(width-1, height)
  1619. monitor.write(" >")
  1620.  
  1621. -- Draw some text
  1622. local fuelString = "Fuel: "
  1623. local tempString = "Temp: "
  1624. local energyBufferString = ""
  1625.  
  1626. if reactor.isActivelyCooled() then
  1627. energyBufferString = "Steam: "
  1628. else
  1629. energyBufferString = "Energy: "
  1630. end
  1631.  
  1632. local padding = math.max(string.len(fuelString), string.len(tempString), string.len(energyBufferString))
  1633.  
  1634. local fuelPercentage = round(reactor.getFuelAmount()/reactor.getFuelAmountMax()*100,1)
  1635. print{fuelString,2,3,monitorIndex}
  1636. print{fuelPercentage.." %",padding+2,3,monitorIndex}
  1637.  
  1638. local reactorTemp = math.ceil(reactor.getFuelTemperature())
  1639. print{tempString,2,5,monitorIndex}
  1640. print{reactorTemp.." C",padding+2,5,monitorIndex}
  1641.  
  1642. local rodPercentage = math.ceil(reactor.getControlRodLevel(0))
  1643. printLog("Current Rod Percentage for reactor["..reactorIndex.."] is "..rodPercentage.."% in displayReactorBars(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..").")
  1644. print{"Target °C",21,3,monitorIndex}
  1645. print{"< >",21,4,monitorIndex}
  1646. --print{stringTrim(rodPercentage),23,4,monitorIndex}
  1647. local target = tostring(reactorInfo["ReactorOptions"]["reactorTargetTemp"])
  1648. print{stringTrim(target),23,4,monitorIndex}
  1649.  
  1650.  
  1651. -- getEnergyProducedLastTick() is used for both RF/t (passively cooled) and mB/t (actively cooled)
  1652. local energyBuffer = reactor.getEnergyProducedLastTick()
  1653. if reactor.isActivelyCooled() then
  1654. printLog("reactor["..reactorIndex.."] produced "..energyBuffer.." mB last tick in displayReactorBars(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..").")
  1655. else
  1656. printLog("reactor["..reactorIndex.."] produced "..energyBuffer.." RF last tick in displayReactorBars(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..").")
  1657. end
  1658.  
  1659. print{energyBufferString,2,4,monitorIndex}
  1660.  
  1661. -- Actively cooled reactors do not produce energy, only hot fluid mB/t to be used in a turbine
  1662. -- still uses getEnergyProducedLastTick for mB/t of hot fluid generated
  1663. if not reactor.isActivelyCooled() then
  1664. printLog("reactor["..reactorIndex.."] in displayReactorBars(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..") is NOT an actively cooled reactor.")
  1665.  
  1666. -- Draw stored energy buffer bar
  1667. drawBar(2,8,28,8,colors.gray,monitorIndex)
  1668.  
  1669. local curStoredEnergyPercent = getReactorStoredEnergyBufferPercent(reactor)
  1670. if curStoredEnergyPercent > 4 then
  1671. drawBar(2, 8, math.floor(26*curStoredEnergyPercent/100)+2, 8, colors.yellow, monitorIndex)
  1672. elseif curStoredEnergyPercent > 0 then
  1673. drawPixel(2, 8, colors.yellow, monitorIndex)
  1674. end -- if curStoredEnergyPercent > 4 then
  1675.  
  1676. print{"Energy Buffer",2,7,monitorIndex}
  1677. print{curStoredEnergyPercent, width-(string.len(curStoredEnergyPercent)+2),7,monitorIndex}
  1678. print{"%",28,7,monitorIndex}
  1679.  
  1680. print{math.ceil(energyBuffer).." RF/t",padding+2,4,monitorIndex}
  1681. else
  1682. printLog("reactor["..reactorIndex.."] in displayReactorBars(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..") is an actively cooled reactor.")
  1683. print{math.ceil(energyBuffer).." mB/t",padding+2,4,monitorIndex}
  1684. end -- if not reactor.isActivelyCooled() then
  1685.  
  1686. -- Print rod override status
  1687. local reactorRodOverrideStatus = ""
  1688.  
  1689. print{"Rod Auto-adjust:",2,9,monitorIndex}
  1690.  
  1691. if not _G[reactorNames[reactorIndex]]["ReactorOptions"]["rodOverride"] then
  1692. printLog("Reactor Rod Override status is: "..tostring(_G[reactorNames[reactorIndex]]["ReactorOptions"]["rodOverride"]).." EOL")
  1693. reactorRodOverrideStatus = "Enabled"
  1694. monitor.setTextColor(colors.green)
  1695. else
  1696. printLog("Reactor Rod Override status is: "..tostring(_G[reactorNames[reactorIndex]]["ReactorOptions"]["rodOverride"]).." EOL")
  1697. reactorRodOverrideStatus = "Disabled"
  1698. monitor.setTextColor(colors.red)
  1699. end -- if not reactorRodOverride then
  1700. printLog("reactorRodOverrideStatus is \""..reactorRodOverrideStatus.."\" in displayReactorBars(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..").")
  1701.  
  1702. print{reactorRodOverrideStatus, width - string.len(reactorRodOverrideStatus) - 1, 9, monitorIndex}
  1703. monitor.setTextColor(colors.white)
  1704.  
  1705. print{"Reactivity: "..math.ceil(reactor.getFuelReactivity()).." %", 2, 10, monitorIndex}
  1706. print{"Fuel: "..round(reactor.getFuelConsumedLastTick(),3).." mB/t", 2, 11, monitorIndex}
  1707. print{"Waste: "..reactor.getWasteAmount().." mB", width-(string.len(reactor.getWasteAmount())+10), 11, monitorIndex}
  1708.  
  1709. monitor.setTextColor(colors.blue)
  1710. printCentered(_G[reactorNames[reactorIndex]]["ReactorOptions"]["reactorName"],12,monitorIndex)
  1711. monitor.setTextColor(colors.white)
  1712.  
  1713. -- monitor switch controls
  1714. monitor.setCursorPos(1, height)
  1715. monitor.write("<")
  1716. monitor.setCursorPos(width, height)
  1717. monitor.write(">")
  1718.  
  1719. end -- function displayReactorBars(barParams)
  1720.  
  1721.  
  1722. local function reactorStatus(statusParams)
  1723. -- Default to first reactor and first monitor
  1724. setmetatable(statusParams,{__index={reactorIndex=1, monitorIndex=1}})
  1725. local reactorIndex, monitorIndex =
  1726. statusParams[1] or statusParams.reactorIndex,
  1727. statusParams[2] or statusParams.monitorIndex
  1728. printLog("Called as reactorStatus(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..")")
  1729.  
  1730. -- Grab current monitor
  1731. local monitor = nil
  1732. monitor = monitorList[monitorIndex]
  1733. if not monitor then
  1734. printLog("monitor["..monitorIndex.."] in reactorStatus(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..") is NOT a valid monitor.")
  1735. return -- Invalid monitorIndex
  1736. end
  1737.  
  1738. -- Grab current reactor
  1739. local reactor = nil
  1740. reactor = reactorList[reactorIndex]
  1741. if not reactor then
  1742. printLog("reactor["..reactorIndex.."] in reactorStatus(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..") is NOT a valid Big Reactor.")
  1743. return -- Invalid reactorIndex
  1744. else
  1745. printLog("reactor["..reactorIndex.."] in reactorStatus(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..") is a valid Big Reactor.")
  1746. end
  1747.  
  1748. local width, height = monitor.getSize()
  1749. local reactorStatus = ""
  1750.  
  1751. if reactor.getConnected() then
  1752. printLog("reactor["..reactorIndex.."] in reactorStatus(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..") is connected.")
  1753.  
  1754. if reactor.getActive() then
  1755. reactorStatus = "ONLINE"
  1756.  
  1757. -- Set "ONLINE" to blue if the actively cooled reactor is both in cruise mode and online
  1758. if _G[reactorNames[reactorIndex]]["ReactorOptions"]["reactorCruising"] and reactor.isActivelyCooled() then
  1759. monitor.setTextColor(colors.blue)
  1760. else
  1761. monitor.setTextColor(colors.green)
  1762. end -- if reactorCruising and reactor.isActivelyCooled() then
  1763. else
  1764. reactorStatus = "OFFLINE"
  1765. monitor.setTextColor(colors.red)
  1766. end -- if reactor.getActive() then
  1767.  
  1768. else
  1769. printLog("reactor["..reactorIndex.."] in reactorStatus(reactorIndex="..reactorIndex..",monitorIndex="..monitorIndex..") is NOT connected.")
  1770. reactorStatus = "DISCONNECTED"
  1771. monitor.setTextColor(colors.red)
  1772. end -- if reactor.getConnected() then
  1773. _G[reactorNames[reactorIndex]]["ReactorOptions"]["Status"] = reactorStatus
  1774. print{reactorStatus, width - string.len(reactorStatus) - 1, 1, monitorIndex}
  1775. monitor.setTextColor(colors.white)
  1776. end -- function reactorStatus(statusParams)
  1777.  
  1778.  
  1779. -- Display all found reactors' status to selected monitor
  1780. -- This is only called if multiple reactors and/or a reactor plus at least one turbine are found
  1781. local function displayAllStatus(monitorIndex)
  1782. local reactor, turbine = nil, nil
  1783. local onlineReactor, onlineTurbine = 0, 0
  1784. local totalReactorRF, totalReactorSteam, totalTurbineRF = 0, 0, 0
  1785. local totalReactorFuelConsumed = 0
  1786. local totalCoolantStored, totalSteamStored, totalEnergy, totalMaxEnergyStored = 0, 0, 0, 0 -- Total turbine and reactor energy buffer and overall capacity
  1787. local maxSteamStored = (2000*#turbineList)+(5000*#reactorList)
  1788. local maxCoolantStored = (2000*#turbineList)+(5000*#reactorList)
  1789.  
  1790. local monitor = monitorList[monitorIndex]
  1791. if not monitor then
  1792. printLog("monitor["..monitorIndex.."] in displayAllStatus() is NOT a valid monitor.")
  1793. return -- Invalid monitorIndex
  1794. end
  1795.  
  1796. for reactorIndex = 1, #reactorList do
  1797. reactor = reactorList[reactorIndex]
  1798. if not reactor then
  1799. printLog("reactor["..reactorIndex.."] in displayAllStatus() is NOT a valid Big Reactor.")
  1800. break -- Invalid reactorIndex
  1801. else
  1802. printLog("reactor["..reactorIndex.."] in displayAllStatus() is a valid Big Reactor.")
  1803. end -- if not reactor then
  1804.  
  1805. if reactor.getConnected() then
  1806. printLog("reactor["..reactorIndex.."] in displayAllStatus() is connected.")
  1807. if reactor.getActive() then
  1808. onlineReactor = onlineReactor + 1
  1809. totalReactorFuelConsumed = totalReactorFuelConsumed + reactor.getFuelConsumedLastTick()
  1810. end -- reactor.getActive() then
  1811.  
  1812. -- Actively cooled reactors do not produce or store energy
  1813. if not reactor.isActivelyCooled() then
  1814. totalMaxEnergyStored = totalMaxEnergyStored + 10000000 -- Reactors store 10M RF
  1815. totalEnergy = totalEnergy + reactor.getEnergyStored()
  1816. totalReactorRF = totalReactorRF + reactor.getEnergyProducedLastTick()
  1817. else
  1818. totalReactorSteam = totalReactorSteam + reactor.getEnergyProducedLastTick()
  1819. totalSteamStored = totalSteamStored + reactor.getHotFluidAmount()
  1820. totalCoolantStored = totalCoolantStored + reactor.getCoolantAmount()
  1821. end -- if not reactor.isActivelyCooled() then
  1822. else
  1823. printLog("reactor["..reactorIndex.."] in displayAllStatus() is NOT connected.")
  1824. end -- if reactor.getConnected() then
  1825. end -- for reactorIndex = 1, #reactorList do
  1826.  
  1827. for turbineIndex = 1, #turbineList do
  1828. turbine = turbineList[turbineIndex]
  1829. if not turbine then
  1830. printLog("turbine["..turbineIndex.."] in displayAllStatus() is NOT a valid Turbine.")
  1831. break -- Invalid turbineIndex
  1832. else
  1833. printLog("turbine["..turbineIndex.."] in displayAllStatus() is a valid Turbine.")
  1834. end -- if not turbine then
  1835.  
  1836. if turbine.getConnected() then
  1837. printLog("turbine["..turbineIndex.."] in displayAllStatus() is connected.")
  1838. if turbine.getActive() then
  1839. onlineTurbine = onlineTurbine + 1
  1840. end
  1841.  
  1842. totalMaxEnergyStored = totalMaxEnergyStored + 1000000 -- Turbines store 1M RF
  1843. totalEnergy = totalEnergy + turbine.getEnergyStored()
  1844. totalTurbineRF = totalTurbineRF + turbine.getEnergyProducedLastTick()
  1845. totalSteamStored = totalSteamStored + turbine.getInputAmount()
  1846. totalCoolantStored = totalCoolantStored + turbine.getOutputAmount()
  1847. else
  1848. printLog("turbine["..turbineIndex.."] in displayAllStatus() is NOT connected.")
  1849. end -- if turbine.getConnected() then
  1850. end -- for turbineIndex = 1, #turbineList do
  1851.  
  1852. print{"Reactors online/found: "..onlineReactor.."/"..#reactorList, 2, 3, monitorIndex}
  1853. print{"Turbines online/found: "..onlineTurbine.."/"..#turbineList, 2, 4, monitorIndex}
  1854.  
  1855. if totalReactorRF ~= 0 then
  1856. monitor.setTextColor(colors.blue)
  1857. printRight("Reactor", 9, monitorIndex)
  1858. monitor.setTextColor(colors.white)
  1859. printRight(math.ceil(totalReactorRF).." (RF/t)", 10, monitorIndex)
  1860. end
  1861.  
  1862. if #turbineList then
  1863. -- Display liquids
  1864. monitor.setTextColor(colors.blue)
  1865. printLeft("Steam (mB)", 6, monitorIndex)
  1866. monitor.setTextColor(colors.white)
  1867. printLeft(math.ceil(totalSteamStored).."/"..maxSteamStored, 7, monitorIndex)
  1868. printLeft(math.ceil(totalReactorSteam).." mB/t", 8, monitorIndex)
  1869. monitor.setTextColor(colors.blue)
  1870. printRight("Coolant (mB)", 6, monitorIndex)
  1871. monitor.setTextColor(colors.white)
  1872. printRight(math.ceil(totalCoolantStored).."/"..maxCoolantStored, 7, monitorIndex)
  1873.  
  1874. monitor.setTextColor(colors.blue)
  1875. printLeft("Turbine", 9, monitorIndex)
  1876. monitor.setTextColor(colors.white)
  1877. printLeft(math.ceil(totalTurbineRF).." RF/t", 10, monitorIndex)
  1878. end -- if #turbineList then
  1879.  
  1880. printCentered("Fuel: "..round(totalReactorFuelConsumed,3).." mB/t", 11, monitorIndex)
  1881. printCentered("Buffer: "..formatReadableSIUnit(math.ceil(totalEnergy)).."/"..formatReadableSIUnit(totalMaxEnergyStored).." RF", 12, monitorIndex)
  1882.  
  1883. -- monitor switch controls
  1884. local width, height = monitor.getSize()
  1885. monitor.setCursorPos(1, height)
  1886. monitor.write("<")
  1887. monitor.setCursorPos(width, height)
  1888. monitor.write(">")
  1889.  
  1890. end -- function displayAllStatus()
  1891.  
  1892.  
  1893. -- Get turbine status
  1894. local function displayTurbineBars(turbineIndex, monitorIndex)
  1895. printLog("Called as displayTurbineBars(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..").")
  1896.  
  1897. -- Grab current monitor
  1898. local monitor = nil
  1899. monitor = monitorList[monitorIndex]
  1900. if not monitor then
  1901. printLog("monitor["..monitorIndex.."] in displayTurbineBars(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..") is NOT a valid monitor.")
  1902. return -- Invalid monitorIndex
  1903. end
  1904.  
  1905. -- Grab current turbine
  1906. local turbine = nil
  1907. turbine = turbineList[turbineIndex]
  1908. if not turbine then
  1909. printLog("turbine["..turbineIndex.."] in displayTurbineBars(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..") is NOT a valid Big Turbine.")
  1910. return -- Invalid turbineIndex
  1911. else
  1912. printLog("turbine["..turbineIndex.."] in displayTurbineBars(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..") is a valid Big Turbine.")
  1913. if turbine.getConnected() then
  1914. printLog("turbine["..turbineIndex.."] in displayTurbineBars(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..") is connected.")
  1915. else
  1916. printLog("turbine["..turbineIndex.."] in displayTurbineBars(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..") is NOT connected.")
  1917. return -- Disconnected turbine
  1918. end -- if turbine.getConnected() then
  1919. end -- if not turbine then
  1920.  
  1921. --local variable to match the view on the monitor
  1922. local turbineBaseSpeed = tonumber(_G[turbineNames[turbineIndex]]["TurbineOptions"]["BaseSpeed"])
  1923.  
  1924. -- Draw border lines
  1925. local width, height = monitor.getSize()
  1926.  
  1927. for i=3, 6 do
  1928. monitor.setCursorPos(21, i)
  1929. monitor.write("|")
  1930. end
  1931.  
  1932. drawLine(7,monitorIndex)
  1933. monitor.setCursorPos(1, height)
  1934. monitor.write("< ")
  1935. monitor.setCursorPos(width-1, height)
  1936. monitor.write(" >")
  1937.  
  1938. local turbineFlowRate = tonumber(_G[turbineNames[turbineIndex]]["TurbineOptions"]["LastFlow"])
  1939. print{" mB/t",22,3,monitorIndex}
  1940. print{"< >",22,4,monitorIndex}
  1941. print{stringTrim(turbineFlowRate),24,4,monitorIndex}
  1942. print{" RPM",22,5,monitorIndex}
  1943. print{"< >",22,6,monitorIndex}
  1944. print{stringTrim(tonumber(_G[turbineNames[turbineIndex]]["TurbineOptions"]["BaseSpeed"])),24,6,monitorIndex}
  1945. local rotorSpeedString = "Speed: "
  1946. local energyBufferString = "Energy: "
  1947. local steamBufferString = "Steam: "
  1948. local padding = math.max(string.len(rotorSpeedString), string.len(energyBufferString), string.len(steamBufferString))
  1949.  
  1950. local energyBuffer = turbine.getEnergyProducedLastTick()
  1951. print{energyBufferString,1,4,monitorIndex}
  1952. print{math.ceil(energyBuffer).." RF/t",padding+1,4,monitorIndex}
  1953.  
  1954. local rotorSpeed = math.ceil(turbine.getRotorSpeed())
  1955. print{rotorSpeedString,1,5,monitorIndex}
  1956. print{rotorSpeed.." RPM",padding+1,5,monitorIndex}
  1957.  
  1958. local steamBuffer = turbine.getFluidFlowRate()
  1959. print{steamBufferString,1,6,monitorIndex}
  1960. print{steamBuffer.." mB/t",padding+1,6,monitorIndex}
  1961.  
  1962. -- PaintUtils only outputs to term., not monitor.
  1963. -- See http://www.computercraft.info/forums2/index.php?/topic/15540-paintutils-on-a-monitor/
  1964.  
  1965. -- Draw stored energy buffer bar
  1966. drawBar(1,9,28,9,colors.gray,monitorIndex)
  1967.  
  1968. local curStoredEnergyPercent = getTurbineStoredEnergyBufferPercent(turbine)
  1969. if curStoredEnergyPercent > 4 then
  1970. drawBar(1, 9, math.floor(26*curStoredEnergyPercent/100)+2, 9, colors.yellow,monitorIndex)
  1971. elseif curStoredEnergyPercent > 0 then
  1972. drawPixel(1, 9, colors.yellow, monitorIndex)
  1973. end -- if curStoredEnergyPercent > 4 then
  1974.  
  1975. print{"Energy Buffer",1,8,monitorIndex}
  1976. print{curStoredEnergyPercent, width-(string.len(curStoredEnergyPercent)+2),8,monitorIndex}
  1977. print{"%",28,8,monitorIndex}
  1978.  
  1979. -- Print rod override status
  1980. local turbineFlowRateOverrideStatus = ""
  1981.  
  1982. print{"Flow Auto-adjust:",2,10,monitorIndex}
  1983.  
  1984. if ((not _G[turbineNames[turbineIndex]]["TurbineOptions"]["flowOverride"]) or (_G[turbineNames[turbineIndex]]["TurbineOptions"]["flowOverride"] == "false")) then
  1985. turbineFlowRateOverrideStatus = "Enabled"
  1986. monitor.setTextColor(colors.green)
  1987. else
  1988. turbineFlowRateOverrideStatus = "Disabled"
  1989. monitor.setTextColor(colors.red)
  1990. end -- if not reactorRodOverride then
  1991.  
  1992. print{turbineFlowRateOverrideStatus, width - string.len(turbineFlowRateOverrideStatus) - 1, 10, monitorIndex}
  1993. monitor.setTextColor(colors.white)
  1994.  
  1995. -- Print coil status
  1996. local turbineCoilStatus = ""
  1997.  
  1998. print{"Turbine coils:",2,11,monitorIndex}
  1999.  
  2000. if ((_G[turbineNames[turbineIndex]]["TurbineOptions"]["CoilsEngaged"]) or (_G[turbineNames[turbineIndex]]["TurbineOptions"]["CoilsEngaged"] == "true")) then
  2001. turbineCoilStatus = "Engaged"
  2002. monitor.setTextColor(colors.green)
  2003. else
  2004. turbineCoilStatus = "Disengaged"
  2005. monitor.setTextColor(colors.red)
  2006. end
  2007.  
  2008. print{turbineCoilStatus, width - string.len(turbineCoilStatus) - 1, 11, monitorIndex}
  2009. monitor.setTextColor(colors.white)
  2010.  
  2011. monitor.setTextColor(colors.blue)
  2012. printCentered(_G[turbineNames[turbineIndex]]["TurbineOptions"]["turbineName"],12,monitorIndex)
  2013. monitor.setTextColor(colors.white)
  2014.  
  2015. -- monitor switch controls
  2016. monitor.setCursorPos(1, height)
  2017. monitor.write("<")
  2018. monitor.setCursorPos(width, height)
  2019. monitor.write(">")
  2020.  
  2021. -- Need equation to figure out rotor efficiency and display
  2022. end -- function displayTurbineBars(statusParams)
  2023.  
  2024.  
  2025. -- Display turbine status
  2026. local function turbineStatus(turbineIndex, monitorIndex)
  2027. printLog("Called as turbineStatus(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..").")
  2028.  
  2029. -- Grab current monitor
  2030. local monitor = nil
  2031. monitor = monitorList[monitorIndex]
  2032. if not monitor then
  2033. printLog("monitor["..monitorIndex.."] in turbineStatus(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..") is NOT a valid monitor.")
  2034. return -- Invalid monitorIndex
  2035. end
  2036.  
  2037. -- Grab current turbine
  2038. local turbine = nil
  2039. turbine = turbineList[turbineIndex]
  2040. if not turbine then
  2041. printLog("turbine["..turbineIndex.."] in turbineStatus(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..") is NOT a valid Big Turbine.")
  2042. return -- Invalid turbineIndex
  2043. else
  2044. printLog("turbine["..turbineIndex.."] in turbineStatus(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..") is a valid Big Turbine.")
  2045. end
  2046.  
  2047. local width, height = monitor.getSize()
  2048. local turbineStatus = ""
  2049.  
  2050. if turbine.getConnected() then
  2051. printLog("turbine["..turbineIndex.."] in turbineStatus(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..") is connected.")
  2052. if turbine.getActive() then
  2053. turbineStatus = "ONLINE"
  2054. monitor.setTextColor(colors.green)
  2055. else
  2056. turbineStatus = "OFFLINE"
  2057. monitor.setTextColor(colors.red)
  2058. end -- if turbine.getActive() then
  2059. _G[turbineNames[turbineIndex]]["TurbineOptions"]["Status"] = turbineStatus
  2060. else
  2061. printLog("turbine["..turbineIndex.."] in turbineStatus(turbineIndex="..turbineIndex..",monitorIndex="..monitorIndex..") is NOT connected.")
  2062. turbineStatus = "DISCONNECTED"
  2063. monitor.setTextColor(colors.red)
  2064. end -- if turbine.getConnected() then
  2065.  
  2066. print{turbineStatus, width - string.len(turbineStatus) - 1, 1, monitorIndex}
  2067. monitor.setTextColor(colors.white)
  2068. end -- function function turbineStatus(turbineIndex, monitorIndex)
  2069.  
  2070.  
  2071. -- Adjust Turbine flow rate to maintain 900 or 1,800 RPM, and disengage coils when buffer full
  2072. local function flowRateControl(turbineIndex)
  2073. if ((not _G[turbineNames[turbineIndex]]["TurbineOptions"]["flowOverride"]) or (_G[turbineNames[turbineIndex]]["TurbineOptions"]["flowOverride"] == "false")) then
  2074.  
  2075. printLog("Called as flowRateControl(turbineIndex="..turbineIndex..").")
  2076.  
  2077. -- Grab current turbine
  2078. local turbine = nil
  2079. turbine = turbineList[turbineIndex]
  2080.  
  2081. -- assign for the duration of this run
  2082. local lastTurbineSpeed = tonumber(_G[turbineNames[turbineIndex]]["TurbineOptions"]["LastSpeed"])
  2083. local turbineBaseSpeed = tonumber(_G[turbineNames[turbineIndex]]["TurbineOptions"]["BaseSpeed"])
  2084. local coilsEngaged = _G[turbineNames[turbineIndex]]["TurbineOptions"]["CoilsEngaged"] or _G[turbineNames[turbineIndex]]["TurbineOptions"]["CoilsEngaged"] == "true"
  2085.  
  2086. if not turbine then
  2087. printLog("turbine["..turbineIndex.."] in flowRateControl(turbineIndex="..turbineIndex..") is NOT a valid Big Turbine.")
  2088. return -- Invalid turbineIndex
  2089. else
  2090. printLog("turbine["..turbineIndex.."] in flowRateControl(turbineIndex="..turbineIndex..") is a valid Big Turbine.")
  2091.  
  2092. if turbine.getConnected() then
  2093. printLog("turbine["..turbineIndex.."] in flowRateControl(turbineIndex="..turbineIndex..") is connected.")
  2094. else
  2095. printLog("turbine["..turbineIndex.."] in flowRateControl(turbineIndex="..turbineIndex..") is NOT connected.")
  2096. end -- if turbine.getConnected() then
  2097. end -- if not turbine then
  2098.  
  2099. -- No point modifying control rod levels for temperature if the turbine is offline
  2100. if turbine.getActive() then
  2101. printLog("turbine["..turbineIndex.."] in flowRateControl(turbineIndex="..turbineIndex..") is active.")
  2102.  
  2103. local flowRate
  2104. local flowRateUserMax = math.ceil(turbine.getFluidFlowRateMax())
  2105. local rotorSpeed = math.ceil(turbine.getRotorSpeed())
  2106. local newFlowRate
  2107.  
  2108.  
  2109. -- Flips on and off the coils. Binary and stupid
  2110. local currentStoredEnergyPercent = getTurbineStoredEnergyBufferPercent(turbine)
  2111. if currentStoredEnergyPercent < 15 and turbineBaseSpeed - rotorSpeed <= 50 then
  2112. coilsEngaged = true
  2113. end
  2114. if currentStoredEnergyPercent > 85 or turbineBaseSpeed - rotorSpeed > 50 then
  2115. coilsEngaged = false
  2116.  
  2117. end
  2118.  
  2119.  
  2120. -- Uses two stored steam values. One for coils engaged, one for disengaged.
  2121. if coilsEngaged then
  2122. flowRate = tonumber(_G[turbineNames[turbineIndex]]["TurbineOptions"]["LastFlowCoilsEngaged"])
  2123. else
  2124. flowRate = tonumber(_G[turbineNames[turbineIndex]]["TurbineOptions"]["LastFlowCoilsDisengaged"])
  2125. end
  2126.  
  2127. -- PID Controller
  2128. local target = turbineBaseSpeed
  2129. local Error = target - rotorSpeed
  2130. local derivedError = lastTurbineSpeed - rotorSpeed
  2131. local integratedError = _G[turbineNames[turbineIndex]]["TurbineOptions"]["integratedError"] + Error
  2132.  
  2133. if integratedError > _G[turbineNames[turbineIndex]]["TurbineOptions"]["integralMax"] then
  2134. integratedError = _G[turbineNames[turbineIndex]]["TurbineOptions"]["integralMax"]
  2135. end
  2136. if integratedError > _G[turbineNames[turbineIndex]]["TurbineOptions"]["integralMin"] then
  2137. integratedError = _G[turbineNames[turbineIndex]]["TurbineOptions"]["integralMin"]
  2138. end
  2139.  
  2140. _G[turbineNames[turbineIndex]]["TurbineOptions"]["integratedError"] = integratedError
  2141.  
  2142.  
  2143.  
  2144.  
  2145. local Kp = _G[turbineNames[turbineIndex]]["TurbineOptions"]["proportionalGain"]
  2146. local Ki = _G[turbineNames[turbineIndex]]["TurbineOptions"]["integralGain"]
  2147. local Kd = _G[turbineNames[turbineIndex]]["TurbineOptions"]["derivativeGain"]
  2148.  
  2149. local adjustAmount = round(Kp * Error + Ki * integratedError + Kd * derivedError, 0) -- for the turbine flow rate
  2150.  
  2151. newFlowRate = flowRate + adjustAmount
  2152.  
  2153.  
  2154.  
  2155.  
  2156. -- Failsafe to prevent explosions
  2157. if rotorSpeed >= 2000 then
  2158. coilsEngaged = true
  2159. newFlowRate = 0
  2160. end
  2161.  
  2162.  
  2163.  
  2164. --boundary check
  2165. if newFlowRate > 2000 then
  2166. newFlowRate = 2000
  2167. elseif newFlowRate < 0 then
  2168. newFlowRate = 0
  2169. end -- if newFlowRate > 2000 then
  2170. --no sense running an adjustment if it's not necessary
  2171.  
  2172. printLog("turbine["..turbineIndex.."] in flowRateControl(turbineIndex="..turbineIndex..") is being commanded to "..newFlowRate.." mB/t flow")
  2173. newFlowRate = round(newFlowRate, 0)
  2174. turbine.setFluidFlowRateMax(newFlowRate)
  2175. _G[turbineNames[turbineIndex]]["TurbineOptions"]["LastFlow"] = newFlowRate -- For display purposes
  2176.  
  2177. -- For the PID
  2178. if coilsEngaged then
  2179. _G[turbineNames[turbineIndex]]["TurbineOptions"]["LastFlowCoilsEngaged"] = newFlowRate
  2180. else
  2181. _G[turbineNames[turbineIndex]]["TurbineOptions"]["LastFlowCoilsDisengaged"] = newFlowRate
  2182. end
  2183.  
  2184. config.save(turbineNames[turbineIndex]..".options", _G[turbineNames[turbineIndex]])
  2185.  
  2186.  
  2187. turbine.setInductorEngaged(coilsEngaged)
  2188.  
  2189. --always set this
  2190. _G[turbineNames[turbineIndex]]["TurbineOptions"]["CoilsEngaged"] = coilsEngaged
  2191. _G[turbineNames[turbineIndex]]["TurbineOptions"]["LastSpeed"] = rotorSpeed
  2192. config.save(turbineNames[turbineIndex]..".options", _G[turbineNames[turbineIndex]])
  2193. else
  2194. printLog("turbine["..turbineIndex.."] in flowRateControl(turbineIndex="..turbineIndex..") is NOT active.")
  2195. end -- if turbine.getActive() then
  2196. else
  2197. printLog("turbine["..turbineIndex.."] has flow override set to "..tostring(_G[turbineNames[turbineIndex]]["TurbineOptions"]["flowOverride"])..", bypassing flow control.")
  2198. end -- if not _G[turbineNames[turbineIndex]]["TurbineOptions"]["flowOverride"] then
  2199. end -- function flowRateControl(turbineIndex)
  2200.  
  2201.  
  2202. local function helpText()
  2203.  
  2204. -- these keys are actually defined in eventHandler(), check there
  2205. return [[Keyboard commands:
  2206. m Select next monitor
  2207. s Make selected monitor display global status
  2208. x Make selected monitor display debug information
  2209. d Toggle debug mode
  2210. q Quit
  2211. r Quit and reboot
  2212. h Print this help
  2213. ]]
  2214.  
  2215. end -- function helpText()
  2216.  
  2217. local function initializePeripherals()
  2218. monitorAssignments = {}
  2219. -- Get our list of connected monitors and reactors
  2220. findMonitors()
  2221. findReactors()
  2222. findTurbines()
  2223. assignMonitors()
  2224. end
  2225.  
  2226.  
  2227. local function updateMonitors()
  2228.  
  2229. -- Display overall status on selected monitors
  2230. for monitorName, deviceData in pairs(monitorAssignments) do
  2231. local monitor = nil
  2232. local monitorIndex = deviceData.index
  2233. local monitorType = deviceData.type
  2234. monitor = monitorList[monitorIndex]
  2235.  
  2236. printLog("main(): Trying to display "..monitorType.." on "..monitorNames[monitorIndex].."["..monitorIndex.."]", DEBUG)
  2237.  
  2238. if #monitorList < (#reactorList + #turbineList + 1) then
  2239. printLog("You may want "..(#reactorList + #turbineList + 1).." monitors for your "..#reactorList.." connected reactors and "..#turbineList.." connected turbines.")
  2240. end
  2241.  
  2242. if (not monitor) or (not monitor.getSize()) then
  2243.  
  2244. printLog("monitor["..monitorIndex.."] in main() is NOT a valid monitor, discarding", ERROR)
  2245. monitorAssignments[monitorName] = nil
  2246. -- we need to get out of the for loop now, or it will dereference x.next (where x is the element we just killed) and crash
  2247. break
  2248.  
  2249. elseif monitorType == "Status" then
  2250.  
  2251. -- General status display
  2252. clearMonitor(progName.." "..progVer, monitorIndex) -- Clear monitor and draw borders
  2253. printCentered(progName.." "..progVer, 1, monitorIndex)
  2254. displayAllStatus(monitorIndex)
  2255.  
  2256. elseif monitorType == "Reactor" then
  2257.  
  2258. -- Reactor display
  2259. local reactorMonitorIndex = monitorIndex
  2260. for reactorIndex = 1, #reactorList do
  2261.  
  2262. if deviceData.reactorName == reactorNames[reactorIndex] then
  2263.  
  2264. printLog("Attempting to display reactor["..reactorIndex.."] on monitor["..monitorIndex.."]...", DEBUG)
  2265. -- Only attempt to assign a monitor if we have a monitor for this reactor
  2266. if (reactorMonitorIndex <= #monitorList) then
  2267. printLog("Displaying reactor["..reactorIndex.."] on monitor["..reactorMonitorIndex.."].")
  2268.  
  2269. clearMonitor(progName, reactorMonitorIndex) -- Clear monitor and draw borders
  2270. printCentered(progName, 1, reactorMonitorIndex)
  2271.  
  2272. -- Display reactor status, includes "Disconnected" but found reactors
  2273. reactorStatus{reactorIndex, reactorMonitorIndex}
  2274.  
  2275. -- Draw the borders and bars for the current reactor on the current monitor
  2276. displayReactorBars{reactorIndex, reactorMonitorIndex}
  2277. end
  2278.  
  2279. end -- if deviceData.reactorName == reactorNames[reactorIndex] then
  2280.  
  2281. end -- for reactorIndex = 1, #reactorList do
  2282.  
  2283. elseif monitorType == "Turbine" then
  2284.  
  2285. -- Turbine display
  2286. local turbineMonitorIndex = monitorIndex
  2287. for turbineIndex = 1, #turbineList do
  2288.  
  2289. if deviceData.turbineName == turbineNames[turbineIndex] then
  2290. printLog("Attempting to display turbine["..turbineIndex.."] on monitor["..turbineMonitorIndex.."]...", DEBUG)
  2291. -- Only attempt to assign a monitor if we have a monitor for this turbine
  2292. --printLog("debug: "..turbineMonitorIndex)
  2293. if (turbineMonitorIndex <= #monitorList) then
  2294. printLog("Displaying turbine["..turbineIndex.."] on monitor["..turbineMonitorIndex.."].")
  2295. clearMonitor(progName, turbineMonitorIndex) -- Clear monitor and draw borders
  2296. printCentered(progName, 1, turbineMonitorIndex)
  2297.  
  2298. -- Display turbine status, includes "Disconnected" but found turbines
  2299. turbineStatus(turbineIndex, turbineMonitorIndex)
  2300.  
  2301. -- Draw the borders and bars for the current turbine on the current monitor
  2302. displayTurbineBars(turbineIndex, turbineMonitorIndex)
  2303. end
  2304. end
  2305. end
  2306.  
  2307. elseif monitorType == "Debug" then
  2308.  
  2309. -- do nothing, printLog() outputs to here
  2310.  
  2311. else
  2312.  
  2313. clearMonitor(progName, monitorIndex)
  2314. print{"Monitor inactive", 7, 7, monitorIndex}
  2315.  
  2316. end -- if monitorType == [...]
  2317. end
  2318. end
  2319.  
  2320. function main()
  2321. -- Load reactor parameters and initialize systems
  2322. loadReactorOptions()
  2323. initializePeripherals()
  2324.  
  2325. write(helpText())
  2326.  
  2327. --TODO: this is a global variable set by the event handler!
  2328. while not finished do
  2329.  
  2330. updateMonitors()
  2331.  
  2332. local reactor = nil
  2333. local sd = 0
  2334.  
  2335. -- Iterate through reactors
  2336. for reactorIndex = 1, #reactorList do
  2337. local monitor = nil
  2338.  
  2339. reactor = reactorList[reactorIndex]
  2340. if not reactor then
  2341. printLog("reactor["..reactorIndex.."] in main() is NOT a valid Big Reactor.")
  2342. break -- Invalid reactorIndex
  2343. else
  2344. printLog("reactor["..reactorIndex.."] in main() is a valid Big Reactor.")
  2345. end -- if not reactor then
  2346.  
  2347. if reactor.getConnected() then
  2348. printLog("reactor["..reactorIndex.."] is connected.")
  2349.  
  2350. -- Collect steam production data
  2351. if reactor.isActivelyCooled() then
  2352. sd = sd + reactor.getHotFluidProducedLastTick()
  2353. else -- Not actively cooled
  2354. local curStoredEnergyPercent = getReactorStoredEnergyBufferPercent(reactor)
  2355.  
  2356. -- Shutdown reactor if current stored energy % is >= desired level, otherwise activate
  2357. -- First pass will have curStoredEnergyPercent=0 until displayBars() is run once
  2358. if curStoredEnergyPercent >= maxStoredEnergyPercent then
  2359. reactor.setActive(false)
  2360. -- Do not auto-start the reactor if it was manually powered off (autoStart=false)
  2361. elseif (curStoredEnergyPercent <= minStoredEnergyPercent) and (_G[reactorNames[reactorIndex]]["ReactorOptions"]["autoStart"] == true) then
  2362. reactor.setActive(true)
  2363. end -- if curStoredEnergyPercent >= maxStoredEnergyPercent then
  2364. end -- if reactor.isActivelyCooled() then
  2365.  
  2366. -- Don't try to auto-adjust control rods if manual control is requested
  2367. if not _G[reactorNames[reactorIndex]]["ReactorOptions"]["rodOverride"] then
  2368. temperatureControl(reactorIndex)
  2369. end -- if not reactorRodOverride then
  2370.  
  2371. else
  2372. printLog("reactor["..reactorIndex.."] is NOT connected.")
  2373. end -- if reactor.getConnected() then
  2374. end -- for reactorIndex = 1, #reactorList do
  2375.  
  2376. -- Now that temperatureControl() had a chance to use it, reset/calculate steam data for next iteration
  2377. printLog("Steam requested: "..steamRequested.." mB")
  2378. printLog("Steam delivered: "..steamDelivered.." mB")
  2379. steamDelivered = sd
  2380. steamRequested = 0
  2381.  
  2382. -- Turbine control
  2383. for turbineIndex = 1, #turbineList do
  2384.  
  2385. local turbine = turbineList[turbineIndex]
  2386. if not turbine then
  2387. printLog("turbine["..turbineIndex.."] in main() is NOT a valid Big Turbine.")
  2388. break -- Invalid turbineIndex
  2389. else
  2390. printLog("turbine["..turbineIndex.."] in main() is a valid Big Turbine.")
  2391. end -- if not turbine then
  2392.  
  2393. if turbine.getConnected() then
  2394. printLog("turbine["..turbineIndex.."] is connected.")
  2395.  
  2396. if ((not _G[turbineNames[turbineIndex]]["TurbineOptions"]["flowOverride"]) or (_G[turbineNames[turbineIndex]]["TurbineOptions"]["flowOverride"] == "false")) then
  2397. flowRateControl(turbineIndex)
  2398. end -- if not turbineFlowRateOverride[turbineIndex] then
  2399.  
  2400. -- Collect steam consumption data
  2401. if turbine.getActive() then
  2402. steamRequested = steamRequested + turbine.getFluidFlowRateMax()
  2403. end
  2404. else
  2405. printLog("turbine["..turbineIndex.."] is NOT connected.")
  2406. end -- if turbine.getConnected() then
  2407. end -- for reactorIndex = 1, #reactorList do
  2408.  
  2409. wait(loopTime) -- Sleep. No, wait...
  2410. saveReactorOptions()
  2411. end -- while not finished do
  2412. end -- main()
  2413.  
  2414. -- handle all the user interaction events
  2415. eventHandler = function(event, arg1, arg2, arg3)
  2416.  
  2417. printLog(string.format("handleEvent(%s, %s, %s, %s)", tostring(event), tostring(arg1), tostring(arg2), tostring(arg3)), DEBUG)
  2418.  
  2419. if event == "monitor_touch" then
  2420. sideClick, xClick, yClick = arg1, math.floor(arg2), math.floor(arg3)
  2421. UI:handlePossibleClick()
  2422. elseif (event == "peripheral") or (event == "peripheral_detach") then
  2423. printLog("Change in network detected. Reinitializing peripherals. We will be back shortly.", WARN)
  2424. initializePeripherals()
  2425. elseif event == "char" and not inManualMode then
  2426. local ch = string.lower(arg1)
  2427. -- remember to update helpText() when you edit these
  2428. if ch == "q" then
  2429. finished = true
  2430. elseif ch == "d" then
  2431. debugMode = not debugMode
  2432. local modeText
  2433. if debugMode then
  2434. modeText = "on"
  2435. else
  2436. modeText = "off"
  2437. end
  2438. termRestore()
  2439. write("debugMode "..modeText.."\n")
  2440. elseif ch == "m" then
  2441. UI:selectNextMonitor()
  2442. elseif ch == "s" then
  2443. UI:selectStatus()
  2444. elseif ch == "x" then
  2445. UI:selectDebug()
  2446. elseif ch == "r" then
  2447. finished = true
  2448. os.reboot()
  2449. elseif ch == "h" then
  2450. write(helpText())
  2451. end -- if ch == "q" then
  2452. end -- if event == "monitor_touch" then
  2453.  
  2454. updateMonitors()
  2455.  
  2456. end -- function eventHandler()
  2457.  
  2458. main()
  2459.  
  2460. -- Clear up after an exit
  2461. term.clear()
  2462. term.setCursorPos(1,1)
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement