diff options
Diffstat (limited to 'resources')
| -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()        ); | 
