// What one wizard is allowed to know. Gestures made while they were blind, or // while the other wizard was invisible, are unknown to them; the log lines that // describe those gestures are withheld too. Spells cast are always visible, as // the rules say. import { hiddenFromViewer, visibleHistory, type GameState, type WizardId } from './state'; export function viewFor(state: GameState, viewer: WizardId): GameState { const view = structuredClone(state); for (const id of view.seats) { if (id === viewer) continue; view.wizards[id].history = visibleHistory(state, viewer, id); } view.log = view.log.filter((l) => !hiddenFromViewer(l.hiddenFrom, viewer)); return view; } /** One line of table talk: from a seat, or from the Peanut Gallery when the host allows it (id SPECTATOR, signed with `name`), or from the keeper of the site. */ export interface ChatLine { id: WizardId; text: string; at: number; name?: string; keeper?: true; } /** What a seated player, or the gallery, is told by the server. Other seats' moves and tokens never leave it. */ export interface RoomView { roomId: string; seq: number; /** The most seats the table will take. */ size: number; /** The viewer's seat, or SPECTATOR for the gallery. */ me: WizardId; /** The wizard who opened the table and may begin the duel. */ host: WizardId; /** Who sits where; `standIn` marks a wizard's seat the host gave to a bot, which duels in it until they take it back. */ seats: { id: WizardId; name: string; bot: boolean; standIn?: true }[]; /** Seats that still have to move before the turn resolves. */ waitingOn: WizardId[]; /** Turns played so far, time stops included; gestures are sent with the count they were made against. */ resolved: number; state: GameState | null; chat: ChatLine[]; /** How many watch from the Peanut Gallery. */ audience: number; /** The host lets the gallery talk. */ galleryTalk: boolean; /** The keeper of the site was called to a seat, and by whom. */ challenge: { by: WizardId; at: number } | null; /** Names with a seat held who have not yet sat: the last table's wizards, or the keeper. */ expected: string[]; /** A finished table's rematch: where it went, and who called. */ rematch: { to: string; by: WizardId } | null; /** The table this one is the rematch of. */ rematchOf: string | null; /** The keeper of the site, and where they live, for a table that calls them. */ keeper: string; keeperZone: string; }