summaryrefslogtreecommitdiff
path: root/resources/js
diff options
context:
space:
mode:
Diffstat (limited to 'resources/js')
-rw-r--r--resources/js/classes/State.js4
-rw-r--r--resources/js/game.js20
-rw-r--r--resources/js/main.js88
-rw-r--r--resources/js/memory.js48
-rw-r--r--resources/js/ui.js24
5 files changed, 131 insertions, 53 deletions
diff --git a/resources/js/classes/State.js b/resources/js/classes/State.js
index 1a65efe..417c685 100644
--- a/resources/js/classes/State.js
+++ b/resources/js/classes/State.js
@@ -15,6 +15,10 @@ class State {
logMaxLength: 1000,
};
+ Game = {
+ isInBattle: false,
+ };
+
/**
* @type {Object.<string, Area>}
*/
diff --git a/resources/js/game.js b/resources/js/game.js
index 0ba5a8d..b628553 100644
--- a/resources/js/game.js
+++ b/resources/js/game.js
@@ -27,7 +27,6 @@ const Game = {
playerIsChoosingNextMonster: false,
doBattleAnimation: true,
opponentActionTimeout: null,
- isInBattle: false,
didTechniqueHit: false,
/* Battle */
@@ -110,7 +109,7 @@ const Game = {
await Game.evolveMonster(Memory.state.player.activeMonster);
}
- Game.isInBattle = false;
+ Memory.state.Game.isInBattle = false;
if (Memory.state.opponent.type === 'monster') {
Memory.state.currentArea.monsterProgress++;
@@ -128,6 +127,8 @@ const Game = {
await Game.encounterNextTrainerMonster();
}
}
+
+ Memory.saveToLocalStorage();
}
},
@@ -144,7 +145,7 @@ const Game = {
// whole party defeated
if (!Memory.state.player.monsters.some((monster) => monster.hp > 0)) {
- Game.isInBattle = false;
+ Memory.state.Game.isInBattle = false;
Memory.state.currentArea.monsterProgress = 0;
// go to last visited town
@@ -167,12 +168,15 @@ const Game = {
Game.log(`Whited out!`);
Game.log(`Payed ${formatPrice(totalHealingCenterPrice)} for full recovery at ${Memory.state.currentArea.name}!`);
});
+
+ Memory.saveToLocalStorage();
}
// party members still left
else {
Game.playerIsChoosingNextMonster = true;
const monsterSelectionNode = UI.createPlayerDefeatedMonsterSelection();
+ monsterSelectionNode.addEventListener('monster:selected', UI.createEventListener(() => Memory.saveToLocalStorage()));
UI.openPlayerDefeatedMonsterSelection(monsterSelectionNode);
}
}
@@ -602,7 +606,7 @@ const Game = {
return;
}
- Game.isInBattle = true;
+ Memory.state.Game.isInBattle = true;
UI.battleClickEvent = event;
// player
@@ -746,6 +750,7 @@ const Game = {
UI.drawArea();
+ Memory.saveToLocalStorage();
Game.isLoadingArea = false;
},
@@ -833,6 +838,8 @@ const Game = {
}
}
}
+
+ Memory.saveToLocalStorage();
},
/**
@@ -882,6 +889,9 @@ const Game = {
Game.log(`Escape attempt ${attempts}: succeeded!`);
Game.log(`${opposingMonster.name} broke free!`);
+ Memory.state.Game.isInBattle = true;
+ UI.drawStatus();
+
Game.opponentTryUseTechnique();
return; // can't catch
}
@@ -903,6 +913,8 @@ const Game = {
Game.log(`Caught ${caughtMonster.name}!`);
await Game.encounterWildMonster();
+
+ Memory.saveToLocalStorage();
},
diff --git a/resources/js/main.js b/resources/js/main.js
index aa86423..662dff6 100644
--- a/resources/js/main.js
+++ b/resources/js/main.js
@@ -1,39 +1,57 @@
UI.createEventListener(async function () {
await initializeDB();
- // Start Game
- const possibleStarterMonsters = ['budaye', 'dollfin', 'grintot', 'ignibus', 'memnomnom'];
-
- const monsterSelection = UI.openStarterMonsterSelection(
- await Promise.all(possibleStarterMonsters.map(async (monsterSlug) => await fetchMonster(monsterSlug)))
- );
- monsterSelection.addEventListener('starter:monster:selected', UI.createEventListener(async (event) => {
- if (!confirm(`Select ${event.detail.monster.name}?`)) {
- return;
- }
-
- Memory.state.player = new Trainer({
- monsters: [
- event.detail.monster,
- ],
- inventory: [
- new InventoryItem(await fetchItem('tuxeball'), 5),
- new InventoryItem(await fetchItem('potion')),
- ]
- });
- await Memory.state.player.initialize();
-
- Game.setActivePlayerMonster(Memory.state.player.monsters[0]);
- Memory.state.activeBall = Memory.state.player.inventory[0]; // tuxeball
-
- possibleStarterMonsters.splice(possibleStarterMonsters.indexOf(event.detail.monster), 1);
- Memory.state.rivalMonster = possibleStarterMonsters[Math.round(Math.random() * (possibleStarterMonsters.length - 1))];
-
- await Game.goToArea('paper-town');
-
- UI.drawActiveMonster();
- UI.drawActiveTechniques();
-
- event.detail.popup.remove();
- }));
+ // Load existing state
+ if (localStorage.getItem('state')) {
+ Memory.loadFromLocalStorage();
+ }
+
+ // Start New Game
+ else {
+ const possibleStarterMonsters = await Promise.all(
+ [
+ 'budaye',
+ 'dollfin',
+ 'grintot',
+ 'ignibus',
+ 'memnomnom',
+ ].map(async (monsterSlug) => await fetchMonster(monsterSlug))
+ );
+
+ const monsterSelection = UI.openStarterMonsterSelection(possibleStarterMonsters);
+ monsterSelection.addEventListener('starter:monster:selected', UI.createEventListener(async (event) => {
+ if (!confirm(`Select ${event.detail.monster.name}?`)) {
+ return;
+ }
+
+ Memory.state.player = new Trainer({
+ monsters: [
+ event.detail.monster,
+ ],
+ inventory: [
+ new InventoryItem(await fetchItem('tuxeball'), 5),
+ new InventoryItem(await fetchItem('potion')),
+ ]
+ });
+ await Memory.state.player.initialize();
+
+ Game.setActivePlayerMonster(Memory.state.player.monsters[0]);
+ Memory.state.activeBall = Memory.state.player.inventory[0]; // tuxeball
+
+ // set rival monster
+ possibleStarterMonsters.splice(possibleStarterMonsters.indexOf(event.detail.monster), 1);
+ const rivalMonster = possibleStarterMonsters[Math.round(Math.random() * (possibleStarterMonsters.length - 1))];
+ Memory.state.opponent = new Trainer({ monsters: [ rivalMonster ] });
+ await Memory.state.opponent.initialize();
+ Memory.state.rivalMonster = rivalMonster.slug
+
+ // go to starting area
+ await Game.goToArea('paper-town');
+
+ UI.drawActiveMonster();
+ UI.drawActiveTechniques();
+
+ event.detail.popup.remove();
+ }));
+ }
})();
diff --git a/resources/js/memory.js b/resources/js/memory.js
index 6023e49..35da905 100644
--- a/resources/js/memory.js
+++ b/resources/js/memory.js
@@ -6,9 +6,9 @@ const Memory = {
/**
- * @returns {string}
+ * @returns {(Object|State)}
*/
- save () {
+ saveToObject () {
const prepareSaveData = (saveData) => {
const prepareMonster = (monster) => {
if (monster.statusEffect && monster.statusEffect.slug === 'lifeleech') {
@@ -62,14 +62,25 @@ const Memory = {
saveData.opponent.activeMonsterIdx = Memory.state.opponent.monsters.indexOf(Memory.state.opponent.activeMonster);
+ return saveData;
+ },
+
+ /**
+ * @returns {string}
+ */
+ saveToString () {
// hash
- return btoa(JSON.stringify(saveData));
+ return btoa(JSON.stringify(Memory.saveToObject()));
+ },
+
+ saveToLocalStorage () {
+ localStorage.setItem('state', Memory.saveToString());
},
/**
- * @param {string} saveData
+ * @param {(Object|State)} saveData
*/
- async load (saveData) {
+ async loadFromObject (saveData) {
/**
* @param {Area} areaData
*/
@@ -169,7 +180,7 @@ const Memory = {
/**
* @type {State}
*/
- const loadedState = JSON.parse(atob(saveData));
+ const loadedState = saveData;
Memory.state.Settings.language = loadedState.Settings.language;
await fetchTranslation(Memory.state.Settings.language);
@@ -177,6 +188,10 @@ const Memory = {
Memory.state.Settings.currency = loadedState.Settings.currency;
Memory.state.Settings.logMaxLength = loadedState.Settings.logMaxLength;
+ if (loadedState.Game) { // backwards compat: TODO: remove check later
+ Memory.state.Game.isInBattle = loadedState.Game.isInBattle;
+ }
+
for (const areaSlug of Object.keys(loadedState.areaProgress)) {
const areaData = loadedState.areaProgress[areaSlug];
Memory.state.areaProgress[areaSlug] = await loadArea(areaData);
@@ -199,10 +214,25 @@ const Memory = {
Memory.state.activeTechnique = await loadTechnique(loadedState.activeTechnique);
Memory.state.activeBall = await loadInventoryItem(loadedState.activeBall);
+ // draw game
+ if (!Game.isTown(Memory.state.currentArea)) {
+ UI.drawOpponentMonster();
+ UI.drawActiveMonster();
+ UI.drawActiveTechniques();
+ }
UI.drawArea();
UI.drawStatus();
- UI.drawOpponentMonster();
- UI.drawActiveMonster();
- UI.drawActiveTechniques();
+ UI.closeAllPopups();
+ },
+
+ /**
+ * @param {string} saveData
+ */
+ loadFromString (saveData) {
+ Memory.loadFromObject(JSON.parse(atob(saveData)));
+ },
+
+ loadFromLocalStorage () {
+ Memory.loadFromString(localStorage.getItem('state'));
},
};
diff --git a/resources/js/ui.js b/resources/js/ui.js
index 7c0c064..006e6fc 100644
--- a/resources/js/ui.js
+++ b/resources/js/ui.js
@@ -188,6 +188,10 @@ const UI = {
document.body.appendChild(popup);
},
+ closeAllPopups () {
+ document.querySelectorAll('.popup__overlay').forEach((popup) => popup.remove());
+ },
+
/* Battle */
@@ -927,7 +931,7 @@ const UI = {
Memory.state.opponent.type === 'monster' &&
currentArea.monsterProgress >= currentArea.requiredEncounters &&
currentArea.trainerProgress < currentArea.trainers.length &&
- !Game.isInBattle
+ !Memory.state.Game.isInBattle
) {
nextTrainerButton.disabled = false;
} else {
@@ -940,7 +944,7 @@ const UI = {
const changeAreaButton = UI.elements.changeArea;
if (!Game.isTown(currentArea)) {
if (
- Game.isInBattle ||
+ Memory.state.Game.isInBattle ||
(Memory.state.opponent && Memory.state.opponent.type === 'trainer')
) {
changeAreaButton.disabled = true;
@@ -991,7 +995,7 @@ const UI = {
},
openMap () {
- if (Game.isInBattle || Game.isTown(Memory.state.currentArea)) {
+ if (Memory.state.Game.isInBattle || Game.isTown(Memory.state.currentArea)) {
return;
}
@@ -1353,6 +1357,16 @@ const UI = {
});
+ // Clear save data
+
+ template.querySelector('[data-template-slot="clearLocalSaveData"]').addEventListener('click', UI.createEventListener(() => {
+ if (confirm(translate('ui:settings:clear_local_save_data:confirm', true))) {
+ localStorage.removeItem('state');
+ window.location.reload();
+ }
+ }));
+
+
popup.querySelector('.popup').appendChild(template);
UI.drawPopup(popup);
},
@@ -1639,7 +1653,7 @@ const UI = {
const popup = UI.createPopup();
const dialog = UI.createTemplate(Template.dialogSave);
- const saveData = Memory.save();
+ const saveData = Memory.saveToString();
dialog.querySelector('[data-template-slot="saveData"]').value = saveData;
dialog.querySelector('[data-template-slot="saveClipboard"]').addEventListener('click', UI.createEventListener(async () => {
@@ -1660,7 +1674,7 @@ const UI = {
const dialog = UI.createTemplate(Template.dialogLoad);
dialog.querySelector('[data-template-slot="load"]').addEventListener('click', UI.createEventListener(() => {
- Memory.load(
+ Memory.loadFromString(
dialog.querySelector('[data-template-slot="saveData"]').value.trim()
);