const Story = { async start () { const settingsPopup = UI.createPopup(); settingsPopup.querySelector('[data-template-slot="content"]').append(UI.createSettingsMenu()); UI.drawPopup(settingsPopup); await new Promise((resolve) => { settingsPopup.addEventListener('close', UI.wrapCallback(async () => { resolve(); })); }); await Story.immediateProgress('start', 'introduction'); }, async introduction () { const story = await fetchStory('introduction'); const characterCeo = story.characters.ceo; const characterShopKeeper = story.characters.shopKeeper; const npcCeo = await fetchNpc(characterCeo.slug); const npcShopKeeper = await fetchNpc(characterShopKeeper.slug); await UI.buildAndShowStoryPopup({ speaker: npcCeo, text: translate(characterCeo.text[0], true) }); await UI.buildAndShowStoryPopup({ speaker: npcCeo, text: translate(characterCeo.text[1], true) }); await UI.buildAndShowStoryPopup({ speaker: npcShopKeeper, text: translate(characterShopKeeper.text[0], true) }); const possibleStarterMonsters = await Promise.all( story.monsters.map(async (monsterData) => { const monster = await fetchMonster(monsterData.slug); monster.level = monsterData.level; return monster; }) ); const monsterSelection = UI.openStarterMonsterSelection(possibleStarterMonsters, { title: translate('story:introduction:monster_selection:title', true) }); await new Promise((resolve) => { monsterSelection.addEventListener('starter:monster:selected', UI.wrapCallback(async (event) => { if (!confirm(`Select ${event.detail.monster.name}?`)) { return; } event.detail.popup.remove(); await UI.buildAndShowStoryPopup({ speaker: npcShopKeeper, text: translate(characterShopKeeper.text[1], true) }); // set rival monster Memory.state.rivalMonster = event.detail.monster.slug; // set initial values Memory.state.money = story.money; // go to starting area await Game.goToArea(story.area); resolve(); })); }); }, async selectStarterMonster () { const story = await fetchStory('select-starter-monster'); const characterDante = story.characters.dante; const npcDante = await fetchNpc(characterDante.slug); await UI.buildAndShowStoryPopup({ speaker: npcDante, text: translate(characterDante.text[0], true) }); await UI.buildAndShowStoryPopup({ speaker: npcDante, text: translate(characterDante.text[1], true) }); await UI.buildAndShowStoryPopup({ speaker: npcDante, text: translate(characterDante.text[2], true) }); const possibleStarterMonsters = await Promise.all( story.monsters.map(async (monsterData) => { const monster = await fetchMonster(monsterData.slug); monster.level = monsterData.level; return monster; }) ); const monsterSelection = UI.openStarterMonsterSelection(possibleStarterMonsters, { title: translate('story:select_starter_monster:monster_selection:title', true) }); await new Promise((resolve) => { monsterSelection.addEventListener('starter:monster:selected', UI.wrapCallback(async (event) => { if (!confirm(`Select ${event.detail.monster.name}?`)) { return; } Memory.state.player.monsters.push(event.detail.monster); Game.setActivePlayerMonster(event.detail.monster); UI.drawActiveMonster(); UI.drawActiveTechniques(); event.detail.popup.remove(); resolve(); })); }); await Story.immediateProgress('selectStarterMonster', 'battleRivalOne'); }, async battleRivalOne () { const story = await fetchStory('battle-rival-one'); const characterRival = story.characters.rival; const npcRival = await fetchNpc(story.characters.rival.slug); Memory.state.opponent = new Trainer({ monsters: await Promise.all( characterRival.monsters.map(async (monsterData) => { if (monsterData.slug === 'RIVAL') { monsterData.slug = Memory.state.rivalMonster; } const monster = await fetchMonster(monsterData.slug); monster.level = monsterData.level; return monster; }) ) }); await Memory.state.opponent.initialize(); await UI.buildAndShowStoryPopup({ speaker: npcRival, text: translate(characterRival.text[0], true) }); await Story.battle(); if (Game.didWinStoryBattle) { await UI.buildAndShowStoryPopup({ speaker: npcRival, text: translate(characterRival.text[1], true) }); } else { await UI.buildAndShowStoryPopup({ speaker: npcRival, text: translate(characterRival.text[2], true) }); } await UI.buildAndShowStoryPopup({ speaker: npcRival, text: translate(characterRival.text[3], true) }); Game.healParty(); }, // Helper /** * @param {StorySlug} slug */ async progress (slug) { if (!Story[slug]) { return; } Memory.state.currentStory = slug; Memory.saveToLocalStorage(); await Story[slug](); Memory.state.storyProgress[slug] = true; Memory.state.currentStory = null; Memory.saveToLocalStorage(); }, /** * @param {StorySlug} fromSlug * @param {StorySlug} toSlug */ async immediateProgress (fromSlug, toSlug) { Memory.state.storyProgress[fromSlug] = true; Memory.saveToLocalStorage(); await Story.progress(toSlug); }, async battle () { const previousArea = Object.assign({}, Memory.state.currentArea); Game.isStoryBattle = true; Memory.state.Game.isInBattle = true; Memory.saveToLocalStorage(); UI.drawBattle(); UI.showBattle(); await new Promise((resolve) => { const interval = setInterval(() => { if (!Game.isStoryBattle) { clearInterval(interval); resolve(); } }, 100); }); // reset incremented trainer progress if (Memory.state.areaProgress[previousArea.slug]) { Memory.state.areaProgress[previousArea.slug].trainerProgress = previousArea.trainerProgress; } if (previousArea.slug === Memory.state.currentArea.slug) { Memory.state.currentArea.trainerProgress = previousArea.trainerProgress; UI.drawStatus(); } }, };