import { Container } from 'pixi.js';
import { DialogueBox, type DialogueBoxOptions } from '@rpg/engine';
import { DIALOGUES } from '../data/dialogues';
/**
* Диалоговая система: держит активный диалог, поднимает флаги сюжета,
* листает реплики по клику/пробелу. Ничего не знает о рендере мира.
*/
export class DialogueSystem {
private box: DialogueBox;
private activeId: string | null = null;
private lineIndex = 0;
/** Флаги сюжета (сохраняются в сейве). */
readonly flags: Record<string, boolean> = {};
/** Сюжетное событие «диалог завершён» — для триггеров/квестов. */
onDialogueFinished: ((id: string) => void) | null = null;
constructor(uiRoot: Container, options: DialogueBoxOptions) {
this.box = new DialogueBox(options);
uiRoot.addChild(this.box.view);
}
get active(): boolean {
return this.activeId !== null;
}
start(dialogueId: string): void {
const dialogue = DIALOGUES[dialogueId];
if (!dialogue) throw new Error(`Нет диалога: ${dialogueId}`);
this.activeId = dialogueId;
this.lineIndex = 0;
this.box.show(dialogue.lines[0]);
}
/** Проклик/пробел: следующая реплика или закрытие. */
advance(): void {
if (!this.activeId) return;
const dialogue = DIALOGUES[this.activeId];
this.lineIndex++;
if (this.lineIndex < dialogue.lines.length) {
this.box.show(dialogue.lines[this.lineIndex]);
} else {
this.close();
}
}
private close(): void {
const id = this.activeId;
this.activeId = null;
this.box.hide();
this.onDialogueFinished?.(id!);
}
}