/**
* Состояние игры: флаги сюжета и именованные переменные.
* Жанронезависимо: движок знает только механику, контент (какие флаги есть)
* определяется игрой. Сериализуется в/из сейва вместе с позицией и прочим.
*/
export interface GameStateData {
version: number;
flags: string[];
vars: Record<string, number | string | boolean>;
}
export type GameStateMigration = (data: GameStateData) => GameStateData;
export class GameState {
private flags = new Set<string>();
private vars = new Map<string, number | string | boolean>();
private migrations: GameStateMigration[] = [];
/** Текущая версия формата данных (растёт при изменениях структуры сейва). */
dataVersion = 1;
/**
* Зарегистрировать миграцию: применяется к сейвам с dataVersion меньше
* текущей. Миграции регистрируются по порядку от старых версий к новым.
*/
addMigration(m: GameStateMigration): void {
this.migrations.push(m);
}
// --- флаги ---
setFlag(flag: string): void {
this.flags.add(flag);
}
hasFlag(flag: string): boolean {
return this.flags.has(flag);
}
clearFlag(flag: string): void {
this.flags.delete(flag);
}
/** Все флаги (для отладки). */
get allFlags(): string[] {
return [...this.flags];
}
// --- переменные ---
setVar(key: string, value: number | string | boolean): void {
this.vars.set(key, value);
}
getVar(key: string): number | string | boolean | undefined {
return this.vars.get(key);
}
getNumber(key: string): number {
const v = this.vars.get(key);
return typeof v === 'number' ? v : 0;
}
getString(key: string): string {
const v = this.vars.get(key);
return typeof v === 'string' ? v : '';
}
getBool(key: string): boolean {
const v = this.vars.get(key);
return v === true || typeof v === 'number' && v !== 0;
}
// --- сериализация ---
serialize(): GameStateData {
return {
version: this.dataVersion,
flags: [...this.flags],
vars: Object.fromEntries(this.vars)
};
}
/** Загрузить данные (с применением миграций). Восстанавливает состояние поверх текущего. */
load(data: GameStateData): void {
let d = data;
for (const m of this.migrations) {
if (d.version < this.dataVersion) {
d = m(d);
}
}
this.dataVersion = d.version;
this.flags = new Set(d.flags);
this.vars = new Map(Object.entries(d.vars));
}
/** Сбросить всё (новая игра). */
reset(): void {
this.flags.clear();
this.vars.clear();
}
}