The finished table lays every hand face-up

Once the game is won, the view stops keeping secrets: revealedHands
carries every player's cards, and the table replaces your hand row
with a face-up gallery — each wizard's name (trophy on the winner)
beside their final hand, tap any card to enlarge, "empty-handed"
written in script for those who died with nothing. In hotseat this is
the thing the winner passes around after dismissing the fanfare; in
async games it greets each player when they open the finished game.
Redaction still guards every phase before "finished."

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Eric Wagoner
2026-08-16 11:17:07 -04:00
co-authored by Claude Fable 5
parent 13aeeea0ef
commit e7b17f7643
2 changed files with 87 additions and 1 deletions
+5
View File
@@ -67,6 +67,8 @@ export interface GameView {
outOfTurnWindow: { playerId: PlayerId; kind: "interrupt" | "opportunity-fire" } | null;
/** YOUR armed ambushes. Other players' ambushes are invisible. */
yourAmbushes: AmbushState[];
/** Once the game is finished, every hand goes face-up on the table. */
revealedHands: Record<PlayerId, CardInstance[]> | null;
}
export function viewFor(state: GameState, playerId: PlayerId): GameView {
@@ -107,6 +109,9 @@ export function viewFor(state: GameState, playerId: PlayerId): GameView {
displayed: p.hand.filter((c) => p.displayed.includes(c.instanceId)),
})),
yourHand: you ? [...you.hand] : [],
revealedHands: state.phase === "finished"
? Object.fromEntries(state.players.map((p) => [p.id, [...p.hand]]))
: null,
treasures: state.treasures.map((t) => ({ ...t })),
deckCount: state.deck.length,
discardCount: state.discard.length,