Credibility pass: the duels leave the code, staying in the ledgers
Third pass, scoped from 7a32370. Three blind reviewers (engine, web,
server/tools) each concluded the work is coherent engineering with
seam-level tells; every finding was verified before touching a line.
Session biography left the comments: the bot brain's heuristics no
longer cite the opponent who taught them, the RNRX coma parenthetical
and the thief-chase citation are gone, the seat-wallet comments state
their invariants without the war stories, and process-named test
groups now name the behaviors they pin. The incident record lives
where history belongs — commit messages and the ledgers.
Structural dedup: one VISIONSTONE one-edge-sight loop serves both
LOS paths; one creature-arrival touch handler serves walking and
warp-stepping (error text aligned); one facingWedge helper draws both
keymap ribbons; one spriteVisibleInCol rule serves the draw pass and
the hover test (which also stops re-sorting per pointermove); and
deepestFacing joins the director, replacing four copied scans.
Test hardening exposed real rot the tells were hiding: the tight
CreatureState cast caught two literals with a bogus field masking
three missing ones; the number-hoarding rig had NEVER run (its
column didn't exist on seed 42 — it now carves its own geometry);
the bank-guard rig now drives the whole table to an arrival
assertion; the bent-trace test walls off straight sight so the bend
must answer. Silent `return`-on-rig-failure became loud throws, and
can-never-fail assertions were removed.
Sweep-up: the eyeTurn ghost comment, the stacked leave() doc
comments (leave now delegates to leaveLocal), the dead ternary in
the seat client, the kick handler's name-coercion drift, kick ledger
lines gain timestamps, archiveRoomFile reuses fileFor, the RULES_REV
alias retires in favor of the engine constant, hitTest un-exports,
the NUL-sentinel hover shape becomes an honest "none" variant, and
the steering holds get named constants. The bezel's stride cluster
also centers per the table's note.
288 tests, 24 ledgers verified, all workspaces typecheck.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015RCWSTnb1KYTPyL4GmhGnF
This commit is contained in:
co-authored by
Claude Fable 5
parent
7bd8eff11c
commit
3bd7e3c81d
+46
-54
@@ -389,13 +389,11 @@ function doorsAjar(state: GameState, viewerId: PlayerId | undefined, board: Asse
|
||||
}
|
||||
|
||||
/** LOS including square-filling blockers. */
|
||||
function losWith(state: GameState, from: Cell, to: Cell, viewerId: PlayerId | undefined, stone: boolean): boolean {
|
||||
const board = doorsAjar(state, viewerId, openedDoors(state, boardView(state)));
|
||||
const blockers = losBlockers(state);
|
||||
if (sightBetween(board, from, to, blockers)) return true;
|
||||
if (!stone) return false;
|
||||
const viewer = viewerId ? state.players.find((p) => p.id === viewerId) : undefined;
|
||||
if (!viewer || !viewer.alive || !displays(viewer, "visionstone")) return false;
|
||||
/** Sight granted by removing any ONE closed edge — the VISIONSTONE's
|
||||
* whole power, shared by every path that honors it. */
|
||||
function sightThroughOneEdge(
|
||||
board: AssembledBoard, from: Cell, to: Cell, blockers: Record<string, true>,
|
||||
): boolean {
|
||||
for (const key of Object.keys(board.edges)) {
|
||||
if ((board.edges[key] ?? "open") === "open") continue;
|
||||
const edges = { ...board.edges };
|
||||
@@ -405,11 +403,21 @@ function losWith(state: GameState, from: Cell, to: Cell, viewerId: PlayerId | un
|
||||
return false;
|
||||
}
|
||||
|
||||
function losWith(state: GameState, from: Cell, to: Cell, viewerId: PlayerId | undefined, stone: boolean): boolean {
|
||||
const board = doorsAjar(state, viewerId, openedDoors(state, boardView(state)));
|
||||
const blockers = losBlockers(state);
|
||||
if (sightBetween(board, from, to, blockers)) return true;
|
||||
if (!stone) return false;
|
||||
const viewer = viewerId ? state.players.find((p) => p.id === viewerId) : undefined;
|
||||
if (!viewer || !viewer.alive || !displays(viewer, "visionstone")) return false;
|
||||
return sightThroughOneEdge(board, from, to, blockers);
|
||||
}
|
||||
|
||||
/** LOS including square-filling blockers. VISIONSTONE is the bearer's
|
||||
* sight wherever sight is asked of them — creations, dispels, utility
|
||||
* spells — not just attacks: one wall or door, any type, falls away.
|
||||
* Safe at every revision: widening what a cast may target never changes
|
||||
* how a recorded command replays. */
|
||||
* Ungated by design: validation may widen without a rev bump, because
|
||||
* refused commands never entered any ledger. */
|
||||
export function gameLos(state: GameState, from: Cell, to: Cell, viewerId?: PlayerId): boolean {
|
||||
return losWith(state, from, to, viewerId, true);
|
||||
}
|
||||
@@ -472,13 +480,7 @@ function casterLos(
|
||||
const blockers = losBlockers(state);
|
||||
if (sightBetween(board, from, to, blockers)) return true;
|
||||
if (!displays(caster, "visionstone")) return false;
|
||||
for (const key of Object.keys(board.edges)) {
|
||||
if ((board.edges[key] ?? "open") === "open") continue;
|
||||
const edges = { ...board.edges };
|
||||
delete edges[key];
|
||||
if (sightBetween({ ...board, edges }, from, to, blockers)) return true;
|
||||
}
|
||||
return false;
|
||||
return sightThroughOneEdge(board, from, to, blockers);
|
||||
}
|
||||
|
||||
/** Bent LOS for AROUND THE CORNER: caster sees a middle cell, which sees the target. */
|
||||
@@ -2941,6 +2943,31 @@ function impCheck(state: GameState, events: GameEvent[], onlyPlayer?: PlayerId):
|
||||
checkVictory(state, events);
|
||||
}
|
||||
|
||||
/** A creature arriving in a player's square touches: the wraith's chill
|
||||
* and the democratic monster's claw open a counteraction window ("REFLECTIONs
|
||||
* used on the wraith's touch will damage the wraith" — the card assumes
|
||||
* exactly this window). True = a stack opened and the turn should return.
|
||||
* "May attack only one player per round of turns" spends attackUsed. */
|
||||
function creatureTouchOnArrival(state: GameState, events: GameEvent[], creature: CreatureState): boolean {
|
||||
for (const p of state.players) {
|
||||
if (!p.alive || cellKey(p.position) !== cellKey(creature.position)) continue;
|
||||
if (p.id === creature.controllerId && creature.kind !== "democratic-monster") continue; // won't hurt creator
|
||||
if (creature.kind === "wraith" && !creature.attackUsed) {
|
||||
creature.attackUsed = true;
|
||||
events.push({ type: "creatureTouched", creatureId: creature.id, kind: creature.kind, player: p.id });
|
||||
openCreatureStack(state, creature, p, 2, "wraith");
|
||||
return true;
|
||||
}
|
||||
if (creature.kind === "democratic-monster" && !creature.attackUsed && !creature.justCreated) {
|
||||
creature.attackUsed = true;
|
||||
events.push({ type: "creatureTouched", creatureId: creature.id, kind: creature.kind, player: p.id });
|
||||
openCreatureStack(state, creature, p, 2, "claw");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/** A creature standing on a DIMENSIONAL WARP token steps through it like
|
||||
* any walker: its commander spends one of its moves, solid stone on the
|
||||
* far side refuses it, and a monster is no braver than a wizard about
|
||||
@@ -2964,7 +2991,7 @@ function doCreatureWarpStep(prev: GameState, creatureId: string): CommandResult
|
||||
if (state.squareContents[cellKey(dest)]?.kind === "stone") return err("the far side is solid stone");
|
||||
if (state.players.some((o) => o.alive && cellKey(o.position) === cellKey(dest) &&
|
||||
sustainedOn(state, o.id, "big-man").length > 0)) {
|
||||
return err("a giant fills that square");
|
||||
return err("a giant fills that corridor");
|
||||
}
|
||||
const from = creature.position;
|
||||
// FEAR holds monsters off too: "no player or monster".
|
||||
@@ -2972,23 +2999,7 @@ function doCreatureWarpStep(prev: GameState, creatureId: string): CommandResult
|
||||
creature.position = { ...dest };
|
||||
creature.movementUsed++;
|
||||
const events: GameEvent[] = [{ type: "creatureWarpStepped", creatureId, from, to: creature.position, by: active.id }];
|
||||
// Touch effects on arriving in a player's square, as any step has.
|
||||
for (const p of state.players) {
|
||||
if (!p.alive || cellKey(p.position) !== cellKey(creature.position)) continue;
|
||||
if (p.id === creature.controllerId && creature.kind !== "democratic-monster") continue;
|
||||
if (creature.kind === "wraith" && !creature.attackUsed) {
|
||||
creature.attackUsed = true;
|
||||
events.push({ type: "creatureTouched", creatureId: creature.id, kind: creature.kind, player: p.id });
|
||||
openCreatureStack(state, creature, p, 2, "wraith");
|
||||
return { ok: true, state, events };
|
||||
}
|
||||
if (creature.kind === "democratic-monster" && !creature.attackUsed && !creature.justCreated) {
|
||||
creature.attackUsed = true;
|
||||
events.push({ type: "creatureTouched", creatureId: creature.id, kind: creature.kind, player: p.id });
|
||||
openCreatureStack(state, creature, p, 2, "claw");
|
||||
return { ok: true, state, events };
|
||||
}
|
||||
}
|
||||
creatureTouchOnArrival(state, events, creature);
|
||||
return { ok: true, state, events };
|
||||
}
|
||||
|
||||
@@ -3046,26 +3057,7 @@ function doMoveCreature(prev: GameState, creatureId: string, direction: Side): C
|
||||
}
|
||||
creature.movementUsed++;
|
||||
events.push({ type: "creatureMoved", creatureId: creature.id, from, to: creature.position, direction, by: active.id });
|
||||
|
||||
// Touch effects on entering a player's square.
|
||||
for (const p of state.players) {
|
||||
if (!p.alive || cellKey(p.position) !== cellKey(creature.position)) continue;
|
||||
if (p.id === creature.controllerId && creature.kind !== "democratic-monster") continue; // won't hurt creator
|
||||
if (creature.kind === "wraith" && !creature.attackUsed) {
|
||||
creature.attackUsed = true;
|
||||
events.push({ type: "creatureTouched", creatureId: creature.id, kind: creature.kind, player: p.id });
|
||||
// The victim may counteract ("REFLECTIONs used on the wraith's touch
|
||||
// will damage the wraith" — the card assumes exactly this window).
|
||||
openCreatureStack(state, creature, p, 2, "wraith");
|
||||
return { ok: true, state, events };
|
||||
}
|
||||
if (creature.kind === "democratic-monster" && !creature.attackUsed && !creature.justCreated) {
|
||||
creature.attackUsed = true; // "may attack only one player per round of turns"
|
||||
events.push({ type: "creatureTouched", creatureId: creature.id, kind: creature.kind, player: p.id });
|
||||
openCreatureStack(state, creature, p, 2, "claw");
|
||||
return { ok: true, state, events };
|
||||
}
|
||||
}
|
||||
if (creatureTouchOnArrival(state, events, creature)) return { ok: true, state, events };
|
||||
checkVictory(state, events);
|
||||
return { ok: true, state, events };
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user