Rev 12: vanishing and water answer the call to arms
INVISIBLE's corner reads NEUTRAL/COUNTERACTION, and ANTI-ANTI's own face names it an escape — yet the engine refused it at the door. Now it counters: the vanishing goes up mid-stack (duration from a NUMBER card riding the counteract command), the attacker's 1-in-4 hit roll happens at resolution, the spell lingers after the exchange, and ANTI-ANTI cannot pin it. WATERWALL — "Acts as counteraction to FIREBALL" — now mirrors WALL OF FIRE's waterbolt-stopping role and counts as a total stop. WALL OF FIRE itself joins the total-stop set at rev 12 only: stored rev-10/11 games bounced after it and replay so. While responding, tapping a number card holds it to ride the next counter (unless a displayed Shieldstone makes the number itself the counteraction, as before). The automatons learn the trick too: vanish when the blow is heavy and the shields are spent, and never waste ANTI-ANTI against an escape. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
fb2266b401
commit
4d8584ae44
@@ -844,3 +844,65 @@ describe("total stops end the exchange (rules rev 10)", () => {
|
||||
expect(state.players.find((p) => p.id === defender)!.life).toBeLessThan(15);
|
||||
});
|
||||
});
|
||||
|
||||
describe("escapes and elemental walls as counteractions", () => {
|
||||
function rigged(attackId: string, defenderCards: { instanceId: string; cardId: string }[]) {
|
||||
let { state } = createGame({ playerIds: ["alice", "bob"], seed: 42, sets: ["basic"], deckRev: 12 });
|
||||
state = toRound2(state);
|
||||
const { attacker, defender } = faceOff(state);
|
||||
const atk = giveCard(state, attacker, attackId);
|
||||
const d = state.players.find((p) => p.id === defender)!;
|
||||
defenderCards.forEach((c, i) => { d.hand[i] = c; });
|
||||
state = must(state, attacker, {
|
||||
type: "cast", instanceId: atk.instanceId, target: { kind: "player", playerId: defender },
|
||||
});
|
||||
return { state, attacker, defender, atk };
|
||||
}
|
||||
|
||||
it("invisible vanishes mid-stack: the sustained goes up, the hit needs a 1", () => {
|
||||
let { state, defender } = rigged("fireball", [
|
||||
{ instanceId: "invisible#T", cardId: "invisible" },
|
||||
{ instanceId: "number-3#T", cardId: "number-3" },
|
||||
]);
|
||||
state = must(state, defender, {
|
||||
type: "counteract", instanceId: "invisible#T", numberInstanceIds: ["number-3#T"],
|
||||
});
|
||||
const fx = state.sustained.find((s) => s.cardId === "invisible" && s.targetId === defender);
|
||||
expect(fx).toBeDefined();
|
||||
expect(fx!.remainingTurns).toBe(3);
|
||||
// The attached number left the hand with the spell.
|
||||
const d = state.players.find((p) => p.id === defender)!;
|
||||
expect(d.hand.some((c) => c.instanceId === "number-3#T")).toBe(false);
|
||||
});
|
||||
|
||||
it("anti-anti cannot pin the vanishing — escape is escape", () => {
|
||||
let { state, attacker, defender } = rigged("fireball", [
|
||||
{ instanceId: "invisible#T", cardId: "invisible" },
|
||||
]);
|
||||
state = must(state, defender, { type: "counteract", instanceId: "invisible#T" });
|
||||
const a = state.players.find((p) => p.id === attacker)!;
|
||||
a.hand[1] = { instanceId: "anti-anti#T", cardId: "anti-anti" };
|
||||
const refused = applyCommand(state, attacker, { type: "counteract", instanceId: "anti-anti#T" });
|
||||
expect(refused.ok).toBe(false);
|
||||
});
|
||||
|
||||
it("waterwall meets the fireball and stops it whole", () => {
|
||||
let { state, attacker, defender } = rigged("fireball", [
|
||||
{ instanceId: "waterwall#T", cardId: "waterwall" },
|
||||
]);
|
||||
const lifeBefore = state.players.find((p) => p.id === defender)!.life;
|
||||
state = must(state, defender, { type: "counteract", instanceId: "waterwall#T" });
|
||||
state = must(state, attacker, { type: "pass" });
|
||||
// A total stop: the attacker's declined answer resolves at once (rev 10+).
|
||||
expect(state.stack).toBeNull();
|
||||
expect(state.players.find((p) => p.id === defender)!.life).toBe(lifeBefore);
|
||||
});
|
||||
|
||||
it("waterwall refuses everything that is not a fireball", () => {
|
||||
let { state, defender } = rigged("dagger", [
|
||||
{ instanceId: "waterwall#T", cardId: "waterwall" },
|
||||
]);
|
||||
const refused = applyCommand(state, defender, { type: "counteract", instanceId: "waterwall#T" });
|
||||
expect(refused.ok).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user