summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--index.html24
-rw-r--r--resources/css/battle.css59
-rw-r--r--resources/css/menu.css18
-rw-r--r--resources/js/classes/State.js17
-rw-r--r--resources/js/db.js2
-rw-r--r--resources/js/game.js89
-rw-r--r--resources/js/helpers.js2
-rw-r--r--resources/js/memory.js4
-rw-r--r--resources/js/ui.js40
9 files changed, 213 insertions, 42 deletions
diff --git a/index.html b/index.html
index 486c5fd..4f498c6 100644
--- a/index.html
+++ b/index.html
@@ -22,12 +22,14 @@
<div id="techniques"></div>
+ <div id="log"></div>
+
<div id="status">
<span>Money: <span data-template-slot="money"></span></span>
- <span>Monster Progress: <span data-template-slot="monsterProgress"></span></span>
- <span>Trainer Progress: <span data-template-slot="trainerProgress"></span></span>
- <button data-template-slot="nextTrainer">&rArr; Next Trainer</button>
- <button data-template-slot="nextArea">&rArr; Next Area</button>
+ <span><img src="/modules/tuxemon/mods/tuxemon/gfx/ui/menu/tuxemon.png" title="Monster Progress" /> <span data-template-slot="monsterProgress"></span></span>
+ <span><img src="/modules/tuxemon/mods/tuxemon/gfx/ui/menu/player.png" title="Trainer Progress" style="filter: invert(1);" /> <span data-template-slot="trainerProgress"></span></span>
+ <button data-template-slot="nextTrainer" class="menu-button">&rArr; Next Trainer</button>
+ <button data-template-slot="nextArea" class="menu-button">&rArr; Next Area</button>
</div>
<div id="menu">
@@ -43,8 +45,13 @@
<img src="/modules/tuxemon/mods/tuxemon/gfx/ui/item/backpack.png" title="Inventory" width="64" height="64" />
</div>
+ <div id="menu__log">
+ <img src="/modules/tuxemon/mods/tuxemon/gfx/ui/menu/journal.png" title="Log" width="64" height="64" />
+ </div>
+
<div id="menu__journal">
- <img src="/modules/tuxemon/mods/tuxemon/gfx/ui/menu/journal.png" title="Journal" width="64" height="64" />
+ <img src="/modules/tuxemon/mods/tuxemon/gfx/ui/menu/save.png" title="Save" width="64" height="64" />
+ <img src="/modules/tuxemon/mods/tuxemon/gfx/ui/menu/load.png" title="Load" width="64" height="64" />
</div>
<div id="menu__settings">
@@ -98,9 +105,10 @@
</div>
</div>
<div class="battle__monster-visual">
- <div class="battle__monster-sprite">
- <img data-template-slot="sprite" class="battle__monster-img" src="" draggable="false" />
- <img data-template-slot="trainerSprite" class="battle__monster__trainer-sprite" src="" draggable="false" />
+ <img data-template-slot="sprite" class="battle__monster-sprite" src="" draggable="false" />
+ <div class="battle__trainer-visual">
+ <img data-template-slot="trainerSprite" class="battle__trainer-sprite" src="" draggable="false" />
+ <div data-template-slot="trainerName"></div>
</div>
</div>
</div>
diff --git a/resources/css/battle.css b/resources/css/battle.css
index 1e52802..748dad1 100644
--- a/resources/css/battle.css
+++ b/resources/css/battle.css
@@ -66,39 +66,43 @@
.exp-label {
margin-right: 0.5rem;
}
+
+
.battle__monster-visual {
flex-grow: 1;
flex-basis: 50%;
position: relative;
-}
-
-.battle__monster-sprite {
text-align: center;
}
-.battle__monster-img {
+.battle__monster-sprite {
cursor: pointer;
transition-property: filter;
width: 90px;
}
-.battle__monster-img.damaged {
- filter: brightness(2);
-}
-.battle__technique-animation {
- position: fixed;
- z-index: 10;
+.battle__monster-sprite.damaged {
+ filter: brightness(2);
}
-.battle__monster__trainer-sprite {
+.battle__trainer-visual {
position: absolute;
top: 0;
right: 0;
+}
+
+.battle__trainer-sprite {
width: 120px;
max-width: 25vw;
}
+
+.battle__technique-animation {
+ position: fixed;
+ z-index: 10;
+}
+
.battle__monster-technique {
background-color: beige;
border: 2px solid #000;
@@ -123,13 +127,7 @@
}
@media (max-width: 600px) {
- .battle__monster--has-trainer-sprite .battle__monster-sprite {
- width: 30vw;
- }
-}
-@media (max-width: 450px) {
- .battle__monster--has-trainer-sprite .battle__monster-sprite {
- width: auto;
+ .battle__monster--has-trainer-sprite .battle__monster-visual {
text-align: left;
}
}
@@ -218,7 +216,6 @@
#techniques {
display: grid;
grid-template-columns: 1fr 1fr;
- grid-template-rows: 1fr 1fr;
background: beige;
}
@@ -253,6 +250,30 @@
}
+
+
+#log {
+ height: 20vh;
+ background-color: #fff;
+ border: 0.5rem solid rgba(0, 0, 0, 0.75);
+ padding: 0.5rem;
+ line-height: 1.75rem;
+ font-size: 1.25rem;
+ overflow-y: scroll;
+
+ transition-property: height, border-width, padding;
+ transition-duration: 0.25s;
+}
+
+#log.log--is-hidden {
+ height: 0;
+ border-width: 0;
+ padding: 0;
+}
+
+
+
+
.action-feedback {
position: absolute;
z-index: 11;
diff --git a/resources/css/menu.css b/resources/css/menu.css
index eee0b5f..84c6c77 100644
--- a/resources/css/menu.css
+++ b/resources/css/menu.css
@@ -96,9 +96,25 @@
#status {
color: #fff;
background-color: #000;
- padding: 0.25rem;
+ padding: 0.5rem;
+
display: flex;
justify-content: space-between;
+ align-items: center;
+
+ font-size: 1.25rem;
+}
+
+#status > span {
+ display: flex;
+ align-items: center;
+}
+#status > span > span {
+ margin-left: 0.5rem;
+}
+
+#status .menu-button:hover {
+ background-color: rgba(255, 255, 255, 0.5);
}
diff --git a/resources/js/classes/State.js b/resources/js/classes/State.js
index 6180c52..b7e9f5d 100644
--- a/resources/js/classes/State.js
+++ b/resources/js/classes/State.js
@@ -1,8 +1,17 @@
class State {
- /**
- * @type {string}
- */
- language = 'en_US';
+ Settings = {
+ /**
+ * @type {string}
+ */
+ language: 'en_US',
+
+ colors: {
+ player: '#00ff00',
+ player: '#ff0000',
+ },
+
+ logMaxLength: 1000,
+ };
/**
* @type {Object.<string, Area>}
diff --git a/resources/js/db.js b/resources/js/db.js
index aaf5423..5850a01 100644
--- a/resources/js/db.js
+++ b/resources/js/db.js
@@ -84,7 +84,7 @@ async function initializeDB () {
DB.elements[element] = await fetch(`/modules/tuxemon/mods/tuxemon/db/element/${element}.json`).then((response) => response.json());
}
- await fetchTranslation(Memory.state.language);
+ await fetchTranslation(Memory.state.Settings.language);
}
/**
diff --git a/resources/js/game.js b/resources/js/game.js
index fad882b..d5e8669 100644
--- a/resources/js/game.js
+++ b/resources/js/game.js
@@ -14,6 +14,8 @@ const Game = {
},
},
+ logMessages: [],
+
isLoadingArea: false,
isProgressingTurn: false,
playerIsChoosingNextMonster: false,
@@ -32,6 +34,8 @@ const Game = {
await Game.applyStatusEffect(Memory.state.opponent.activeMonster);
await Game.applyStatusEffect(Memory.state.player.activeMonster);
+ Game.logTurn('begin');
+
// Phases
for (const phaseKey of Object.keys(Game.phases)) {
for (const event of Game.phases[phaseKey].player) {
@@ -53,6 +57,8 @@ const Game = {
Game.phases[phaseKey].opponent = [];
}
+ Game.logTurn('end');
+
UI.progressTurn();
Game.isProgressingTurn = false;
},
@@ -186,6 +192,14 @@ const Game = {
async tryUseTechnique (technique, user, target) {
let canUse = true;
+ const log = (message, indentation) => {
+ Game.addPhaseEvent(Game.phases.preAction, user, () => {
+ Game.log(message, indentation);
+ });
+ };
+
+ log(`${user.name} attempts to use ${technique.name}!`);
+
// recharge
if (technique.isRecharging()) {
if (Game.doBattleAnimation) {
@@ -194,6 +208,8 @@ const Game = {
UI.drawActionFeedback(feedbackNode);
}
+ log('But has to recharge!', 1);
+
canUse = false;
}
@@ -204,6 +220,8 @@ const Game = {
UI.drawActionFeedback(feedbackNode);
}
+ log('But is nodding off!', 1);
+
canUse = false;
}
@@ -216,6 +234,8 @@ const Game = {
technique.use();
Game.doBattleAnimation && UI.drawDamageMiss(UI.createDamageMiss());
+ log('But missed!', 1);
+
return;
}
@@ -231,6 +251,10 @@ const Game = {
async useTechnique (technique, user, target) {
technique.use();
+ Game.addPhaseEvent(Game.phases.action, user, () => {
+ Game.log(`${user.name} is using ${technique.name}!`);
+ });
+
for (const techniqueEffectCode of technique.effects) {
const techniqueEffect = new TechniqueEffect(techniqueEffectCode);
techniqueEffect.setUser(user);
@@ -250,6 +274,8 @@ const Game = {
UI.drawDamage(damageNode);
UI.drawTechniqueAnimation(technique);
}
+
+ Game.log(`Deals ${damage} to ${target.name}!`, 1);
});
}
@@ -271,7 +297,12 @@ const Game = {
// healing
else if (techniqueEffect.type === 'healing') {
for (const recipient of techniqueEffect.recipients) {
- recipient.hp += (user.level + 7) * technique.healingPower;
+ Game.addPhaseEvent(Game.phases.action, user, () => {
+ const heal = (user.level + 7) * technique.healingPower;
+ recipient.hp += heal;
+
+ Game.log(`Heals ${heal}!`, 1);
+ });
}
}
@@ -293,7 +324,7 @@ const Game = {
statusEffect.issuer = user;
}
- Game.addPhaseEvent(Game.phases.postAction, user, () => {
+ Game.addPhaseEvent(Game.phases.action, user, () => {
// add status effect
const potency = Math.random();
const success = technique.potency >= potency;
@@ -304,6 +335,8 @@ const Game = {
if (recipient.statusEffect) continue;
recipient.statusEffect = statusEffect;
+
+ Game.log(`${techniqueEffect.recipients.map((recipient) => recipient.name).join(', ')} ${techniqueEffect.recipients.length > 1 ? 'are' : 'is'} now ${statusEffect.name}!`, 1);
}
}
});
@@ -327,6 +360,8 @@ const Game = {
// if still 0 turns left after remove action
if (monster.statusEffect.turnsLeft === 0) {
+ Game.log(`${monster.name} is not ${monster.statusEffect.name} anymore!`);
+
monster.statusEffect = null;
} else {
Game.applyStatusEffect(monster);
@@ -336,6 +371,10 @@ const Game = {
return;
}
+ const logStatusIs = () => {
+ Game.log(`${monster.name} is ${monster.statusEffect.name}!`);
+ }
+
// poison / burn
if (monster.statusEffect.slug === 'poison' || monster.statusEffect.slug === 'burn') {
const statusEffectDamage = Math.floor(monster.stats.hp / 8);
@@ -348,6 +387,8 @@ const Game = {
UI.applyStatusEffectToDamage(damageNode, monster.statusEffect);
UI.drawDamage(damageNode);
}
+
+ logStatusIs();
});
}
@@ -369,6 +410,8 @@ const Game = {
UI.applyStatusEffectToDamage(damageNode, monster.statusEffect);
UI.drawDamage(damageNode);
}
+
+ logStatusIs();
});
}
@@ -384,6 +427,8 @@ const Game = {
UI.applyStatusEffectToDamage(feedbackNode, monster.statusEffect);
UI.drawActionFeedback(feedbackNode);
}
+
+ logStatusIs();
});
}
@@ -394,6 +439,8 @@ const Game = {
Game.addPhaseEvent(Game.phases.preAction, monster, () => {
technique.potency = technique.stats.potency * 0.5;
technique.power = technique.stats.power * 0.5;
+
+ logStatusIs();
});
monster.statusEffect.onRemove = () => {
@@ -410,6 +457,8 @@ const Game = {
Game.addPhaseEvent(Game.phases.preAction, monster, () => {
technique.potency = technique.stats.potency * 0.5;
technique.power = technique.stats.power * 0.5;
+
+ logStatusIs();
});
monster.statusEffect.onRemove = () => {
@@ -423,6 +472,10 @@ const Game = {
else if (monster.statusEffect.slug === 'charging') {
const nextStatusEffect = await fetchStatusEffect('chargedup');
+ Game.addPhaseEvent(Game.phases.preAction, monster, () => {
+ logStatusIs();
+ });
+
monster.statusEffect.onRemove = () => {
monster.statusEffect = nextStatusEffect;
};
@@ -438,6 +491,8 @@ const Game = {
Game.addPhaseEvent(Game.phases.preAction, monster, () => {
monster.setStatModifier(statType, modifiedValue);
+
+ logStatusIs();
});
}
@@ -533,6 +588,33 @@ const Game = {
}));
},
+ /**
+ * @param {string} message
+ * @param {number} indentation
+ * @param {string} style
+ */
+ log (message, indentation = 0, style) {
+ Game.logMessages.push({
+ message: message,
+ indentation: indentation,
+ style: style,
+ });
+ UI.drawLog();
+ },
+
+ /**
+ * @param {('begin' | 'end')}
+ */
+ logTurn (state) {
+ Game.log(
+ '- '.repeat(8) + `Turn ${Memory.state.turn} &middot; ${slugToName(state)}` + ' -'.repeat(8),
+ 0,
+ {
+ textAlign: 'center',
+ }
+ );
+ },
+
/* Progression */
@@ -718,8 +800,9 @@ const Game = {
Memory.state.player.monsters.push(caughtMonster);
+ Game.log(`Caught ${caughtMonster.name}!`);
+
await Game.encounterWildMonster();
- await Game.progressTurn();
},
diff --git a/resources/js/helpers.js b/resources/js/helpers.js
index 53a5c87..2395878 100644
--- a/resources/js/helpers.js
+++ b/resources/js/helpers.js
@@ -55,5 +55,5 @@ function randomString () {
* @param {string} msgid
*/
function translate (msgid) {
- return DB.translations[Memory.state.language][msgid];
+ return DB.translations[Memory.state.Settings.language][msgid];
}
diff --git a/resources/js/memory.js b/resources/js/memory.js
index 1732472..550ea55 100644
--- a/resources/js/memory.js
+++ b/resources/js/memory.js
@@ -131,8 +131,8 @@ const Memory = {
*/
const loadedState = JSON.parse(atob(saveData));
- Memory.state.language = loadedState.language;
- await fetchTranslation(Memory.state.language);
+ Memory.state.Settings.language = loadedState.language;
+ await fetchTranslation(Memory.state.Settings.language);
Memory.state.turn = loadedState.turn;
Memory.state.money = loadedState.money;
diff --git a/resources/js/ui.js b/resources/js/ui.js
index 06e55ed..bfd9204 100644
--- a/resources/js/ui.js
+++ b/resources/js/ui.js
@@ -42,6 +42,8 @@ const UI = {
techniques: document.querySelector('#techniques'),
+ log: document.querySelector('#log'),
+
status: document.querySelector('#status'),
nextTrainer: document.querySelector('#status [data-template-slot="nextTrainer"]'),
nextArea: document.querySelector('#status [data-template-slot="nextArea"]'),
@@ -49,6 +51,7 @@ const UI = {
menuParty: document.querySelector('#menu__party'),
menuInventory: document.querySelector('#menu__inventory'),
menuCatch: document.querySelector('#menu__catch'),
+ menuLog: document.querySelector('#menu__log'),
menuJournal: document.querySelector('#menu__journal'),
menuSettings: document.querySelector('#menu__settings'),
},
@@ -299,10 +302,12 @@ const UI = {
if (Game.isBattleType('trainer')) {
battleMonsterNode.classList.add('battle__monster--is-trainer');
+ battleMonsterNode.querySelector('[data-template-slot="trainerName"]').textContent = Memory.state.opponent.name;
if (Memory.state.opponent.sprite) {
battleMonsterNode.classList.add('battle__monster--has-trainer-sprite');
battleMonsterNode.querySelector('[data-template-slot="trainerSprite"]').src = `/modules/tuxemon/mods/tuxemon/gfx/sprites/player/${Memory.state.opponent.sprite}`;
+ battleMonsterNode.querySelector('[data-template-slot="trainerSprite"]').title = Memory.state.opponent.name;
}
}
@@ -456,6 +461,34 @@ const UI = {
requestAnimationFrame(techniqueAnimationLoop);
},
+ drawLog () {
+ if (UI.elements.log.children.length > Memory.state.Settings.logMaxLength) {
+ UI.elements.log.innerHTML = '';
+ }
+
+ for (const message of Game.logMessages) {
+ const textNode = document.createElement('div');
+
+ textNode.innerHTML = '> '.repeat(message.indentation) + message.message;
+
+ if (message.style) {
+ for (const property of Object.keys(message.style)) {
+ const value = message.style[property];
+ textNode.style[property] = value;
+ }
+ }
+
+ UI.elements.log.appendChild(textNode);
+ UI.elements.log.scrollTop = UI.elements.log.scrollHeight;
+ }
+
+ Game.logMessages = [];
+ },
+
+ toggleLog () {
+ UI.elements.log.classList.toggle('log--is-hidden');
+ },
+
/**
* @param {Area} area
*/
@@ -892,7 +925,7 @@ const UI = {
languageOptionNode.value = languageCode;
languageOptionNode.textContent = languageName;
- if (languageCode === Memory.state.language) {
+ if (languageCode === Memory.state.Settings.language) {
languageOptionNode.selected = true;
}
@@ -901,9 +934,9 @@ const UI = {
languageSelectNode.addEventListener('change', async () => {
const selected = [...languageSelectNode.children].find((node) => node.selected === true);
- Memory.state.language = selected.value;
+ Memory.state.Settings.language = selected.value;
- await fetchTranslation(Memory.state.language);
+ await fetchTranslation(Memory.state.Settings.language);
UI.drawOpponentMonster();
UI.drawActiveMonster();
UI.drawActiveTechniques();
@@ -1227,5 +1260,6 @@ const UI = {
// UI element click bindings
UI.elements.menuParty.addEventListener('click', UI.openPartyMenu);
UI.elements.menuInventory.addEventListener('click', UI.openInventoryMenu);
+UI.elements.menuLog.addEventListener('click', UI.toggleLog);
UI.elements.menuJournal.addEventListener('click', UI.openJournalMenu);
UI.elements.menuSettings.addEventListener('click', UI.openSettingsMenu);