The die rolls in the open

Every player-facing D4 roll now lands in the chronicle as pips with
its purpose: "🎲 alice rolls a 3 — aiming at the unseen — only a 1
finds them." A shared rollD4 helper threads the generic dieRolled
event through blind staggers and swings, pit leaps, ooze and pit
struggles, and the invisible/shrink miss rolls — the table sees the
die land, exactly as it would in person. Rolls whose numbers already
showed (the troll's swing, the misdirection direction, the opening
roll-off) keep their lines.

And the physical die's other job — "any 50-50 call" — gets its
button: 🎲 beside the say-box in online games (server-rolled,
published through the chat ledger so it persists, replays, and counts
toward unread badges) and under the chronicle in hotseat, rolled on
the device. Chronicle only; no game state touched.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
Eric Wagoner
2026-08-16 15:57:28 -04:00
co-authored by Claude Fable 5
parent d6d34887e3
commit ef661c79ad
6 changed files with 221 additions and 17 deletions
+11
View File
@@ -278,6 +278,17 @@ wss.on("connection", (socket) => {
broadcast(room, (playerId) => ({ type: "state", view: viewForPlayer(room, playerId), seq: room.log.length }));
break;
}
case "rollDie": {
// The tabletop D4 for house calls: publishes to the room's talk,
// so it persists, replays, and shows in unread badges like chat.
const room = session.roomId ? getRoom(session.roomId) : undefined;
if (!room || !session.playerId) return send(socket, { type: "error", message: "not in a room" });
const roll = 1 + Math.floor(Math.random() * 4);
const result = addChat(room, session.playerId, `rolls the die \u2014 ${roll}`);
if ("error" in result) return send(socket, { type: "error", message: result.error });
broadcast(room, () => ({ type: "chat", player: session.playerId, text: result.text, at: result.at }));
break;
}
case "chat": {
const room = session.roomId ? getRoom(session.roomId) : undefined;
if (!room || !session.playerId) return send(socket, { type: "error", message: "not in a room" });