From 43a28ad77190f2e55e2e6ba65a9a7b5b1f5dea6c Mon Sep 17 00:00:00 2001 From: Daniel Weipert Date: Sun, 20 Aug 2023 20:48:29 +0200 Subject: area progression, item usage --- resources/js/ui.js | 329 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 264 insertions(+), 65 deletions(-) (limited to 'resources/js/ui.js') diff --git a/resources/js/ui.js b/resources/js/ui.js index 0d6a8f9..dbec9b2 100644 --- a/resources/js/ui.js +++ b/resources/js/ui.js @@ -37,12 +37,15 @@ const UI = { battle: document.querySelector('#battle'), battleOpponent: document.querySelector('#battle__opponent'), battleOpponentSprite: null, - battleOpponentAnimation: document.querySelector('.battle__monster-sprite__animation'), + battleOpponentTrainerSprite: document.querySelector('.battle__opponent__trainer-sprite'), + battleOpponentAnimation: document.querySelector('.battle__technique-animation'), battlePlayer: document.querySelector('#battle__player'), techniques: document.querySelector('#techniques'), status: document.querySelector('#status'), + nextTrainer: document.querySelector('#status [data-template-slot="nextTrainer"]'), + nextArea: document.querySelector('#status [data-template-slot="nextArea"]'), menuParty: document.querySelector('#menu__party'), menuInventory: document.querySelector('#menu__inventory'), @@ -355,13 +358,15 @@ const UI = { UI.elements.battleOpponentSprite = battleMonsterNode.querySelector('[data-template-slot="sprite"]'); UI.elements.battleOpponentSprite.style.transitionDuration = `${UI.damageHighlightClickDuration}s`; - // en/disable catch - if (Memory.state.opponent.type === 'trainer') { - UI.elements.menuCatch.setAttribute('disabled', true); + if (Game.isBattleType('trainer') && Memory.state.opponent.sprite) { + UI.elements.battleOpponentTrainerSprite.src = `/modules/tuxemon/mods/tuxemon/gfx/sprites/player/${Memory.state.opponent.sprite}`; } else { - UI.elements.menuCatch.removeAttribute('disabled'); + UI.elements.battleOpponentTrainerSprite.src = ''; } + // en/disable catch + UI.drawActiveBall(); + const previousBattleMonsterNode = UI.elements.battleOpponent.querySelector('.battle__monster'); if (previousBattleMonsterNode) { UI.elements.battleOpponentSprite.classList = previousBattleMonsterNode.querySelector('[data-template-slot="sprite"]').classList; @@ -564,19 +569,36 @@ const UI = { /* Menu */ partySelectionMode: 'select', + inventorySelectionMode: 'use', drawStatus () { - UI.elements.status.querySelector('[data-template-slot="money"]').textContent = `${Memory.state.money} €`; - UI.elements.status.querySelector('[data-template-slot="monster-progress"]').textContent = `${Memory.state.currentArea.monsterProgress} / ${'10'}`; - UI.elements.status.querySelector('[data-template-slot="trainer-progress"]').textContent = `${Memory.state.currentArea.trainerProgress} / ${Memory.state.currentArea.trainers.length}`; + const currentArea = Memory.state.currentArea; - const nextTrainerButton = UI.elements.status.querySelector('[data-template-slot="next-trainer"]'); - if (Memory.state.currentArea.monsterProgress >= Memory.state.currentArea.requiredEncounters) { + UI.elements.status.querySelector('[data-template-slot="money"]').textContent = `${Memory.state.money} €`; + UI.elements.status.querySelector('[data-template-slot="monsterProgress"]').textContent = `${currentArea.monsterProgress} / ${currentArea.requiredEncounters}`; + UI.elements.status.querySelector('[data-template-slot="trainerProgress"]').textContent = `${currentArea.trainerProgress} / ${currentArea.trainers.length}`; + + const nextTrainerButton = UI.elements.nextTrainer; + if ( + Memory.state.opponent.type === 'monster' && + currentArea.monsterProgress >= currentArea.requiredEncounters && + currentArea.trainerProgress < currentArea.trainers.length + ) { nextTrainerButton.disabled = false; } 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; + } }, openPartyMenu () { @@ -586,13 +608,7 @@ const UI = { party.id = 'party'; for (const monsterIdx in Memory.state.player.monsters) { const monster = Memory.state.player.monsters[monsterIdx]; - const partyMonster = UI.createTemplate(Template.partyMonster); - - partyMonster.querySelector('[data-template-slot="sprite"]').src = `/modules/tuxemon/mods/tuxemon/gfx/sprites/battle/${monster.slug}-front.png`; - partyMonster.querySelector('[data-template-slot="name"]').textContent = monster.name; - partyMonster.querySelector('[data-template-slot="gender"]').innerHTML = UI.createGenderIcon(monster.gender).outerHTML; - partyMonster.querySelector('[data-template-slot="level"]').textContent = monster.level; - partyMonster.querySelector('[data-template-slot="hpText"]').textContent = `${monster.hp} / ${monster.stats.hp}`; + const partyMonster = UI.createPartyMonster(monster); partyMonster.addEventListener('click', async (event) => { // bubble up to partyNode @@ -648,9 +664,24 @@ const UI = { UI.drawPopup(popup); }, + drawActiveBall () { + if (Game.canCatchMonster()) { + UI.elements.menuCatch.removeAttribute('disabled'); + } else { + UI.elements.menuCatch.setAttribute('disabled', true); + } + + if (Memory.state.activeBall) { + UI.elements.menuCatch.querySelector('img').src = `/modules/tuxemon/mods/tuxemon/gfx/items/${Memory.state.activeBall.slug}.png`; + } else { + UI.elements.menuCatch.querySelector('img').src = `/modules/tuxemon/mods/tuxemon/gfx/items/tuxeball.png`; + } + }, + openInventoryMenu () { const popup = UI.createPopup(); const inventory = UI.createTemplate(Template.inventory); + inventory.id = 'inventory'; const tabs = { heal: { @@ -680,17 +711,7 @@ const UI = { }; for (const item of Memory.state.player.inventory) { - const inventoryItemNode = UI.createTemplate(Template.inventoryItem); - - inventoryItemNode.title = item.description; - - inventoryItemNode.querySelector('[data-template-slot="sprite"]').src = `/modules/tuxemon/mods/tuxemon/${item.sprite}`; - inventoryItemNode.querySelector('[data-template-slot="name"]').textContent = item.name; - inventoryItemNode.querySelector('[data-template-slot="quantity"]').textContent = item.quantity; - - inventoryItemNode.addEventListener('click', async () => { - Game.useItem(item); - }); + const inventoryItemNode = UI.createInventoryItem(item); if (['potion', 'revive'].includes(item.category)) { tabs['heal'].items.push(inventoryItemNode); @@ -726,7 +747,23 @@ const UI = { })); tabsNode.style.gridTemplateColumns = '1fr 1fr 1fr'; - inventory.appendChild(tabsNode); + inventory.querySelector('[data-template-slot="items"]').appendChild(tabsNode); + + const selectionModesNode = inventory.querySelector('[data-template-slot="modes"]'); + const selectionModeNodes = selectionModesNode.querySelectorAll('[data-selection-mode]'); + selectionModeNodes.forEach((node) => { + if (node.dataset.selectionMode === UI.inventorySelectionMode) { + node.setAttribute('selected', true); + } + + node.addEventListener('click', () => { + selectionModesNode.querySelector(`[data-selection-mode="${UI.inventorySelectionMode}"]`).removeAttribute('selected'); + + UI.inventorySelectionMode = node.dataset.selectionMode; + + node.setAttribute('selected', true); + }); + }); popup.querySelector('.popup').appendChild(inventory); popup.classList.add('inventory__popup'); @@ -750,42 +787,6 @@ const UI = { UI.drawPopup(popup); }, - openSaveDialog () { - const popup = UI.createPopup(); - const dialog = UI.createTemplate(Template.dialogSave); - - const saveData = Memory.save(); - - dialog.querySelector('[data-template-slot="saveData"]').value = saveData; - dialog.querySelector('[data-template-slot="saveClipboard"]').addEventListener('click', async () => { - if (navigator.clipboard) { - await navigator.clipboard.writeText(saveData); - alert('Saved to clipboard!'); - } else { - alert('ERROR: Browser can\'t copy to clipboard! You have to do it manually.'); - } - }); - - popup.querySelector('.popup').appendChild(dialog); - UI.drawPopup(popup); - }, - - openLoadDialog () { - const popup = UI.createPopup(); - const dialog = UI.createTemplate(Template.dialogLoad); - - dialog.querySelector('[data-template-slot="load"]').addEventListener('click', () => { - Memory.load( - dialog.querySelector('[data-template-slot="saveData"]').value.trim() - ); - - document.querySelectorAll('.popup__overlay').forEach((element) => element.remove()) - }); - - popup.querySelector('.popup').appendChild(dialog); - UI.drawPopup(popup); - }, - openSettingsMenu () { const popup = UI.createPopup(); const template = UI.createTemplate(Template.menuSettings); @@ -842,6 +843,26 @@ const UI = { }, + /* Menu - Party */ + + /** + * @param {Monster} + * + * @returns {HTMLElement} + */ + createPartyMonster (monster) { + const partyMonster = UI.createTemplate(Template.partyMonster); + + partyMonster.querySelector('[data-template-slot="sprite"]').src = `/modules/tuxemon/mods/tuxemon/gfx/sprites/battle/${monster.slug}-front.png`; + partyMonster.querySelector('[data-template-slot="name"]').textContent = monster.name; + partyMonster.querySelector('[data-template-slot="gender"]').innerHTML = UI.createGenderIcon(monster.gender).outerHTML; + partyMonster.querySelector('[data-template-slot="level"]').textContent = monster.level; + partyMonster.querySelector('[data-template-slot="hpText"]').textContent = `${monster.hp} / ${monster.stats.hp}`; + + return partyMonster; + }, + + /* Menu - Monster */ /** @@ -940,6 +961,9 @@ const UI = { return movesetListNode; }, + /** + * @param {Monster} monster + */ openStatsMenu (monster) { const popup = UI.createPopup(); const statusMenu = UI.createStatsMenu(monster); @@ -960,6 +984,181 @@ const UI = { UI.drawPopup(popup); }, + + + /* Menu - Inventory */ + + /** + * @param {InventoryItem} item + * + * @returns {HTMLElement} + */ + createInventoryItem (item) { + const inventoryItemNode = UI.createTemplate(Template.inventoryItem); + + inventoryItemNode.title = item.description; + inventoryItemNode.dataset.templateItem = item.slug; + + inventoryItemNode.querySelector('[data-template-slot="sprite"]').src = `/modules/tuxemon/mods/tuxemon/${item.sprite}`; + inventoryItemNode.querySelector('[data-template-slot="name"]').textContent = item.name; + inventoryItemNode.querySelector('[data-template-slot="quantity"]').textContent = item.quantity; + + inventoryItemNode.addEventListener('click', async () => { + if (UI.inventorySelectionMode === 'use') { + if (item.category === 'potion') { + UI.openItemMonsterSelection(item); + } + + else if (item.category === 'capture') { + Game.useItem(item); + } + } + else if (UI.inventorySelectionMode === 'info') { + UI.openItemInfo(item); + } + }); + + return inventoryItemNode; + }, + + /** + * @param {InventoryItem} item + */ + redrawInventoryItem (item) { + const itemNode = document.querySelector(`#inventory *[data-template-item="${item.slug}"]`); + if (item.quantity === 0) { + itemNode.remove(); + } + + const newNode = UI.createInventoryItem(item); + itemNode.replaceWith(newNode); + }, + + /** + * @param {InventoryItem} item + * @param {Monster[]} monsters + * + * @returns {HTMLElement} + */ + createItemMonsterSelection (item, monsters) { + const template = document.createElement('div'); + + /** + * @param {Monster} monster + * + * @returns {(HTMLElement|null)} + */ + const createMonsterNode = (monster) => { + if (!Game.canUseItem(item, monster)) { + return null; + } + + const monsterNode = UI.createPartyMonster(monster); + + monsterNode.addEventListener('click', async () => { + await Game.useItem(item, monster); + + if (item.quantity === 0) { + Game.removeItemFromInventory(Memory.state.player.inventory, item); + template.dispatchEvent(new Event('item:isExhausted')); + } else { + const replacingMonsterNode = createMonsterNode(monster); + if (replacingMonsterNode) { + monsterNode.replaceWith(replacingMonsterNode); + } else { + monsterNode.remove(); + template.dispatchEvent(new Event('monster:lostCondition')); + } + } + + UI.redrawInventoryItem(item); + }); + + return monsterNode; + }; + + for (const monster of monsters) { + const monsterNode = createMonsterNode(monster); + + monsterNode && template.appendChild(monsterNode); + } + + return template; + }, + + /** + * @param {InventoryItem} item + */ + openItemMonsterSelection (item) { + const popup = UI.createPopup(); + const template = UI.createItemMonsterSelection(item, Memory.state.player.monsters); + template.classList.add('inventory__monster-selection'); + + if (template.children.length === 0) { + alert('No applicable monsters.'); + return; + } + + template.addEventListener('item:isExhausted', () => popup.remove()); + template.addEventListener('monster:lostCondition', () => popup.remove()); + + popup.querySelector('.popup').appendChild(template); + + UI.drawPopup(popup); + }, + + /** + * @param {InventoryItem} item + */ + openItemInfo (item) { + const popup = UI.createPopup(); + const template = document.createElement('div'); + + template.textContent = item.conditions + ' -- ' + item.effects + ' -- ' + item.description; + + popup.querySelector('.popup').appendChild(template); + + UI.drawPopup(popup); + }, + + + /* Menu - Journal */ + + openSaveDialog () { + const popup = UI.createPopup(); + const dialog = UI.createTemplate(Template.dialogSave); + + const saveData = Memory.save(); + + dialog.querySelector('[data-template-slot="saveData"]').value = saveData; + dialog.querySelector('[data-template-slot="saveClipboard"]').addEventListener('click', async () => { + if (navigator.clipboard) { + await navigator.clipboard.writeText(saveData); + alert('Saved to clipboard!'); + } else { + alert('ERROR: Browser can\'t copy to clipboard! You have to do it manually.'); + } + }); + + popup.querySelector('.popup').appendChild(dialog); + UI.drawPopup(popup); + }, + + openLoadDialog () { + const popup = UI.createPopup(); + const dialog = UI.createTemplate(Template.dialogLoad); + + dialog.querySelector('[data-template-slot="load"]').addEventListener('click', () => { + Memory.load( + dialog.querySelector('[data-template-slot="saveData"]').value.trim() + ); + + document.querySelectorAll('.popup__overlay').forEach((element) => element.remove()) + }); + + popup.querySelector('.popup').appendChild(dialog); + UI.drawPopup(popup); + }, }; // UI element click bindings -- cgit v1.2.3