From d2b78b32ad41dd7d2e7f86cda8bada33238fd286 Mon Sep 17 00:00:00 2001 From: Daniel Weipert Date: Tue, 15 Aug 2023 19:24:47 +0200 Subject: ui reorder and menu --- index.html | 60 +++++++++++++---- script.js | 221 ++++++++++++++++++++++++++++++++++++++++++++----------------- style.css | 84 ++++++++++++++++++++--- 3 files changed, 280 insertions(+), 85 deletions(-) diff --git a/index.html b/index.html index fa5498b..94f298c 100644 --- a/index.html +++ b/index.html @@ -1,12 +1,12 @@ + + +
-
Money:
-
-
@@ -15,18 +15,38 @@
-
CATCH
+
+
Money:
+
+ +
@@ -35,14 +55,19 @@
- {NAME} {GENDER} Lv. {LEVEL} + {NAME} + {GENDER} + Lv. {LEVEL}
-
-
-
+
+
+
+
+
+
+
+
-
-
XP
@@ -58,7 +83,11 @@
-
+
+
+
+
+
@@ -74,7 +103,10 @@ diff --git a/script.js b/script.js index 575db99..9eecc44 100644 --- a/script.js +++ b/script.js @@ -14,6 +14,34 @@ const ElementType = { earth: 'earth', metal: 'metal', water: 'water', + + /* lightning: 'lightning', + frost: 'frost', + venom: 'venom', + //vermin: 'vermin', + cosmic: 'cosmic', + battle: 'battle', + psionic: 'psionic', + darkness: 'darkness', + heaven: 'heaven', + + combineTypes(typeA, typeB) { + if (typeA === ElementType.earth & typeB === ElementType.fire) { + return ElementType.lightning; + } + if (typeA === ElementType.earth & typeB === ElementType.water) { + return ElementType.frost; + } + if (typeA === ElementType.earth & typeB === ElementType.wood) { + return ElementType.venom; + } + // if (typeA === ElementType.earth & typeB === ElementType.metal) { + // return ElementType.vermin; + // } + if (typeA === ElementType.fire && typeB === ElementType.water) { + return ElementType.cosmic; + } + } */ }; const ElementTypeColor = { [ElementType.aether]: 'rgba(255, 255, 255, 1)', @@ -58,7 +86,10 @@ class State { money = 0; monsters = []; + inventory = []; + partyMonsters = []; + activeMonster = null; activeTechnique = null; @@ -77,6 +108,9 @@ class Monster { gender = ''; + heldItem = null; + statusEffect = ''; + statusModifiers = { hp: 0, melee: 0, @@ -164,7 +198,8 @@ class Monster { } getPossibleEvolutions () { - return this.evolutions.filter((evolution) => this.level >= evolution.at_level && (!evolution.item || this.heldItem === evolution.item)); + // return this.evolutions.filter((evolution) => this.level >= evolution.at_level && (!evolution.item || this.heldItem === evolution.item)); + return this.evolutions.filter((evolution) => evolution.path === 'standard' && this.level >= evolution.at_level); } canEvolve () { @@ -268,8 +303,14 @@ class Technique { get animation () { return DB.techniques[this.slug].animation; } + + get sfx () { + return DB.techniques[this.slug].sfx; + } } +class Item {} + function simpleDamageMultiplier (techniqueTypes, targetTypes) { let multiplier = 1; @@ -412,7 +453,7 @@ function slugToName (slug) { const UI = { activeMonster: null, - damageAnimationInterval: null, + damageAnimationIsRunning: false, damageAnimationNumber: 0, getTemplate (template) { @@ -449,13 +490,13 @@ function slugToName (slug) { hpText.textContent = monster.hp + ' / ' + monster.status.hp; }, - createDamage (event, damage) { + async createDamage (event, damage) { const damageNode = document.createElement('div'); damageNode.classList.add('damage'); damageNode.textContent = damage; const damageMultiplier = simpleDamageMultiplier(state.activeTechnique.types, state.enemy.monster.types); - damageNode.style.fontSize = damageMultiplier + 'rem'; + damageNode.style.fontSize = damageMultiplier*2 + 'rem'; damageNode.style.top = event.pageY - battleEnemy.offsetTop + (Math.random() * 40 - 20); damageNode.style.left = event.pageX - battleEnemy.offsetLeft + (Math.random() * 40 - 20); @@ -476,57 +517,34 @@ function slugToName (slug) { clickTimeout = setTimeout(() => enemyImg.classList.remove('damaged'), imgClickDuration * 1000); var enemyAnimation = battleEnemy.querySelector('.battle__monster-sprite__animation'); - // enemyAnimation.style.top = enemyImg.getBoundingClientRect().top; - // enemyAnimation.style.left = enemyImg.getBoundingClientRect().left; - if (!this.damageAnimationInterval && state.activeTechnique.animation) { - this.damageAnimationInterval = setInterval(() => { + if (!this.damageAnimationIsRunning && state.activeTechnique.animation) { + this.damageAnimationIsRunning = true; + + const damageAnimationLoop = () => { enemyAnimation.src = `/modules/tuxemon/mods/tuxemon/animations/technique/${state.activeTechnique.animation}_${("00" + this.damageAnimationNumber).slice(-2)}.png`; enemyAnimation.style.top = event.clientY - (enemyAnimation.clientHeight / 2); enemyAnimation.style.left = event.clientX - (enemyAnimation.clientWidth / 2); - console.log(enemyAnimation.src); + // console.log(enemyAnimation.src); this.damageAnimationNumber++; if (this.damageAnimationNumber === DB.allAnimations[state.activeTechnique.animation].length) { - clearInterval(this.damageAnimationInterval); - this.damageAnimationInterval = null; + this.damageAnimationIsRunning = false; this.damageAnimationNumber = 0; enemyAnimation.src = ''; + return; } - }, 50); - } - }, - - addPartyMonster (slug) { - let partyMonster = document.createElement('div'); - partyMonster.innerHTML = templatePartyMonster.trim(); - partyMonster = partyMonster.firstChild; - - partyMonster.dataset.slug = slug; - partyMonster.querySelector('img').src = `/modules/tuxemon/mods/tuxemon/gfx/sprites/battle/${slug}-front.png`; - partyMonster.addEventListener('click', (event) => { - let target = event.target; - while (target.parentNode.id !== 'party') { - target = target.parentNode; - } + setTimeout(() => requestAnimationFrame(damageAnimationLoop), 50); + }; - state.activeMonster = state.partyMonsters[Array.prototype.indexOf.call(document.querySelector('#party').children, target)]; - UI.setActiveMonster(); - }); - partyMonster.style.cursor = 'pointer'; + requestAnimationFrame(damageAnimationLoop); - party.appendChild(partyMonster); - }, - - async setActiveMonster () { - let activeMoveIndex = 0; - while ((await fetchTechnique(state.activeMonster.moveset[activeMoveIndex].technique)).power === 0) { - activeMoveIndex++; + // sfx + /* let sfx = state.activeTechnique.sfx.substr(4); + const audio = new Audio(`/modules/tuxemon/mods/tuxemon/sounds/technique/${sfx}.ogg`); + audio.play(); */ } - state.activeTechnique = await fetchTechnique(state.activeMonster.moveset[activeMoveIndex].technique); - - UI.setBattleMonster(state.activeMonster, 'player'); }, setBattleMonster (monster, where) { @@ -537,28 +555,44 @@ function slugToName (slug) { battleMonster.querySelector('.battle__monster-info__name').textContent = monster.name; battleMonster.querySelector('.battle__monster-info__gender').textContent = monster.gender === 'male' ? '♂' : monster.gender === 'female' ? '♀' : '⚲'; battleMonster.querySelector('.battle__monster-info__level').textContent = monster.level; + battleMonster.querySelector('.battle__monster-info__status').innerHTML = UI.createStatusIcon(monster.statusEffect); + battleMonster.querySelector('.battle__monster-img').src = `/modules/tuxemon/mods/tuxemon/gfx/sprites/battle/${monster.slug}-front.png`; + UI.setHp(monster, battleMonster.querySelector('.hp')); - battleMonster.querySelector('img').src = `/modules/tuxemon/mods/tuxemon/gfx/sprites/battle/${monster.slug}-front.png`; if (where === 'player') { UI.setExp(monster, battleMonster.querySelector('.exp')); - battleMonster.querySelector('.battle__monster-technique').textContent = - state.activeTechnique.slug + ' - ' + state.activeTechnique.types + ' - ' + state.activeTechnique.power; + battleMonster.querySelector('.battle__monster-technique').innerHTML = + slugToName(state.activeTechnique.slug) + '   ' + + state.activeTechnique.types.map((type) => UI.createElementTypeIcon(type)).join(''); battleMonster.querySelector('.battle__monster-technique').addEventListener('click', UI.openMovesetSelection); battleMonster.classList.add('battle__monster--player'); - battlePlayer.replaceChildren(battleMonster); + battlePlayer.querySelector('.battle__monster') && battlePlayer.removeChild(battlePlayer.querySelector('.battle__monster')); + battlePlayer.appendChild(battleMonster); } else { battleMonster.classList.add('battle__monster--enemy'); - // battleEnemy.replaceChildren(battleMonster); battleEnemy.querySelector('.battle__monster') && battleEnemy.removeChild(battleEnemy.querySelector('.battle__monster')); battleEnemy.appendChild(battleMonster); } }, + setEnemyMonster () { + UI.setBattleMonster(state.enemy.monster, 'enemy'); + }, + + async setActiveMonster () { + let activeMoveIndex = 0; + while ((await fetchTechnique(state.activeMonster.moveset[activeMoveIndex].technique)).power === 0) { + activeMoveIndex++; + } + state.activeTechnique = await fetchTechnique(state.activeMonster.moveset[activeMoveIndex].technique); + + UI.setBattleMonster(state.activeMonster, 'player'); + }, + async openMovesetSelection () { - const popup = UI.getTemplate(templatePopup); - popup.addEventListener('click', ({ target }) => target === popup && popup.remove()); + const popup = UI.createPopup(); const movesetList = UI.getTemplate(templateMovesetList); for (const move of state.activeMonster.moveset) { @@ -570,7 +604,11 @@ function slugToName (slug) { const movesetItem = UI.getTemplate(templateMovesetItem); - movesetItem.textContent = slugToName(technique.slug) + ' - ' + technique.types + ' - ' + technique.power + ' - ' + move.level_learned; + movesetItem.querySelector('.moveset__item__name').textContent = slugToName(technique.slug); + movesetItem.querySelector('.moveset__item__type').innerHTML = technique.types.map((type) => UI.createElementTypeIcon(type)).join(''); + movesetItem.querySelector('.moveset__item__power').innerHTML = technique.power; + movesetItem.querySelector('.moveset__item__level').innerHTML = move.level_learned; + movesetItem.addEventListener('click', () => { if (movesetItem.getAttribute('disabled')) { return false; @@ -598,17 +636,79 @@ function slugToName (slug) { state.enemy.monster.level = Math.ceil(Math.random() * state.activeMonster.level); // state.enemy.monster.experienceModifier = state.enemy.monster.level; state.enemy.monster.moneyModifier = state.enemy.monster.level; - UI.setBattleMonster(state.enemy.monster, 'enemy'); + UI.setEnemyMonster(); }, - }; - for (const monster of state.partyMonsters) { - UI.addPartyMonster(monster.slug); - } + createElementTypeIcon (type) { + var img = document.createElement('img'); + img.src = `/modules/tuxemon/mods/tuxemon/gfx/ui/icons/element/${type}_type.png`; + img.title = slugToName(type); + + return img.outerHTML; + }, + + createStatusIcon (status) { + if (!status) return ''; + + var img = document.createElement('img'); + img.src = `/modules/tuxemon/mods/tuxemon/gfx/ui/icons/status/icon_${status}.png`; + img.title = slugToName(status); + + return img.outerHTML; + }, + + createPopup () { + const popup = UI.getTemplate(templatePopup); + popup.addEventListener('click', ({ target }) => target === popup && popup.remove()); + + return popup; + }, + + openPartyMenu () { + const popup = UI.createPopup(); + + const party = document.createElement('div'); + party.id = 'party'; + for (const monster of state.partyMonsters) { + const partyMonster = UI.getTemplate(templatePartyMonster); + + partyMonster.dataset.slug = monster.slug; + partyMonster.querySelector('img').src = `/modules/tuxemon/mods/tuxemon/gfx/sprites/battle/${monster.slug}-front.png`; + + partyMonster.addEventListener('click', (event) => { + let target = event.target; + while (target.parentNode.id !== 'party') { + target = target.parentNode; + } + + state.activeMonster = state.partyMonsters[Array.prototype.indexOf.call(document.querySelector('#party').children, target)]; + UI.setActiveMonster(); + + popup.remove(); + }); + + party.appendChild(partyMonster); + } + + popup.querySelector('.popup').appendChild(party); + document.body.appendChild(popup); + }, + + openInventoryMenu () { + const popup = UI.createPopup(); + + const inventory = document.createElement('div'); + inventory.id = 'inventory'; + for (const item of state.inventory) { + } + + popup.querySelector('.popup').appendChild(inventory); + document.body.appendChild(popup); + }, + }; - UI.setBattleMonster(state.activeMonster, 'player'); - UI.setBattleMonster(state.enemy.monster, 'enemy'); UI.setActiveMonster(); + UI.setEnemyMonster(); var clickTimeout; document.querySelector('#battle__enemy').addEventListener('click', async (event) => { @@ -630,20 +730,21 @@ function slugToName (slug) { state.activeMonster.evolve(); UI.setActiveMonster(); } - - UI.setBattleMonster(state.activeMonster, 'player'); } UI.setHp(state.enemy.monster, battleEnemy); money.textContent = state.money; }); - document.querySelector('#catch').addEventListener('click', async (event) => { + document.querySelector('#menu__party').addEventListener('click', UI.openPartyMenu); + + document.querySelector('#menu__catch').addEventListener('click', async () => { const caughtMonster = new Monster(state.enemy.monster.slug); caughtMonster.level = state.enemy.monster.level; state.partyMonsters.push(caughtMonster); UI.createNewEnemyMonster(); - UI.addPartyMonster(caughtMonster.slug); }); + + document.querySelector('#menu__inventory').addEventListener('click', UI.openInventoryMenu); })(); diff --git a/style.css b/style.css index 3a97ff1..c0bf5f4 100644 --- a/style.css +++ b/style.css @@ -2,6 +2,10 @@ box-sizing: border-box; } +html { + font-size: 14px; +} + body { margin: 0; } @@ -13,11 +17,10 @@ img { .wrap { margin: 0 auto; - width: 1200px; + min-width: 360px; + max-width: 750px; + width: 100vw; height: 100vh; - display: flex; - justify-content: center; - align-items: center; } .popup__overlay { @@ -33,21 +36,19 @@ img { } .popup { background-color: #fff; - padding: 1rem; + padding: 0.25rem 0.5rem; } #battle { user-select: none; - min-width: 750px; min-height: 300px; - padding: 1rem; + padding: 0.5rem; display: flex; flex-direction: column; justify-content: space-between; - background-image: url('/modules/tuxemon/mods/tuxemon/gfx/backgrounds/test/back02.png'); - background-image: url('https://wiki.tuxemon.org/images/9/9f/Sea_background.png'); + background-image: url('/modules/tuxemon/mods/tuxemon/gfx/ui/combat/sea_background.png'); background-size: cover; } @@ -78,6 +79,17 @@ img { .battle__monster-info__gender { line-height: 1em; } + +.battle__monster-info-box__status { + display: flex; + justify-content: space-between; + /* align-items: center; */ +} +.battle__monster-info__status { + flex-basis: 5%; + text-align: center; +} + .battle__monster-info-exp { display: flex; align-items: center; @@ -113,9 +125,14 @@ img { .battle__monster-technique { background-color: beige; border: 2px solid #000; - display: inline; padding: 0.25rem; + + display: inline-flex; + align-items: center; } +.battle__monster-technique__name {} +.battle__monster-technique__types {} +.battle__monster-technique__power {} .battle__monster--player { flex-direction: row-reverse; @@ -139,6 +156,9 @@ img { transition: background-color; width: 0%; } +.hp { + flex-grow: 1; +} .hp-bar-wrap { width: 100%; border: 1px solid rgba(0, 0, 0, 0.5); @@ -149,8 +169,50 @@ img { transition: background-color; } +.moveset__item { + font-size: 1.5rem; + border: 1px solid #000; + padding: 0.5em 0.75em; + margin: 0.5em 0; + line-height: 1em; + cursor: pointer; +} +.moveset__item:hover { + background-color: rgba(0, 0, 0, 0.1); +} .moveset__item[disabled] { - color: #ebebeb; + filter: grayscale(100%); + opacity: 0.5; +} +.moveset__item img { + height: 1em; + width: 1em; +} + + +#menu { + display: grid; + grid-template-columns: 1fr 1fr 1fr; + text-align: center; +} +#menu > div { + cursor: pointer; +} +#menu > div:hover { + background-color: rgba(0, 0, 0, 0.05); +} + + +#party { + display: grid; + grid-template-columns: 1fr 1fr 1fr 1fr 1fr 1fr; +} + +.party__monster { + cursor: pointer; +} +.party__monster:hover { + background-color: rgba(0, 0, 0, 0.1); } -- cgit v1.2.3