diff options
Diffstat (limited to 'resources/js')
-rw-r--r-- | resources/js/classes/State.js | 4 | ||||
-rw-r--r-- | resources/js/game.js | 20 | ||||
-rw-r--r-- | resources/js/main.js | 88 | ||||
-rw-r--r-- | resources/js/memory.js | 48 | ||||
-rw-r--r-- | resources/js/ui.js | 24 |
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() ); |