summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDaniel Weipert <code@drogueronin.de>2023-08-17 22:46:12 +0200
committerDaniel Weipert <code@drogueronin.de>2023-08-17 22:46:12 +0200
commitaa44f67ab57673528e96a4a075fbd8cd0354bd68 (patch)
treec232349cbe9583378ad510774be27b4371d50cd4
parentcc685bfe02b42b592987117fa008a4461785f53c (diff)
ui
-rw-r--r--index.html145
-rw-r--r--resources/css/battle.css6
-rw-r--r--resources/css/menu.css86
-rw-r--r--resources/js/classes/StatusEffect.js2
-rw-r--r--resources/js/classes/Technique.js20
-rw-r--r--resources/js/game.js90
-rw-r--r--resources/js/ui.js154
7 files changed, 377 insertions, 126 deletions
diff --git a/index.html b/index.html
index 9a27020..b4d1eb5 100644
--- a/index.html
+++ b/index.html
@@ -1,3 +1,4 @@
+<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
@@ -20,22 +21,6 @@
</div>
<div id="techniques"></div>
- <template id="tpl___techniques">
- <div></div>
- </template>
- <template id="tpl___technique">
- <div class="techniques__technique">
- <div>
- <div data-template-slot="name"></div>
- <div data-template-slot="types"></div>
- </div>
- <div>
- <div data-template-slot="power"></div>
- <div data-template-slot="accuracy"></div>
- <div data-template-slot="range"></div>
- </div>
- </div>
- </template>
<div id="status">
<div>Money: <span id="money"></span></div>
@@ -63,30 +48,9 @@
<!-- Templates -->
- <template id="tpl___party">
- <div class="party">
- <div data-template-slot="monsters" class="party__monsters"></div>
- <div data-template-slot="modes" class="party__selection-modes">
- <button data-template-slot="modeSelect" data-party-selection-mode="select">Select</button>
- <button data-template-slot="modeStats" data-party-selection-mode="stats">Stats</button>
- <button data-template-slot="modeTechniques" data-party-selection-mode="techniques">Techniques</button>
- </div>
- </div>
- </template>
-
- <template id="tpl___party__monster">
- <div class="party__monster">
- <div><div class="monster__level"></div></div>
- <img data-template-slot="sprite" class="monster__img" src="" />
- <div class="monster__exp">
- <div class="monster__exp-bar"></div>
- </div>
- <div class="monster__exp-text"></div>
- <div class="monster__active-technique">
- <div class="monster__active-technique__name"></div>
- <div class="monster__active-technique__types"></div>
- <div class="monster__active-technique__power"></div>
- </div>
+ <template id="tpl___popup">
+ <div class="popup__overlay">
+ <div class="popup"></div>
</div>
</template>
@@ -139,9 +103,86 @@
<div data-template-slot="text" class="damage"></div>
</template>
- <template id="tpl___popup">
- <div class="popup__overlay">
- <div class="popup"></div>
+ <template id="tpl___techniques">
+ <div></div>
+ </template>
+ <template id="tpl___technique">
+ <div class="techniques__technique">
+ <div>
+ <div data-template-slot="name"></div>
+ </div>
+ <div>
+ <div data-template-slot="types"></div>
+ <div data-template-slot="range" title="range"></div>
+ <div data-template-slot="recharge" title="recharge"></div>
+ </div>
+ <div>
+ <div data-template-slot="power" title="power"></div>
+ <div data-template-slot="accuracy" title="accuracy"></div>
+ </div>
+ </div>
+ </template>
+
+ <template id="tpl___party">
+ <div class="party">
+ <div data-template-slot="monsters" class="party__monsters"></div>
+ <div data-template-slot="modes" class="party__selection-modes">
+ <button data-template-slot="modeSelect" data-party-selection-mode="select" class="menu-button">Select</button>
+ <button data-template-slot="modeStats" data-party-selection-mode="stats" class="menu-button">Stats</button>
+ <button data-template-slot="modeTechniques" data-party-selection-mode="techniques" class="menu-button">Techniques</button>
+ </div>
+ </div>
+ </template>
+
+ <template id="tpl___party__monster">
+ <div class="party__monster">
+ <img data-template-slot="sprite" class="monster__img" src="" />
+ <div class="party__monster__stats">
+ <span data-template-slot="name"></span>
+ <span data-template-slot="gender"></span>
+ Lv. <span data-template-slot="level"></span>
+ </div>
+ <div>
+ HP <span data-template-slot="hpText"></span>
+ </div>
+ </div>
+ </template>
+
+ <template id="tpl___monster-stats">
+ <div class="monster-stats">
+ <div class="monster-stats__identity">
+ <span data-template-slot="name"></span>
+ <span data-template-slot="gender"></span>
+ Lv. <span data-template-slot="level"></span>
+ <span data-template-slot="types"></span>
+ </div>
+
+ <div>
+ <table>
+ <tr>
+ <th>Melee</th>
+ <td data-template-slot="stats.melee"></td>
+ </tr>
+ <tr>
+ <th>Armour</th>
+ <td data-template-slot="stats.armour"></td>
+ </tr>
+ <tr>
+ <th>Ranged</th>
+ <td data-template-slot="stats.ranged"></td>
+ </tr>
+ <tr>
+ <th>Dodge</th>
+ <td data-template-slot="stats.dodge"></td>
+ </tr>
+ <tr>
+ <th>Speed</th>
+ <td data-template-slot="stats.speed"></td>
+ </tr>
+ </table>
+ </div>
+
+ <button data-template-slot="techniques">Techniques</button>
</div>
</template>
@@ -158,8 +199,22 @@
</template>
<template id="tpl___menu__journal">
- <div>
- <button data-template-slot="save">Save</button>
+ <div class="menu__journal">
+ <button data-template-slot="save" class="menu-button">Save</button>
+ <button data-template-slot="load" class="menu-button">Load</button>
+ </div>
+ </template>
+
+ <template id="tpl___dialog__save">
+ <div class="dialog__save">
+ <textarea data-template-slot="saveData"></textarea>
+ <button data-template-slot="saveClipboard" class="menu-button">Save to Clipboard</button>
+ </div>
+ </template>
+
+ <template id="tpl___dialog__load">
+ <div class="dialog__load">
+ <textarea data-template-slot="saveData"></textarea>
<button data-template-slot="load">Load</button>
</div>
</template>
diff --git a/resources/css/battle.css b/resources/css/battle.css
index 0f56234..099142b 100644
--- a/resources/css/battle.css
+++ b/resources/css/battle.css
@@ -76,6 +76,7 @@
margin-bottom: 0.25rem;
}
.battle__monster-img {
+ cursor: pointer;
transition-property: filter;
}
.battle__monster-img.damaged {
@@ -198,6 +199,11 @@
background-color: rgba(0, 0, 0, 0.05);
}
+.techniques__technique[disabled] {
+ filter: grayscale(100%);
+ opacity: 0.5;
+}
+
.techniques__technique > div {
display: flex;
justify-content: space-between;
diff --git a/resources/css/menu.css b/resources/css/menu.css
index 41353b2..72c225a 100644
--- a/resources/css/menu.css
+++ b/resources/css/menu.css
@@ -15,12 +15,38 @@
}
.popup {
+ max-width: 100%;
+
background-image: url('/modules/tuxemon/mods/tuxemon/gfx/ui/background/spyder_empty.png');
background-size: cover;
background-position: center;
}
+.menu-button {
+ font-size: 1.5rem;
+ border: 1px solid #000;
+ padding: 0.4em 0.75em;
+ line-height: 1em;
+ cursor: pointer;
+ background-color: rgba(255, 255, 255, 0.9);
+}
+
+.menu-button:hover {
+ background-color: rgba(0, 0, 0, 0.1);
+}
+
+.menu-button[disabled] {
+ filter: grayscale(100%);
+ opacity: 0.5;
+}
+
+
+.gender-icon {
+ line-height: 1em;
+}
+
+
#status {
@@ -39,12 +65,55 @@
}
#menu > div {
cursor: pointer;
+ padding: 1rem;
}
#menu > div:hover {
background-color: rgba(0, 0, 0, 0.05);
}
+.menu__journal {
+ display: flex;
+ flex-direction: column;
+}
+
+.menu__journal button {
+ margin: 0.5em;
+ font-size: 5rem;
+ padding: 1em 1em;
+}
+
+
+.dialog__save {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+.dialog__save textarea {
+ width: 80vw;
+ height: 60vh;
+}
+.dialog__save button {
+ font-size: 2rem;
+ width: 80vw;
+}
+
+
+.dialog__load {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+.dialog__load textarea {
+ width: 80vw;
+ height: 60vh;
+}
+.dialog__load button {
+ font-size: 2rem;
+ width: 80vw;
+}
+
+
.party__monsters {
display: grid;
@@ -53,7 +122,9 @@
.party__monster {
cursor: pointer;
- padding: 1rem;
+ padding: 0.75rem;
+ text-align: center;
+ font-size: 0.75rem;
}
.party__monster:hover {
background-color: rgba(0, 0, 0, 0.1);
@@ -67,4 +138,17 @@
.party__selection-modes button[selected] {
border-color: var(--color-success);
+ color: var(--color-success);
+}
+
+
+
+.monster-stats {
+ padding: 0.5rem;
+}
+
+.monster-stats__identity {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
}
diff --git a/resources/js/classes/StatusEffect.js b/resources/js/classes/StatusEffect.js
index ac6ae54..e1ae9c9 100644
--- a/resources/js/classes/StatusEffect.js
+++ b/resources/js/classes/StatusEffect.js
@@ -4,6 +4,8 @@ class StatusEffect {
/**
* @type {Monster}
+ *
+ * currently only used for lifeleech
*/
issuer = null;
diff --git a/resources/js/classes/Technique.js b/resources/js/classes/Technique.js
index a24e094..7558748 100644
--- a/resources/js/classes/Technique.js
+++ b/resources/js/classes/Technique.js
@@ -3,10 +3,14 @@ class Technique {
#potency = 0;
#power = 0;
+ turnLastUse = 0;
+
constructor (slug) {
this.slug = slug;
this.resetStats();
+
+ this.turnLastUse = -this.rechargeLength;
}
get name () {
@@ -36,6 +40,22 @@ class Technique {
return DB.techniques[this.slug].effects;
}
+ get rechargeLength () {
+ return DB.techniques[this.slug].recharge;
+ }
+
+ isUsable () {
+ if (this.turnLastUse >= Game.turn) {
+ return true;
+ }
+
+ return Game.turn - this.turnLastUse >= this.rechargeLength;
+ }
+
+ use () {
+ this.turnLastUse = Game.turn;
+ }
+
get accuracy () {
return this.#accuracy;
}
diff --git a/resources/js/game.js b/resources/js/game.js
index 1f1f92b..140f9d5 100644
--- a/resources/js/game.js
+++ b/resources/js/game.js
@@ -9,9 +9,12 @@ const Game = {
},
didTechniqueHit: false,
+ turn: 0,
async progressTurn () {
+ Game.turn++;
+
await Game.applyStatusEffect(state.enemy.monster);
await Game.applyStatusEffect(state.activeMonster);
@@ -28,11 +31,30 @@ const Game = {
}
Game.phases.postAction = [];
+ // enemy defeated
+ if (state.enemy.monster.hp <= 0) {
+ // money
+ state.money += state.enemy.monster.level * state.enemy.monster.moneyModifier;
+
+ // exp
+ state.activeMonster.exp += calculateAwardedExperience(state.enemy.monster, [state.activeMonster])[0];
+
+ if (state.activeMonster.canLevelUp()) {
+ state.activeMonster.levelUp();
+ }
+ if (state.activeMonster.canEvolve()) {
+ await fetchMonster(state.activeMonster.evolutions[0].monster_slug);
+ state.activeMonster.evolve();
+ }
+
+ await Game.spawnEnemyMonster();
+ }
+
UI.drawEnemyMonster();
UI.drawActiveMonster();
UI.drawActiveTechniques();
- UI.elements.money.textContent = state.money;
+ UI.elements.money.textContent = `${state.money} €`;
},
/**
@@ -41,15 +63,13 @@ const Game = {
* @param {Monster} target
*/
async useTechnique (technique, user, target) {
+ technique.use();
+
if (!Game.didTechniqueHit) {
UI.drawDamageMiss(UI.createDamageMiss());
return;
}
- if (state.activeMonster.hp === state.activeMonster.stats.hp) {
- state.activeMonster.hp = 1;
- }
-
for (const techniqueEffect of technique.effects) {
// damage
@@ -62,15 +82,24 @@ const Game = {
UI.applyMultiplierToDamage(damageNode, simpleDamageMultiplier(state.activeTechnique.types, state.enemy.monster.types));
UI.applyTechniqueToDamage(damageNode, state.activeTechnique);
UI.drawDamage(damageNode);
+ UI.drawTechniqueAnimation();
});
}
else if (techniqueEffect === 'money') {
- state.money += Math.floor(Math.random() * target.level);
+ Game.phases.action.push(() => {
+ const money = Math.max(1, Math.floor(Math.random() * target.level));
+ state.money += money;
+
+ const damageNode = UI.createDamage(`${money} €`);
+ UI.applyTechniqueToDamage(damageNode, state.activeTechnique);
+ UI.drawDamage(damageNode);
+ UI.drawTechniqueAnimation();
+ });
}
else if (techniqueEffect === 'enhance') {
- UI.drawDamage(UI.createDamage('!!ENHANCE!!'));
+ UI.drawTechniqueAnimation();
}
// status effect
@@ -81,7 +110,10 @@ const Game = {
const statusEffect_effect = techniqueEffect.split(',')[0].split(' ')[1].split('_')[1];
const statusEffect = await fetchStatusEffect(statusEffect_effect);
- statusEffect.issuer = user;
+
+ if (statusEffect.slug === 'lifeleech') {
+ statusEffect.issuer = user;
+ }
let recipient;
if (statusEffect_recipient === 'user') {
@@ -108,6 +140,11 @@ const Game = {
}
},
+ rechargeTechnique () {
+ const feedbackNode = UI.createActionFeedback('recharge');
+ UI.drawActionFeedback(feedbackNode);
+ },
+
/**
* @param {Monster} monster
*/
@@ -165,9 +202,9 @@ const Game = {
Game.phases.postAction.push(() => {
monster.hp += statusEffectHeal;
- const damageNode = UI.createDamage(statusEffectHeal);
- UI.applyStatusEffectToDamage(damageNode, monster.statusEffect);
- UI.drawDamage(damageNode);
+ const feedbackNode = UI.createActionFeedback(statusEffectHeal);
+ UI.applyStatusEffectToDamage(feedbackNode, monster.statusEffect);
+ UI.drawActionFeedback(feedbackNode);
});
}
@@ -255,28 +292,11 @@ const Game = {
const accuracy = Math.random();
Game.didTechniqueHit = state.activeTechnique.accuracy >= accuracy;
- await Game.useTechnique(state.activeTechnique, state.activeMonster, state.enemy.monster);
-
- Game.phases.postAction.push(async () => {
- // enemy defeated
- if (state.enemy.monster.hp <= 0) {
- // money
- state.money += state.enemy.monster.level * state.enemy.monster.moneyModifier;
-
- // exp
- state.activeMonster.exp += calculateAwardedExperience(state.enemy.monster, [state.activeMonster])[0];
-
- if (state.activeMonster.canLevelUp()) {
- state.activeMonster.levelUp();
- }
- if (state.activeMonster.canEvolve()) {
- await fetchMonster(state.activeMonster.evolutions[0].monster_slug);
- state.activeMonster.evolve();
- }
-
- await Game.spawnEnemyMonster();
- }
- });
+ if (state.activeTechnique.isUsable()) {
+ await Game.useTechnique(state.activeTechnique, state.activeMonster, state.enemy.monster);
+ } else {
+ Game.rechargeTechnique();
+ }
Game.progressTurn();
},
@@ -327,6 +347,10 @@ const Game = {
monsterData.level = monsterState.level;
monsterData.hp = monsterState.hp;
+ if (monsterData.statusEffect && monsterData.statusEffect.slug === 'lifeleech') {
+ monsterData.statusEffect = null;
+ }
+
return monsterData;
};
diff --git a/resources/js/ui.js b/resources/js/ui.js
index f6a36b8..3739ce6 100644
--- a/resources/js/ui.js
+++ b/resources/js/ui.js
@@ -6,16 +6,20 @@ const Template = {
battleExpBar: document.querySelector('#tpl___battle__exp-bar'),
battleDamage: document.querySelector('#tpl___battle__damage'),
- movesetList: document.querySelector('#tpl___moveset__list'),
- movesetItem: document.querySelector('#tpl___moveset__item'),
-
techniques: document.querySelector('#tpl___techniques'),
technique: document.querySelector('#tpl___technique'),
party: document.querySelector('#tpl___party'),
partyMonster: document.querySelector('#tpl___party__monster'),
+ monsterStats: document.querySelector('#tpl___monster-stats'),
+
+ movesetList: document.querySelector('#tpl___moveset__list'),
+ movesetItem: document.querySelector('#tpl___moveset__item'),
+
menuJournal: document.querySelector('#tpl___menu__journal'),
+ dialogSave: document.querySelector('#tpl___dialog__save'),
+ dialogLoad: document.querySelector('#tpl___dialog__load'),
};
const UI = {
@@ -92,11 +96,6 @@ const UI = {
/* Battle */
- /**
- * @type {MouseEvent}
- */
- battleClickEvent: null,
-
techniqueAnimationIsRunning: false,
techniqueAnimationNumber: 0,
techniqueAnimationFps: 20,
@@ -150,6 +149,21 @@ const UI = {
},
/**
+ * @param {string} gender
+ *
+ * @returns {HTMLElement}
+ */
+ createGenderIcon (gender) {
+ const icon = document.createElement('span');
+ icon.textContent = gender === 'male' ? '♂' : gender === 'female' ? '♀' : '⚲';
+ icon.title = slugToName(gender);
+
+ icon.classList.add('gender-icon');
+
+ return icon;
+ },
+
+ /**
* @param {string} type
*
* @returns {HTMLElement}
@@ -186,7 +200,7 @@ const UI = {
const template = UI.createTemplate(Template.battleMonster);
template.querySelector('[data-template-slot="name"]').textContent = monster.name;
- template.querySelector('[data-template-slot="gender"]').textContent = monster.gender === 'male' ? '♂' : monster.gender === 'female' ? '♀' : '⚲';
+ template.querySelector('[data-template-slot="gender"]').innerHTML = UI.createGenderIcon(monster.gender).outerHTML;
template.querySelector('[data-template-slot="level"]').textContent = monster.level;
template.querySelector('[data-template-slot="statusEffect"]').innerHTML = UI.createStatusEffectIcon(monster.statusEffect).outerHTML;
template.querySelector('[data-template-slot="sprite"]').src = `/modules/tuxemon/mods/tuxemon/gfx/sprites/battle/${monster.slug}-front.png`;
@@ -239,10 +253,15 @@ const UI = {
const techniqueNode = UI.createTemplate(Template.technique);
techniqueNode.querySelector('[data-template-slot="name"]').textContent = technique.name;
+ techniqueNode.querySelector('[data-template-slot="recharge"]').textContent = technique.rechargeLength;
techniqueNode.querySelector('[data-template-slot="types"]').innerHTML = technique.types.map((type) => UI.createElementTypeIcon(type).outerHTML).join('');
+ techniqueNode.querySelector('[data-template-slot="range"]').textContent = technique.range;
techniqueNode.querySelector('[data-template-slot="power"]').textContent = technique.power;
techniqueNode.querySelector('[data-template-slot="accuracy"]').textContent = technique.accuracy;
- techniqueNode.querySelector('[data-template-slot="range"]').textContent = technique.range;
+
+ if (!technique.isUsable()) {
+ techniqueNode.setAttribute('disabled', true);
+ }
template.appendChild(techniqueNode);
}
@@ -295,13 +314,16 @@ const UI = {
* @returns {void}
*/
drawTechniqueAnimation () {
+ const x = UI.battleClickEvent.clientX;
+ const y = UI.battleClickEvent.clientY;
+
if (!UI.techniqueAnimationIsRunning && state.activeTechnique.animation && DB.allAnimations[state.activeTechnique.animation]) {
UI.techniqueAnimationIsRunning = true;
const techniqueAnimationLoop = () => {
UI.elements.battleEnemyAnimation.src = `/modules/tuxemon/mods/tuxemon/animations/technique/${state.activeTechnique.animation}_${("00" + UI.techniqueAnimationNumber).slice(-2)}.png`;
- UI.elements.battleEnemyAnimation.style.top = UI.battleClickEvent.clientY - (UI.elements.battleEnemyAnimation.clientHeight / 2);
- UI.elements.battleEnemyAnimation.style.left = UI.battleClickEvent.clientX - (UI.elements.battleEnemyAnimation.clientWidth / 2);
+ UI.elements.battleEnemyAnimation.style.top = y - (UI.elements.battleEnemyAnimation.clientHeight / 2) + 'px';
+ UI.elements.battleEnemyAnimation.style.left = x - (UI.elements.battleEnemyAnimation.clientWidth / 2) + 'px';
// console.log(UI.elements.battleEnemyAnimation.src);
UI.techniqueAnimationNumber++;
@@ -323,32 +345,46 @@ const UI = {
/* Battle - Damage */
+ /**
+ * @type {MouseEvent}
+ */
+ battleClickEvent: null,
+
damageHighlightClickDuration: 0.1,
damageHighlightClickTimeout: null,
/**
- * @param {number|string} damage
+ * @param {any} feedback
*
* @returns {HTMLElement}
*/
- createDamage (damage) {
- const damageNode = UI.createTemplate(Template.battleDamage);
- damageNode.innerHTML = damage;
+ createActionFeedback (feedback) {
+ const feedbackNode = UI.createTemplate(Template.battleDamage);
+ feedbackNode.innerHTML = feedback;
- damageNode.style.top = UI.battleClickEvent.pageY - UI.elements.battleEnemy.offsetTop + (Math.random() * 40 - 20);
- damageNode.style.left = UI.battleClickEvent.pageX - UI.elements.battleEnemy.offsetLeft + (Math.random() * 40 - 20);
+ feedbackNode.style.top = UI.battleClickEvent.pageY - UI.elements.battleEnemy.offsetTop + (Math.random() * 40 - 20) + 'px';
+ feedbackNode.style.left = UI.battleClickEvent.pageX - UI.elements.battleEnemy.offsetLeft + (Math.random() * 40 - 20) + 'px';
- damageNode.dataset.duration = 2;
- damageNode.style.animationDuration = `${damageNode.dataset.duration}s`;
+ feedbackNode.dataset.duration = 2;
+ feedbackNode.style.animationDuration = `${feedbackNode.dataset.duration}s`;
- return damageNode;
+ return feedbackNode;
+ },
+
+ /**
+ * @param {number|string} damage
+ *
+ * @returns {HTMLElement}
+ */
+ createDamage (damage) {
+ return UI.createActionFeedback(damage);
},
/**
* @returns {HTMLElement}
*/
createDamageMiss () {
- return UI.createDamage('MISS!');
+ return UI.createActionFeedback('MISS!');
},
/**
@@ -392,23 +428,27 @@ const UI = {
/**
* @param {HTMLElement} damageNode
*/
+ drawActionFeedback (node) {
+ UI.elements.battleEnemy.appendChild(node);
+ setTimeout(() => node.remove(), (node.dataset.duration * 1000) - 500);
+ },
+
+ /**
+ * @param {HTMLElement} damageNode
+ */
drawDamage (damageNode) {
- UI.elements.battleEnemy.appendChild(damageNode);
- setTimeout(() => damageNode.remove(), (damageNode.dataset.duration * 1000) - 500);
+ UI.drawActionFeedback(damageNode);
UI.elements.battleEnemySprite.classList.add('damaged');
clearTimeout(UI.damageHighlightClickTimeout);
UI.damageHighlightClickTimeout = setTimeout(() => UI.elements.battleEnemySprite.classList.remove('damaged'), UI.damageHighlightClickDuration * 1000);
-
- UI.drawTechniqueAnimation();
},
/**
* @param {HTMLElement} damageNode
*/
drawDamageMiss (damageNode) {
- UI.elements.battleEnemy.appendChild(damageNode);
- setTimeout(() => damageNode.remove(), (damageNode.dataset.duration * 1000) - 500);
+ UI.drawActionFeedback(damageNode);
},
@@ -428,6 +468,10 @@ const UI = {
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}`;
partyMonster.addEventListener('click', async (event) => {
// bubble up to partyNode
@@ -495,7 +539,7 @@ const UI = {
UI.drawPopup(popup);
},
- openJournalMenu () { // TODO
+ openJournalMenu () {
const popup = UI.createPopup();
const journal = UI.createTemplate(Template.menuJournal);
@@ -511,28 +555,32 @@ const UI = {
UI.drawPopup(popup);
},
- openSaveDialog () { // TODO
+ openSaveDialog () {
const popup = UI.createPopup();
+ const dialog = UI.createTemplate(Template.dialogSave);
- const textarea = document.createElement('textarea');
- textarea.value = Game.save();
+ dialog.querySelector('[data-template-slot="saveData"]').value = Game.save();
+ dialog.querySelector('[data-template-slot="saveClipboard"]').addEventListener('click', () => {
+ alert('Saved to clipboard!');
+ });
- popup.querySelector('.popup').appendChild(textarea);
+ popup.querySelector('.popup').appendChild(dialog);
UI.drawPopup(popup);
},
- openLoadDialog () { // TODO
+ openLoadDialog () {
const popup = UI.createPopup();
+ const dialog = UI.createTemplate(Template.dialogLoad);
- const textarea = document.createElement('textarea');
-
- const loadButton = document.createElement('button');
- loadButton.textContent = "Load";
- loadButton.addEventListener('click', () => Game.load(textarea.value.trim()));
+ dialog.querySelector('[data-template-slot="load"]').addEventListener('click', () => {
+ Game.load(
+ dialog.querySelector('[data-template-slot="saveData"]').value.trim()
+ );
- popup.querySelector('.popup').appendChild(textarea);
- popup.querySelector('.popup').appendChild(loadButton);
+ document.querySelectorAll('.popup__overlay').forEach((element) => element.remove())
+ });
+ popup.querySelector('.popup').appendChild(dialog);
UI.drawPopup(popup);
},
@@ -545,12 +593,20 @@ const UI = {
* @returns {HTMLElement}
*/
createStatsMenu (monster) { // TODO
- const template = document.createElement('div');
- template.textContent = "select moves for " + monster.name;
- template.style.width = '90vw';
- template.style.height = '90vh';
+ const template = UI.createTemplate(Template.monsterStats);
- template.addEventListener('click', () => UI.openMovesetSelection(monster));
+ template.querySelector('[data-template-slot="name"]').textContent = monster.name;
+ template.querySelector('[data-template-slot="gender"]').innerHTML = UI.createGenderIcon(monster.gender).outerHTML;
+ template.querySelector('[data-template-slot="level"]').textContent = monster.level;
+ template.querySelector('[data-template-slot="types"]').innerHTML = monster.types.map((type) => UI.createElementTypeIcon(type).outerHTML).join('');
+
+ template.querySelector('[data-template-slot="stats.melee"]').textContent = monster.stats.melee;
+ template.querySelector('[data-template-slot="stats.armour"]').textContent = monster.stats.armour;
+ template.querySelector('[data-template-slot="stats.ranged"]').textContent = monster.stats.ranged;
+ template.querySelector('[data-template-slot="stats.dodge"]').textContent = monster.stats.dodge;
+ template.querySelector('[data-template-slot="stats.speed"]').textContent = monster.stats.speed;
+
+ template.querySelector('[data-template-slot="techniques"]').addEventListener('click', () => UI.openMovesetSelection(monster));
return template;
},
@@ -566,7 +622,7 @@ const UI = {
const technique = await fetchTechnique(move.technique);
const movesetItemNode = UI.createTemplate(Template.movesetItem);
- movesetItemNode.querySelector('[data-template-slot="name"]').textContent = slugToName(technique.slug);
+ movesetItemNode.querySelector('[data-template-slot="name"]').textContent = technique.name;
movesetItemNode.querySelector('[data-template-slot="types"]').innerHTML = technique.types.map((type) => UI.createElementTypeIcon(type).outerHTML).join('');
movesetItemNode.querySelector('[data-template-slot="power"]').textContent = technique.power;
movesetItemNode.querySelector('[data-template-slot="level"]').textContent = move.level_learned;
@@ -587,6 +643,10 @@ const UI = {
return false;
}
+ if (monster.activeTechniques.length === 4 && !movesetItemNode.hasAttribute('selected')) {
+ return;
+ }
+
// un/select
movesetItemNode.toggleAttribute('selected');