553 lines
16 KiB
Lua
553 lines
16 KiB
Lua
|
|
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 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.close()
|
|
end
|
|
|
|
function load_config()
|
|
sr = fs.open("reactorconfig.txt", "r")
|
|
autoInputGate = tonumber(sr.readLine())
|
|
curInputGate = tonumber(sr.readLine())
|
|
targetOutput = tonumber(sr.readLine())
|
|
sr.close()
|
|
end
|
|
|
|
if fs.exists("reactorconfig.txt") then
|
|
load_config()
|
|
end
|
|
|
|
if not targetOutput or targetOutput == 0 then
|
|
targetOutput = fluxgate.getSignalLowFlow()
|
|
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)
|
|
|
|
-- 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(5000, absDiff / 20))
|
|
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 sLength3 = 4+(string.len("Back")+1)
|
|
button.setButton("back", "Back", buttonMain, 4, 32, sLength3, 34, 0, 0, colors.blue)
|
|
|
|
button.screen()
|
|
end
|
|
|
|
function changeOutputValue(num, val)
|
|
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 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
|
|
|
|
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 outputText
|
|
if currentFlow ~= targetOutput then
|
|
local arrow = currentFlow < targetOutput and " ▲" or " ▼"
|
|
outputText = f.format_int(currentFlow).." → "..f.format_int(targetOutput).." rf/t"..arrow
|
|
else
|
|
outputText = f.format_int(currentFlow).." rf/t"
|
|
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_text_lr(mon, x, y, 3, " ", " ", colors.white, color, 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) |