Fireball burns only the stones in play (rules rev 33)

'Destroys all magical stones an opponent is CARRYING' — the owner's
ruling: a stone hidden in the hand is a secret card, not a carried
stone. Only displayed stones burn; the old all-hand burning also leaked
hidden information by announcing cards nobody knew existed. Earlier
games replay their broader fire. All 42 production ledgers verified
before deploy.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
This commit is contained in:
Eric Wagoner
2026-08-19 22:19:20 -04:00
co-authored by Claude Fable 5
parent 1cf5d0a68d
commit b67f2a4c8a
4 changed files with 31 additions and 4 deletions
+11 -2
View File
@@ -840,9 +840,18 @@ const CARD_EFFECTS: Record<string, AttackEffect | NeutralEffect | CounterEffect>
baseDamage: () => 5,
onResolved: (ctx) => {
if (ctx.damageDealt <= 0) return;
const stones = ctx.defender.hand.filter((c) => isMagicStone(c.cardId));
// "Destroys all magical stones an opponent is CARRYING": a stone
// still hidden in the hand is a secret card, not a carried stone —
// only displayed stones burn (rules rev 33; earlier games burned
// the hand's hidden stones too and replay so).
const rev33 = (ctx.state.config.deckRev ?? 1) >= 33;
const stones = ctx.defender.hand.filter((c) =>
isMagicStone(c.cardId) &&
(!rev33 || ctx.defender.displayed.includes(c.instanceId)));
if (stones.length === 0) return;
ctx.defender.hand = ctx.defender.hand.filter((c) => !isMagicStone(c.cardId));
ctx.defender.hand = ctx.defender.hand.filter(
(c) => !stones.some((s) => s.instanceId === c.instanceId),
);
ctx.defender.displayed = ctx.defender.displayed.filter(
(id) => !stones.some((s) => s.instanceId === id),
);