The great simplification: every vintage gate collapses, the count restarts at 1
All 50 rooms were retired (backed up on the droplet and in Spaces), so no ledger needs an old branch to replay: forty revisions of deckRev gates fold into one canonical ruleset — the newest behavior everywhere. The ward's arming, the idiot's steering, the lazy illusion roll, the legacy redirection swap, and the flat wave all leave with their gates; RULES_REV restarts at 1 for whenever the rules fork again. Old-vintage test pins go with them. The opening screen now quietly drops seats whose rooms the server no longer knows, instead of listing them "unreachable" forever. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Fable 5
parent
e8df6efcde
commit
8a50ff7f36
+11
-16
@@ -42,7 +42,8 @@ export interface GameView {
|
||||
winReason: "treasures" | "lastStanding" | null;
|
||||
turn: TurnState;
|
||||
activePlayerId: PlayerId;
|
||||
/** The game's rules revision — the client mirrors rev-gated legality. */
|
||||
/** The game's rules revision (a fresh count from 1; gates return if the
|
||||
* rules ever fork again while games are live). */
|
||||
deckRev: number;
|
||||
/** Board with dynamic wall changes already merged in. */
|
||||
board: AssembledBoard;
|
||||
@@ -70,7 +71,7 @@ export interface GameView {
|
||||
createdEdges: string[];
|
||||
/** Illusion edges YOU know are fake (creator or saw through); others see walls. */
|
||||
knownIllusionEdges: string[];
|
||||
/** Every illusion edge and YOUR verdict on it (rules rev 29+): untested
|
||||
/** Every illusion edge and YOUR verdict on it: untested
|
||||
* shimmers, believes renders solid, mine/seesThrough are ghosts. */
|
||||
illusionEdges: Record<string, "untested" | "believes" | "seesThrough" | "mine">;
|
||||
creatures: CreatureState[];
|
||||
@@ -82,9 +83,7 @@ export interface GameView {
|
||||
outOfTurnWindow: { playerId: PlayerId; kind: "interrupt" | "opportunity-fire" } | null;
|
||||
/** CHAOS shield windows in progress (public: everyone sees it coming). */
|
||||
chaosPending: { casterId: PlayerId; queue: PlayerId[] } | null;
|
||||
/** Whether YOUR ward is set to spring. */
|
||||
yourWardArmed: boolean;
|
||||
/** A grab hangs while the treasure's owner decides their Ward (rev 31). */
|
||||
/** A grab hangs while the treasure's owner decides their Ward. */
|
||||
wardPending: { ownerId: PlayerId; takerId: PlayerId } | null;
|
||||
/** YOUR armed ambushes. Other players' ambushes are invisible. */
|
||||
yourAmbushes: AmbushState[];
|
||||
@@ -95,20 +94,17 @@ export interface GameView {
|
||||
export function viewFor(state: GameState, playerId: PlayerId): GameView {
|
||||
const you = state.players.find((p) => p.id === playerId);
|
||||
// Illusion walls render as real walls unless this viewer knows better.
|
||||
// From rules rev 29 their locations are open knowledge (the cast is
|
||||
// public at a table) — what stays personal is each player's verdict.
|
||||
// Their locations are open knowledge (the cast is public at a table) —
|
||||
// what stays personal is each player's verdict.
|
||||
const base = boardView(state);
|
||||
const rev29 = (state.config.deckRev ?? 1) >= 29;
|
||||
const knownIllusionEdges: string[] = [];
|
||||
const illusionEdges: Record<string, "untested" | "believes" | "seesThrough" | "mine"> = {};
|
||||
let edges = base.edges;
|
||||
for (const [key, wall] of Object.entries(state.illusionWalls)) {
|
||||
const knows = wall.createdBy === playerId || wall.belief[playerId] === "seesThrough";
|
||||
if (rev29) {
|
||||
illusionEdges[key] =
|
||||
wall.createdBy === playerId ? "mine"
|
||||
: wall.belief[playerId] ?? "untested";
|
||||
}
|
||||
illusionEdges[key] =
|
||||
wall.createdBy === playerId ? "mine"
|
||||
: wall.belief[playerId] ?? "untested";
|
||||
if (knows) {
|
||||
knownIllusionEdges.push(key);
|
||||
} else {
|
||||
@@ -169,7 +165,6 @@ export function viewFor(state: GameState, playerId: PlayerId): GameView {
|
||||
chaosPending: state.chaosPending
|
||||
? { casterId: state.chaosPending.casterId, queue: [...state.chaosPending.queue] }
|
||||
: null,
|
||||
yourWardArmed: state.wardArmed.includes(playerId),
|
||||
wardPending: state.wardPending ? { ...state.wardPending } : null,
|
||||
yourAmbushes: state.ambushes
|
||||
.filter((a) => a.ownerId === playerId)
|
||||
@@ -205,9 +200,9 @@ 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 (rules rev 15).
|
||||
// Held-open doors are open doorways to the eye.
|
||||
let board = view.board;
|
||||
if (view.deckRev >= 15 && view.heldDoorEdges.length > 0) {
|
||||
if (view.heldDoorEdges.length > 0) {
|
||||
const edges = { ...board.edges };
|
||||
for (const k of view.heldDoorEdges) delete edges[k];
|
||||
board = { ...board, edges };
|
||||
|
||||
Reference in New Issue
Block a user