Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141G6xqLeNRYEtviLWSB5Up
61 lines
2.4 KiB
TypeScript
61 lines
2.4 KiB
TypeScript
// 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;
|
|
}
|