Files
systemic-game-design-course/course/05-assemble/expansion
Lucas WintherandClaude Opus 5.5 e04dc1a11f feat: module 05 assemble
Cards become JSON data in course/cards (one file per card, validated
against card.schema.json and the catalog); the M5 references load them
via registerCards and interpret effects, replacing content closures.
Adds assemble(base, donor, half), the assemble/buffHand effects with an
injected chooser, Fleshshape as the data-only Expansion Drop, and stages
course/cards in verify-references and start-module.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-10-29 03:17:21 +01:00
..
2026-10-29 03:17:21 +01:00
2026-10-29 03:17:21 +01:00
2026-10-29 03:17:21 +01:00

Module 5 Expansion Drop: Fleshshape

The lesson's Expansion Drop beat explains the task. This file holds the scenario, the test locations and the check.

  • Card: Fleshshape, 3-mana Death Knight spell, "Assemble a Deathrattle minion. Give all minions in your hand +2/+2." (Fleshshape, hearthstone.wiki.gg).
  • Tests: tests/rust/test_05x.rs and tests/ts/test_05x.test.ts. Copy the one for your track into your workspace's tests/.
  • Reference answer: solution/cards/fleshshape.json, one card file for both tracks. Copy it into your workspace's cards/. Nothing under src/engine/ changes, and neither does the harness. It is not in course/cards/, so start-module doesn't hand it to you.
  • Check: commit your workspace before you start, then run node tools/expansion-check.mjs <your-workspace> <that-commit> from the course repository. It fails if any file under src/engine/ changed.

Fleshshape is Test Workshop (a Module 5 test card) with two values changed: the pool filter's trigger is deathrattle instead of battlecry, and the buff is +2/+2 instead of +1/+1. The wiki says a pool named on the card applies only to the base minion (Assemble, hearthstone.wiki.gg), which is what the filter of an assemble effect does: the donor options are not filtered.

Scenario

test_05x_fleshshape_pool_filter

  • Setup: newGame() (no decks). Set a chooser that records every call and answers "Loot Hoarder" for "base", "Novice Engineer" for "donor" and "top" for "half". Call clearLog().
  • Action: player 0 casts Fleshshape.
  • Assertions:
    • The chooser was called exactly three times, with kinds "base", "donor", "half" in that order.
    • The "base" options are exactly the names of the minion files in cards/ that have a deathrattle trigger clause, sorted. That list includes Loot Hoarder and not Novice Engineer. (With the course's cards: Harvest Golem, Loot Hoarder, Unstable Ghoul.)
    • The "donor" options include "Novice Engineer": the filter applies to the base only.
    • hand(0) has exactly 1 card, A. nameOf(A) is "Loot Hoarder (Assembled)" ("Battlecry: Draw a card."), cost(A) is 2, attack(A) is 4 and health(A) is 3: Loot Hoarder's 2/1, then +2/+2.
    • The log is exactly: SpellCast{card: "Fleshshape"}, StatsChanged{id: A, attack: 4, health: 3}.