The automatons learn Eric's tactics: roadwork, denial, bursts, breathing room

Per the owner's briefing on how these cards are actually played:
- Roadwork on the march: DISPEL CREATION un-creates conjured walls and
  filled squares; STONE TO WATER melts walls and stone blocks (cast only
  from outside its own wave); CREATE DOOR plus a lock-opener turns a wall
  into a doorway; DIMENSIONAL WARP folds a 6+-step detour into one step,
  and the bot steps through its tokens when the far side is closer.
- Path denial grows: JAM LOCK seals doors on a threat's road, ILLUSION
  WALL stands in for CREATE WALL, the full nuisance shelf (pit, slime,
  ooze, rosebush, tacks, dust cloud) joins stone and thornbush, and a
  BOOBYTRAP lands mid-path when nothing can reroute the thief.
- Bursts: ADD joins a second number to the march; MAD DASH doubles the
  sprint to gold (never while carrying); POWER RUN buys the last spaces
  of a winning delivery with blood.
- Breathing room when pressed (worrier, treasure-carrier, or bleeding):
  FEAR at three paces, UGLY when they crowd in, BUDDY to pacify the hound.
- AROUND THE CORNER: an enemy one bend out of sight can be attacked; new
  bentSightFor mirrors the engine's bentLos from the viewer's knowledge.
- GameView gains createdEdges (public — the table watched them conjured).
All newly playable cards leave the bottom discard tier via USEFUL_NEUTRALS.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
This commit is contained in:
Eric Wagoner
2026-08-17 20:14:55 -04:00
co-authored by Claude Fable 5
parent 4e14926c0c
commit 4bda6087b1
3 changed files with 393 additions and 49 deletions
+22
View File
@@ -66,6 +66,8 @@ export interface GameView {
openDoorEdges: string[];
/** Door edges held open by a standing wizard. */
heldDoorEdges: string[];
/** Edges conjured into being (walls, doors, firewalls) - dispellable. */
createdEdges: string[];
/** Illusion edges YOU know are fake (creator or saw through); others see walls. */
knownIllusionEdges: string[];
creatures: CreatureState[];
@@ -143,6 +145,7 @@ export function viewFor(state: GameState, playerId: PlayerId): GameView {
wallDamage: { ...state.wallDamage },
openDoorEdges: [...state.openDoorEdges],
heldDoorEdges: state.heldDoors.map((h) => h.key),
createdEdges: Object.keys(state.createdEdges),
knownIllusionEdges,
creatures: state.creatures.map((c) => ({ ...c, scorchedThisTurn: [...c.scorchedThisTurn] })),
wandCharges: { ...state.wandCharges },
@@ -215,6 +218,25 @@ export function traceSightFor(view: GameView, from: Cell, to: Cell): SightTrace
return traceSight(board, from, to, blockers);
}
/**
* AROUND THE CORNER's bent sight, from this viewer's knowledge: the caster
* sees a middle square which sees the target — mirroring the engine's
* bentLos so a client can predict whether the modifier will land.
*/
export function bentSightFor(view: GameView, from: Cell, to: Cell): boolean {
const { board, blockers } = sightBasis(view);
if (sightBetween(board, from, to, blockers)) return true;
for (const key of Object.keys(board.cells)) {
if (blockers[key]) continue;
const [mx, my] = key.split(",").map(Number) as [number, number];
const mid = { x: mx, y: my };
if (sightBetween(board, from, mid, blockers) && sightBetween(board, mid, to, blockers)) {
return true;
}
}
return false;
}
/**
* The sight line behind the attack currently on the stack — the board's
* answer to "how can he even see me?". Null when nothing should draw: