Add save/load/delete states

This commit is contained in:
aNNiMON 2024-03-14 00:00:55 +02:00
parent cc3e39c6b9
commit c574dd5b84
6 changed files with 132 additions and 22 deletions

10
src/runtime/SaveInfo.ts Normal file
View File

@ -0,0 +1,10 @@
import { NameInfoMap } from "../view/model/NameInfoMap";
export class SaveInfo {
public time: Date;
public position: number;
public variables: {[key: string]: any};
public characterNames: NameInfoMap;
public backgroundType: string;
public backgroundName: string;
}

View File

@ -1,7 +1,7 @@
import { VariablesHolder } from "./VariablesHolder";
export class Variables {
private static holder: VariablesHolder = new VariablesHolder();
private static readonly holder: VariablesHolder = new VariablesHolder();
public static getVariable(name: string): any {
return Variables.holder.getVariable(name);
@ -10,4 +10,12 @@ export class Variables {
public static setVariable(name: string, value: any): void {
Variables.holder.setVariable(name, value);
}
public static getVariables(): {[key: string]: any} {
return Variables.holder.getVariables();
}
public static setVariables(dump: {[key: string]: any}): void {
Variables.holder.setVariables(dump);
}
}

View File

@ -1,12 +1,7 @@
export class VariablesHolder {
private variables: object
private variables: {[key: string]: any};
constructor() {
this.variables = {};
}
public init(): void {
this.variables = {
"True": 1,
"False": 0
@ -23,4 +18,12 @@ export class VariablesHolder {
public setVariable(name: string, value: any): void {
this.variables[name] = value;
}
public getVariables(): {[key: string]: any} {
return this.variables;
}
public setVariables(dump: {[key: string]: any}): void {
this.variables = dump;
}
}

View File

@ -1,6 +1,8 @@
import { PathResolver } from "../utils/PathResolver";
import { TextUtils } from "../utils/TextUtils";
import { UIUtils } from "../utils/UIUtils";
import { SaveInfo } from "../runtime/SaveInfo";
import { Variables } from "../runtime/Variables";
import { Characters } from "./model/Characters";
import { FadeInfo } from "./model/FadeInfo";
import { MapPlaces } from "./model/MapPlaces";
@ -307,23 +309,101 @@ export class MainView implements ViewModel {
});
this.addMainMenuItem("Previous scene", () => this.navigable.prevScene());
this.addMainMenuItem("Next scene", () => this.navigable.nextScene());
// TODO
this.addMainMenuItem("Save", () => {
this.elMenu.style.display = 'none';
// this.saveState();
this.saveState();
});
const saves = JSON.parse(localStorage.saves || null) || {};
//saves[rpyscript] = saves[rpyscript] || [];
//if (saves[rpyscript].length > 0) {
// this.addMainMenuItem("Load…", () => this.showLoadStateMenu());
// this.addMainMenuItem("Delete…", () => this.showRemoveStateMenu());
//}
const saves = this.loadCurrentStatesList();
if (saves.length > 0) {
this.addMainMenuItem("Load…", () => this.showLoadStateMenu());
this.addMainMenuItem("Delete…", () => this.showRemoveStateMenu());
}
this.addMainMenuItem("Close", () => {
this.elMenu.style.display = 'none';
});
this.elMenu.style.display = 'block';
}
private showLoadStateMenu(): void {
document.getElementById('menuTitle').textContent = 'Load';
document.getElementById('menuChoose').innerHTML = '';
this.addMainMenuItem("Close", () => {
this.elMenu.style.display = 'none';
});
const saves = this.loadCurrentStatesList();
for (let i = saves.length - 1; i >= 0; i--) {
const save = saves[i];
this.addMainMenuItem(save.time.toLocaleString(), () => {
this.loadState(save);
this.elMenu.style.display = 'none';
});
}
this.elMenu.style.display = 'block';
}
private showRemoveStateMenu(): void {
document.getElementById('menuTitle').textContent = 'Delete';
document.getElementById('menuChoose').innerHTML = '';
this.addMainMenuItem("Close", () => {
this.elMenu.style.display = 'none';
});
const saves = this.loadCurrentStatesList();
for (let i = saves.length - 1; i >= 0; i--) {
this.addMainMenuItem(saves[i].time.toLocaleString(), () => {
this.deleteState(i);
this.showRemoveStateMenu();
});
}
this.elMenu.style.display = 'block';
}
private loadCurrentStatesList(): SaveInfo[] {
const rpyscript = window['rpyscript'] || 'default';
const saves = JSON.parse(window.localStorage.getItem('saves') || null) || {};
const items = saves[rpyscript] || [];
return items as SaveInfo[];
}
private saveState(): void {
this.modifyCurrentScenarioStates(items => items.push(this.createSave()))
}
private deleteState(i: number): void {
this.modifyCurrentScenarioStates(items => items.splice(i, 1))
}
private modifyCurrentScenarioStates(func: (items: SaveInfo[]) => void): void {
const rpyscript = window['rpyscript'] || 'default';
const saves = JSON.parse(window.localStorage.getItem('saves') || null) || {};
if (!(rpyscript in saves)) {
saves[rpyscript] = [];
}
func(saves[rpyscript] as SaveInfo[]);
window.localStorage.setItem('saves', JSON.stringify(saves));
}
private createSave(): SaveInfo {
const save = new SaveInfo();
save.position = this.navigable.getLastPosition();
save.time = new Date();
save.variables = Variables.getVariables();
save.characterNames = this.characters.getNames();
save.backgroundType = this.backgroundType;
save.backgroundName = this.backgroundName;
return save;
}
private loadState(save: SaveInfo): void {
Variables.setVariables(save.variables);
this.characters.setNames(save.characterNames);
if (!TextUtils.isEmpty(save.backgroundName)) {
this.background(save.backgroundType, save.backgroundName, "");
}
this.navigable.setPosition(save.position);
}
private addMainMenuItem(name: string, func: () => void) {
const li = document.createElement('li');
li.textContent = name;
@ -382,7 +462,6 @@ export class MainView implements ViewModel {
public music(name: string, fade: FadeInfo): void {
try {
console.log("Music: " + name, this.pathResolver.music(name));
this.stopMusic(this.musicPlayerAudio.fade);
this.musicPlayerAudio.src = this.pathResolver.music(name);
this.musicPlayerAudio.fade = fade;
@ -589,9 +668,9 @@ export class MainView implements ViewModel {
this.stopSoundLoop(FadeInfo.NO_FADE);
this.stopAmbience(FadeInfo.NO_FADE);
this.spritesClear();
this.text('{center}{html}<span style="color: white">Сценарий завершён</span>');
this.text('{center}{html}<span style="color: white">Scenario completed</span>');
} else {
this.text('{center}{html}<a style="color: white" href="/">Вернуться на главную</a>');
this.text('{center}{html}<a style="color: white" href="/">Back to main page</a>');
}
}

View File

@ -1,8 +1,5 @@
import { NameInfo } from "./NameInfo";
type NameInfoMap = {
[key: string]: NameInfo;
};
import { NameInfoMap } from "./NameInfoMap";
export class Characters {
private static readonly DEFAULT_COLOR: number = 0xFFC0C0C0;
@ -34,6 +31,14 @@ export class Characters {
return shortName in this.names;
}
public getNames(): NameInfoMap {
return this.names;
}
public setNames(dump: NameInfoMap): void {
this.names = dump;
}
public makeNamesUnknown(): void { }
public makeNamesKnown(): void { }

View File

@ -0,0 +1,5 @@
import { NameInfo } from "./NameInfo";
export type NameInfoMap = {
[key: string]: NameInfo;
};