Rev 10: a total stop ends the exchange, and the modal stops goading
Slow Death, countered with Force Field — and the battle modal popped right back up as if nothing had happened, goading a second counter out of a hand that had already won the exchange. The engine was bouncing every attacker's pass back to the defender so counters could stack; correct for partial stops (Blunt, Absorb, Reflection numbers), senseless past a total one. Under rules rev 10, when a Full Shield, Force Field, Teleport escape, Full Reflection, or Reverse stands unnullified, the attacker's declined answer resolves the stack on the spot. Older ledgers keep the bounce and replay unchanged. And when the exchange legitimately returns — a partial counter standing, or a shield broken by Anti-Anti — the modal now says so: "Your Blunt stands — only what slips past it will land," or "Your Full Shield was nullified — the attack comes on unchecked," instead of replaying the fanfare of a fresh, unanswered attack. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
ac53773fe4
commit
18d3142f95
@@ -859,6 +859,22 @@
|
||||
{:else if view.stack.counters.length > 0}
|
||||
<div class="attack-card"><Card card={view.stack.counters[view.stack.counters.length - 1]!.card} /></div>
|
||||
{/if}
|
||||
{#if view.stack.defenderId === view.you && view.stack.counters.length > 0}
|
||||
{@const standing = view.stack.counters.filter((c) => c.player === view.you && !c.nullified)}
|
||||
{@const broken = view.stack.counters.filter((c) => c.player === view.you && c.nullified)}
|
||||
{#if broken.length > 0 && standing.length === 0}
|
||||
<div class="attack-standing nullified">
|
||||
Your {broken.map((c) => cardDef(c.card.cardId).name).join(" and ")}
|
||||
{broken.length === 1 ? "was" : "were"} nullified — the attack comes on unchecked.
|
||||
</div>
|
||||
{:else if standing.length > 0}
|
||||
<div class="attack-standing">
|
||||
Your {standing.map((c) => cardDef(c.card.cardId).name).join(" and ")}
|
||||
stand{standing.length === 1 ? "s" : ""} — only what slips past
|
||||
{standing.length === 1 ? "it" : "them"} will land. Counter again, or let it resolve.
|
||||
</div>
|
||||
{/if}
|
||||
{/if}
|
||||
<button class="stamp big" onclick={() => (attackNoticeSeen = attackNoticeKey)}>To arms!</button>
|
||||
</div>
|
||||
</div>
|
||||
@@ -1999,6 +2015,14 @@
|
||||
.attack-card :global(.card) { transform: scale(1.35); margin: 1.2rem 0; }
|
||||
.attack-card :global(.card:hover) { transform: scale(1.35); }
|
||||
.attack-power { font-family: "Courier Prime", monospace; color: #6b5a41; font-size: 0.9rem; }
|
||||
.attack-standing {
|
||||
font-family: "Courier Prime", monospace;
|
||||
font-size: 0.85rem;
|
||||
color: #3f6b41;
|
||||
max-width: 17rem;
|
||||
margin: 0.3rem auto 0;
|
||||
}
|
||||
.attack-standing.nullified { color: #b3372b; }
|
||||
.attack-fist { font-size: 1.1rem; color: #43331f; }
|
||||
|
||||
.table-talk {
|
||||
|
||||
@@ -132,7 +132,7 @@ class LocalGame {
|
||||
seed,
|
||||
sets: expansion ? ["basic", "expansion1"] : ["basic"],
|
||||
...(colors ? { colors } : {}),
|
||||
deckRev: 9,
|
||||
deckRev: 10,
|
||||
};
|
||||
const { state, events } = createGame(config);
|
||||
this.config = config;
|
||||
|
||||
Reference in New Issue
Block a user