Fix caching, Limits placement, and explain the board better
This commit is contained in:
+31
-2
@@ -32,7 +32,14 @@ import type { GameConfig, GameState, PlayerIndex } from '../engine/state.ts';
|
||||
import { narrate } from '../sim/narrate.ts';
|
||||
// Import from the view module, NOT replay.ts — replay.ts writes files and reads process.argv,
|
||||
// which would pull node:fs into a browser bundle.
|
||||
import { cardName, describeIntent, geometryLabel, snapshot, variantLabel } from '../sim/view.ts';
|
||||
import {
|
||||
cardName,
|
||||
describeIntent,
|
||||
geometryLabel,
|
||||
snapshot,
|
||||
trainName,
|
||||
variantLabel,
|
||||
} from '../sim/view.ts';
|
||||
import type { TrackGeometry } from '../engine/content.ts';
|
||||
import { variantsFor } from '../engine/track.ts';
|
||||
import type { Frame } from '../sim/view.ts';
|
||||
@@ -258,6 +265,25 @@ export function submit(game: Game, intent: Intent): boolean {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Which cards in hand can be played RIGHT NOW, in hand order.
|
||||
*
|
||||
* A hand where some cards are simply unplayable — a Station upgrade before the Office is a Depot, a
|
||||
* Modifier with no Facility to sit beside — looks identical to one where everything is available.
|
||||
* Derived from `legalActions`, so it cannot disagree with what the buttons offer.
|
||||
*/
|
||||
export function handPlayable(game: Game): boolean[] {
|
||||
const hand = game.state.decks.hands.get(0) ?? [];
|
||||
const actor = currentActor(game);
|
||||
if (actor === null) return hand.map(() => false);
|
||||
const playable = new Set(
|
||||
legalActions(game.state, actor)
|
||||
.filter((i) => i.type === 'card.play')
|
||||
.map((i) => (i as Extract<Intent, { type: 'card.play' }>).cardId),
|
||||
);
|
||||
return hand.map((id) => playable.has(id));
|
||||
}
|
||||
|
||||
/** The board as the replay draws it, so the live game and the replay agree. */
|
||||
export function view(game: Game): Frame {
|
||||
return snapshot(game.state, [], null);
|
||||
@@ -267,7 +293,10 @@ function record(game: Game, events: GameEvent[]): void {
|
||||
for (const e of events) {
|
||||
// The same filter the replay uses: actor changes and phase bookkeeping are noise on screen.
|
||||
if (e.type === 'actorChanged') continue;
|
||||
const n = narrate(e, { cardName: (id) => cardName(game.state, id) });
|
||||
const n = narrate(e, {
|
||||
cardName: (id) => cardName(game.state, id),
|
||||
trainName: (id) => trainName(game.state, id),
|
||||
});
|
||||
game.log.push({ text: n.text, tone: n.tone });
|
||||
}
|
||||
// Keep the log bounded; the full history lives in `history` and can be replayed.
|
||||
|
||||
Reference in New Issue
Block a user