Trigger multipliers as aura data on cards, snapshotted by an Aura Update (Other) after each Death Creation Step and on summon, and applied by one generic routine (activations) when each queued trigger starts. Baron Rivendare is content only (stacking "max"); Brann Bronzebeard is the content-only Expansion Drop. Adds play (now required) and Battlecry. Co-Authored-By: Claude Opus 5.5 <[email protected]>
123 lines
3.8 KiB
TypeScript
123 lines
3.8 KiB
TypeScript
// Module 4: Interceptors and "trigger twice". Each test matches a heading in scenarios.md.
|
|
import { expect, test } from "vitest";
|
|
import { newGame } from "../src/harness";
|
|
|
|
const fillers = (n: number): string[] => Array(n).fill("Test Filler");
|
|
|
|
test("test_04_baron_doubles", () => {
|
|
const g = newGame({ decks: [fillers(5), []] });
|
|
const b = g.summon("Baron Rivendare", 0);
|
|
const h = g.summon("Loot Hoarder", 0);
|
|
const golem = g.summon("Harvest Golem", 0);
|
|
g.dealDamage(golem, 2);
|
|
g.clearLog();
|
|
|
|
g.cast("Whirlwind", 0);
|
|
|
|
const hand = g.hand(0);
|
|
expect(hand).toHaveLength(2);
|
|
const [c1, c2] = hand;
|
|
const board = g.board(0);
|
|
expect(board).toHaveLength(3);
|
|
expect(board[0]).toBe(b);
|
|
const [, d1, d2] = board;
|
|
expect(g.log()).toEqual([
|
|
{ type: "SpellCast", card: "Whirlwind" },
|
|
{ type: "Damaged", target: b, amount: 1 },
|
|
{ type: "Damaged", target: h, amount: 1 },
|
|
{ type: "Damaged", target: golem, amount: 1 },
|
|
{ type: "Destroyed", id: h },
|
|
{ type: "Destroyed", id: golem },
|
|
{ type: "DeathPhase", round: 1 },
|
|
{ type: "Triggered", source: h, trigger: "deathrattle" },
|
|
{ type: "Drew", player: 0, id: c1 },
|
|
{ type: "Triggered", source: h, trigger: "deathrattle" },
|
|
{ type: "Drew", player: 0, id: c2 },
|
|
{ type: "Triggered", source: golem, trigger: "deathrattle" },
|
|
{ type: "Summoned", id: d1 },
|
|
{ type: "Triggered", source: golem, trigger: "deathrattle" },
|
|
{ type: "Summoned", id: d2 },
|
|
]);
|
|
expect(g.nameOf(d1)).toBe("Damaged Golem");
|
|
expect(g.nameOf(d2)).toBe("Damaged Golem");
|
|
expect(g.health(b)).toBe(6);
|
|
});
|
|
|
|
test("test_04_simultaneous_death_not_doubled", () => {
|
|
const g = newGame({ decks: [fillers(5), []] });
|
|
const b = g.summon("Baron Rivendare", 0);
|
|
const h = g.summon("Loot Hoarder", 0);
|
|
g.clearLog();
|
|
|
|
g.cast("Twisting Nether", 0);
|
|
|
|
expect(g.hand(0)).toHaveLength(1);
|
|
const triggers = g.log().filter((e) => e.type === "Triggered" && e.source === h && e.trigger === "deathrattle");
|
|
expect(triggers).toHaveLength(1);
|
|
expect(g.zoneOf(b)).toBe("graveyard");
|
|
expect(g.zoneOf(h)).toBe("graveyard");
|
|
});
|
|
|
|
test("test_04_two_barons_do_not_stack", () => {
|
|
const g = newGame({ decks: [fillers(5), []] });
|
|
g.summon("Baron Rivendare", 0);
|
|
g.summon("Baron Rivendare", 0);
|
|
const h = g.summon("Loot Hoarder", 0);
|
|
g.clearLog();
|
|
|
|
g.dealDamage(h, 1);
|
|
|
|
const hand = g.hand(0);
|
|
expect(hand).toHaveLength(2);
|
|
const [c1, c2] = hand;
|
|
expect(g.log()).toEqual([
|
|
{ type: "Damaged", target: h, amount: 1 },
|
|
{ type: "Destroyed", id: h },
|
|
{ type: "DeathPhase", round: 1 },
|
|
{ type: "Triggered", source: h, trigger: "deathrattle" },
|
|
{ type: "Drew", player: 0, id: c1 },
|
|
{ type: "Triggered", source: h, trigger: "deathrattle" },
|
|
{ type: "Drew", player: 0, id: c2 },
|
|
]);
|
|
});
|
|
|
|
test("test_04_aura_timing_order", () => {
|
|
const g = newGame({ decks: [fillers(5), []] });
|
|
const h = g.summon("Loot Hoarder", 0);
|
|
const b = g.summon("Baron Rivendare", 0);
|
|
g.clearLog();
|
|
|
|
g.cast("Twisting Nether", 0);
|
|
|
|
const hand = g.hand(0);
|
|
expect(hand).toHaveLength(1);
|
|
const c = hand[0];
|
|
expect(g.log()).toEqual([
|
|
{ type: "SpellCast", card: "Twisting Nether" },
|
|
{ type: "Destroyed", id: h },
|
|
{ type: "Destroyed", id: b },
|
|
{ type: "DeathPhase", round: 1 },
|
|
{ type: "Triggered", source: h, trigger: "deathrattle" },
|
|
{ type: "Drew", player: 0, id: c },
|
|
]);
|
|
});
|
|
|
|
test("test_04_battlecry_on_play", () => {
|
|
const g = newGame({ decks: [fillers(5), []] });
|
|
const e = g.addToHand("Novice Engineer", 0);
|
|
g.clearLog();
|
|
|
|
g.play(e);
|
|
|
|
const hand = g.hand(0);
|
|
expect(hand).toHaveLength(1);
|
|
const c = hand[0];
|
|
expect(g.log()).toEqual([
|
|
{ type: "Summoned", id: e },
|
|
{ type: "Triggered", source: e, trigger: "battlecry" },
|
|
{ type: "Drew", player: 0, id: c },
|
|
]);
|
|
expect(g.zoneOf(e)).toBe("board");
|
|
expect(g.board(0)).toEqual([e]);
|
|
});
|