import {
Container,
DialogueBox,
DialogueRunner,
GameState,
type DialogueBoxOptions,
type DialogueGraph
} from '@rpg/engine';
/**
* Диалоги игры: DialogueRunner движка ходит по графам и применяет флаги
* к GameState, DialogueBox рисует реплики и варианты.
*/
export class DialogueSystem {
private box: DialogueBox;
private runner: DialogueRunner;
/** Сюжетное событие «диалог завершён» — для триггеров/квестов. */
onDialogueFinished: ((id: string) => void) | null = null;
/** id стартованного диалога (для onFinish). */
private currentId: string | null = null;
constructor(uiRoot: Container, state: GameState, options: DialogueBoxOptions) {
this.box = new DialogueBox({
...options,
onChoice: (index) => this.runner.pick(index)
});
uiRoot.addChild(this.box.view);
this.runner = new DialogueRunner(state);
this.runner.setView({
show: ({ speaker, text, choices }) => this.box.show({ speaker, text, choices }),
hide: () => this.box.hide()
});
}
get active(): boolean {
return this.runner.active;
}
/** Начать диалог по ключу из data/dialogues.ts. */
start(graph: DialogueGraph, id: string): void {
this.currentId = id;
this.runner.onFinish = () => {
const id = this.currentId;
this.currentId = null;
if (id) this.onDialogueFinished?.(id);
};
this.runner.start(graph);
}
/** Клик/пробел: следующая реплика (во время выбора игнорируется). */
advance(): void {
this.runner.advance();
}
}