Newer
Older
rpg / v2 / apps / game / src / state.ts
/**
 * Состояние игры «Пепельных луга»: флаги сюжета и числовые вары.
 * Реализует DialogueState движка (диалоги и квест-стадии пишут прямо сюда);
 * данные сериализуемы (toData/fromData) — автосейв подхватит в треке сейвов.
 * Ключи — только из реестров data/ids.ts.
 */
import type { DialogueState } from '@rpg/engine';

export type VarValue = number | string | boolean;

/** Данные для сейва: какие флаги подняты + значения варов. */
export interface GameStateData {
    flags: string[];
    vars: Record<string, VarValue>;
}

export class GameState implements DialogueState {
    private readonly flags = new Set<string>();
    private readonly vars = new Map<string, VarValue>();

    hasFlag(flag: string): boolean {
        return this.flags.has(flag);
    }

    setFlag(flag: string): void {
        this.flags.add(flag);
    }

    clearFlag(flag: string): void {
        this.flags.delete(flag);
    }

    getVar(key: string): VarValue | undefined {
        return this.vars.get(key);
    }

    setVar(key: string, value: VarValue): void {
        this.vars.set(key, value);
    }

    /** Числовой вар (для прогресса N/M); нет/не число — 0. */
    getNumber(key: string): number {
        const v = this.vars.get(key);
        return typeof v === 'number' ? v : 0;
    }

    toData(): GameStateData {
        return { flags: [...this.flags], vars: Object.fromEntries(this.vars) };
    }

    /** Заменить состояние (загрузка сейва); пусто — новая игра. */
    fromData(data: GameStateData | null): void {
        this.flags.clear();
        this.vars.clear();
        if (!data) return;
        for (const f of data.flags) this.flags.add(f);
        for (const [k, v] of Object.entries(data.vars)) this.vars.set(k, v);
    }
}