feat(battle-engine-port): M8 COMPLETE — lethal damage proves follower death via combat math

A when_play damage=5 spell (the M6 card 800134020) played at a select_count=1
enemy follower with life <= 5 kills it as a consequence of damage -> life <= 0 ->
the dead-check + the same RemoveInplayCard/cemetery path M7 lit up (the dominant
real-card removal mechanic), reached through combat math rather than `destroy`.

Oracle LethalDamageSpellOracleTests: selected follower (1/2) removed (board -1 +
cemetery +1, the M7 dimension); un-selected control (6/7, life > 5) untouched and
still on board (M6 routing; select_count=1 hits only the selected target). 8/8
green; engine 0 errors; check_drift clean; ZERO new Engine/shim/manifest work —
the death path inherited M7's death-voice fix; the predicted damage-VFX shadow
never materialized.

Load-bearing (M4/M6 discipline): swapping the selection to the 6/7 -> it survives
at 2 and nobody dies, proving removal is gated on the SELECTED follower's life
reaching <= 0, not on selection (M7's destroy) or a blanket wipe.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
gamer147
2026-06-06 08:34:22 -04:00
parent 9fc97abee7
commit 4f76fb21f0
2 changed files with 142 additions and 0 deletions

View File

@@ -85,6 +85,19 @@ namespace SVSim.BattleEngine.Tests
public const int DestroyTargetFollowerId = FollowerId; // neutral 1/2 (the selected, destroyed one)
public const int DestroyOtherFollowerId = UnselectTargetFollowerId; // neutral 6/7 (the un-selected survivor)
// M8 next milestone: LETHAL damage — proves follower DEATH VIA COMBAT MATH (damage >= life ->
// 0 life -> the same RemoveInplayCard/cemetery death path M7 lit up via `destroy`, but reached
// through the dominant real-card mechanic: "deal N damage"). Reuses the M6 damage=5 spell
// (800134020) but with target followers STRADDLING 5 life so the SAME spell kills one and merely
// chips the other in a single oracle: the SELECTED target has life <= 5 and dies (board -1 +
// cemetery +1, the M7 assertions), while the UN-SELECTED control has life > 5 and survives at
// reduced life (the M6 life-delta assertion). This combines M7's removal dimension with M6's
// life-delta + routing, and distinguishes death-via-damage from the unconditional `destroy`.
public const int LethalDamageSpellId = TargetSpellId; // 800134020, when_play damage=5
public const int LethalDamage = TargetSpellDamage; // 5
public const int LethalTargetFollowerId = FollowerId; // neutral 1/2 (life 2 <= 5 -> dies)
public const int SurvivorTargetFollowerId = UnselectTargetFollowerId; // neutral 6/7 (life 7 > 5 -> survives at 2)
private static bool _done;
public static void EnsureInitialized()