Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- Reactor Controller 2.5 by m1cr0man
- os.loadAPI("/reactor/m1")
- local origx, origy = term.getSize()
- m1.set(true, origy-10, 2)
- local relock, info, m1cr0s, wiring, downtime, eutick, ice, ids, ticktime, version, rats, thermal, user, savecount = nil, {[1] = "pwdchk"}, {}, {}, nil, 250, {}, {[1] = false}, os.startTimer(1), "2.5", {}, {[1] = false, [3] = false}, {menu = 0, input = "", line = origy-7}, 0
- local evt, p1, p2;
- function save(arg) --To provide a central place for controlling settings file
- if arg == nil then
- m1.tablesave("/reactor/settings", {[1] = wiring, [2] = m1cr0s, [3] = eutick, [4] = downtime, [5] = ice, [6] = ids, [7] = thermal})
- else
- local loaded = m1.tableload("/reactor/settings")
- wiring, m1cr0s, eutick, downtime, ice, ids, thermal = loaded[1], loaded[2], loaded[3], loaded[4], loaded[5], loaded[6], loaded[7]
- end
- end
- function wireschk(wire) --Handles redstone state checking
- if wiring[1] == true then return(m1.redchk(wiring[wire]))
- else return(m1.redchk(wiring[1], nil, wiring[wire])) end
- end
- function wires(wire, state) --Handles redstone wiring actions
- if wiring[1] == true then
- if wire == "door" and state == nil then
- local currstate = wireschk(wire)
- m1.redinvert(wiring[wire])
- if not currstate then wiring[5] = "Open" else wiring[5] = "Closed" end
- else
- rs.setOutput(wiring[wire], state)
- if wire == "door" and state then wiring[5] = "Open" elseif wire == "door" then wiring[5] = "Closed" end
- end
- else
- local cols = 0
- if wire == "door" and state == nil then
- local currstate = wireschk("door")
- --Sort out reactor colour
- if (wiring[6] == "On" and not wiring[7]) or (wiring[6] == "Off" and wiring[7]) then cols = colors[wiring["reactor"]] end
- if not currstate then cols = cols+colors[wiring["door"]] end
- rs.setBundledOutput(wiring[1], cols)
- --Update Door Status
- if not currstate then wiring[5] = "Open" else wiring[5] = "Closed" end
- else
- --Check if reactor wire should go on or not, same for door wire
- if (wire == "reactor" and ((wiring[7] and state == wiring[7]) or (not wiring[7] and state ~= wiring[7]))) or (wire == "door" and state) then cols = colors[wiring[wire]] end
- --Check for and keep currently active wires on
- if wire == "reactor" and wiring["door"] and wiring[5] == "Open" then cols = cols+colors[wiring["door"]]
- elseif wire == "door" and ((wiring[6] == "On" and not wiring[7]) or (wiring[6] == "Off" and wiring[7])) then cols = cols+colors[wiring["reactor"]] end
- rs.setBundledOutput(wiring[1], cols)
- --Update Door Status
- if wire == "door" and state then wiring[5] = "Open" elseif wire == "door" then wiring[5] = "Closed" end
- end
- end
- --Update status of reactor
- if wire == "reactor" and state ~= wiring[7] then wiring[6] = "On" elseif wire == "reactor" then wiring[6] = "Off" end
- end
- function redraw(hst, reset) --Redraws constant GUI items, also handles variable resetting to default
- m1.printex(1, "-----Reactor Controller "..version.."-----", "center")
- m1.printex(2, "------History------")
- m1.printex(origy-8, "-------------------")
- --Add history and/or clear bottom of screen
- if reset then for line = 1,6 do m1.printex(origy-line, " ") end end
- if hst then m1.printex(origy-9, hst, 1, "history") end
- --Update Reactor Status at bottom of UI
- local status = "Reactor:"..wiring[6]
- if wiring["door"] then status = status.." - Door:"..wiring[5] end
- if thermal[1] then status = status.." - Heat:"..wiring[8] end
- if downtime then status = status.." - Time:"..tostring(downtime) end
- m1.printex(origy, status, "center")
- end
- function userAction(action) --Handles user actions
- --Shutdown
- if action == 1 then
- wires("reactor", wiring[7])
- ice[4], ice[2], downtime, thermal[3] = 0, 0, nil, false
- if thermal[4] ~= 1 then thermal[4] = 0 end
- redraw("INFO: Reactor Shutdown", true)
- --Generate X EUs
- elseif action == 2 then
- downtime = math.floor((downtime*1000000)/(eutick*20)) --All The Math
- wires("reactor", not wiring[7])
- redraw("INFO: Reactor shutting down in "..tostring(downtime).." seconds", true)
- --Reset Detectors
- elseif action == 3 then
- ice[4], ice[2], downtime, thermal[3] = 0, 0, nil, false
- redraw("INFO: Detectors Reset", true)
- --Toggle Door
- elseif action == 4 and wiring["door"] then
- wires("door")
- redraw("INFO: Door "..wiring[5], true)
- --Toggle ESU Control
- elseif action == 5 and wiring["esu"] then
- if thermal[4] == 1 then
- thermal[4] = false
- redraw("INFO: ESU control enabled", true)
- return "enabled"
- else
- thermal[4] = 1
- redraw("INFO: ESU control disabled", true)
- return "disabled"
- end
- --Start reactor
- elseif action == 6 then
- wires("reactor", not wiring[7])
- ice[4], ice[2], downtime, thermal[3] = 0, 0, nil, false
- if thermal[4] ~= 1 then thermal[4] = false end
- redraw("INFO: Reactor Started", true)
- end
- end
- function pwdchk() --Checks info table credentials
- if type(m1cr0s[1]) == "number" then
- m1.tablesend(info, m1cr0s[1])
- local id, result = rednet.receive(m1cr0s[1], 1)
- ticktime, ice[4] = os.startTimer(1), os.startTimer(ice[3]/2)
- if result == nil then
- return "No Connection to Server "..tostring(m1cr0s[1])
- elseif m1.deserialize(result) == nil then
- return result
- elseif m1.deserialize(result)[1] ~= "true" then
- return m1.deserialize(result)[1]
- elseif m1.deserialize(result)[1] == "true" and m1.deserialize(result)[2] < m1cr0s[2] then
- return "Access Denied"
- elseif m1.deserialize(result)[1] == "true" and m1.deserialize(result)[2] >= m1cr0s[2] then
- return true
- end
- else
- local count = 0
- for i,data in ipairs(info[3]) do if data == m1cr0s[3][i] then count = count+1 end end
- if count == #m1cr0s[3] then return true else return false end
- end
- end
- function reset() --Manage cancel/reset of user input
- redraw(nil, true)
- info, user, relock = {[1] = "pwdchk"}, {menu = 0, input = "", line = origy-7}, nil
- m1.printex(user.line, "Enter Username:")
- end
- function checkUser() --Handles user input and menus
- local function getInput(mode, limit) --Manage keys pressed
- --Password
- if mode == true then
- if p1 == 14 then table.remove(info[3])
- elseif evt == "key" then table.insert(info[3], p1*(info[2]:len()/2)) end
- local stars = ""
- for i = 1,#info[3] do stars = stars.."*" end
- m1.printex(user.line+1, stars)
- --Other fields
- else
- if p1 == 14 then user.input = user.input:sub(1, user.input:len()-1)
- elseif evt == "char" and (mode ~= "num" or (mode == "num" and (tonumber(p1) or p1 == "."))) and (not limit or user.input:len() <= limit) then user.input = user.input..p1 end
- m1.printex(user.line+1, user.input)
- end
- end
- --Cancel on press escape or press cancel in menu
- if p1 == 1 or (user.menu == 0.75 and p1 == "9") then reset()
- --Menu 0 = Get Username, or move onto password
- elseif user.menu == 0 and p1 == 28 then
- info[2], user.input, user.line, user.menu, info[3] = user.input, "", origy-5, 0.5, {}
- m1.printex(user.line, "Enter Password:")
- elseif user.menu == 0 then getInput()
- --Menu 0.5 = Get Password and check credentials
- elseif user.menu == 0.5 and p1 == 28 then
- --Check Password
- local result = pwdchk()
- if result ~= true then
- if result ~= false then redraw(result) else redraw("Incorrect Name/Password") end
- relock = 3
- reset()
- else
- --If password is right
- user.menu, relock, user.line = 0.75, 15, origy-7
- m1.printex(user.line, "Password Correct, Select Action:")
- m1.printex(user.line+1, "[1] Shutdown Reactor")
- m1.printex(user.line+2, "[2] Generate Xm EUs")
- m1.printex(user.line+3, "[3] Reset Detectors")
- if wiring["door"] then m1.printex(nil, "[4] Toggle Door") end
- if wiring["esu"] then m1.printex(nil, "[5] Toggle ESU Control") end
- m1.printex(nil, "[6] Start Reactor Permanently (unless fault)")
- m1.printex(user.line+1, "[7] + Remote Controller", "right", "noclr")
- m1.printex(user.line+2, "[8] - Remote Controller", "right", "noclr")
- m1.printex(user.line+3, "[9] Cancel ", "right", "noclr")
- info = {[1] = "pwdchk"}
- end
- elseif user.menu == 0.5 then getInput(true)
- --Selecting sub menu
- elseif user.menu == 0.75 and evt == "char" and tonumber(p1) and tonumber(p1) > 0 and tonumber(p1) < 10 then
- redraw(nil, true)
- relock, user.menu, user.line = nil, tonumber(p1), origy-7
- --Generate X EUs
- if user.menu == 2 then m1.printex(user.line, "How many EUs? (x1m):")
- --Get PCID for add/remove controller
- elseif user.menu == 7 or user.menu == 8 then m1.printex(user.line, "Enter PCID:")
- --Other actions
- else
- userAction(user.menu)
- reset()
- end
- --Generate X EU Stuff
- elseif user.menu == 2 and p1 == 28 then
- downtime = user.input
- userAction(user.menu)
- reset()
- --Add/Remove Remote Controller Stuff
- elseif user.menu == 7 and p1 == 28 then
- ids[tonumber(user.input)] = true
- redraw("INFO: PC "..user.input.." Added", true)
- reset()
- elseif user.menu == 8 and p1 == 28 then
- ids[tonumber(user.input)] = false
- redraw("INFO: PC "..user.input.." Removed", true)
- reset()
- --Get input for pcid and x eu actions (as a number)
- elseif user.menu == 2 or user.menu == 7 or user.menu == 8 then getInput("num") end
- end
- function checkMsg() --Handles wifi stuff
- if evt == "rednet_message" and p2:find("r3act0r1d") then
- redraw("INFO: Sent PCID to "..tostring(p1))
- if ids[p1] then rednet.send(p1, tostring(m1cr0s[1])) else rednet.send(p1, "Unauthorised") end
- --Verify message to stop crashes
- elseif evt == "rednet_message" and ids[p1] and type(m1.deserialize(p2)) == "table" then
- if m1.deserialize(p2)[1] == "pwdchk" then
- --Check Password if computer is authorised
- if not ids[p1] then
- rednet.send(p1, "Unauthorised")
- redraw("INFO: PC "..tostring(p1).." attempted unauthorised access")
- return true
- end
- info = m1.deserialize(p2)
- for i, data in pairs(info[3]) do info[3][i] = data*(info[2]:len()/2) end
- local result = pwdchk()
- --If its wrong
- if result ~= true then
- if result ~= false then redraw("INFO: Error @ PC "..":"..tostring(p1)..result) else redraw("INFO: Error @ PC "..tostring(p1)..":".."Incorrect Name/Password") end
- rednet.send(p1, tostring(result))
- return true
- end
- --If its right
- rednet.send(p1, tostring(result))
- redraw("INFO: "..info[2].." logged in from PC "..tostring(p1))
- rats[p1], info = os.clock(), {[1] = "pwdchk"}
- --Check actions from remote controller
- elseif m1.deserialize(p2)[1] == "r3act0rctr1r" then
- local tbl = m1.deserialize(p2)
- --Mange Actual commands
- if not rats[p1] then
- rednet.send(p1, "Unauthorised")
- redraw("INFO: PC "..tostring(p1).." attempted unauthorised access")
- --Send history
- elseif tbl[2] == 7 then
- m1.tablesend(m1.gethistory(), p1)
- redraw("INFO: PC "..tostring(p1).." requested history")
- --Shutdown, Reset Detector, Start Reactor
- elseif tbl[2] == 1 or tbl[2] == 3 or tbl[2] == 6 then
- userAction(tbl[2])
- rednet.send(p1, "true")
- --Timed generator
- elseif type(tbl[2]) == "string" and tbl[2]:find("eu") then
- downtime = tonumber(tbl[2]:sub(3, tbl[2]:len()))
- userAction(2)
- rednet.send(p1, tostring(downtime))
- --Door Toggle
- elseif tbl[2] == 4 and wiring["door"] then
- userAction(3)
- rednet.send(p1, wiring[5])
- --Send wires status
- elseif tbl[2] == 9 then
- local msg = {[1] = wiring[5], [2] = wiring[6], [3] = wiring[8], [4] = downtime}
- if not wiring["door"] then msg[1] = false end
- if not thermal[1] then msg[3] = false end
- if wiring["esu"] then msg[5] = true end
- m1.tablesend(msg, p1)
- --Toggle ESU Control
- elseif tbl[2] == 5 then
- rednet.send(p1, userAction(5))
- --Deauthorisation of the RAT after exiting
- elseif tbl[2] == 8 then
- rats[p1] = false
- redraw("INFO: Lease for controller "..p1.." expired")
- end
- --Renew lease upon receiving command
- if p2 ~= 8 then rats[p1] = os.clock() end
- end
- end
- end
- function checkIce() --Checks Ice status
- --If ice is pumping
- if evt == "redstone" and wireschk("ice") then
- --If it previously wasnt pumping
- if ice[2] > 0 then
- if not thermal[3] then wires("reactor", not wiring[7]) end
- redraw("INFO: Ice pumping again.")
- end
- ice[2], ice[4] = 0, os.startTimer(ice[3]/2)
- --If no ice has pumped in last ice[3]/2 seconds and reactor is on
- elseif evt == "timer" and p1 == ice[4] and ice[2] == 0 and wiring[6] == "On" then
- redraw("WARNING: No ice in last "..tostring(ice[3]/2).." seconds")
- ice[2] = 1
- --If no ice has pumped in ice[3] seconds, shutdown reactor
- elseif evt == "timer" and p1 == ice[4] and ice[2] == 1 and wiring[6] == "On" then
- wires("reactor", wiring[7])
- redraw("SEVERE: No ice in "..tostring(ice[3]).." seconds. Reactor Shutdown")
- ice[2] = 2
- end
- end
- function checkThermal() --Checks thermal monitor status
- --If reactor was overheated and now cooled down
- if evt == "redstone" and not wireschk("thermal") and thermal[3] == true and wiring[6] == "Off" then
- thermal[3], wiring[8] = os.startTimer(thermal[2]), "Cool"
- redraw("INFO: Cooled down. Restarting in "..tostring(thermal[2]).." seconds")
- --If reactor is overheating turn it off
- elseif evt == "redstone" and wireschk("thermal") and not thermal[3] and wiring[6] == "On" then
- thermal[3], wiring[8] = true, "Hot"
- wires("reactor", wiring[7])
- redraw("SEVERE: Overheating!! Shutdown Reactor")
- --If timer is on to restart reactor
- elseif evt == "timer" and p1 == thermal[3] then
- wires("reactor", not wiring[7])
- redraw("INFO: Reactor Restarted")
- thermal[3] = false
- end
- end
- function checkEsu() --Checks ESU status
- if evt == "redstone" and not wireschk("esu") and thermal[4] == true and wiring[6] == "Off" then
- redraw("INFO: ESU not full. Resarting in "..tostring(thermal[2]).." seconds")
- thermal[4] = os.startTimer(thermal[2])
- elseif evt == "redstone" and wireschk("esu") and not thermal[4] and wiring[6] == "On" then
- thermal[4] = true
- wires("reactor", wiring[7])
- redraw("INFO: ESU filled. Shutdown Reactor")
- elseif evt == "timer" and p1 == thermal[4] then
- if not wireschk("esu") then
- thermal[4] = false
- wires("reactor", not wiring[7])
- redraw("INFO: Reactor Restarted")
- else
- redraw("INFO: ESU full again, Resarting in "..tostring(thermal[2]).." seconds")
- thermal[4] = os.startTimer(thermal[2])
- end
- end
- end
- function checkCountdowns() --Handles timed shutdown and auto-closing of menu
- if relock and relock <= 0 then
- relock = nil
- reset()
- elseif relock and relock > 0 then
- relock = relock-1
- end
- if downtime and downtime > 0 and wiring[6] == "On" then
- downtime = downtime-1
- redraw()
- elseif downtime and downtime <= 0 then
- downtime = nil
- userAction(1)
- end
- --Check for and remove expired RAT leases
- for id, jointime in pairs(rats) do
- if type(jointime) == "number" and jointime+60 < os.clock() then
- rats[id] = false
- redraw("INFO: Lease for controller "..id.." expired")
- end
- end
- end
- function setup() --First Time Setup
- term.clear()
- term.setCursorPos(1, 1)
- print("bundled/redstone wiring?")
- local wiretype = string.lower(read())
- print("Use Ice Checker? yes/no")
- ice[1] = string.lower(read())
- if ice[1] == "yes" then
- ice[1] = true
- print("How long before shutdown due to lack of ice?")
- ice[3] = tonumber(read())
- else ice[1] = false end
- print("Thermal monitor connected? yes/no")
- thermal[1] = string.lower(read())
- if thermal[1] == "yes" then thermal[1] = true else thermal[1] = false end
- print("Use energy storage unit auto-shutdown? yes/no")
- wiring["esu"] = string.lower(read())
- if wiring["esu"] == "no" then wiring["esu"] = false end
- if thermal[1] or wiring["esu"] then
- print("How long before restart after overheat/ESU filled?")
- thermal[2] = tonumber(read())
- end
- print("Use door control? yes/no")
- wiring["door"] = string.lower(read())
- if wiring["door"] == "no" then wiring["door"] = false end
- if wiretype == "bundled" then
- print("What face is the bundled cable connected to?")
- wiring[1] = string.lower(read())
- print("What colour is the reactor wire?")
- wiring["reactor"] = string.lower(read())
- if ice[1] then
- print("What colour is the ice detection wire?")
- wiring["ice"] = string.lower(read())
- end
- if thermal[1] then
- print("What colour is the thermal wire?")
- wiring["thermal"] = string.lower(read())
- end
- if wiring["door"] then
- print("What colour is the door wire?")
- wiring["door"] = string.lower(read())
- end
- if wiring["esu"] then
- print("What colour is the energy storage unit wire?")
- wiring["esu"] = string.lower(read())
- end
- elseif wiretype == "redstone" then
- wiring[1] = true
- print("What face is the reactor wire on?")
- wiring["reactor"] = string.lower(read())
- if ice[1] then
- print("What face is the ice detection wire on?")
- wiring["ice"] = string.lower(read())
- end
- if thermal[1] then
- print("What face is the thermal wire?")
- wiring["thermal"] = string.lower(read())
- end
- if wiring["door"] then
- print("What face is the door wire on?")
- wiring["door"] = string.lower(read())
- end
- if wiring["esu"] then
- print("What face is the energy storage unit wire on?")
- wiring["esu"] = string.lower(read())
- end
- end
- print("What redstone state turns the reactor OFF? on/off")
- local state = string.lower(read())
- if state == "on" then wiring[7] = true else wiring[7] = false end
- print("How many EUs/tick are made?")
- eutick = tonumber(read())
- print("Use M1cr0s login server? (yes/no)")
- local ans = string.lower(read())
- if ans == "yes" then
- print("Getting Server ID")
- rednet.open(m1.getperipheral("modem"))
- repeat
- rednet.broadcast("srvidreq")
- m1cr0s[1], junk = rednet.receive(3)
- until type(m1cr0s[1]) == "number"
- rednet.close(m1.getperipheral("modem"))
- print("Minimum Rank required to use this?")
- m1cr0s[2] = tonumber(read())
- else
- term.clear()
- term.setCursorPos(1, 1)
- m1cr0s[1] = "no"
- print("Enter Username:")
- m1cr0s[2] = read()
- print("Enter Password:")
- m1cr0s[3] = {}
- repeat
- event, key = os.pullEvent("key")
- if event == "key" and key == 14 then table.remove(m1cr0s[3])
- elseif event == "key" and key ~= 28 and key ~= 1 then table.insert(m1cr0s[3], key*(m1cr0s[2]:len()/2)) end
- m1.printex(4, " ")
- for i,letter in ipairs(m1cr0s[3]) do m1.printex(4, "*", i, "noclr") end
- until event == "key" and key == 28
- end
- ice[2], ice[4], wiring[5], wiring[6], wiring[8] = ice[2] or 0, ice[4] or 0, "Closed", "On", "Cool" --Stops problems with nils
- save()
- print("Finished, Rebooting...")
- os.sleep(1)
- os.reboot()
- end
- function ticker() --Manages Timers
- evt, p1, p2 = os.pullEvent()
- checkUser()
- checkMsg()
- if thermal[1] then checkThermal() end
- if wiring["esu"] and thermal[4] ~= 0 then checkEsu() end
- if p1 == ticktime then
- checkCountdowns()
- ticktime, savecount = os.startTimer(1), savecount+1
- end
- if p1 == ice[4] then
- checkIce()
- ice[4] = os.startTimer(ice[3]/2)
- else checkIce() end
- if savecount >= 5 then
- save()
- savecount = 0
- end
- end
- function startup() --Loads settings
- if fs.exists("/reactor/settings") == false then setup() end
- term.clear()
- save(1)
- if wiring["door"] and wiring[5] == "Open" then wires("door") end
- --Print last known problems if any
- if ice[1] and ice[2] == 2 then
- redraw("SEVERE: No ice on last run. Shutdown Reactor")
- elseif ice[1] and ice[2] ~= 0 then
- redraw("WARNING: Ice fault on last run of program.")
- end
- if thermal[1] and not wireschk("thermal") and thermal[3] then
- thermal[3] = os.startTimer(thermal[2])
- wiring[8] = "Cool"
- redraw("INFO: Cooled down. Restarting in "..tostring(thermal[2]).." seconds")
- elseif thermal[1] and wireschk("thermal") and not thermal[3] then
- wires("reactor", wiring[7])
- thermal[3], wiring[8] = true, "Hot"
- redraw("SEVERE: Overheating!! Shutdown Reactor")
- end
- if downtime ~= nil then
- wires("reactor", not wiring[7])
- redraw("INFO: Reactor shutting down in "..tostring(downtime).." seconds")
- elseif wiring[6] == "On" then
- wires("reactor", not wiring[7])
- redraw("INFO: Reactor Restarted")
- elseif wiring[6] == "Off" then
- wires("reactor", wiring[7])
- redraw("INFO: Booted")
- end
- reset()
- if m1.getperipheral("modem") == nil then error("\nPlease Attach a Wireless Modem") end
- rednet.open(m1.getperipheral("modem"))
- repeat ticker() until false
- rednet.close(m1.getperipheral("modem"))
- end
- startup()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement