Power bus: a consumer its thermostat has closed is not billed
The bus billed every active IPowerConsumer, but a behaviour group stops at its Thermotoggle: a heater above its target never runs its EnergyDraw, yet its full draw (1000-2500/s) was charged every tick. On an idle station that kept the reactor in permanent deficit, overloading at overload efficiency. The bus now skips a consumer whose group has a closed thermostat ahead of it, the same rule it already applies to inactive items; Thermotoggle.Open is the one statement of when a thermostat is open, and Execute returns it. Tests (Soul's F2; S17 survived before): from a hull at one uniform temperature, one tick below the heater's target raises its cells and one above does not, so the heater's own contribution is measured with no reactor heat in it; and the bus bills the heater's draw below its target and not above. This does not keep an idle station warm (Soul's F1, reported separately): the reactor's throttled idle heat alone still drives it past its plateau. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
072a56f0b4
commit
74d2cf8fc4
3 changed files with 65 additions and 5 deletions
|
|
@ -47,8 +47,8 @@ public class Thermotoggle : Behavior
|
|||
TargetTemperature = data.TargetTemperature;
|
||||
}
|
||||
|
||||
public override bool Execute(float dt)
|
||||
{
|
||||
return Temperature < TargetTemperature ^ _data.HighPass;
|
||||
}
|
||||
// Whether the rest of this behaviour's group runs this tick: below the target, or above it for a high-pass one.
|
||||
public bool Open => Temperature < TargetTemperature ^ _data.HighPass;
|
||||
|
||||
public override bool Execute(float dt) => Open;
|
||||
}
|
||||
|
|
@ -92,6 +92,16 @@ public class PowerBus
|
|||
public Draw(EquippedItem item, int tier, float request) { Item = item; Tier = tier; Request = request; }
|
||||
}
|
||||
|
||||
private static bool ClosedByThermostat(EquippedItem item, Behavior consumer)
|
||||
{
|
||||
foreach (var behavior in item.BehaviorGroups[consumer.Data.Group].Behaviors)
|
||||
{
|
||||
if (behavior == consumer) return false;
|
||||
if (behavior is Thermotoggle { Open: false }) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Step(float dt)
|
||||
{
|
||||
var reactors = new List<Reactor>();
|
||||
|
|
@ -119,7 +129,9 @@ public class PowerBus
|
|||
// The other direction of the same rule: a consumer switched off or shut down (Active.Value false)
|
||||
// never runs its Execute, so it must never be billed either -- otherwise a disabled item's demand
|
||||
// starves every live consumer and drains the capacitors for energy nobody spends.
|
||||
if (behavior is IPowerConsumer consumer && item.Active.Value)
|
||||
// And a consumer whose group a thermostat has closed ahead of it does not run this tick either, so it is
|
||||
// not billed: a heater above its target draws nothing.
|
||||
if (behavior is IPowerConsumer consumer && item.Active.Value && !ClosedByThermostat(item, behavior))
|
||||
{
|
||||
// Cut 5 (docs/stats-and-power-cut.md §1.3): the item's own stored choice wins once it has one;
|
||||
// PowerTiers.Unassigned only survives past EquippedItem's constructor for a consumer added to
|
||||
|
|
|
|||
Loading…
Reference in a new issue