DR-042 Phase A: expedition-driven win — move win-driver off base-siege survival, kill the AFK path
Design-review-gated (wf_ebef4e81-dba, GREEN-WITH-CHANGES). The win-driver moves from "survive N base sieges" to "clear N expeditions". The review overturned the literal plan: credit on RETURN, not at the clear edge (clear-edge crediting arms the undefended final base siege -> uncontestable terminal Loss). - ExpeditionGateSystem: now the sole production writer of GoalProgress.Charge — a clamped +1 per cleared expedition folded into the existing once-per-epoch reward block, reusing the LastRewardedEpoch latch (Ore + Charge share fate) + a SaveRequest checkpoint. No new latch, no new GhostField, no ordering change. - CyclePhaseSystem: deleted the survived-siege +1 (the AFK win path). Victory latch unchanged; GoalReached still arms the final base siege at cap. - CycleDirectorAuthoring + CycleDirector.prefab: ScheduleEnabled baked OFF (retaliation-only). A serialized prefab bool ignores the C# field initializer, so the value is flipped in the prefab, not just the code default. - Tests: re-pointed CyclePhaseSystemTests + EndgameWinLoseTests survived-siege assertions; extended ExpeditionGateRewardTests (+1, no-double-credit, clamp). 389/389 EditMode green; clean netcode Play smoke (no sort-cycle, Schedule=0). SaveData stays v5. Docs: DR-042 build record + forks resolved, CLAUDE.md base-loop line, Backlog (A done). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -13,7 +13,7 @@ namespace ProjectM.Tests
|
||||
/// carrying CycleState + CycleRuntime (+ optionally ThreatState / WaveState / GoalProgress). The global phase
|
||||
/// is only ever Calm or Siege — being out on an expedition is per-player presence, NOT a global phase — so
|
||||
/// these pin: Calm holds with no pending siege; an armed ThreatState.PendingSiegeSize enters Siege and seeds
|
||||
/// WaveState's Spawning entry at the EXACT size; a cleared Siege returns to Calm and charges the goal once;
|
||||
/// WaveState's Spawning entry at the EXACT size; a cleared Siege returns to Calm WITHOUT charging the goal (DR-042: expedition clears drive the win);
|
||||
/// and split co-op presence never produces a non-Calm phase. All timing is wrap-safe NetworkTick math.
|
||||
/// </summary>
|
||||
public class CyclePhaseSystemTests
|
||||
@@ -99,7 +99,7 @@ namespace ProjectM.Tests
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Siege_Exits_To_Calm_On_DefendCleared_And_Charges_Goal_Once()
|
||||
public void Siege_Exits_To_Calm_On_DefendCleared_Does_Not_Charge_Goal()
|
||||
{
|
||||
var (world, group) = MakeWorld("SiegeClears", serverTick: 200);
|
||||
using (world)
|
||||
@@ -114,8 +114,8 @@ namespace ProjectM.Tests
|
||||
|
||||
Assert.AreEqual(CyclePhase.Calm, em.GetComponentData<CycleState>(cycle).Phase,
|
||||
"A cleared siege returns to Calm.");
|
||||
Assert.AreEqual(1, em.GetComponentData<GoalProgress>(cycle).Charge,
|
||||
"One goal charge accrues per siege survived (single writer).");
|
||||
Assert.AreEqual(0, em.GetComponentData<GoalProgress>(cycle).Charge,
|
||||
"DR-042: surviving a base siege does NOT charge the goal (the AFK win path is closed).");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user