Credibility pass: one teleport step, one bell, one step type, and the comments that argued are gone

Since 6e49fc9. Engine: the teleport BFS in the view and the engine's
wallIgnoringDistance share teleportStep; the counter trail is weighed
between steps instead of on six arms; the bush attack takes its
adjacency from SIDES like the wall does; a dead redirected clause, a
one-member set, an identity ternary, and a stray try/catch are gone;
two tests now assert what their names promise. Server: KEEPER and
MAX_SEATS live in rooms.ts, the three Sentry bells ring through one
helper, the unread reply field is dropped, actingSeat comes from the
engine, and the protocol header names every message. Web: ReplayStep
is one type, cardName one helper, the say box and the reference section
one snippet each, the keeper's name arrives from the server rather than
the source, and the lifesaver ruling that ruled nothing is out.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Jm2auWk6RP71CjaAb4FMoG
This commit is contained in:
Eric WagonerandClaude Fable 5.1 committed 2026-09-22 09:56:49 -04:00
1 parent c4a555f8df
commit 66b5c06f17
21 files changed
+245 -239

No files matched your search

+13 -25
View File
@@ -20,6 +20,7 @@ import {
type TreasureState,
type TurnState,
dreadDistance,
teleportStep,
} from "./game";
export interface PlayerPublicView {
@@ -367,13 +368,6 @@ export function bentSightFor(view: GameView, from: Cell, to: Cell): boolean {
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:
* no stack, a creature's or physical attack, a non-LOS card, attacker and
* defender sharing a square, or no sight under this viewer's knowledge
* (a believed illusion wall can honestly hide the line).
*/
/** A sight line as the board draws it: the legs, the corner bend, and the
* one wall a VISIONSTONE dissolved. */
export interface SightLine {
@@ -429,7 +423,13 @@ export function sightTraceBetween(
return null;
}
/** The sight line of the attack on the stack, for the board to draw. */
/**
* 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:
* no stack, a creature's or physical attack, a non-LOS card, attacker and
* defender sharing a square, or no sight under this viewer's knowledge
* (a believed illusion wall can honestly hide the line).
*/
export function stackSightTrace(view: GameView): SightLine | null {
const stack = view.stack;
if (!stack || stack.creatureId) return null;
@@ -453,9 +453,7 @@ export function castSightTrace(
events: readonly GameEvent[],
afterTheFact = false,
): SightLine | null {
let def;
try { def = cardDef(cast.cardId); } catch { return null; }
if (def.los !== true) return null;
if (cardDef(cast.cardId).los !== true) return null;
const to = cast.targetCell ?? view.players.find((p) => p.id === cast.target)?.position ?? null;
if (!to) return null;
const caster = view.players.find((p) => p.id === cast.caster);
@@ -517,9 +515,8 @@ export function eligibleCellsFor(view: GameView, cardId: string, bentCorner = fa
if (cardId === "teleport") {
// Up to four spaces, walls and objects ignored; not into solid stone.
// BFS over existing cells, matching the engine's wallIgnoringDistance —
// the maze wraps for teleporters as it does for walkers, a warp mouth
// being one step like any doorway.
// The maze wraps for teleporters as it does for walkers, and from
// rev 22 the outer edge is no more than a wall to them.
const out = new Set<string>();
const dist = new Map<string, number>([[key(me.position.x, me.position.y), 0]]);
const queue = [me.position];
@@ -528,17 +525,8 @@ export function eligibleCellsFor(view: GameView, cardId: string, bentCorner = fa
const d = dist.get(key(cur.x, cur.y))!;
if (d >= 4) continue;
for (const side of SIDES) {
let n = neighbor(cur, side);
if (!view.board.cells[key(n.x, n.y)]) {
const w = view.board.warps.find((w) => w.from.cell.x === cur.x && w.from.cell.y === cur.y && w.from.side === side);
if (w) n = w.to.cell;
else if (view.deckRev >= 22) {
// Rev 22: the outer edge is no more than a wall to a teleporter.
const back = edgeReentry(view.board, cur, side);
if (!back) continue;
n = back;
} else continue;
}
const n = teleportStep(view.board, cur, side, view.deckRev >= 22);
if (!n) continue;
const nk = key(n.x, n.y);
if (dist.has(nk)) continue;
dist.set(nk, d + 1);