Files
cosmoteer-pressure-relief-r…/components/radiator_auto.rules
T
TotenKnopfandClaude Fable 5 c5ddc78495 fix: v3.0.0 -- thresholds on the free-fraction scale the assembly actually uses
Disassembling Cosmoteer.dll (tools/ildump.py) shows PartThresholdToggle
compares plain floats with no percent logic, and that a
NetworkResourceInput's Value is the free fraction (0..1) of the connected
network. v2.1.0 compared that against 2000000, so it always vented.

Thresholds are now 5% / 10% free as local constants. New guard
test_threshold_amounts_match_value_scale fails on the old values. README
corrects the earlier wrong diagnosis of v2.0.0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011oLWY1G6S8U35bi2FxVWni
2026-08-29 01:23:02 +02:00

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 with a bare NetworkResourceInput, the same component an
// overclocked part pushes its heat through (base_part_overclock.rules:
// NetworkHeatInput), so this is exactly the producer's view of the network.
//
// Its Value, from Cosmoteer.dll (PartNetworkResourceInput.get_Value, see
// tools/ildump.py), is the FREE FRACTION of the connected heat storage:
// 1 - stored / total capacity -> 1.0 empty, 0.0 full, 0 if nothing attached
// and a ThresholdToggle compares that against MinAmount/MaxAmount as plain
// floats, so the amounts below are fractions too ("5%" is 0.05).
AutoRad_NetworkSpace
{
Type = NetworkResourceInput
ResourceType = heat
Mode = DistributeProportionallyByAvailable
Categories = [ thermal_storage ]
}
// Vent while less than VENT_BELOW_FREE of the network is still free.
AutoRad_SpaceLow
{
Type = ThresholdToggle
ValueFrom = AutoRad_NetworkSpace
VENT_BELOW_FREE = 5%
MaxAmount = &VENT_BELOW_FREE
}
// Hold heat again once at least HOLD_ABOVE_FREE is free. The gap between the
// two is a deadband so radiators do not chatter at the threshold.
AutoRad_SpaceAmple
{
Type = ThresholdToggle
ValueFrom = AutoRad_NetworkSpace
HOLD_ABOVE_FREE = 10%
MinAmount = &HOLD_ABOVE_FREE
}
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
}