Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- ---------------------------------------------------
- -- Mekanism Fission Reactor Monitoring Program --
- -- Created for CC:Tweaked and Mekanism --
- -- Originally created by InternetUnexplorer on --
- -- GitHub. Modified for personal use, by --
- -- iPlay_G on Minecraft, Derrick355 on GitHub. --
- -- As the original program did not contain any --
- -- license, this will not contain any license. --
- -- However, this software is provided "AS-IS", --
- -- with NO WARRANTY of ANY kind. There is no --
- -- guarentee of fitness for a particular --
- -- purpose. --
- -- Feel free to use it, but I, nor the --
- -- original author are responsible for any --
- -- issues arising from the use of this program. --
- -- -=@=- --
- -- Thank you for downloading this program. --
- ---------------------------------------------------
- --- NOTES ---
- -- If you see 'CRITICAL' on your monitor as the
- -- state, that is OK. Critical is what real
- -- reactors are considered when operating normally.
- -- It is generally recommended to edit settings
- -- in an IDE or text editor for ease of use.
- -- It is assumed you have a 6 wide, 4 tall monitor
- -- attached via a modem.
- -- References to an analog lever are common, since
- -- I used the Create mod, however if you don't
- -- have it, any way to input a variable-power
- -- redstone signal should work.
- -- Binary levers are just vanillia levers.
- --- RECOMMENDED & ASSUMED COMPUTER I/O SETUP ---
- -- TOP: Binary lever, used to enable/disable manual burn rate control
- -- LEFT: Analog lever, used as coarse adjust on burn control
- -- RIGHT: Analog lever, used as fine adjust on burn control
- -- BOTTOM: Binary lever, used as reactor on/off control
- -- BACK: Modem to connect to reactor, turbine, and monitor
- -- FRONT: Alarm or siren. Outputs a redstone signal if turbine power falls below a set threshold.
- --- VARIABLE SETTINGS ---
- -- Set the multiplier for the burn rate coarse setting.
- -- Default = 75
- burn_rate_coarse_multi = 75
- -- Set the multiplier for the burn rate fine setting.
- -- Default = 5
- burn_rate_fine_multi = 5
- -- Maximum auto burn rate to establish
- -- Default = 120
- burn_rate_auto_max = 120
- -- What turbine power percent value should burn rate be max at?
- -- For this value and all lower, burn rate will be at the max defined above.
- -- Default = 0.5 (for 50%)
- min_turbine_power = 0.50
- -- What turbine power percent value should burn rate be zero at?
- -- For this value and all higher, burn rate will be at zero.
- -- Default = 0.75 (for 75%)
- max_turbine_power = 0.75
- -- What value should the alarm go off if turbine power falls below?
- -- Default = 0.46
- turbine_min_power = 0.46
- -- What is the monitor called on the network?
- -- Default = monitor_0
- monitor_name = "monitor_2"
- -- Are you playing on a server with Advanced peripherals?
- -- This is used so that if a server is restarting the computer can
- -- shot down the reactor. Note, the server must issue some kind of
- -- restart warning beforehand.
- -- Default = true
- on_server = true
- -- If the above is true, you must configure this line.
- -- What message in chat should the program look for to see if the server
- -- is restarting?
- -- Default = "SCRAM"
- restart_message = "SCRAM"
- -- Do not modify anything past this line unless you know what you are doing.
- ------------------------------------------------
- local state, data, reactor, turbine, info_window, rules_window
- local STATES = {
- READY = 1, -- Reactor is off and can be started with the lever
- RUNNING = 2, -- Reactor is running and all rules are met
- ESTOP = 3, -- Reactor is stopped due to rule(s) being violated
- UNKNOWN = 4, -- Reactor or turbine peripherals are missing
- }
- ------------------------------------------------
- local function check_for_restart_scram()
- if fs.exists("disk/scrammed") then
- incoming_restart = true
- fs.delete("disk/scrammed")
- fs.makeDir("disk/notify_restart")
- else
- incoming_restart = false
- end
- return incoming_restart
- end
- incoming_restart = check_for_restart_scram()
- local function check_for_restart_notify()
- if fs.exists("disk/notify_restart") then
- notify_restart = true
- fs.delete("disk/notify_restart")
- else
- notify_restart = false
- end
- return notify_restart
- end
- notify_restart = check_for_restart_notify()
- local function pollChatbox()
- while true do
- local box = peripheral.find('chatBox', function(_, chatbox) return chatbox.getOperationCooldown('chatMessage') == 0 end)
- if box then
- return box
- end
- sleep(0.1)
- end
- end
- ------------------------------------------------
- local rules = {}
- local function add_rule(name, fn)
- table.insert(rules, function()
- local ok, rule_met, value = pcall(fn)
- if ok and value ~= false then
- return rule_met, string.format("%s ( %s)", name, value)
- elseif ok then
- return rule_met, string.format("%s (%s)", name, value)
- else
- return false, name
- end
- end)
- end
- add_rule("REACTOR TEMPERATURE <= 1100K ", function()
- local value = string.format("%3dK", math.ceil(data.reactor_temp))
- return data.reactor_temp <= 1100, value
- end)
- add_rule("REACTOR DAMAGE <= 10% ", function()
- local value = string.format("%3d%%", math.ceil(data.reactor_damage * 100))
- return data.reactor_damage <= 0.10, value
- end)
- add_rule("REACTOR COOLANT LEVEL >= 95% ", function()
- local value = string.format("%3d%%", math.floor(data.reactor_coolant * 100))
- return data.reactor_coolant >= 0.95, value
- end)
- add_rule("REACTOR WASTE LEVEL <= 90% ", function()
- local value = string.format("%3d%%", math.ceil(data.reactor_waste * 100))
- return data.reactor_waste <= 0.90, value
- end)
- add_rule("TURBINE ENERGY LEVEL <= 95% ", function()
- local value = string.format("%3d%%", math.ceil(data.turbine_energy * 100))
- return data.turbine_energy <= 0.95, value
- end)
- if on_server then
- add_rule("INCOMING SERVER RESTART == FALSE ", function()
- return not incoming_restart, notify_restart
- end)
- end
- local function all_rules_met()
- for i, rule in ipairs(rules) do
- if not rule() then
- return false
- end
- end
- -- Allow manual emergency stop with SCRAM button
- return state ~= STATES.RUNNING or data.reactor_on
- end
- ------------------------------------------------
- local function update_data()
- coarse_adjust = (tonumber(redstone.getAnalogInput("left")) * burn_rate_coarse_multi)
- fine_adjust = (tonumber(redstone.getAnalogInput("right")) * burn_rate_fine_multi)
- set_burn_rate = (coarse_adjust + fine_adjust)
- data = {
- lever_on = redstone.getInput("bottom"),
- burn_rate_limit = set_burn_rate,
- burn_rate_limited = redstone.getInput("top"),
- reactor_on = reactor.getStatus(),
- reactor_burn_rate = reactor.getBurnRate(),
- reactor_max_burn_rate = reactor.getMaxBurnRate(),
- reactor_temp = reactor.getTemperature(),
- reactor_damage = reactor.getDamagePercent(),
- reactor_coolant = reactor.getCoolantFilledPercentage(),
- reactor_waste = reactor.getWasteFilledPercentage(),
- turbine_energy = turbine.getEnergyFilledPercentage(),
- turbine_power = turbine.getEnergy(),
- turbine_power = turbine.getEnergy(),
- max_turbine_power = turbine.getMaxEnergy()
- }
- end
- ------------------------------------------------
- local monitor = peripheral.wrap(monitor_name)
- term.redirect(monitor)
- local function colored(text, fg, bg)
- term.setTextColor(fg or colors.white)
- term.setBackgroundColor(bg or colors.black)
- term.write(string.upper(text))
- end
- local function make_section(name, x, y, w, h, color)
- for row = 1, h do
- term.setCursorPos(x, y + row - 1)
- local char = (row == 1 or row == h) and "\127" or " "
- colored("\127" .. string.rep(char, w - 2) .. "\127", color or colors.gray)
- end
- term.setCursorPos(x + 2, y)
- colored(" " .. name .. " ")
- return window.create(term.current(), x + 2, y + 2, w - 4, h - 4)
- end
- local function update_info()
- local prev_term = term.redirect(info_window)
- term.clear()
- term.setCursorPos(1, 1)
- if state == STATES.UNKNOWN then
- colored("ERROR RETRIEVING DATA", colors.red)
- return
- end
- colored("REACTOR: ")
- colored(data.reactor_on and "CRITICAL" or "SHUTDOWN", data.reactor_on and colors.green or colors.red)
- colored(" LEVER: ")
- colored(data.lever_on and "POWERED" or "SECURED", data.lever_on and colors.green or colors.red)
- colored(" BURN RATE: ")
- if data.burn_rate_limited == false then
- colored(string.format("%4.1f", data.reactor_burn_rate), colors.blue)
- else
- colored(string.format("%4.1f", data.reactor_burn_rate), colors.yellow)
- end
- colored("/", colors.lightGray)
- colored(string.format("%4.0f", data.reactor_max_burn_rate), colors.blue)
- term.setCursorPos(34, 2)
- colored("SET LIMIT: ")
- if data.burn_rate_limited then
- colored(string.format("%4.1f", data.burn_rate_limit), colors.green)
- else
- colored(string.format("%4.1f", data.burn_rate_limit), colors.gray)
- end
- term.setCursorPos(1, 4)
- colored("STATUS: ")
- if state == STATES.READY then
- colored("READY - PULL LEVER TO STARTUP", colors.blue)
- elseif state == STATES.RUNNING then
- colored("RUNNING - PULL LEVER TO SHUTDOWN", colors.green)
- elseif state == STATES.ESTOP and not all_rules_met() then
- colored("SCRAM - SAFETY RULE VIOLATED", colors.red)
- elseif state == STATES.ESTOP then
- colored("SCRAM - TOGGLE LEVER TO RESET", colors.red)
- end -- STATES.UNKNOWN cases handled above
- term.setCursorPos(1, 6)
- colored("STORED POWER: ")
- colored(string.format("%4.0f", (data.turbine_power*4/1000000)), colors.green)
- colored(" MFE", colors.green)
- colored("/", colors.lightGray)
- colored(string.format("%4.0f", (data.max_turbine_power*4/1000000)), colors.blue)
- colored(" MFE", colors.blue)
- colored(" (")
- colored(string.format("%5.2f", (data.turbine_energy*100)), colors.green)
- colored("%", colors.green)
- colored(")")
- term.redirect(prev_term)
- end
- local estop_reasons = {}
- local function update_rules()
- local prev_term = term.redirect(rules_window)
- term.clear()
- if state ~= STATES.ESTOP then
- estop_reasons = {}
- end
- for i, rule in ipairs(rules) do
- local ok, text = rule()
- term.setCursorPos(1, i)
- if ok and not estop_reasons[i] then
- colored("[ SAFE ] ", colors.green)
- colored(text, colors.lightGray)
- else
- colored("[ FAIL ] ", colors.red)
- colored(text, colors.red)
- estop_reasons[i] = true
- end
- end
- term.redirect(prev_term)
- end
- ------------------------------------------------
- local function main_loop()
- -- Search for peripherals again if one or both are missing
- if not state or state == STATES.UNKNOWN then
- reactor = peripheral.find("fissionReactorLogicAdapter")
- turbine = peripheral.find("turbineValve")
- end
- if not pcall(update_data) then
- -- Error getting data (either reactor or turbine is nil?)
- data = {}
- state = STATES.UNKNOWN
- elseif data.reactor_on == nil then
- -- Reactor is not connected
- state = STATES.UNKNOWN
- elseif data.turbine_energy == nil then
- -- Turbine is not connected
- state = STATES.UNKNOWN
- elseif not state then
- -- Program just started, get current state from lever
- state = data.lever_on and STATES.RUNNING or STATES.READY
- elseif state == STATES.READY and data.lever_on then
- -- READY -> RUNNING
- state = STATES.RUNNING
- -- Activate reactor
- incoming_restart = false
- pcall(reactor.activate)
- data.reactor_on = true
- elseif state == STATES.RUNNING and not data.lever_on then
- -- RUNNING -> READY
- state = STATES.READY
- elseif state == STATES.ESTOP and not data.lever_on then
- -- ESTOP -> READY
- state = STATES.READY
- elseif state == STATES.UNKNOWN then
- -- UNKNOWN -> ESTOP
- state = data.lever_on and STATES.ESTOP or STATES.READY
- estop_reasons = {}
- end
- -- Always enter ESTOP if safety rules are not met
- if state ~= STATES.UNKNOWN and not all_rules_met() then
- state = STATES.ESTOP
- end
- -- SCRAM reactor if not running
- if state ~= STATES.RUNNING and reactor then
- pcall(reactor.scram)
- end
- -- Make Windows
- local width = term.getSize()
- if state == STATES.ESTOP then
- window_color = colors.red
- elseif state == STATES.READY then
- window_color = colors.green
- else
- window_color = colors.gray
- end
- info_window = make_section("INFORMATION", 2, 2, width - 2, 10, window_color)
- rules_window = make_section("SAFETY RULES", 2, 13, width - 2, 13, window_color)
- -- Update info and rules windows
- pcall(update_info)
- pcall(update_rules)
- -- Update max burn rate to keep turbine below 75% energy.
- if state ~= STATES.UNKNOWN and data.burn_rate_limited == false then
- local tgt_burn_pct = math.min(math.max(0.0, 1 - (data.turbine_energy - min_turbine_power) / (max_turbine_power - min_turbine_power)), 1.0)
- pcall(reactor.setBurnRate, tgt_burn_pct * burn_rate_auto_max)
- elseif state ~= STATES.UNKNOWN and data.burn_rate_limited == true then
- pcall(reactor.setBurnRate, data.burn_rate_limit) -- Let burn rate be limited by an analog lever
- end
- if data.turbine_energy < turbine_min_power then --Sound an alarm that's attached to the front of the computer if turbine power falls below 45%.
- redstone.setOutput("right", true)
- else
- redstone.setOutput("right", false)
- end
- sleep() -- Other calls should already yield, this is just in case
- return main_loop()
- end
- term.setPaletteColor(colors.black, 0x000000)
- term.setPaletteColor(colors.gray, 0x343434)
- term.setPaletteColor(colors.lightGray, 0xababab)
- term.setPaletteColor(colors.red, 0xdb2d20)
- term.setPaletteColor(colors.green, 0x01a252)
- term.setPaletteColor(colors.blue, 0x01a0e4)
- term.clear()
- function scram_on_restart()
- chatBox = peripheral.find("chatBox")
- local event, username, message, uuid, isHidden = os.pullEvent("chat")
- pollChatbox().sendMessage("username: " .. username .. " message: `".. message .. "`")
- if message == restart_message then
- --fs.copy("/disk/scram.lua", "/disk/scrammed.lua")
- fs.makeDir("/disk/scrammed")
- pollChatbox().sendMessage("SCRAM aye")
- end
- end
- if on_server then
- parallel.waitForAny(main_loop, scram_on_restart)
- else
- parallel.waitForAny(main_loop, function()
- os.pullEventRaw("terminate")
- end)
- end
- os.reboot()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement