Three rulings from the night games (rules rev 2)
Teleport wraps the maze's rim: its four counted squares now step through warp mouths like any doorway, so a wizard can blink off one side of the board and onto the other. A wizard at a door's threshold may pull it open and peek — lock removed, door unlocked this turn, or PICK LOCK / MASTER KEY in hand — without stepping through. The door still hangs shut to everyone down the hallway; only a HELD door is propped open for every eye. Gated behind rules rev 2 (now sourced from the engine's CURRENT_RULES_REV) so stored games replay with their doors dark; the client's sight mirror learns the same peek. Fear no longer nails a cornered wizard to the floor: a step closer to the dread is allowed when it walks the shortest way out of it, so escape can round a corner. Standing outside and stepping in is still refused. All 15 production ledgers verified before deploy; 269 engine tests. 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
2932d1e500
commit
154e00141c
@@ -2,7 +2,7 @@
|
||||
// The server sends this after every state change; clients never see the
|
||||
// deck order or other players' hands.
|
||||
|
||||
import { sightBetween, traceSight, type AssembledBoard, type Cell, type SightTrace } from "./board";
|
||||
import { SIDES, edgeKey, sightBetween, traceSight, type AssembledBoard, type Cell, type SightTrace } from "./board";
|
||||
import { cardDef, type CardInstance } from "./cards";
|
||||
import {
|
||||
boardView,
|
||||
@@ -62,6 +62,8 @@ export interface GameView {
|
||||
/** Safes standing open (their combination entered this turn). */
|
||||
openSafes: string[];
|
||||
groundObjects: Record<string, CardInstance[]>;
|
||||
/** The rules revision this game was dealt under. */
|
||||
deckRev: number;
|
||||
doorStates: Record<string, "jammed" | "removed">;
|
||||
/** Accumulated attack damage per edge (public — cracks show). */
|
||||
wallDamage: Record<string, number>;
|
||||
@@ -153,6 +155,7 @@ export function viewFor(state: GameState, playerId: PlayerId): GameView {
|
||||
groundObjects: Object.fromEntries(
|
||||
Object.entries(state.groundObjects).map(([k, v]) => [k, [...v]]),
|
||||
),
|
||||
deckRev: state.config.deckRev ?? 1,
|
||||
doorStates: { ...state.doorStates },
|
||||
wallDamage: { ...state.wallDamage },
|
||||
openDoorEdges: [...state.openDoorEdges],
|
||||
@@ -202,11 +205,25 @@ export function sightedCellsFor(view: GameView): Set<string> {
|
||||
|
||||
/** The board-as-seen and sight blockers this view's sight rules run against. */
|
||||
function sightBasis(view: GameView): { board: GameView["board"]; blockers: Record<string, true> } {
|
||||
// Held-open doors are open doorways to the eye.
|
||||
// Held-open doors are open doorways to every eye. Beyond them, the
|
||||
// viewer at a door's threshold may pull it open and peek (rules rev 2):
|
||||
// lock removed, door unlocked this turn, or PICK LOCK / MASTER KEY in
|
||||
// hand — mirroring the engine's doorsAjar.
|
||||
let board = view.board;
|
||||
if (view.heldDoorEdges.length > 0) {
|
||||
const openKeys = new Set(view.heldDoorEdges);
|
||||
const me = view.players.find((p) => p.id === view.you);
|
||||
if (view.deckRev >= 2 && me?.alive) {
|
||||
const carriesKey = view.yourHand.some((c) => c.cardId === "pick-lock" || c.cardId === "master-key");
|
||||
for (const side of SIDES) {
|
||||
const key = edgeKey(me.position, side);
|
||||
if (board.edges[key] !== "door") continue;
|
||||
const workable = carriesKey && view.doorStates[key] !== "jammed";
|
||||
if (workable || view.doorStates[key] === "removed" || view.openDoorEdges.includes(key)) openKeys.add(key);
|
||||
}
|
||||
}
|
||||
if (openKeys.size > 0) {
|
||||
const edges = { ...board.edges };
|
||||
for (const k of view.heldDoorEdges) delete edges[k];
|
||||
for (const k of openKeys) delete edges[k];
|
||||
board = { ...board, edges };
|
||||
}
|
||||
const blockers: Record<string, true> = {};
|
||||
|
||||
Reference in New Issue
Block a user