Files
idlegame/src/state/storyOrchestration.ts
T

54 lines
1.8 KiB
TypeScript

import type { GameContent } from '../content/index';
import type { GameState } from '../engine/game';
import { evaluateTriggers, type StoryEvent, type TriggerContext } from '../engine/story';
import type { GamePrefs } from './prefs';
import type { StoryLogEntry } from './store';
export interface StoryUiEffect {
enteredNodeIds: string[];
logEntries: StoryLogEntry[];
shouldOpenPanel: boolean;
eventLogLines: string[];
}
export function storyEventsToLogEntries(events: StoryEvent[]): StoryLogEntry[] {
return events
.filter((e) => e.kind === 'enter')
.map((e) => ({ nodeId: e.nodeId, prose: e.prose, choiceLabel: e.choiceLabel }));
}
export function shouldAutoNavigateToStory(
prefs: GamePrefs,
nodeId: string,
content: GameContent,
): boolean {
const node = content.storyNodesById[nodeId];
if (!node) return false;
if (prefs.storyOpenMode === 'manual') return false;
if (prefs.storyOpenMode === 'auto') return true;
return (node.choices?.length ?? 0) > 0;
}
export function processStoryTriggers(
state: GameState,
content: GameContent,
ctx: TriggerContext,
prefs: GamePrefs,
): StoryUiEffect {
const { enteredNodeIds, events } = evaluateTriggers(state, content, ctx);
const logEntries = storyEventsToLogEntries(events);
const shouldOpenPanel =
enteredNodeIds.length > 0 &&
enteredNodeIds.some((id) => shouldAutoNavigateToStory(prefs, id, content));
const customLogs = events.filter((e) => e.kind === 'log').map((e) => e.prose);
const eventLogLines = [
...customLogs,
...logEntries.map((e) =>
e.choiceLabel
? `Story: ${e.choiceLabel}`
: `Story: ${(content.storyNodesById[e.nodeId]?.prose ?? '').slice(0, 40)}…`,
),
];
return { enteredNodeIds, logEntries, shouldOpenPanel, eventLogLines };
}