.
This commit is contained in:
parent
7eec32ad38
commit
59cfe70407
118
de_react_auto
118
de_react_auto
@ -347,7 +347,18 @@ local function calculateFieldInput()
|
||||
-- Add 10% safety margin, but ensure minimum of 1M RF/t during warmup when drain is 0
|
||||
local minimumInput = math.max(drainRate * 1.1, 1000000)
|
||||
|
||||
return math.max(minimumInput, math.floor(totalInput))
|
||||
local result = math.max(minimumInput, math.floor(totalInput))
|
||||
|
||||
-- Verbose output
|
||||
local fieldPct = string.format("%.1f%%", currentStrength * 100)
|
||||
local targetPct = string.format("%.1f%%", targetStrength * 100)
|
||||
if currentStrength < targetStrength - 0.01 then
|
||||
print("[FIELD] " .. fieldPct .. " < " .. targetPct .. " target -> increasing input to " .. formatNumber(result) .. " RF/t")
|
||||
elseif currentStrength > targetStrength + 0.01 then
|
||||
print("[FIELD] " .. fieldPct .. " > " .. targetPct .. " target -> reducing input to " .. formatNumber(result) .. " RF/t")
|
||||
end
|
||||
|
||||
return result
|
||||
end
|
||||
|
||||
-- Calculate safe output rate based on temperature and saturation
|
||||
@ -368,52 +379,66 @@ local function calculateOutputRate()
|
||||
local temp = reactorInfo.temperature or 0
|
||||
local saturation = reactorInfo.energySaturation / reactorInfo.maxEnergySaturation
|
||||
local generationRate = reactorInfo.generationRate or 0
|
||||
local result = 0
|
||||
local reason = ""
|
||||
|
||||
-- If we're in emergency or cooling, limit output
|
||||
if state == STATES.EMERGENCY then
|
||||
return 0
|
||||
result = 0
|
||||
reason = "EMERGENCY state"
|
||||
elseif state == STATES.COOLING then
|
||||
result = math.floor(generationRate * 0.5)
|
||||
reason = "COOLING - 50% of generation"
|
||||
elseif state == STATES.CHARGING or state == STATES.WARMING_UP then
|
||||
result = math.floor(generationRate * 0.8)
|
||||
reason = state .. " - 80% of generation"
|
||||
else
|
||||
-- Normal operation
|
||||
local tempFactor = 1.0
|
||||
if temp > CONFIG.critical_temperature then
|
||||
local overTemp = temp - CONFIG.critical_temperature
|
||||
local tempRange = CONFIG.max_temperature - CONFIG.critical_temperature
|
||||
tempFactor = 1.0 - (overTemp / tempRange) * 0.5
|
||||
reason = "temp " .. formatTemp(temp) .. " > critical, factor=" .. string.format("%.2f", tempFactor)
|
||||
end
|
||||
|
||||
local outputRate = generationRate * tempFactor
|
||||
|
||||
if saturation > 0.8 then
|
||||
outputRate = generationRate * 1.1 * tempFactor
|
||||
if reason == "" then reason = "high saturation (110%)" end
|
||||
elseif reason == "" then
|
||||
reason = "normal operation"
|
||||
end
|
||||
|
||||
result = math.max(0, math.floor(outputRate))
|
||||
end
|
||||
|
||||
if state == STATES.COOLING then
|
||||
-- During cooling, output less than we generate to build saturation
|
||||
return math.floor(generationRate * 0.5)
|
||||
if generationRate > 0 then
|
||||
print("[OUTPUT] " .. formatNumber(result) .. " RF/t (" .. reason .. ")")
|
||||
end
|
||||
|
||||
if state == STATES.CHARGING or state == STATES.WARMING_UP then
|
||||
-- During warmup, output slightly less than generation
|
||||
return math.floor(generationRate * 0.8)
|
||||
end
|
||||
|
||||
-- Normal operation: output slightly more than generation to keep temp rising slowly
|
||||
-- But cap it if temperature is getting high
|
||||
local tempFactor = 1.0
|
||||
if temp > CONFIG.critical_temperature then
|
||||
-- Reduce output as we approach max temp
|
||||
local overTemp = temp - CONFIG.critical_temperature
|
||||
local tempRange = CONFIG.max_temperature - CONFIG.critical_temperature
|
||||
tempFactor = 1.0 - (overTemp / tempRange) * 0.5
|
||||
end
|
||||
|
||||
-- Output rate based on generation and saturation
|
||||
local outputRate = generationRate * tempFactor
|
||||
|
||||
-- If saturation is high, we can output more
|
||||
if saturation > 0.8 then
|
||||
outputRate = generationRate * 1.1 * tempFactor
|
||||
end
|
||||
|
||||
return math.max(0, math.floor(outputRate))
|
||||
return result
|
||||
end
|
||||
|
||||
-- ============================================================================
|
||||
-- STATE MACHINE LOGIC
|
||||
-- ============================================================================
|
||||
|
||||
local lastState = nil
|
||||
|
||||
local function setState(newState, reason)
|
||||
if state ~= newState then
|
||||
print("[STATE] " .. state .. " -> " .. newState .. " (" .. reason .. ")")
|
||||
state = newState
|
||||
end
|
||||
end
|
||||
|
||||
local function processStateMachine()
|
||||
if not reactorInfo or not reactorInfo.status then
|
||||
-- SAFETY: Can't read reactor, go to emergency to maintain field
|
||||
if state ~= STATES.OFFLINE and state ~= STATES.ERROR then
|
||||
state = STATES.EMERGENCY
|
||||
setState(STATES.EMERGENCY, "cannot read reactor data")
|
||||
end
|
||||
return
|
||||
end
|
||||
@ -429,15 +454,16 @@ local function processStateMachine()
|
||||
|
||||
local fieldStrength = (reactorInfo.fieldStrength or 0) / maxField
|
||||
local saturation = (reactorInfo.energySaturation or 0) / maxSat
|
||||
local fieldPct = string.format("%.1f%%", fieldStrength * 100)
|
||||
|
||||
-- Check for emergency conditions first (always)
|
||||
if reactorStatus ~= "cold" and reactorStatus ~= "cooling" then
|
||||
if fieldStrength < CONFIG.min_field_strength then
|
||||
state = STATES.EMERGENCY
|
||||
setState(STATES.EMERGENCY, "field " .. fieldPct .. " below minimum " .. formatPercent(CONFIG.min_field_strength))
|
||||
return
|
||||
end
|
||||
if temp > CONFIG.max_temperature then
|
||||
state = STATES.EMERGENCY
|
||||
setState(STATES.EMERGENCY, "temp " .. formatTemp(temp) .. " exceeds max " .. formatTemp(CONFIG.max_temperature))
|
||||
return
|
||||
end
|
||||
end
|
||||
@ -445,26 +471,25 @@ local function processStateMachine()
|
||||
-- Check for shutdown request
|
||||
if shutdownRequested then
|
||||
if reactorStatus == "cold" or reactorStatus == "cooling" then
|
||||
state = STATES.SHUTDOWN
|
||||
setState(STATES.SHUTDOWN, "shutdown requested, reactor cooling")
|
||||
shutdownRequested = false
|
||||
elseif state ~= STATES.EMERGENCY then
|
||||
state = STATES.SHUTDOWN
|
||||
setState(STATES.SHUTDOWN, "shutdown requested")
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
-- State transitions based on reactor status
|
||||
if reactorStatus == "cold" or reactorStatus == "invalid" then
|
||||
state = STATES.OFFLINE
|
||||
setState(STATES.OFFLINE, "reactor status: " .. reactorStatus)
|
||||
return
|
||||
end
|
||||
|
||||
-- Clear charge request flag once field is sufficiently charged
|
||||
if chargeRequested then
|
||||
local fieldPercent = fieldStrength -- Already calculated above as ratio
|
||||
if fieldPercent >= CONFIG.charge_field_target then
|
||||
if fieldStrength >= CONFIG.charge_field_target then
|
||||
chargeRequested = false
|
||||
print("[INFO] Field charged to " .. string.format("%.1f%%", fieldPercent * 100) .. ", charge request cleared")
|
||||
print("[INFO] Field charged to " .. fieldPct .. ", charge request cleared")
|
||||
end
|
||||
end
|
||||
|
||||
@ -473,33 +498,33 @@ local function processStateMachine()
|
||||
-- Keep current state during cooldown
|
||||
return
|
||||
end
|
||||
state = STATES.COOLING
|
||||
setState(STATES.COOLING, "reactor cooling down")
|
||||
return
|
||||
end
|
||||
|
||||
if reactorStatus == "warming_up" then
|
||||
-- Use 0.9 multiplier for hysteresis (consistent with RUNNING state)
|
||||
if fieldStrength < CONFIG.charge_field_target * 0.9 then
|
||||
state = STATES.CHARGING
|
||||
setState(STATES.CHARGING, "field " .. fieldPct .. " below charge target")
|
||||
else
|
||||
state = STATES.WARMING_UP
|
||||
setState(STATES.WARMING_UP, "field " .. fieldPct .. " sufficient, warming up")
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if reactorStatus == "running" then
|
||||
if fieldStrength < CONFIG.charge_field_target * 0.9 then
|
||||
state = STATES.CHARGING
|
||||
setState(STATES.CHARGING, "field " .. fieldPct .. " dropped below threshold while running")
|
||||
elseif temp > CONFIG.critical_temperature then
|
||||
state = STATES.COOLING
|
||||
setState(STATES.COOLING, "temp " .. formatTemp(temp) .. " above critical " .. formatTemp(CONFIG.critical_temperature))
|
||||
else
|
||||
state = STATES.RUNNING
|
||||
setState(STATES.RUNNING, "normal operation")
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if reactorStatus == "stopping" then
|
||||
state = STATES.SHUTDOWN
|
||||
setState(STATES.SHUTDOWN, "reactor stopping")
|
||||
return
|
||||
end
|
||||
end
|
||||
@ -602,7 +627,7 @@ local function controlReactor()
|
||||
-- User requested charge - provide input flux to start charging the field
|
||||
inputRate = CONFIG.emergency_field_input
|
||||
outputRate = 0
|
||||
print("[DEBUG] OFFLINE+chargeRequested: inputRate=" .. inputRate)
|
||||
print("[CHARGE] Providing " .. formatNumber(inputRate) .. " RF/t to charge field")
|
||||
else
|
||||
-- No action needed
|
||||
inputRate = 0
|
||||
@ -623,7 +648,6 @@ local function controlReactor()
|
||||
lastInputRate = inputRate
|
||||
lastOutputRate = outputRate
|
||||
|
||||
print("[DEBUG] Setting flux gates: input=" .. inputRate .. " output=" .. outputRate)
|
||||
local inputSuccess = pcall(function()
|
||||
inputGate.setFlowOverride(math.floor(inputRate))
|
||||
end)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user