Tests: END-1 Core drain/regen/lose-edge + persistence v4 (330/330 EditMode)
CoreSystemsTests (new): a breaching Husk drains + is consumed; idles at 0; regen fires once per interval in Calm only; no regen mid-Siege; caps at Max. CyclePhaseSystemTests: the soft-loss overrun edge ends the siege, drains the ledger, despawns husks, withholds the goal charge, and resolves once. StorageMathTests: DrainFraction floors per row, drops zeroed rows, clamps. SavePersistenceTests: CoreCurrent round-trips at v4; a pre-END-1 save with no CoreCurrent defaults to 0 (-> born full); the v3->v4 version pin updated. TuningConfig golden pin extended with the 3 Core defaults. See DR-034. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -158,5 +158,62 @@ namespace ProjectM.Tests
|
||||
"CycleState.WaveNumber mirrors the server-only WaveState.WaveNumber for the replicated-state-only HUD.");
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Siege_Overrun_Ends_Siege_Drains_Ledger_Despawns_Husks_No_Goal_Charge()
|
||||
{
|
||||
var (world, group) = MakeWorld("SiegeOverrun", serverTick: 200);
|
||||
using (world)
|
||||
{
|
||||
var em = world.EntityManager;
|
||||
var cycle = MakeCycle(em, CyclePhase.Siege, defendStartWave: 5);
|
||||
em.AddComponentData(cycle, new GoalProgress { Charge = 3, Target = 10 });
|
||||
em.AddComponentData(cycle, new CoreIntegrity { Current = 0, Max = 100, OverrunTick = 0 }); // breached
|
||||
var ledger = em.AddBuffer<StorageEntry>(cycle);
|
||||
ledger.Add(new StorageEntry { ItemId = 2, Count = 100 });
|
||||
ledger.Add(new StorageEntry { ItemId = 4, Count = 40 });
|
||||
MakeWaveState(em, waveNumber: 6, phase: WavePhase.Spawning, remainingToSpawn: 3);
|
||||
em.CreateEntity(typeof(EnemyTag)); // two live husks the team failed to clear
|
||||
em.CreateEntity(typeof(EnemyTag));
|
||||
|
||||
group.Update();
|
||||
|
||||
Assert.AreEqual(CyclePhase.Calm, em.GetComponentData<CycleState>(cycle).Phase,
|
||||
"an overrun ends the siege -> Calm (soft loss).");
|
||||
Assert.AreEqual(3, em.GetComponentData<GoalProgress>(cycle).Charge,
|
||||
"NO goal charge on a loss (you were overrun, not survived).");
|
||||
var l = em.GetBuffer<StorageEntry>(cycle);
|
||||
Assert.AreEqual(50, l[0].Count, "ledger row 1 drained 50% (100 -> 50).");
|
||||
Assert.AreEqual(20, l[1].Count, "ledger row 2 drained 50% (40 -> 20).");
|
||||
Assert.AreNotEqual(0u, em.GetComponentData<CoreIntegrity>(cycle).OverrunTick,
|
||||
"the overrun pulse is stamped for the HUD flash.");
|
||||
using var huskQ = em.CreateEntityQuery(typeof(EnemyTag));
|
||||
Assert.AreEqual(0, huskQ.CalculateEntityCount(),
|
||||
"remaining husks are despawned (the siege disperses).");
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Overrun_Resolves_Once_Then_Stays_Calm_Without_Recharging()
|
||||
{
|
||||
var (world, group) = MakeWorld("OverrunOnce", serverTick: 200);
|
||||
using (world)
|
||||
{
|
||||
var em = world.EntityManager;
|
||||
var cycle = MakeCycle(em, CyclePhase.Siege, defendStartWave: 5);
|
||||
em.AddComponentData(cycle, new GoalProgress { Charge = 0, Target = 10 });
|
||||
em.AddComponentData(cycle, new CoreIntegrity { Current = 0, Max = 100 });
|
||||
em.AddBuffer<StorageEntry>(cycle);
|
||||
MakeWaveState(em, waveNumber: 6, phase: WavePhase.Spawning, remainingToSpawn: 0);
|
||||
|
||||
group.Update();
|
||||
group.Update(); // second tick: Calm branch -> must not re-resolve or charge
|
||||
|
||||
Assert.AreEqual(CyclePhase.Calm, em.GetComponentData<CycleState>(cycle).Phase);
|
||||
Assert.AreEqual(0, em.GetComponentData<GoalProgress>(cycle).Charge,
|
||||
"the loss never charges the goal across ticks.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user