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.js154
1 files changed, 107 insertions, 47 deletions
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');