The chronicle marks each line with its wizard's color; the turn's owner stands out
Two of Randy's flourishes. Every chronicle line now carries a small square in the color of the wizard acting — whoever cast, struck, walked, or countered, else the turn's owner — so one player's doings can be picked out of the scroll at a glance. And the life-points row of the wizard whose turn it is wears an accent bar and a tint, since bold alone was lost in the handwriting. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Jm2auWk6RP71CjaAb4FMoG
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
19aec73b30
commit
3fc9df85ac
@@ -234,6 +234,22 @@ export interface LogLine {
|
||||
text: string;
|
||||
turn: number | null;
|
||||
notable: boolean;
|
||||
/** The wizard acting, for the color mark beside the line: whoever
|
||||
* cast, struck, walked, or countered — otherwise the turn's owner. */
|
||||
actor?: string;
|
||||
}
|
||||
|
||||
/** Events whose `player` is the one acting rather than the one acted on. */
|
||||
const ACTING = new Set([
|
||||
"moved", "warpStepped", "jumpedPit", "counteractionPlayed", "treasurePickedUp", "treasureDropped",
|
||||
"numberPlayedForMovement", "cardsDiscarded", "turnStarted", "turnEnded", "doorUnlocked", "madDash",
|
||||
"climbedFromPit", "spellTrapped",
|
||||
]);
|
||||
function actorOf(e: GameEvent, turnOwner: string | null): string | undefined {
|
||||
const any = e as unknown as Record<string, unknown>;
|
||||
for (const k of ["caster", "attacker", "by", "owner"]) if (typeof any[k] === "string") return any[k] as string;
|
||||
if (ACTING.has(e.type) && typeof any.player === "string") return any.player as string;
|
||||
return turnOwner ?? undefined;
|
||||
}
|
||||
|
||||
/** The boundaries the turn count walks — mirrored by the server's
|
||||
@@ -305,6 +321,8 @@ class Net {
|
||||
* socket that never fires onclose; the watchdog closes it by hand so
|
||||
* the reconnect loop (and the masthead banner) actually engage. */
|
||||
private lastHeard = Date.now();
|
||||
/** Whose turn the chronicle is in, for the mark on lines with no actor of their own. */
|
||||
private turnOwner: string | null = null;
|
||||
private watchdog: ReturnType<typeof setInterval> | null = null;
|
||||
roomId = $state<string | null>(null);
|
||||
players = $state<string[]>([]);
|
||||
@@ -510,6 +528,7 @@ class Net {
|
||||
this.openingRolls = { rolls: e.dieRolls, first: e.firstPlayer, players: e.players };
|
||||
}
|
||||
if (TURN_BOUNDARY.has(e.type)) this.turnCounter++;
|
||||
if (e.type === "turnStarted") this.turnOwner = e.player;
|
||||
const line = humanize(e);
|
||||
if (line) {
|
||||
// Every turn wears its eye, on the header line that opens
|
||||
@@ -517,7 +536,7 @@ class Net {
|
||||
// winning line carries its own besides.
|
||||
const notable = this.turnCounter >= 0 &&
|
||||
(e.type === "gameWon" || TURN_BOUNDARY.has(e.type));
|
||||
this.log = [...this.log, { text: line, turn: this.turnCounter >= 0 ? this.turnCounter : null, notable }];
|
||||
this.log = [...this.log, { text: line, turn: this.turnCounter >= 0 ? this.turnCounter : null, notable, actor: actorOf(e, this.turnOwner) }];
|
||||
}
|
||||
}
|
||||
if (talk > 0) {
|
||||
@@ -545,7 +564,7 @@ class Net {
|
||||
break;
|
||||
}
|
||||
case "chat": {
|
||||
this.log = [...this.log, { text: `\u{1F4AC} ${msg.player}: ${msg.text}`, turn: null, notable: false }];
|
||||
this.log = [...this.log, { text: `\u{1F4AC} ${msg.player}: ${msg.text}`, turn: null, notable: false, actor: msg.player }];
|
||||
this.chatCount += 1;
|
||||
if (this.roomId) this.markChatSeen();
|
||||
break;
|
||||
|
||||
Reference in New Issue
Block a user