Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- 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 rules = {}
- local function add_rule(name, fn)
- table.insert(rules, function()
- local ok, rule_met, value = pcall(fn)
- if ok then
- return rule_met, string.format("%s (%s)", name, value)
- else
- return false, name
- end
- end)
- end
- add_rule("REACTOR TEMPERATURE <= 745K", function()
- local value = string.format("%3dK", math.ceil(data.reactor_temp))
- return data.reactor_temp <= 745, 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)
- 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()
- data = {
- lever_on = 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(),
- }
- end
- ------------------------------------------------
- local function colored(text, fg, bg)
- term.setTextColor(fg or colors.white)
- term.setBackgroundColor(bg or colors.black)
- term.write(text)
- end
- local function make_section(name, x, y, w, h)
- 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", 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 "ON " or "OFF", data.reactor_on and colors.green or colors.red)
- colored(" LEVER: ")
- colored(data.lever_on and "ON " or "OFF", data.lever_on and colors.green or colors.red)
- colored(" R. LIMIT: ")
- colored(string.format("%4.1f", data.reactor_burn_rate), colors.blue)
- colored("/", colors.lightGray)
- colored(string.format("%4.1f", data.reactor_max_burn_rate), colors.blue)
- term.setCursorPos(1, 3)
- colored("STATUS: ")
- if state == STATES.READY then
- colored("READY, flip lever to start", colors.blue)
- elseif state == STATES.RUNNING then
- colored("RUNNING, flip lever to stop", colors.green)
- elseif state == STATES.ESTOP and not all_rules_met() then
- colored("EMERGENCY STOP, safety rules violated", colors.red)
- elseif state == STATES.ESTOP then
- colored("EMERGENCY STOP, toggle lever to reset", colors.red)
- end -- STATES.UNKNOWN cases handled above
- 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("[ OK ] ", 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
- 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
- -- Update info and rules windows
- pcall(update_info)
- pcall(update_rules)
- 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()
- local width = term.getSize()
- info_window = make_section("INFORMATION", 2, 2, width - 2, 7)
- rules_window = make_section("SAFETY RULES", 2, 10, width - 2, 9)
- parallel.waitForAny(main_loop, function()
- os.pullEventRaw("terminate")
- end)
- os.reboot()
Add Comment
Please, Sign In to add comment