diff options
| author | Daniel Weipert <code@drogueronin.de> | 2023-09-01 22:32:45 +0200 | 
|---|---|---|
| committer | Daniel Weipert <code@drogueronin.de> | 2023-09-01 22:32:45 +0200 | 
| commit | 1d29ee6d87d3794a9319bca5bf36afdfe176072c (patch) | |
| tree | 1e7e89ca87afd313b1806fcc80d456796b0af6db /resources | |
| parent | 6b3a8aef783368d0ed9a2c104eea3ff5cf9984da (diff) | |
translations with fallback
Diffstat (limited to 'resources')
| -rw-r--r-- | resources/js/classes/Area.js | 2 | ||||
| -rw-r--r-- | resources/js/classes/Item.js | 4 | ||||
| -rw-r--r-- | resources/js/classes/Monster.js | 2 | ||||
| -rw-r--r-- | resources/js/classes/Npc.js | 2 | ||||
| -rw-r--r-- | resources/js/classes/StatusEffect.js | 2 | ||||
| -rw-r--r-- | resources/js/classes/Technique.js | 4 | ||||
| -rw-r--r-- | resources/js/db.js | 1 | ||||
| -rw-r--r-- | resources/js/game.js | 48 | ||||
| -rw-r--r-- | resources/js/helpers.js | 15 | ||||
| -rw-r--r-- | resources/js/memory.js | 2 | ||||
| -rw-r--r-- | resources/js/story.js | 26 | ||||
| -rw-r--r-- | resources/js/ui.js | 44 | 
12 files changed, 82 insertions, 70 deletions
| diff --git a/resources/js/classes/Area.js b/resources/js/classes/Area.js index bafa949..1b07e35 100644 --- a/resources/js/classes/Area.js +++ b/resources/js/classes/Area.js @@ -9,7 +9,7 @@ class Area {    }    get name () { -    return translate(this.alternateSlug) || slugToName(this.slug); +    return translate(this.alternateSlug);    }    get isCompleted () { diff --git a/resources/js/classes/Item.js b/resources/js/classes/Item.js index 40089f2..c70c28a 100644 --- a/resources/js/classes/Item.js +++ b/resources/js/classes/Item.js @@ -4,11 +4,11 @@ class Item {    }    get name () { -    return translate(this.slug) || slugToName(this.slug); +    return translate(this.slug);    }    get description () { -    return translate(`${this.slug}_description`) || 'ITEM_DESCRIPTION_MISSING'; +    return translate(`${this.slug}_description`);    }    get category () { diff --git a/resources/js/classes/Monster.js b/resources/js/classes/Monster.js index c058a75..2d34d8e 100644 --- a/resources/js/classes/Monster.js +++ b/resources/js/classes/Monster.js @@ -124,7 +124,7 @@ class Monster {    }    get name () { -    return translate(this.slug) || slugToName(this.slug); +    return translate(this.slug);    }    /** diff --git a/resources/js/classes/Npc.js b/resources/js/classes/Npc.js index 6121bce..82dba7e 100644 --- a/resources/js/classes/Npc.js +++ b/resources/js/classes/Npc.js @@ -5,7 +5,7 @@ class Npc {    constructor (slug) {      this.slug = slug; -    this.name = translate(slug) || slugToName(slug.replace('spyder_', '')); +    this.name = translate(slug);      this.spriteName = DB.npcs[slug]?.template[0].sprite_name;    } diff --git a/resources/js/classes/StatusEffect.js b/resources/js/classes/StatusEffect.js index d161761..1a164a1 100644 --- a/resources/js/classes/StatusEffect.js +++ b/resources/js/classes/StatusEffect.js @@ -44,7 +44,7 @@ class StatusEffect {    }    get name () { -    return slugToName(this.slug); +    return translate(`status_${this.slug}`);    }    get stats () { diff --git a/resources/js/classes/Technique.js b/resources/js/classes/Technique.js index 5f01e64..0fa31c9 100644 --- a/resources/js/classes/Technique.js +++ b/resources/js/classes/Technique.js @@ -14,11 +14,11 @@ class Technique {    }    get name () { -    return translate(this.slug) || slugToName(this.slug); +    return translate(this.slug);    }    get description () { -    return translate(`${this.slug}_description`) || 'TECHNIQUE_DESCRIPTION_MISSING'; +    return translate(`${this.slug}_description`);    }    get types () { diff --git a/resources/js/db.js b/resources/js/db.js index 6e53b7e..d564851 100644 --- a/resources/js/db.js +++ b/resources/js/db.js @@ -123,6 +123,7 @@ async function initializeDB () {      DB.elements[element] = await fetchDBData(`/modules/tuxemon/mods/tuxemon/db/element/${element}.json`).then((response) => response.json());    } +  await fetchTranslation('en_US'); // fallback    await fetchTranslation(Memory.state.Settings.language);    applyTranslation(); diff --git a/resources/js/game.js b/resources/js/game.js index 5abc42f..6c3a393 100644 --- a/resources/js/game.js +++ b/resources/js/game.js @@ -98,7 +98,7 @@ const Game = {        const money = calculateAwardedMoney(Memory.state.opponent.activeMonster);        Memory.state.money += money;        Game.addPhaseEvent('postTurn', () => { -        Game.log(translate('game:battle:money:get', true).replace('{amount}', money)); +        Game.log(translate('game:battle:money:get').replace('{amount}', money));        });        // exp @@ -171,9 +171,9 @@ const Game = {          Memory.state.money -= totalHealingCenterPrice;          Game.addPhaseEvent('postTurnEnd', () => { -          Game.log(translate('game:battle:defeat', true)); +          Game.log(translate('game:battle:defeat'));            Game.log( -            translate('game:battle:defeat:recovery_price', true) +            translate('game:battle:defeat:recovery_price')                .replace('{amount}', formatPrice(totalHealingCenterPrice))                .replace('{name}', Memory.state.currentArea.name)            ); @@ -251,7 +251,7 @@ const Game = {      };      log( -      translate('game:battle:technique:attempt', true) +      translate('game:battle:technique:attempt')          .replace('{monster.name}', user.name)          .replace('{technique.name}', technique.name)      ); @@ -264,7 +264,7 @@ const Game = {          UI.drawActionFeedback(feedbackNode);        } -      log(translate('game:battle:technique:attempt:fail:recharge', true), 1); +      log(translate('game:battle:technique:attempt:fail:recharge'), 1);        canUse = false;      } @@ -276,7 +276,7 @@ const Game = {          UI.drawActionFeedback(feedbackNode);        } -      log(translate('game:battle:technique:attempt:fail:noddingoff', true), 1); +      log(translate('game:battle:technique:attempt:fail:noddingoff'), 1);        canUse = false;      } @@ -290,7 +290,7 @@ const Game = {          technique.use();          Game.doBattleAnimation && UI.drawDamageMiss(UI.createDamageMiss()); -        log(translate('game:battle:technique:attempt:fail:miss', true), 1); +        log(translate('game:battle:technique:attempt:fail:miss'), 1);          return;        } @@ -309,7 +309,7 @@ const Game = {      Game.addBattlePhaseEvent('action', user, () => {        Game.log( -        translate('game:battle:technique:use', true) +        translate('game:battle:technique:use')            .replace('{monster.name}', user.name)            .replace('{technique.name}', technique.name)        ); @@ -336,7 +336,7 @@ const Game = {            }              Game.log( -              translate('game:battle:technique:use:damage', true) +              translate('game:battle:technique:use:damage')                  .replace('{amount}', damage)                  .replace('{name}', target.name),                1 @@ -367,7 +367,7 @@ const Game = {              recipient.hp += heal;              Game.log( -              translate('game:battle:technique:use:healing', true) +              translate('game:battle:technique:use:healing')                  .replace('{amount}', heal),                1              ); @@ -406,9 +406,9 @@ const Game = {                recipient.statusEffect = statusEffect;                Game.log( -                translate('game:battle:technique:use:status', true) +                translate('game:battle:technique:use:status')                    .replace('{monster.name}', recipient.name) -                  .replace('{status_effect.name}', translate(`status_${statusEffect.slug}`, true)), +                  .replace('{status_effect.name}', translate(`status_${statusEffect.slug}`)),                  1                );              } @@ -435,9 +435,9 @@ const Game = {          // if still 0 turns left after remove action          if (monster.statusEffect.turnsLeft === 0) {            Game.log( -            translate('game:battle:status_effect:removed', true) +            translate('game:battle:status_effect:removed')                .replace('{monster.name}', monster.name) -              .replace('{status_effect.name}', translate(`status_${monster.statusEffect.slug}`, true)) +              .replace('{status_effect.name}', translate(`status_${monster.statusEffect.slug}`))            );            monster.statusEffect = null; @@ -451,9 +451,9 @@ const Game = {      const logStatusIs = () => {        Game.log( -        translate('game:battle:status_effect:is', true) +        translate('game:battle:status_effect:is')            .replace('{monster.name}', monster.name) -          .replace('{status_effect.name}', translate(`status_${monster.statusEffect.slug}`, true)) +          .replace('{status_effect.name}', translate(`status_${monster.statusEffect.slug}`))        );      } @@ -963,7 +963,7 @@ const Game = {      const activeBall = Game.getItemFromInventory(Memory.state.player.inventory, Memory.state.activeBall);      // remove ball -    Game.log(translate('game:catch:ball:throw', true).replace('{ball}', activeBall.name)); +    Game.log(translate('game:catch:ball:throw').replace('{ball}', activeBall.name));      activeBall.quantity--;      if (activeBall.quantity === 0) {        Game.removeItemFromInventory(Memory.state.player.inventory, Memory.state.activeBall); @@ -972,7 +972,7 @@ const Game = {      }      // attempt capture -    Game.log(translate('game:catch:attempt', true), 1); +    Game.log(translate('game:catch:attempt'), 1);      let success = true;      let attempts = 1;      const maxAttempts = 4; @@ -980,8 +980,8 @@ const Game = {        success = checkCapture(playerMonster, opposingMonster, activeBall);        if (!success) { -        Game.log(translate('game:catch:attempt:nr:success', true).replace('{nr}', attempts), 2); -        Game.log(translate('game:catch:broke_free', true).replace('{monster}', opposingMonster.name), 1); +        Game.log(translate('game:catch:attempt:nr:success').replace('{nr}', attempts), 2); +        Game.log(translate('game:catch:broke_free').replace('{monster}', opposingMonster.name), 1);          Memory.state.Game.isInBattle = true;          UI.drawStatus(); @@ -990,7 +990,7 @@ const Game = {          return; // can't catch        } -      Game.log(translate('game:catch:attempt:nr:fail', true).replace('{nr}', attempts), 2); +      Game.log(translate('game:catch:attempt:nr:fail').replace('{nr}', attempts), 2);        attempts++;      } @@ -1002,16 +1002,16 @@ const Game = {      caughtMonster.level = Memory.state.opponent.activeMonster.level;      caughtMonster.hp = Memory.state.opponent.activeMonster.hp; -    Game.log(translate('game:catch:caught', true).replace('{monster}', caughtMonster.name), 1); +    Game.log(translate('game:catch:caught').replace('{monster}', caughtMonster.name), 1);      if (Memory.state.player.monsters.length < 6) {        Memory.state.player.monsters.push(caughtMonster); -      Game.log(translate('game:catch:to_party', true).replace('{monster}', caughtMonster.name), 2); +      Game.log(translate('game:catch:to_party').replace('{monster}', caughtMonster.name), 2);      } else {        Memory.state.monsters.push(caughtMonster); -      Game.log(translate('game:catch:to_box', true).replace('{monster}', caughtMonster.name), 2); +      Game.log(translate('game:catch:to_box').replace('{monster}', caughtMonster.name), 2);      }      await Game.encounterWildMonster(); diff --git a/resources/js/helpers.js b/resources/js/helpers.js index aa149b1..cee9166 100644 --- a/resources/js/helpers.js +++ b/resources/js/helpers.js @@ -68,14 +68,19 @@ function randomString () {  /**   * @param {string} msgid + * @param {boolean} useFallback   *   * @returns {string}   */ -function translate (msgid, showTranslationMissing = false) { +function translate (msgid, useFallback = true) {    let translation = DB.translations[Memory.state.Settings.language][msgid]; -  if (!translation && showTranslationMissing) { -    translation = (translate('translation_missing') || 'translation_missing') + `: ${msgid}`; +  if (!translation && useFallback) { +    translation = DB.translations['en_US'][msgid]; + +    if (!translation) { +      translation = (translate('translation_missing', false) || 'translation_missing') + `: ${msgid}`; +    }    }    return translation; @@ -89,7 +94,7 @@ function applyTranslation () {      }      parentNode.querySelectorAll('[data-i18n-msgid]').forEach((node) => { -      node.innerHTML = translate(node.dataset.i18nMsgid, true); +      node.innerHTML = translate(node.dataset.i18nMsgid);      });      parentNode.querySelectorAll('[data-i18n-properties]').forEach((node) => { @@ -99,7 +104,7 @@ function applyTranslation () {          const property = properties[idx];          const msgid = msgids[idx]; -        node.setAttribute(property, translate(msgid, true)) +        node.setAttribute(property, translate(msgid))        }      });    }); diff --git a/resources/js/memory.js b/resources/js/memory.js index c0fa171..421cecb 100644 --- a/resources/js/memory.js +++ b/resources/js/memory.js @@ -76,7 +76,7 @@ const Memory = {    saveToLocalStorage () {      const lastWrite = new Date(localStorage.getItem('lastWrite'));      if (Math.abs(new Date() - lastWrite) / (1000 * 60 * 60 * 24) >= 0.25) { -      localStorage.setItem(`state_${(new Date()).toLocaleDateString()}_${(new Date()).getTime()}`, localStorage.getItem('state')); +      localStorage.setItem(`state_${(new Date()).toLocaleDateString()}_${(new Date()).toLocaleTimeString()}`, localStorage.getItem('state'));      }      localStorage.setItem('state', Memory.saveToString()); diff --git a/resources/js/story.js b/resources/js/story.js index 0ceb224..d5e6486 100644 --- a/resources/js/story.js +++ b/resources/js/story.js @@ -20,9 +20,9 @@ const Story = {      const npcCeo = await fetchNpc(characterCeo.slug);      const npcShopKeeper = await fetchNpc(characterShopKeeper.slug); -    await UI.buildAndShowStoryPopup({ speaker: npcCeo, text: translate(characterCeo.text[0], true) }); -    await UI.buildAndShowStoryPopup({ speaker: npcCeo, text: translate(characterCeo.text[1], true) }); -    await UI.buildAndShowStoryPopup({ speaker: npcShopKeeper, text: translate(characterShopKeeper.text[0], true) }); +    await UI.buildAndShowStoryPopup({ speaker: npcCeo, text: translate(characterCeo.text[0]) }); +    await UI.buildAndShowStoryPopup({ speaker: npcCeo, text: translate(characterCeo.text[1]) }); +    await UI.buildAndShowStoryPopup({ speaker: npcShopKeeper, text: translate(characterShopKeeper.text[0]) });      const possibleStarterMonsters = await Promise.all(        story.monsters.map(async (monsterData) => { @@ -32,7 +32,7 @@ const Story = {        })      ); -    const monsterSelection = UI.openStarterMonsterSelection(possibleStarterMonsters, { title: translate('story:introduction:monster_selection:title', true) }); +    const monsterSelection = UI.openStarterMonsterSelection(possibleStarterMonsters, { title: translate('story:introduction:monster_selection:title') });      await new Promise((resolve) => {        monsterSelection.addEventListener('starter:monster:selected', UI.wrapCallback(async (event) => {          if (!confirm(`Select ${event.detail.monster.name}?`)) { @@ -41,7 +41,7 @@ const Story = {          event.detail.popup.remove(); -        await UI.buildAndShowStoryPopup({ speaker: npcShopKeeper, text: translate(characterShopKeeper.text[1], true) }); +        await UI.buildAndShowStoryPopup({ speaker: npcShopKeeper, text: translate(characterShopKeeper.text[1]) });          // set rival monster          Memory.state.rivalMonster = event.detail.monster.slug; @@ -62,9 +62,9 @@ const Story = {      const characterDante = story.characters.dante;      const npcDante = await fetchNpc(characterDante.slug); -    await UI.buildAndShowStoryPopup({ speaker: npcDante, text: translate(characterDante.text[0], true) }); -    await UI.buildAndShowStoryPopup({ speaker: npcDante, text: translate(characterDante.text[1], true) }); -    await UI.buildAndShowStoryPopup({ speaker: npcDante, text: translate(characterDante.text[2], true) }); +    await UI.buildAndShowStoryPopup({ speaker: npcDante, text: translate(characterDante.text[0]) }); +    await UI.buildAndShowStoryPopup({ speaker: npcDante, text: translate(characterDante.text[1]) }); +    await UI.buildAndShowStoryPopup({ speaker: npcDante, text: translate(characterDante.text[2]) });      const possibleStarterMonsters = await Promise.all(        story.monsters.map(async (monsterData) => { @@ -74,7 +74,7 @@ const Story = {        })      ); -    const monsterSelection = UI.openStarterMonsterSelection(possibleStarterMonsters, { title: translate('story:select_starter_monster:monster_selection:title', true) }); +    const monsterSelection = UI.openStarterMonsterSelection(possibleStarterMonsters, { title: translate('story:select_starter_monster:monster_selection:title') });      await new Promise((resolve) => {        monsterSelection.addEventListener('starter:monster:selected', UI.wrapCallback(async (event) => {          if (!confirm(`Select ${event.detail.monster.name}?`)) { @@ -117,17 +117,17 @@ const Story = {      });      await Memory.state.opponent.initialize(); -    await UI.buildAndShowStoryPopup({ speaker: npcRival, text: translate(characterRival.text[0], true) }); +    await UI.buildAndShowStoryPopup({ speaker: npcRival, text: translate(characterRival.text[0]) });      await Story.battle();      if (Game.didWinStoryBattle) { -      await UI.buildAndShowStoryPopup({ speaker: npcRival, text: translate(characterRival.text[1], true) }); +      await UI.buildAndShowStoryPopup({ speaker: npcRival, text: translate(characterRival.text[1]) });      } else { -      await UI.buildAndShowStoryPopup({ speaker: npcRival, text: translate(characterRival.text[2], true) }); +      await UI.buildAndShowStoryPopup({ speaker: npcRival, text: translate(characterRival.text[2]) });      } -    await UI.buildAndShowStoryPopup({ speaker: npcRival, text: translate(characterRival.text[3], true) }); +    await UI.buildAndShowStoryPopup({ speaker: npcRival, text: translate(characterRival.text[3]) });      Game.healParty();    }, diff --git a/resources/js/ui.js b/resources/js/ui.js index 3aa0c98..04186f5 100644 --- a/resources/js/ui.js +++ b/resources/js/ui.js @@ -283,7 +283,7 @@ const UI = {    createElementTypeIcon (type) {      const img = document.createElement('img');      img.src = `/modules/tuxemon/mods/tuxemon/gfx/ui/icons/element/${type}_type.png`; -    img.title = translate(type) || slugToName(type); +    img.title = translate(type);      return img;    }, @@ -301,14 +301,14 @@ const UI = {      if (statusEffect.slug === 'faint') {        const node = document.createElement('b');        node.innerHTML = 'X'; -      node.title = translate(`status_${statusEffect.slug}`) || statusEffect.name; +      node.title = translate(`status_${statusEffect.slug}`);        return node;      }      const img = document.createElement('img');      img.src = `/modules/tuxemon/mods/tuxemon/gfx/ui/icons/status/icon_${statusEffect.slug}.png`; -    img.title = translate(`status_${statusEffect.slug}`) || statusEffect.name; +    img.title = translate(`status_${statusEffect.slug}`);      return img;    }, @@ -389,7 +389,7 @@ const UI = {        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 = translate(technique.range) || slugToName(technique.range); +      techniqueNode.querySelector('[data-template-slot="range"]').textContent = translate(technique.range);        techniqueNode.querySelector('[data-template-slot="power"]').textContent = technique.power;        techniqueNode.querySelector('[data-template-slot="accuracy"]').textContent = technique.accuracy; @@ -792,7 +792,7 @@ const UI = {        });        if (applicableMonsters.length === 0) { -        alert(translate('ui:no_applicable_monsters', true)); +        alert(translate('ui:no_applicable_monsters'));          return;        } @@ -823,11 +823,11 @@ const UI = {      template.querySelector('[data-template-slot="box.withdraw"]').addEventListener('click', UI.wrapCallback(() => {        if (Memory.state.monsters.length === 0) { -        alert(translate('ui:healing_center:box:withdraw:no_tuxemon_in_box', true)); +        alert(translate('ui:healing_center:box:withdraw:no_tuxemon_in_box'));          return;        }        if (Memory.state.player.monsters.length === 6) { -        alert(translate('ui:healing_center:box:withdraw:no_space_in_party', true)); +        alert(translate('ui:healing_center:box:withdraw:no_space_in_party'));          return;        } @@ -849,7 +849,7 @@ const UI = {      template.querySelector('[data-template-slot="box.deposit"]').addEventListener('click', UI.wrapCallback(() => {        if (Memory.state.player.monsters.length === 1) { -        alert(translate('ui:healing_center:box:deposit:last_tuxemon', true)); +        alert(translate('ui:healing_center:box:deposit:last_tuxemon'));          return;        } @@ -871,7 +871,7 @@ const UI = {      template.querySelector('[data-template-slot="box.view"]').addEventListener('click', UI.wrapCallback(() => {        if (Memory.state.monsters.length === 0) { -        alert(translate('ui:healing_center:box:view:no_tuxemon_in_box', true)); +        alert(translate('ui:healing_center:box:view:no_tuxemon_in_box'));          return;        } @@ -1175,8 +1175,7 @@ const UI = {        const connection = currentArea.connections[connectionSlug];        const connectionNode = UI.createTemplate(Template.areaSelectionItem); -      connectionNode.querySelector('[data-template-slot="text"]').textContent = -        translate(connection['modules/tuxemon.slug']) || slugToName(connection['modules/tuxemon.slug']); +      connectionNode.querySelector('[data-template-slot="text"]').textContent = translate(connection['modules/tuxemon.slug']);        let canGo = true;        for (const condition of connection.conditions) { @@ -1455,11 +1454,11 @@ const UI = {      template.querySelector('[data-template-slot="exp"]').innerHTML = `${monster.exp} / ${monster.getExperienceRequired(1)}`; -    template.querySelector('[data-template-slot="stats.melee.name"]').textContent = translate(StatType.melee) || slugToName(StatType.melee); -    template.querySelector('[data-template-slot="stats.armour.name"]').textContent = translate(StatType.armour) || slugToName(StatType.armour); -    template.querySelector('[data-template-slot="stats.ranged.name"]').textContent = translate(StatType.ranged) || slugToName(StatType.ranged); -    template.querySelector('[data-template-slot="stats.dodge.name"]').textContent = translate(StatType.dodge) || slugToName(StatType.dodge); -    template.querySelector('[data-template-slot="stats.speed.name"]').textContent = translate(StatType.speed) || slugToName(StatType.speed); +    template.querySelector('[data-template-slot="stats.melee.name"]').textContent = translate(StatType.melee); +    template.querySelector('[data-template-slot="stats.armour.name"]').textContent = translate(StatType.armour); +    template.querySelector('[data-template-slot="stats.ranged.name"]').textContent = translate(StatType.ranged); +    template.querySelector('[data-template-slot="stats.dodge.name"]').textContent = translate(StatType.dodge); +    template.querySelector('[data-template-slot="stats.speed.name"]').textContent = translate(StatType.speed);      template.querySelector('[data-template-slot="stats.melee.value"]').textContent = monster.stats.melee;      template.querySelector('[data-template-slot="stats.armour.value"]').textContent = monster.stats.armour; @@ -1671,7 +1670,7 @@ const UI = {      template.classList.add('inventory__monster-selection');      if (template.children.length === 0) { -      alert(translate('ui:no_applicable_monsters', true)); +      alert(translate('ui:no_applicable_monsters'));        return;      } @@ -1917,7 +1916,7 @@ const UI = {      // Clear save data      template.querySelector('[data-template-slot="clearLocalSaveData"]').addEventListener('click', UI.wrapCallback(() => { -      if (confirm(translate('ui:settings:clear_local_save_data:confirm', true))) { +      if (confirm(translate('ui:settings:clear_local_save_data:confirm'))) {          localStorage.removeItem('state');          window.location.reload();        } @@ -1940,6 +1939,9 @@ const UI = {    /**     * @param {HTMLElement} popup +   * @param {Object} data +   * @param {Npc}    data.speaker +   * @param {string} data.text     *     * @returns {HTMLElement}     */ @@ -1961,7 +1963,7 @@ const UI = {    /**     * @param {HTMLElement} popup     * -   * @returns {Promise<any>} +   * @returns {Promise<void>}     */    drawStoryPopup (popup) {      UI.drawPopup(popup); @@ -1979,6 +1981,10 @@ const UI = {    },    /** +   * @param {Object} data +   * @param {Npc}    data.speaker +   * @param {string} data.text +   *     * @returns {Promise<any>}     */    async buildAndShowStoryPopup ({ speaker, text }) { | 
