Rules rev 4: a creature's blow can be counteracted

The WRAITH card assumes the window exists — "REFLECTIONs used on the
wraith's touch will damage the wraith" — but creature damage applied
instantly, so BLUNT had nothing to catch, as playtesting found. Under
revision 4 every creature blow against a wizard opens the same
counteraction stack a spell does: the wraith's entry touch, the
democratic monster's claw, and commanded troll/skeleton/shadow
attacks. The blow's damage rides the stack; BLUNT halves it (round
up); reflections work by name against creatures — half back for
REFLECTION, the whole blow for FULL REFLECTION — landing on the
creature, not its controller; FULL SHIELD correctly does nothing
("does not stop any physical attack"); the wraith's card theft is a
secondary effect that lands only if damage does. No aim-miss rolls
against invisible or shrunk defenders — the creature is already in
the square. The attack fanfare shows the creature's own card.

Earlier revisions keep the instant touch so every stored game — and
the live one that found this — replays unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Eric Wagoner
2026-08-16 13:25:45 -04:00
co-authored by Claude Fable 5
parent 3f3e6d9853
commit d1eace9530
5 changed files with 166 additions and 15 deletions
+11 -4
View File
@@ -83,9 +83,12 @@
const youMustRespond = $derived(view?.stack != null && view.stack.waitingOn === view.you);
const attackNoticeKey = $derived(
youMustRespond && view?.stack
? `${view.stack.attackerId}:${view.stack.attackCard?.instanceId ?? "punch"}:${view.stack.counters.length}`
? `${view.stack.attackerId}:${view.stack.attackCard?.instanceId ?? view.stack.creatureId ?? "punch"}:${view.stack.counters.length}`
: null,
);
const attackingCreature = $derived(
view?.stack?.creatureId ? view.creatures.find((c) => c.id === view!.stack!.creatureId) ?? null : null,
);
const youMustDiscard = $derived(view != null && view.pendingDiscard === view.you);
const youMustShield = $derived(view?.chaosPending?.queue[0] === view?.you && view != null);
const holdingWard = $derived(view?.yourHand.some((c) => c.cardId === "ward") ?? false);
@@ -746,13 +749,17 @@
<div class="scrim attack-scrim" role="alertdialog" aria-label="you are under attack">
<div class="attack-notice">
<div class="attack-headline">
{#if view.stack.defenderId === view.you}
{#if view.stack.defenderId === view.you && attackingCreature}
<strong>{view.stack.attackerId}</strong>'s {cardDef(attackingCreature.kind).name} attacks you!
{:else if view.stack.defenderId === view.you}
<strong>{view.stack.attackerId}</strong> attacks you!
{:else}
<strong>{view.stack.counters[view.stack.counters.length - 1]?.player}</strong> counters your spell!
{/if}
</div>
{#if view.stack.defenderId === view.you && view.stack.attackCard}
{#if view.stack.defenderId === view.you && attackingCreature}
<div class="attack-card"><Card card={{ instanceId: `atk-${attackingCreature.id}`, cardId: attackingCreature.kind }} /></div>
{:else if view.stack.defenderId === view.you && view.stack.attackCard}
<div class="attack-card"><Card card={view.stack.attackCard} /></div>
{#if view.stack.numberValue != null}
<div class="attack-power">powered by a {view.stack.numberValue}</div>
@@ -1131,7 +1138,7 @@
<span class="hint-alert">
{#if view.stack.defenderId === view.you}
{view.stack.attackerId} attacks with
{view.stack.attackCard ? cardDef(view.stack.attackCard.cardId).name : "a punch"} —
{attackingCreature ? `the ${cardDef(attackingCreature.kind).name}` : view.stack.attackCard ? cardDef(view.stack.attackCard.cardId).name : "a punch"} —
tap a counteraction card, or
{:else}
{view.stack.waitingOn === view.you ? "They counter your spell — counter back, or" : ""}