summaryrefslogtreecommitdiff
path: root/resources
diff options
context:
space:
mode:
authorDaniel Weipert <code@drogueronin.de>2023-09-02 14:59:09 +0200
committerDaniel Weipert <code@drogueronin.de>2023-09-02 14:59:09 +0200
commit2030caa0c85102b1cf6131dd9eefef4a347cda42 (patch)
tree9188abac0d7b7730ded1e8e154c3f7c589f785cf /resources
parent1d29ee6d87d3794a9319bca5bf36afdfe176072c (diff)
translations and story
Diffstat (limited to 'resources')
-rw-r--r--resources/css/page.css5
-rw-r--r--resources/js/classes/Npc.js2
-rw-r--r--resources/js/db.js6
-rw-r--r--resources/js/game.js36
-rw-r--r--resources/js/story.js181
-rw-r--r--resources/js/ui.js7
6 files changed, 195 insertions, 42 deletions
diff --git a/resources/css/page.css b/resources/css/page.css
index 2091829..b59ad6d 100644
--- a/resources/css/page.css
+++ b/resources/css/page.css
@@ -47,3 +47,8 @@ svg [data-interactable="false"] {
stroke: transparent;
fill: transparent;
}
+
+svg [data-interactable="false"][data-blackout="true"] {
+ stroke: black;
+ fill: black;
+}
diff --git a/resources/js/classes/Npc.js b/resources/js/classes/Npc.js
index 82dba7e..c13b9b4 100644
--- a/resources/js/classes/Npc.js
+++ b/resources/js/classes/Npc.js
@@ -6,7 +6,7 @@ class Npc {
this.slug = slug;
this.name = translate(slug);
- this.spriteName = DB.npcs[slug]?.template[0].sprite_name;
+ this.spriteName = DB.npcs[slug]?.template[0].combat_front;
}
get sprite () {
diff --git a/resources/js/db.js b/resources/js/db.js
index d564851..aff2c7c 100644
--- a/resources/js/db.js
+++ b/resources/js/db.js
@@ -13,12 +13,18 @@
* @typedef {Object} DB_Story
* @property {number} money
* @property {string} area
+ * @property {boolean} canTriggerMultipleTimes
* @property {Object<string, DB_StoryCharacter>} characters
+ * @property {Object<string, DB_StoryEncounter>} encounters
*
* @typedef {Object} DB_StoryCharacter
* @property {string} slug
* @property {string[]} text
* @property {Object[]} monsters
+ *
+ * @typedef {Object} DB_StoryEncounter
+ * @property {string} slug
+ * @property {number} level
*/
//
diff --git a/resources/js/game.js b/resources/js/game.js
index 6c3a393..309d013 100644
--- a/resources/js/game.js
+++ b/resources/js/game.js
@@ -761,14 +761,6 @@ const Game = {
}
const nextTrainer = Memory.state.currentArea.trainers[nextTrainerIdx];
- if (nextTrainer.name.startsWith('Rival')) {
- for (const idx in nextTrainer.monsters) {
- if (nextTrainer.monsters[idx].slug === 'STARTER') {
- nextTrainer.monsters[idx].slug = Memory.state.rivalMonster;
- }
- }
- }
-
const trainer = new Trainer(nextTrainer);
await trainer.initialize()
Memory.state.opponent = trainer;
@@ -797,11 +789,37 @@ const Game = {
Memory.state.currentArea = await fetchArea(areaSlug);
+
+ // on enter
+ let storyIsDone = true;
+ if (Memory.state.currentArea.events?.onEnter.length > 0) {
+ Game.isLoadingArea = false;
+
+ for (const event of Memory.state.currentArea.events.onEnter) {
+ if (event.type === 'story') {
+ UI.showMap();
+ UI.drawTown();
+
+ storyIsDone = await Story.progress(event.story);
+ }
+ }
+ }
+
+ if (!storyIsDone) {
+ return;
+ }
+
+ Game.isLoadingArea = true;
+
+
+ // after events resolved
+
if (Game.isTown(Memory.state.currentArea)) {
if (Object.values(Memory.state.currentArea.locations).some((location) => location.type === 'healingCenter')) {
Memory.state.lastVisitedTown = areaSlug;
}
- } else {
+ }
+ else {
if (Memory.state.currentArea.encounters.length > 0) {
await Game.encounterWildMonster();
} else if (Memory.state.currentArea.trainers.length > 0) {
diff --git a/resources/js/story.js b/resources/js/story.js
index d5e6486..bb6fc4b 100644
--- a/resources/js/story.js
+++ b/resources/js/story.js
@@ -1,5 +1,5 @@
const Story = {
- async start () {
+ 'start': async () => {
const settingsPopup = UI.createPopup();
settingsPopup.querySelector('[data-template-slot="content"]').append(UI.createSettingsMenu());
UI.drawPopup(settingsPopup);
@@ -10,10 +10,10 @@ const Story = {
}));
});
- await Story.immediateProgress('start', 'introduction');
+ return await Story.immediateProgress('start', 'introduction');
},
- async introduction () {
+ 'introduction': async () => {
const story = await fetchStory('introduction');
const characterCeo = story.characters.ceo;
const characterShopKeeper = story.characters.shopKeeper;
@@ -55,9 +55,11 @@ const Story = {
resolve();
}));
});
+
+ return true;
},
- async selectStarterMonster () {
+ 'select-starter-monster': async () => {
const story = await fetchStory('select-starter-monster');
const characterDante = story.characters.dante;
const npcDante = await fetchNpc(characterDante.slug);
@@ -93,35 +95,19 @@ const Story = {
}));
});
- await Story.immediateProgress('selectStarterMonster', 'battleRivalOne');
+ return await Story.immediateProgress('select-starter-monster', 'battle-rival-one');
},
- async battleRivalOne () {
+ 'battle-rival-one': async () => {
const story = await fetchStory('battle-rival-one');
const characterRival = story.characters.rival;
const npcRival = await fetchNpc(story.characters.rival.slug);
- Memory.state.opponent = new Trainer({
- monsters: await Promise.all(
- characterRival.monsters.map(async (monsterData) => {
- if (monsterData.slug === 'RIVAL') {
- monsterData.slug = Memory.state.rivalMonster;
- }
-
- const monster = await fetchMonster(monsterData.slug);
- monster.level = monsterData.level;
-
- return monster;
- })
- )
- });
- await Memory.state.opponent.initialize();
-
await UI.buildAndShowStoryPopup({ speaker: npcRival, text: translate(characterRival.text[0]) });
+ await Story.setupBattle(npcRival, characterRival.monsters);
+ const didWin = await Story.battle();
- await Story.battle();
-
- if (Game.didWinStoryBattle) {
+ if (didWin) {
await UI.buildAndShowStoryPopup({ speaker: npcRival, text: translate(characterRival.text[1]) });
} else {
await UI.buildAndShowStoryPopup({ speaker: npcRival, text: translate(characterRival.text[2]) });
@@ -129,6 +115,94 @@ const Story = {
await UI.buildAndShowStoryPopup({ speaker: npcRival, text: translate(characterRival.text[3]) });
Game.healParty();
+
+ return true;
+ },
+
+ 'battle-rival-two': async () => {
+ const story = await fetchStory('battle-rival-two');
+ const characterRival = story.characters.rival;
+ const npcRival = await fetchNpc(story.characters.rival.slug);
+
+ await UI.buildAndShowStoryPopup({ speaker: npcRival, text: translate(characterRival.text[0]) });
+ await Story.setupBattle(npcRival, characterRival.monsters);
+ const didWin = await Story.battle();
+ if (didWin) {
+ await UI.buildAndShowStoryPopup({ speaker: npcRival, text: translate(characterRival.text[1]) });
+ }
+
+ return didWin;
+ },
+
+ 'hospital-floor-1': async () => {
+ const story = await fetchStory('hospital-floor-1');
+ const characterAurora = story.characters.aurora;
+ const npcAurora = await fetchNpc(characterAurora.slug);
+
+ await UI.buildAndShowStoryPopup({ speaker: npcAurora, text: translate(characterAurora.text[0]) });
+ await Story.setupBattle(npcAurora, characterAurora.monsters);
+ didWin = await Story.battle();
+ if (didWin) {
+ await UI.buildAndShowStoryPopup({ speaker: npcAurora, text: translate(characterAurora.text[1]) });
+ }
+
+ return didWin;
+ },
+
+ 'hospital-floor-2': async () => {
+ const story = await fetchStory('hospital-floor-2');
+ const characterLuzia = story.characters.luzia;
+ const npcLuzia = await fetchNpc(characterLuzia.slug);
+ const characterRhizome = story.characters.rhizome;
+ const npcRhizome = await fetchNpc(characterRhizome.slug);
+
+ await UI.buildAndShowStoryPopup({ speaker: npcLuzia, text: translate(characterLuzia.text[0]) });
+ await Story.setupBattle(npcLuzia, characterLuzia.monsters);
+ let didWin = await Story.battle();
+ if (didWin) {
+ await UI.buildAndShowStoryPopup({ speaker: npcLuzia, text: translate(characterLuzia.text[1]) });
+ } else {
+ return false;
+ }
+
+ await UI.buildAndShowStoryPopup({ speaker: npcRhizome, text: translate(characterRhizome.text[0]) });
+ await Story.setupBattle(npcRhizome, characterRhizome.monsters);
+ didWin = await Story.battle();
+ if (didWin) {
+ await UI.buildAndShowStoryPopup({ speaker: npcRhizome, text: translate(characterRhizome.text[1]) });
+ }
+
+ return didWin;
+ },
+
+ 'hospital-floor-3': async () => {
+ const story = await fetchStory('hospital-floor-3');
+ const characterRival = story.characters.rival;
+ const npcRival = await fetchNpc(characterRival.slug);
+
+ await UI.buildAndShowStoryPopup({
+ speaker: npcRival,
+ text: translate(characterRival.text[0]).replace('${{name}}', Memory.state.Settings.name)
+ });
+ await Story.setupBattle(npcRival, characterRival.monsters);
+ didWin = await Story.battle();
+ if (didWin) {
+ await UI.buildAndShowStoryPopup({ speaker: npcRival, text: translate(characterRival.text[1]) });
+ }
+
+ return didWin;
+ },
+
+ 'drokoro': async () => {
+ const story = await fetchStory('drokoro');
+
+ const monster = await fetchMonster(story.encounters.drokoro.slug);
+ monster.level = story.encounters.drokoro.level;
+
+ Memory.state.opponent = new Trainer({ monsters: [monster] });
+ await Memory.state.opponent.initialize();
+
+ return await Story.battle();
},
@@ -136,33 +210,51 @@ const Story = {
/**
* @param {StorySlug} slug
+ *
+ * @returns {Promise<boolean>}
*/
async progress (slug) {
if (!Story[slug]) {
- return;
+ return true;
+ }
+
+ // story already done
+ const story = await fetchStory(slug);
+ if (!story.canTriggerMultipleTimes && Memory.state.storyProgress[slug]) {
+ return true;
}
Memory.state.currentStory = slug;
Memory.saveToLocalStorage();
- await Story[slug]();
+ const isDone = await Story[slug]();
+
+ if (isDone) {
+ Memory.state.storyProgress[slug] = true;
+ }
- Memory.state.storyProgress[slug] = true;
Memory.state.currentStory = null;
Memory.saveToLocalStorage();
+
+ return isDone;
},
/**
* @param {StorySlug} fromSlug
* @param {StorySlug} toSlug
+ *
+ * @returns {Promise<boolean>}
*/
async immediateProgress (fromSlug, toSlug) {
Memory.state.storyProgress[fromSlug] = true;
Memory.saveToLocalStorage();
- await Story.progress(toSlug);
+ return await Story.progress(toSlug);
},
+ /**
+ * @returns {Promise<boolean>}
+ */
async battle () {
const previousArea = Object.assign({}, Memory.state.currentArea);
@@ -191,5 +283,36 @@ const Story = {
UI.drawStatus();
}
+
+ return Game.didWinStoryBattle;
+ },
+
+ /**
+ * @param {Npc} npc
+ * @param {DB_StoryEncounter[]} monsters
+ * @param {Object[]} inventory
+ */
+ async setupBattle (npc, monsters, inventory = []) {
+ Memory.state.opponent = new Trainer({
+ monsters: await Promise.all(
+ monsters.map(async (monsterData) => {
+ if (monsterData.slug === 'RIVAL') {
+ monsterData.slug = Memory.state.rivalMonster;
+ }
+
+ const monster = await fetchMonster(monsterData.slug);
+ monster.level = monsterData.level;
+
+ return monster;
+ })
+ ),
+
+ inventory: inventory,
+
+ name: translate(npc.slug),
+ sprite: npc.spriteName + '.png',
+ });
+
+ await Memory.state.opponent.initialize();
},
};
diff --git a/resources/js/ui.js b/resources/js/ui.js
index 04186f5..ede8a1f 100644
--- a/resources/js/ui.js
+++ b/resources/js/ui.js
@@ -757,9 +757,10 @@ const UI = {
}
})));
- template.querySelectorAll('[data-interactable="true"]').forEach((node) => {
+ template.querySelectorAll('[data-interactable="true"]').forEach(async (node) => {
if (node.dataset.story) {
- if (node.dataset.storyOnce && Memory.state.storyProgress[node.dataset.story]) {
+ const story = await fetchStory(node.dataset.story);
+ if (!story.canTriggerMultipleTimes && Memory.state.storyProgress[node.dataset.story]) {
node.dataset.interactable = false;
return;
}
@@ -1932,7 +1933,7 @@ const UI = {
* @returns {HTMLElement}
*/
createStoryPopup () {
- const popup = UI.createPopup();
+ const popup = UI.createPopup({ isClosable: false });
return popup;
},