Implement casting layer: attack stack, counteraction chain, first effects

The attack/counteraction stack: casting an attack (or punching) opens a
stack; the defender counteracts or passes, the attacker may respond
(ANTI-ANTI nullifies a counter), and resolution runs the damage
pipeline in play order. First effect wave, encoded from verified card
text: Fireball (flat 5 + destroys carried magic stones if damage gets
through), Lightning Blast (number damage + stun unless fully stopped),
Powerthrust (2 + optional number), Waterbolt (caster-chosen
damage/knockback split with push-away movement), Blunt (halve, round
result up), Absorb (-3), Full Shield (spell-only stop), Reflection
(half to both), Full Reflection (redirect), Absorb Spell (nullify and
steal the attack card), Create/Destroy Wall (dynamic edge overrides
layered over the board; collapse deals 4 to adjacent squares), Speed
(extra turn), and TRAP! on draw (lose next turn, redraw). Lost turns
skip on advance; unimplemented cards refuse to cast with a clear
error. 35 tests passing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Eric Wagoner
2026-08-15 19:47:06 -04:00
co-authored by Claude Fable 5
parent a8884592a4
commit 7c607ad5c7
4 changed files with 974 additions and 70 deletions
+6
View File
@@ -21,6 +21,7 @@ export interface CardDef {
name: string;
set: CardSet;
cardType: CardType | null;
subtypes?: string[];
los: boolean | null;
text: string | null;
quantity: number | null;
@@ -84,3 +85,8 @@ export function numberValue(cardId: string): number {
export function isTrap(cardId: string): boolean {
return cardId === "trap";
}
/** Magic stones (Powerstone, Shieldstone, ...) — destroyed by Fireball. */
export function isMagicStone(cardId: string): boolean {
return cardDef(cardId).subtypes?.includes("stone") ?? false;
}