Duels record the rules revision they began under
CURRENT_RULES is stamped on the start line and the game state, and a ledger replays under the revision it recorded (1 when it has none), so a future fix that changes how a past turn resolves can keep the old path for old duels. The reports desk skill now says when to bump it: only when the deploy gate flags ledgers. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0141G6xqLeNRYEtviLWSB5Up
This commit is contained in:
co-authored by
Claude Fable 5.1
parent
8eca078043
commit
7485d50b8d
+4
-4
@@ -7,7 +7,7 @@ import { randomBytes } from 'node:crypto';
|
||||
import { chooseBotTurn } from '../../src/lib/game/bot';
|
||||
import { resolveTurn } from '../../src/lib/game/resolve';
|
||||
import { GESTURES, type Gesture } from '../../src/lib/game/spells';
|
||||
import { createGame, inDuel, SPECTATOR, type GameState, type TurnInput, type WizardId } from '../../src/lib/game/state';
|
||||
import { CURRENT_RULES, createGame, inDuel, SPECTATOR, type GameState, type TurnInput, type WizardId } from '../../src/lib/game/state';
|
||||
import { viewFor, type ChatLine, type RoomView } from '../../src/lib/game/view';
|
||||
import type { LedgerLine, Store } from './store';
|
||||
|
||||
@@ -142,7 +142,7 @@ export class Rooms {
|
||||
if (seat.id !== room.seats[0]?.id) throw new RoomError('Only the wizard who opened the table may begin the duel.', 403);
|
||||
if (room.state) throw new RoomError('The duel has already begun.', 409);
|
||||
if (room.seats.length < 2) throw new RoomError('A duel needs at least two wizards.', 409);
|
||||
this.commit(room, { t: 'start', seed: newSeed() });
|
||||
this.commit(room, { t: 'start', seed: newSeed(), rules: CURRENT_RULES });
|
||||
}
|
||||
|
||||
addBot(room: Room, token: string | undefined): Seat {
|
||||
@@ -160,7 +160,7 @@ export class Rooms {
|
||||
if (room.seats.some((s) => s.name.toLowerCase() === name.toLowerCase())) throw new RoomError('Another wizard here already has that name.', 409);
|
||||
const seat: Seat = { id: SEAT_IDS[room.seats.length], name, token: bot ? '' : newId(18), bot };
|
||||
this.commit(room, { t: 'seat', id: seat.id, name, token: seat.token, bot });
|
||||
if (room.seats.length === room.size) this.commit(room, { t: 'start', seed: newSeed() });
|
||||
if (room.seats.length === room.size) this.commit(room, { t: 'start', seed: newSeed(), rules: CURRENT_RULES });
|
||||
return seat;
|
||||
}
|
||||
|
||||
@@ -279,7 +279,7 @@ function apply(room: Room, line: LedgerLine): void {
|
||||
room.seats.push({ id: line.id, name: line.name, token: line.token, bot: line.bot });
|
||||
break;
|
||||
case 'start':
|
||||
room.state = createGame(Object.fromEntries(room.seats.map((s) => [s.id, s.name])), line.seed);
|
||||
room.state = createGame(Object.fromEntries(room.seats.map((s) => [s.id, s.name])), line.seed, line.rules ?? 1);
|
||||
break;
|
||||
case 'turn':
|
||||
if (!room.state) return;
|
||||
|
||||
+2
-1
@@ -9,7 +9,8 @@ import type { TurnInput, WizardId } from '../../src/lib/game/state';
|
||||
export type LedgerLine =
|
||||
| { t: 'room'; id: string; seats: number; createdAt: number }
|
||||
| { t: 'seat'; id: WizardId; name: string; token: string; bot: boolean }
|
||||
| { t: 'start'; seed: number }
|
||||
/** Ledgers from before revisions were recorded resolve under rules 1. */
|
||||
| { t: 'start'; seed: number; rules?: number }
|
||||
| { t: 'turn'; at: number; inputs: Record<WizardId, TurnInput> }
|
||||
/** Written after the turn that ends the duel, for anything that reads ledgers without the engine. */
|
||||
| { t: 'over'; at: number; winner: WizardId | null; reason: string }
|
||||
|
||||
Reference in New Issue
Block a user