Final wave: complete the 6th edition basic set (69/69 cards)

The hard six: AROUND THE CORNER attaches to any LOS attack and bends
the sight line through one intermediate cell. BLIND victims lurch in
die-rolled directions (bumping a wall costs the movement point, per
the card) and their attacks fly wherever the die says — hitting
whoever stands that way, or dissipating. UGLY drives every opponent
in sight fleeing along shortest paths (breadth-first, die-broken ties)
until they cannot see the caster. ILLUSION WALL is per-player reality:
each opponent rolls 50/50 the first time it matters and the wall is
real for believers forever — believers' views render it as a wall,
the caster and those who saw through it get a ghostly dashed line,
and Dispel Creation banishes it. ROTATE SECTOR turns a sector 90
degrees with every wall, door, wizard, treasure, object, firewall and
alteration turning in place (the home star, being the exact center,
never moves); RELOCATE SECTOR slides a sector anywhere that keeps all
sectors adjacent, reassembling the map and recomputing wraparounds.

Client: modifier attachment (Amplify/Add/Extend/Around The Corner),
two-stage relocate, rotation direction toggle, dashed known-illusions.
Every card in the 6th edition basic deck is now implemented.
81 tests passing.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Eric Wagoner
2026-08-15 20:29:09 -04:00
co-authored by Claude Fable 5
parent 4ab44cc535
commit 1924114b6d
7 changed files with 844 additions and 21 deletions
+18 -1
View File
@@ -50,17 +50,33 @@ export interface GameView {
groundObjects: Record<string, CardInstance[]>;
doorStates: Record<string, "jammed" | "removed">;
openDoorEdges: string[];
/** Illusion edges YOU know are fake (creator or saw through); others see walls. */
knownIllusionEdges: string[];
}
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.
const base = boardView(state);
const knownIllusionEdges: string[] = [];
let edges = base.edges;
for (const [key, wall] of Object.entries(state.illusionWalls)) {
const knows = wall.createdBy === playerId || wall.belief[playerId] === "seesThrough";
if (knows) {
knownIllusionEdges.push(key);
} else {
if (edges === base.edges) edges = { ...base.edges };
edges[key] = "wall";
}
}
const board = edges === base.edges ? base : { ...base, edges };
return {
you: playerId,
phase: state.phase,
winner: state.winner,
turn: state.turn,
activePlayerId: state.players[state.turn.activeIndex]!.id,
board: boardView(state),
board,
players: state.players.map((p) => ({
id: p.id,
position: p.position,
@@ -86,5 +102,6 @@ export function viewFor(state: GameState, playerId: PlayerId): GameView {
),
doorStates: { ...state.doorStates },
openDoorEdges: [...state.openDoorEdges],
knownIllusionEdges,
};
}