import type { GameData, SceneNode, ChapterInfo, Choice, Condition } from '../types' export class SceneManager { private scenes: Record = {} private startScene: string = '' chapters: ChapterInfo[] = [] load(data: GameData) { this.scenes = data.scenes this.startScene = data.startScene this.chapters = data.chapters || [] } getScene(id: string): SceneNode | undefined { return this.scenes[id] } getStartScene(): SceneNode { const scene = this.scenes[this.startScene] if (!scene) throw new Error(`Start scene "${this.startScene}" not found`) return scene } getAllSceneIds(): string[] { return Object.keys(this.scenes) } getScenes(): Record { return this.scenes } getChapterBySceneId(sceneId: string): ChapterInfo | undefined { return this.chapters.find((ch) => ch.startScene === sceneId) } getChapter(chapterId: string): ChapterInfo | undefined { return this.chapters.find((ch) => ch.id === chapterId) } getCandidateTargetIds(scene: SceneNode, evaluateCondition: (conds?: Condition[]) => boolean): string[] { const targets: string[] = [] if (scene.choices) { for (const choice of scene.choices) { if (!choice.conditions || evaluateCondition(choice.conditions)) { if (!targets.includes(choice.targetScene)) { targets.push(choice.targetScene) } } } } if (scene.nextScene && !targets.includes(scene.nextScene)) { targets.push(scene.nextScene) } return targets } getCandidateUrls(scene: SceneNode, evaluateCondition: (conds?: Condition[]) => boolean): string[] { return this.getCandidateTargetIds(scene, evaluateCondition) .map(id => this.scenes[id]?.videoUrl) .filter((url): url is string => !!url) } }