diff --git a/src/runtime/SaveInfo.ts b/src/runtime/SaveInfo.ts
new file mode 100644
index 0000000..9451ee5
--- /dev/null
+++ b/src/runtime/SaveInfo.ts
@@ -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;
+}
\ No newline at end of file
diff --git a/src/runtime/Variables.ts b/src/runtime/Variables.ts
index 7bb2ab9..0e76a4a 100644
--- a/src/runtime/Variables.ts
+++ b/src/runtime/Variables.ts
@@ -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);
+ }
}
\ No newline at end of file
diff --git a/src/runtime/VariablesHolder.ts b/src/runtime/VariablesHolder.ts
index b9fb3a7..c05018c 100644
--- a/src/runtime/VariablesHolder.ts
+++ b/src/runtime/VariablesHolder.ts
@@ -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;
+ }
}
\ No newline at end of file
diff --git a/src/view/MainView.ts b/src/view/MainView.ts
index f521382..3b978db 100644
--- a/src/view/MainView.ts
+++ b/src/view/MainView.ts
@@ -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}Сценарий завершён');
+ this.text('{center}{html}Scenario completed');
} else {
- this.text('{center}{html}Вернуться на главную');
+ this.text('{center}{html}Back to main page');
}
}
diff --git a/src/view/model/Characters.ts b/src/view/model/Characters.ts
index 2cf4b23..e47c5f6 100644
--- a/src/view/model/Characters.ts
+++ b/src/view/model/Characters.ts
@@ -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 { }
diff --git a/src/view/model/NameInfoMap.ts b/src/view/model/NameInfoMap.ts
new file mode 100644
index 0000000..eefaadb
--- /dev/null
+++ b/src/view/model/NameInfoMap.ts
@@ -0,0 +1,5 @@
+import { NameInfo } from "./NameInfo";
+
+export type NameInfoMap = {
+ [key: string]: NameInfo;
+};
\ No newline at end of file