os.loadAPI("lib/f") os.loadAPI("lib/button") local targetStrength = 50 local maxTemp = 7750 local safeTemp = 3000 local lowFieldPer = 15 local activateOnCharge = true local version = 0.3 local autoInputGate = 1 local curInputGate = 222000 local targetOutput local autoOutputGate = 0 local mon, monitor, monX, monY local reactor local fluxgate local inputFluxgate local ri local action = "None since reboot" local actioncolor = colors.gray local emergencyCharge = false local emergencyTemp = false monitor = f.periphSearch("monitor") -- inputFluxgate = f.periphSearch("flow_gate") -- fluxgate = f.getPeripheral("flow_gate") reactor = f.periphSearch("draconic_reactor") function detectFlowGates() local gates = {peripheral.find("flow_gate")} if #gates < 2 then error("Error: Less than 2 flow gates detected!") return nil, nil end print("Please set input flow gate to **10 RF/t** manually.") local inputGate, outputGate, inputName, outputName while not inputGate do sleep(1) -- Wait before checking again for _, name in pairs(peripheral.getNames()) do if peripheral.getType(name) == "flow_gate" then local gate = peripheral.wrap(name) local setFlow = gate.getSignalLowFlow() if setFlow == 10 then inputGate, inputName = gate, name print("Detected input gate:", name) else outputGate, outputName = gate, name end end end end if not outputGate then print("Error: Could not identify output gate!") return nil, nil end return inputGate, outputGate, inputName, outputName end function saveFlowGateNames(inputName, outputName) local file = fs.open("flowgate_names.txt", "w") file.writeLine(inputName) file.writeLine(outputName) file.close() print("Saved flow gate names for reboot!") end function loadFlowGateNames() if not fs.exists("flowgate_names.txt") then print("No saved flow gate names found! Running detection again...") return nil, nil, nil, nil end local file = fs.open("flowgate_names.txt", "r") local inputName = file.readLine() local outputName = file.readLine() file.close() print("Loaded saved flow gate names:", inputName, outputName) if peripheral.isPresent(inputName) and peripheral.isPresent(outputName) then return peripheral.wrap(inputName), peripheral.wrap(outputName), inputName, outputName else print("Saved peripherals not found! Running detection again...") return nil, nil, nil, nil end end function setupFlowGates() -- Try to load saved names local inputFluxgate, outputFluxgate, inputName, outputName = loadFlowGateNames() -- If names don't exist, detect manually if not inputFluxgate or not outputFluxgate then inputFluxgate, outputFluxgate, inputName, outputName = detectFlowGates() if inputFluxgate and outputFluxgate then saveFlowGateNames(inputName, outputName) else error("Flow gate setup failed! Make sure to set the input flow gate to 10 before running the script again!") return nil, nil end end return inputFluxgate, outputFluxgate end inputFluxgate, fluxgate = setupFlowGates() if monitor == nil then error("No valid monitor was found") end if fluxgate == nil then error("No valid flow gate was found") end if inputFluxgate == nil then error("No input flow gate was found. Please put the low signal value to 10") end if reactor == nil then error("No reactor was found") end monX, monY = monitor.getSize() mon = {} mon.monitor, mon.X, mon.Y = monitor, monX, monY f.firstSet(mon) function mon.clear() mon.monitor.setBackgroundColor(colors.black) mon.monitor.clear() mon.monitor.setCursorPos(1,1) button.screen() end function save_config() sw = fs.open("reactorconfig.txt", "w") sw.writeLine(autoInputGate) sw.writeLine(curInputGate) sw.writeLine(targetOutput or 0) sw.writeLine(autoOutputGate or 0) sw.close() end function load_config() sr = fs.open("reactorconfig.txt", "r") autoInputGate = tonumber(sr.readLine() or 1) curInputGate = tonumber(sr.readLine() or 222000) targetOutput = tonumber(sr.readLine() or 0) autoOutputGate = tonumber(sr.readLine() or 0) sr.close() end if fs.exists("reactorconfig.txt") then load_config() end if not targetOutput or targetOutput == 0 then targetOutput = fluxgate.getSignalLowFlow() end if not autoOutputGate then autoOutputGate = 0 end save_config() function reset() term.clear() term.setCursorPos(1,1) end function reactorStatus(r) local statusTable = { running = {"Online", colors.green}, cold = {"Offline", colors.gray}, warming_up = {"Charging", colors.orange}, cooling = {"Cooling Down", colors.blue}, stopping = {"Shutting Down", colors.red} -- Default case } -- Return status or default to "Shutting Down" return statusTable[r] or statusTable["stopping"] end local lastTerminalValues = {} function drawTerminalText(x, y, label, newValue) local key = label -- Use label as key to track changes -- Only update if the value changed if lastTerminalValues[key] ~= newValue then term.setCursorPos(x, y) term.clearLine() -- Clear only the current line term.write(label .. ": " .. newValue) lastTerminalValues[key] = newValue -- Store new value end end function reactorControl() reset() -- Clear the terminal once at startup while true do local ri = reactor.getReactorInfo() if not ri then print("Reactor not setup correctly. Retrying in 2s...") sleep(2) goto continue end -- Update terminal output local i = 1 for k, v in pairs(ri) do drawTerminalText(1, i, k, tostring(v)) i = i + 1 end i = i + 1 drawTerminalText(1, i, "Output Gate", fluxgate.getSignalLowFlow()) i = i + 1 drawTerminalText(1, i, "Input Gate", inputFluxgate.getSignalLowFlow()) i = i + 1 drawTerminalText(1, i, "Target Output", targetOutput) i = i + 1 drawTerminalText(1, i, "Auto Output", autoOutputGate == 1 and "ON" or "OFF") -- Reactor Control Logic if emergencyCharge then reactor.chargeReactor() end if ri.status == "warming_up" then inputFluxgate.setSignalLowFlow(900000) emergencyCharge = false elseif ri.status == "stopping" and ri.temperature < safeTemp and emergencyTemp then reactor.activateReactor() emergencyTemp = false elseif ri.status == "warming_up" and activateOnCharge then reactor.activateReactor() end -- Auto-adjust power flow if ri.status == "running" then local fluxval = autoInputGate == 1 and ri.fieldDrainRate / (1 - (targetStrength / 100)) or curInputGate i = i + 1 drawTerminalText(1, i, "Target Gate", fluxval) inputFluxgate.setSignalLowFlow(fluxval) end -- Ramp output toward target with safety checks if ri.status == "running" then local currentFlow = fluxgate.getSignalLowFlow() if currentFlow ~= targetOutput then local diff = targetOutput - currentFlow local absDiff = math.abs(diff) local step = math.min(absDiff, math.max(1000, absDiff / 60)) if diff > 0 then local fieldPercent = math.ceil(ri.fieldStrength / ri.maxFieldStrength * 10000) * 0.01 if fieldPercent >= 20 then fluxgate.setSignalLowFlow(currentFlow + step) end else fluxgate.setSignalLowFlow(currentFlow - step) end end end -- Emergency Safeguards checkReactorSafety(ri) sleep(0.2) -- Keeps CPU usage low while maintaining constant monitoring ::continue:: end end function checkReactorSafety(ri) local fuelPercent = 100 - math.ceil(ri.fuelConversion / ri.maxFuelConversion * 10000) * 0.01 local fieldPercent = math.ceil(ri.fieldStrength / ri.maxFieldStrength * 10000) * 0.01 if fuelPercent <= 10 then emergencyShutdown("Fuel Low! Refuel Now!") elseif fieldPercent <= lowFieldPer and ri.status == "running" then emergencyShutdown("Field Strength Below "..lowFieldPer.."%!") reactor.chargeReactor() emergencyCharge = true elseif ri.temperature > maxTemp then emergencyShutdown("Reactor Overheated!") emergencyTemp = true end end function emergencyShutdown(message) reactor.stopReactor() actioncolor = colors.red action = message ActionMenu() end local MenuText = "Loading..." function clearMenuArea() -- Ensure we clear enough space for buttons for i = 26, monY-1 do f.draw_line(mon, 2, i, monX-2, colors.black) end button.clearTable() -- Clear stored button references f.draw_line(mon, 2, 26, monX-2, colors.gray) -- Redraw top of the menu box f.draw_line(mon, 2, monY-1, monX-2, colors.gray) -- Redraw bottom border f.draw_line_y(mon, 2, 26, monY-1, colors.gray) -- Left border f.draw_line_y(mon, monX-1, 26, monY-1, colors.gray) -- Right border f.draw_text(mon, 4, 26, " "..MenuText.." ", colors.white, colors.black) end function toggleReactor() ri = reactor.getReactorInfo() if ri.status == "running" then reactor.stopReactor() elseif ri.status == "stopping" then reactor.activateReactor() else reactor.chargeReactor() end end function ActionMenu() currentMenu = "action" MenuText = "ATTENTION" clearMenuArea() button.setButton("action", action, buttonMain, 5, 28, monX-4, 30, 0, 0, colors.red) button.screen() end function rebootSystem() os.reboot() end function buttonControls() if currentMenu == "controls" then return end currentMenu = "controls" MenuText = "CONTROLS" clearMenuArea() -- Clear old buttons local sLength = 6+(string.len("Toggle Reactor")+1) button.setButton("toggle", "Toggle Reactor", toggleReactor, 6, 28, sLength, 30, 0, 0, colors.blue) local sLength2 = (sLength+12+(string.len("Reboot"))+1) button.setButton("reboot", "Reboot", rebootSystem, sLength+12, 28, sLength2, 30, 0, 0, colors.blue) local autoLabel = autoOutputGate == 1 and "Auto Out:ON" or "Auto Out:OFF" local sLength3 = sLength2 + 11 + string.len(autoLabel) button.setButton("autoOut", autoLabel, toggleAutoOutput, sLength2+11, 28, sLength3, 30, 0, 0, autoOutputGate == 1 and colors.green or colors.red) local sLength4 = 4+(string.len("Back")+1) button.setButton("back", "Back", buttonMain, 4, 32, sLength4, 34, 0, 0, colors.blue) button.screen() end function changeOutputValue(num, val) autoOutputGate = 0 if val == 1 then targetOutput = math.min(targetOutput + num, 2000000000) else targetOutput = math.max(targetOutput - num, 0) end local ri_local = reactor.getReactorInfo() if not ri_local or ri_local.status ~= "running" then fluxgate.setSignalLowFlow(targetOutput) end updateReactorInfo() save_config() end function toggleAutoOutput() autoOutputGate = autoOutputGate == 1 and 0 or 1 updateReactorInfo() save_config() end function outputMenu() if currentMenu == "output" then return end currentMenu = "output" MenuText = "OUTPUT" clearMenuArea() -- Clear old buttons -- Define button data (Label, Value, Change Type) local buttonData = { {label = ">>>>", value = 1000000, changeType = 1}, -- +1,000,000 {label = ">>>", value = 100000, changeType = 1}, -- +100,000 {label = ">>", value = 10000, changeType = 1}, -- +10,000 {label = ">", value = 1000, changeType = 1}, -- +1,000 {label = "<", value = 1000, changeType = 0}, -- -1,000 {label = "<<", value = 10000, changeType = 0}, -- -10,000 {label = "<<<", value = 100000, changeType = 0}, -- -100,000 {label = "<<<<", value = 1000000, changeType = 0}, -- -1,000,000 } -- Determine the starting X position dynamically local spacing = 2 local buttonY = 28 -- Button row position -- Add buttons dynamically local currentX = monX - 7 for _, data in ipairs(buttonData) do local buttonLength = string.len(data.label) + 1 local startX = currentX - buttonLength local endX = startX + buttonLength button.setButton(data.label, data.label, changeOutputValue, startX, buttonY, endX, buttonY + 2, data.value, data.changeType, colors.blue) currentX = currentX - buttonLength - spacing -- Move left for the next button end -- Add "Back" button at the bottom local backLength = 4 + string.len("Back") + 1 button.setButton("back", "Back", buttonMain, 4, 32, backLength, 34, 0, 0, colors.blue) -- Refresh screen button.screen() end function buttonMain() if currentMenu == "main" then return end currentMenu = "main" MenuText = "MAIN MENU" clearMenuArea() -- Clear old buttons local sLength = 4+(string.len("Controls")+1) button.setButton("controls", "Controls", buttonControls, 4, 28, sLength, 30, 0, 0, colors.blue) local sLength2 = (sLength+13+(string.len("Output"))+1) button.setButton("output", "Output", outputMenu, sLength+13, 28, sLength2, 30, 0, 0, colors.blue) button.screen() end local lastValues = {} function reactorInfoScreen() mon.clear() f.draw_text(mon, 2, 38, "Made by: StormFusions v"..version, colors.gray, colors.black) -- Draw Static UI Elements (Frames, Labels) f.draw_line(mon, 2, 22, monX-2, colors.gray) f.draw_line(mon, 2, 2, monX-2, colors.gray) f.draw_line_y(mon, 2, 2, 22, colors.gray) f.draw_line_y(mon, monX-1, 2, 22, colors.gray) f.draw_text(mon, 4, 2, " INFO ", colors.white, colors.black) f.draw_line(mon, 2, 26, monX-2, colors.gray) f.draw_line(mon, 2, monY-1, monX-2, colors.gray) f.draw_line_y(mon, 2, 26, monY-1, colors.gray) f.draw_line_y(mon, monX-1, 26, monY-1, colors.gray) f.draw_text(mon, 4, 26, " "..MenuText.." ", colors.white, colors.black) -- Loop to continuously update screen while true do updateReactorInfo() sleep(1) end end function updateReactorInfo() ri = reactor.getReactorInfo() if not ri then return end if ri.status == "running" and autoOutputGate == 1 then local satPercent = getPercentage(ri.energySaturation, ri.maxEnergySaturation) local currentOutput = fluxgate.getSignalLowFlow() if satPercent > 95 then local boost = math.max(10000, math.floor(currentOutput * 0.05)) targetOutput = math.min(targetOutput + boost, 2000000000) elseif satPercent > 90 then local boost = math.max(5000, math.floor(currentOutput * 0.02)) targetOutput = math.min(targetOutput + boost, 2000000000) end end drawUpdatedText(4, 4, "Status:", reactorStatus(ri.status)[1], reactorStatus(ri.status)[2], colors.white) drawUpdatedText(4, 5, "Generation:", f.format_int(ri.generationRate).." rf/t", colors.lime, colors.yellow) local tempColor = getTempColor(ri.temperature) drawUpdatedText(4, 7, "Temperature:", f.format_int(ri.temperature).."C", tempColor, colors.lightGray) local currentFlow = fluxgate.getSignalLowFlow() local autoTag = autoOutputGate == 1 and " [AUTO]" or " [MAN]" local outputText if currentFlow ~= targetOutput then local dir = currentFlow < targetOutput and " +" or " -" outputText = f.format_int(currentFlow).." > "..f.format_int(targetOutput).." rf/t"..dir..autoTag else outputText = f.format_int(currentFlow).." rf/t"..autoTag end drawUpdatedText(4, 9, "Output:", outputText, colors.lightBlue, colors.cyan) drawUpdatedText(4, 10, "Input:", f.format_int(inputFluxgate.getSignalLowFlow()).." rf/t", colors.lightBlue, colors.cyan) local satPercent = getPercentage(ri.energySaturation, ri.maxEnergySaturation) drawUpdatedText(4, 12, "Energy Saturation:", satPercent.."%", colors.green, colors.green) f.progress_bar(mon, 4, 13, monX-7, satPercent, 100, colors.green, colors.lightGray) local fieldPercent = getPercentage(ri.fieldStrength, ri.maxFieldStrength) local fieldColor = getFieldColor(fieldPercent) drawUpdatedText(4, 15, "Field Strength:", fieldPercent.."%", fieldColor, colors.blue) f.progress_bar(mon, 4, 16, monX-7, fieldPercent, 100, fieldColor, colors.lightGray) local fuelPercent = 100 - getPercentage(ri.fuelConversion, ri.maxFuelConversion) local fuelColor = getFuelColor(fuelPercent) drawUpdatedText(4, 18, "Fuel:", fuelPercent.."%", fuelColor, colors.orange) f.progress_bar(mon, 4, 19, monX-7, fuelPercent, 100, fuelColor, colors.lightGray) end function drawUpdatedText(x, y, label, value, color, labelColor) local key = label if lastValues[key] ~= value then labelColor = labelColor or colors.white f.draw_line(mon, x, y, monX - x, colors.black) f.draw_text_lr(mon, x, y, 3, label, value, labelColor, color, colors.black) lastValues[key] = value end end function getTempColor(temp) if temp <= 5000 then return colors.green end if temp <= 6500 then return colors.orange end return colors.red end function getFieldColor(percent) if percent >= 50 then return colors.blue end if percent > 30 then return colors.orange end return colors.red end function getFuelColor(percent) if percent >= 70 then return colors.green end if percent > 30 then return colors.orange end return colors.red end function getPercentage(value, maxValue) return math.ceil(value / maxValue * 10000) * 0.01 end mon.clear() mon.monitor.setTextScale(0.5) buttonMain() -- Initialize buttons before the event listener parallel.waitForAny(reactorInfoScreen, reactorControl, button.clickEvent)