Zero-damage attacks stop lying about being stopped

DROP OBJECT resolved correctly — the treasure fell — but the
chronicle announced "The attack is completely stopped," because the
attackResolved event branded any attack that dealt zero damage as
stopped. Utility attacks deal zero by design; only an attack that was
TRYING to wound counts as stopped when nothing lands. Tests pin both
sides: uncountered DROP OBJECT reports unstopped and drops the
treasure; FULL SHIELD reports stopped and the treasure stays carried.

Not deployed — a live game is in progress.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Eric Wagoner
2026-08-16 12:58:16 -04:00
co-authored by Claude Fable 5
parent 7e3e00bf97
commit b210cffa76
2 changed files with 51 additions and 1 deletions
+4 -1
View File
@@ -4497,6 +4497,9 @@ function resolveStack(state: GameState, events: GameEvent[]): void {
? (stack.numberValue ?? 1) * stack.amplifyFactor * stack.extendFactor
: 0;
// Whether this attack even tries to wound: utility attacks (DROP OBJECT,
// TELEPORT OPPONENT) deal 0 by design, and dealing 0 is not being stopped.
const dealsDamage = base > 0;
const pipe: DamagePipeline = {
damage: base,
duration: baseDuration,
@@ -4578,7 +4581,7 @@ function resolveStack(state: GameState, events: GameEvent[]): void {
attackCardId: attackId,
damageDealt,
reflectedDamage: pipe.redirected ? pipe.damage : pipe.reflectedDamage,
fullyStopped: pipe.fullyStopped || (damageDealt === 0 && !pipe.redirected && !effect?.sustains),
fullyStopped: pipe.fullyStopped || (dealsDamage && damageDealt === 0 && !pipe.redirected && !effect?.sustains),
redirected: pipe.redirected,
});