Deferred death: damage and destroy only mark minions; the Death Creation Step removes them when the outermost Phase ends, and Death Phases resolve Deathrattles in order of play until no new deaths occur. Deathrattle summons use the board position the Death Event remembered. Harness adds destroy(target). Expansion Drop: Twisting Nether as content only. test_02_mortally_wounded_still_triggers no longer asserts the Acolyte is still on the board: from Module 3 on it leaves at the end of the Sequence, and verify-references runs Module 2's tests against the Module 3 reference. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
57 lines
5.0 KiB
Markdown
57 lines
5.0 KiB
Markdown
# Module 3 scenarios: Deferred death
|
|
|
|
Each heading is a test name. The Rust test lives in `tests/rust/test_03.rs` and the TypeScript test in `tests/ts/test_03.test.ts`; both state exactly what is written here. Player 0 is the first player, player 1 the second. Every minion in these tests is summoned for player 0, in the order listed, so the first one listed has the lowest order of play and stands furthest left. Each test calls `clearLog()` after its setup, so `log()` holds only the events of the action under test.
|
|
|
|
Cards used (text from `course/catalog.json`):
|
|
|
|
- `Loot Hoarder`, 2/1: "Deathrattle: Draw a card."
|
|
- `Harvest Golem`, 2/3: "Deathrattle: Summon a 2/1 Damaged Golem."
|
|
- `Damaged Golem`, 2/1, no text. Only Harvest Golem creates it.
|
|
- `Unstable Ghoul`, 1/3: "Taunt. Deathrattle: Deal 1 damage to all minions." Taunt has no effect in these tests.
|
|
- `Armorsmith`, 1/4: "Whenever a friendly minion takes damage, gain 1 Armor."
|
|
- `Test Reactor` (fictional), 1/5: "Whenever a hero takes damage, gain +1 Attack." No hero takes damage in these tests, so it never triggers; it is here to stand on the board.
|
|
- `Whirlwind`, spell: "Deal 1 damage to ALL minions."
|
|
- `Test Filler` (fictional), 1/1, no text. Used to fill decks.
|
|
|
|
A minion is removed from play only in the Death Creation Step, which runs when the Sequence's outermost Phase ends. The step removes every minion at 0 or less Health and every minion marked by a destroy effect, all at once, and records `Destroyed{id}` for each in order of play. If it removed anything, a Death Phase follows: it records `DeathPhase{round}` (1 for the first Death Phase of the Sequence, 2 for the next, and so on) and resolves the Deathrattles of the removed minions in order of play. When the Death Phase ends, the step runs again, until it removes nothing.
|
|
|
|
### test_03_removed_only_after_sequence
|
|
|
|
- Setup: `newGame` with a deck of 5 `Test Filler` for player 0. Summon `Loot Hoarder` (id H), then `Armorsmith` (id S).
|
|
- Action: player 0 casts `Whirlwind`.
|
|
- Assertions:
|
|
- The log is exactly, in this order: `SpellCast{card: "Whirlwind"}`, `Damaged{target: H, amount: 1}`, `Damaged{target: S, amount: 1}`, `Triggered{source: S, trigger: "damaged"}`, `ArmorGained{player: 0, amount: 1}`, `Triggered{source: S, trigger: "damaged"}`, `ArmorGained{player: 0, amount: 1}`, `Destroyed{id: H}`, `DeathPhase{round: 1}`, `Triggered{source: H, trigger: "deathrattle"}`, `Drew{player: 0, id: C}`, where C is the only card in `hand(0)`. H is at 0 Health from the first `Damaged` event, but it is removed only after every reaction to the Whirlwind has resolved.
|
|
- `zoneOf(H)` is graveyard.
|
|
- `board(0)` is `[S]`.
|
|
- `armor(0)` is 2.
|
|
|
|
### test_03_chained_death_phases
|
|
|
|
- Setup: an empty game. Summon `Harvest Golem` (id G), then `Unstable Ghoul` (id U), then `Test Reactor` (id R). `dealDamage(G, 2)`, which leaves G at 1 Health.
|
|
- Action: `dealDamage(U, 3)`.
|
|
- Assertions:
|
|
- The log is exactly, in this order: `Damaged{target: U, amount: 3}`, `Destroyed{id: U}`, `DeathPhase{round: 1}`, `Triggered{source: U, trigger: "deathrattle"}`, `Damaged{target: G, amount: 1}`, `Damaged{target: R, amount: 1}`, `Destroyed{id: G}`, `DeathPhase{round: 2}`, `Triggered{source: G, trigger: "deathrattle"}`, `Summoned{id: D}`, where D is the first id in `board(0)`. The Ghoul's Deathrattle does not hit the Ghoul: it has already left play. Its damage leaves G at 0 Health, and G is removed by the second Death Creation Step, after the first Death Phase has ended.
|
|
- `nameOf(D)` is `"Damaged Golem"`.
|
|
- `board(0)` is `[D, R]`: the Damaged Golem takes the board position G had when it died, left of R, not the right end.
|
|
- `zoneOf(U)` and `zoneOf(G)` are graveyard.
|
|
- `health(R)` is 4.
|
|
|
|
### test_03_simultaneous_removal
|
|
|
|
- Setup: `newGame` with a deck of 5 `Test Filler` for player 0. Summon `Loot Hoarder` (id H1), then another `Loot Hoarder` (id H2).
|
|
- Action: player 0 casts `Whirlwind`.
|
|
- Assertions:
|
|
- `hand(0)` has 2 cards; call them C1 and C2, in hand order.
|
|
- The log is exactly, in this order: `SpellCast{card: "Whirlwind"}`, `Damaged{target: H1, amount: 1}`, `Damaged{target: H2, amount: 1}`, `Destroyed{id: H1}`, `Destroyed{id: H2}`, `DeathPhase{round: 1}`, `Triggered{source: H1, trigger: "deathrattle"}`, `Drew{player: 0, id: C1}`, `Triggered{source: H2, trigger: "deathrattle"}`, `Drew{player: 0, id: C2}`. Both minions leave play before either Deathrattle resolves, and the Deathrattles resolve in order of play, in one Death Phase.
|
|
- `zoneOf(H1)` and `zoneOf(H2)` are graveyard, and `board(0)` is empty.
|
|
|
|
### test_03_destroy_marks_pending
|
|
|
|
- Setup: an empty game. Summon `Harvest Golem` (id G).
|
|
- Action: `destroy(G)`.
|
|
- Assertions:
|
|
- The log is exactly, in this order: `Destroyed{id: G}`, `DeathPhase{round: 1}`, `Triggered{source: G, trigger: "deathrattle"}`, `Summoned{id: D}`, where D is the only id in `board(0)`. A destroy effect deals no damage and does not remove the minion itself: it marks G, and the Death Creation Step removes it like any other death.
|
|
- `health(G)` is 3: G was at full Health when it was removed.
|
|
- `zoneOf(G)` is graveyard.
|
|
- `nameOf(D)` is `"Damaged Golem"`.
|