From dbcd0118863ff3e7c5bee45041ccdb757eb2f366 Mon Sep 17 00:00:00 2001 From: Daniel Weipert Date: Tue, 22 Aug 2023 16:37:33 +0200 Subject: areas and town/shop setup --- resources/css/page.css | 4 +++ resources/css/town.css | 3 ++ resources/js/classes/Area.js | 8 ++--- resources/js/classes/State.js | 4 +-- resources/js/db.js | 5 +++- resources/js/game.js | 68 ++++++++++++++++++++++++++----------------- resources/js/main.js | 7 ++--- resources/js/ui.js | 65 ++++++++++++++++++++++++++++++++--------- 8 files changed, 111 insertions(+), 53 deletions(-) create mode 100644 resources/css/town.css (limited to 'resources') diff --git a/resources/css/page.css b/resources/css/page.css index 813b361..57c46a5 100644 --- a/resources/css/page.css +++ b/resources/css/page.css @@ -23,3 +23,7 @@ img { width: 100vw; height: 100vh; } + +.hidden { + display: none; +} diff --git a/resources/css/town.css b/resources/css/town.css new file mode 100644 index 0000000..4dd8195 --- /dev/null +++ b/resources/css/town.css @@ -0,0 +1,3 @@ +#scene__town { + background-color: #fff; +} diff --git a/resources/js/classes/Area.js b/resources/js/classes/Area.js index 3451757..b2af3ea 100644 --- a/resources/js/classes/Area.js +++ b/resources/js/classes/Area.js @@ -27,11 +27,11 @@ class Area { return DB.areas[this.slug].environment; } - get previousArea () { - return DB.areas[this.slug].previousArea; + get events () { + return DB.areas[this.slug].events; } - get nextArea () { - return DB.areas[this.slug].nextArea; + get connections () { + return DB.areas[this.slug].connections; } } diff --git a/resources/js/classes/State.js b/resources/js/classes/State.js index 9a72a8f..085d1c7 100644 --- a/resources/js/classes/State.js +++ b/resources/js/classes/State.js @@ -51,9 +51,9 @@ class State { opponent = null; /** - * @type {Monster} + * @type {MonsterSlug} */ - rivalMonster = null; + rivalMonster = ''; /** * @type {Technique} diff --git a/resources/js/db.js b/resources/js/db.js index ede65aa..f5cff6c 100644 --- a/resources/js/db.js +++ b/resources/js/db.js @@ -165,12 +165,15 @@ async function fetchTranslation (locale) { * @returns {Promise} */ async function fetchArea (slug) { + if (Memory.state.areaProgress[slug]) { + return Memory.state.areaProgress[slug]; + } + if (! DB.areas[slug]) { DB.areas[slug] = await fetch(`/db/_generated/areas/${slug}.json`).then((response) => response.json()); } const area = new Area(slug); - return area; } diff --git a/resources/js/game.js b/resources/js/game.js index 5a31c39..7b40015 100644 --- a/resources/js/game.js +++ b/resources/js/game.js @@ -114,7 +114,7 @@ const Game = { if (Memory.state.currentArea.encounters.length > 0) { await Game.encounterWildMonster(); } else { - await Game.progressToNextArea(); + await Game.encounterTrainer(); } } else { await Game.encounterNextTrainerMonster(); @@ -662,12 +662,21 @@ const Game = { async encounterTrainer () { Game.clearCurrentTurn(); - const nextTrainer = Memory.state.currentArea.trainers[Memory.state.currentArea.trainerProgress]; + let nextTrainerIdx = Memory.state.currentArea.trainerProgress; + while (nextTrainerIdx > Memory.state.currentArea.trainers.length - 1) { + nextTrainerIdx -= Memory.state.currentArea.trainers.length; + } - const trainer = new Trainer(nextTrainer); + const nextTrainer = Memory.state.currentArea.trainers[nextTrainerIdx]; if (nextTrainer.name === 'Rival') { - trainer.monsters.push(Memory.state.rivalMonster); + for (const idx in nextTrainer.monsters) { + if (nextTrainer.monsters[idx].slug === 'STARTER') { + nextTrainer.monsters[idx].slug = Memory.state.rivalMonster; + } + } } + + const trainer = new Trainer(nextTrainer); await trainer.initialize() Memory.state.opponent = trainer; @@ -682,40 +691,39 @@ const Game = { UI.drawOpponentMonster(); }, - async progressToNextArea () { + /** + * @param {string} areaSlug + */ + async goToArea (areaSlug) { Game.isLoadingArea = true; Game.clearCurrentTurn(); - const currentArea = Memory.state.currentArea; - const nextArea = await fetchArea(currentArea.nextArea); + if (Memory.state.currentArea) { + Memory.state.areaProgress[Memory.state.currentArea.slug] = Memory.state.currentArea; + } - await Game.jumpToArea(nextArea); + Memory.state.currentArea = await fetchArea(areaSlug); + UI.drawArea(); - if (nextArea.encounters.length > 0) { - await Game.encounterWildMonster(); + if (Game.isTown(Memory.state.currentArea)) { + UI.elements.sceneBattle.classList.add('hidden'); + UI.elements.sceneTown.classList.remove('hidden'); } else { - await Game.encounterTrainer(); + UI.elements.sceneTown.classList.add('hidden'); + UI.elements.sceneBattle.classList.remove('hidden'); + if (Memory.state.currentArea.encounters.length > 0) { + await Game.encounterWildMonster(); + } else if (Memory.state.currentArea.trainers.length > 0) { + await Game.encounterTrainer(); + } } UI.drawStatus(); + UI.drawActiveBall(); Game.isLoadingArea = false; }, - /** - * @param {Area} area - */ - async jumpToArea (area) { - Game.clearCurrentTurn(); - - if (Memory.state.currentArea) { - Memory.state.areaProgress[Memory.state.currentArea.slug] = Memory.state.currentArea; - } - Memory.state.currentArea = area; - - UI.drawArea(area); - }, - /* Menu - Inventory */ @@ -806,7 +814,7 @@ const Game = { * @returns {boolean} */ canCatchMonster () { - return Game.isBattleType('monster') && Memory.state.activeBall; + return !Game.isTown(Memory.state.currentArea) && Game.isBattleType('monster') && Memory.state.activeBall; }, async catchMonster () { @@ -866,6 +874,13 @@ const Game = { return Memory.state.opponent.type === type; }, + /** + * @param {Area} area + */ + isTown (area) { + return area.encounters.length === 0 && area.trainers.length === 0; + }, + getStageOfDaySimple () { const hours = (new Date()).getHours(); if (hours >= 6 && hours < 18) { @@ -878,7 +893,6 @@ const Game = { // Game click bindings UI.elements.nextTrainer.addEventListener('click', Game.encounterTrainer); -UI.elements.nextArea.addEventListener('click', Game.progressToNextArea); UI.elements.battleOpponent.addEventListener('click', Game.battleClick); UI.elements.techniques.addEventListener('click', Game.techniqueClick); UI.elements.menuCatch.addEventListener('click', Game.catchMonster); diff --git a/resources/js/main.js b/resources/js/main.js index 4fd9c62..24eafec 100644 --- a/resources/js/main.js +++ b/resources/js/main.js @@ -18,12 +18,9 @@ Game.setActivePlayerMonster(Memory.state.player.monsters[0]); Memory.state.activeBall = Memory.state.player.inventory[0]; // tuxeball - Memory.state.rivalMonster = await fetchMonster(possibleStarterMonsters[Math.round(Math.random() * (possibleStarterMonsters.length - 1))]); + Memory.state.rivalMonster = possibleStarterMonsters[Math.round(Math.random() * (possibleStarterMonsters.length - 1))]; - const area = await fetchArea('paper-town'); - await Game.jumpToArea(area); - await Game.encounterTrainer(); - UI.drawStatus(); + await Game.goToArea('paper-town'); UI.drawActiveMonster(); UI.drawActiveTechniques(); diff --git a/resources/js/ui.js b/resources/js/ui.js index 92ca313..a40550b 100644 --- a/resources/js/ui.js +++ b/resources/js/ui.js @@ -34,6 +34,9 @@ const Template = { const UI = { elements: { + sceneBattle: document.querySelector('#scene__battle'), + sceneTown: document.querySelector('#scene__town'), + battle: document.querySelector('#battle'), battleOpponent: document.querySelector('#battle__opponent'), battleOpponentSprite: null, @@ -46,7 +49,7 @@ const UI = { status: document.querySelector('#status'), nextTrainer: document.querySelector('#status [data-template-slot="nextTrainer"]'), - nextArea: document.querySelector('#status [data-template-slot="nextArea"]'), + changeArea: document.querySelector('#status [data-template-slot="changeArea"]'), menuParty: document.querySelector('#menu__party'), menuInventory: document.querySelector('#menu__inventory'), @@ -489,11 +492,8 @@ const UI = { UI.elements.log.classList.toggle('log--is-hidden'); }, - /** - * @param {Area} area - */ - drawArea (area) { - UI.elements.battle.style.backgroundImage = `url(/modules/tuxemon/mods/tuxemon/gfx/ui/combat/${area.environment.battle_graphics.background})`; + drawArea () { + UI.elements.battle.style.backgroundImage = `url(/modules/tuxemon/mods/tuxemon/gfx/ui/combat/${Memory.state.currentArea.environment.battle_graphics.background})`; }, progressTurn () { @@ -701,16 +701,52 @@ const UI = { } else { nextTrainerButton.disabled = true; } + }, - const nextAreaButton = UI.elements.nextArea; - if ( - currentArea.monsterProgress >= currentArea.requiredEncounters && - currentArea.trainerProgress === currentArea.trainers.length - ) { - nextAreaButton.disabled = false; - } else { - nextAreaButton.disabled = true; + openAreaSelection () { + const popup = UI.createPopup(); + const template = document.createElement('div'); + const currentArea = Memory.state.currentArea; + + for (const connectionSlug in currentArea.connections) { + const connection = currentArea.connections[connectionSlug]; + const connectionNode = document.createElement('div'); + + connectionNode.textContent = slugToName(connectionSlug); + + let canGo = true; + for (const condition of connection.conditions) { + if (condition === 'encounters') { + canGo = canGo && currentArea.monsterProgress >= currentArea.requiredEncounters; + } + + else if (condition === 'trainers') { + canGo = canGo && currentArea.trainerProgress >= currentArea.trainers.length; + } + + else if (condition.startsWith('event.')) { + canGo = false; + } + } + + if (!canGo) { + connectionNode.setAttribute('disabled', true); + } + + connectionNode.addEventListener('click', () => { + if (canGo) { + Game.goToArea(connectionSlug); + popup.remove(); + } else { + alert("Can\'t go there yet!"); + } + }); + + template.appendChild(connectionNode); } + + popup.querySelector('.popup').appendChild(template); + UI.drawPopup(popup); }, openPartyMenu () { @@ -1305,6 +1341,7 @@ const UI = { }; // UI element click bindings +UI.elements.changeArea.addEventListener('click', UI.openAreaSelection); UI.elements.menuParty.addEventListener('click', UI.openPartyMenu); UI.elements.menuInventory.addEventListener('click', UI.openInventoryMenu); UI.elements.menuLog.addEventListener('click', UI.toggleLog); -- cgit v1.2.3