Files
systemic-game-design-course/course/02-action-queue/scenarios.md
T
Lucas WintherandClaude Opus 5.5 8a4eba1948 feat: module 03 death step
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 <[email protected]>
2026-10-29 02:42:12 +01:00

3.2 KiB

Module 2 scenarios: The action queue, depth-first

Each heading is a test name. The Rust test lives in tests/rust/test_02.rs and the TypeScript test in tests/ts/test_02.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. 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):

  • Armorsmith, 1/4: "Whenever a friendly minion takes damage, gain 1 Armor."
  • Acolyte of Pain, 1/4: "Whenever this minion takes damage, draw a card."
  • Whirlwind, spell: "Deal 1 damage to ALL minions."
  • Test Echo (fictional), 1/5: "Whenever a minion takes damage, deal 1 damage to the enemy hero." Player 0's enemy hero is hero(1).
  • Test Reactor (fictional), 1/5: "Whenever a hero takes damage, gain +1 Attack."
  • Test Filler (fictional), 1/1, no text. Used to fill decks.

Heroes have 30 Health and 0 Armor at the start of a game.

test_02_aoe_damage_then_triggers

  • Setup: newGame with a deck of 5 Test Filler for each player. Summon Armorsmith (id S), then Acolyte of Pain (id A).
  • Action: player 0 casts Whirlwind.
  • Assertions:
    • The log has two Damaged events, for S then A (area damage is created in order of play), each of amount 1.
    • Every Damaged event comes before every Triggered event in the log.
    • Triggered events: S appears twice (once for each damaged friendly minion, itself included), A once. The test does not check how those three are interleaved.
    • armor(0) is 2.
    • hand(0) has 1 card.

test_02_mortally_wounded_still_triggers

  • Setup: newGame with a deck of 5 Test Filler for player 0. Summon Acolyte of Pain (id A). dealDamage(A, 3), which leaves A at 1 Health and draws one card. Record hand(0)'s length as N.
  • Action: player 0 casts Whirlwind.
  • Assertions:
    • The log contains Triggered{source: A, trigger: "damaged"} and a Drew event for player 0.
    • hand(0) has N + 1 cards.
    • health(A) is 0.
    • The test does not check zoneOf(A). Module 2 has no death step, so A stays on the board at 0 Health. Module 3 adds the step that removes A once the Sequence's reactions have resolved, and this test must keep passing then.

test_02_depth_first_nesting

  • Setup: an empty game. Summon Test Echo (id E), then Armorsmith (id S), then Test Reactor (id R).
  • Action: dealDamage(S, 1).
  • Assertions:
    • The sources of the Triggered events, in log order, are E, R, S. E and S both respond to S taking damage. E resolves first (older), and the hero damage it deals makes R trigger and resolve before S gets its turn.
    • The StatsChanged event for R comes before the ArmorGained event in the log.
    • attack(R) is 2.
    • armor(0) is 1.
    • health(hero(1)) is 29.

test_02_empty_deck_draw_is_fatigue

  • Setup: an empty game (no decks). Summon Acolyte of Pain (id A).
  • Action: dealDamage(A, 1).
  • Assertions:
    • The log is exactly Damaged{target: A, amount: 1}, Triggered{source: A, trigger: "damaged"}, Fatigue{player: 0}.
    • hand(0) is empty.
    • health(hero(0)) is 30: in this course, Fatigue is only an event.