From 7d97bb1093a200db26d85e119c26c14aaf6952b4 Mon Sep 17 00:00:00 2001 From: Eric Wagoner Date: Tue, 18 Aug 2026 00:57:31 -0400 Subject: [PATCH] Bots stop wasting counters on what cannot be countered MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Per the owner's ruling: EMPATHY mirrors only delivered damage, so a damage-less curse gives it nothing — the berserker keeps it sheathed against afflictions (an automaton burned one on SLOW DEATH). And the permanent curses (slow death, walking dead, idiot) ride no duration pipe, so BLUNT and shieldstone numbers can't shorten them: only a full stop or REMOVE CURSE answers those, and the ladder now knows it. Co-Authored-By: Claude Fable 5 Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc --- packages/engine/src/automaton.ts | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/packages/engine/src/automaton.ts b/packages/engine/src/automaton.ts index 78ff8e6..90c8f36 100644 --- a/packages/engine/src/automaton.ts +++ b/packages/engine/src/automaton.ts @@ -760,14 +760,19 @@ function respond(view: GameView, style: AutomatonStyle, tier: TierTraits): Comma if (half && incoming >= 3) return { type: "counteract", instanceId: half.instanceId }; } // ABSORB soaks points only ("no effect on duration-based spells"); - // BLUNT and the stones work on durations too. + // BLUNT and the stones halve durations — but a PERMANENT curse (slow + // death, walking dead, idiot) rides no duration pipe, so nothing short + // of a full stop or REMOVE CURSE touches it. + const permanentCurse = affliction && + (attackId === "slow-death" || attackId === "walking-dead" || attackId === "idiot"); const absorb = find("absorb"); if (absorb && !affliction && incoming >= 2 - flinch && incoming <= 3) return { type: "counteract", instanceId: absorb.instanceId }; const blunt = find("blunt"); - if (blunt && incoming >= 2 - flinch) return { type: "counteract", instanceId: blunt.instanceId }; - // The berserker shares its pain out of spite. + if (blunt && !permanentCurse && incoming >= 2 - flinch) return { type: "counteract", instanceId: blunt.instanceId }; + // The berserker shares its pain out of spite — but only pain: a + // damage-less curse gives EMPATHY nothing to mirror. const empathy = find("empathy"); - if (empathy && style === "berserker" && incoming >= 2) { + if (empathy && style === "berserker" && !affliction && incoming >= 2) { return { type: "counteract", instanceId: empathy.instanceId }; } // Nothing to block with: teleport clear of the big ones. @@ -785,9 +790,10 @@ function respond(view: GameView, style: AutomatonStyle, tier: TierTraits): Comma ...(num ? { numberInstanceIds: [num.instanceId] } : {}), }; } - // A displayed shieldstone lets numbers soak the small ones. + // A displayed shieldstone lets numbers soak the small ones — durations + // included, but never a permanent curse. const stoneShown = me(view).displayed.some((c) => c.cardId === "shieldstone"); - if (stoneShown && incoming >= 2) { + if (stoneShown && !permanentCurse && incoming >= 2) { const num = numbersInHand(view)[0]; if (num) return { type: "counteract", instanceId: num.instanceId }; }