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
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 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
|
|
}
|