v2.0.0 held heat forever: thermal batteries visibly full, parts taking heat damage, radiators still idle. That is the dangerous direction. The ceiling read a thermal battery's own HeatStorage with a percentage threshold. That storage is wrapped by a NetworkResourceStore, and the local read never crossed 98% however full the network actually got, so the battery broadcast "hold" permanently. Measure the network's remaining room directly instead, from the radiator itself, with a bare NetworkResourceInput -- the same way the heat exchanger decides whether it can still push heat. Vent below ~2000 status heat of headroom, hold again above ~6000. Absolute headroom is also the better metric: what matters is room against the generation rate, not a percentage of whatever storage happens to be installed. Polarity is now fail-safe. Holding requires positive evidence of headroom, so anything missing or unmeasurable vents rather than holds -- the opposite of the failure above. This deletes both broadcasters. The thermal battery and base_part_overclock are no longer patched at all, and the mod touches two parts instead of four. The launcher ammo signal stays; it is confirmed working in both directions. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_011oLWY1G6S8U35bi2FxVWni
136 lines
3.9 KiB
Plaintext
136 lines
3.9 KiB
Plaintext
// ABOUT ME
|
|
// Components merged into the Radiator. They decide whether this radiator should
|
|
// vent or hold, and combine that into a single gate, AutoPowerToggle, which
|
|
// mod.rules substitutes for the radiator's vanilla PowerToggle on the parts of
|
|
// the radiator that actually dissipate heat.
|
|
//
|
|
// The player's manual on/off switch (PowerToggle) is preserved and still wins:
|
|
// a radiator the player has switched off stays off. The automation can only
|
|
// idle a radiator the player has left on.
|
|
//
|
|
// A radiator vents when EITHER:
|
|
// - the heat network is running out of room, or
|
|
// - no launcher on the network is using thermal ammunition
|
|
//
|
|
// The design is fail-safe: holding requires positive evidence that the network
|
|
// has room to spare. Anything missing, disconnected or unmeasurable results in
|
|
// venting, which is vanilla behaviour.
|
|
|
|
// --- Is the heat network running out of room? -------------------------------
|
|
//
|
|
// Measured locally, exactly the way the heat exchanger decides whether it can
|
|
// still push heat into the network (heat_exchanger.rules: IsNetworkHeatNonFull
|
|
// reads a bare NetworkResourceInput). A NetworkResourceInput's value is how much
|
|
// the network can still accept.
|
|
//
|
|
// Reading a thermal battery's own HeatStorage does NOT work for this. That
|
|
// storage is wrapped by a NetworkResourceStore, and v2.0.0 held heat forever --
|
|
// batteries visibly full, parts cooking -- because a local percentage threshold
|
|
// on it never crossed. This measures the network itself instead, from the part
|
|
// that acts on the answer, so no cross-part broadcast is involved at all.
|
|
//
|
|
// Amounts are resource units: 1 status heat = 1000 resource units
|
|
// (statuses/heat/heat.rules: STATUS_TO_RESOURCE_RATIO).
|
|
|
|
AutoRad_NetworkSpace
|
|
{
|
|
Type = NetworkResourceInput
|
|
ResourceType = heat
|
|
Mode = DistributeProportionallyByAvailable
|
|
}
|
|
|
|
// Under ~2000 status heat of headroom left: vent.
|
|
AutoRad_SpaceLow
|
|
{
|
|
Type = ThresholdToggle
|
|
ValueFrom = AutoRad_NetworkSpace
|
|
MaxAmount = 2000000
|
|
}
|
|
|
|
// Back above ~6000 status heat of headroom: safe to bank heat again.
|
|
AutoRad_SpaceAmple
|
|
{
|
|
Type = ThresholdToggle
|
|
ValueFrom = AutoRad_NetworkSpace
|
|
MinAmount = 6000000
|
|
}
|
|
|
|
AutoRad_LowTrigger
|
|
{
|
|
Type = ToggleTrigger
|
|
Toggle = AutoRad_SpaceLow
|
|
TriggerWhenOn = true
|
|
TriggerWhenOff = false
|
|
}
|
|
|
|
AutoRad_AmpleTrigger
|
|
{
|
|
Type = ToggleTrigger
|
|
Toggle = AutoRad_SpaceAmple
|
|
TriggerWhenOn = true
|
|
TriggerWhenOff = false
|
|
}
|
|
|
|
// The deadband, so radiators do not chatter at the threshold.
|
|
AutoRad_VentLatch
|
|
{
|
|
Type = TriggeredToggle
|
|
OnTrigger = AutoRad_LowTrigger
|
|
OffTrigger = AutoRad_AmpleTrigger
|
|
}
|
|
|
|
// OR the raw low reading back in, so a ship that loads already out of room
|
|
// vents at once instead of waiting for a crossing that never comes.
|
|
AutoRad_MustVent
|
|
{
|
|
Type = MultiToggle
|
|
Toggles = [ AutoRad_VentLatch, AutoRad_SpaceLow ]
|
|
Mode = Any
|
|
}
|
|
|
|
// --- Is anything actually spending heat as ammunition? ----------------------
|
|
//
|
|
// Broadcast by the missile launcher over the heat network. Confirmed working in
|
|
// game: with a launcher on Thermal Canister ammo this reads 1, and with the
|
|
// launcher on anything else it reads 0 and radiators behave exactly as vanilla.
|
|
|
|
AutoRad_ThermalAmmoSignal
|
|
{
|
|
Type = NetworkValueReceiver
|
|
Categories = [ auto_radiator_ammo_user ]
|
|
Mode = Max
|
|
AllowUncategorized = false
|
|
}
|
|
|
|
AutoRad_ThermalAmmoInUse
|
|
{
|
|
Type = ThresholdToggle
|
|
ValueFrom = AutoRad_ThermalAmmoSignal
|
|
MinAmount = 0
|
|
MaxAmount = 0
|
|
Invert = true
|
|
}
|
|
|
|
// --- The gate ---------------------------------------------------------------
|
|
|
|
AutoRad_VentAllowed
|
|
{
|
|
Type = MultiToggle
|
|
Toggles
|
|
[
|
|
AutoRad_MustVent
|
|
{ Toggle = AutoRad_ThermalAmmoInUse; Invert = true }
|
|
]
|
|
Mode = Any
|
|
}
|
|
|
|
// PowerToggle is the radiator's vanilla UIToggle, so the player's switch remains
|
|
// the master control: it can turn a radiator off, and the automation can only
|
|
// idle one the player has left on.
|
|
AutoPowerToggle
|
|
{
|
|
Type = MultiToggle
|
|
Toggles = [ PowerToggle, AutoRad_VentAllowed ]
|
|
Mode = All
|
|
}
|