Illusion walls shimmer until YOU test them (rules rev 29)
Per the owner's design — and truer to a real table, where the cast is public: every illusion wall's location is open knowledge, rendered as a shimmering wall to any player whose eyes have not yet ruled on it. Testing is an explicit act: tap the shimmer (or bump into it) and a modal explains the 50/50 and offers 'Roll to test your eyes' — the new testIllusion command rolls once, then the wall either hardens or dissolves for you alone. Nobody's verdict is moved by watching someone else stroll through (the Q3WZ mystery: an automaton walking through its own round-1 fake). Untested walls block movement and sight without consuming RNG; the pre-29 lazy belief roll is preserved for stored games. Automatons doubt free shimmers on their best crossing before spending any card on that wall. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0138A8CjeQRpvzKxuMfz1Bqc
This commit is contained in:
co-authored by
Claude Fable 5
parent
500d9a7154
commit
d5b2b92f2c
@@ -70,6 +70,9 @@ 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
|
||||
* shimmers, believes renders solid, mine/seesThrough are ghosts. */
|
||||
illusionEdges: Record<string, "untested" | "believes" | "seesThrough" | "mine">;
|
||||
creatures: CreatureState[];
|
||||
/** Charges left on displayed wands (public), by card instance id. */
|
||||
wandCharges: Record<string, number>;
|
||||
@@ -90,11 +93,20 @@ 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.
|
||||
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";
|
||||
}
|
||||
if (knows) {
|
||||
knownIllusionEdges.push(key);
|
||||
} else {
|
||||
@@ -147,6 +159,7 @@ export function viewFor(state: GameState, playerId: PlayerId): GameView {
|
||||
heldDoorEdges: state.heldDoors.map((h) => h.key),
|
||||
createdEdges: Object.keys(state.createdEdges),
|
||||
knownIllusionEdges,
|
||||
illusionEdges,
|
||||
creatures: state.creatures.map((c) => ({ ...c, scorchedThisTurn: [...c.scorchedThisTurn] })),
|
||||
wandCharges: { ...state.wandCharges },
|
||||
dimWarps: state.dimWarps.map((w) => ({ a: { ...w.a }, b: { ...w.b } })),
|
||||
|
||||
Reference in New Issue
Block a user