A power request may not depend on power supply (Cut 6/F6), and continuous consumers brown out through a power term on their own performance stats (Cut 7). For Radiator (PumpedHeat) and AetherDrive (Torque) those were the same stat, making six shipped catalog records illegal and leaving six BrownoutTests cases skipped. Resolved per the operator's ruling: a power request is evaluated nominally -- what the item wants at full supply, not what it is currently managing. EquippedItem.EvaluateNominalPower (mirroring ConditionRatio's own NominalContext) pins only PowerSupplyFactor to 1; Heat/Durability stay live, since they are not the term a request would be circular through. Every PowerRequest/RefreshReserve/RefreshInputCapacitor implementation now reads a StatValidation.PowerRequestFields stat through it, so the same stat can carry a brownout curve and be a request field without the request depending on its own answer. StatValidation.ValidateNoPowerSupplyOnRequest (F6's static half of the rule, forbidding the term outright) is deleted -- nominal evaluation removes the circularity at the root instead. Only the dynamic modifier-chain half (StatModifier.ValidateNoPowerSupplyChain) still refuses anything, since EvaluateNominalPower forwards ScaleModifier/ ConstantModifier unchanged (real, not nominal). Un-skips BrownoutTests' six Radiator/AetherDrive cases and adds two new regression tests (a direct EvaluateNominalPower probe, and a two-tick Radiator demand check) backed by a new mutation harness. Updates the four PowerCurveTests/AetheriaStoresTests cases that pinned the now-superseded static refusal to instead assert acceptance. GameData/Aetheria.cc is unchanged and still validates. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
70 lines
No EOL
3.1 KiB
C#
70 lines
No EOL
3.1 KiB
C#
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at https://mozilla.org/MPL/2.0/. */
|
|
|
|
using System;
|
|
using System.Linq;
|
|
using MessagePack;
|
|
using Newtonsoft.Json;
|
|
|
|
[Inspectable, MessagePackObject, JsonObject(MemberSerialization.OptIn), RuntimeInspectable]
|
|
public class EnergyDrawData : BehaviorData
|
|
{
|
|
[Inspectable, JsonProperty("draw"), Key(1), RuntimeInspectable]
|
|
public PerformanceStat EnergyDraw = new PerformanceStat();
|
|
|
|
[Inspectable, JsonProperty("perSecond"), Key(2)]
|
|
public bool PerSecond;
|
|
|
|
public override Behavior CreateInstance(EquippedItem item)
|
|
{
|
|
return new EnergyDraw(this, item);
|
|
}
|
|
|
|
public override Behavior CreateInstance(ConsumableItemEffect item)
|
|
{
|
|
return new EnergyDraw(this, item);
|
|
}
|
|
}
|
|
|
|
public class EnergyDraw : Behavior, IPowerConsumer
|
|
{
|
|
private EnergyDrawData _data;
|
|
|
|
public EnergyDraw(EnergyDrawData data, EquippedItem item) : base(data, item)
|
|
{
|
|
_data = data;
|
|
}
|
|
|
|
public EnergyDraw(EnergyDrawData data, ConsumableItemEffect item) : base(data, item)
|
|
{
|
|
_data = data;
|
|
}
|
|
|
|
// Cut 3 (docs/stats-and-power-cut.md): the request PowerBus needs before Execute runs, in place of the
|
|
// direct Entity.TryConsumeEnergy spend that used to happen inside Execute.
|
|
//
|
|
// Nominal-request ruling (docs/stats-and-power-cut.md, operator ruling 2026-09-19): EnergyDraw is a
|
|
// registered request field (StatValidation.PowerRequestFields) -- read nominally, same reasoning as every
|
|
// other IPowerConsumer in this cut.
|
|
public float PowerRequest(float dt) => EvaluateNominalPower(_data.EnergyDraw) * (_data.PerSecond ? dt : 1);
|
|
|
|
// Cut 5 (docs/stats-and-power-cut.md §1.3, PowerTiers.cs): Utility -- the generic/unclassified draw. An item
|
|
// that declares power use without asking for a specific tier should not accidentally outrank a named one.
|
|
public int DefaultPowerTier => PowerTiers.Utility;
|
|
|
|
public override bool Execute(float dt)
|
|
{
|
|
// A consumable-hosted instance (Item null) has no PowerBus entry (§1.2's grants are keyed by
|
|
// EquippedItem); named rather than silently assumed away, it always succeeds here, the same way every
|
|
// other context-dependent factor a ConsumableItemEffect answers with the identity elsewhere in this cut.
|
|
//
|
|
// Cut 7 (docs/stats-and-power-target.md): unlike the other four continuous consumers, EnergyDraw has no
|
|
// performance stat of its own to curve -- its Execute return value IS its whole effect, the gate that
|
|
// decides whether the rest of its BehaviorGroup runs at all (Entity.cs's per-group Execute chain). There
|
|
// is nothing here for a PowerSupply term to degrade continuously, so brownout is expressed the only way
|
|
// this behaviour can express it: a partial grant still passes (no more flicking off at 80%), and only a
|
|
// true zero grant closes the gate.
|
|
return Item == null || Item.PowerSupply > 1e-4f;
|
|
}
|
|
} |