Adds course/12-combat: lesson, scenarios, nine test_12 tests in both tracks, the cumulative reference (Module 11's plus combat) and the drop. The Damage action carries per-target hits with a priority; react stable-sorts its Queue by priority before order of play, so the triggers answering the defender's Damage Event go first. orderAttack/canAttack/endTurn join the harness (orderAttack because attack(id) already reads Attack). endOfTurn triggers fire, so Drakkari Enchanter's data is live. Test Bell is scoped to Module 12's cards. Harness contract, catalog, research notes and earlier lessons' forward pointers follow. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Module 12 Expansion Drop: Bonechewer Brawler
The lesson's Expansion Drop beat explains the task. This file holds the scenario, the test locations and the check.
- Card: Bonechewer Brawler, 2-mana 2/3 Neutral minion, "Taunt. Whenever this minion takes damage, gain +2 Attack." (Bonechewer Brawler, hearthstone.wiki.gg).
- Tests:
tests/rust/test_12x.rsandtests/ts/test_12x.test.ts. Copy the one for your track into your workspace'stests/. - Reference answer:
solution/cards/bonechewer-brawler.json, one card file for both tracks. Copy it into your workspace'scards/. Nothing undersrc/engine/changes, and neither does the harness. It is not incourse/cards/, sostart-moduledoesn'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 undersrc/engine/changed.
Every clause of the card is a word the course already has: the keyword taunt (Unstable Ghoul has it), the trigger selfDamaged (Acolyte of Pain) and the effect gainAttack on self (Frothing Berserker). Before this module the engine kept taunt and did nothing with it. Now combat reads it.
Scenario
test_12x_bonechewer_brawler
- Setup:
newGamewith a deck of 5Test Fillerfor each player. SummonBonechewer Brawlerfor player 1 (id W), thenLoot Hoarderfor player 1 (id H), thenHarvest Golemfor player 0 (id A). CallclearLog(). - Assertions 1:
canAttack(A, H)is a string containingTaunt: the Brawler protects the Hoarder. - Action:
orderAttack(A, W). - Assertions 2:
- The log is exactly, in this order:
Damaged{target: W, amount: 2},Damaged{target: A, amount: 2},Triggered{source: W, trigger: "damaged"},StatsChanged{id: W, attack: 4, health: 1}. health(A)is 1: the Golem took 2, the Brawler's Attack when the damage was dealt. The +2 Attack comes from a trigger, after the simultaneous damage.attack(W)is 4.
- The log is exactly, in this order: