summaryrefslogtreecommitdiff
path: root/resources/js/ui.js
diff options
context:
space:
mode:
Diffstat (limited to 'resources/js/ui.js')
-rw-r--r--resources/js/ui.js329
1 files changed, 264 insertions, 65 deletions
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