summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--index.html4
-rw-r--r--resources/css/menu.css8
-rw-r--r--resources/js/game.js230
-rw-r--r--resources/js/main.js2
-rw-r--r--resources/js/ui.js140
5 files changed, 258 insertions, 126 deletions
diff --git a/index.html b/index.html
index 7564564..329be97 100644
--- a/index.html
+++ b/index.html
@@ -59,7 +59,7 @@
<template id="tpl___popup">
<div class="popup__overlay">
- <div class="popup"></div>
+ <div data-template-slot="content" class="popup"></div>
</div>
</template>
@@ -132,7 +132,7 @@
<div></div>
</template>
<template id="tpl___technique">
- <div class="techniques__technique">
+ <div data-game-element-type="menuBattleTechniquesTechnique" class="techniques__technique">
<div>
<div data-template-slot="name"></div>
</div>
diff --git a/resources/css/menu.css b/resources/css/menu.css
index 1c5fb76..eee0b5f 100644
--- a/resources/css/menu.css
+++ b/resources/css/menu.css
@@ -85,6 +85,14 @@
+.monster-selection {
+ display: grid;
+ grid-template-columns: 1fr 1fr 1fr;
+}
+
+
+
+
#status {
color: #fff;
background-color: #000;
diff --git a/resources/js/game.js b/resources/js/game.js
index d31d6e5..fad882b 100644
--- a/resources/js/game.js
+++ b/resources/js/game.js
@@ -22,6 +22,8 @@ const Game = {
isInBattle: false,
didTechniqueHit: false,
+ /* Battle */
+
async progressTurn () {
Game.isProgressingTurn = true;
Memory.state.turn++;
@@ -106,8 +108,37 @@ const Game = {
}
Game.removePhaseEvents('action', 'opponent');
- Game.playerIsChoosingNextMonster = true;
- UI.openPartyMenu();
+ // whole party defeated
+ if (!Memory.state.player.monsters.some((monster) => monster.hp > 0)) {
+ if (Game.isBattleType('trainer')) {
+ if (Memory.state.currentArea.encounters.length > 0) {
+ await Game.encounterWildMonster();
+ } else {
+ await Game.encounterTrainer();
+ }
+ }
+
+ else if (Game.isBattleType('monster')) {
+ if (Memory.state.currentArea.monsterProgress < Memory.state.currentArea.requiredEncounters) {
+ Memory.state.currentArea.monsterProgress = 0;
+ UI.drawStatus();
+ }
+
+ await Game.encounterWildMonster();
+ }
+
+ // heal all monsters full
+ for (const monster of Memory.state.player.monsters) {
+ monster.hp = monster.stats.hp;
+ }
+ }
+
+ // party members still left
+ else {
+ Game.playerIsChoosingNextMonster = true;
+ const monsterSelectionNode = UI.createPlayerDefeatedMonsterSelection();
+ UI.openPlayerDefeatedMonsterSelection(monsterSelectionNode);
+ }
}
},
@@ -325,6 +356,11 @@ const Game = {
const statusEffectLeech = Math.floor(monster.stats.hp / 16);
Game.addPhaseEvent(Game.phases.postAction, monster, () => {
+ // if issuer is defeated => don't
+ if (monster.statusEffect.issuer.hp <= 0) {
+ return;
+ }
+
monster.hp -= statusEffectLeech;
monster.statusEffect.issuer.hp += statusEffectLeech;
@@ -442,6 +478,7 @@ const Game = {
return;
}
+ // technique
Game.doBattleAnimation = false;
await Game.tryUseTechnique(
await fetchTechnique(Memory.state.opponent.activeMonster.getLearnableTechniques()[Math.floor(Math.random() * Memory.state.opponent.activeMonster.getLearnableTechniques().length)].technique),
@@ -452,6 +489,10 @@ const Game = {
await Game.progressTurn();
+ // item
+ if (Memory.state.opponent.inventory.length > 0) {
+ }
+
Game.opponentActionTimeout = null;
}, Math.max(500, 2000 - (speedDifference * 10)));
console.log(
@@ -473,7 +514,7 @@ const Game = {
}
let target = event.target;
- while (!target.classList.contains('techniques__technique')) {
+ while (target.dataset.gameElementType !== 'menuBattleTechniquesTechnique') {
target = target.parentNode;
}
@@ -492,6 +533,81 @@ const Game = {
}));
},
+
+ /* Progression */
+
+ async encounterWildMonster () {
+ const randomMonster = Memory.state.currentArea.encounters[Math.floor(Math.random() * Memory.state.currentArea.encounters.length)];
+ const randomLevel = Math.floor(Math.random() * (randomMonster.level_range[1] - randomMonster.level_range[0]) + randomMonster.level_range[0]);
+
+ const monster = await fetchMonster(randomMonster.monster);
+ monster.level = randomLevel;
+
+ const wildMonster = new Trainer({ monsters: [monster] });
+ wildMonster.type = 'monster';
+ await wildMonster.initialize();
+ Memory.state.opponent = wildMonster;
+
+ UI.drawOpponentMonster();
+ },
+
+ async encounterTrainer () {
+ Game.clearCurrentTurn();
+
+ const nextTrainer = Memory.state.currentArea.trainers[Memory.state.currentArea.trainerProgress];
+
+ const trainer = new Trainer(nextTrainer);
+ if (nextTrainer.name === 'Rival') {
+ trainer.monsters.push(Memory.state.rivalMonster);
+ }
+ await trainer.initialize()
+ Memory.state.opponent = trainer;
+
+ UI.drawOpponentMonster();
+ UI.drawStatus();
+ },
+
+ async encounterNextTrainerMonster () {
+ const activeMonsterIdx = Memory.state.opponent.monsters.indexOf(Memory.state.opponent.activeMonster);
+ Memory.state.opponent.activeMonster = Memory.state.opponent.monsters[activeMonsterIdx + 1];
+
+ UI.drawOpponentMonster();
+ },
+
+ async progressToNextArea () {
+ Game.isLoadingArea = true;
+ Game.clearCurrentTurn();
+
+ const currentArea = Memory.state.currentArea;
+ const nextArea = await fetchArea(currentArea.nextArea);
+
+ await Game.jumpToArea(nextArea);
+
+ if (nextArea.encounters.length > 0) {
+ await Game.encounterWildMonster();
+ } else {
+ await Game.encounterTrainer();
+ }
+
+ UI.drawStatus();
+
+ Game.isLoadingArea = false;
+ },
+
+ /**
+ * @param {Area} area
+ */
+ async jumpToArea (area) {
+ Game.clearCurrentTurn();
+
+ Memory.state.currentArea = area;
+
+ UI.drawArea(area);
+ },
+
+
+ /* Menu - Inventory */
+
/**
* @param {InventoryItem} item
* @param {Monster} monster
@@ -571,22 +687,8 @@ const Game = {
inventory.splice(inventory.indexOf(item), 1);
},
- /**
- * @param {string} type
- *
- * @returns {boolean}
- */
- isBattleType (type) {
- return Memory.state.opponent.type === type;
- },
- /**
- * @param {Monster} monster
- */
- async evolveMonster (monster) {
- await fetchMonster(monster.evolutions[0].monster_slug);
- monster.evolve(monster.evolutions[0]);
- },
+ /* Menu - Catch */
/**
* @returns {boolean}
@@ -620,82 +722,44 @@ const Game = {
await Game.progressTurn();
},
- getStageOfDaySimple () {
- const hours = (new Date()).getHours();
- if (hours >= 6 && hours < 18) {
- return 'day';
- } else {
- return 'night';
- }
- },
+
+ /* Helper */
/**
- * @param {Area} area
+ * @param {Monster} monster
*/
- async jumpToArea (area) {
- Game.clearCurrentTurn();
+ setActivePlayerMonster (monster) {
+ Memory.state.player.activeMonster = monster;
+ Memory.state.activeTechnique = Memory.state.player.activeMonster.activeTechniques[0];
- Memory.state.currentArea = area;
-
- UI.drawArea(area);
+ UI.drawActiveMonster();
+ UI.drawActiveTechniques();
},
- async progressToNextArea () {
- Game.isLoadingArea = true;
- Game.clearCurrentTurn();
-
- const currentArea = Memory.state.currentArea;
- const nextArea = await fetchArea(currentArea.nextArea);
-
- await Game.jumpToArea(nextArea);
-
- if (nextArea.encounters.length > 0) {
- await Game.encounterWildMonster();
- } else {
- await Game.encounterTrainer();
- }
-
- UI.drawStatus();
-
- Game.isLoadingArea = false;
+ /**
+ * @param {Monster} monster
+ */
+ async evolveMonster (monster) {
+ await fetchMonster(monster.evolutions[0].monster_slug);
+ monster.evolve(monster.evolutions[0]);
},
- async encounterWildMonster () {
- const randomMonster = Memory.state.currentArea.encounters[Math.floor(Math.random() * Memory.state.currentArea.encounters.length)];
- const randomLevel = Math.floor(Math.random() * (randomMonster.level_range[1] - randomMonster.level_range[0]) + randomMonster.level_range[0]);
-
- const monster = await fetchMonster(randomMonster.monster);
- monster.level = randomLevel;
-
- const wildMonster = new Trainer({ monsters: [monster] });
- wildMonster.type = 'monster';
- await wildMonster.initialize();
- Memory.state.opponent = wildMonster;
-
- UI.drawOpponentMonster();
+ /**
+ * @param {string} type
+ *
+ * @returns {boolean}
+ */
+ isBattleType (type) {
+ return Memory.state.opponent.type === type;
},
- async encounterTrainer () {
- Game.clearCurrentTurn();
-
- const nextTrainer = Memory.state.currentArea.trainers[Memory.state.currentArea.trainerProgress];
-
- const trainer = new Trainer(nextTrainer);
- if (nextTrainer.name === 'Rival') {
- trainer.monsters.push(Memory.state.rivalMonster);
+ getStageOfDaySimple () {
+ const hours = (new Date()).getHours();
+ if (hours >= 6 && hours < 18) {
+ return 'day';
+ } else {
+ return 'night';
}
- await trainer.initialize()
- Memory.state.opponent = trainer;
-
- UI.drawOpponentMonster();
- UI.drawStatus();
- },
-
- async encounterNextTrainerMonster () {
- const activeMonsterIdx = Memory.state.opponent.monsters.indexOf(Memory.state.opponent.activeMonster);
- Memory.state.opponent.activeMonster = Memory.state.opponent.monsters[activeMonsterIdx + 1];
-
- UI.drawOpponentMonster();
},
};
diff --git a/resources/js/main.js b/resources/js/main.js
index 8622731..4fd9c62 100644
--- a/resources/js/main.js
+++ b/resources/js/main.js
@@ -15,7 +15,7 @@
});
await Memory.state.player.initialize();
- Memory.state.activeTechnique = Memory.state.player.activeMonster.activeTechniques[0];
+ Game.setActivePlayerMonster(Memory.state.player.monsters[0]);
Memory.state.activeBall = Memory.state.player.inventory[0]; // tuxeball
Memory.state.rivalMonster = await fetchMonster(possibleStarterMonsters[Math.round(Math.random() * (possibleStarterMonsters.length - 1))]);
diff --git a/resources/js/ui.js b/resources/js/ui.js
index c67e2f0..820a49c 100644
--- a/resources/js/ui.js
+++ b/resources/js/ui.js
@@ -350,6 +350,20 @@ const UI = {
},
/**
+ * @returns {HTMLElement}
+ */
+ createPlayerDefeatedMonsterSelection () {
+ const monsterSelectionNode = UI.createMonsterSelection(Memory.state.player.monsters.filter((monster) => monster.hp > 0));
+
+ monsterSelectionNode.addEventListener('monster:selected', (event) => {
+ Game.setActivePlayerMonster(event.detail.monster);
+ Game.playerIsChoosingNextMonster = false;
+ });
+
+ return monsterSelectionNode;
+ },
+
+ /**
* @param {HTMLElement} battleMonsterNode
*/
drawOpponentMonster () {
@@ -454,6 +468,20 @@ const UI = {
UI.drawStatus();
},
+ /**
+ * @param {HTMLElement} monsterSelectionNode
+ */
+ openPlayerDefeatedMonsterSelection (monsterSelectionNode) {
+ const popup = UI.createPopup().cloneNode(true); // remove event listeners
+
+ monsterSelectionNode.addEventListener('monster:selected', () => {
+ popup.remove();
+ });
+
+ popup.querySelector('[data-template-slot="content"]').appendChild(monsterSelectionNode);
+ UI.drawPopup(popup);
+ },
+
/* Battle - Action Feedback */
@@ -572,6 +600,52 @@ const UI = {
inventorySelectionMode: 'use',
+ /**
+ * @param {Monster[]} monsters
+ *
+ * @returns {HTMLElement}
+ */
+ createMonsterSelection (monsters) {
+ const template = document.createElement('div');
+ template.classList.add('monster-selection');
+
+ for (const monster of monsters) {
+ const monsterNode = UI.createMonsterSelectionMonster(monster);
+
+ monsterNode.addEventListener('monster:selected', (event) => {
+ template.dispatchEvent(new CustomEvent('monster:selected', {
+ detail: {
+ node: monsterNode,
+ monster: event.detail.monster,
+ },
+ }));
+ });
+
+ template.appendChild(monsterNode);
+ }
+
+ return template;
+ },
+
+ /**
+ * @param {Monster} monster
+ *
+ * @returns {HTMLElement}
+ */
+ createMonsterSelectionMonster (monster) {
+ const template = UI.createPartyMonster(monster);
+
+ template.addEventListener('click', () => {
+ template.dispatchEvent(new CustomEvent('monster:selected', {
+ detail: {
+ monster: monster,
+ },
+ }));
+ });
+
+ return template;
+ },
+
drawStatus () {
const currentArea = Memory.state.currentArea;
@@ -618,13 +692,8 @@ const UI = {
}
if (UI.partySelectionMode === 'select') {
- Memory.state.player.activeMonster = monster;
- Memory.state.activeTechnique = Memory.state.player.activeMonster.activeTechniques[0];
-
- UI.drawActiveMonster();
- UI.drawActiveTechniques();
+ Game.setActivePlayerMonster(monster);
- Game.playerIsChoosingNextMonster = false;
popup.remove();
}
else if (UI.partySelectionMode === 'stats') {
@@ -998,7 +1067,7 @@ const UI = {
const inventoryItemNode = UI.createTemplate(Template.inventoryItem);
inventoryItemNode.title = item.description;
- inventoryItemNode.dataset.templateItem = item.slug;
+ inventoryItemNode.dataset.inventoryItem = item.slug;
inventoryItemNode.querySelector('[data-template-slot="sprite"]').src = `/modules/tuxemon/mods/tuxemon/${item.sprite}`;
inventoryItemNode.querySelector('[data-template-slot="name"]').textContent = item.name;
@@ -1026,7 +1095,7 @@ const UI = {
* @param {InventoryItem} item
*/
redrawInventoryItem (item) {
- const itemNode = document.querySelector(`#inventory *[data-template-item="${item.slug}"]`);
+ const itemNode = document.querySelector(`#inventory *[data-inventory-item="${item.slug}"]`);
if (item.quantity === 0) {
itemNode.remove();
}
@@ -1042,47 +1111,38 @@ const UI = {
* @returns {HTMLElement}
*/
createItemMonsterSelection (item, monsters) {
- const template = document.createElement('div');
+ const template = UI.createMonsterSelection(
+ monsters.filter((monster) => Game.canUseItem(item, monster))
+ );
- /**
- * @param {Monster} monster
- *
- * @returns {(HTMLElement|null)}
- */
- const createMonsterNode = (monster) => {
- if (!Game.canUseItem(item, monster)) {
- return null;
- }
+ const onMonsterSelectd = async (event) => {
+ const monster = event.detail.monster;
+ const monsterNode = event.detail.node || event.target;
+
+ await Game.useItem(item, monster);
- const monsterNode = UI.createPartyMonster(monster);
+ if (item.quantity === 0) {
+ Game.removeItemFromInventory(Memory.state.player.inventory, item);
+ template.dispatchEvent(new Event('item:isExhausted'));
+ }
- monsterNode.addEventListener('click', async () => {
- await Game.useItem(item, monster);
+ else {
+ const canStillUseItem = Game.canUseItem(item, monster);
+ if (canStillUseItem) {
+ const replacingMonsterNode = UI.createMonsterSelectionMonster(monster);
+ replacingMonsterNode.addEventListener('monster:selected', onMonsterSelectd);
- if (item.quantity === 0) {
- Game.removeItemFromInventory(Memory.state.player.inventory, item);
- template.dispatchEvent(new Event('item:isExhausted'));
+ monsterNode.replaceWith(replacingMonsterNode);
} else {
- const replacingMonsterNode = createMonsterNode(monster);
- if (replacingMonsterNode) {
- monsterNode.replaceWith(replacingMonsterNode);
- } else {
- monsterNode.remove();
- template.dispatchEvent(new Event('monster:lostCondition'));
- }
+ monsterNode.remove();
+ template.dispatchEvent(new Event('monster:lostCondition'));
}
+ }
- UI.redrawInventoryItem(item);
- });
-
- return monsterNode;
+ UI.redrawInventoryItem(item);
};
- for (const monster of monsters) {
- const monsterNode = createMonsterNode(monster);
-
- monsterNode && template.appendChild(monsterNode);
- }
+ template.addEventListener('monster:selected', onMonsterSelectd);
return template;
},