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>
5.0 KiB
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:
newGamewith a deck of 5Test Fillerfor player 0. SummonLoot Hoarder(id H), thenArmorsmith(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 inhand(0). H is at 0 Health from the firstDamagedevent, 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.
- The log is exactly, in this order:
test_03_chained_death_phases
- Setup: an empty game. Summon
Harvest Golem(id G), thenUnstable Ghoul(id U), thenTest 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 inboard(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)andzoneOf(G)are graveyard.health(R)is 4.
- The log is exactly, in this order:
test_03_simultaneous_removal
- Setup:
newGamewith a deck of 5Test Fillerfor player 0. SummonLoot Hoarder(id H1), then anotherLoot 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)andzoneOf(H2)are graveyard, andboard(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 inboard(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".
- The log is exactly, in this order: