From a8adfc2476c0d9907931a7b2c1a115dcf2d7cc5c Mon Sep 17 00:00:00 2001 From: "Adrian T." <68144167+torranx@users.noreply.github.com> Date: Mon, 29 Jul 2024 04:46:37 +0800 Subject: [PATCH 001/282] [Hotfix] Fix interactions of some moves not changing types (#3183) --- src/data/move.ts | 6 +++++- src/field/pokemon.ts | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/data/move.ts b/src/data/move.ts index a2b879a388b..ee7ad1abc02 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -717,9 +717,13 @@ export default class Move implements Localizable { * @returns The calculated power of the move. */ calculateBattlePower(source: Pokemon, target: Pokemon): number { - const power = new Utils.NumberHolder(this.power); + if (this.category === MoveCategory.STATUS) { + return -1; + } + const power = new Utils.NumberHolder(this.power); const typeChangeMovePowerMultiplier = new Utils.NumberHolder(1); + applyPreAttackAbAttrs(MoveTypeChangeAttr, source, target, this, typeChangeMovePowerMultiplier); const sourceTeraType = source.getTeraType(); diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index f630cc16a48..cd9ff748b0a 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -1836,7 +1836,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { const types = this.getTypes(true, true); const cancelled = new Utils.BooleanHolder(false); + const power = move.calculateBattlePower(source, this); const typeless = move.hasAttr(TypelessAttr); + const typeMultiplier = new Utils.NumberHolder(!typeless && (moveCategory !== MoveCategory.STATUS || move.getAttrs(StatusMoveTypeImmunityAttr).find(attr => types.includes(attr.immuneType))) ? this.getAttackTypeEffectiveness(move, source, false, false) : 1); @@ -1861,7 +1863,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { case MoveCategory.PHYSICAL: case MoveCategory.SPECIAL: const isPhysical = moveCategory === MoveCategory.PHYSICAL; - const power = move.calculateBattlePower(source, this); const sourceTeraType = source.getTeraType(); if (!typeless) { From f25d4e1ee2ec0a04d1631fd1e1bcb74a90295e2a Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Sun, 28 Jul 2024 14:06:38 -0700 Subject: [PATCH 002/282] [Hotfix] Fix wild spawns not having their HA (#3190) --- src/field/pokemon.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index cd9ff748b0a..b6cba8387df 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -135,10 +135,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { // If abilityIndex is not provided, determine it based on species and hidden ability if (species.abilityHidden && hasHiddenAbility) { // If the species has a hidden ability and the hidden ability is present - this.abilityIndex = species.ability2 ? 2 : 1; // Use ability index 2 if species has a second ability, otherwise use 1 + this.abilityIndex = 2; } else { // If there is no hidden ability or species does not have a hidden ability - this.abilityIndex = species.ability2 ? randAbilityIndex : 0; // Use random ability index if species has a second ability, otherwise use 0 + this.abilityIndex = species.ability2 !== species.ability1 ? randAbilityIndex : 0; // Use random ability index if species has a second ability, otherwise use 0 } } if (formIndex !== undefined) { From f5101308fee9168007b628f4467f6eaa0add3182 Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Mon, 29 Jul 2024 14:00:49 -0700 Subject: [PATCH 003/282] [Hotfix] Allow to hatch pokemon with Hidden Ability again (#3222) --- src/data/egg.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/egg.ts b/src/data/egg.ts index bf4d6577dd7..870e28fbaaf 100644 --- a/src/data/egg.ts +++ b/src/data/egg.ts @@ -212,7 +212,7 @@ export class Egg { let abilityIndex = undefined; if (pokemonSpecies.abilityHidden && (this._overrideHiddenAbility || (this._sourceType === EggSourceType.SAME_SPECIES_EGG && !Utils.randSeedInt(SAME_SPECIES_EGG_HA_RATE)))) { - abilityIndex = pokemonSpecies.ability2 ? 2 : 1; + abilityIndex = 2; } // This function has way to many optional parameters From 0922f1123a60b2252be19c2b3f3464755236f75d Mon Sep 17 00:00:00 2001 From: Frederico Santos Date: Mon, 29 Jul 2024 22:09:35 +0100 Subject: [PATCH 004/282] chore: Update TNC links layout and position in index.html --- index.css | 2 +- index.html | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/index.css b/index.css index 85878e54fff..749f432b8ea 100644 --- a/index.css +++ b/index.css @@ -33,6 +33,7 @@ body { display: flex; justify-content: space-around; } + #app { display: flex; justify-content: center; @@ -209,7 +210,6 @@ input:-internal-autofill-selected { #tnc-links { font-size: larger; position: relative; - bottom: max(calc(92vh - 100vw / 16 * 9), 0%); } a { diff --git a/index.html b/index.html index e37529572e5..ebe5b063c52 100644 --- a/index.html +++ b/index.html @@ -114,9 +114,6 @@ - - - + + + \ No newline at end of file From e1de9373a99b0cca4d07afe4c5c034c26ebe9571 Mon Sep 17 00:00:00 2001 From: Frederico Santos Date: Tue, 30 Jul 2024 00:12:29 +0100 Subject: [PATCH 005/282] chore: Update TNC links font size in index.css (#3230) --- index.css | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/index.css b/index.css index 749f432b8ea..be480ab6c78 100644 --- a/index.css +++ b/index.css @@ -208,7 +208,7 @@ input:-internal-autofill-selected { } #tnc-links { - font-size: larger; + font-size: xx-small; position: relative; } From c186d53f3e087d7a4e22152fd15783c49c0d928b Mon Sep 17 00:00:00 2001 From: Leo Kim <47556641+KimJeongSun@users.noreply.github.com> Date: Wed, 7 Aug 2024 23:24:45 +0900 Subject: [PATCH 006/282] [QoL] Update `Normal` -> `Not Shiny`. Remove no pokerus option (#3402) --- src/locales/en/filter-bar.ts | 2 +- src/ui/starter-select-ui-handler.ts | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/locales/en/filter-bar.ts b/src/locales/en/filter-bar.ts index 7a3174957ea..0961df9f058 100644 --- a/src/locales/en/filter-bar.ts +++ b/src/locales/en/filter-bar.ts @@ -8,7 +8,7 @@ export const filterBar: SimpleTranslationEntries = { "miscFilter": "Misc", "sortFilter": "Sort", "all": "All", - "normal": "Normal", + "normal": "Not Shiny", "uncaught": "Uncaught", "passive": "Passive", "passiveUnlocked": "Passive Unlocked", diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index c1f7639ca99..028786c85f0 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -467,7 +467,6 @@ export default class StarterSelectUiHandler extends MessageUiHandler { const pokerusLabels = [ new DropDownLabel(i18next.t("filterBar:pokerus"), undefined, DropDownState.OFF), new DropDownLabel(i18next.t("filterBar:hasPokerus"), undefined, DropDownState.ON), - new DropDownLabel(i18next.t("filterBar:noPokerus"), undefined, DropDownState.EXCLUDE), ]; const miscOptions = [ new DropDownOption(this.scene, "WIN", winLabels), From 1700658c5c75f57760d05245cdaad79d2502ba0d Mon Sep 17 00:00:00 2001 From: Enoch Date: Wed, 7 Aug 2024 23:26:18 +0900 Subject: [PATCH 007/282] [Localization] Translate weather (Japanese) (#3399) --- src/locales/ja/weather.ts | 88 +++++++++++++++++++-------------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/src/locales/ja/weather.ts b/src/locales/ja/weather.ts index 8222064f341..a346983d8ec 100644 --- a/src/locales/ja/weather.ts +++ b/src/locales/ja/weather.ts @@ -4,63 +4,63 @@ import { SimpleTranslationEntries } from "#app/interfaces/locales"; * The weather namespace holds text displayed when weather is active during a battle */ export const weather: SimpleTranslationEntries = { - "sunnyStartMessage": "The sunlight got bright!", - "sunnyLapseMessage": "The sunlight is strong.", - "sunnyClearMessage": "The sunlight faded.", + "sunnyStartMessage": "日差しが 強くなった!", + "sunnyLapseMessage": "日差しが 強い!", + "sunnyClearMessage": "日差しが 元に戻った!", - "rainStartMessage": "A downpour started!", - "rainLapseMessage": "The downpour continues.", - "rainClearMessage": "The rain stopped.", + "rainStartMessage": "雨が 降り始めた!", + "rainLapseMessage": "雨が 降っている!", + "rainClearMessage": "雨が あがった!", - "sandstormStartMessage": "A sandstorm brewed!", - "sandstormLapseMessage": "The sandstorm rages.", - "sandstormClearMessage": "The sandstorm subsided.", - "sandstormDamageMessage": "{{pokemonNameWithAffix}} is buffeted\nby the sandstorm!", + "sandstormStartMessage": "砂あらしが 吹き始めた!", + "sandstormLapseMessage": "砂あらしが 吹きあれる!", + "sandstormClearMessage": "砂あらしが おさまった!", + "sandstormDamageMessage": "砂あらしが\n{{pokemonNameWithAffix}}を 襲う!", - "hailStartMessage": "It started to hail!", - "hailLapseMessage": "Hail continues to fall.", - "hailClearMessage": "The hail stopped.", - "hailDamageMessage": "{{pokemonNameWithAffix}} is pelted\nby the hail!", + "hailStartMessage": "あられが 降り始めた!", + "hailLapseMessage": "あられが 降っている!", + "hailClearMessage": "あられが 止んだ!", + "hailDamageMessage": "あられが\n{{pokemonNameWithAffix}}を 襲う!", - "snowStartMessage": "It started to snow!", - "snowLapseMessage": "The snow is falling down.", - "snowClearMessage": "The snow stopped.", + "snowStartMessage": "雪が 降り始めた!", + "snowLapseMessage": "雪が 降っている!", + "snowClearMessage": "雪が 止んだ!", - "fogStartMessage": "A thick fog emerged!", - "fogLapseMessage": "The fog continues.", - "fogClearMessage": "The fog disappeared.", + "fogStartMessage": "足下に 霧(きり)が立ち込めた!", + "fogLapseMessage": "足下に 霧(きり)が 立ち込めている!", + "fogClearMessage": "足下の 霧(きり)が消え去った!", - "heavyRainStartMessage": "A heavy downpour started!", - "heavyRainLapseMessage": "The heavy downpour continues.", - "heavyRainClearMessage": "The heavy rain stopped.", + "heavyRainStartMessage": "強い雨が 降り始めた!", + "heavyRainLapseMessage": "強い雨が 降っている!", + "heavyRainClearMessage": "強い雨が あがった!", - "harshSunStartMessage": "The sunlight got hot!", - "harshSunLapseMessage": "The sun is scorching hot.", - "harshSunClearMessage": "The harsh sunlight faded.", + "harshSunStartMessage": "日差しが とても強くなった!", + "harshSunLapseMessage": "日差しが とても強い!", + "harshSunClearMessage": "日差しが 元に戻った!", - "strongWindsStartMessage": "A heavy wind began!", - "strongWindsLapseMessage": "The wind blows intensely.", - "strongWindsEffectMessage": "The mysterious air current weakened the attack!", - "strongWindsClearMessage": "The heavy wind stopped." + "strongWindsStartMessage": "謎(なぞ)の 乱気流(らんきりゅう)が\nひこうポケモンを 護(まも)る!", + "strongWindsLapseMessage": "謎(なぞ)の 乱気流(らんきりゅう)の 勢(いきお)いは 止まらない!", + "strongWindsEffectMessage": "謎(なぞ)の 乱気流(らんきりゅう)が 攻撃(こうげき)を 弱(よわ)めた!", + "strongWindsClearMessage": "謎(なぞ)の 乱気流(らんきりゅう)が おさまった!" }; export const terrain: SimpleTranslationEntries = { - "misty": "Misty", - "mistyStartMessage": "Mist swirled around the battlefield!", - "mistyClearMessage": "The mist disappeared from the battlefield.", - "mistyBlockMessage": "{{pokemonNameWithAffix}} surrounds itself with a protective mist!", + "misty": "ミストフィールド", + "mistyStartMessage": "足下に 霧(きり)が立ち込めた!", + "mistyClearMessage": "足下の 霧(きり)が消え去った!", + "mistyBlockMessage": "{{pokemonNameWithAffix}}は\nミストフィールドに 守られている!", - "electric": "Electric", - "electricStartMessage": "An electric current ran across the battlefield!", - "electricClearMessage": "The electricity disappeared from the battlefield.", + "electric": "エレキフィールド", + "electricStartMessage": "足下に 電気が かけめぐる!", + "electricClearMessage": "足下の 電気が 消え去った!", - "grassy": "Grassy", - "grassyStartMessage": "Grass grew to cover the battlefield!", - "grassyClearMessage": "The grass disappeared from the battlefield.", + "grassy": "グラスフィールド", + "grassyStartMessage": "足下に 草がおいしげった!", + "grassyClearMessage": "足下の 草が消え去った!", - "psychic": "Psychic", - "psychicStartMessage": "The battlefield got weird!", - "psychicClearMessage": "The weirdness disappeared from the battlefield!", + "psychic": "サイコフィールド", + "psychicStartMessage": "足元が 不思議な感じに なった!", + "psychicClearMessage": "足元の 不思議感が 消え去った!", - "defaultBlockMessage": "{{pokemonNameWithAffix}} is protected by the {{terrainName}} Terrain!" + "defaultBlockMessage": "{{pokemonNameWithAffix}}は\n{{terrainName}}に 守られている!" }; From 60d19c9a2c96e2e7235878edfa930a5e49291b06 Mon Sep 17 00:00:00 2001 From: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> Date: Wed, 7 Aug 2024 16:31:02 +0200 Subject: [PATCH 008/282] [Feature] Unique Evil Team Admins (#3384) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Hardcoded Pokemon should have proper names * Add evil admin placeholder images * Add admin names to locale files * Add evil team admin dialogue * current things. * rename * team galactic wants to be special * Revert debug changes * Added Trainer Names and Titles * [Hotfix] Fix interactions of some moves not changing types (#3183) * [Hotfix] Fix wild spawns not having their HA (#3190) * Add evil admin placeholder images * Add admin names to locale files * Add evil team admin dialogue * Added new sprites * Make simple admin trainer pools * Add Korean localization * Revert this * [Feature] Named Evil Team Admins * Dateien removed * Revert override * French only needs one pair of evil team bosses :) * Some things Temp Mentioned in the PR * Removed NoDuplicates again...Because it only works on the speciality pool.... Also reordered the second admin wave. So we guarantee it is never the same one * German dialogue * Offset * Jördis just better * Credit for the artists (see https://www.deviantart.com/icejkai/art/Magma-Admin-Courtney-Trainer-Sprite-544510574) * Order * Added tsdoc and named it more clear * Fixed formatting and made it a void function * Changed offset to number and updated tsdoch * Improve readability * Removed extra lines * Fix this * Revert override * colress gets his own pool because @blitzy wants it (and i agree) * Added Rood (some plasma sage guy) * has voucher is not false by default. So only it will be set true for evil team leaders, gym leaders, elite 4 and champions * Apply suggestions from code review Co-authored-by: Lugiad' Co-authored-by: returntoice * Added the localization also to japanese * Update src/locales/ko/trainers.ts Co-authored-by: sodam <66295123+sodaMelon@users.noreply.github.com> * CA * Removed Colress * Colress Last Stand --------- Co-authored-by: Adrian T. <68144167+torranx@users.noreply.github.com> Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> Co-authored-by: Lugiad' Co-authored-by: returntoice Co-authored-by: sodam <66295123+sodaMelon@users.noreply.github.com> --- README.md | 1 + public/images/trainer/aqua_admin_f.json | 41 - .../{aqua_admin_m.json => archer.json} | 4 +- .../{rocket_admin_m.png => archer.png} | Bin .../{rocket_admin_m.json => ariana.json} | 2 +- .../{rocket_admin_f.png => ariana.png} | Bin .../{magma_admin_f.json => bryony.json} | 4 +- .../trainer/{flare_admin_f.png => bryony.png} | Bin public/images/trainer/courtney.json | 41 + public/images/trainer/courtney.png | Bin 0 -> 1508 bytes public/images/trainer/flare_admin_m.json | 41 - public/images/trainer/galactic_admin_f.json | 41 - public/images/trainer/galactic_admin_m.json | 41 - .../{flare_admin_f.json => jupiter.json} | 4 +- public/images/trainer/jupiter.png | Bin 0 -> 657 bytes public/images/trainer/magma_admin_f.png | Bin 847 -> 0 bytes public/images/trainer/magma_admin_m.json | 41 - public/images/trainer/mars.json | 41 + .../{galactic_admin_f.png => mars.png} | Bin public/images/trainer/matt.json | 41 + .../trainer/{aqua_admin_m.png => matt.png} | Bin public/images/trainer/petrel.json | 41 + public/images/trainer/petrel.png | Bin 0 -> 728 bytes public/images/trainer/plasma_sage.json | 2120 ----------------- public/images/trainer/plasma_sage.png | Bin 5075 -> 0 bytes public/images/trainer/proton.json | 41 + public/images/trainer/proton.png | Bin 0 -> 670 bytes public/images/trainer/rocket_admin_f.json | 41 - public/images/trainer/saturn.json | 41 + .../{galactic_admin_m.png => saturn.png} | Bin public/images/trainer/shelly.json | 41 + .../trainer/{aqua_admin_f.png => shelly.png} | Bin public/images/trainer/tabitha.json | 41 + .../{magma_admin_m.png => tabitha.png} | Bin public/images/trainer/xerosic.json | 41 + .../{flare_admin_m.png => xerosic.png} | Bin src/battle.ts | 24 +- src/data/dialogue.ts | 196 +- src/data/trainer-config.ts | 749 +++--- src/enums/trainer-type.ts | 430 ++-- src/field/trainer.ts | 4 +- src/locales/ca-ES/dialogue.ts | 275 ++- src/locales/ca-ES/trainers.ts | 42 +- src/locales/de/dialogue.ts | 289 ++- src/locales/de/trainers.ts | 42 +- src/locales/en/dialogue.ts | 271 ++- src/locales/en/trainers.ts | 42 +- src/locales/es/dialogue.ts | 197 ++ src/locales/es/trainers.ts | 53 +- src/locales/fr/dialogue.ts | 269 ++- src/locales/fr/trainers.ts | 43 +- src/locales/it/dialogue.ts | 269 ++- src/locales/it/trainers.ts | 52 +- src/locales/ja/dialogue.ts | 275 ++- src/locales/ja/trainers.ts | 44 +- src/locales/ko/dialogue.ts | 269 ++- src/locales/ko/trainers.ts | 44 +- src/locales/pt_BR/dialogue.ts | 197 ++ src/locales/pt_BR/trainers.ts | 42 +- src/locales/zh_CN/dialogue.ts | 269 ++- src/locales/zh_CN/trainers.ts | 41 +- src/locales/zh_TW/dialogue.ts | 269 ++- src/locales/zh_TW/trainers.ts | 53 +- src/system/voucher.ts | 2 +- 64 files changed, 3757 insertions(+), 3745 deletions(-) delete mode 100644 public/images/trainer/aqua_admin_f.json rename public/images/trainer/{aqua_admin_m.json => archer.json} (95%) rename public/images/trainer/{rocket_admin_m.png => archer.png} (100%) rename public/images/trainer/{rocket_admin_m.json => ariana.json} (95%) rename public/images/trainer/{rocket_admin_f.png => ariana.png} (100%) rename public/images/trainer/{magma_admin_f.json => bryony.json} (95%) rename public/images/trainer/{flare_admin_f.png => bryony.png} (100%) create mode 100644 public/images/trainer/courtney.json create mode 100644 public/images/trainer/courtney.png delete mode 100644 public/images/trainer/flare_admin_m.json delete mode 100644 public/images/trainer/galactic_admin_f.json delete mode 100644 public/images/trainer/galactic_admin_m.json rename public/images/trainer/{flare_admin_f.json => jupiter.json} (95%) create mode 100644 public/images/trainer/jupiter.png delete mode 100644 public/images/trainer/magma_admin_f.png delete mode 100644 public/images/trainer/magma_admin_m.json create mode 100644 public/images/trainer/mars.json rename public/images/trainer/{galactic_admin_f.png => mars.png} (100%) create mode 100644 public/images/trainer/matt.json rename public/images/trainer/{aqua_admin_m.png => matt.png} (100%) create mode 100644 public/images/trainer/petrel.json create mode 100644 public/images/trainer/petrel.png delete mode 100644 public/images/trainer/plasma_sage.json delete mode 100644 public/images/trainer/plasma_sage.png create mode 100644 public/images/trainer/proton.json create mode 100644 public/images/trainer/proton.png delete mode 100644 public/images/trainer/rocket_admin_f.json create mode 100644 public/images/trainer/saturn.json rename public/images/trainer/{galactic_admin_m.png => saturn.png} (100%) create mode 100644 public/images/trainer/shelly.json rename public/images/trainer/{aqua_admin_f.png => shelly.png} (100%) create mode 100644 public/images/trainer/tabitha.json rename public/images/trainer/{magma_admin_m.png => tabitha.png} (100%) create mode 100644 public/images/trainer/xerosic.json rename public/images/trainer/{flare_admin_m.png => xerosic.png} (100%) diff --git a/README.md b/README.md index ade4adc2c59..77246fa4402 100644 --- a/README.md +++ b/README.md @@ -81,6 +81,7 @@ Check out [Github Issues](https://github.com/pagefaultgames/pokerogue/issues) to - kyledove - Brumirage - pkmn_realidea (Paid Commissions) + - IceJkai ### 🎨 Trainer Portraits - pkmn_realidea (Paid Commissions) diff --git a/public/images/trainer/aqua_admin_f.json b/public/images/trainer/aqua_admin_f.json deleted file mode 100644 index 35e6e43edc3..00000000000 --- a/public/images/trainer/aqua_admin_f.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "textures": [ - { - "image": "aqua_admin_f.png", - "format": "RGBA8888", - "size": { - "w": 80, - "h": 80 - }, - "scale": 1, - "frames": [ - { - "filename": "0001.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 80, - "h": 80 - }, - "frame": { - "x": 0, - "y": 0, - "w": 80, - "h": 80 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:efd07ff3ed1e610150a4b8ca18974343:d9b85b9eb11182e9e4669e2bd8b08694:72b7b50231708a9486d5f315824e4df1$" - } -} diff --git a/public/images/trainer/aqua_admin_m.json b/public/images/trainer/archer.json similarity index 95% rename from public/images/trainer/aqua_admin_m.json rename to public/images/trainer/archer.json index f52412623cc..892a137d61c 100644 --- a/public/images/trainer/aqua_admin_m.json +++ b/public/images/trainer/archer.json @@ -1,7 +1,7 @@ { "textures": [ { - "image": "aqua_admin_m.png", + "image": "archer.png", "format": "RGBA8888", "size": { "w": 80, @@ -38,4 +38,4 @@ "version": "3.0", "smartupdate": "$TexturePacker:SmartUpdate:831f5748dad92911b10a1cb358ee2dae:a3bf81bbaa3b49cad5e0e549cf94563b:bb6befc9383c9c08837183ae2a7a80c1$" } -} \ No newline at end of file +} diff --git a/public/images/trainer/rocket_admin_m.png b/public/images/trainer/archer.png similarity index 100% rename from public/images/trainer/rocket_admin_m.png rename to public/images/trainer/archer.png diff --git a/public/images/trainer/rocket_admin_m.json b/public/images/trainer/ariana.json similarity index 95% rename from public/images/trainer/rocket_admin_m.json rename to public/images/trainer/ariana.json index a1ad82dd9a2..d7d24afed6e 100644 --- a/public/images/trainer/rocket_admin_m.json +++ b/public/images/trainer/ariana.json @@ -1,7 +1,7 @@ { "textures": [ { - "image": "rocket_admin_m.png", + "image": "ariana.png", "format": "RGBA8888", "size": { "w": 80, diff --git a/public/images/trainer/rocket_admin_f.png b/public/images/trainer/ariana.png similarity index 100% rename from public/images/trainer/rocket_admin_f.png rename to public/images/trainer/ariana.png diff --git a/public/images/trainer/magma_admin_f.json b/public/images/trainer/bryony.json similarity index 95% rename from public/images/trainer/magma_admin_f.json rename to public/images/trainer/bryony.json index 95e00803df4..7d939fff58f 100644 --- a/public/images/trainer/magma_admin_f.json +++ b/public/images/trainer/bryony.json @@ -1,7 +1,7 @@ { "textures": [ { - "image": "magma_admin_f.png", + "image": "bryony.png", "format": "RGBA8888", "size": { "w": 80, @@ -38,4 +38,4 @@ "version": "3.0", "smartupdate": "$TexturePacker:SmartUpdate:831f5748dad92911b10a1cb358ee2dae:a3bf81bbaa3b49cad5e0e549cf94563b:bb6befc9383c9c08837183ae2a7a80c1$" } -} \ No newline at end of file +} diff --git a/public/images/trainer/flare_admin_f.png b/public/images/trainer/bryony.png similarity index 100% rename from public/images/trainer/flare_admin_f.png rename to public/images/trainer/bryony.png diff --git a/public/images/trainer/courtney.json b/public/images/trainer/courtney.json new file mode 100644 index 00000000000..de55e91eb85 --- /dev/null +++ b/public/images/trainer/courtney.json @@ -0,0 +1,41 @@ +{ + "textures": [ + { + "image": "courtney.png", + "format": "RGBA8888", + "size": { + "w": 52, + "h": 80 + }, + "scale": 1, + "frames": [ + { + "filename": "0001.png", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 52, + "h": 80 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 52, + "h": 80 + }, + "frame": { + "x": 0, + "y": 0, + "w": 52, + "h": 80 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:831f5748dad92911b10a1cb358ee2dae:a3bf81bbaa3b49cad5e0e549cf94563b:bb6befc9383c9c08837183ae2a7a80c1$" + } +} diff --git a/public/images/trainer/courtney.png b/public/images/trainer/courtney.png new file mode 100644 index 0000000000000000000000000000000000000000..991e7ac006f416414404789ac4e889141b058506 GIT binary patch literal 1508 zcmV{b*2000+sMObuGZ)S9NVRB^vM@&RePDdbiWpW@hE;Mn4q~QPn00?w&PDe*f zL^A*Y002sWDIWj;00d`2O+f$vv5yPBlF#s}z7bD+YMIV~GZojShF z&h1*SlJ>o6b6Pea`*mXqS(}0Yv-k0K!4ClpL%x{}F1-Odv%XoH0$>JWcJIb+!T-$* zlLZK;bcC~ZoHxhK>=;na6^NwF(BC-_eZm~29T*HyRR;rV7MScn^b-_#e7H9?0)_K+ARKoB zr^Z^D3RPw4YnxTLhAgWAfc_;?;^7G5Zi=u=9kVFk= z_tVW0lviomvL_qR3#;pe8TFX<4RhX?Hw@1Pr7Fz=k`2f}-oNr;@#eXAO2a8@GXsce z1Hb^0cV-324rESKn<*e__?)9q^TK2SGH1+j1tLjWJC4V4P7`Ia01;XSLAU{<;RRGG zh^#=UV@@+d#h}PJDPfWV*{FnrKzSf$q`6=k18L!Cd4r)AAcgeRK<|LaDI`IhkEw(* zHUcVSYM8l!%o)w>9)@e^OTcig{Q$iK(nMGlLO`i9sF@3DE*PH(HN(fQweZt|vo}Br zRu7e7MeT)==_xL;!KuN-P*d|zb(UoMpfgF-@F6xSM94#g-7HW(EV)nP zJ~SAFu|6_wMGTAX5_RG5z+V zAdafyOf!H{Xbt@&AvZ5jY$oapQ{BhHk)k)rppX*CgJ@x@ucmw`HYr|{1H}f87?4)z z8d^=uqNG4|psWM2Y{Gjt_NwH<0O{J0wfW^0v!-*U)_}a@w8d5>ngF%(CCTSo+tK#5 zvuD#ktPO?ChEQV)*?CMIYj5(LRupP;YYphy-i>x1)KTqi<w!ZqWAF)5&-%tOrHq>E?fKtqZf>UWB6f$-E z_R9L{(XpzOVkFECboHO5a)0pPe)#j~ei?dfcKqu0Zh4$6{Bnn!O$T&-#4Odn+2L=Y z;k&t3Mmb&8u6k*r6TIF7>Fksj`z*6ysor(BUdz4l((-73@Z`5}?zPuTOSSc)IQ{YN zop9-g1N(&sjc?XgxaqqDoqAi}Nx8JrsX{wvE|=>3`o~}CZrYVPW~tT5rjS+FL&s~c zNveu&DHXx=iz*$mRUvXu>J{;1FqTX7V^{q~)WZOjB9UeVs`{!o29u-zB<(}D9v+Mx zU;g=KxPEl>zw78b$wxP~9DOKAiKE{qkazS;$GUae&O%P1a8~=0hMBHPu+-UWAgXB; zs;Z{BHYH4QAP*J$h}K`%dmxdrDeLN?I{7F#rGn{RYsA00001 zbW%=J06^y0W&i*J4@pEpRCwCV(?O0ZF%W~{kkFG(rQN>&ZJ$+nd%ucX-kNm0L9%RuDvwoEWzS1!sVcQyP$ihB z(*n-LdO(P20+;LnJ7!H#oCBPLwN6m(fqhWoscPk@0u5f_0@bt(%!xHKd79Xy9kr1x zmROHD<;{7xMAk}9fi6)b1ezvN5x6PP;z6y4Hm^Nk6A1<$55x^dfDUlr(J;aVatr`t z3_@*#MEn9t2iW@pJ7`(R-tQY-5e|@G-1i+3bbvBQEzE(1Ah`{Kkpu6Xi#?De$Z_9e z3?{z^F5nFo1IY3lBuMUf%z+E+lE{efLFT{&Ltb7V8=yF%B$yXtf%pmp*)FVsePl$6 z_-Z1a&nM4Izzgia_c!x7p3jcDyq+QxYh`4Gk38sh_ zSk+l2engUIJ+I}dAhj#OtG3oI@-t5hE_rWIo=UK_vwb>HM;EfZ!Ok<|`nFvERWA<_ z(9wMV9^3~}UkJ&qh3jDarx?I$^EzE#VWd~()n);EkBA$pvUtE>e`80C2>QI72rnqg zFDBTXAmxp5+r;2dHZZ~qrUMEF3MLH|TQ2v|Wzgdgmq_uD3t=-me@ rjG={edg?EO1rb3OWAt+WMkD|L6%sG6qL9*v00000NkvXXu0mjfNFOIX literal 0 HcmV?d00001 diff --git a/public/images/trainer/magma_admin_f.png b/public/images/trainer/magma_admin_f.png deleted file mode 100644 index 979fe6ae83738ea7c680d15006b2199a56529fbd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 847 zcmV-V1F-ywP)^j`@E{2+?9q~^>| zegX|MSJPNTUS34%kPze4(>TEpF3-3khTs6#&@hHx8>0m^{ewq+%W!n%0C zWnIa*<9L66Z@G9-z#)Rr9>0}4juu2%d|(5T_T<`mW)*#2!y>I|$_;~o#BLC#&GUfI z0X0Bs`%et>zQ29#pbBDp^j~lDyldLFM$M$6c?KTvgC;7d;-DgY9{K`u2kptQ&*<0% zA`*X#O7?E=MxA_%N+ze*Aa;?uQ$)@=IUBM`ymf_0Oh`FpYznwUi74I{V;WQ51TGLE z1QVb#D>!oWiD4<5Y098D893dd3uF@O339@%h*Oj;Il!=reK$xMa^sW}tCwA(NOyvw zAQNrbB{D5bfD)hrQUpx&bS2~hf{2xkuoWF0Vz3fNWW)k)Xc~+j5y@VM6-`W&dKE+~ z6B{OCg-_9O9f5igF;1B7XDGtD__iJOCKWYBRF5cly-nRy3`<7~u>&-Zq=+zpNyPw{ z$0U!UdWJs}+&vS&6%Lc?c!q>>8!^nwDuN3Dk`EGjLS#V7k0<9(sNgB$15e(Uh;z!w z3TCFeh~~K@GYlKks3a@si_MCaJHdv%pfa4s3v>r328(+BB$V{Crmq2>Qn@A81@}rI zY-(uwy&7l|nj-cUy#ns21okFZ1m^-)>Pmkv6jeYB1-yoCa8{&&A^P`ZvBpooxxk0Lq12AYQdeboHt Z`2!llB*-I|PaFUM002ovPDHLkV1fX3YV`mB diff --git a/public/images/trainer/magma_admin_m.json b/public/images/trainer/magma_admin_m.json deleted file mode 100644 index 977e911eb69..00000000000 --- a/public/images/trainer/magma_admin_m.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "textures": [ - { - "image": "magma_admin_m.png", - "format": "RGBA8888", - "size": { - "w": 80, - "h": 80 - }, - "scale": 1, - "frames": [ - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 80, - "h": 80 - }, - "frame": { - "x": 0, - "y": 0, - "w": 80, - "h": 80 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:f63ad48affc076f60fae78992c96a2bf:80928b32710abcb28c07c6fc5a425d99:3b961d8852b62aaf24ceb2030c036515$" - } -} diff --git a/public/images/trainer/mars.json b/public/images/trainer/mars.json new file mode 100644 index 00000000000..0f2dcded0c3 --- /dev/null +++ b/public/images/trainer/mars.json @@ -0,0 +1,41 @@ +{ + "textures": [ + { + "image": "mars.png", + "format": "RGBA8888", + "size": { + "w": 80, + "h": 80 + }, + "scale": 1, + "frames": [ + { + "filename": "0001.png", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 80, + "h": 80 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 80, + "h": 80 + }, + "frame": { + "x": 0, + "y": 0, + "w": 80, + "h": 80 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:831f5748dad92911b10a1cb358ee2dae:a3bf81bbaa3b49cad5e0e549cf94563b:bb6befc9383c9c08837183ae2a7a80c1$" + } +} diff --git a/public/images/trainer/galactic_admin_f.png b/public/images/trainer/mars.png similarity index 100% rename from public/images/trainer/galactic_admin_f.png rename to public/images/trainer/mars.png diff --git a/public/images/trainer/matt.json b/public/images/trainer/matt.json new file mode 100644 index 00000000000..b749e740d00 --- /dev/null +++ b/public/images/trainer/matt.json @@ -0,0 +1,41 @@ +{ + "textures": [ + { + "image": "matt.png", + "format": "RGBA8888", + "size": { + "w": 80, + "h": 80 + }, + "scale": 1, + "frames": [ + { + "filename": "0001.png", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 80, + "h": 80 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 80, + "h": 80 + }, + "frame": { + "x": 0, + "y": 0, + "w": 80, + "h": 80 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:831f5748dad92911b10a1cb358ee2dae:a3bf81bbaa3b49cad5e0e549cf94563b:bb6befc9383c9c08837183ae2a7a80c1$" + } +} diff --git a/public/images/trainer/aqua_admin_m.png b/public/images/trainer/matt.png similarity index 100% rename from public/images/trainer/aqua_admin_m.png rename to public/images/trainer/matt.png diff --git a/public/images/trainer/petrel.json b/public/images/trainer/petrel.json new file mode 100644 index 00000000000..182a402cae4 --- /dev/null +++ b/public/images/trainer/petrel.json @@ -0,0 +1,41 @@ +{ + "textures": [ + { + "image": "petrel.png", + "format": "RGBA8888", + "size": { + "w": 80, + "h": 80 + }, + "scale": 1, + "frames": [ + { + "filename": "0001.png", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 80, + "h": 80 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 80, + "h": 80 + }, + "frame": { + "x": 0, + "y": 0, + "w": 80, + "h": 80 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:831f5748dad92911b10a1cb358ee2dae:a3bf81bbaa3b49cad5e0e549cf94563b:bb6befc9383c9c08837183ae2a7a80c1$" + } +} diff --git a/public/images/trainer/petrel.png b/public/images/trainer/petrel.png new file mode 100644 index 0000000000000000000000000000000000000000..d4043735316d1373011700877f69da15e83f8dfd GIT binary patch literal 728 zcmV;}0w?{6P)q77h0asqVC1&DI zDimB?+(Q>q^XszI^E?B<<>I*gS_tk7=D}+P!Hk^~_dNp4nFH6H2?i`=gq&g*y@0N+ z5d{kXaW$|k5J2Wh(Q7GtDN8NnL}p1*#kFk9QU%35Rg!a{qB2k`hbR-3aZgAbD$kDQ z&4AiK1@H+fCJrnFTf$0do(jf61;z64icgf=#;})g=%YtaQ~((irFjWb+>#DD)JcqZ z?F~hFANh8=I5yBhp;lZxo(ldSgo?;bH>|ii1NMdY#9pB?<}oOP#)6i!{t8sHfp;0O z%=gxx9Y2B(Go=4b-SdgS0lYv$Y7dGs0%ium;ZOr13N@oh@4v+c!lXbvuni6}O#`Vm z&`jYSa)^nFj(SXuU{BR}anP8gQ8B;84^Y!+Gyr{rRRCv4JQ1xWS--F%#wOg-moW9{dn6 z2_hbRdm(3rh`Nzp2_`502p|}wHw$`ZPXUH0Pz}QJ4R*g~49kjuG)Fq`xkGJAszX)b+%& literal 0 HcmV?d00001 diff --git a/public/images/trainer/plasma_sage.json b/public/images/trainer/plasma_sage.json deleted file mode 100644 index 05e75141ec0..00000000000 --- a/public/images/trainer/plasma_sage.json +++ /dev/null @@ -1,2120 +0,0 @@ -{ - "textures": [ - { - "image": "plasma_sage.png", - "format": "RGBA8888", - "size": { - "w": 250, - "h": 250 - }, - "scale": 1, - "frames": [ - { - "filename": "0001.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 11, - "y": 1, - "w": 56, - "h": 79 - }, - "frame": { - "x": 1, - "y": 1, - "w": 56, - "h": 79 - } - }, - { - "filename": "0002.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 11, - "y": 1, - "w": 56, - "h": 79 - }, - "frame": { - "x": 1, - "y": 1, - "w": 56, - "h": 79 - } - }, - { - "filename": "0003.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 11, - "y": 1, - "w": 56, - "h": 79 - }, - "frame": { - "x": 1, - "y": 1, - "w": 56, - "h": 79 - } - }, - { - "filename": "0004.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 11, - "y": 1, - "w": 56, - "h": 79 - }, - "frame": { - "x": 1, - "y": 1, - "w": 56, - "h": 79 - } - }, - { - "filename": "0005.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 13, - "y": 2, - "w": 55, - "h": 78 - }, - "frame": { - "x": 1, - "y": 82, - "w": 55, - "h": 78 - } - }, - { - "filename": "0006.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 14, - "y": 2, - "w": 54, - "h": 78 - }, - "frame": { - "x": 59, - "y": 1, - "w": 54, - "h": 78 - } - }, - { - "filename": "0007.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 14, - "y": 2, - "w": 54, - "h": 78 - }, - "frame": { - "x": 59, - "y": 1, - "w": 54, - "h": 78 - } - }, - { - "filename": "0008.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 16, - "y": 3, - "w": 53, - "h": 77 - }, - "frame": { - "x": 1, - "y": 162, - "w": 53, - "h": 77 - } - }, - { - "filename": "0009.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 16, - "y": 4, - "w": 53, - "h": 76 - }, - "frame": { - "x": 115, - "y": 1, - "w": 53, - "h": 76 - } - }, - { - "filename": "0010.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 16, - "y": 4, - "w": 53, - "h": 76 - }, - "frame": { - "x": 115, - "y": 1, - "w": 53, - "h": 76 - } - }, - { - "filename": "0011.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 16, - "y": 4, - "w": 53, - "h": 76 - }, - "frame": { - "x": 115, - "y": 1, - "w": 53, - "h": 76 - } - }, - { - "filename": "0012.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 16, - "y": 4, - "w": 53, - "h": 76 - }, - "frame": { - "x": 115, - "y": 1, - "w": 53, - "h": 76 - } - }, - { - "filename": "0013.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 16, - "y": 4, - "w": 53, - "h": 76 - }, - "frame": { - "x": 115, - "y": 1, - "w": 53, - "h": 76 - } - }, - { - "filename": "0014.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 16, - "y": 4, - "w": 53, - "h": 76 - }, - "frame": { - "x": 115, - "y": 1, - "w": 53, - "h": 76 - } - }, - { - "filename": "0015.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 16, - "y": 4, - "w": 53, - "h": 76 - }, - "frame": { - "x": 115, - "y": 1, - "w": 53, - "h": 76 - } - }, - { - "filename": "0016.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 20, - "y": 3, - "w": 49, - "h": 77 - }, - "frame": { - "x": 170, - "y": 1, - "w": 49, - "h": 77 - } - }, - { - "filename": "0017.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 20, - "y": 2, - "w": 47, - "h": 78 - }, - "frame": { - "x": 58, - "y": 82, - "w": 47, - "h": 78 - } - }, - { - "filename": "0018.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 56, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0019.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 56, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0020.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 0, - "w": 46, - "h": 80 - }, - "frame": { - "x": 107, - "y": 81, - "w": 46, - "h": 80 - } - }, - { - "filename": "0021.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 0, - "w": 46, - "h": 80 - }, - "frame": { - "x": 104, - "y": 163, - "w": 46, - "h": 80 - } - }, - { - "filename": "0022.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 0, - "w": 46, - "h": 80 - }, - "frame": { - "x": 155, - "y": 80, - "w": 46, - "h": 80 - } - }, - { - "filename": "0023.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 0, - "w": 46, - "h": 80 - }, - "frame": { - "x": 155, - "y": 80, - "w": 46, - "h": 80 - } - }, - { - "filename": "0024.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 0, - "w": 46, - "h": 80 - }, - "frame": { - "x": 155, - "y": 80, - "w": 46, - "h": 80 - } - }, - { - "filename": "0025.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 0, - "w": 46, - "h": 80 - }, - "frame": { - "x": 155, - "y": 80, - "w": 46, - "h": 80 - } - }, - { - "filename": "0026.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 0, - "w": 46, - "h": 80 - }, - "frame": { - "x": 155, - "y": 80, - "w": 46, - "h": 80 - } - }, - { - "filename": "0027.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 0, - "w": 46, - "h": 80 - }, - "frame": { - "x": 155, - "y": 80, - "w": 46, - "h": 80 - } - }, - { - "filename": "0028.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 0, - "w": 46, - "h": 80 - }, - "frame": { - "x": 155, - "y": 80, - "w": 46, - "h": 80 - } - }, - { - "filename": "0029.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 0, - "w": 46, - "h": 80 - }, - "frame": { - "x": 155, - "y": 80, - "w": 46, - "h": 80 - } - }, - { - "filename": "0030.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 0, - "w": 46, - "h": 80 - }, - "frame": { - "x": 155, - "y": 80, - "w": 46, - "h": 80 - } - }, - { - "filename": "0031.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 0, - "w": 46, - "h": 80 - }, - "frame": { - "x": 155, - "y": 80, - "w": 46, - "h": 80 - } - }, - { - "filename": "0032.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 0, - "w": 46, - "h": 80 - }, - "frame": { - "x": 155, - "y": 80, - "w": 46, - "h": 80 - } - }, - { - "filename": "0033.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 0, - "w": 46, - "h": 80 - }, - "frame": { - "x": 155, - "y": 80, - "w": 46, - "h": 80 - } - }, - { - "filename": "0034.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 0, - "w": 46, - "h": 80 - }, - "frame": { - "x": 203, - "y": 80, - "w": 46, - "h": 80 - } - }, - { - "filename": "0035.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 0, - "w": 46, - "h": 80 - }, - "frame": { - "x": 203, - "y": 80, - "w": 46, - "h": 80 - } - }, - { - "filename": "0036.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 0, - "w": 46, - "h": 80 - }, - "frame": { - "x": 152, - "y": 163, - "w": 46, - "h": 80 - } - }, - { - "filename": "0037.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0038.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0039.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0040.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0041.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0042.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0043.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0044.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0045.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0046.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0047.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0048.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0049.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0050.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0051.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0052.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0053.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0054.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0055.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0056.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0057.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0058.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0059.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0060.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0061.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0062.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0063.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0064.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0065.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0066.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0067.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0068.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0069.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0070.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0071.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0072.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0073.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0074.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0075.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0076.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0077.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0078.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0079.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0080.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0081.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0082.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0083.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0084.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0085.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0086.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0087.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0088.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0089.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0090.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0091.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0092.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0093.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0094.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0095.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0096.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0097.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0098.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0099.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - }, - { - "filename": "0100.png", - "rotated": false, - "trimmed": true, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 21, - "y": 1, - "w": 46, - "h": 79 - }, - "frame": { - "x": 200, - "y": 162, - "w": 46, - "h": 79 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:98df2be457c75de554b8ce6c2f5ff582:93e2cb242dc211e2485f87e4db93af88:0c38bc008e5ede7b6331c02b8220846f$" - } -} \ No newline at end of file diff --git a/public/images/trainer/plasma_sage.png b/public/images/trainer/plasma_sage.png deleted file mode 100644 index 6c866562989a99bbba8b844b7d17f3e5be6128de..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5075 zcmXX~cRX9)8#Ze;c5SJ>XNkQ+t48fj?LCUdtWrCuReOYrEv-#$@8|vJoWTPY?Ah@Y}U)vNPPp>CAG5$IzgP_3& zDPsfkyZDG7tgsGYVPR=uFn;KPZSliZ5A1830E59A5+IYNrjwJatJRTvt8edpV$sJ7 z2!l-x%?LEm3m*7{BJjQqgn)pG;d&Ah6vJ2u2pCj!wKdJdmv&)PIaMO`iK6W9tqN4H zuGS<1H0gf1=?3iHV?Q1pnG2jzp%~B@9NP#uTLvsUbvkBKm=B#VEh|X8uebtkGrJMx zNvRudzJ)s6`YFLsmvGW@FDKo{m1f2Lx)5p-Wdog*iPbAydl?e#^;7JcabXjXz~$!^ z34;Hv07Z}96cuM+K;Zei*Gym=V!39cDX@v^uQxWvw)4|X(SOnwEK9JHorPGtfq*f^ zp=;ti*~es{zD$t@|A(f2y6(eTwRiyfSw+URk7J~nY`yctcYc@&fJDx9*DRx-WQC({ zKTy9q0&Nd_v*^qW)&u@-Io1sTFTeSSAZ`NT?o~E6U0#GQ#A#jsQ2O~tpZtz`~_t0Z?m_t6|K zuYUqDOr>Ia;r^Py(Qzlhe`qNvw9}xR9zAx{7{B~uwll?_w?rxP(}{Y~U$k9q>4%aU z>Ts%Dk|X{i9b0hSKf#_vp<3B^8efHn*FRcsQ`(E&nlg_{OSgZ3%%ypi-)8Od&es_@ zCg&Oc&Q!adbd;6|60sXXEzjX@#CxsW+3x@HRlVx1SG$w&g{~b6>Sc#6Id$i* zAlM#cgh%fd(R7~Z*Y@k~kIl*!O&7H6I@vV39oOeRj*3T*g**}ncioRNJ8j(N2{m^Z zmyj8Vz>2utSb*5&UYfSFs&q2-=umZWxSywJdwegV(#+}G%&mWj8+47pemfic?<#$GW8h(lVvRWyWS|20n1cKW_*qG2)u6tiG-6!DpIi z$HJ#x138|4wfDk8tzuxOPzqXzg=%?0l3IqpOW8hNl;(|ek+}k$GN>3aJzBXH9lg7u z60BV0NfhPl=IaZ_EKG3TM9&vdPHLe>;R2#1&GFQh!Y*55+YmwdXAz?%3E>5PdyKy= zo4J6%duunc;Ud2p7P3c8?}ZbTOI;koCQ1e#)KG2Vy1RKqLxFWmP?n%WU-9Av#P-!W zV{(6!m`8BgRjNCgyT~~0C*EM`1ODF;VRA*Reo?T(!w>~bA(_Zs-4GN2g<&^WvLw&z zj-^7JuNolybSpoXLOi2%fp>*e7?!}xIv@I853n-|MTWE1wVqYhN*nm;UL0XhVO%M{ zr5#kVQ)rLp0q&j@v(HX93W6?OG6krUIF{JNAJE@v#TAuUR2E#*ofO&L}xFcPkvV*NN|n3J~S}DI5Nm4O4}A% zxF3HP^J6fs;1{|l7_B0>Zjd3D@ zeWJfz-5!CY&a9!N(q{g)@=N5(A!e6xO}HVF14cl%x z71?srX<9v&q zc6*Clw@9{xy{SBdKg^BLrNCcQ<@LY&+^R{9Me5Iso7Sx9^+*Dql9{GHu#unszGNX@ z`CN|Rj*I?$lVcjl>_#Dp9Ry`oqbKji%4wVUy?P=t^JMr!BGPhzL`vVcyQ-VFEJR(^ z%%0~}!?&&!P6LlxK_h`-C60$yz9M4pRRaE8YJJtrf8off`f7*JlFKE|r={UNLgd~3 z2iRRnrB`1bN5JQ^eYpEGtSoX(+O3r`3!p_+w$tIzS0e9)Bw8IEys>q+*1GEuLuvb% z=5pKfS3Mu%#d!Y{A1?_L=R_r(aovCj7Rtacm7}r>z?15{tScOx-%n z80a(T!CBiKOQ|3?L~_(Uzx`}jDa1JW^;y8p8#N*2CjoX)(>uQKWuGRVWzg!1%AL5l z9Su@gaYG*Oqn60hH5ECc_`g8p_6%fxw6|m{iu@mgiDYsqFzj%6|E)%7Igz0_7kA~Q zYgcbX=;B>XJP^|QEYe%kb&kYS%v6XSfN#axCv^MKG%9p@$=s}v|3K@oo?V*8%&FdH zyf~#eZeAoyZuW8xM&>@O8CpnWfRe5aMn34g+S2fCZ}>^s>aomR+zIzn7zdcg)JH7k zKT=nmEGBGtu-xO2HTtxA5>?_R!{J6IGCfxj((vaEtOHm9T&i=vnCo-rBwK`2%E~SE z)2xNsdp{s;y#@EvJxnCN-l>l0fj{)M`0(-Z@l@umx!b;xXA9>gr2k5W;<2x{UA9Y~ ze&+TS&P9Q)#^PJQ-Bz}at;yG%_bRi?>LAYb_t07l%;H4EnCWx-_NN z#qT(g78hR)T~XVxW4#>>(#Tr1m~KlN+K8FcwSvBUbbu8iQ=?{|qn@*?*1gl3$I+ls zwHsP(Q8(P#_xRDm)2X|RG0e3p!4rfxK7{GCYt2(SwBp(e^g71fddRq^S6TK0>=XAG zL6Q=EP_IGKPgng8hxr=w5)==y{@PXu+cQ5RXAO-=%Dabe4d1DA_ietdPcD~sq?$P| z-b$w*U*fOPj8-0RRsvdp5Tx#bK+xVkTNz{GZ7K~BMMNqo4 zn@pG4nvV=he+-MP6%*OZ?aAApY?dg9L{`gq?;y;rb|G6>|7U=43D0uPRM%SjgLU)u zk;0Gh3j^OnNNq$55Tx$PCey{Ydx`S>0T8KEgz4tna*Wlo>0ZA+lMyE{dT`q1fIw|*@nQZ3EJ}&5sOL@Pw zEF^aR*nN4|(wH1Z&gLl`?}bWZ3iAZ9<`b_3kZ!g*?>>BHH*veTuwz|-#4!GkgQ!6< z`+dW}x$ZF8+G8vf@KO-1COpnc>S|FZ)JOzR@qU4cAI;S&1Kw zX|lL>QLI4&d2FRGImgoF3k)EFDLEohl|Pm3CBW!rBJv$PNX&(+gE6eeG6w0sYed!N zbT;%^!QN$+)OGL8Tq!JKmz5Rkx-UZYU28v zIpfRHtO7we>iSzFJMjPI0wtTH9`}ehqz-H-BAFU71k(%M`fJ79WzECI8(Vr3iL!MS;b#C;`uPy>|u10P(2U9 z_jYYdykYMz@da3(In&-Wy<#uJ0T;L!>Tf+v6Ue|Du%K zc$|{a`}L&d8Z%Di+kAY!zG*eIIP46$l>3Yzs=+%tWvu=8a}<=c&=Ev^dkd&5}?xE<*!0LT-?oZ{=bQmenyq+nxPjY_w0V2Y{5l@tR|261Ki(w1TIcHd5NWVn`! zxFVv`YS&W2~0S$Wg`Z4Y-+ZnNQxZ$Je|(s+--Ul0 z@cgrx+dG0zho(HXEw-$hyGRs!vK7Mc{*Vs4^dF(@uYeJ`p7YTJ;!KQ@elE`qVs-J( zOY&EuR={c);%-1Lf;hW*;zHk1P5zZ)#CphreM*T{{8&g0zvZv`9Fsr?)(`(-4D_Eq zZ-X*?zCDS5(iORFf?xCC8&&e+CgY1a`xAT|eP!+1+@3~A(P72ND15JzT$7?XStn0s z=-OV3Vww^00001 zbW%=J06^y0W&i*J97#k$RCwC$*GIavIt+wi+@d2cef!_-HG&hGlP!<#^Vf{@y2vp7 z%P}4q$SL9s@}w6M#&~)q9gzpOL{UctlmbyCxByErhKS)|WlgtOZ?#qc-$Y7Dg7tR0 z-&c%aUCD+aHZxG^a-puGSvSaiBj+uZI}~dq{bEZKD^@QvcE3+FFhMr4)_W^g=F{o% zxYssoBcWGhuJ_YCpIWHfywte?=F2Jac%4_w8cOEcK3&S?1%T9n^z)i!S=TF0i;p_?B8b;aYrr%c#VGD#}HqGHcwXUYGk+_dI6QtR!=&B39Whl9+c;}09{WN zgG+&jiljZ~sbaq1CZa72@Ei|u2xzOfvSUD&#mv}?`T)?DWnl_1k_V&UChjU(kZB;O z&p^oSu{eT80*sEZgQZZ4Tc)ByEGi{5qgd+s0M>%3m^ICW$-_&LGBwA{VLvBXl89?* zZ&QgWPwr2#NFEF_z+vLb;bXz~4L$Eg4i)ntFcx$shU_zX@um?KL)pDok)$^sRCsTq zr+;w68&eT^fQRWE=;APd$av4sRB~W!4j)buBtCB3p1_!6eW0$kW_bd)SqpvOn&)k~ zM!LZG#kn5KEHTeIL2Kc7T({8SjR!y7kpDLr+kG$Qz4740c(6lM;|7Drb9@jbqvJNw zcNGnO53Vukd(eL0lJ6@Z>91nsyYYYnm`M!w?U)1eA9|oUa#PuW{r~^~07*qoM6N<$ Eg1sv%4*&oF literal 0 HcmV?d00001 diff --git a/public/images/trainer/rocket_admin_f.json b/public/images/trainer/rocket_admin_f.json deleted file mode 100644 index 7c154785ba3..00000000000 --- a/public/images/trainer/rocket_admin_f.json +++ /dev/null @@ -1,41 +0,0 @@ -{ - "textures": [ - { - "image": "rocket_admin_f.png", - "format": "RGBA8888", - "size": { - "w": 80, - "h": 80 - }, - "scale": 1, - "frames": [ - { - "filename": "0001.png", - "rotated": false, - "trimmed": false, - "sourceSize": { - "w": 80, - "h": 80 - }, - "spriteSourceSize": { - "x": 0, - "y": 0, - "w": 80, - "h": 80 - }, - "frame": { - "x": 0, - "y": 0, - "w": 80, - "h": 80 - } - } - ] - } - ], - "meta": { - "app": "https://www.codeandweb.com/texturepacker", - "version": "3.0", - "smartupdate": "$TexturePacker:SmartUpdate:831f5748dad92911b10a1cb358ee2dae:a3bf81bbaa3b49cad5e0e549cf94563b:bb6befc9383c9c08837183ae2a7a80c1$" - } -} \ No newline at end of file diff --git a/public/images/trainer/saturn.json b/public/images/trainer/saturn.json new file mode 100644 index 00000000000..29fad6324c9 --- /dev/null +++ b/public/images/trainer/saturn.json @@ -0,0 +1,41 @@ +{ + "textures": [ + { + "image": "saturn.png", + "format": "RGBA8888", + "size": { + "w": 80, + "h": 80 + }, + "scale": 1, + "frames": [ + { + "filename": "0001.png", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 80, + "h": 80 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 80, + "h": 80 + }, + "frame": { + "x": 0, + "y": 0, + "w": 80, + "h": 80 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:831f5748dad92911b10a1cb358ee2dae:a3bf81bbaa3b49cad5e0e549cf94563b:bb6befc9383c9c08837183ae2a7a80c1$" + } +} diff --git a/public/images/trainer/galactic_admin_m.png b/public/images/trainer/saturn.png similarity index 100% rename from public/images/trainer/galactic_admin_m.png rename to public/images/trainer/saturn.png diff --git a/public/images/trainer/shelly.json b/public/images/trainer/shelly.json new file mode 100644 index 00000000000..7761779864a --- /dev/null +++ b/public/images/trainer/shelly.json @@ -0,0 +1,41 @@ +{ + "textures": [ + { + "image": "shelly.png", + "format": "RGBA8888", + "size": { + "w": 80, + "h": 80 + }, + "scale": 1, + "frames": [ + { + "filename": "0001.png", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 80, + "h": 80 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 80, + "h": 80 + }, + "frame": { + "x": 0, + "y": 0, + "w": 80, + "h": 80 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:831f5748dad92911b10a1cb358ee2dae:a3bf81bbaa3b49cad5e0e549cf94563b:bb6befc9383c9c08837183ae2a7a80c1$" + } +} diff --git a/public/images/trainer/aqua_admin_f.png b/public/images/trainer/shelly.png similarity index 100% rename from public/images/trainer/aqua_admin_f.png rename to public/images/trainer/shelly.png diff --git a/public/images/trainer/tabitha.json b/public/images/trainer/tabitha.json new file mode 100644 index 00000000000..8360f33bffe --- /dev/null +++ b/public/images/trainer/tabitha.json @@ -0,0 +1,41 @@ +{ + "textures": [ + { + "image": "tabitha.png", + "format": "RGBA8888", + "size": { + "w": 80, + "h": 80 + }, + "scale": 1, + "frames": [ + { + "filename": "0001.png", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 80, + "h": 80 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 80, + "h": 80 + }, + "frame": { + "x": 0, + "y": 0, + "w": 80, + "h": 80 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:831f5748dad92911b10a1cb358ee2dae:a3bf81bbaa3b49cad5e0e549cf94563b:bb6befc9383c9c08837183ae2a7a80c1$" + } +} diff --git a/public/images/trainer/magma_admin_m.png b/public/images/trainer/tabitha.png similarity index 100% rename from public/images/trainer/magma_admin_m.png rename to public/images/trainer/tabitha.png diff --git a/public/images/trainer/xerosic.json b/public/images/trainer/xerosic.json new file mode 100644 index 00000000000..fd9604637ac --- /dev/null +++ b/public/images/trainer/xerosic.json @@ -0,0 +1,41 @@ +{ + "textures": [ + { + "image": "xerosic.png", + "format": "RGBA8888", + "size": { + "w": 80, + "h": 80 + }, + "scale": 1, + "frames": [ + { + "filename": "0001.png", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 80, + "h": 80 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 80, + "h": 80 + }, + "frame": { + "x": 0, + "y": 0, + "w": 80, + "h": 80 + } + } + ] + } + ], + "meta": { + "app": "https://www.codeandweb.com/texturepacker", + "version": "3.0", + "smartupdate": "$TexturePacker:SmartUpdate:831f5748dad92911b10a1cb358ee2dae:a3bf81bbaa3b49cad5e0e549cf94563b:bb6befc9383c9c08837183ae2a7a80c1$" + } +} diff --git a/public/images/trainer/flare_admin_m.png b/public/images/trainer/xerosic.png similarity index 100% rename from public/images/trainer/flare_admin_m.png rename to public/images/trainer/xerosic.png diff --git a/src/battle.ts b/src/battle.ts index e8a1323fc4c..8a1309938f7 100644 --- a/src/battle.ts +++ b/src/battle.ts @@ -425,22 +425,28 @@ export class FixedBattleConfig { } } + /** * Helper function to generate a random trainer for evil team trainers and the elite 4/champion * @param trainerPool The TrainerType or list of TrainerTypes that can possibly be generated * @param randomGender whether or not to randomly (50%) generate a female trainer (for use with evil team grunts) + * @param seedOffset the seed offset to use for the random generation of the trainer * @returns the generated trainer */ -function getRandomTrainerFunc(trainerPool: (TrainerType | TrainerType[])[], randomGender: boolean = false): GetTrainerFunc { +function getRandomTrainerFunc(trainerPool: (TrainerType | TrainerType[])[], randomGender: boolean = false, seedOffset: number = 0): GetTrainerFunc { return (scene: BattleScene) => { const rand = Utils.randSeedInt(trainerPool.length); const trainerTypes: TrainerType[] = []; - for (const trainerPoolEntry of trainerPool) { - const trainerType = Array.isArray(trainerPoolEntry) - ? Utils.randSeedItem(trainerPoolEntry) - : trainerPoolEntry; - trainerTypes.push(trainerType); - } + + scene.executeWithSeedOffset(() => { + for (const trainerPoolEntry of trainerPool) { + const trainerType = Array.isArray(trainerPoolEntry) + ? Utils.randSeedItem(trainerPoolEntry) + : trainerPoolEntry; + trainerTypes.push(trainerType); + } + }, seedOffset); + let trainerGender = TrainerVariant.DEFAULT; if (randomGender) { trainerGender = (Utils.randInt(2) === 0) ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT; @@ -486,13 +492,13 @@ export const classicFixedBattles: FixedBattleConfigs = { [64]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35) .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_GRUNT, TrainerType.MAGMA_GRUNT, TrainerType.AQUA_GRUNT, TrainerType.GALACTIC_GRUNT, TrainerType.PLASMA_GRUNT, TrainerType.FLARE_GRUNT ], true)), [66]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35) - .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_ADMIN, TrainerType.MAGMA_ADMIN, TrainerType.AQUA_ADMIN, TrainerType.GALACTIC_ADMIN, TrainerType.PLASMA_SAGE, TrainerType.FLARE_ADMIN ], true)), + .setGetTrainerFunc(getRandomTrainerFunc([[ TrainerType.ARCHER, TrainerType.ARIANA, TrainerType.PROTON, TrainerType.PETREL ], [ TrainerType.TABITHA, TrainerType.COURTNEY ], [ TrainerType.MATT, TrainerType.SHELLY ], [ TrainerType.JUPITER, TrainerType.MARS, TrainerType.SATURN ], [ TrainerType.ZINZOLIN, TrainerType.ROOD ], [ TrainerType.XEROSIC, TrainerType.BRYONY ] ], true)), [95]: new FixedBattleConfig().setBattleType(BattleType.TRAINER) .setGetTrainerFunc(scene => new Trainer(scene, TrainerType.RIVAL_4, scene.gameData.gender === PlayerGender.MALE ? TrainerVariant.FEMALE : TrainerVariant.DEFAULT)), [112]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35) .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_GRUNT, TrainerType.MAGMA_GRUNT, TrainerType.AQUA_GRUNT, TrainerType.GALACTIC_GRUNT, TrainerType.PLASMA_GRUNT, TrainerType.FLARE_GRUNT ], true)), [114]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35) - .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_ADMIN, TrainerType.MAGMA_ADMIN, TrainerType.AQUA_ADMIN, TrainerType.GALACTIC_ADMIN, TrainerType.PLASMA_SAGE, TrainerType.FLARE_ADMIN ], true)), + .setGetTrainerFunc(getRandomTrainerFunc([[ TrainerType.ARCHER, TrainerType.ARIANA, TrainerType.PROTON, TrainerType.PETREL ], [ TrainerType.TABITHA, TrainerType.COURTNEY ], [ TrainerType.MATT, TrainerType.SHELLY ], [ TrainerType.JUPITER, TrainerType.MARS, TrainerType.SATURN ], [ TrainerType.ZINZOLIN, TrainerType.ROOD ], [ TrainerType.XEROSIC, TrainerType.BRYONY ] ], true,1)), [115]: new FixedBattleConfig().setBattleType(BattleType.TRAINER).setSeedOffsetWave(35) .setGetTrainerFunc(getRandomTrainerFunc([ TrainerType.ROCKET_BOSS_GIOVANNI_1, TrainerType.MAXIE, TrainerType.ARCHIE, TrainerType.CYRUS, TrainerType.GHETSIS, TrainerType.LYSANDRE ])), [145]: new FixedBattleConfig().setBattleType(BattleType.TRAINER) diff --git a/src/data/dialogue.ts b/src/data/dialogue.ts index 4386515c953..8a595855a30 100644 --- a/src/data/dialogue.ts +++ b/src/data/dialogue.ts @@ -459,17 +459,59 @@ export const trainerTypeDialogue: TrainerTypeDialogue = { ] } ], - [TrainerType.ROCKET_ADMIN]: [ + [TrainerType.ARCHER]: [ { encounter: [ - "dialogue:rocket_admin.encounter.1", - "dialogue:rocket_admin.encounter.2", - "dialogue:rocket_admin.encounter.3", + "dialogue:archer.encounter.1", + "dialogue:archer.encounter.2", + "dialogue:archer.encounter.3", ], victory: [ - "dialogue:rocket_admin.victory.1", - "dialogue:rocket_admin.victory.2", - "dialogue:rocket_admin.victory.3", + "dialogue:archer.victory.1", + "dialogue:archer.victory.2", + "dialogue:archer.victory.3", + ] + } + ], + [TrainerType.ARIANA]: [ + { + encounter: [ + "dialogue:ariana.encounter.1", + "dialogue:ariana.encounter.2", + "dialogue:ariana.encounter.3", + ], + victory: [ + "dialogue:ariana.victory.1", + "dialogue:ariana.victory.2", + "dialogue:ariana.victory.3", + ] + } + ], + [TrainerType.PROTON]: [ + { + encounter: [ + "dialogue:proton.encounter.1", + "dialogue:proton.encounter.2", + "dialogue:proton.encounter.3", + ], + victory: [ + "dialogue:proton.victory.1", + "dialogue:proton.victory.2", + "dialogue:proton.victory.3", + ] + } + ], + [TrainerType.PETREL]: [ + { + encounter: [ + "dialogue:petrel.encounter.1", + "dialogue:petrel.encounter.2", + "dialogue:petrel.encounter.3", + ], + victory: [ + "dialogue:petrel.victory.1", + "dialogue:petrel.victory.2", + "dialogue:petrel.victory.3", ] } ], @@ -483,17 +525,31 @@ export const trainerTypeDialogue: TrainerTypeDialogue = { ] } ], - [TrainerType.MAGMA_ADMIN]: [ + [TrainerType.TABITHA]: [ { encounter: [ - "dialogue:magma_admin.encounter.1", - "dialogue:magma_admin.encounter.2", - "dialogue:magma_admin.encounter.3", + "dialogue:tabitha.encounter.1", + "dialogue:tabitha.encounter.2", + "dialogue:tabitha.encounter.3", ], victory: [ - "dialogue:magma_admin.victory.1", - "dialogue:magma_admin.victory.2", - "dialogue:magma_admin.victory.3", + "dialogue:tabitha.victory.1", + "dialogue:tabitha.victory.2", + "dialogue:tabitha.victory.3", + ] + } + ], + [TrainerType.COURTNEY]: [ + { + encounter: [ + "dialogue:courtney.encounter.1", + "dialogue:courtney.encounter.2", + "dialogue:courtney.encounter.3", + ], + victory: [ + "dialogue:courtney.victory.1", + "dialogue:courtney.victory.2", + "dialogue:courtney.victory.3", ] } ], @@ -507,17 +563,31 @@ export const trainerTypeDialogue: TrainerTypeDialogue = { ] } ], - [TrainerType.AQUA_ADMIN]: [ + [TrainerType.MATT]: [ { encounter: [ - "dialogue:aqua_admin.encounter.1", - "dialogue:aqua_admin.encounter.2", - "dialogue:aqua_admin.encounter.3", + "dialogue:matt.encounter.1", + "dialogue:matt.encounter.2", + "dialogue:matt.encounter.3", ], victory: [ - "dialogue:aqua_admin.victory.1", - "dialogue:aqua_admin.victory.2", - "dialogue:aqua_admin.victory.3", + "dialogue:matt.victory.1", + "dialogue:matt.victory.2", + "dialogue:matt.victory.3", + ] + } + ], + [TrainerType.SHELLY]: [ + { + encounter: [ + "dialogue:shelly.encounter.1", + "dialogue:shelly.encounter.2", + "dialogue:shelly.encounter.3", + ], + victory: [ + "dialogue:shelly.victory.1", + "dialogue:shelly.victory.2", + "dialogue:shelly.victory.3", ] } ], @@ -531,17 +601,45 @@ export const trainerTypeDialogue: TrainerTypeDialogue = { ] } ], - [TrainerType.GALACTIC_ADMIN]: [ + [TrainerType.JUPITER]: [ { encounter: [ - "dialogue:galactic_admin.encounter.1", - "dialogue:galactic_admin.encounter.2", - "dialogue:galactic_admin.encounter.3", + "dialogue:jupiter.encounter.1", + "dialogue:jupiter.encounter.2", + "dialogue:jupiter.encounter.3", ], victory: [ - "dialogue:galactic_admin.victory.1", - "dialogue:galactic_admin.victory.2", - "dialogue:galactic_admin.victory.3", + "dialogue:jupiter.victory.1", + "dialogue:jupiter.victory.2", + "dialogue:jupiter.victory.3", + ] + } + ], + [TrainerType.MARS]: [ + { + encounter: [ + "dialogue:mars.encounter.1", + "dialogue:mars.encounter.2", + "dialogue:mars.encounter.3", + ], + victory: [ + "dialogue:mars.victory.1", + "dialogue:mars.victory.2", + "dialogue:mars.victory.3", + ] + } + ], + [TrainerType.SATURN]: [ + { + encounter: [ + "dialogue:saturn.encounter.1", + "dialogue:saturn.encounter.2", + "dialogue:saturn.encounter.3", + ], + victory: [ + "dialogue:saturn.victory.1", + "dialogue:saturn.victory.2", + "dialogue:saturn.victory.3", ] } ], @@ -555,17 +653,17 @@ export const trainerTypeDialogue: TrainerTypeDialogue = { ] } ], - [TrainerType.PLASMA_SAGE]: [ + [TrainerType.ZINZOLIN]: [ { encounter: [ - "dialogue:plasma_sage.encounter.1", - "dialogue:plasma_sage.encounter.2", - "dialogue:plasma_sage.encounter.3", + "dialogue:zinzolin.encounter.1", + "dialogue:zinzolin.encounter.2", + "dialogue:zinzolin.encounter.3", ], victory: [ - "dialogue:plasma_sage.victory.1", - "dialogue:plasma_sage.victory.2", - "dialogue:plasma_sage.victory.3", + "dialogue:zinzolin.victory.1", + "dialogue:zinzolin.victory.2", + "dialogue:zinzolin.victory.3", ] } ], @@ -579,17 +677,31 @@ export const trainerTypeDialogue: TrainerTypeDialogue = { ] } ], - [TrainerType.FLARE_ADMIN]: [ + [TrainerType.BRYONY]: [ { encounter: [ - "dialogue:flare_admin.encounter.1", - "dialogue:flare_admin.encounter.2", - "dialogue:flare_admin.encounter.3", + "dialogue:bryony.encounter.1", + "dialogue:bryony.encounter.2", + "dialogue:bryony.encounter.3", ], victory: [ - "dialogue:flare_admin.victory.1", - "dialogue:flare_admin.victory.2", - "dialogue:flare_admin.victory.3", + "dialogue:bryony.victory.1", + "dialogue:bryony.victory.2", + "dialogue:bryony.victory.3", + ] + } + ], + [TrainerType.XEROSIC]: [ + { + encounter: [ + "dialogue:xerosic.encounter.1", + "dialogue:xerosic.encounter.2", + "dialogue:xerosic.encounter.3", + ], + victory: [ + "dialogue:xerosic.victory.1", + "dialogue:xerosic.victory.2", + "dialogue:xerosic.victory.3", ] } ], diff --git a/src/data/trainer-config.ts b/src/data/trainer-config.ts index 8d61463f316..87d1901eb01 100644 --- a/src/data/trainer-config.ts +++ b/src/data/trainer-config.ts @@ -12,27 +12,27 @@ import {PersistentModifier} from "../modifier/modifier"; import {TrainerVariant} from "../field/trainer"; import {getIsInitialized, initI18n} from "#app/plugins/i18n"; import i18next from "i18next"; -import { Moves } from "#enums/moves"; -import { PartyMemberStrength } from "#enums/party-member-strength"; -import { Species } from "#enums/species"; -import { TrainerType } from "#enums/trainer-type"; +import {Moves} from "#enums/moves"; +import {PartyMemberStrength} from "#enums/party-member-strength"; +import {Species} from "#enums/species"; +import {TrainerType} from "#enums/trainer-type"; export enum TrainerPoolTier { - COMMON, - UNCOMMON, - RARE, - SUPER_RARE, - ULTRA_RARE + COMMON, + UNCOMMON, + RARE, + SUPER_RARE, + ULTRA_RARE } export interface TrainerTierPools { - [key: integer]: Species[] + [key: integer]: Species[] } export enum TrainerSlot { - NONE, - TRAINER, - TRAINER_PARTNER + NONE, + TRAINER, + TRAINER_PARTNER } export class TrainerPartyTemplate { @@ -168,7 +168,7 @@ type PartyMemberFunc = (scene: BattleScene, level: integer, strength: PartyMembe type GenModifiersFunc = (party: EnemyPokemon[]) => PersistentModifier[]; export interface PartyMemberFuncs { - [key: integer]: PartyMemberFunc + [key: integer]: PartyMemberFunc } export class TrainerConfig { @@ -201,6 +201,7 @@ export class TrainerConfig { public speciesPools: TrainerTierPools; public speciesFilter: PokemonSpeciesFilter; public specialtyTypes: Type[] = []; + public hasVoucher: boolean = false; public encounterMessages: string[] = []; public victoryMessages: string[] = []; @@ -228,7 +229,7 @@ export class TrainerConfig { return TrainerType[this.getDerivedType()].toString().toLowerCase(); } - getSpriteKey(female?: boolean,isDouble: boolean = false): string { + getSpriteKey(female?: boolean, isDouble: boolean = false): string { let ret = this.getKey(); if (this.hasGenders) { ret += `_${female ? "f" : "m"}`; @@ -257,6 +258,14 @@ export class TrainerConfig { return this; } + /** + * Sets if a boss trainer will have a voucher or not. + * @param hasVoucher - If the boss trainer will have a voucher. + */ + setHasVoucher(hasVoucher: boolean): void { + this.hasVoucher = hasVoucher; + } + setTitle(title: string): TrainerConfig { // First check if i18n is initialized if (!getIsInitialized()) { @@ -275,10 +284,10 @@ export class TrainerConfig { /** - * Returns the derived trainer type for a given trainer type. - * @param trainerTypeToDeriveFrom - The trainer type to derive from. (If null, the this.trainerType property will be used.) - * @returns {TrainerType} - The derived trainer type. - */ + * Returns the derived trainer type for a given trainer type. + * @param trainerTypeToDeriveFrom - The trainer type to derive from. (If null, the this.trainerType property will be used.) + * @returns {TrainerType} - The derived trainer type. + */ getDerivedType(trainerTypeToDeriveFrom: TrainerType = null): TrainerType { let trainerType = trainerTypeToDeriveFrom ? trainerTypeToDeriveFrom : this.trainerType; switch (trainerType) { @@ -335,11 +344,11 @@ export class TrainerConfig { } /** - * Sets the configuration for trainers with genders, including the female name and encounter background music (BGM). - * @param {string} [nameFemale] - The name of the female trainer. If 'Ivy', a localized name will be assigned. - * @param {TrainerType | string} [femaleEncounterBgm] - The encounter BGM for the female trainer, which can be a TrainerType or a string. - * @returns {TrainerConfig} - The updated TrainerConfig instance. - **/ + * Sets the configuration for trainers with genders, including the female name and encounter background music (BGM). + * @param {string} [nameFemale] - The name of the female trainer. If 'Ivy', a localized name will be assigned. + * @param {TrainerType | string} [femaleEncounterBgm] - The encounter BGM for the female trainer, which can be a TrainerType or a string. + * @returns {TrainerConfig} - The updated TrainerConfig instance. + **/ setHasGenders(nameFemale?: string, femaleEncounterBgm?: TrainerType | string): TrainerConfig { // If the female name is 'Ivy' (the rival), assign a localized name. if (nameFemale === "Ivy") { @@ -372,11 +381,11 @@ export class TrainerConfig { } /** - * Sets the configuration for trainers with double battles, including the name of the double trainer and the encounter BGM. - * @param nameDouble - The name of the double trainer (e.g., "Ace Duo" for Trainer Class Doubles or "red_blue_double" for NAMED trainer doubles). - * @param doubleEncounterBgm - The encounter BGM for the double trainer, which can be a TrainerType or a string. - * @returns {TrainerConfig} - The updated TrainerConfig instance. - */ + * Sets the configuration for trainers with double battles, including the name of the double trainer and the encounter BGM. + * @param nameDouble - The name of the double trainer (e.g., "Ace Duo" for Trainer Class Doubles or "red_blue_double" for NAMED trainer doubles). + * @param doubleEncounterBgm - The encounter BGM for the double trainer, which can be a TrainerType or a string. + * @returns {TrainerConfig} - The updated TrainerConfig instance. + */ setHasDouble(nameDouble: string, doubleEncounterBgm?: TrainerType | string): TrainerConfig { this.hasDouble = true; this.nameDouble = nameDouble; @@ -387,10 +396,10 @@ export class TrainerConfig { } /** - * Sets the trainer type for double battles. - * @param trainerTypeDouble - The TrainerType of the partner in a double battle. - * @returns {TrainerConfig} - The updated TrainerConfig instance. - */ + * Sets the trainer type for double battles. + * @param trainerTypeDouble - The TrainerType of the partner in a double battle. + * @returns {TrainerConfig} - The updated TrainerConfig instance. + */ setDoubleTrainerType(trainerTypeDouble: TrainerType): TrainerConfig { this.trainerTypeDouble = trainerTypeDouble; this.setDoubleMessages(this.nameDouble); @@ -398,9 +407,9 @@ export class TrainerConfig { } /** - * Sets the encounter and victory messages for double trainers. - * @param nameDouble - The name of the pair (e.g. "red_blue_double"). - */ + * Sets the encounter and victory messages for double trainers. + * @param nameDouble - The name of the pair (e.g. "red_blue_double"). + */ setDoubleMessages(nameDouble: string) { // Check if there is double battle dialogue for this trainer if (doubleBattleDialogue[nameDouble]) { @@ -412,10 +421,10 @@ export class TrainerConfig { } /** - * Sets the title for double trainers - * @param titleDouble - the key for the title in the i18n file. (e.g., "champion_double"). - * @returns {TrainerConfig} - The updated TrainerConfig instance. - */ + * Sets the title for double trainers + * @param titleDouble - the key for the title in the i18n file. (e.g., "champion_double"). + * @returns {TrainerConfig} - The updated TrainerConfig instance. + */ setDoubleTitle(titleDouble: string): TrainerConfig { // First check if i18n is initialized if (!getIsInitialized()) { @@ -527,6 +536,95 @@ export class TrainerConfig { return this; } + /** + * Returns the pool of species for an evil team admin + * @param team - The evil team the admin belongs to. + * @returns {TrainerTierPools} + */ + speciesPoolPerEvilTeamAdmin(team): TrainerTierPools { + team = team.toLowerCase(); + switch (team) { + case "rocket": { + return { + [TrainerPoolTier.COMMON]: [Species.RATTATA, Species.KOFFING, Species.EKANS, Species.GYARADOS, Species.TAUROS, Species.SCYTHER, Species.CUBONE, Species.GROWLITHE, Species.MURKROW, Species.GASTLY, Species.EXEGGCUTE, Species.VOLTORB], + [TrainerPoolTier.UNCOMMON]: [Species.PORYGON, Species.ALOLA_RATTATA, Species.ALOLA_SANDSHREW, Species.ALOLA_MEOWTH, Species.ALOLA_GRIMER, Species.ALOLA_GEODUDE], + [TrainerPoolTier.RARE]: [Species.DRATINI, Species.LARVITAR] + }; + } + case "magma": { + return { + [TrainerPoolTier.COMMON]: [Species.NUMEL, Species.POOCHYENA, Species.SLUGMA, Species.SOLROCK, Species.HIPPOPOTAS, Species.SANDACONDA, Species.PHANPY, Species.SWINUB, Species.GLIGAR], + [TrainerPoolTier.UNCOMMON]: [Species.TRAPINCH, Species.HEATMOR], + [TrainerPoolTier.RARE]: [Species.TURTONATOR, Species.CHARCADET] + }; + } + case "aqua": { + return { + [TrainerPoolTier.COMMON]: [Species.CARVANHA, Species.CORPHISH, Species.ZIGZAGOON, Species.CLAMPERL, Species.CHINCHOU, Species.WOOPER, Species.WINGULL, Species.TENTACOOL, Species.QWILFISH], + [TrainerPoolTier.UNCOMMON]: [Species.MANTINE, Species.BASCULEGION, Species.REMORAID, Species.ARROKUDA], + [TrainerPoolTier.RARE]: [Species.DONDOZO] + }; + } + case "galactic": { + return { + [TrainerPoolTier.COMMON]: [Species.GLAMEOW, Species.STUNKY, Species.BRONZOR, Species.CARNIVINE, Species.GROWLITHE, Species.QWILFISH, Species.SNEASEL], + [TrainerPoolTier.UNCOMMON]: [Species.HISUI_GROWLITHE, Species.HISUI_QWILFISH, Species.HISUI_SNEASEL], + [TrainerPoolTier.RARE]: [Species.HISUI_ZORUA, Species.HISUI_SLIGGOO] + }; + } + case "plasma": { + return { + [TrainerPoolTier.COMMON]: [Species.SCRAFTY, Species.LILLIPUP, Species.PURRLOIN, Species.FRILLISH, Species.VENIPEDE, Species.GOLETT, Species.TIMBURR, Species.DARUMAKA, Species.AMOONGUSS], + [TrainerPoolTier.UNCOMMON]: [Species.PAWNIARD, Species.VULLABY, Species.ZORUA, Species.DRILBUR, Species.KLINK], + [TrainerPoolTier.RARE]: [Species.DRUDDIGON, Species.BOUFFALANT, Species.AXEW, Species.DEINO, Species.DURANT] + }; + } + case "flare": { + return { + [TrainerPoolTier.COMMON]: [Species.FLETCHLING, Species.LITLEO, Species.INKAY, Species.HELIOPTILE, Species.ELECTRIKE, Species.SKRELP, Species.GULPIN, Species.PURRLOIN, Species.POOCHYENA, Species.SCATTERBUG], + [TrainerPoolTier.UNCOMMON]: [Species.LITWICK, Species.SNEASEL, Species.PANCHAM, Species.PAWNIARD], + [TrainerPoolTier.RARE]: [Species.NOIVERN, Species.DRUDDIGON] + }; + } + } + } + + /** + * Initializes the trainer configuration for an evil team admin. + * @param title - The title of the evil team admin. + * @param poolName - The evil team the admin belongs to. + * @param {Species | Species[]} signatureSpecies - The signature species for the evil team leader. + * @returns {TrainerConfig} - The updated TrainerConfig instance. + * **/ + initForEvilTeamAdmin(title: string, poolName: string, signatureSpecies: (Species | Species[])[],): TrainerConfig { + if (!getIsInitialized()) { + initI18n(); + } + this.setPartyTemplates(trainerPartyTemplates.RIVAL_5); + + // Set the species pools for the evil team admin. + this.speciesPools = this.speciesPoolPerEvilTeamAdmin(poolName); + + signatureSpecies.forEach((speciesPool, s) => { + if (!Array.isArray(speciesPool)) { + speciesPool = [speciesPool]; + } + this.setPartyMemberFunc(-(s + 1), getRandomPartyMemberFunc(speciesPool)); + }); + + const nameForCall = this.name.toLowerCase().replace(/\s/g, "_"); + this.name = i18next.t(`trainerNames:${nameForCall}`); + this.setHasVoucher(false); + this.setTitle(title); + this.setMoneyMultiplier(1.5); + this.setBoss(); + this.setStaticParty(); + this.setBattleBgm("battle_plasma_boss"); + this.setVictoryBgm("victory_team_plasma"); + + return this; + } + /** * Initializes the trainer configuration for an evil team leader. Temporarily hardcoding evil leader teams though. * @param {Species | Species[]} signatureSpecies - The signature species for the evil team leader. @@ -559,6 +657,7 @@ export class TrainerConfig { this.setMoneyMultiplier(2.5); this.setBoss(); this.setStaticParty(); + this.setHasVoucher(true); this.setBattleBgm("battle_plasma_boss"); this.setVictoryBgm("victory_team_plasma"); @@ -566,13 +665,13 @@ export class TrainerConfig { } /** - * Initializes the trainer configuration for a Gym Leader. - * @param {Species | Species[]} signatureSpecies - The signature species for the Gym Leader. - * @param {Type[]} specialtyTypes - The specialty types for the Gym Leader. - * @param isMale - Whether the Gym Leader is Male or Not (for localization of the title). - * @returns {TrainerConfig} - The updated TrainerConfig instance. - * **/ - initForGymLeader(signatureSpecies: (Species | Species[])[],isMale:boolean, ...specialtyTypes: Type[]): TrainerConfig { + * Initializes the trainer configuration for a Gym Leader. + * @param {Species | Species[]} signatureSpecies - The signature species for the Gym Leader. + * @param {Type[]} specialtyTypes - The specialty types for the Gym Leader. + * @param isMale - Whether the Gym Leader is Male or Not (for localization of the title). + * @returns {TrainerConfig} - The updated TrainerConfig instance. + * **/ + initForGymLeader(signatureSpecies: (Species | Species[])[], isMale: boolean, ...specialtyTypes: Type[]): TrainerConfig { // Check if the internationalization (i18n) system is initialized. if (!getIsInitialized()) { initI18n(); @@ -611,6 +710,7 @@ export class TrainerConfig { this.setMoneyMultiplier(2.5); this.setBoss(); this.setStaticParty(); + this.setHasVoucher(true); this.setBattleBgm("battle_unova_gym"); this.setVictoryBgm("victory_gym"); this.setGenModifiersFunc(party => { @@ -622,13 +722,13 @@ export class TrainerConfig { } /** - * Initializes the trainer configuration for an Elite Four member. - * @param {Species | Species[]} signatureSpecies - The signature species for the Elite Four member. - * @param {Type[]} specialtyTypes - The specialty types for the Elite Four member. - * @param isMale - Whether the Elite Four Member is Male or Female (for localization of the title). - * @returns {TrainerConfig} - The updated TrainerConfig instance. - **/ - initForEliteFour(signatureSpecies: (Species | Species[])[],isMale: boolean, ...specialtyTypes: Type[]): TrainerConfig { + * Initializes the trainer configuration for an Elite Four member. + * @param {Species | Species[]} signatureSpecies - The signature species for the Elite Four member. + * @param {Type[]} specialtyTypes - The specialty types for the Elite Four member. + * @param isMale - Whether the Elite Four Member is Male or Female (for localization of the title). + * @returns {TrainerConfig} - The updated TrainerConfig instance. + **/ + initForEliteFour(signatureSpecies: (Species | Species[])[], isMale: boolean, ...specialtyTypes: Type[]): TrainerConfig { // Check if the internationalization (i18n) system is initialized. if (!getIsInitialized()) { initI18n(); @@ -669,6 +769,7 @@ export class TrainerConfig { this.setMoneyMultiplier(3.25); this.setBoss(); this.setStaticParty(); + this.setHasVoucher(true); this.setBattleBgm("battle_unova_elite"); this.setVictoryBgm("victory_gym"); this.setGenModifiersFunc(party => getRandomTeraModifiers(party, 2, specialtyTypes.length ? specialtyTypes : null)); @@ -677,11 +778,11 @@ export class TrainerConfig { } /** - * Initializes the trainer configuration for a Champion. - * @param {Species | Species[]} signatureSpecies - The signature species for the Champion. - * @param isMale - Whether the Champion is Male or Female (for localization of the title). - * @returns {TrainerConfig} - The updated TrainerConfig instance. - **/ + * Initializes the trainer configuration for a Champion. + * @param {Species | Species[]} signatureSpecies - The signature species for the Champion. + * @param isMale - Whether the Champion is Male or Female (for localization of the title). + * @returns {TrainerConfig} - The updated TrainerConfig instance. + **/ initForChampion(signatureSpecies: (Species | Species[])[], isMale: boolean): TrainerConfig { // Check if the internationalization (i18n) system is initialized. if (!getIsInitialized()) { @@ -719,6 +820,7 @@ export class TrainerConfig { this.setMoneyMultiplier(10); this.setBoss(); this.setStaticParty(); + this.setHasVoucher(true); this.setBattleBgm("battle_champion_alder"); this.setVictoryBgm("victory_champion"); this.setGenModifiersFunc(party => getRandomTeraModifiers(party, 3)); @@ -727,11 +829,11 @@ export class TrainerConfig { } /** - * Retrieves the title for the trainer based on the provided trainer slot and variant. - * @param {TrainerSlot} trainerSlot - The slot to determine which title to use. Defaults to TrainerSlot.NONE. - * @param {TrainerVariant} variant - The variant of the trainer to determine the specific title. - * @returns {string} - The title of the trainer. - **/ + * Retrieves the title for the trainer based on the provided trainer slot and variant. + * @param {TrainerSlot} trainerSlot - The slot to determine which title to use. Defaults to TrainerSlot.NONE. + * @param {TrainerVariant} variant - The variant of the trainer to determine the specific title. + * @returns {string} - The title of the trainer. + **/ getTitle(trainerSlot: TrainerSlot = TrainerSlot.NONE, variant: TrainerVariant): string { const ret = this.name; @@ -756,11 +858,11 @@ export class TrainerConfig { } // Check if the female version exists in the i18n file if (i18next.exists(`trainerClasses:${this.name.toLowerCase()}`)) { - // If it does, return + // If it does, return return ret + "_female"; } else { - // If it doesn't, we do not do anything and go to the normal return - // This is to prevent the game from displaying an error if a female version of the trainer does not exist in the localization + // If it doesn't, we do not do anything and go to the normal return + // This is to prevent the game from displaying an error if a female version of the trainer does not exist in the localization } } } @@ -772,7 +874,7 @@ export class TrainerConfig { return new Promise(resolve => { const isDouble = variant === TrainerVariant.DOUBLE; const trainerKey = this.getSpriteKey(variant === TrainerVariant.FEMALE, false); - const partnerTrainerKey = this.getSpriteKey(true,true); + const partnerTrainerKey = this.getSpriteKey(true, true); scene.loadAtlas(trainerKey, "trainer"); if (isDouble) { scene.loadAtlas(partnerTrainerKey, "trainer"); @@ -782,9 +884,19 @@ export class TrainerConfig { // Ignore warnings for missing frames, because there will be a lot console.warn = () => { }; - const frameNames = scene.anims.generateFrameNames(trainerKey, {zeroPad: 4,suffix: ".png",start: 1,end: 128}); + const frameNames = scene.anims.generateFrameNames(trainerKey, { + zeroPad: 4, + suffix: ".png", + start: 1, + end: 128 + }); const partnerFrameNames = isDouble - ? scene.anims.generateFrameNames(partnerTrainerKey, {zeroPad: 4,suffix: ".png",start: 1,end: 128}) + ? scene.anims.generateFrameNames(partnerTrainerKey, { + zeroPad: 4, + suffix: ".png", + start: 1, + end: 128 + }) : null; console.warn = originalWarn; if (!(scene.anims.exists(trainerKey))) { @@ -815,7 +927,7 @@ export class TrainerConfig { let t = 0; interface TrainerConfigs { - [key: integer]: TrainerConfig + [key: integer]: TrainerConfig } /** @@ -877,7 +989,7 @@ function getRandomTeraModifiers(party: EnemyPokemon[], count: integer, types?: T } type SignatureSpecies = { - [key in string]: (Species | Species[])[]; + [key in string]: (Species | Species[])[]; }; /* @@ -991,7 +1103,7 @@ export const signatureSpecies: SignatureSpecies = { MARNIE_ELITE: [Species.MORPEKO, Species.LIEPARD, [Species.TOXICROAK, Species.SCRAFTY], Species.GRIMMSNARL], NESSA_ELITE: [Species.GOLISOPOD, [Species.PELIPPER, Species.QUAGSIRE], Species.TOXAPEX, Species.DREDNAW], BEA_ELITE: [Species.HAWLUCHA, [Species.GRAPPLOCT, Species.SIRFETCHD], Species.FALINKS, Species.MACHAMP], - ALLISTER_ELITE:[Species.DUSKNOIR, [Species.POLTEAGEIST, Species.RUNERIGUS], Species.CURSOLA, Species.GENGAR], + ALLISTER_ELITE: [Species.DUSKNOIR, [Species.POLTEAGEIST, Species.RUNERIGUS], Species.CURSOLA, Species.GENGAR], RAIHAN_ELITE: [Species.GOODRA, [Species.TORKOAL, Species.TURTONATOR], Species.FLYGON, Species.ARCHALUDON], RIKA: [Species.WHISCASH, [Species.DONPHAN, Species.DUGTRIO], Species.CAMERUPT, Species.CLODSIRE], POPPY: [Species.COPPERAJAH, Species.BRONZONG, Species.CORVIKNIGHT, Species.TINKATON], @@ -1182,17 +1294,15 @@ export const trainerConfigs: TrainerConfigs = { ), [TrainerType.ROCKET_GRUNT]: new TrainerConfig(++t).setHasGenders("Rocket Grunt Female").setHasDouble("Rocket Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_rocket_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)) .setSpeciesPools({ - [TrainerPoolTier.COMMON]: [ Species.WEEDLE, Species.RATTATA, Species.EKANS, Species.SANDSHREW, Species.ZUBAT, Species.GEODUDE, Species.KOFFING, Species.GRIMER, Species.ODDISH], - [TrainerPoolTier.UNCOMMON]: [ Species.GYARADOS, Species.TAUROS, Species.SCYTHER, Species.CUBONE, Species.GROWLITHE, Species.MURKROW, Species.GASTLY, Species.EXEGGCUTE, Species.VOLTORB], + [TrainerPoolTier.COMMON]: [Species.WEEDLE, Species.RATTATA, Species.EKANS, Species.SANDSHREW, Species.ZUBAT, Species.GEODUDE, Species.KOFFING, Species.GRIMER, Species.ODDISH], + [TrainerPoolTier.UNCOMMON]: [Species.GYARADOS, Species.TAUROS, Species.SCYTHER, Species.CUBONE, Species.GROWLITHE, Species.MURKROW, Species.GASTLY, Species.EXEGGCUTE, Species.VOLTORB], [TrainerPoolTier.RARE]: [Species.PORYGON, Species.ALOLA_RATTATA, Species.ALOLA_SANDSHREW, Species.ALOLA_MEOWTH, Species.ALOLA_GRIMER, Species.ALOLA_GEODUDE], [TrainerPoolTier.SUPER_RARE]: [Species.DRATINI, Species.LARVITAR] }), - [TrainerType.ROCKET_ADMIN]: new TrainerConfig(++t).setHasGenders().setMoneyMultiplier(1.5).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_rocket_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)) - .setSpeciesPools({ - [TrainerPoolTier.COMMON]: [ Species.RATTATA, Species.KOFFING, Species.EKANS, Species.GYARADOS, Species.TAUROS, Species.SCYTHER, Species.CUBONE, Species.GROWLITHE, Species.MURKROW, Species.GASTLY, Species.EXEGGCUTE, Species.VOLTORB], - [TrainerPoolTier.UNCOMMON]: [Species.PORYGON, Species.ALOLA_RATTATA, Species.ALOLA_SANDSHREW, Species.ALOLA_MEOWTH, Species.ALOLA_GRIMER, Species.ALOLA_GEODUDE], - [TrainerPoolTier.RARE]: [Species.DRATINI, Species.LARVITAR] - }), + [TrainerType.ARCHER]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("rocket_admin", "rocket", [Species.HOUNDOOM]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_rocket_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), + [TrainerType.ARIANA]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("rocket_admin_female", "rocket", [Species.ARBOK]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_rocket_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), + [TrainerType.PROTON]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("rocket_admin", "rocket", [Species.CROBAT]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_rocket_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), + [TrainerType.PETREL]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("rocket_admin", "rocket", [Species.WEEZING]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_rocket_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), [TrainerType.MAGMA_GRUNT]: new TrainerConfig(++t).setHasGenders("Magma Grunt Female").setHasDouble("Magma Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_aqua_magma_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)) .setSpeciesPools({ [TrainerPoolTier.COMMON]: [Species.SLUGMA, Species.POOCHYENA, Species.NUMEL, Species.ZIGZAGOON, Species.DIGLETT, Species.MAGBY, Species.TORKOAL, Species.BALTOY, Species.BARBOACH], @@ -1200,182 +1310,165 @@ export const trainerConfigs: TrainerConfigs = { [TrainerPoolTier.RARE]: [Species.TRAPINCH, Species.HEATMOR], [TrainerPoolTier.SUPER_RARE]: [Species.TURTONATOR, Species.CHARCADET] }), - [TrainerType.MAGMA_ADMIN]: new TrainerConfig(++t).setHasGenders().setMoneyMultiplier(1.5).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_aqua_magma_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)) - .setSpeciesPools({ - [TrainerPoolTier.COMMON]: [ Species.NUMEL, Species.POOCHYENA, Species.SLUGMA, Species.SOLROCK, Species.HIPPOPOTAS, Species.SANDACONDA, Species.PHANPY, Species.SWINUB, Species.GLIGAR], - [TrainerPoolTier.UNCOMMON]: [Species.TRAPINCH, Species.HEATMOR], - [TrainerPoolTier.RARE]: [Species.TURTONATOR, Species.CHARCADET] - }), + [TrainerType.TABITHA]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("magma_admin", "magma", [Species.CAMERUPT]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_aqua_magma_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), + [TrainerType.COURTNEY]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("magma_admin_female", "magma", [Species.CAMERUPT]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_aqua_magma_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), [TrainerType.AQUA_GRUNT]: new TrainerConfig(++t).setHasGenders("Aqua Grunt Female").setHasDouble("Aqua Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_aqua_magma_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)) .setSpeciesPools({ - [TrainerPoolTier.COMMON]: [ Species.CARVANHA, Species.WAILMER, Species.ZIGZAGOON, Species.LOTAD, Species.CORPHISH, Species.SPHEAL ], - [TrainerPoolTier.UNCOMMON]: [Species.CLAMPERL, Species.CHINCHOU, Species.WOOPER, Species.WINGULL, Species.TENTACOOL, Species.QWILFISH ], + [TrainerPoolTier.COMMON]: [Species.CARVANHA, Species.WAILMER, Species.ZIGZAGOON, Species.LOTAD, Species.CORPHISH, Species.SPHEAL], + [TrainerPoolTier.UNCOMMON]: [Species.CLAMPERL, Species.CHINCHOU, Species.WOOPER, Species.WINGULL, Species.TENTACOOL, Species.QWILFISH], [TrainerPoolTier.RARE]: [Species.MANTINE, Species.BASCULEGION, Species.REMORAID, Species.ARROKUDA], [TrainerPoolTier.SUPER_RARE]: [Species.DONDOZO] }), - [TrainerType.AQUA_ADMIN]: new TrainerConfig(++t).setHasGenders().setMoneyMultiplier(1.5).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_aqua_magma_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)) - .setSpeciesPools({ - [TrainerPoolTier.COMMON]: [ Species.CARVANHA, Species.CORPHISH, Species.ZIGZAGOON, Species.CLAMPERL, Species.CHINCHOU, Species.WOOPER, Species.WINGULL, Species.TENTACOOL, Species.QWILFISH ], - [TrainerPoolTier.UNCOMMON]: [Species.MANTINE, Species.BASCULEGION, Species.REMORAID, Species.ARROKUDA], - [TrainerPoolTier.RARE]: [Species.DONDOZO] - }), + [TrainerType.MATT]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("aqua_admin", "aqua", [Species.SHARPEDO]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_aqua_magma_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), + [TrainerType.SHELLY]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("aqua_admin_female", "aqua", [Species.SHARPEDO]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_aqua_magma_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), [TrainerType.GALACTIC_GRUNT]: new TrainerConfig(++t).setHasGenders("Galactic Grunt Female").setHasDouble("Galactic Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_galactic_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)) .setSpeciesPools({ - [TrainerPoolTier.COMMON]: [ Species.GLAMEOW, Species.STUNKY, Species.CROAGUNK, Species.SHINX, Species.WURMPLE, Species.BRONZOR, Species.DRIFLOON, Species.BURMY], - [TrainerPoolTier.UNCOMMON]: [ Species.CARNIVINE, Species.GROWLITHE, Species.QWILFISH, Species.SNEASEL ], + [TrainerPoolTier.COMMON]: [Species.GLAMEOW, Species.STUNKY, Species.CROAGUNK, Species.SHINX, Species.WURMPLE, Species.BRONZOR, Species.DRIFLOON, Species.BURMY], + [TrainerPoolTier.UNCOMMON]: [Species.CARNIVINE, Species.GROWLITHE, Species.QWILFISH, Species.SNEASEL], [TrainerPoolTier.RARE]: [Species.HISUI_GROWLITHE, Species.HISUI_QWILFISH, Species.HISUI_SNEASEL], [TrainerPoolTier.SUPER_RARE]: [Species.HISUI_ZORUA, Species.HISUI_SLIGGOO] }), - [TrainerType.GALACTIC_ADMIN]: new TrainerConfig(++t).setHasGenders().setMoneyMultiplier(1.5).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_galactic_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)) - .setSpeciesPools({ - [TrainerPoolTier.COMMON]: [ Species.GLAMEOW, Species.STUNKY, Species.BRONZOR, Species.CARNIVINE, Species.GROWLITHE, Species.QWILFISH, Species.SNEASEL ], - [TrainerPoolTier.UNCOMMON]: [Species.HISUI_GROWLITHE, Species.HISUI_QWILFISH, Species.HISUI_SNEASEL], - [TrainerPoolTier.RARE]: [Species.HISUI_ZORUA, Species.HISUI_SLIGGOO] - }), + + [TrainerType.JUPITER]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("galactic_commander_female", "galactic", [Species.SKUNTANK]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_galactic_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), + [TrainerType.MARS]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("galactic_commander_female", "galactic", [Species.PURUGLY]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_galactic_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), + [TrainerType.SATURN]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("galactic_commander", "galactic", [Species.TOXICROAK]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_galactic_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), [TrainerType.PLASMA_GRUNT]: new TrainerConfig(++t).setHasGenders("Plasma Grunt Female").setHasDouble("Plasma Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_plasma_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)) .setSpeciesPools({ - [TrainerPoolTier.COMMON]: [ Species.PATRAT, Species.LILLIPUP, Species.PURRLOIN, Species.SCRAFTY, Species.WOOBAT, Species.VANILLITE, Species.SANDILE, Species.TRUBBISH], - [TrainerPoolTier.UNCOMMON]: [ Species.FRILLISH, Species.VENIPEDE, Species.GOLETT, Species.TIMBURR, Species.DARUMAKA, Species.AMOONGUSS], + [TrainerPoolTier.COMMON]: [Species.PATRAT, Species.LILLIPUP, Species.PURRLOIN, Species.SCRAFTY, Species.WOOBAT, Species.VANILLITE, Species.SANDILE, Species.TRUBBISH], + [TrainerPoolTier.UNCOMMON]: [Species.FRILLISH, Species.VENIPEDE, Species.GOLETT, Species.TIMBURR, Species.DARUMAKA, Species.AMOONGUSS], [TrainerPoolTier.RARE]: [Species.PAWNIARD, Species.VULLABY, Species.ZORUA, Species.DRILBUR, Species.KLINK], [TrainerPoolTier.SUPER_RARE]: [Species.DRUDDIGON, Species.BOUFFALANT, Species.AXEW, Species.DEINO, Species.DURANT] }), - [TrainerType.PLASMA_SAGE]: new TrainerConfig(++t).setMoneyMultiplier(1.5).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_plasma_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)) - .setSpeciesPools({ - [TrainerPoolTier.COMMON]: [ Species.SCRAFTY, Species.LILLIPUP, Species.PURRLOIN, Species.FRILLISH, Species.VENIPEDE, Species.GOLETT, Species.TIMBURR, Species.DARUMAKA, Species.AMOONGUSS], - [TrainerPoolTier.UNCOMMON]: [Species.PAWNIARD, Species.VULLABY, Species.ZORUA, Species.DRILBUR, Species.KLINK], - [TrainerPoolTier.RARE]: [Species.DRUDDIGON, Species.BOUFFALANT, Species.AXEW, Species.DEINO, Species.DURANT] - }), + [TrainerType.ZINZOLIN]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("plasma_sage", "plasma", [Species.CRYOGONAL]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_plasma_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), + [TrainerType.ROOD]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("plasma_sage", "plasma", [Species.SWOOBAT]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_plasma_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), + [TrainerType.FLARE_GRUNT]: new TrainerConfig(++t).setHasGenders("Flare Grunt Female").setHasDouble("Flare Grunts").setMoneyMultiplier(1.0).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_flare_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)) .setSpeciesPools({ - [TrainerPoolTier.COMMON]: [ Species.FLETCHLING, Species.LITLEO, Species.PONYTA, Species.INKAY, Species.HOUNDOUR, Species.SKORUPI, Species.SCRAFTY, Species.CROAGUNK], + [TrainerPoolTier.COMMON]: [Species.FLETCHLING, Species.LITLEO, Species.PONYTA, Species.INKAY, Species.HOUNDOUR, Species.SKORUPI, Species.SCRAFTY, Species.CROAGUNK], [TrainerPoolTier.UNCOMMON]: [Species.HELIOPTILE, Species.ELECTRIKE, Species.SKRELP, Species.GULPIN, Species.PURRLOIN, Species.POOCHYENA, Species.SCATTERBUG], [TrainerPoolTier.RARE]: [Species.LITWICK, Species.SNEASEL, Species.PANCHAM, Species.PAWNIARD], [TrainerPoolTier.SUPER_RARE]: [Species.NOIVERN, Species.DRUDDIGON] }), - [TrainerType.FLARE_ADMIN]: new TrainerConfig(++t).setHasGenders().setMoneyMultiplier(1.5).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_flare_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)) - .setSpeciesPools({ - [TrainerPoolTier.COMMON]: [ Species.FLETCHLING, Species.LITLEO, Species.INKAY, Species.HELIOPTILE, Species.ELECTRIKE, Species.SKRELP, Species.GULPIN, Species.PURRLOIN, Species.POOCHYENA, Species.SCATTERBUG], - [TrainerPoolTier.UNCOMMON]: [Species.LITWICK, Species.SNEASEL, Species.PANCHAM, Species.PAWNIARD], - [TrainerPoolTier.RARE]: [Species.NOIVERN, Species.DRUDDIGON] - }), - [TrainerType.BROCK]: new TrainerConfig((t = TrainerType.BROCK)).initForGymLeader(signatureSpecies["BROCK"],true, Type.ROCK).setBattleBgm("battle_kanto_gym").setMixedBattleBgm("battle_kanto_gym"), - [TrainerType.MISTY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["MISTY"],false, Type.WATER).setBattleBgm("battle_kanto_gym").setMixedBattleBgm("battle_kanto_gym"), - [TrainerType.LT_SURGE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["LT_SURGE"],true, Type.ELECTRIC).setBattleBgm("battle_kanto_gym").setMixedBattleBgm("battle_kanto_gym"), - [TrainerType.ERIKA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["ERIKA"],false, Type.GRASS).setBattleBgm("battle_kanto_gym").setMixedBattleBgm("battle_kanto_gym"), - [TrainerType.JANINE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["JANINE"],false, Type.POISON).setBattleBgm("battle_kanto_gym").setMixedBattleBgm("battle_kanto_gym"), - [TrainerType.SABRINA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["SABRINA"],false, Type.PSYCHIC).setBattleBgm("battle_kanto_gym").setMixedBattleBgm("battle_kanto_gym"), - [TrainerType.BLAINE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BLAINE"],true, Type.FIRE).setBattleBgm("battle_kanto_gym").setMixedBattleBgm("battle_kanto_gym"), - [TrainerType.GIOVANNI]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["GIOVANNI"],true, Type.DARK).setBattleBgm("battle_kanto_gym").setMixedBattleBgm("battle_kanto_gym"), - [TrainerType.FALKNER]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["FALKNER"],true, Type.FLYING).setBattleBgm("battle_johto_gym").setMixedBattleBgm("battle_johto_gym"), - [TrainerType.BUGSY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BUGSY"],true, Type.BUG).setBattleBgm("battle_johto_gym").setMixedBattleBgm("battle_johto_gym"), - [TrainerType.WHITNEY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["WHITNEY"],false, Type.NORMAL).setBattleBgm("battle_johto_gym").setMixedBattleBgm("battle_johto_gym"), - [TrainerType.MORTY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["MORTY"],true, Type.GHOST).setBattleBgm("battle_johto_gym").setMixedBattleBgm("battle_johto_gym"), - [TrainerType.CHUCK]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CHUCK"],true, Type.FIGHTING).setBattleBgm("battle_johto_gym").setMixedBattleBgm("battle_johto_gym"), - [TrainerType.JASMINE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["JASMINE"],false, Type.STEEL).setBattleBgm("battle_johto_gym").setMixedBattleBgm("battle_johto_gym"), - [TrainerType.PRYCE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["PRYCE"],true, Type.ICE).setBattleBgm("battle_johto_gym").setMixedBattleBgm("battle_johto_gym"), - [TrainerType.CLAIR]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CLAIR"],false, Type.DRAGON).setBattleBgm("battle_johto_gym").setMixedBattleBgm("battle_johto_gym"), - [TrainerType.ROXANNE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["ROXANNE"],false, Type.ROCK).setBattleBgm("battle_hoenn_gym").setMixedBattleBgm("battle_hoenn_gym"), - [TrainerType.BRAWLY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BRAWLY"],true, Type.FIGHTING).setBattleBgm("battle_hoenn_gym").setMixedBattleBgm("battle_hoenn_gym"), - [TrainerType.WATTSON]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["WATTSON"],true, Type.ELECTRIC).setBattleBgm("battle_hoenn_gym").setMixedBattleBgm("battle_hoenn_gym"), - [TrainerType.FLANNERY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["FLANNERY"],false, Type.FIRE).setBattleBgm("battle_hoenn_gym").setMixedBattleBgm("battle_hoenn_gym"), - [TrainerType.NORMAN]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["NORMAN"],true, Type.NORMAL).setBattleBgm("battle_hoenn_gym").setMixedBattleBgm("battle_hoenn_gym"), - [TrainerType.WINONA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["WINONA"],false, Type.FLYING).setBattleBgm("battle_hoenn_gym").setMixedBattleBgm("battle_hoenn_gym"), - [TrainerType.TATE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["TATE"],true, Type.PSYCHIC).setBattleBgm("battle_hoenn_gym").setMixedBattleBgm("battle_hoenn_gym").setHasDouble("tate_liza_double").setDoubleTrainerType(TrainerType.LIZA).setDoubleTitle("gym_leader_double"), - [TrainerType.LIZA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["LIZA"],false, Type.PSYCHIC).setBattleBgm("battle_hoenn_gym").setMixedBattleBgm("battle_hoenn_gym").setHasDouble("liza_tate_double").setDoubleTrainerType(TrainerType.TATE).setDoubleTitle("gym_leader_double"), - [TrainerType.JUAN]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["JUAN"],true, Type.WATER).setBattleBgm("battle_hoenn_gym").setMixedBattleBgm("battle_hoenn_gym"), - [TrainerType.ROARK]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["ROARK"],true, Type.ROCK).setBattleBgm("battle_sinnoh_gym").setMixedBattleBgm("battle_sinnoh_gym"), - [TrainerType.GARDENIA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["GARDENIA"],false, Type.GRASS).setBattleBgm("battle_sinnoh_gym").setMixedBattleBgm("battle_sinnoh_gym"), - [TrainerType.MAYLENE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["MAYLENE"],false, Type.FIGHTING).setBattleBgm("battle_sinnoh_gym").setMixedBattleBgm("battle_sinnoh_gym"), - [TrainerType.CRASHER_WAKE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CRASHER_WAKE"],true, Type.WATER).setBattleBgm("battle_sinnoh_gym").setMixedBattleBgm("battle_sinnoh_gym"), - [TrainerType.FANTINA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["FANTINA"],false, Type.GHOST).setBattleBgm("battle_sinnoh_gym").setMixedBattleBgm("battle_sinnoh_gym"), - [TrainerType.BYRON]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BYRON"],true, Type.STEEL).setBattleBgm("battle_sinnoh_gym").setMixedBattleBgm("battle_sinnoh_gym"), - [TrainerType.CANDICE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CANDICE"],false, Type.ICE).setBattleBgm("battle_sinnoh_gym").setMixedBattleBgm("battle_sinnoh_gym"), - [TrainerType.VOLKNER]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["VOLKNER"],true, Type.ELECTRIC).setBattleBgm("battle_sinnoh_gym").setMixedBattleBgm("battle_sinnoh_gym"), - [TrainerType.CILAN]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CILAN"],true, Type.GRASS).setMixedBattleBgm("battle_unova_gym"), - [TrainerType.CHILI]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CHILI"],true, Type.FIRE).setMixedBattleBgm("battle_unova_gym"), - [TrainerType.CRESS]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CRESS"],true, Type.WATER).setMixedBattleBgm("battle_unova_gym"), - [TrainerType.CHEREN]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CHEREN"],true, Type.NORMAL).setMixedBattleBgm("battle_unova_gym"), - [TrainerType.LENORA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["LENORA"],false, Type.NORMAL).setMixedBattleBgm("battle_unova_gym"), - [TrainerType.ROXIE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["ROXIE"],false, Type.POISON).setMixedBattleBgm("battle_unova_gym"), - [TrainerType.BURGH]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BURGH"],true, Type.BUG).setMixedBattleBgm("battle_unova_gym"), - [TrainerType.ELESA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["ELESA"],false, Type.ELECTRIC).setMixedBattleBgm("battle_unova_gym"), - [TrainerType.CLAY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CLAY"],true, Type.GROUND).setMixedBattleBgm("battle_unova_gym"), - [TrainerType.SKYLA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["SKYLA"],false, Type.FLYING).setMixedBattleBgm("battle_unova_gym"), - [TrainerType.BRYCEN]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BRYCEN"],true, Type.ICE).setMixedBattleBgm("battle_unova_gym"), - [TrainerType.DRAYDEN]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["DRAYDEN"],true, Type.DRAGON).setMixedBattleBgm("battle_unova_gym"), - [TrainerType.MARLON]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["MARLON"],true, Type.WATER).setMixedBattleBgm("battle_unova_gym"), - [TrainerType.VIOLA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["VIOLA"],false, Type.BUG).setMixedBattleBgm("battle_kalos_gym"), - [TrainerType.GRANT]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["GRANT"],true, Type.ROCK).setMixedBattleBgm("battle_kalos_gym"), - [TrainerType.KORRINA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["KORRINA"],false, Type.FIGHTING).setMixedBattleBgm("battle_kalos_gym"), - [TrainerType.RAMOS]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["RAMOS"],true, Type.GRASS).setMixedBattleBgm("battle_kalos_gym"), - [TrainerType.CLEMONT]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CLEMONT"],true, Type.ELECTRIC).setMixedBattleBgm("battle_kalos_gym"), - [TrainerType.VALERIE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["VALERIE"],false, Type.FAIRY).setMixedBattleBgm("battle_kalos_gym"), - [TrainerType.OLYMPIA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["OLYMPIA"],false, Type.PSYCHIC).setMixedBattleBgm("battle_kalos_gym"), - [TrainerType.WULFRIC]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["WULFRIC"],true, Type.ICE).setMixedBattleBgm("battle_kalos_gym"), - [TrainerType.MILO]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["MILO"],true, Type.GRASS).setMixedBattleBgm("battle_galar_gym"), - [TrainerType.NESSA]: new TrainerConfig(++t).setName("Nessa").initForGymLeader(signatureSpecies["NESSA"],false, Type.WATER).setMixedBattleBgm("battle_galar_gym"), - [TrainerType.KABU]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["KABU"],true, Type.FIRE).setMixedBattleBgm("battle_galar_gym"), - [TrainerType.BEA]: new TrainerConfig(++t).setName("Bea").initForGymLeader(signatureSpecies["BEA"],false, Type.FIGHTING).setMixedBattleBgm("battle_galar_gym"), - [TrainerType.ALLISTER]: new TrainerConfig(++t).setName("Allister").initForGymLeader(signatureSpecies["ALLISTER"],true, Type.GHOST).setMixedBattleBgm("battle_galar_gym"), - [TrainerType.OPAL]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["OPAL"],false, Type.FAIRY).setMixedBattleBgm("battle_galar_gym"), - [TrainerType.BEDE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BEDE"],true, Type.FAIRY).setMixedBattleBgm("battle_galar_gym"), - [TrainerType.GORDIE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["GORDIE"],true, Type.ROCK).setMixedBattleBgm("battle_galar_gym"), - [TrainerType.MELONY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["MELONY"],false, Type.ICE).setMixedBattleBgm("battle_galar_gym"), - [TrainerType.PIERS]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["PIERS"],true, Type.DARK).setHasDouble("piers_marnie_double").setDoubleTrainerType(TrainerType.MARNIE).setDoubleTitle("gym_leader_double").setMixedBattleBgm("battle_galar_gym"), - [TrainerType.MARNIE]: new TrainerConfig(++t).setName("Marnie").initForGymLeader(signatureSpecies["MARNIE"],false, Type.DARK).setHasDouble("marnie_piers_double").setDoubleTrainerType(TrainerType.PIERS).setDoubleTitle("gym_leader_double").setMixedBattleBgm("battle_galar_gym"), - [TrainerType.RAIHAN]: new TrainerConfig(++t).setName("Raihan").initForGymLeader(signatureSpecies["RAIHAN"],true, Type.DRAGON).setMixedBattleBgm("battle_galar_gym"), - [TrainerType.KATY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["KATY"],false, Type.BUG).setMixedBattleBgm("battle_paldea_gym"), - [TrainerType.BRASSIUS]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BRASSIUS"],true, Type.GRASS).setMixedBattleBgm("battle_paldea_gym"), - [TrainerType.IONO]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["IONO"],false, Type.ELECTRIC).setMixedBattleBgm("battle_paldea_gym"), - [TrainerType.KOFU]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["KOFU"],true, Type.WATER).setMixedBattleBgm("battle_paldea_gym"), - [TrainerType.LARRY]: new TrainerConfig(++t).setName("Larry").initForGymLeader(signatureSpecies["LARRY"],true, Type.NORMAL).setMixedBattleBgm("battle_paldea_gym"), - [TrainerType.RYME]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["RYME"],false, Type.GHOST).setMixedBattleBgm("battle_paldea_gym"), - [TrainerType.TULIP]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["TULIP"],false, Type.PSYCHIC).setMixedBattleBgm("battle_paldea_gym"), - [TrainerType.GRUSHA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["GRUSHA"],true, Type.ICE).setMixedBattleBgm("battle_paldea_gym"), + [TrainerType.BRYONY]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("flare_admin_female", "flare", [Species.LIEPARD]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_flare_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), + [TrainerType.XEROSIC]: new TrainerConfig(++t).setMoneyMultiplier(1.5).initForEvilTeamAdmin("flare_admin", "flare", [Species.MALAMAR]).setEncounterBgm(TrainerType.PLASMA_GRUNT).setBattleBgm("battle_plasma_grunt").setMixedBattleBgm("battle_flare_grunt").setVictoryBgm("victory_team_plasma").setPartyTemplateFunc(scene => getEvilGruntPartyTemplate(scene)), + [TrainerType.BROCK]: new TrainerConfig((t = TrainerType.BROCK)).initForGymLeader(signatureSpecies["BROCK"], true, Type.ROCK).setBattleBgm("battle_kanto_gym").setMixedBattleBgm("battle_kanto_gym"), + [TrainerType.MISTY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["MISTY"], false, Type.WATER).setBattleBgm("battle_kanto_gym").setMixedBattleBgm("battle_kanto_gym"), + [TrainerType.LT_SURGE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["LT_SURGE"], true, Type.ELECTRIC).setBattleBgm("battle_kanto_gym").setMixedBattleBgm("battle_kanto_gym"), + [TrainerType.ERIKA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["ERIKA"], false, Type.GRASS).setBattleBgm("battle_kanto_gym").setMixedBattleBgm("battle_kanto_gym"), + [TrainerType.JANINE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["JANINE"], false, Type.POISON).setBattleBgm("battle_kanto_gym").setMixedBattleBgm("battle_kanto_gym"), + [TrainerType.SABRINA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["SABRINA"], false, Type.PSYCHIC).setBattleBgm("battle_kanto_gym").setMixedBattleBgm("battle_kanto_gym"), + [TrainerType.BLAINE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BLAINE"], true, Type.FIRE).setBattleBgm("battle_kanto_gym").setMixedBattleBgm("battle_kanto_gym"), + [TrainerType.GIOVANNI]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["GIOVANNI"], true, Type.DARK).setBattleBgm("battle_kanto_gym").setMixedBattleBgm("battle_kanto_gym"), + [TrainerType.FALKNER]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["FALKNER"], true, Type.FLYING).setBattleBgm("battle_johto_gym").setMixedBattleBgm("battle_johto_gym"), + [TrainerType.BUGSY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BUGSY"], true, Type.BUG).setBattleBgm("battle_johto_gym").setMixedBattleBgm("battle_johto_gym"), + [TrainerType.WHITNEY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["WHITNEY"], false, Type.NORMAL).setBattleBgm("battle_johto_gym").setMixedBattleBgm("battle_johto_gym"), + [TrainerType.MORTY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["MORTY"], true, Type.GHOST).setBattleBgm("battle_johto_gym").setMixedBattleBgm("battle_johto_gym"), + [TrainerType.CHUCK]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CHUCK"], true, Type.FIGHTING).setBattleBgm("battle_johto_gym").setMixedBattleBgm("battle_johto_gym"), + [TrainerType.JASMINE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["JASMINE"], false, Type.STEEL).setBattleBgm("battle_johto_gym").setMixedBattleBgm("battle_johto_gym"), + [TrainerType.PRYCE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["PRYCE"], true, Type.ICE).setBattleBgm("battle_johto_gym").setMixedBattleBgm("battle_johto_gym"), + [TrainerType.CLAIR]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CLAIR"], false, Type.DRAGON).setBattleBgm("battle_johto_gym").setMixedBattleBgm("battle_johto_gym"), + [TrainerType.ROXANNE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["ROXANNE"], false, Type.ROCK).setBattleBgm("battle_hoenn_gym").setMixedBattleBgm("battle_hoenn_gym"), + [TrainerType.BRAWLY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BRAWLY"], true, Type.FIGHTING).setBattleBgm("battle_hoenn_gym").setMixedBattleBgm("battle_hoenn_gym"), + [TrainerType.WATTSON]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["WATTSON"], true, Type.ELECTRIC).setBattleBgm("battle_hoenn_gym").setMixedBattleBgm("battle_hoenn_gym"), + [TrainerType.FLANNERY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["FLANNERY"], false, Type.FIRE).setBattleBgm("battle_hoenn_gym").setMixedBattleBgm("battle_hoenn_gym"), + [TrainerType.NORMAN]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["NORMAN"], true, Type.NORMAL).setBattleBgm("battle_hoenn_gym").setMixedBattleBgm("battle_hoenn_gym"), + [TrainerType.WINONA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["WINONA"], false, Type.FLYING).setBattleBgm("battle_hoenn_gym").setMixedBattleBgm("battle_hoenn_gym"), + [TrainerType.TATE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["TATE"], true, Type.PSYCHIC).setBattleBgm("battle_hoenn_gym").setMixedBattleBgm("battle_hoenn_gym").setHasDouble("tate_liza_double").setDoubleTrainerType(TrainerType.LIZA).setDoubleTitle("gym_leader_double"), + [TrainerType.LIZA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["LIZA"], false, Type.PSYCHIC).setBattleBgm("battle_hoenn_gym").setMixedBattleBgm("battle_hoenn_gym").setHasDouble("liza_tate_double").setDoubleTrainerType(TrainerType.TATE).setDoubleTitle("gym_leader_double"), + [TrainerType.JUAN]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["JUAN"], true, Type.WATER).setBattleBgm("battle_hoenn_gym").setMixedBattleBgm("battle_hoenn_gym"), + [TrainerType.ROARK]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["ROARK"], true, Type.ROCK).setBattleBgm("battle_sinnoh_gym").setMixedBattleBgm("battle_sinnoh_gym"), + [TrainerType.GARDENIA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["GARDENIA"], false, Type.GRASS).setBattleBgm("battle_sinnoh_gym").setMixedBattleBgm("battle_sinnoh_gym"), + [TrainerType.MAYLENE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["MAYLENE"], false, Type.FIGHTING).setBattleBgm("battle_sinnoh_gym").setMixedBattleBgm("battle_sinnoh_gym"), + [TrainerType.CRASHER_WAKE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CRASHER_WAKE"], true, Type.WATER).setBattleBgm("battle_sinnoh_gym").setMixedBattleBgm("battle_sinnoh_gym"), + [TrainerType.FANTINA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["FANTINA"], false, Type.GHOST).setBattleBgm("battle_sinnoh_gym").setMixedBattleBgm("battle_sinnoh_gym"), + [TrainerType.BYRON]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BYRON"], true, Type.STEEL).setBattleBgm("battle_sinnoh_gym").setMixedBattleBgm("battle_sinnoh_gym"), + [TrainerType.CANDICE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CANDICE"], false, Type.ICE).setBattleBgm("battle_sinnoh_gym").setMixedBattleBgm("battle_sinnoh_gym"), + [TrainerType.VOLKNER]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["VOLKNER"], true, Type.ELECTRIC).setBattleBgm("battle_sinnoh_gym").setMixedBattleBgm("battle_sinnoh_gym"), + [TrainerType.CILAN]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CILAN"], true, Type.GRASS).setMixedBattleBgm("battle_unova_gym"), + [TrainerType.CHILI]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CHILI"], true, Type.FIRE).setMixedBattleBgm("battle_unova_gym"), + [TrainerType.CRESS]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CRESS"], true, Type.WATER).setMixedBattleBgm("battle_unova_gym"), + [TrainerType.CHEREN]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CHEREN"], true, Type.NORMAL).setMixedBattleBgm("battle_unova_gym"), + [TrainerType.LENORA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["LENORA"], false, Type.NORMAL).setMixedBattleBgm("battle_unova_gym"), + [TrainerType.ROXIE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["ROXIE"], false, Type.POISON).setMixedBattleBgm("battle_unova_gym"), + [TrainerType.BURGH]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BURGH"], true, Type.BUG).setMixedBattleBgm("battle_unova_gym"), + [TrainerType.ELESA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["ELESA"], false, Type.ELECTRIC).setMixedBattleBgm("battle_unova_gym"), + [TrainerType.CLAY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CLAY"], true, Type.GROUND).setMixedBattleBgm("battle_unova_gym"), + [TrainerType.SKYLA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["SKYLA"], false, Type.FLYING).setMixedBattleBgm("battle_unova_gym"), + [TrainerType.BRYCEN]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BRYCEN"], true, Type.ICE).setMixedBattleBgm("battle_unova_gym"), + [TrainerType.DRAYDEN]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["DRAYDEN"], true, Type.DRAGON).setMixedBattleBgm("battle_unova_gym"), + [TrainerType.MARLON]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["MARLON"], true, Type.WATER).setMixedBattleBgm("battle_unova_gym"), + [TrainerType.VIOLA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["VIOLA"], false, Type.BUG).setMixedBattleBgm("battle_kalos_gym"), + [TrainerType.GRANT]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["GRANT"], true, Type.ROCK).setMixedBattleBgm("battle_kalos_gym"), + [TrainerType.KORRINA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["KORRINA"], false, Type.FIGHTING).setMixedBattleBgm("battle_kalos_gym"), + [TrainerType.RAMOS]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["RAMOS"], true, Type.GRASS).setMixedBattleBgm("battle_kalos_gym"), + [TrainerType.CLEMONT]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["CLEMONT"], true, Type.ELECTRIC).setMixedBattleBgm("battle_kalos_gym"), + [TrainerType.VALERIE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["VALERIE"], false, Type.FAIRY).setMixedBattleBgm("battle_kalos_gym"), + [TrainerType.OLYMPIA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["OLYMPIA"], false, Type.PSYCHIC).setMixedBattleBgm("battle_kalos_gym"), + [TrainerType.WULFRIC]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["WULFRIC"], true, Type.ICE).setMixedBattleBgm("battle_kalos_gym"), + [TrainerType.MILO]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["MILO"], true, Type.GRASS).setMixedBattleBgm("battle_galar_gym"), + [TrainerType.NESSA]: new TrainerConfig(++t).setName("Nessa").initForGymLeader(signatureSpecies["NESSA"], false, Type.WATER).setMixedBattleBgm("battle_galar_gym"), + [TrainerType.KABU]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["KABU"], true, Type.FIRE).setMixedBattleBgm("battle_galar_gym"), + [TrainerType.BEA]: new TrainerConfig(++t).setName("Bea").initForGymLeader(signatureSpecies["BEA"], false, Type.FIGHTING).setMixedBattleBgm("battle_galar_gym"), + [TrainerType.ALLISTER]: new TrainerConfig(++t).setName("Allister").initForGymLeader(signatureSpecies["ALLISTER"], true, Type.GHOST).setMixedBattleBgm("battle_galar_gym"), + [TrainerType.OPAL]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["OPAL"], false, Type.FAIRY).setMixedBattleBgm("battle_galar_gym"), + [TrainerType.BEDE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BEDE"], true, Type.FAIRY).setMixedBattleBgm("battle_galar_gym"), + [TrainerType.GORDIE]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["GORDIE"], true, Type.ROCK).setMixedBattleBgm("battle_galar_gym"), + [TrainerType.MELONY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["MELONY"], false, Type.ICE).setMixedBattleBgm("battle_galar_gym"), + [TrainerType.PIERS]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["PIERS"], true, Type.DARK).setHasDouble("piers_marnie_double").setDoubleTrainerType(TrainerType.MARNIE).setDoubleTitle("gym_leader_double").setMixedBattleBgm("battle_galar_gym"), + [TrainerType.MARNIE]: new TrainerConfig(++t).setName("Marnie").initForGymLeader(signatureSpecies["MARNIE"], false, Type.DARK).setHasDouble("marnie_piers_double").setDoubleTrainerType(TrainerType.PIERS).setDoubleTitle("gym_leader_double").setMixedBattleBgm("battle_galar_gym"), + [TrainerType.RAIHAN]: new TrainerConfig(++t).setName("Raihan").initForGymLeader(signatureSpecies["RAIHAN"], true, Type.DRAGON).setMixedBattleBgm("battle_galar_gym"), + [TrainerType.KATY]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["KATY"], false, Type.BUG).setMixedBattleBgm("battle_paldea_gym"), + [TrainerType.BRASSIUS]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["BRASSIUS"], true, Type.GRASS).setMixedBattleBgm("battle_paldea_gym"), + [TrainerType.IONO]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["IONO"], false, Type.ELECTRIC).setMixedBattleBgm("battle_paldea_gym"), + [TrainerType.KOFU]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["KOFU"], true, Type.WATER).setMixedBattleBgm("battle_paldea_gym"), + [TrainerType.LARRY]: new TrainerConfig(++t).setName("Larry").initForGymLeader(signatureSpecies["LARRY"], true, Type.NORMAL).setMixedBattleBgm("battle_paldea_gym"), + [TrainerType.RYME]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["RYME"], false, Type.GHOST).setMixedBattleBgm("battle_paldea_gym"), + [TrainerType.TULIP]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["TULIP"], false, Type.PSYCHIC).setMixedBattleBgm("battle_paldea_gym"), + [TrainerType.GRUSHA]: new TrainerConfig(++t).initForGymLeader(signatureSpecies["GRUSHA"], true, Type.ICE).setMixedBattleBgm("battle_paldea_gym"), - [TrainerType.LORELEI]: new TrainerConfig((t = TrainerType.LORELEI)).initForEliteFour(signatureSpecies["LORELEI"],false, Type.ICE).setBattleBgm("battle_kanto_gym").setMixedBattleBgm("battle_kanto_gym"), + [TrainerType.LORELEI]: new TrainerConfig((t = TrainerType.LORELEI)).initForEliteFour(signatureSpecies["LORELEI"], false, Type.ICE).setBattleBgm("battle_kanto_gym").setMixedBattleBgm("battle_kanto_gym"), [TrainerType.BRUNO]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["BRUNO"], true, Type.FIGHTING).setBattleBgm("battle_kanto_gym").setMixedBattleBgm("battle_kanto_gym"), - [TrainerType.AGATHA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["AGATHA"], false,Type.GHOST).setBattleBgm("battle_kanto_gym").setMixedBattleBgm("battle_kanto_gym"), - [TrainerType.LANCE]: new TrainerConfig(++t).setName("Lance").initForEliteFour(signatureSpecies["LANCE"],true, Type.DRAGON).setBattleBgm("battle_kanto_gym").setMixedBattleBgm("battle_kanto_gym"), - [TrainerType.WILL]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["WILL"],true, Type.PSYCHIC).setBattleBgm("battle_johto_gym").setMixedBattleBgm("battle_johto_gym"), + [TrainerType.AGATHA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["AGATHA"], false, Type.GHOST).setBattleBgm("battle_kanto_gym").setMixedBattleBgm("battle_kanto_gym"), + [TrainerType.LANCE]: new TrainerConfig(++t).setName("Lance").initForEliteFour(signatureSpecies["LANCE"], true, Type.DRAGON).setBattleBgm("battle_kanto_gym").setMixedBattleBgm("battle_kanto_gym"), + [TrainerType.WILL]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["WILL"], true, Type.PSYCHIC).setBattleBgm("battle_johto_gym").setMixedBattleBgm("battle_johto_gym"), [TrainerType.KOGA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["KOGA"], true, Type.POISON).setBattleBgm("battle_johto_gym").setMixedBattleBgm("battle_johto_gym"), - [TrainerType.KAREN]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["KAREN"],false, Type.DARK).setBattleBgm("battle_johto_gym").setMixedBattleBgm("battle_johto_gym"), - [TrainerType.SIDNEY]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["SIDNEY"],true, Type.DARK).setMixedBattleBgm("battle_hoenn_elite"), - [TrainerType.PHOEBE]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["PHOEBE"],false, Type.GHOST).setMixedBattleBgm("battle_hoenn_elite"), - [TrainerType.GLACIA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["GLACIA"],false, Type.ICE).setMixedBattleBgm("battle_hoenn_elite"), - [TrainerType.DRAKE]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["DRAKE"],true, Type.DRAGON).setMixedBattleBgm("battle_hoenn_elite"), - [TrainerType.AARON]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["AARON"],true, Type.BUG).setBattleBgm("battle_sinnoh_gym").setMixedBattleBgm("battle_sinnoh_gym"), - [TrainerType.BERTHA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["BERTHA"],false, Type.GROUND).setBattleBgm("battle_sinnoh_gym").setMixedBattleBgm("battle_sinnoh_gym"), - [TrainerType.FLINT]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["FLINT"],true, Type.FIRE).setBattleBgm("battle_sinnoh_gym").setMixedBattleBgm("battle_sinnoh_gym"), - [TrainerType.LUCIAN]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["LUCIAN"], true,Type.PSYCHIC).setBattleBgm("battle_sinnoh_gym").setMixedBattleBgm("battle_sinnoh_gym"), - [TrainerType.SHAUNTAL]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["SHAUNTAL"],false, Type.GHOST).setMixedBattleBgm("battle_unova_elite"), - [TrainerType.MARSHAL]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["MARSHAL"],true, Type.FIGHTING).setMixedBattleBgm("battle_unova_elite"), - [TrainerType.GRIMSLEY]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["GRIMSLEY"],true, Type.DARK).setMixedBattleBgm("battle_unova_elite"), - [TrainerType.CAITLIN]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["CAITLIN"],false, Type.PSYCHIC).setMixedBattleBgm("battle_unova_elite"), - [TrainerType.MALVA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["MALVA"], false,Type.FIRE).setMixedBattleBgm("battle_kalos_elite"), - [TrainerType.SIEBOLD]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["SIEBOLD"], true,Type.WATER).setMixedBattleBgm("battle_kalos_elite"), - [TrainerType.WIKSTROM]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["WIKSTROM"],true, Type.STEEL).setMixedBattleBgm("battle_kalos_elite"), - [TrainerType.DRASNA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["DRASNA"],false, Type.DRAGON).setMixedBattleBgm("battle_kalos_elite"), - [TrainerType.HALA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["HALA"],true, Type.FIGHTING).setMixedBattleBgm("battle_alola_elite"), - [TrainerType.MOLAYNE]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["MOLAYNE"],true, Type.STEEL).setMixedBattleBgm("battle_alola_elite"), - [TrainerType.OLIVIA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["OLIVIA"],false, Type.ROCK).setMixedBattleBgm("battle_alola_elite"), - [TrainerType.ACEROLA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["ACEROLA"],false, Type.GHOST).setMixedBattleBgm("battle_alola_elite"), - [TrainerType.KAHILI]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["KAHILI"],false, Type.FLYING).setMixedBattleBgm("battle_alola_elite"), - [TrainerType.MARNIE_ELITE]: new TrainerConfig(++t).setName("Marnie").initForEliteFour(signatureSpecies["MARNIE_ELITE"],false, Type.DARK).setMixedBattleBgm("battle_galar_elite"), - [TrainerType.NESSA_ELITE]: new TrainerConfig(++t).setName("Nessa").initForEliteFour(signatureSpecies["NESSA_ELITE"],false, Type.WATER).setMixedBattleBgm("battle_galar_elite"), - [TrainerType.BEA_ELITE]: new TrainerConfig(++t).setName("Bea").initForEliteFour(signatureSpecies["BEA_ELITE"],false, Type.FIGHTING).setMixedBattleBgm("battle_galar_elite"), - [TrainerType.ALLISTER_ELITE]: new TrainerConfig(++t).setName("Allister").initForEliteFour(signatureSpecies["ALLISTER_ELITE"],true, Type.GHOST).setMixedBattleBgm("battle_galar_elite"), - [TrainerType.RAIHAN_ELITE]: new TrainerConfig(++t).setName("Raihan").initForEliteFour(signatureSpecies["RAIHAN_ELITE"],true, Type.DRAGON).setMixedBattleBgm("battle_galar_elite"), - [TrainerType.RIKA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["RIKA"],false, Type.GROUND).setMixedBattleBgm("battle_paldea_elite"), - [TrainerType.POPPY]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["POPPY"],false, Type.STEEL).setMixedBattleBgm("battle_paldea_elite"), - [TrainerType.LARRY_ELITE]: new TrainerConfig(++t).setName("Larry").initForEliteFour(signatureSpecies["LARRY_ELITE"],true, Type.NORMAL, Type.FLYING).setMixedBattleBgm("battle_paldea_elite"), - [TrainerType.HASSEL]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["HASSEL"],true, Type.DRAGON).setMixedBattleBgm("battle_paldea_elite"), - [TrainerType.CRISPIN]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["CRISPIN"],true, Type.FIRE).setMixedBattleBgm("battle_bb_elite"), - [TrainerType.AMARYS]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["AMARYS"],false, Type.STEEL).setMixedBattleBgm("battle_bb_elite"), - [TrainerType.LACEY]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["LACEY"],false, Type.FAIRY).setMixedBattleBgm("battle_bb_elite"), - [TrainerType.DRAYTON]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["DRAYTON"],true, Type.DRAGON).setMixedBattleBgm("battle_bb_elite"), + [TrainerType.KAREN]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["KAREN"], false, Type.DARK).setBattleBgm("battle_johto_gym").setMixedBattleBgm("battle_johto_gym"), + [TrainerType.SIDNEY]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["SIDNEY"], true, Type.DARK).setMixedBattleBgm("battle_hoenn_elite"), + [TrainerType.PHOEBE]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["PHOEBE"], false, Type.GHOST).setMixedBattleBgm("battle_hoenn_elite"), + [TrainerType.GLACIA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["GLACIA"], false, Type.ICE).setMixedBattleBgm("battle_hoenn_elite"), + [TrainerType.DRAKE]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["DRAKE"], true, Type.DRAGON).setMixedBattleBgm("battle_hoenn_elite"), + [TrainerType.AARON]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["AARON"], true, Type.BUG).setBattleBgm("battle_sinnoh_gym").setMixedBattleBgm("battle_sinnoh_gym"), + [TrainerType.BERTHA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["BERTHA"], false, Type.GROUND).setBattleBgm("battle_sinnoh_gym").setMixedBattleBgm("battle_sinnoh_gym"), + [TrainerType.FLINT]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["FLINT"], true, Type.FIRE).setBattleBgm("battle_sinnoh_gym").setMixedBattleBgm("battle_sinnoh_gym"), + [TrainerType.LUCIAN]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["LUCIAN"], true, Type.PSYCHIC).setBattleBgm("battle_sinnoh_gym").setMixedBattleBgm("battle_sinnoh_gym"), + [TrainerType.SHAUNTAL]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["SHAUNTAL"], false, Type.GHOST).setMixedBattleBgm("battle_unova_elite"), + [TrainerType.MARSHAL]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["MARSHAL"], true, Type.FIGHTING).setMixedBattleBgm("battle_unova_elite"), + [TrainerType.GRIMSLEY]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["GRIMSLEY"], true, Type.DARK).setMixedBattleBgm("battle_unova_elite"), + [TrainerType.CAITLIN]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["CAITLIN"], false, Type.PSYCHIC).setMixedBattleBgm("battle_unova_elite"), + [TrainerType.MALVA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["MALVA"], false, Type.FIRE).setMixedBattleBgm("battle_kalos_elite"), + [TrainerType.SIEBOLD]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["SIEBOLD"], true, Type.WATER).setMixedBattleBgm("battle_kalos_elite"), + [TrainerType.WIKSTROM]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["WIKSTROM"], true, Type.STEEL).setMixedBattleBgm("battle_kalos_elite"), + [TrainerType.DRASNA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["DRASNA"], false, Type.DRAGON).setMixedBattleBgm("battle_kalos_elite"), + [TrainerType.HALA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["HALA"], true, Type.FIGHTING).setMixedBattleBgm("battle_alola_elite"), + [TrainerType.MOLAYNE]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["MOLAYNE"], true, Type.STEEL).setMixedBattleBgm("battle_alola_elite"), + [TrainerType.OLIVIA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["OLIVIA"], false, Type.ROCK).setMixedBattleBgm("battle_alola_elite"), + [TrainerType.ACEROLA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["ACEROLA"], false, Type.GHOST).setMixedBattleBgm("battle_alola_elite"), + [TrainerType.KAHILI]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["KAHILI"], false, Type.FLYING).setMixedBattleBgm("battle_alola_elite"), + [TrainerType.MARNIE_ELITE]: new TrainerConfig(++t).setName("Marnie").initForEliteFour(signatureSpecies["MARNIE_ELITE"], false, Type.DARK).setMixedBattleBgm("battle_galar_elite"), + [TrainerType.NESSA_ELITE]: new TrainerConfig(++t).setName("Nessa").initForEliteFour(signatureSpecies["NESSA_ELITE"], false, Type.WATER).setMixedBattleBgm("battle_galar_elite"), + [TrainerType.BEA_ELITE]: new TrainerConfig(++t).setName("Bea").initForEliteFour(signatureSpecies["BEA_ELITE"], false, Type.FIGHTING).setMixedBattleBgm("battle_galar_elite"), + [TrainerType.ALLISTER_ELITE]: new TrainerConfig(++t).setName("Allister").initForEliteFour(signatureSpecies["ALLISTER_ELITE"], true, Type.GHOST).setMixedBattleBgm("battle_galar_elite"), + [TrainerType.RAIHAN_ELITE]: new TrainerConfig(++t).setName("Raihan").initForEliteFour(signatureSpecies["RAIHAN_ELITE"], true, Type.DRAGON).setMixedBattleBgm("battle_galar_elite"), + [TrainerType.RIKA]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["RIKA"], false, Type.GROUND).setMixedBattleBgm("battle_paldea_elite"), + [TrainerType.POPPY]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["POPPY"], false, Type.STEEL).setMixedBattleBgm("battle_paldea_elite"), + [TrainerType.LARRY_ELITE]: new TrainerConfig(++t).setName("Larry").initForEliteFour(signatureSpecies["LARRY_ELITE"], true, Type.NORMAL, Type.FLYING).setMixedBattleBgm("battle_paldea_elite"), + [TrainerType.HASSEL]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["HASSEL"], true, Type.DRAGON).setMixedBattleBgm("battle_paldea_elite"), + [TrainerType.CRISPIN]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["CRISPIN"], true, Type.FIRE).setMixedBattleBgm("battle_bb_elite"), + [TrainerType.AMARYS]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["AMARYS"], false, Type.STEEL).setMixedBattleBgm("battle_bb_elite"), + [TrainerType.LACEY]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["LACEY"], false, Type.FAIRY).setMixedBattleBgm("battle_bb_elite"), + [TrainerType.DRAYTON]: new TrainerConfig(++t).initForEliteFour(signatureSpecies["DRAYTON"], true, Type.DRAGON).setMixedBattleBgm("battle_bb_elite"), - [TrainerType.BLUE]: new TrainerConfig((t = TrainerType.BLUE)).initForChampion(signatureSpecies["BLUE"],true).setBattleBgm("battle_kanto_champion").setMixedBattleBgm("battle_kanto_champion").setHasDouble("blue_red_double").setDoubleTrainerType(TrainerType.RED).setDoubleTitle("champion_double") + [TrainerType.BLUE]: new TrainerConfig((t = TrainerType.BLUE)).initForChampion(signatureSpecies["BLUE"], true).setBattleBgm("battle_kanto_champion").setMixedBattleBgm("battle_kanto_champion").setHasDouble("blue_red_double").setDoubleTrainerType(TrainerType.RED).setDoubleTitle("champion_double") .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.ALAKAZAM], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); })) @@ -1384,7 +1477,7 @@ export const trainerConfigs: TrainerConfigs = { p.generateAndPopulateMoveset(); p.generateName(); })), - [TrainerType.RED]: new TrainerConfig(++t).initForChampion(signatureSpecies["RED"],true).setBattleBgm("battle_johto_champion").setMixedBattleBgm("battle_johto_champion").setHasDouble("red_blue_double").setDoubleTrainerType(TrainerType.BLUE).setDoubleTitle("champion_double") + [TrainerType.RED]: new TrainerConfig(++t).initForChampion(signatureSpecies["RED"], true).setBattleBgm("battle_johto_champion").setMixedBattleBgm("battle_johto_champion").setHasDouble("red_blue_double").setDoubleTrainerType(TrainerType.BLUE).setDoubleTitle("champion_double") .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.PIKACHU], TrainerSlot.TRAINER, true, p => { p.formIndex = 8; p.generateAndPopulateMoveset(); @@ -1395,7 +1488,7 @@ export const trainerConfigs: TrainerConfigs = { p.generateAndPopulateMoveset(); p.generateName(); })), - [TrainerType.LANCE_CHAMPION]: new TrainerConfig(++t).setName("Lance").initForChampion(signatureSpecies["LANCE_CHAMPION"],true).setBattleBgm("battle_johto_champion").setMixedBattleBgm("battle_johto_champion") + [TrainerType.LANCE_CHAMPION]: new TrainerConfig(++t).setName("Lance").initForChampion(signatureSpecies["LANCE_CHAMPION"], true).setBattleBgm("battle_johto_champion").setMixedBattleBgm("battle_johto_champion") .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.AERODACTYL], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); })) @@ -1404,7 +1497,7 @@ export const trainerConfigs: TrainerConfigs = { p.generateAndPopulateMoveset(); p.generateName(); })), - [TrainerType.STEVEN]: new TrainerConfig(++t).initForChampion(signatureSpecies["STEVEN"],true).setBattleBgm("battle_hoenn_champion_g5").setMixedBattleBgm("battle_hoenn_champion_g6").setHasDouble("steven_wallace_double").setDoubleTrainerType(TrainerType.WALLACE).setDoubleTitle("champion_double") + [TrainerType.STEVEN]: new TrainerConfig(++t).initForChampion(signatureSpecies["STEVEN"], true).setBattleBgm("battle_hoenn_champion_g5").setMixedBattleBgm("battle_hoenn_champion_g6").setHasDouble("steven_wallace_double").setDoubleTrainerType(TrainerType.WALLACE).setDoubleTitle("champion_double") .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.SKARMORY], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); })) @@ -1413,7 +1506,7 @@ export const trainerConfigs: TrainerConfigs = { p.generateAndPopulateMoveset(); p.generateName(); })), - [TrainerType.WALLACE]: new TrainerConfig(++t).initForChampion(signatureSpecies["WALLACE"],true).setBattleBgm("battle_hoenn_champion_g5").setMixedBattleBgm("battle_hoenn_champion_g6").setHasDouble("wallace_steven_double").setDoubleTrainerType(TrainerType.STEVEN).setDoubleTitle("champion_double") + [TrainerType.WALLACE]: new TrainerConfig(++t).initForChampion(signatureSpecies["WALLACE"], true).setBattleBgm("battle_hoenn_champion_g5").setMixedBattleBgm("battle_hoenn_champion_g6").setHasDouble("wallace_steven_double").setDoubleTrainerType(TrainerType.STEVEN).setDoubleTitle("champion_double") .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.PELIPPER], TrainerSlot.TRAINER, true, p => { p.abilityIndex = 1; // Drizzle p.generateAndPopulateMoveset(); @@ -1422,7 +1515,7 @@ export const trainerConfigs: TrainerConfigs = { p.formIndex = 1; p.generateAndPopulateMoveset(); })), - [TrainerType.CYNTHIA]: new TrainerConfig(++t).initForChampion(signatureSpecies["CYNTHIA"],false).setBattleBgm("battle_sinnoh_champion").setMixedBattleBgm("battle_sinnoh_champion") + [TrainerType.CYNTHIA]: new TrainerConfig(++t).initForChampion(signatureSpecies["CYNTHIA"], false).setBattleBgm("battle_sinnoh_champion").setMixedBattleBgm("battle_sinnoh_champion") .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.SPIRITOMB], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); })) @@ -1431,11 +1524,11 @@ export const trainerConfigs: TrainerConfigs = { p.generateAndPopulateMoveset(); p.generateName(); })), - [TrainerType.ALDER]: new TrainerConfig(++t).initForChampion(signatureSpecies["ALDER"],true).setHasDouble("alder_iris_double").setDoubleTrainerType(TrainerType.IRIS).setDoubleTitle("champion_double").setBattleBgm("battle_champion_alder").setMixedBattleBgm("battle_champion_alder") + [TrainerType.ALDER]: new TrainerConfig(++t).initForChampion(signatureSpecies["ALDER"], true).setHasDouble("alder_iris_double").setDoubleTrainerType(TrainerType.IRIS).setDoubleTitle("champion_double").setBattleBgm("battle_champion_alder").setMixedBattleBgm("battle_champion_alder") .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.BOUFFALANT, Species.BRAVIARY], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); })), - [TrainerType.IRIS]: new TrainerConfig(++t).initForChampion(signatureSpecies["IRIS"],false).setBattleBgm("battle_champion_iris").setMixedBattleBgm("battle_champion_iris").setHasDouble("iris_alder_double").setDoubleTrainerType(TrainerType.ALDER).setDoubleTitle("champion_double") + [TrainerType.IRIS]: new TrainerConfig(++t).initForChampion(signatureSpecies["IRIS"], false).setBattleBgm("battle_champion_iris").setMixedBattleBgm("battle_champion_iris").setHasDouble("iris_alder_double").setDoubleTrainerType(TrainerType.ALDER).setDoubleTitle("champion_double") .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.DRUDDIGON], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); })) @@ -1444,7 +1537,7 @@ export const trainerConfigs: TrainerConfigs = { p.generateAndPopulateMoveset(); p.generateName(); })), - [TrainerType.DIANTHA]: new TrainerConfig(++t).initForChampion(signatureSpecies["DIANTHA"],false).setMixedBattleBgm("battle_kalos_champion") + [TrainerType.DIANTHA]: new TrainerConfig(++t).initForChampion(signatureSpecies["DIANTHA"], false).setMixedBattleBgm("battle_kalos_champion") .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.GOURGEIST], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); })) @@ -1453,11 +1546,11 @@ export const trainerConfigs: TrainerConfigs = { p.generateAndPopulateMoveset(); p.generateName(); })), - [TrainerType.HAU]: new TrainerConfig(++t).initForChampion(signatureSpecies["HAU"],true).setMixedBattleBgm("battle_alola_champion") + [TrainerType.HAU]: new TrainerConfig(++t).initForChampion(signatureSpecies["HAU"], true).setMixedBattleBgm("battle_alola_champion") .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.ALOLA_RAICHU], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); })), - [TrainerType.LEON]: new TrainerConfig(++t).initForChampion(signatureSpecies["LEON"],true).setMixedBattleBgm("battle_galar_champion") + [TrainerType.LEON]: new TrainerConfig(++t).initForChampion(signatureSpecies["LEON"], true).setMixedBattleBgm("battle_galar_champion") .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.RILLABOOM, Species.CINDERACE, Species.INTELEON], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); })) @@ -1466,16 +1559,16 @@ export const trainerConfigs: TrainerConfigs = { p.generateAndPopulateMoveset(); p.generateName(); })), - [TrainerType.GEETA]: new TrainerConfig(++t).initForChampion(signatureSpecies["GEETA"],false).setMixedBattleBgm("battle_champion_geeta") + [TrainerType.GEETA]: new TrainerConfig(++t).initForChampion(signatureSpecies["GEETA"], false).setMixedBattleBgm("battle_champion_geeta") .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.GLIMMORA], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); })), - [TrainerType.NEMONA]: new TrainerConfig(++t).initForChampion(signatureSpecies["NEMONA"],false).setMixedBattleBgm("battle_champion_nemona") + [TrainerType.NEMONA]: new TrainerConfig(++t).initForChampion(signatureSpecies["NEMONA"], false).setMixedBattleBgm("battle_champion_nemona") .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.LYCANROC], TrainerSlot.TRAINER, true, p => { p.formIndex = 0; // Midday form p.generateAndPopulateMoveset(); })), - [TrainerType.KIERAN]: new TrainerConfig(++t).initForChampion(signatureSpecies["KIERAN"],true).setMixedBattleBgm("battle_champion_kieran") + [TrainerType.KIERAN]: new TrainerConfig(++t).initForChampion(signatureSpecies["KIERAN"], true).setMixedBattleBgm("battle_champion_kieran") .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.POLIWRATH, Species.POLITOED], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); })), @@ -1546,13 +1639,13 @@ export const trainerConfigs: TrainerConfigs = { return [modifierTypes.TERA_SHARD().generateType(null, [starter.species.type1]).withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(starter) as PersistentModifier]; }), - [TrainerType.ROCKET_BOSS_GIOVANNI_1]: new TrainerConfig(t = TrainerType.ROCKET_BOSS_GIOVANNI_1).setName("Giovanni").initForEvilTeamLeader("Rocket Boss",[]).setMixedBattleBgm("battle_rocket_boss").setVictoryBgm("victory_team_plasma") - .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.PERSIAN , Species.ALOLA_PERSIAN])) - .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.NIDOKING , Species.NIDOQUEEN ])) - .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.RHYPERIOR ])) - .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.DUGTRIO, Species.ALOLA_DUGTRIO ])) - .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.MAROWAK , Species.ALOLA_MAROWAK])) - .setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.KANGASKHAN ], TrainerSlot.TRAINER, true, p => { + [TrainerType.ROCKET_BOSS_GIOVANNI_1]: new TrainerConfig(t = TrainerType.ROCKET_BOSS_GIOVANNI_1).setName("Giovanni").initForEvilTeamLeader("Rocket Boss", []).setMixedBattleBgm("battle_rocket_boss").setVictoryBgm("victory_team_plasma") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.PERSIAN, Species.ALOLA_PERSIAN])) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.NIDOKING, Species.NIDOQUEEN])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.RHYPERIOR])) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.DUGTRIO, Species.ALOLA_DUGTRIO])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.MAROWAK, Species.ALOLA_MAROWAK])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.KANGASKHAN], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; @@ -1560,208 +1653,208 @@ export const trainerConfigs: TrainerConfigs = { p.generateName(); })), [TrainerType.ROCKET_BOSS_GIOVANNI_2]: new TrainerConfig(++t).setName("Giovanni").initForEvilTeamLeader("Rocket Boss", [], true).setMixedBattleBgm("battle_rocket_boss").setVictoryBgm("victory_team_plasma") - .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.TYRANITAR , Species.IRON_THORNS], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.TYRANITAR, Species.IRON_THORNS], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; })) - .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.HIPPOWDON ])) - .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.EXCADRILL ])) - .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.KANGASKHAN ], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.HIPPOWDON])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.EXCADRILL])) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.KANGASKHAN], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; p.formIndex = 1; p.generateName(); })) - .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.GASTRODON])) - .setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.MEWTWO ], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.GASTRODON])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.MEWTWO], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); p.pokeball = PokeballType.MASTER_BALL; })), - [TrainerType.MAXIE]: new TrainerConfig(++t).setName("Maxie").initForEvilTeamLeader("Magma Boss",[]).setMixedBattleBgm("battle_aqua_magma_boss").setVictoryBgm("victory_team_plasma") - .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.MIGHTYENA ])) - .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.CROBAT, Species.GLISCOR ])) - .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.WEEZING, Species.GALAR_WEEZING ])) - .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.MAGMORTAR, Species.TORKOAL ])) - .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.FLYGON])) - .setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.CAMERUPT ], TrainerSlot.TRAINER, true, p => { + [TrainerType.MAXIE]: new TrainerConfig(++t).setName("Maxie").initForEvilTeamLeader("Magma Boss", []).setMixedBattleBgm("battle_aqua_magma_boss").setVictoryBgm("victory_team_plasma") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.MIGHTYENA])) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.CROBAT, Species.GLISCOR])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.WEEZING, Species.GALAR_WEEZING])) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.MAGMORTAR, Species.TORKOAL])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.FLYGON])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.CAMERUPT], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; p.formIndex = 1; p.generateName(); })), - [TrainerType.MAXIE_2]: new TrainerConfig(++t).setName("Maxie").initForEvilTeamLeader("Magma Boss",[], true).setMixedBattleBgm("battle_aqua_magma_boss").setVictoryBgm("victory_team_plasma") - .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.SOLROCK, Species.TYPHLOSION ], TrainerSlot.TRAINER, true, p => { + [TrainerType.MAXIE_2]: new TrainerConfig(++t).setName("Maxie").initForEvilTeamLeader("Magma Boss", [], true).setMixedBattleBgm("battle_aqua_magma_boss").setVictoryBgm("victory_team_plasma") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.SOLROCK, Species.TYPHLOSION], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; })) - .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.TORKOAL, Species.NINETALES ], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.TORKOAL, Species.NINETALES], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.abilityIndex = 2; // DROUGHT })) - .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.SHIFTRY, Species.SCOVILLAIN ], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.SHIFTRY, Species.SCOVILLAIN], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.abilityIndex = 0; // Chlorophyll })) - .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.GREAT_TUSK ])) - .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.CAMERUPT ], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.GREAT_TUSK])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.CAMERUPT], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; p.formIndex = 1; p.generateName(); })) - .setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.GROUDON ], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.GROUDON], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); p.pokeball = PokeballType.MASTER_BALL; })), - [TrainerType.ARCHIE]: new TrainerConfig(++t).setName("Archie").initForEvilTeamLeader("Aqua Boss",[]).setMixedBattleBgm("battle_aqua_magma_boss").setVictoryBgm("victory_team_plasma") - .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.LINOONE ])) - .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.CROBAT, Species.PELIPPER ])) - .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.MUK, Species.ALOLA_MUK ])) - .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.TENTACRUEL ])) - .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.RELICANTH, Species.WAILORD ])) - .setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.SHARPEDO ], TrainerSlot.TRAINER, true, p => { + [TrainerType.ARCHIE]: new TrainerConfig(++t).setName("Archie").initForEvilTeamLeader("Aqua Boss", []).setMixedBattleBgm("battle_aqua_magma_boss").setVictoryBgm("victory_team_plasma") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.LINOONE])) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.CROBAT, Species.PELIPPER])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.MUK, Species.ALOLA_MUK])) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.TENTACRUEL])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.RELICANTH, Species.WAILORD])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.SHARPEDO], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; p.formIndex = 1; p.generateName(); })), - [TrainerType.ARCHIE_2]: new TrainerConfig(++t).setName("Archie").initForEvilTeamLeader("Aqua Boss",[], true).setMixedBattleBgm("battle_aqua_magma_boss").setVictoryBgm("victory_team_plasma") - .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.KINGDRA, Species.LUDICOLO ], TrainerSlot.TRAINER, true, p => { + [TrainerType.ARCHIE_2]: new TrainerConfig(++t).setName("Archie").initForEvilTeamLeader("Aqua Boss", [], true).setMixedBattleBgm("battle_aqua_magma_boss").setVictoryBgm("victory_team_plasma") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.KINGDRA, Species.LUDICOLO], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; })) - .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.POLITOED, Species.PELIPPER ], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.POLITOED, Species.PELIPPER], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.abilityIndex = 2; // Drizzle })) - .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.BEARTIC, Species.ARMALDO ], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.BEARTIC, Species.ARMALDO], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.abilityIndex = 2; // Swift Swim })) - .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.HUNTAIL, Species.GOREBYSS ], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.HUNTAIL, Species.GOREBYSS], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.abilityIndex = 0; // Swift Swim })) - .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.SHARPEDO ], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.SHARPEDO], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; p.formIndex = 1; p.generateName(); })) - .setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.KYOGRE ], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.KYOGRE], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); p.pokeball = PokeballType.MASTER_BALL; })), - [TrainerType.CYRUS]: new TrainerConfig(++t).setName("Cyrus").initForEvilTeamLeader("Galactic Boss",[]).setMixedBattleBgm("battle_galactic_boss").setVictoryBgm("victory_team_plasma") - .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.GYARADOS, Species.BASCULEGION ])) - .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.HONCHKROW, Species.HISUI_BRAVIARY ])) - .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.CROBAT, Species.OVERQWIL ])) - .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.AZELF, Species.UXIE, Species.MESPRIT ])) - .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.HOUNDOOM ], TrainerSlot.TRAINER, true, p => { + [TrainerType.CYRUS]: new TrainerConfig(++t).setName("Cyrus").initForEvilTeamLeader("Galactic Boss", []).setMixedBattleBgm("battle_galactic_boss").setVictoryBgm("victory_team_plasma") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.GYARADOS, Species.BASCULEGION])) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.HONCHKROW, Species.HISUI_BRAVIARY])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.CROBAT, Species.OVERQWIL])) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.AZELF, Species.UXIE, Species.MESPRIT])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.HOUNDOOM], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; p.formIndex = 1; p.generateName(); })) - .setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.WEAVILE ], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.WEAVILE], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; })), - [TrainerType.CYRUS_2]: new TrainerConfig(++t).setName("Cyrus").initForEvilTeamLeader("Galactic Boss",[], true).setMixedBattleBgm("battle_galactic_boss").setVictoryBgm("victory_team_plasma") - .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.AZELF, Species.UXIE, Species.MESPRIT ], TrainerSlot.TRAINER, true, p => { + [TrainerType.CYRUS_2]: new TrainerConfig(++t).setName("Cyrus").initForEvilTeamLeader("Galactic Boss", [], true).setMixedBattleBgm("battle_galactic_boss").setVictoryBgm("victory_team_plasma") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.AZELF, Species.UXIE, Species.MESPRIT], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); })) - .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.ELECTRODE, Species.HISUI_ELECTRODE ])) - .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.SALAMENCE, Species.ROARING_MOON ])) - .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.HOUNDOOM ], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.ELECTRODE, Species.HISUI_ELECTRODE])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.SALAMENCE, Species.ROARING_MOON])) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.HOUNDOOM], TrainerSlot.TRAINER, true, p => { p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; p.formIndex = 1; p.generateName(); })) - .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.WEAVILE ], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.WEAVILE], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; })) - .setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.DARKRAI ], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.DARKRAI], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); p.pokeball = PokeballType.MASTER_BALL; })), - [TrainerType.GHETSIS]: new TrainerConfig(++t).setName("Ghetsis").initForEvilTeamLeader("Plasma Boss",[]).setMixedBattleBgm("battle_plasma_boss").setVictoryBgm("victory_team_plasma") - .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.COFAGRIGUS, Species.RUNERIGUS ])) - .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.BOUFFALANT ])) - .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.SEISMITOAD, Species.CARRACOSTA ])) - .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.EELEKTROSS, Species.GALVANTULA ])) - .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.VOLCARONA ])) - .setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.HYDREIGON ], TrainerSlot.TRAINER, true, p => { + [TrainerType.GHETSIS]: new TrainerConfig(++t).setName("Ghetsis").initForEvilTeamLeader("Plasma Boss", []).setMixedBattleBgm("battle_plasma_boss").setVictoryBgm("victory_team_plasma") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.COFAGRIGUS, Species.RUNERIGUS])) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.BOUFFALANT])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.SEISMITOAD, Species.CARRACOSTA])) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.EELEKTROSS, Species.GALVANTULA])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.VOLCARONA])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.HYDREIGON], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; })), - [TrainerType.GHETSIS_2]: new TrainerConfig(++t).setName("Ghetsis").initForEvilTeamLeader("Plasma Boss",[], true).setMixedBattleBgm("battle_plasma_boss").setVictoryBgm("victory_team_plasma") - .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.SLITHER_WING, Species.IRON_MOTH ], TrainerSlot.TRAINER, true, p => { + [TrainerType.GHETSIS_2]: new TrainerConfig(++t).setName("Ghetsis").initForEvilTeamLeader("Plasma Boss", [], true).setMixedBattleBgm("battle_plasma_boss").setVictoryBgm("victory_team_plasma") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.SLITHER_WING, Species.IRON_MOTH], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; })) - .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.DURANT ])) - .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.DARMANITAN, Species.GALAR_DARMANITAN ])) - .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.KINGAMBIT ])) - .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.HYDREIGON, Species.IRON_JUGULIS ], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.DURANT])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.DARMANITAN, Species.GALAR_DARMANITAN])) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.KINGAMBIT])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.HYDREIGON, Species.IRON_JUGULIS], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; })) - .setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.KYUREM ], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.KYUREM], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); p.pokeball = PokeballType.MASTER_BALL; })), - [TrainerType.LYSANDRE]: new TrainerConfig(++t).setName("Lysandre").initForEvilTeamLeader("Flare Boss",[]).setMixedBattleBgm("battle_flare_boss").setVictoryBgm("victory_team_plasma") - .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.MIENSHAO ])) - .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.HONCHKROW, Species.TALONFLAME ])) - .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.PYROAR ])) - .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.MILOTIC ])) - .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.HELIOLISK ])) - .setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.GYARADOS ], TrainerSlot.TRAINER, true, p => { + [TrainerType.LYSANDRE]: new TrainerConfig(++t).setName("Lysandre").initForEvilTeamLeader("Flare Boss", []).setMixedBattleBgm("battle_flare_boss").setVictoryBgm("victory_team_plasma") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.MIENSHAO])) + .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.HONCHKROW, Species.TALONFLAME])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.PYROAR])) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.MILOTIC])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.HELIOLISK])) + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.GYARADOS], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; p.formIndex = 1; p.generateName(); })), - [TrainerType.LYSANDRE_2]: new TrainerConfig(++t).setName("Lysandre").initForEvilTeamLeader("Flare Boss",[], true).setMixedBattleBgm("battle_flare_boss").setVictoryBgm("victory_team_plasma") - .setPartyMemberFunc(0, getRandomPartyMemberFunc([ Species.SCREAM_TAIL, Species.FLUTTER_MANE ], TrainerSlot.TRAINER, true, p => { + [TrainerType.LYSANDRE_2]: new TrainerConfig(++t).setName("Lysandre").initForEvilTeamLeader("Flare Boss", [], true).setMixedBattleBgm("battle_flare_boss").setVictoryBgm("victory_team_plasma") + .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.SCREAM_TAIL, Species.FLUTTER_MANE], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; })) - .setPartyMemberFunc(1, getRandomPartyMemberFunc([ Species.GHOLDENGO, Species.AEGISLASH ])) - .setPartyMemberFunc(2, getRandomPartyMemberFunc([ Species.PYROAR ])) - .setPartyMemberFunc(3, getRandomPartyMemberFunc([ Species.GOODRA, Species.HISUI_GOODRA ])) - .setPartyMemberFunc(4, getRandomPartyMemberFunc([ Species.GYARADOS ], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(1, getRandomPartyMemberFunc([Species.GHOLDENGO, Species.AEGISLASH])) + .setPartyMemberFunc(2, getRandomPartyMemberFunc([Species.PYROAR])) + .setPartyMemberFunc(3, getRandomPartyMemberFunc([Species.GOODRA, Species.HISUI_GOODRA])) + .setPartyMemberFunc(4, getRandomPartyMemberFunc([Species.GYARADOS], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); p.pokeball = PokeballType.ULTRA_BALL; p.formIndex = 1; p.generateName(); })) - .setPartyMemberFunc(5, getRandomPartyMemberFunc([ Species.YVELTAL ], TrainerSlot.TRAINER, true, p => { + .setPartyMemberFunc(5, getRandomPartyMemberFunc([Species.YVELTAL], TrainerSlot.TRAINER, true, p => { p.setBoss(true, 2); p.generateAndPopulateMoveset(); p.pokeball = PokeballType.MASTER_BALL; diff --git a/src/enums/trainer-type.ts b/src/enums/trainer-type.ts index db0bf3a8d64..1d4d9579ee3 100644 --- a/src/enums/trainer-type.ts +++ b/src/enums/trainer-type.ts @@ -1,215 +1,223 @@ - export enum TrainerType { - UNKNOWN, + UNKNOWN, - ACE_TRAINER, - ARTIST, - BACKERS, - BACKPACKER, - BAKER, - BEAUTY, - BIKER, - BLACK_BELT, - BREEDER, - CLERK, - CYCLIST, - DANCER, - DEPOT_AGENT, - DOCTOR, - FIREBREATHER, - FISHERMAN, - GUITARIST, - HARLEQUIN, - HIKER, - HOOLIGANS, - HOOPSTER, - INFIELDER, - JANITOR, - LINEBACKER, - MAID, - MUSICIAN, - HEX_MANIAC, - NURSERY_AIDE, - OFFICER, - PARASOL_LADY, - PILOT, - POKEFAN, - PRESCHOOLER, - PSYCHIC, - RANGER, - RICH, - RICH_KID, - ROUGHNECK, - SAILOR, - SCIENTIST, - SMASHER, - SNOW_WORKER, - STRIKER, - SCHOOL_KID, - SWIMMER, - TWINS, - VETERAN, - WAITER, - WORKER, - YOUNGSTER, - ROCKET_GRUNT, - ROCKET_ADMIN, - MAGMA_GRUNT, - MAGMA_ADMIN, - AQUA_GRUNT, - AQUA_ADMIN, - GALACTIC_GRUNT, - GALACTIC_ADMIN, - PLASMA_GRUNT, - PLASMA_SAGE, - FLARE_GRUNT, - FLARE_ADMIN, - ROCKET_BOSS_GIOVANNI_1, - ROCKET_BOSS_GIOVANNI_2, - MAXIE, - MAXIE_2, - ARCHIE, - ARCHIE_2, - CYRUS, - CYRUS_2, - GHETSIS, - GHETSIS_2, - LYSANDRE, - LYSANDRE_2, + ACE_TRAINER, + ARTIST, + BACKERS, + BACKPACKER, + BAKER, + BEAUTY, + BIKER, + BLACK_BELT, + BREEDER, + CLERK, + CYCLIST, + DANCER, + DEPOT_AGENT, + DOCTOR, + FIREBREATHER, + FISHERMAN, + GUITARIST, + HARLEQUIN, + HIKER, + HOOLIGANS, + HOOPSTER, + INFIELDER, + JANITOR, + LINEBACKER, + MAID, + MUSICIAN, + HEX_MANIAC, + NURSERY_AIDE, + OFFICER, + PARASOL_LADY, + PILOT, + POKEFAN, + PRESCHOOLER, + PSYCHIC, + RANGER, + RICH, + RICH_KID, + ROUGHNECK, + SAILOR, + SCIENTIST, + SMASHER, + SNOW_WORKER, + STRIKER, + SCHOOL_KID, + SWIMMER, + TWINS, + VETERAN, + WAITER, + WORKER, + YOUNGSTER, + ROCKET_GRUNT, + ARCHER, + ARIANA, + PROTON, + PETREL, + MAGMA_GRUNT, + TABITHA, + COURTNEY, + AQUA_GRUNT, + MATT, + SHELLY, + GALACTIC_GRUNT, + JUPITER, + MARS, + SATURN, + PLASMA_GRUNT, + ZINZOLIN, + ROOD, + FLARE_GRUNT, + BRYONY, + XEROSIC, + ROCKET_BOSS_GIOVANNI_1, + ROCKET_BOSS_GIOVANNI_2, + MAXIE, + MAXIE_2, + ARCHIE, + ARCHIE_2, + CYRUS, + CYRUS_2, + GHETSIS, + GHETSIS_2, + LYSANDRE, + LYSANDRE_2, - BROCK = 200, - MISTY, - LT_SURGE, - ERIKA, - JANINE, - SABRINA, - BLAINE, - GIOVANNI, - FALKNER, - BUGSY, - WHITNEY, - MORTY, - CHUCK, - JASMINE, - PRYCE, - CLAIR, - ROXANNE, - BRAWLY, - WATTSON, - FLANNERY, - NORMAN, - WINONA, - TATE, - LIZA, - JUAN, - ROARK, - GARDENIA, - MAYLENE, - CRASHER_WAKE, - FANTINA, - BYRON, - CANDICE, - VOLKNER, - CILAN, - CHILI, - CRESS, - CHEREN, - LENORA, - ROXIE, - BURGH, - ELESA, - CLAY, - SKYLA, - BRYCEN, - DRAYDEN, - MARLON, - VIOLA, - GRANT, - KORRINA, - RAMOS, - CLEMONT, - VALERIE, - OLYMPIA, - WULFRIC, - MILO, - NESSA, - KABU, - BEA, - ALLISTER, - OPAL, - BEDE, - GORDIE, - MELONY, - PIERS, - MARNIE, - RAIHAN, - KATY, - BRASSIUS, - IONO, - KOFU, - LARRY, - RYME, - TULIP, - GRUSHA, - LORELEI = 300, - BRUNO, - AGATHA, - LANCE, - WILL, - KOGA, - KAREN, - SIDNEY, - PHOEBE, - GLACIA, - DRAKE, - AARON, - BERTHA, - FLINT, - LUCIAN, - SHAUNTAL, - MARSHAL, - GRIMSLEY, - CAITLIN, - MALVA, - SIEBOLD, - WIKSTROM, - DRASNA, - HALA, - MOLAYNE, - OLIVIA, - ACEROLA, - KAHILI, - MARNIE_ELITE, - NESSA_ELITE, - BEA_ELITE, - ALLISTER_ELITE, - RAIHAN_ELITE, - RIKA, - POPPY, - LARRY_ELITE, - HASSEL, - CRISPIN, - AMARYS, - LACEY, - DRAYTON, - BLUE = 350, - RED, - LANCE_CHAMPION, - STEVEN, - WALLACE, - CYNTHIA, - ALDER, - IRIS, - DIANTHA, - HAU, - LEON, - GEETA, - NEMONA, - KIERAN, - RIVAL = 375, - RIVAL_2, - RIVAL_3, - RIVAL_4, - RIVAL_5, - RIVAL_6 + BROCK = 200, + MISTY, + LT_SURGE, + ERIKA, + JANINE, + SABRINA, + BLAINE, + GIOVANNI, + FALKNER, + BUGSY, + WHITNEY, + MORTY, + CHUCK, + JASMINE, + PRYCE, + CLAIR, + ROXANNE, + BRAWLY, + WATTSON, + FLANNERY, + NORMAN, + WINONA, + TATE, + LIZA, + JUAN, + ROARK, + GARDENIA, + MAYLENE, + CRASHER_WAKE, + FANTINA, + BYRON, + CANDICE, + VOLKNER, + CILAN, + CHILI, + CRESS, + CHEREN, + LENORA, + ROXIE, + BURGH, + ELESA, + CLAY, + SKYLA, + BRYCEN, + DRAYDEN, + MARLON, + VIOLA, + GRANT, + KORRINA, + RAMOS, + CLEMONT, + VALERIE, + OLYMPIA, + WULFRIC, + MILO, + NESSA, + KABU, + BEA, + ALLISTER, + OPAL, + BEDE, + GORDIE, + MELONY, + PIERS, + MARNIE, + RAIHAN, + KATY, + BRASSIUS, + IONO, + KOFU, + LARRY, + RYME, + TULIP, + GRUSHA, + LORELEI = 300, + BRUNO, + AGATHA, + LANCE, + WILL, + KOGA, + KAREN, + SIDNEY, + PHOEBE, + GLACIA, + DRAKE, + AARON, + BERTHA, + FLINT, + LUCIAN, + SHAUNTAL, + MARSHAL, + GRIMSLEY, + CAITLIN, + MALVA, + SIEBOLD, + WIKSTROM, + DRASNA, + HALA, + MOLAYNE, + OLIVIA, + ACEROLA, + KAHILI, + MARNIE_ELITE, + NESSA_ELITE, + BEA_ELITE, + ALLISTER_ELITE, + RAIHAN_ELITE, + RIKA, + POPPY, + LARRY_ELITE, + HASSEL, + CRISPIN, + AMARYS, + LACEY, + DRAYTON, + BLUE = 350, + RED, + LANCE_CHAMPION, + STEVEN, + WALLACE, + CYNTHIA, + ALDER, + IRIS, + DIANTHA, + HAU, + LEON, + GEETA, + NEMONA, + KIERAN, + RIVAL = 375, + RIVAL_2, + RIVAL_3, + RIVAL_4, + RIVAL_5, + RIVAL_6 } diff --git a/src/field/trainer.ts b/src/field/trainer.ts index 107dfbe6831..470e8d2267f 100644 --- a/src/field/trainer.ts +++ b/src/field/trainer.ts @@ -121,7 +121,7 @@ export default class Trainer extends Phaser.GameObjects.Container { // Determine the title to include based on the configuration and includeTitle flag. let title = includeTitle && this.config.title ? this.config.title : null; - const evilTeamTitles = ["grunt", "admin", "sage"]; + const evilTeamTitles = ["grunt"]; if (this.name === "" && evilTeamTitles.some(t => name.toLocaleLowerCase().includes(t))) { // This is a evil team grunt so we localize it by only using the "name" as the title title = i18next.t(`trainerClasses:${name.toLowerCase().replace(/\s/g, "_")}`); @@ -165,6 +165,8 @@ export default class Trainer extends Phaser.GameObjects.Container { name = i18next.t(`trainerNames:${this.config.nameDouble.toLowerCase().replace(/\s/g, "_")}`); } + console.log(title ? `${title} ${name}` : name); + // Return the formatted name, including the title if it is set. return title ? `${title} ${name}` : name; } diff --git a/src/locales/ca-ES/dialogue.ts b/src/locales/ca-ES/dialogue.ts index 44693c38aa1..64e4028a912 100644 --- a/src/locales/ca-ES/dialogue.ts +++ b/src/locales/ca-ES/dialogue.ts @@ -383,6 +383,204 @@ export const PGMdialogue: DialogueTranslationEntries = { 3: "I think it's me that's seasick..." }, }, + + "archer": { + "encounter": { + 1: "Before you go any further, let's see how you far against us, Team Rocket!", + 2: "I have received reports that your skills are not insignificant. Let's see if they are true.", + 3: "I am Archer, an Admin of Team Rocket. And I do not go easy on enemies of our organization." + }, + "victory": { + 1: "What a blunder!", + 2: "With my current skills, I was not up to the task after all.", + 3: "F-forgive me, Giovanni... For me to be defeated by a mere trainer..." + }, + }, + "ariana": { + "encounter": { + 1: `Hold it right there! We can't someone on the loose." + $It's harmful to Team Rocket's pride, you see.`, + 2: `I don't know or care if what I'm doing is right or wrong... + $I just put my faith in Giovanni and do as I am told`, + 3: "Your trip ends here. I'm going to take you down!" + }, + "victory": { + 1: `Tch, you really are strong. It's too bad. + $If you were to join Team Rocket, you could become an Executive.`, + 2: "I... I'm shattered...", + 3: "Aaaieeeee! This can't be happening! I fought hard, but I still lost…" + }, + }, + "proton": { + "encounter": { + 1: "What do you want? If you interrupt our work, don't expect any mercy!", + 2: `What do we have here? I am often labeled as the scariest and cruelest guy in Team Rocket… + $I strongly urge you not to interfere with our business!`, + 3: "I am Proton, an Admin of Team Rocket. I am here to put an end to your meddling!" + }, + "victory": { + 1: "The fortress came down!", + 2: "You may have won this time… But all you did was make Team Rocket's wrath grow…", + 3: "I am defeated… But I will not forget this!" + }, + }, + + "petrel": { + "encounter": { + 1: `Muhahaha, we've been waiting for you. Me? You don't know who I am? It is me, Giovanni. + $The majestic Giovanni himself! Wahahaha! …Huh? I don't sound anything like Giovanni? + $I don't even look like Giovanni? How come? I've worked so hard to mimic him!`, + 2: "I am Petrel, an Admin of Team Rocket. I will not allow you to interfere with our plans!", + 3: "Rocket Executive Petrel will deal with this intruder!" + }, + "victory": { + 1: "OK, OK. I'll tell you where he is.", + 2: "I… I couldn't do a thing… Giovanni, please forgive me…", + 3: "No, I can't let this affect me. I have to inform the others…" + }, + }, + "tabitha": { + "encounter": { + 1: "Hehehe! So you've come all the way here! But you're too late!", + 2: `Hehehe... Got here already, did you? We underestimated you! But this is it! + $I'm a cut above the Grunts you've seen so far. I'm not stalling for time. + $I'm going to pulverize you!`, + 3: "I'm going to give you a little taste of pain! Resign yourself to it!" + }, + "victory": { + 1: `Hehehe! You might have beaten me, but you don't stand a chance against the Boss! + $If you get lost now, you won't have to face a sound whipping!`, + 2: "Hehehe... So, I lost, too...", + 3: "Ahya! How could this be? For an Admin like me to lose to some random trainer..." + }, + }, + "courtney": { + "encounter": { + 1: "The thing...The thing that you hold...That is what... That's what we of Team Magma seek...", + 2: "... Well then...Deleting...", + 3: "...Ha. ...Analyzing... ...Hah♪" + }, + "victory": { + 1: "... ...Change...the world.", + 2: `As anticipated. Unanticipated. You. Target lock...completed. + $Commencing...experiment. You. Forever. Aha... ♪`, + 3: "...Again? That's unanticipated. ...I knew it. You...are interesting! ...Haha. ♪" + }, + }, + "shelly": { + "encounter": { + 1: `Ahahahaha! You're going to meddle in Team Aqua's affairs? + $You're either absolutely fearless, simply ignorant, or both! + $You're so cute, you're disgusting! I'll put you down`, + 2: "What's this? Who's this spoiled brat?", + 3: "Cool your jets. Be patient. I'll crush you shortly." + }, + "victory": { + 1: `Ahahahaha! We got meddled with unexpectedly! We're out of options. + $We'll have to pull out. But this isn't the last you'll see of Team Aqua! + $We have other plans! Don't you forget it!`, + 2: "Ahhh?! Did I go too easy on you?!", + 3: `Uh. Are you telling me you've upped your game even more during the fight? + $You're a brat with a bright future… My Pokémon and I don't have any strength left to fight… + $Go on… Go and be destroyed by Archie.` + }, + }, + "matt": { + "encounter": { + 1: "Hoohahaha! What, you got a screw loose or something? Look at you, little Makuhita person!", + 2: "Oho! You! You're that funny kid!", + 3: "What are you doing here? Did you follow us?" + }, + "victory": { + 1: "All right then, until the Boss has time for you, I'll be your opponent!", + 2: `I can feel it! I can feel it, all right! The strength coming offa you! + $More! I still want more! But looks like we're outta time...`, + 3: "That was fun! I knew you'd show me a good time! I look forward to facing you again someday!" + }, + }, + "mars": { + "encounter": { + 1: "I'm Mars, one of Team Galactic's top Commanders.", + 2: "Team Galactic's vision for the future is unwavering. Opposition will be crushed without mercy!", + 3: "Feeling nervous? You should be!" + }, + "victory": { + 1: "This can't be happening! How did I lose?!", + 2: "You have some skill, I'll give you that.", + 3: "Defeated... This was a costly mistake." + } + }, + "jupiter": { + "encounter": { + 1: "Jupiter, Commander of Team Galactic, at your service.", + 2: "Resistance is futile. Team Galactic will prevail!", + 3: "You're trembling... scared already?" + }, + "victory": { + 1: "No way... I lost?!", + 2: "Impressive, you've got guts!", + 3: "Losing like this... How embarrassing." + } + }, + "saturn": { + "encounter": { + 1: "I am Saturn, Commander of Team Galactic.", + 2: "Our mission is absolute. Any hindrance will be obliterated!", + 3: "Is that fear I see in your eyes?" + }, + "victory": { + 1: "Impossible... Defeated by you?!", + 2: "You have proven yourself a worthy adversary.", + 3: "Bestowed in defeat... This is unacceptable." + }}, + "zinzolin": { + "encounter": { + 1: "You could become a threat to Team Plasma, so we will eliminate you here and now!", + 2: "Oh, for crying out loud... I didn't expect to have to battle in this freezing cold!", + 3: "You're an impressive Trainer to have made it this far. But it ends here." + }, + "victory": { + 1: "Ghetsis... I have failed you...", + 2: "It's bitter cold. I'm shivering. I'm suffering. Yet, I still stand victorious.", + 3: "Hmph. You're a smarter Trainer than I expected, but not smart enough." + } + }, + "rood": { + "encounter": { + 1: "You are a threat to Team Plasma. We cannot let you walk away from here and now!", + 2: "Oh, this icy wind... I never thought I'd have to fight here!", + 3: "You are a remarkable Trainer to have made it this far. But this is where it ends." + }, + "victory": { + 1: "Ghetsis... I have failed my mission...", + 2: "The cold is piercing. I'm shivering. I'm suffering. Yet, I have triumphed.", + 3: "Hm. You are a talented Trainer, but unfortunately not talented enough." + } + }, + "xerosic": { + "encounter": { + 1: "Ah ha ha! It would be my pleasure. Come on, little Trainer! Let's see what you've got!", + 2: "Hmm... You're more powerful than you look. I wonder how much energy there is inside you.", + 3: "I've been waiting for you! I need to do a little research on you! Come, let us begin!" + }, + "victory": { + 1: "Ah, you're quite strong. Oh yes—very strong, indeed.", + 2: "Ding-ding-ding! You did it! To the victor go the spoils!", + 3: "Wonderful! Amazing! You have tremendous skill and bravery!" + } + }, + "bryony": { + "encounter": { + 1: "I am Bryony, and it would be my pleasure to battle you. Show me what you've got.", + 2: "Impressive... You're more powerful than you appear. Let's see the true extent of your energy.", + 3: "I've anticipated your arrival. It's time for a little test. Shall we begin?" + }, + "victory": { + 1: "You're quite strong. Oh yes—very strong, indeed.", + 2: "Ding-ding-ding! You've done well. Victory is yours.", + 3: "Wonderful! Remarkable! Your skill and bravery are commendable." + } + }, "rocket_grunt": { "encounter": { 1: "Prepare for trouble!" @@ -391,18 +589,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "Team Rocket blasting off again!" }, }, - "rocket_admin": { - "encounter": { - 1: "Oh? You managed to get this far? You must be quite the trainer.", - 2: "That's quite enough of you playing hero, kid.", - 3: "I'll show you how scary an angry adult can be!" - }, - "victory": { - 1: "No! Forgive me Giovanni!", - 2: "How could this be?", - 3: "Urgh... You were too strong..." - }, - }, "magma_grunt": { "encounter": { 1: " If you get in the way of Team Magma, don’t expect any mercy!" @@ -411,18 +597,7 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "Huh? I lost?!" }, }, - "magma_admin": { - "encounter": { - 1: "Hehehe! So you've come all the way here! But you're too late!", - 2: "You're going to meddle in Team Magma's affairs? You're so cute you're disgusting! I'll put you down kiddy!", - 3: "I'm going to give you a little taste of pain! Resign yourself to it!" - }, - "victory": { - 1: "Hehehe... So I lost...", - 2: "You're disgustingly strong!", - 3: "Ahahaha! Ouch!" - }, - }, + "aqua_grunt": { "encounter": { 1: "No one who crosses Team Aqua gets any mercy, not even kids!" @@ -431,18 +606,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "You're kidding me!" }, }, - "aqua_admin": { - "encounter": { - 1: "I'm a cut above the grunts you've seen so far. I'm going to puvlerize you!", - 2: "Hahn? What's this? Who's this spoiled brat?", - 3: "What are you doing here? Did you follow us?" - }, - "victory": { - 1: "So I lost too...", - 2: "Ahhh?! Did I go too easy on you?!", - 3: "Wh-what was that?" - }, - }, "galactic_grunt": { "encounter": { 1: "Don't mess with Team Galactic!" @@ -451,18 +614,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "Shut down..." }, }, - "galactic_admin": { - "encounter": { - 1: "I'm one of Team Galactic's Commanders.", - 2: "Anything that opposes Team Galactic must be crushed! Even the very thought of opposition will not be tolerated!", - 3: "What's the matter? Don't tell me you're shaking?" - }, - "victory": { - 1: "This can't be?! I lost?! You... you uppity brat!", - 2: "You, my friend, are tough!", - 3: "Losing to some child... Being careless cost me too much." - }, - }, "plasma_grunt": { "encounter": { 1: "We won't tolerate people who have different ideas!" @@ -471,18 +622,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "Plasmaaaaaaaaa!" }, }, - "plasma_sage": { - "encounter": { - 1: "You could become a threat to Team Plasma, so we will eliminate you here!", - 2: "Oh, for crying out loud... I didn't expect to have to fight!", - 3: "You're an impressive Trainer to have made it this far." - }, - "victory": { - 1: "Ghetsis...", - 2: "It's bitter cold. I'm shivering. I'm suffering.", - 3: "Hmph. You're a smarter Trainer than I expected." - }, - }, "flare_grunt": { "encounter": { 1: "Fashion is most important to us!" @@ -491,18 +630,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "The future doesn't look bright for me." }, }, - "flare_admin": { - "encounter": { - 1: "Ah ha ha! It would be my pleasure. Come on, little Trainer! Let's see what you've got!", - 2: "Hmm... You're more powerful than you look. I wonder how much energy there is inside you.", - 3: "I've been waiting for you! I need to do a little research on you! Come, let us begin!" - }, - "victory": { - 1: "You're quite strong. Oh yes-very strong, indeed.", - 2: "Ding-ding-ding! Yup, you did it! To the victor goes the spoils!", - 3: "Wonderful! Amazing! You have tremendous skill and bravery!" - }, - }, "rocket_boss_giovanni_1": { "encounter": { 1: "So! I must say, I am impressed you got here!" @@ -2605,7 +2732,7 @@ export const PGFbattleSpecDialogue: SimpleTranslationEntries = PGMbattleSpecDial // Dialogue that does not fit into any other category (e.g. tutorial messages, or the end of the game). For when the player character is male export const PGMmiscDialogue: SimpleTranslationEntries = { "ending": - `@c{smile}Oh? You won?@d{96} @c{smile_eclosed}I guess I should've known.\nBut, you're back now. + `@c{smile}Oh? You won?@d{96} @c{smile_eclosed}I guess I should've known.\nBut, you're back now. $@c{smile}It's over.@d{64} You ended the loop. $@c{serious_smile_fists}You fulfilled your dream too, didn't you?\nYou didn't lose even once. $@c{neutral}I'm the only one who'll remember what you did.@d{96}\nI guess that's okay, isn't it? @@ -2613,7 +2740,7 @@ export const PGMmiscDialogue: SimpleTranslationEntries = { $@c{smile_eclosed}Anyway, I've had about enough of this place, haven't you? Let's head home. $@c{serious_smile_fists}Maybe when we get back, we can have another battle?\nIf you're up to it.`, "ending_female": - `@c{shock}You're back?@d{32} Does that mean…@d{96} you won?!\n@c{smile_ehalf}I should have known you had it in you. + `@c{shock}You're back?@d{32} Does that mean…@d{96} you won?!\n@c{smile_ehalf}I should have known you had it in you. $@c{smile_eclosed}Of course… I always had that feeling.\n@c{smile}It's over now, right? You ended the loop. $@c{smile_ehalf}You fulfilled your dream too, didn't you?\nYou didn't lose even once. $I'll be the only one to remember what you did.\n@c{angry_mopen}I'll try not to forget! diff --git a/src/locales/ca-ES/trainers.ts b/src/locales/ca-ES/trainers.ts index 00367865d14..a40fabaeacc 100644 --- a/src/locales/ca-ES/trainers.ts +++ b/src/locales/ca-ES/trainers.ts @@ -19,6 +19,19 @@ export const titles: SimpleTranslationEntries = { "galactic_boss": "Team Galactic Boss", "plasma_boss": "Team Plasma Boss", "flare_boss": "Team Flare Boss", + + "rocket_admin": "Team Rocket Admin", + "rocket_admin_female": "Team Rocket Admin", + "magma_admin": "Team Magma Admin", + "magma_admin_female": "Team Magma Admin", + "aqua_admin": "Team Aqua Admin", + "aqua_admin_female": "Team Aqua Admin", + "galactic_commander": "Team Galactic Commander", + "galactic_commander_female": "Team Galactic Commander", + "plasma_sage": "Team Plasma Sage", + "plasma_admin": "Team Plasma Admin", + "flare_admin": "Team Flare Admin", + "flare_admin_female": "Team Flare Admin", // Maybe if we add the evil teams we can add "Team Rocket" and "Team Aqua" etc. here as well as "Team Rocket Boss" and "Team Aqua Admin" etc. } as const; @@ -128,32 +141,21 @@ export const trainerClasses: SimpleTranslationEntries = { "rocket_grunt": "Rocket Grunt", "rocket_grunts": "Rocket Grunts", "rocket_grunt_female": "Rocket Grunt", - "rocket_admin": "Rocket Admin", - "rocket_admin_female": "Rocket Admin", "magma_grunt": "Magma Grunt", "magma_grunt_female": "Magma Grunt", "magma_grunts": "Magma Grunts", - "magma_admin": "Magma Admin", - "magma_admin_female": "Magma Admin", "aqua_grunt": "Aqua Grunt", "aqua_grunt_female": "Aqua Grunt", "aqua_grunts": "Aqua Grunts", - "aqua_admin": "Aqua Admin", - "aqua_admin_female": "Aqua Admin", "galactic_grunt": "Galactic Grunt", "galactic_grunt_female": "Galactic Grunt", "galactic_grunts": "Galactic Grunts", - "galactic_admin": "Galactic Admin", - "galactic_admin_female": "Galactic Admin", "plasma_grunt": "Plasma Grunt", "plasma_grunt_female": "Plasma Grunt", "plasma_grunts": "Plasma Grunts", - "plasma_sage": "Plasma Sage", "flare_grunt": "Flare Grunt", "flare_grunt_female": "Flare Grunt", "flare_grunts": "Flare Grunts", - "flare_admin": "Flare Admin", - "flare_admin_female": "Flare Admin", } as const; // Names of special trainers like gym leaders, elite four, and the champion @@ -282,6 +284,24 @@ export const trainerNames: SimpleTranslationEntries = { "leon": "Leon", "rival": "Finn", "rival_female": "Ivy", + + // Evil Team Admins + "archer": "Archer", + "ariana": "Ariana", + "proton": "Proton", + "petrel": "Petrel", + "tabitha": "Tabitha", + "courtney": "Courtney", + "shelly": "Shelly", + "matt": "Matt", + "mars": "Mars", + "jupiter": "Jupiter", + "saturn": "Saturn", + "zinzolin": "Zinzolin", + "rood": "Rood", + "xerosic": "Xerosic", + "bryony": "Bryony", + "maxie": "Maxie", "archie": "Archie", "cyrus": "Cyrus", diff --git a/src/locales/de/dialogue.ts b/src/locales/de/dialogue.ts index 57fd9071463..09a887ef875 100644 --- a/src/locales/de/dialogue.ts +++ b/src/locales/de/dialogue.ts @@ -367,30 +367,212 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "Ich werde für das nächste Rennen tunen." }, }, - "rocket_grunt": { + "archer": { "encounter": { - 1: `Jetzt gibt es Ärger!… - $und es kommt noch härter! - $Wir wollen über die Erde regieren… - $und naja du kennst den Rest…!` + 1: "Bevor du weitergehst, lass uns sehen, wie du dich gegen uns, Team Rocket, schlägst!", + 2: `Ich habe Berichte erhalten, dass deine Fähigkeiten nicht unbedeutend sind. + $Mal sehen, ob sie wahr sind.`, + 3: `Ich bin Atlas, ein Vorstand von Team Rocket. + $Und ich mache es den Feinden unserer Organisation nicht leicht.` }, "victory": { - 1: "Das war mal wieder ein Schuss in den Ofen!" - }, + 1: "Was für ein Fehler!", + 2: "Mit meinen aktuellen Fähigkeiten war ich der Aufgabe doch nicht gewachsen.", + 3: "V-verzeih mir, Giovanni... Dass ich von einem einfachen Trainer besiegt wurde..." + } }, - "rocket_admin": { + "ariana": { "encounter": { - 1: "Oh? Du wagst es, dich Team Rocket zu widersetzen? Du wirst es bereuen.", - 2: "Du glaubst, du kannst uns aufhalten? Naiver Narr!", - 3: "Ich werde dir die wahre Macht von Team Rocket zeigen!" + 1: `Halt! Wir können niemanden herumlaufen lassen. + $Es ist schädlich für den Stolz von Team Rocket, verstehst du.`, + 2: `Ich weiß nicht und es ist mir egal, ob das, was ich tue, richtig oder falsch ist... + $Ich vertraue einfach auf Giovanni und tue, was mir gesagt wird.`, + 3: "Dein Trip endet hier. Ich werde dich erledigen!" }, "victory": { - 1: "Nein! Verzeih mir, Giovanni!", - 2: "Wie konnte das geschehen?", - 3: "Urgh... Du warst zu stark..." - }, + 1: `Tch, du bist wirklich stark. Es ist schade. + $Wenn du Team Rocket beitreten würdest, könntest du ein Vorstand werden.`, + 2: "Ich... ich bin zerstört...", + 3: "Aaaieeeee! Das kann nicht passieren! Ich habe hart gekämpft, aber trotzdem verloren..." + } + }, + "proton": { + "encounter": { + 1: "Was willst du? Wenn du unsere Arbeit unterbrichst, erwarte keine Gnade!", + 2: `Was haben wir hier? Ich werde oft als der gruseligste und grausamste Typ bei Team Rocket bezeichnet… + $Ich rate dir dringend, dich nicht in unsere Geschäfte einzumischen!`, + 3: "Ich bin Proton, ein Admin von Team Rocket. Ich bin hier, um deinem Einmischen ein Ende zu setzen!" + }, + "victory": { + 1: "Die Festung ist gefallen! Alle Mann zurückziehen!", + 2: "Du hast diesmal gewonnen… Aber alles, was du getan hast, war, den Zorn von Team Rocket zu vergrößern…", + 3: "Ich bin besiegt… Aber ich werde das nicht vergessen!" + } + }, + "petrel": { + "encounter": { + 1: `Muhahaha, wir haben auf dich gewartet. Ich? Du weißt nicht, wer ich bin? Ich bin Giovanni. + $Der majestätische Giovanni höchstpersönlich! Wahahaha! + $…Huh? Ich klinge überhaupt nicht wie Giovanni? + $Ich sehe nicht einmal aus wie Giovanni? + $Wie kommt das? Ich habe so hart daran gearbeitet, ihn nachzuahmen!`, + 2: "Ich bin Lambda, ein Admin von Team Rocket. Ich werde nicht zulassen, dass du unsere Pläne störst!", + 3: "Rocket Vorstand Lambda wird sich um diesen Eindringling kümmern!" + }, + "victory": { + 1: "OK, OK. Ich sage dir, wo er ist.", + 2: "Ich… Ich konnte nichts tun… Giovanni, bitte vergib mir…", + 3: "Nein, ich kann das nicht auf mich sitzen lassen. Ich muss die anderen informieren…" + } + }, + "tabitha": { + "encounter": { + 1: "Hehehe! Du bist also bis hierher gekommen! Aber du bist zu spät!", + 2: `Hehehe... Schon hier, oder? Wir haben dich unterschätzt! Aber das war's! + $Ich bin eine Klasse über den Rüpeln, die du bisher gesehen hast. Ich halte dich nicht hin. + $Ich werde dich zermalmen!`, + 3: "Ich werde dir eine kleine Kostprobe des Schmerzes geben! Ergebe dich!" + }, + "victory": { + 1: `Hehehe! Du hast mich vielleicht besiegt, aber du hast keine Chance gegen den Boss! + $Wenn du jetzt aufgibst, musst du dich keiner ordentlichen Tracht Prügel stellen!`, + 2: "Hehehe... Also habe ich auch verloren...", + 3: "Ahya! Wie konnte das passieren? Ein Vorstand wie ich von einem zufälligen Trainer besiegt..." + } + }, + "courtney": { + "encounter": { + 1: `Das Ding... Das Ding, das du hältst... Das ist es, was... + $Das ist es, wonach wir von Team Magma suchen...`, + 2: "... Nun dann... Auslöschen...", + 3: `...?! Du... Hm... ♪ Das trifft sich ausgezeichnet... ♪ + $Dann hole ich mir eben zuerst deine Pokémon... Her damit...` + }, + "victory": { + 1: "... ...Ändere... die Welt.", + 2: `Wie erwartet. Unerwartet. Du. Ziel erfasst... abgeschlossen. + $Beginne... Experiment. Du. Für immer. Aha... ♪`, + 3: "...Schon wieder? Das war unerwartet. ...Ich wusste es. Du... bist interessant! ...Haha. ♪" + } + }, + "shelly": { + "encounter": { + 1: `Ahahahaha! Du wirst dich in die Angelegenheiten von Team Aqua einmischen? + $Du bist entweder absolut furchtlos, einfach unwissend oder beides! + $Du bist so süß, dass es ekelhaft ist! Ich werde dich erledigen.`, + 2: "Was ist das? Wer ist dieser verwöhnte Gör?", + 3: "Beruhige dich. Sei geduldig. Ich werde dich gleich zermalmen." + }, + "victory": { + 1: `Ahahahaha! Wir wurden unerwartet gestört! Uns bleiben keine Optionen. + $Wir müssen uns zurückziehen. Aber das ist nicht das letzte Mal, dass du Team Aqua siehst! + $Wir haben andere Pläne! Vergiss das nicht!`, + 2: "Ahhh?! War ich zu nachsichtig mit dir?!", + 3: `Uh. Willst du mir sagen, dass du während des Kampfes noch besser geworden bist? + $Du bist ein Gör mit einer glänzenden Zukunft… + $Meine Pokémon und ich haben keine Kraft mehr zu kämpfen… + $Geh weiter… Geh und werde von Adrian zerstört.` + } + }, + "matt": { + "encounter": { + 1: `Hoohahaha! Was, hast du eine Schraube locker oder so? + $Sieh dich an, kleiner Makuhita-ähnlicher Trainer!`, + 2: "Oho! Du! Du bist das lustige Kind!", + 3: "Was machst du hier? Bist du uns gefolgt?" + }, + "victory": { + 1: "Na gut, bis der Boss Zeit für dich hat, werde ich dein Gegner sein!", + 2: `Ich kann es fühlen! Ich kann es spüren, das ist klar! Die Stärke, die von dir ausgeht! + $Mehr! Ich will noch mehr! Aber es sieht so aus, als hätten wir keine Zeit mehr...`, + 3: `Das war Spaß! Ich wusste, dass du mir eine gute Zeit bieten würdest! + $Ich freue mich darauf, dich eines Tages wieder zu treffen!` + } + }, + "mars": { + "encounter": { + 1: "Ich bin Mars, eine der obersten Commander von Team Galaktik.", + 2: "Die Vision von Team Galaktik für die Zukunft ist unbeirrt. Opposition wird gnadenlos zerschlagen!", + 3: "Fühlst du dich nervös? Das solltest du!" + }, + "victory": { + 1: "Das kann nicht passieren! Wie habe ich verloren?!", + 2: "Du hast etwas Können, das muss ich zugeben.", + 3: "Besiegt... Das war ein teurer Fehler." + } + }, + "jupiter": { + "encounter": { + 1: "Jupiter, Commander von Team Galaktik, zu Diensten.", + 2: "Widerstand ist zwecklos. Team Galaktik wird siegen!", + 3: "Du zitterst... Schon Angst?" + }, + "victory": { + 1: "Unmöglich... Ich habe verloren?!", + 2: "Beeindruckend, du hast Mut!", + 3: "So zu verlieren... Wie peinlich." + } + }, + "saturn": { + "encounter": { + 1: "Ich bin Saturn, Commander von Team Galaktik.", + 2: "Unsere Mission ist absolut. Jeder Widerstand wird vernichtet!", + 3: "Ist das Angst, die ich in deinen Augen sehe?" + }, + "victory": { + 1: "Unmöglich... Von dir besiegt?!", + 2: "Du hast dich als würdiger Gegner erwiesen.", + 3: "Besiegt in der Niederlage... Das ist inakzeptabel." + } + }, + "zinzolin": { + "encounter": { + 1: "Du könntest eine Bedrohung für Team Plasma werden, also werden wir dich hier und jetzt eliminieren!", + 2: "Oh, zum Heulen... Ich hatte nicht erwartet, in dieser eisigen Kälte kämpfen zu müssen!", + 3: "Du bist ein beeindruckender Trainer, dass du es so weit geschafft hast. Aber hier endet es." + }, + "victory": { + 1: "G-Cis... Ich habe versagt...", + 2: "Es ist bitterkalt. Ich zittere. Ich leide. Doch ich stehe immer noch siegreich da.", + 3: "Hm. Du bist ein klügerer Trainer, als ich erwartet habe, aber nicht klug genug." + } + }, + "rood": { + "encounter": { + 1: "Du bist eine Bedrohung für Team Plasma. Wir können dich hier und jetzt nicht laufen lassen!", + 2: "Oh, dieser eisige Wind... Ich hätte nie gedacht, dass ich hier kämpfen müsste!", + 3: "Du bist ein bemerkenswerter Trainer, dass du es bis hierher geschafft hast. Aber hier wird es enden." + }, + "victory": { + 1: "G-Cis... Ich habe meine Mission nicht erfüllt...", + 2: "Die Kälte ist durchdringend. Ich zittere. Ich leide. Doch ich habe gesiegt.", + 3: "Hm. Du bist ein talentierter Trainer, aber leider nicht talentiert genug." + } + }, + "xerosic": { + "encounter": { + 1: "Ah ha ha! Es wäre mir ein Vergnügen. Komm schon, kleiner Trainer! Zeig mir, was du drauf hast!", + 2: "Hm... Du bist mächtiger, als du aussiehst. Ich frage mich, wie viel Energie in dir steckt.", + 3: "Ich habe auf dich gewartet! Ich muss ein wenig Forschung an dir betreiben! Komm, lass uns beginnen!" + }, + "victory": { + 1: "Ah, du bist ziemlich stark. Oh ja—sehr stark, in der Tat.", + 2: "Ding-ding-ding! Du hast es geschafft! Dem Sieger gebührt die Beute!", + 3: "Wunderbar! Erstaunlich! Du hast enorme Fähigkeiten und Mut!" + } + }, + "bryony": { + "encounter": { + 1: "Ich bin Begonia, und es wäre mir ein Vergnügen, gegen dich zu kämpfen. Zeig mir, was du drauf hast.", + 2: "Beeindruckend... Du bist mächtiger, als du aussiehst. Zeig mir das wahre Ausmaß deiner Energie.", + 3: "Ich habe deine Ankunft erwartet. Es ist Zeit für einen kleinen Test. Sollen wir beginnen?" + }, + "victory": { + 1: "Du bist ziemlich stark. Oh ja—sehr stark, in der Tat.", + 2: "Ding-ding-ding! Du hast dich gut geschlagen. Der Sieg gehört dir.", + 3: "Wunderbar! Bemerkenswert! Deine Fähigkeiten und dein Mut sind lobenswert." + } }, - "firebreather": { "encounter": { 1: "Meine Flammen werden dich verschlingen!", @@ -415,6 +597,17 @@ export const PGMdialogue: DialogueTranslationEntries = { 3: "Ich glaube, ich bin der der seekrank ist..." }, }, + "rocket_grunt": { + "encounter": { + 1: `Jetzt gibt es Ärger!… + $und es kommt noch härter! + $Wir wollen über die Erde regieren… + $und naja du kennst den Rest…!` + }, + "victory": { + 1: "Das war mal wieder ein Schuss in den Ofen!" + }, + }, "magma_grunt": { "encounter": { 1: "Keiner, der sich Team Magma in den Weg stellt, bekommt Gnade, nicht einmal Kinder!" @@ -423,20 +616,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "Wie kann das sein? Ich bin Teil vom mächtigen Team Magma! Wir wollen doch nur die Welt verbessern…" }, }, - "magma_admin": { - "encounter": { - 1: `Hahaha! Du hast den ganzen weiten Weg auf dich genommen! Aber du bist zu spät! - $Unsere Mission ist schon fast abgeschlossen!`, - 2: `Du willst dich in Team Magmas Angelegenheiten einmischen? Du bist so süß, dass es ekelhaft ist! - $Ich werde dich ein für alle Mal erledigen!`, - 3: "Ich werde dir zeigen, was wahrer Schmerz ist! Mach dich bereit!", - }, - "victory": { - 1: "Hahaha! Ouch! Ich habe wohl verloren...", - 2: "Du bist ekelhaft stark!", - 3: "Da habe ich meine eigene Medizin zu schmecken bekommen!" - }, - }, "aqua_grunt": { "encounter": { 1: "Du willst dich also mit Team Aqua anlegen? Du traust dich ja was… Dich werfe ich über Bord!", @@ -445,18 +624,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "Vielleicht sollte ich wohl lieber selber über die Planke gehen…", }, }, - "aqua_admin": { - "encounter": { - 1: "Ich bin eine Stufe über den Rüpeln, die du bisher gesehen hast. Ich werde dich pulverisieren!", - 2: "Hmmm? Wer ist das? Wer ist dieses verwöhnte Gör?", - 3: "Was machst du hier? Bist du uns gefolgt? Dann müssen wir dich wohl loswerden!" - }, - "victory": { - 1: "Also habe ich auch verloren...", - 2: "Ahhh?! War ich zu nachsichtig mit dir?!", - 3: "W-was war das?" - }, - }, "galactic_grunt": { "encounter": { 1: "Team Galaktik wird die Welt in eine bessere Welt verwandeln! Und du wirst uns nicht aufhalten!" @@ -465,19 +632,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "Zyrus wird uns für diese Niederlage bestrafen…" }, }, - "galactic_admin": { - "encounter": { - 1: "Ich bin einer der Commander von Team Galaktik. Wir werden Zyrus' Traum verwirklichen!", - 2: `Alles, was sich Team Galaktik widersetzt, muss zerschlagen werden! - $Selbst der Gedanke an Widerstand wird nicht toleriert!`, - 3: "Was ist los? Sag mir nicht, dass du zitterst? Mach ich dir Angst? Gut so! Knie nieder!" - }, - "victory": { - 1: "Das kann nicht sein?! Ich habe verloren?! Du... du freches Gör!", - 2: "Du, mein Freund, bist stark! Aber widestand ist zwecklos! Team Galaktik wird siegen!", - 3: "Gegen ein Kind zu verlieren... Meine Unachtsamkeit wird mir nicht verziehen werden..." - }, - }, "plasma_grunt": { "encounter": { 1: "Pokémon sollten frei sein! Team Plasma wird sie befreien!" @@ -486,19 +640,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "Wie konnte ich verlieren? Ich dachte, ich würde die Welt retten…" }, }, - "plasma_sage": { - "encounter": { - 1: "Du könntest eine Bedrohung für Team Plasma werden, also werden wir dich hier eliminieren!", - 2: "Oh, ernsthaft... Ich hatte nicht erwartet, kämpfen zu müssen!", - 3: `Du bist ein beeindruckender Trainer, dass du es so weit geschafft hast. - $Als Weiser von Team Plasma werde ich dich besiegen!` - }, - "victory": { - 1: "G-Cis...", - 2: "Es ist bitterkalt. Ich zittere. Ich leide.", - 3: "Hm. Du bist ein klügerer Trainer, als ich erwartet hatte. Ich bin beeindruckt." - }, - }, "flare_grunt": { "encounter": { 1: `Ich bin ein Mitglied von Team Flare! Das sieht man mir doch an. Mein Stil ist unverkennbar! @@ -508,18 +649,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "Stil ist wohl doch nicht alles…" }, }, - "flare_admin": { - "encounter": { - 1: "Ah ha ha! Es wäre mir ein Vergnügen. Komm schon, kleiner Trainer! Zeig mir, was du drauf hast!", - 2: "Wir von Team Flare sind die einzigen, die die Schönheit der Welt wirklich schätzen!", - 3: "Ich habe auf dich gewartet! Lass mich ein wenig an dir forschen! Komm, lass uns beginnen!" - }, - "victory": { - 1: "Du bist ziemlich stark. Oh ja, sehr stark, in der Tat.", - 2: "Es scheint als hätte ich mich geirrt… Der Sieger steht fest.", - 3: "Wunderbar! Erstaunlich! Du hast enormes Geschick und dieser Mut!" - }, - }, "rocket_boss_giovanni_1": { "encounter": { 1: `Ich bin beeindruckt, du hast es bis hierher geschafft! diff --git a/src/locales/de/trainers.ts b/src/locales/de/trainers.ts index 5b156afd331..6bde37a4ea3 100644 --- a/src/locales/de/trainers.ts +++ b/src/locales/de/trainers.ts @@ -19,6 +19,19 @@ export const titles: SimpleTranslationEntries = { "galactic_boss": "Galaktik-Boss", "plasma_boss": "Weiser von Team Plasma", // This is on purpose, since "Ghetsis" is never mentioned as the boss of team plasma in the game but as "Weiser" "flare_boss": "Flare-Boss", + + "rocket_admin": "Team Rocket Vorstand", + "rocket_admin_female": "Team Rocket Vorstand", + "magma_admin": "Team Magma Vorstand", + "magma_admin_female": "Team Magma Vorstand", + "aqua_admin": "Team Aqua Vorstand", + "aqua_admin_female": "Team Aqua Vorstand", + "galactic_commander": "Team Galaktik Commander", + "galactic_commander_female": "Team Galaktik Commander", + "plasma_sage": "Weiser von Team Plasma", + "plasma_admin": "Team Plasma Vorstand", + "flare_admin": "Team Flare Vorstand", + "flare_admin_female": "Team Flare Vorstand", // Maybe if we add the evil teams we can add "Team Rocket" and "Team Aqua" etc. here as well as "Team Rocket Boss" and "Team Aqua Admin" etc. } as const; @@ -128,32 +141,21 @@ export const trainerClasses: SimpleTranslationEntries = { "rocket_grunt": "Rüpel von Team Rocket", "rocket_grunt_female": "Rüpel von Team Rocket", "rocket_grunts": "Rüpel von Team Rocket", - "rocket_admin": "Team Rocket Vorstand", - "rocket_admin_female": "Team Rocket Vorstand", "magma_grunt": "Rüpel von Team Magma", "magma_grunt_female": "Rüpel von Team Magma", "magma_grunts": "Rüpel von Team Magma", - "magma_admin": "Team Magma Vorstand", - "magma_admin_female": "Team Magma Vorstand", "aqua_grunt": "Rüpel von Team Aqua", "aqua_grunt_female": "Rüpel von Team Aqua", "aqua_grunts": "Rüpel von Team Aqua", - "aqua_admin": "Team Aqua Vorstand", - "aqua_admin_female": "Team Aqua Vorstand", "galactic_grunt": "Rüpel von Team Galaktik", "galactic_grunt_female": "Rüpel von Team Galaktik", "galactic_grunts": "Rüpel von Team Galaktik", - "galactic_admin": "Team Galaktik Commander", - "galactic_admin_female": "Team Galaktik Commander", "plasma_grunt": "Rüpel von Team Plasma", "plasma_grunt_female": "Rüpel von Team Plasma", "plasma_grunts": "Rüpel von Team Plasma", - "plasma_sage": "Weiser von Team Plasma", "flare_grunt": "Rüpel von Team Flare", "flare_grunt_female": "Rüpel von Team Flare", "flare_grunts": "Rüpel von Team Flare", - "flare_admin": "Team Flare Vorstand", - "flare_admin_female": "Team Flare Vorstand", } as const; // Names of special trainers like gym leaders, elite four, and the champion @@ -282,6 +284,24 @@ export const trainerNames: SimpleTranslationEntries = { "leon": "Delion", "rival": "Finn", "rival_female": "Ivy", + + // Evil Team Admins + "archer": "Atlas", + "ariana": "Athena", + "proton": "Lance", + "petrel": "Lambda", + "tabitha": "Kalle", + "courtney": "Jördis", + "shelly": "Kordula", + "matt": "Wolfgang", + "mars": "Mars", + "jupiter": "Jupiter", + "saturn": "Saturn", + "zinzolin": "Violaceus", + "rood": "Rubius", + "xerosic": "Xeros", + "bryony": "Begonia", + "maxie": "Marc", "archie": "Adrian", "cyrus": "Zyrus", diff --git a/src/locales/en/dialogue.ts b/src/locales/en/dialogue.ts index 44693c38aa1..95382eeb4e0 100644 --- a/src/locales/en/dialogue.ts +++ b/src/locales/en/dialogue.ts @@ -383,6 +383,204 @@ export const PGMdialogue: DialogueTranslationEntries = { 3: "I think it's me that's seasick..." }, }, + + "archer": { + "encounter": { + 1: "Before you go any further, let's see how you far against us, Team Rocket!", + 2: "I have received reports that your skills are not insignificant. Let's see if they are true.", + 3: "I am Archer, an Admin of Team Rocket. And I do not go easy on enemies of our organization." + }, + "victory": { + 1: "What a blunder!", + 2: "With my current skills, I was not up to the task after all.", + 3: "F-forgive me, Giovanni... For me to be defeated by a mere trainer..." + }, + }, + "ariana": { + "encounter": { + 1: `Hold it right there! We can't someone on the loose." + $It's harmful to Team Rocket's pride, you see.`, + 2: `I don't know or care if what I'm doing is right or wrong... + $I just put my faith in Giovanni and do as I am told`, + 3: "Your trip ends here. I'm going to take you down!" + }, + "victory": { + 1: `Tch, you really are strong. It's too bad. + $If you were to join Team Rocket, you could become an Executive.`, + 2: "I... I'm shattered...", + 3: "Aaaieeeee! This can't be happening! I fought hard, but I still lost…" + }, + }, + "proton": { + "encounter": { + 1: "What do you want? If you interrupt our work, don't expect any mercy!", + 2: `What do we have here? I am often labeled as the scariest and cruelest guy in Team Rocket… + $I strongly urge you not to interfere with our business!`, + 3: "I am Proton, an Admin of Team Rocket. I am here to put an end to your meddling!" + }, + "victory": { + 1: "The fortress came down!", + 2: "You may have won this time… But all you did was make Team Rocket's wrath grow…", + 3: "I am defeated… But I will not forget this!" + }, + }, + + "petrel": { + "encounter": { + 1: `Muhahaha, we've been waiting for you. Me? You don't know who I am? It is me, Giovanni. + $The majestic Giovanni himself! Wahahaha! …Huh? I don't sound anything like Giovanni? + $I don't even look like Giovanni? How come? I've worked so hard to mimic him!`, + 2: "I am Petrel, an Admin of Team Rocket. I will not allow you to interfere with our plans!", + 3: "Rocket Executive Petrel will deal with this intruder!" + }, + "victory": { + 1: "OK, OK. I'll tell you where he is.", + 2: "I… I couldn't do a thing… Giovanni, please forgive me…", + 3: "No, I can't let this affect me. I have to inform the others…" + }, + }, + "tabitha": { + "encounter": { + 1: "Hehehe! So you've come all the way here! But you're too late!", + 2: `Hehehe... Got here already, did you? We underestimated you! But this is it! + $I'm a cut above the Grunts you've seen so far. I'm not stalling for time. + $I'm going to pulverize you!`, + 3: "I'm going to give you a little taste of pain! Resign yourself to it!" + }, + "victory": { + 1: `Hehehe! You might have beaten me, but you don't stand a chance against the Boss! + $If you get lost now, you won't have to face a sound whipping!`, + 2: "Hehehe... So, I lost, too...", + 3: "Ahya! How could this be? For an Admin like me to lose to some random trainer..." + }, + }, + "courtney": { + "encounter": { + 1: "The thing...The thing that you hold...That is what... That's what we of Team Magma seek...", + 2: "... Well then...Deleting...", + 3: "...Ha. ...Analyzing... ...Hah♪" + }, + "victory": { + 1: "... ...Change...the world.", + 2: `As anticipated. Unanticipated. You. Target lock...completed. + $Commencing...experiment. You. Forever. Aha... ♪`, + 3: "...Again? That's unanticipated. ...I knew it. You...are interesting! ...Haha. ♪" + }, + }, + "shelly": { + "encounter": { + 1: `Ahahahaha! You're going to meddle in Team Aqua's affairs? + $You're either absolutely fearless, simply ignorant, or both! + $You're so cute, you're disgusting! I'll put you down`, + 2: "What's this? Who's this spoiled brat?", + 3: "Cool your jets. Be patient. I'll crush you shortly." + }, + "victory": { + 1: `Ahahahaha! We got meddled with unexpectedly! We're out of options. + $We'll have to pull out. But this isn't the last you'll see of Team Aqua! + $We have other plans! Don't you forget it!`, + 2: "Ahhh?! Did I go too easy on you?!", + 3: `Uh. Are you telling me you've upped your game even more during the fight? + $You're a brat with a bright future… My Pokémon and I don't have any strength left to fight… + $Go on… Go and be destroyed by Archie.` + }, + }, + "matt": { + "encounter": { + 1: "Hoohahaha! What, you got a screw loose or something? Look at you, little Makuhita person!", + 2: "Oho! You! You're that funny kid!", + 3: "What are you doing here? Did you follow us?" + }, + "victory": { + 1: "All right then, until the Boss has time for you, I'll be your opponent!", + 2: `I can feel it! I can feel it, all right! The strength coming offa you! + $More! I still want more! But looks like we're outta time...`, + 3: "That was fun! I knew you'd show me a good time! I look forward to facing you again someday!" + }, + }, + "mars": { + "encounter": { + 1: "I'm Mars, one of Team Galactic's top Commanders.", + 2: "Team Galactic's vision for the future is unwavering. Opposition will be crushed without mercy!", + 3: "Feeling nervous? You should be!" + }, + "victory": { + 1: "This can't be happening! How did I lose?!", + 2: "You have some skill, I'll give you that.", + 3: "Defeated... This was a costly mistake." + } + }, + "jupiter": { + "encounter": { + 1: "Jupiter, Commander of Team Galactic, at your service.", + 2: "Resistance is futile. Team Galactic will prevail!", + 3: "You're trembling... scared already?" + }, + "victory": { + 1: "No way... I lost?!", + 2: "Impressive, you've got guts!", + 3: "Losing like this... How embarrassing." + } + }, + "saturn": { + "encounter": { + 1: "I am Saturn, Commander of Team Galactic.", + 2: "Our mission is absolute. Any hindrance will be obliterated!", + 3: "Is that fear I see in your eyes?" + }, + "victory": { + 1: "Impossible... Defeated by you?!", + 2: "You have proven yourself a worthy adversary.", + 3: "Bestowed in defeat... This is unacceptable." + }}, + "zinzolin": { + "encounter": { + 1: "You could become a threat to Team Plasma, so we will eliminate you here and now!", + 2: "Oh, for crying out loud... I didn't expect to have to battle in this freezing cold!", + 3: "You're an impressive Trainer to have made it this far. But it ends here." + }, + "victory": { + 1: "Ghetsis... I have failed you...", + 2: "It's bitter cold. I'm shivering. I'm suffering. Yet, I still stand victorious.", + 3: "Hmph. You're a smarter Trainer than I expected, but not smart enough." + } + }, + "rood": { + "encounter": { + 1: "You are a threat to Team Plasma. We cannot let you walk away from here and now!", + 2: "Oh, this icy wind... I never thought I'd have to fight here!", + 3: "You are a remarkable Trainer to have made it this far. But this is where it ends." + }, + "victory": { + 1: "Ghetsis... I have failed my mission...", + 2: "The cold is piercing. I'm shivering. I'm suffering. Yet, I have triumphed.", + 3: "Hm. You are a talented Trainer, but unfortunately not talented enough." + } + }, + "xerosic": { + "encounter": { + 1: "Ah ha ha! It would be my pleasure. Come on, little Trainer! Let's see what you've got!", + 2: "Hmm... You're more powerful than you look. I wonder how much energy there is inside you.", + 3: "I've been waiting for you! I need to do a little research on you! Come, let us begin!" + }, + "victory": { + 1: "Ah, you're quite strong. Oh yes—very strong, indeed.", + 2: "Ding-ding-ding! You did it! To the victor go the spoils!", + 3: "Wonderful! Amazing! You have tremendous skill and bravery!" + } + }, + "bryony": { + "encounter": { + 1: "I am Bryony, and it would be my pleasure to battle you. Show me what you've got.", + 2: "Impressive... You're more powerful than you appear. Let's see the true extent of your energy.", + 3: "I've anticipated your arrival. It's time for a little test. Shall we begin?" + }, + "victory": { + 1: "You're quite strong. Oh yes—very strong, indeed.", + 2: "Ding-ding-ding! You've done well. Victory is yours.", + 3: "Wonderful! Remarkable! Your skill and bravery are commendable." + } + }, "rocket_grunt": { "encounter": { 1: "Prepare for trouble!" @@ -391,18 +589,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "Team Rocket blasting off again!" }, }, - "rocket_admin": { - "encounter": { - 1: "Oh? You managed to get this far? You must be quite the trainer.", - 2: "That's quite enough of you playing hero, kid.", - 3: "I'll show you how scary an angry adult can be!" - }, - "victory": { - 1: "No! Forgive me Giovanni!", - 2: "How could this be?", - 3: "Urgh... You were too strong..." - }, - }, "magma_grunt": { "encounter": { 1: " If you get in the way of Team Magma, don’t expect any mercy!" @@ -411,18 +597,7 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "Huh? I lost?!" }, }, - "magma_admin": { - "encounter": { - 1: "Hehehe! So you've come all the way here! But you're too late!", - 2: "You're going to meddle in Team Magma's affairs? You're so cute you're disgusting! I'll put you down kiddy!", - 3: "I'm going to give you a little taste of pain! Resign yourself to it!" - }, - "victory": { - 1: "Hehehe... So I lost...", - 2: "You're disgustingly strong!", - 3: "Ahahaha! Ouch!" - }, - }, + "aqua_grunt": { "encounter": { 1: "No one who crosses Team Aqua gets any mercy, not even kids!" @@ -431,18 +606,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "You're kidding me!" }, }, - "aqua_admin": { - "encounter": { - 1: "I'm a cut above the grunts you've seen so far. I'm going to puvlerize you!", - 2: "Hahn? What's this? Who's this spoiled brat?", - 3: "What are you doing here? Did you follow us?" - }, - "victory": { - 1: "So I lost too...", - 2: "Ahhh?! Did I go too easy on you?!", - 3: "Wh-what was that?" - }, - }, "galactic_grunt": { "encounter": { 1: "Don't mess with Team Galactic!" @@ -451,18 +614,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "Shut down..." }, }, - "galactic_admin": { - "encounter": { - 1: "I'm one of Team Galactic's Commanders.", - 2: "Anything that opposes Team Galactic must be crushed! Even the very thought of opposition will not be tolerated!", - 3: "What's the matter? Don't tell me you're shaking?" - }, - "victory": { - 1: "This can't be?! I lost?! You... you uppity brat!", - 2: "You, my friend, are tough!", - 3: "Losing to some child... Being careless cost me too much." - }, - }, "plasma_grunt": { "encounter": { 1: "We won't tolerate people who have different ideas!" @@ -471,18 +622,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "Plasmaaaaaaaaa!" }, }, - "plasma_sage": { - "encounter": { - 1: "You could become a threat to Team Plasma, so we will eliminate you here!", - 2: "Oh, for crying out loud... I didn't expect to have to fight!", - 3: "You're an impressive Trainer to have made it this far." - }, - "victory": { - 1: "Ghetsis...", - 2: "It's bitter cold. I'm shivering. I'm suffering.", - 3: "Hmph. You're a smarter Trainer than I expected." - }, - }, "flare_grunt": { "encounter": { 1: "Fashion is most important to us!" @@ -491,18 +630,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "The future doesn't look bright for me." }, }, - "flare_admin": { - "encounter": { - 1: "Ah ha ha! It would be my pleasure. Come on, little Trainer! Let's see what you've got!", - 2: "Hmm... You're more powerful than you look. I wonder how much energy there is inside you.", - 3: "I've been waiting for you! I need to do a little research on you! Come, let us begin!" - }, - "victory": { - 1: "You're quite strong. Oh yes-very strong, indeed.", - 2: "Ding-ding-ding! Yup, you did it! To the victor goes the spoils!", - 3: "Wonderful! Amazing! You have tremendous skill and bravery!" - }, - }, "rocket_boss_giovanni_1": { "encounter": { 1: "So! I must say, I am impressed you got here!" diff --git a/src/locales/en/trainers.ts b/src/locales/en/trainers.ts index 00367865d14..a40fabaeacc 100644 --- a/src/locales/en/trainers.ts +++ b/src/locales/en/trainers.ts @@ -19,6 +19,19 @@ export const titles: SimpleTranslationEntries = { "galactic_boss": "Team Galactic Boss", "plasma_boss": "Team Plasma Boss", "flare_boss": "Team Flare Boss", + + "rocket_admin": "Team Rocket Admin", + "rocket_admin_female": "Team Rocket Admin", + "magma_admin": "Team Magma Admin", + "magma_admin_female": "Team Magma Admin", + "aqua_admin": "Team Aqua Admin", + "aqua_admin_female": "Team Aqua Admin", + "galactic_commander": "Team Galactic Commander", + "galactic_commander_female": "Team Galactic Commander", + "plasma_sage": "Team Plasma Sage", + "plasma_admin": "Team Plasma Admin", + "flare_admin": "Team Flare Admin", + "flare_admin_female": "Team Flare Admin", // Maybe if we add the evil teams we can add "Team Rocket" and "Team Aqua" etc. here as well as "Team Rocket Boss" and "Team Aqua Admin" etc. } as const; @@ -128,32 +141,21 @@ export const trainerClasses: SimpleTranslationEntries = { "rocket_grunt": "Rocket Grunt", "rocket_grunts": "Rocket Grunts", "rocket_grunt_female": "Rocket Grunt", - "rocket_admin": "Rocket Admin", - "rocket_admin_female": "Rocket Admin", "magma_grunt": "Magma Grunt", "magma_grunt_female": "Magma Grunt", "magma_grunts": "Magma Grunts", - "magma_admin": "Magma Admin", - "magma_admin_female": "Magma Admin", "aqua_grunt": "Aqua Grunt", "aqua_grunt_female": "Aqua Grunt", "aqua_grunts": "Aqua Grunts", - "aqua_admin": "Aqua Admin", - "aqua_admin_female": "Aqua Admin", "galactic_grunt": "Galactic Grunt", "galactic_grunt_female": "Galactic Grunt", "galactic_grunts": "Galactic Grunts", - "galactic_admin": "Galactic Admin", - "galactic_admin_female": "Galactic Admin", "plasma_grunt": "Plasma Grunt", "plasma_grunt_female": "Plasma Grunt", "plasma_grunts": "Plasma Grunts", - "plasma_sage": "Plasma Sage", "flare_grunt": "Flare Grunt", "flare_grunt_female": "Flare Grunt", "flare_grunts": "Flare Grunts", - "flare_admin": "Flare Admin", - "flare_admin_female": "Flare Admin", } as const; // Names of special trainers like gym leaders, elite four, and the champion @@ -282,6 +284,24 @@ export const trainerNames: SimpleTranslationEntries = { "leon": "Leon", "rival": "Finn", "rival_female": "Ivy", + + // Evil Team Admins + "archer": "Archer", + "ariana": "Ariana", + "proton": "Proton", + "petrel": "Petrel", + "tabitha": "Tabitha", + "courtney": "Courtney", + "shelly": "Shelly", + "matt": "Matt", + "mars": "Mars", + "jupiter": "Jupiter", + "saturn": "Saturn", + "zinzolin": "Zinzolin", + "rood": "Rood", + "xerosic": "Xerosic", + "bryony": "Bryony", + "maxie": "Maxie", "archie": "Archie", "cyrus": "Cyrus", diff --git a/src/locales/es/dialogue.ts b/src/locales/es/dialogue.ts index d19acc3ec0f..6908984b171 100644 --- a/src/locales/es/dialogue.ts +++ b/src/locales/es/dialogue.ts @@ -383,6 +383,203 @@ export const PGMdialogue: DialogueTranslationEntries = { 3: "Creo que soy yo quien está mareado..." }, }, + "archer": { + "encounter": { + 1: "Before you go any further, let's see how you far against us, Team Rocket!", + 2: "I have received reports that your skills are not insignificant. Let's see if they are true.", + 3: "I am Archer, an Admin of Team Rocket. And I do not go easy on enemies of our organization." + }, + "victory": { + 1: "What a blunder!", + 2: "With my current skills, I was not up to the task after all.", + 3: "F-forgive me, Giovanni... For me to be defeated by a mere trainer..." + }, + }, + "ariana": { + "encounter": { + 1: `Hold it right there! We can't someone on the loose." + $It's harmful to Team Rocket's pride, you see.`, + 2: `I don't know or care if what I'm doing is right or wrong... + $I just put my faith in Giovanni and do as I am told`, + 3: "Your trip ends here. I'm going to take you down!" + }, + "victory": { + 1: `Tch, you really are strong. It's too bad. + $If you were to join Team Rocket, you could become an Executive.`, + 2: "I... I'm shattered...", + 3: "Aaaieeeee! This can't be happening! I fought hard, but I still lost…" + }, + }, + "proton": { + "encounter": { + 1: "What do you want? If you interrupt our work, don't expect any mercy!", + 2: `What do we have here? I am often labeled as the scariest and cruelest guy in Team Rocket… + $I strongly urge you not to interfere with our business!`, + 3: "I am Proton, an Admin of Team Rocket. I am here to put an end to your meddling!" + }, + "victory": { + 1: "The fortress came down!", + 2: "You may have won this time… But all you did was make Team Rocket's wrath grow…", + 3: "I am defeated… But I will not forget this!" + }, + }, + + "petrel": { + "encounter": { + 1: `Muhahaha, we've been waiting for you. Me? You don't know who I am? It is me, Giovanni. + $The majestic Giovanni himself! Wahahaha! …Huh? I don't sound anything like Giovanni? + $I don't even look like Giovanni? How come? I've worked so hard to mimic him!`, + 2: "I am Petrel, an Admin of Team Rocket. I will not allow you to interfere with our plans!", + 3: "Rocket Executive Petrel will deal with this intruder!" + }, + "victory": { + 1: "OK, OK. I'll tell you where he is.", + 2: "I… I couldn't do a thing… Giovanni, please forgive me…", + 3: "No, I can't let this affect me. I have to inform the others…" + }, + }, + "tabitha": { + "encounter": { + 1: "Hehehe! So you've come all the way here! But you're too late!", + 2: `Hehehe... Got here already, did you? We underestimated you! But this is it! + $I'm a cut above the Grunts you've seen so far. I'm not stalling for time. + $I'm going to pulverize you!`, + 3: "I'm going to give you a little taste of pain! Resign yourself to it!" + }, + "victory": { + 1: `Hehehe! You might have beaten me, but you don't stand a chance against the Boss! + $If you get lost now, you won't have to face a sound whipping!`, + 2: "Hehehe... So, I lost, too...", + 3: "Ahya! How could this be? For an Admin like me to lose to some random trainer..." + }, + }, + "courtney": { + "encounter": { + 1: "The thing...The thing that you hold...That is what... That's what we of Team Magma seek...", + 2: "... Well then...Deleting...", + 3: "...Ha. ...Analyzing... ...Hah♪" + }, + "victory": { + 1: "... ...Change...the world.", + 2: `As anticipated. Unanticipated. You. Target lock...completed. + $Commencing...experiment. You. Forever. Aha... ♪`, + 3: "...Again? That's unanticipated. ...I knew it. You...are interesting! ...Haha. ♪" + }, + }, + "shelly": { + "encounter": { + 1: `Ahahahaha! You're going to meddle in Team Aqua's affairs? + $You're either absolutely fearless, simply ignorant, or both! + $You're so cute, you're disgusting! I'll put you down`, + 2: "What's this? Who's this spoiled brat?", + 3: "Cool your jets. Be patient. I'll crush you shortly." + }, + "victory": { + 1: `Ahahahaha! We got meddled with unexpectedly! We're out of options. + $We'll have to pull out. But this isn't the last you'll see of Team Aqua! + $We have other plans! Don't you forget it!`, + 2: "Ahhh?! Did I go too easy on you?!", + 3: `Uh. Are you telling me you've upped your game even more during the fight? + $You're a brat with a bright future… My Pokémon and I don't have any strength left to fight… + $Go on… Go and be destroyed by Archie.` + }, + }, + "matt": { + "encounter": { + 1: "Hoohahaha! What, you got a screw loose or something? Look at you, little Makuhita person!", + 2: "Oho! You! You're that funny kid!", + 3: "What are you doing here? Did you follow us?" + }, + "victory": { + 1: "All right then, until the Boss has time for you, I'll be your opponent!", + 2: `I can feel it! I can feel it, all right! The strength coming offa you! + $More! I still want more! But looks like we're outta time...`, + 3: "That was fun! I knew you'd show me a good time! I look forward to facing you again someday!" + }, + }, + "mars": { + "encounter": { + 1: "I'm Mars, one of Team Galactic's top Commanders.", + 2: "Team Galactic's vision for the future is unwavering. Opposition will be crushed without mercy!", + 3: "Feeling nervous? You should be!" + }, + "victory": { + 1: "This can't be happening! How did I lose?!", + 2: "You have some skill, I'll give you that.", + 3: "Defeated... This was a costly mistake." + } + }, + "jupiter": { + "encounter": { + 1: "Jupiter, Commander of Team Galactic, at your service.", + 2: "Resistance is futile. Team Galactic will prevail!", + 3: "You're trembling... scared already?" + }, + "victory": { + 1: "No way... I lost?!", + 2: "Impressive, you've got guts!", + 3: "Losing like this... How embarrassing." + } + }, + "saturn": { + "encounter": { + 1: "I am Saturn, Commander of Team Galactic.", + 2: "Our mission is absolute. Any hindrance will be obliterated!", + 3: "Is that fear I see in your eyes?" + }, + "victory": { + 1: "Impossible... Defeated by you?!", + 2: "You have proven yourself a worthy adversary.", + 3: "Bestowed in defeat... This is unacceptable." + }}, + "zinzolin": { + "encounter": { + 1: "You could become a threat to Team Plasma, so we will eliminate you here and now!", + 2: "Oh, for crying out loud... I didn't expect to have to battle in this freezing cold!", + 3: "You're an impressive Trainer to have made it this far. But it ends here." + }, + "victory": { + 1: "Ghetsis... I have failed you...", + 2: "It's bitter cold. I'm shivering. I'm suffering. Yet, I still stand victorious.", + 3: "Hmph. You're a smarter Trainer than I expected, but not smart enough." + } + }, + "rood": { + "encounter": { + 1: "You are a threat to Team Plasma. We cannot let you walk away from here and now!", + 2: "Oh, this icy wind... I never thought I'd have to fight here!", + 3: "You are a remarkable Trainer to have made it this far. But this is where it ends." + }, + "victory": { + 1: "Ghetsis... I have failed my mission...", + 2: "The cold is piercing. I'm shivering. I'm suffering. Yet, I have triumphed.", + 3: "Hm. You are a talented Trainer, but unfortunately not talented enough." + } + }, + "xerosic": { + "encounter": { + 1: "Ah ha ha! It would be my pleasure. Come on, little Trainer! Let's see what you've got!", + 2: "Hmm... You're more powerful than you look. I wonder how much energy there is inside you.", + 3: "I've been waiting for you! I need to do a little research on you! Come, let us begin!" + }, + "victory": { + 1: "Ah, you're quite strong. Oh yes—very strong, indeed.", + 2: "Ding-ding-ding! You did it! To the victor go the spoils!", + 3: "Wonderful! Amazing! You have tremendous skill and bravery!" + } + }, + "bryony": { + "encounter": { + 1: "I am Bryony, and it would be my pleasure to battle you. Show me what you've got.", + 2: "Impressive... You're more powerful than you appear. Let's see the true extent of your energy.", + 3: "I've anticipated your arrival. It's time for a little test. Shall we begin?" + }, + "victory": { + 1: "You're quite strong. Oh yes—very strong, indeed.", + 2: "Ding-ding-ding! You've done well. Victory is yours.", + 3: "Wonderful! Remarkable! Your skill and bravery are commendable." + } + }, "rocket_grunt": { "encounter": { 1: "¡Ríndete ahora, o prepárate para luchar!" diff --git a/src/locales/es/trainers.ts b/src/locales/es/trainers.ts index f881fc04f94..32f966c6359 100644 --- a/src/locales/es/trainers.ts +++ b/src/locales/es/trainers.ts @@ -13,6 +13,25 @@ export const titles: SimpleTranslationEntries = { "rival": "Rival", "professor": "Profesor", "frontier_brain": "As del Frente Batalla", + "rocket_boss": "Team Rocket Boss", + "magma_boss": "Team Magma Boss", + "aqua_boss": "Team Aqua Boss", + "galactic_boss": "Team Galactic Boss", + "plasma_boss": "Team Plasma Boss", + "flare_boss": "Team Flare Boss", + + "rocket_admin": "Team Rocket Admin", + "rocket_admin_female": "Team Rocket Admin", + "magma_admin": "Team Magma Admin", + "magma_admin_female": "Team Magma Admin", + "aqua_admin": "Team Aqua Admin", + "aqua_admin_female": "Team Aqua Admin", + "galactic_commander": "Team Galactic Commander", + "galactic_commander_female": "Team Galactic Commander", + "plasma_sage": "Team Plasma Sage", + "plasma_admin": "Team Plasma Admin", + "flare_admin": "Team Flare Admin", + "flare_admin_female": "Team Flare Admin", // Maybe if we add the evil teams we can add "Team Rocket" and "Team Aqua" etc. here as well as "Team Rocket Boss" and "Team Aqua Admin" etc. } as const; @@ -121,31 +140,21 @@ export const trainerClasses: SimpleTranslationEntries = { "rocket_grunt": "Rocket Grunt", "rocket_grunts": "Rocket Grunts", "rocket_grunt_female": "Rocket Grunt", - "rocket_admin": "Rocket Admin", - "rocket_admin_female": "Rocket Admin", "magma_grunt": "Magma Grunt", "magma_grunt_female": "Magma Grunt", "magma_grunts": "Magma Grunts", - "magma_admin": "Magma Admin", - "magma_admin_female": "Magma Admin", "aqua_grunt": "Aqua Grunt", "aqua_grunt_female": "Aqua Grunt", "aqua_grunts": "Aqua Grunts", - "aqua_admin": "Aqua Admin", - "aqua_admin_female": "Aqua Admin", "galactic_grunt": "Galactic Grunt", "galactic_grunt_female": "Galactic Grunt", "galactic_grunts": "Galactic Grunts", - "galactic_admin": "Galactic Admin", - "galactic_admin_female": "Galactic Admin", "plasma_grunt": "Plasma Grunt", "plasma_grunt_female": "Plasma Grunt", "plasma_grunts": "Plasma Grunts", "flare_grunt": "Flare Grunt", "flare_grunt_female": "Flare Grunt", "flare_grunts": "Flare Grunts", - "flare_admin": "Flare Admin", - "flare_admin_female": "Flare Admin", } as const; // Names of special trainers like gym leaders, elite four, and the champion @@ -275,6 +284,30 @@ export const trainerNames: SimpleTranslationEntries = { "rival": "Finn", "rival_female": "Ivy", + // Evil Team Admins + "archer": "Archer", + "ariana": "Ariana", + "proton": "Proton", + "petrel": "Petrel", + "tabitha": "Tabitha", + "courtney": "Courtney", + "shelly": "Shelly", + "matt": "Matt", + "mars": "Mars", + "jupiter": "Jupiter", + "saturn": "Saturn", + "zinzolin": "Zinzolin", + "rood": "Rood", + "xerosic": "Xerosic", + "bryony": "Bryony", + + "maxie": "Maxie", + "archie": "Archie", + "cyrus": "Cyrus", + "ghetsis": "Ghetsis", + "lysandre": "Lysandre", + + // Double Names "blue_red_double": "Azul y Rojo", "red_blue_double": "Rojo y Azul", diff --git a/src/locales/fr/dialogue.ts b/src/locales/fr/dialogue.ts index ac68aa6413b..ad70a01f210 100644 --- a/src/locales/fr/dialogue.ts +++ b/src/locales/fr/dialogue.ts @@ -2890,6 +2890,203 @@ export const PGFdialogue: DialogueTranslationEntries = { 3: "I think it's me that's seasick..." }, }, + "archer": { + "encounter": { + 1: "Before you go any further, let's see how you far against us, Team Rocket!", + 2: "I have received reports that your skills are not insignificant. Let's see if they are true.", + 3: "I am Archer, an Admin of Team Rocket. And I do not go easy on enemies of our organization." + }, + "victory": { + 1: "What a blunder!", + 2: "With my current skills, I was not up to the task after all.", + 3: "F-forgive me, Giovanni... For me to be defeated by a mere trainer..." + }, + }, + "ariana": { + "encounter": { + 1: `Hold it right there! We can't someone on the loose." + $It's harmful to Team Rocket's pride, you see.`, + 2: `I don't know or care if what I'm doing is right or wrong... + $I just put my faith in Giovanni and do as I am told`, + 3: "Your trip ends here. I'm going to take you down!" + }, + "victory": { + 1: `Tch, you really are strong. It's too bad. + $If you were to join Team Rocket, you could become an Executive.`, + 2: "I... I'm shattered...", + 3: "Aaaieeeee! This can't be happening! I fought hard, but I still lost…" + }, + }, + "proton": { + "encounter": { + 1: "What do you want? If you interrupt our work, don't expect any mercy!", + 2: `What do we have here? I am often labeled as the scariest and cruelest guy in Team Rocket… + $I strongly urge you not to interfere with our business!`, + 3: "I am Proton, an Admin of Team Rocket. I am here to put an end to your meddling!" + }, + "victory": { + 1: "The fortress came down!", + 2: "You may have won this time… But all you did was make Team Rocket's wrath grow…", + 3: "I am defeated… But I will not forget this!" + }, + }, + + "petrel": { + "encounter": { + 1: `Muhahaha, we've been waiting for you. Me? You don't know who I am? It is me, Giovanni. + $The majestic Giovanni himself! Wahahaha! …Huh? I don't sound anything like Giovanni? + $I don't even look like Giovanni? How come? I've worked so hard to mimic him!`, + 2: "I am Petrel, an Admin of Team Rocket. I will not allow you to interfere with our plans!", + 3: "Rocket Executive Petrel will deal with this intruder!" + }, + "victory": { + 1: "OK, OK. I'll tell you where he is.", + 2: "I… I couldn't do a thing… Giovanni, please forgive me…", + 3: "No, I can't let this affect me. I have to inform the others…" + }, + }, + "tabitha": { + "encounter": { + 1: "Hehehe! So you've come all the way here! But you're too late!", + 2: `Hehehe... Got here already, did you? We underestimated you! But this is it! + $I'm a cut above the Grunts you've seen so far. I'm not stalling for time. + $I'm going to pulverize you!`, + 3: "I'm going to give you a little taste of pain! Resign yourself to it!" + }, + "victory": { + 1: `Hehehe! You might have beaten me, but you don't stand a chance against the Boss! + $If you get lost now, you won't have to face a sound whipping!`, + 2: "Hehehe... So, I lost, too...", + 3: "Ahya! How could this be? For an Admin like me to lose to some random trainer..." + }, + }, + "courtney": { + "encounter": { + 1: "The thing...The thing that you hold...That is what... That's what we of Team Magma seek...", + 2: "... Well then...Deleting...", + 3: "...Ha. ...Analyzing... ...Hah♪" + }, + "victory": { + 1: "... ...Change...the world.", + 2: `As anticipated. Unanticipated. You. Target lock...completed. + $Commencing...experiment. You. Forever. Aha... ♪`, + 3: "...Again? That's unanticipated. ...I knew it. You...are interesting! ...Haha. ♪" + }, + }, + "shelly": { + "encounter": { + 1: `Ahahahaha! You're going to meddle in Team Aqua's affairs? + $You're either absolutely fearless, simply ignorant, or both! + $You're so cute, you're disgusting! I'll put you down`, + 2: "What's this? Who's this spoiled brat?", + 3: "Cool your jets. Be patient. I'll crush you shortly." + }, + "victory": { + 1: `Ahahahaha! We got meddled with unexpectedly! We're out of options. + $We'll have to pull out. But this isn't the last you'll see of Team Aqua! + $We have other plans! Don't you forget it!`, + 2: "Ahhh?! Did I go too easy on you?!", + 3: `Uh. Are you telling me you've upped your game even more during the fight? + $You're a brat with a bright future… My Pokémon and I don't have any strength left to fight… + $Go on… Go and be destroyed by Archie.` + }, + }, + "matt": { + "encounter": { + 1: "Hoohahaha! What, you got a screw loose or something? Look at you, little Makuhita person!", + 2: "Oho! You! You're that funny kid!", + 3: "What are you doing here? Did you follow us?" + }, + "victory": { + 1: "All right then, until the Boss has time for you, I'll be your opponent!", + 2: `I can feel it! I can feel it, all right! The strength coming offa you! + $More! I still want more! But looks like we're outta time...`, + 3: "That was fun! I knew you'd show me a good time! I look forward to facing you again someday!" + }, + }, + "mars": { + "encounter": { + 1: "I'm Mars, one of Team Galactic's top Commanders.", + 2: "Team Galactic's vision for the future is unwavering. Opposition will be crushed without mercy!", + 3: "Feeling nervous? You should be!" + }, + "victory": { + 1: "This can't be happening! How did I lose?!", + 2: "You have some skill, I'll give you that.", + 3: "Defeated... This was a costly mistake." + } + }, + "jupiter": { + "encounter": { + 1: "Jupiter, Commander of Team Galactic, at your service.", + 2: "Resistance is futile. Team Galactic will prevail!", + 3: "You're trembling... scared already?" + }, + "victory": { + 1: "No way... I lost?!", + 2: "Impressive, you've got guts!", + 3: "Losing like this... How embarrassing." + } + }, + "saturn": { + "encounter": { + 1: "I am Saturn, Commander of Team Galactic.", + 2: "Our mission is absolute. Any hindrance will be obliterated!", + 3: "Is that fear I see in your eyes?" + }, + "victory": { + 1: "Impossible... Defeated by you?!", + 2: "You have proven yourself a worthy adversary.", + 3: "Bestowed in defeat... This is unacceptable." + }}, + "zinzolin": { + "encounter": { + 1: "You could become a threat to Team Plasma, so we will eliminate you here and now!", + 2: "Oh, for crying out loud... I didn't expect to have to battle in this freezing cold!", + 3: "You're an impressive Trainer to have made it this far. But it ends here." + }, + "victory": { + 1: "Ghetsis... I have failed you...", + 2: "It's bitter cold. I'm shivering. I'm suffering. Yet, I still stand victorious.", + 3: "Hmph. You're a smarter Trainer than I expected, but not smart enough." + } + }, + "rood": { + "encounter": { + 1: "You are a threat to Team Plasma. We cannot let you walk away from here and now!", + 2: "Oh, this icy wind... I never thought I'd have to fight here!", + 3: "You are a remarkable Trainer to have made it this far. But this is where it ends." + }, + "victory": { + 1: "Ghetsis... I have failed my mission...", + 2: "The cold is piercing. I'm shivering. I'm suffering. Yet, I have triumphed.", + 3: "Hm. You are a talented Trainer, but unfortunately not talented enough." + } + }, + "xerosic": { + "encounter": { + 1: "Ah ha ha! It would be my pleasure. Come on, little Trainer! Let's see what you've got!", + 2: "Hmm... You're more powerful than you look. I wonder how much energy there is inside you.", + 3: "I've been waiting for you! I need to do a little research on you! Come, let us begin!" + }, + "victory": { + 1: "Ah, you're quite strong. Oh yes—very strong, indeed.", + 2: "Ding-ding-ding! You did it! To the victor go the spoils!", + 3: "Wonderful! Amazing! You have tremendous skill and bravery!" + } + }, + "bryony": { + "encounter": { + 1: "I am Bryony, and it would be my pleasure to battle you. Show me what you've got.", + 2: "Impressive... You're more powerful than you appear. Let's see the true extent of your energy.", + 3: "I've anticipated your arrival. It's time for a little test. Shall we begin?" + }, + "victory": { + 1: "You're quite strong. Oh yes—very strong, indeed.", + 2: "Ding-ding-ding! You've done well. Victory is yours.", + 3: "Wonderful! Remarkable! Your skill and bravery are commendable." + } + }, "rocket_grunt": { "encounter": { 1: "Nous sommes de retour !" @@ -2898,18 +3095,6 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Une fois de plus la Team Rocket s’envole vers d’autres cieux !" }, }, - "rocket_admin": { - "encounter": { - 1: "Oh? You managed to get this far? You must be quite the trainer.", - 2: "That's quite enough of you playing hero, kid.", - 3: "I'll show you how scary an angry adult can be!" - }, - "victory": { - 1: "No! Forgive me Giovanni!", - 2: "How could this be?", - 3: "Urgh... You were too strong..." - }, - }, "magma_grunt": { "encounter": { 1: "N’espère pas recevoir de la pitié si tu te mets sur le chemin de la Team Magma !" @@ -2918,18 +3103,6 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Je…?\nJ’ai perdu ?!" }, }, - "magma_admin": { - "encounter": { - 1: "Hehehe! So you've come all the way here! But you're too late!", - 2: "You're going to meddle in Team Magma's affairs? You're so cute you're disgusting! I'll put you down kiddy!", - 3: "I'm going to give you a little taste of pain! Resign yourself to it!" - }, - "victory": { - 1: "Hehehe... So I lost...", - 2: "You're disgustingly strong!", - 3: "Ahahaha! Ouch!" - }, - }, "aqua_grunt": { "encounter": { 1: "Aucune pitié si tu te mets sur le chemin de la Team Aqua, même pour une gamine !" @@ -2938,18 +3111,6 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Comment ça ?" }, }, - "aqua_admin": { - "encounter": { - 1: "I'm a cut above the grunts you've seen so far. I'm going to puvlerize you!", - 2: "Hahn? What's this? Who's this spoiled brat?", - 3: "What are you doing here? Did you follow us?" - }, - "victory": { - 1: "So I lost too...", - 2: "Ahhh?! Did I go too easy on you?!", - 3: "Wh-what was that?" - }, - }, "galactic_grunt": { "encounter": { 1: "Ne te mets pas en travers de la Team Galaxie !" @@ -2958,18 +3119,6 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Désactivation…" }, }, - "galactic_admin": { - "encounter": { - 1: "I'm one of Team Galactic's Commanders.", - 2: "Anything that opposes Team Galactic must be crushed! Even the very thought of opposition will not be tolerated!", - 3: "What's the matter? Don't tell me you're shaking?" - }, - "victory": { - 1: "This can't be?! I lost?! You... you uppity brat!", - 2: "You, my friend, are tough!", - 3: "Losing to some child... Being careless cost me too much." - }, - }, "plasma_grunt": { "encounter": { 1: "Pas de quatiers à ceux qui ne suivent pas notre idéal !" @@ -2978,18 +3127,6 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Plasmaaaaaaaaa !" }, }, - "plasma_sage": { - "encounter": { - 1: "You could become a threat to Team Plasma, so we will eliminate you here!", - 2: "Oh, for crying out loud... I didn't expect to have to fight!", - 3: "You're an impressive Trainer to have made it this far." - }, - "victory": { - 1: "Ghetsis...", - 2: "It's bitter cold. I'm shivering. I'm suffering.", - 3: "Hmph. You're a smarter Trainer than I expected." - }, - }, "flare_grunt": { "encounter": { 1: "Le style et le bon gout, il n’y a que ça qui compte !" @@ -2998,18 +3135,6 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Mon futur me semble guère radieux." }, }, - "flare_admin": { - "encounter": { - 1: "Ah ha ha! It would be my pleasure. Come on, little Trainer! Let's see what you've got!", - 2: "Hmm... You're more powerful than you look. I wonder how much energy there is inside you.", - 3: "I've been waiting for you! I need to do a little research on you! Come, let us begin!" - }, - "victory": { - 1: "You're quite strong. Oh yes-very strong, indeed.", - 2: "Ding-ding-ding! Yup, you did it! To the victor goes the spoils!", - 3: "Wonderful! Amazing! You have tremendous skill and bravery!" - }, - }, "rocket_boss_giovanni_1": { "encounter": { 1: "Bien. Je dois admettre que je suis impressionné de te voir ici !" diff --git a/src/locales/fr/trainers.ts b/src/locales/fr/trainers.ts index 84d49eba549..e52921a5546 100644 --- a/src/locales/fr/trainers.ts +++ b/src/locales/fr/trainers.ts @@ -19,6 +19,19 @@ export const titles: SimpleTranslationEntries = { "galactic_boss": "Leader de la Team Galaxie", "plasma_boss": "Leader de la Team Plasma", "flare_boss": "Leader de la Team Flare", + + "rocket_admin": "Admin Team Rocket", + "rocket_admin_female": "Admin Team Rocket", + "magma_admin": "Admin Team Magma", + "magma_admin_female": "Admin Team Magma", + "aqua_admin": "Admin Team Aqua", + "aqua_admin_female": "Admin Team Aqua", + "galactic_commander": "Admin Team Galaxie", + "galactic_commander_female": "Admin Team Galaxie", + "plasma_sage": "Sage Plasma", + "plasma_admin": "Admin Team Plasma", + "flare_admin": "Manager de la Team Flare", + "flare_admin_female": "Manageuse de la Team Flare", // Maybe if we add the evil teams we can add "Team Rocket" and "Team Aqua" etc. here as well as "Team Rocket Boss" and "Team Aqua Admin" etc. } as const; @@ -128,32 +141,21 @@ export const trainerClasses: SimpleTranslationEntries = { "rocket_grunt": "Sbire de la Team Rocket", "rocket_grunt_female": "Sbire de la Team Rocket", "rocket_grunts": "Sbires de la Team Rocket", - "rocket_admin": "Rocket Admin", - "rocket_admin_female": "Rocket Admin", "magma_grunt": "Sbire de la Team Magma", "magma_grunt_female": "Sbire de la Team Magma", "magma_grunts": "Sbires de la Team Magma", - "magma_admin": "Magma Admin", - "magma_admin_female": "Magma Admin", "aqua_grunt": "Sbire de la Team Aqua", "aqua_grunt_female": "Sbire de la Team Aqua", "aqua_grunts": "Sbires de la Team Aqua", - "aqua_admin": "Aqua Admin", - "aqua_admin_female": "Aqua Admin", "galactic_grunt": "Sbire de la Team Galaxie", "galactic_grunt_female": "Sbire de la Team Galaxie", "galactic_grunts": "Sbires de la Team Galaxie", - "galactic_admin": "Galactic Admin", - "galactic_admin_female": "Galactic Admin", "plasma_grunt": "Sbire de la Team Plasma", "plasma_grunt_female": "Sbire de la Team Plasma", "plasma_grunts": "Sbires de la Team Plasma", - "plasma_sage": "Plasma Sage", "flare_grunt": "Sbire de la Team Flare", "flare_grunt_female": "Sbire de la Team Flare", "flare_grunts": "Sbires de la Team Flare", - "flare_admin": "Manager de la Team Flare", - "flare_admin_female": "Manageuse de la Team Flare", } as const; // Names of special trainers like gym leaders, elite four, and the champion @@ -288,6 +290,25 @@ export const trainerNames: SimpleTranslationEntries = { "ghetsis": "Ghetis", "lysandre": "Lysandre", + // Evil Team Admins + "archer": "Amos", + "ariana": "Ariane", + "proton": "Lance", + "petrel": "Lambda", + "tabitha": "Kelvin", + "courtney": "Courtney", + "shelly": "Sarah", + "matt": "Matthieu", + "mars": "Mars", + "jupiter": "Jupiter", + "saturn": "Saturne", + "zinzolin": "Lilien", + "rood": "Carmine", + "xerosic": "Xanthin", + "bryony": "Brasénie", + + + // Double Names "blue_red_double": "Blue & Red", "red_blue_double": "Red & Blue", diff --git a/src/locales/it/dialogue.ts b/src/locales/it/dialogue.ts index 3861d530c01..d0c14dee824 100644 --- a/src/locales/it/dialogue.ts +++ b/src/locales/it/dialogue.ts @@ -383,6 +383,203 @@ export const PGMdialogue: DialogueTranslationEntries = { 3: "I think it's me that's seasick..." }, }, + "archer": { + "encounter": { + 1: "Before you go any further, let's see how you far against us, Team Rocket!", + 2: "I have received reports that your skills are not insignificant. Let's see if they are true.", + 3: "I am Archer, an Admin of Team Rocket. And I do not go easy on enemies of our organization." + }, + "victory": { + 1: "What a blunder!", + 2: "With my current skills, I was not up to the task after all.", + 3: "F-forgive me, Giovanni... For me to be defeated by a mere trainer..." + }, + }, + "ariana": { + "encounter": { + 1: `Hold it right there! We can't someone on the loose." + $It's harmful to Team Rocket's pride, you see.`, + 2: `I don't know or care if what I'm doing is right or wrong... + $I just put my faith in Giovanni and do as I am told`, + 3: "Your trip ends here. I'm going to take you down!" + }, + "victory": { + 1: `Tch, you really are strong. It's too bad. + $If you were to join Team Rocket, you could become an Executive.`, + 2: "I... I'm shattered...", + 3: "Aaaieeeee! This can't be happening! I fought hard, but I still lost…" + }, + }, + "proton": { + "encounter": { + 1: "What do you want? If you interrupt our work, don't expect any mercy!", + 2: `What do we have here? I am often labeled as the scariest and cruelest guy in Team Rocket… + $I strongly urge you not to interfere with our business!`, + 3: "I am Proton, an Admin of Team Rocket. I am here to put an end to your meddling!" + }, + "victory": { + 1: "The fortress came down!", + 2: "You may have won this time… But all you did was make Team Rocket's wrath grow…", + 3: "I am defeated… But I will not forget this!" + }, + }, + + "petrel": { + "encounter": { + 1: `Muhahaha, we've been waiting for you. Me? You don't know who I am? It is me, Giovanni. + $The majestic Giovanni himself! Wahahaha! …Huh? I don't sound anything like Giovanni? + $I don't even look like Giovanni? How come? I've worked so hard to mimic him!`, + 2: "I am Petrel, an Admin of Team Rocket. I will not allow you to interfere with our plans!", + 3: "Rocket Executive Petrel will deal with this intruder!" + }, + "victory": { + 1: "OK, OK. I'll tell you where he is.", + 2: "I… I couldn't do a thing… Giovanni, please forgive me…", + 3: "No, I can't let this affect me. I have to inform the others…" + }, + }, + "tabitha": { + "encounter": { + 1: "Hehehe! So you've come all the way here! But you're too late!", + 2: `Hehehe... Got here already, did you? We underestimated you! But this is it! + $I'm a cut above the Grunts you've seen so far. I'm not stalling for time. + $I'm going to pulverize you!`, + 3: "I'm going to give you a little taste of pain! Resign yourself to it!" + }, + "victory": { + 1: `Hehehe! You might have beaten me, but you don't stand a chance against the Boss! + $If you get lost now, you won't have to face a sound whipping!`, + 2: "Hehehe... So, I lost, too...", + 3: "Ahya! How could this be? For an Admin like me to lose to some random trainer..." + }, + }, + "courtney": { + "encounter": { + 1: "The thing...The thing that you hold...That is what... That's what we of Team Magma seek...", + 2: "... Well then...Deleting...", + 3: "...Ha. ...Analyzing... ...Hah♪" + }, + "victory": { + 1: "... ...Change...the world.", + 2: `As anticipated. Unanticipated. You. Target lock...completed. + $Commencing...experiment. You. Forever. Aha... ♪`, + 3: "...Again? That's unanticipated. ...I knew it. You...are interesting! ...Haha. ♪" + }, + }, + "shelly": { + "encounter": { + 1: `Ahahahaha! You're going to meddle in Team Aqua's affairs? + $You're either absolutely fearless, simply ignorant, or both! + $You're so cute, you're disgusting! I'll put you down`, + 2: "What's this? Who's this spoiled brat?", + 3: "Cool your jets. Be patient. I'll crush you shortly." + }, + "victory": { + 1: `Ahahahaha! We got meddled with unexpectedly! We're out of options. + $We'll have to pull out. But this isn't the last you'll see of Team Aqua! + $We have other plans! Don't you forget it!`, + 2: "Ahhh?! Did I go too easy on you?!", + 3: `Uh. Are you telling me you've upped your game even more during the fight? + $You're a brat with a bright future… My Pokémon and I don't have any strength left to fight… + $Go on… Go and be destroyed by Archie.` + }, + }, + "matt": { + "encounter": { + 1: "Hoohahaha! What, you got a screw loose or something? Look at you, little Makuhita person!", + 2: "Oho! You! You're that funny kid!", + 3: "What are you doing here? Did you follow us?" + }, + "victory": { + 1: "All right then, until the Boss has time for you, I'll be your opponent!", + 2: `I can feel it! I can feel it, all right! The strength coming offa you! + $More! I still want more! But looks like we're outta time...`, + 3: "That was fun! I knew you'd show me a good time! I look forward to facing you again someday!" + }, + }, + "mars": { + "encounter": { + 1: "I'm Mars, one of Team Galactic's top Commanders.", + 2: "Team Galactic's vision for the future is unwavering. Opposition will be crushed without mercy!", + 3: "Feeling nervous? You should be!" + }, + "victory": { + 1: "This can't be happening! How did I lose?!", + 2: "You have some skill, I'll give you that.", + 3: "Defeated... This was a costly mistake." + } + }, + "jupiter": { + "encounter": { + 1: "Jupiter, Commander of Team Galactic, at your service.", + 2: "Resistance is futile. Team Galactic will prevail!", + 3: "You're trembling... scared already?" + }, + "victory": { + 1: "No way... I lost?!", + 2: "Impressive, you've got guts!", + 3: "Losing like this... How embarrassing." + } + }, + "saturn": { + "encounter": { + 1: "I am Saturn, Commander of Team Galactic.", + 2: "Our mission is absolute. Any hindrance will be obliterated!", + 3: "Is that fear I see in your eyes?" + }, + "victory": { + 1: "Impossible... Defeated by you?!", + 2: "You have proven yourself a worthy adversary.", + 3: "Bestowed in defeat... This is unacceptable." + }}, + "zinzolin": { + "encounter": { + 1: "You could become a threat to Team Plasma, so we will eliminate you here and now!", + 2: "Oh, for crying out loud... I didn't expect to have to battle in this freezing cold!", + 3: "You're an impressive Trainer to have made it this far. But it ends here." + }, + "victory": { + 1: "Ghetsis... I have failed you...", + 2: "It's bitter cold. I'm shivering. I'm suffering. Yet, I still stand victorious.", + 3: "Hmph. You're a smarter Trainer than I expected, but not smart enough." + } + }, + "rood": { + "encounter": { + 1: "You are a threat to Team Plasma. We cannot let you walk away from here and now!", + 2: "Oh, this icy wind... I never thought I'd have to fight here!", + 3: "You are a remarkable Trainer to have made it this far. But this is where it ends." + }, + "victory": { + 1: "Ghetsis... I have failed my mission...", + 2: "The cold is piercing. I'm shivering. I'm suffering. Yet, I have triumphed.", + 3: "Hm. You are a talented Trainer, but unfortunately not talented enough." + } + }, + "xerosic": { + "encounter": { + 1: "Ah ha ha! It would be my pleasure. Come on, little Trainer! Let's see what you've got!", + 2: "Hmm... You're more powerful than you look. I wonder how much energy there is inside you.", + 3: "I've been waiting for you! I need to do a little research on you! Come, let us begin!" + }, + "victory": { + 1: "Ah, you're quite strong. Oh yes—very strong, indeed.", + 2: "Ding-ding-ding! You did it! To the victor go the spoils!", + 3: "Wonderful! Amazing! You have tremendous skill and bravery!" + } + }, + "bryony": { + "encounter": { + 1: "I am Bryony, and it would be my pleasure to battle you. Show me what you've got.", + 2: "Impressive... You're more powerful than you appear. Let's see the true extent of your energy.", + 3: "I've anticipated your arrival. It's time for a little test. Shall we begin?" + }, + "victory": { + 1: "You're quite strong. Oh yes—very strong, indeed.", + 2: "Ding-ding-ding! You've done well. Victory is yours.", + 3: "Wonderful! Remarkable! Your skill and bravery are commendable." + } + }, "rocket_grunt": { "encounter": { 1: "Prepare for trouble!" @@ -391,18 +588,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "Team Rocket blasting off again!" }, }, - "rocket_admin": { - "encounter": { - 1: "Oh? You managed to get this far? You must be quite the trainer.", - 2: "That's quite enough of you playing hero, kid.", - 3: "I'll show you how scary an angry adult can be!" - }, - "victory": { - 1: "No! Forgive me Giovanni!", - 2: "How could this be?", - 3: "Urgh... You were too strong..." - }, - }, "magma_grunt": { "encounter": { 1: " If you get in the way of Team Magma, don’t expect any mercy!" @@ -411,18 +596,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "Huh? I lost?!" }, }, - "magma_admin": { - "encounter": { - 1: "Hehehe! So you've come all the way here! But you're too late!", - 2: "You're going to meddle in Team Magma's affairs? You're so cute you're disgusting! I'll put you down kiddy!", - 3: "I'm going to give you a little taste of pain! Resign yourself to it!" - }, - "victory": { - 1: "Hehehe... So I lost...", - 2: "You're disgustingly strong!", - 3: "Ahahaha! Ouch!" - }, - }, "aqua_grunt": { "encounter": { 1: "No one who crosses Team Aqua gets any mercy, not even kids!" @@ -431,18 +604,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "You're kidding me!" }, }, - "aqua_admin": { - "encounter": { - 1: "I'm a cut above the grunts you've seen so far. I'm going to puvlerize you!", - 2: "Hahn? What's this? Who's this spoiled brat?", - 3: "What are you doing here? Did you follow us?" - }, - "victory": { - 1: "So I lost too...", - 2: "Ahhh?! Did I go too easy on you?!", - 3: "Wh-what was that?" - }, - }, "galactic_grunt": { "encounter": { 1: "Don't mess with Team Galactic!" @@ -451,18 +612,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "Shut down..." }, }, - "galactic_admin": { - "encounter": { - 1: "I'm one of Team Galactic's Commanders.", - 2: "Anything that opposes Team Galactic must be crushed! Even the very thought of opposition will not be tolerated!", - 3: "What's the matter? Don't tell me you're shaking?" - }, - "victory": { - 1: "This can't be?! I lost?! You... you uppity brat!", - 2: "You, my friend, are tough!", - 3: "Losing to some child... Being careless cost me too much." - }, - }, "plasma_grunt": { "encounter": { 1: "We won't tolerate people who have different ideas!" @@ -471,18 +620,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "Plasmaaaaaaaaa!" }, }, - "plasma_sage": { - "encounter": { - 1: "You could become a threat to Team Plasma, so we will eliminate you here!", - 2: "Oh, for crying out loud... I didn't expect to have to fight!", - 3: "You're an impressive Trainer to have made it this far." - }, - "victory": { - 1: "Ghetsis...", - 2: "It's bitter cold. I'm shivering. I'm suffering.", - 3: "Hmph. You're a smarter Trainer than I expected." - }, - }, "flare_grunt": { "encounter": { 1: "Fashion is most important to us!" @@ -491,18 +628,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "The future doesn't look bright for me." }, }, - "flare_admin": { - "encounter": { - 1: "Ah ha ha! It would be my pleasure. Come on, little Trainer! Let's see what you've got!", - 2: "Hmm... You're more powerful than you look. I wonder how much energy there is inside you.", - 3: "I've been waiting for you! I need to do a little research on you! Come, let us begin!" - }, - "victory": { - 1: "You're quite strong. Oh yes-very strong, indeed.", - 2: "Ding-ding-ding! Yup, you did it! To the victor goes the spoils!", - 3: "Wonderful! Amazing! You have tremendous skill and bravery!" - }, - }, "rocket_boss_giovanni_1": { "encounter": { 1: "So! I must say, I am impressed you got here!" diff --git a/src/locales/it/trainers.ts b/src/locales/it/trainers.ts index dde79d694ca..931d11ae216 100644 --- a/src/locales/it/trainers.ts +++ b/src/locales/it/trainers.ts @@ -13,6 +13,25 @@ export const titles: SimpleTranslationEntries = { "rival": "Rivale", "professor": "Professore", "frontier_brain": "Asso lotta", + "rocket_boss": "Team Rocket Boss", + "magma_boss": "Team Magma Boss", + "aqua_boss": "Team Aqua Boss", + "galactic_boss": "Team Galactic Boss", + "plasma_boss": "Team Plasma Boss", + "flare_boss": "Team Flare Boss", + + "rocket_admin": "Team Rocket Admin", + "rocket_admin_female": "Team Rocket Admin", + "magma_admin": "Team Magma Admin", + "magma_admin_female": "Team Magma Admin", + "aqua_admin": "Team Aqua Admin", + "aqua_admin_female": "Team Aqua Admin", + "galactic_commander": "Team Galactic Commander", + "galactic_commander_female": "Team Galactic Commander", + "plasma_sage": "Team Plasma Sage", + "plasma_admin": "Team Plasma Admin", + "flare_admin": "Team Flare Admin", + "flare_admin_female": "Team Flare Admin", // Maybe if we add the evil teams we can add "Team Rocket" and "Team Aqua" etc. here as well as "Team Rocket Boss" and "Team Aqua Admin" etc. } as const; @@ -122,31 +141,22 @@ export const trainerClasses: SimpleTranslationEntries = { "rocket_grunt": "Recluta Team Rocket", "rocket_grunt_female": "Recluta Team Rocket", "rocket_grunts": "Reclute Team Rocket", - "rocket_admin": "Rocket Admin", - "rocket_admin_female": "Rocket Admin", "magma_grunt": "Recluta Team Magma", "magma_grunt_female": "Recluta Team Magma", "magma_grunts": "Reclute Team Magma", - "magma_admin": "Magma Admin", - "magma_admin_female": "Magma Admin", "aqua_grunt": "Recluta Team Idro", "aqua_grunt_female": "Recluta Team Idro", "aqua_grunts": "Recluta Team Idro", - "aqua_admin": "Aqua Admin", - "aqua_admin_female": "Aqua Admin", "galactic_grunt": "Recluta Team Galassia", "galactic_grunt_female": "Recluta Team Galassia", "galactic_grunts": "Reclute Team Galassia", - "galactic_admin": "Galactic Admin", - "galactic_admin_female": "Galactic Admin", "plasma_grunt": "Seguace Plasma", "plasma_grunt_female": "Seguace Plasma", "plasma_grunts": "Seguaci Plasma", "flare_grunt": "Recluta Team Flare", "flare_grunt_female": "Recluta Team Flare", "flare_grunts": "Reclute Team Flare", - "flare_admin": "Flare Admin", - "flare_admin_female": "Flare Admin", + } as const; // Names of special trainers like gym leaders, elite four, and the champion @@ -276,6 +286,28 @@ export const trainerNames: SimpleTranslationEntries = { "rival": "Finn", "rival_female": "Ivy", + // Evil Team Admins + "archer": "Archer", + "ariana": "Ariana", + "proton": "Proton", + "petrel": "Petrel", + "tabitha": "Tabitha", + "courtney": "Courtney", + "shelly": "Shelly", + "matt": "Matt", + "mars": "Mars", + "jupiter": "Jupiter", + "saturn": "Saturn", + "zinzolin": "Zinzolin", + "rood": "Rood", + "xerosic": "Xerosic", + "bryony": "Bryony", + + "maxie": "Maxie", + "archie": "Archie", + "cyrus": "Cyrus", + "ghetsis": "Ghetsis", + "lysandre": "Lysandre", // Double Names "blue_red_double": "Blu & Rosso", diff --git a/src/locales/ja/dialogue.ts b/src/locales/ja/dialogue.ts index 44693c38aa1..64e4028a912 100644 --- a/src/locales/ja/dialogue.ts +++ b/src/locales/ja/dialogue.ts @@ -383,6 +383,204 @@ export const PGMdialogue: DialogueTranslationEntries = { 3: "I think it's me that's seasick..." }, }, + + "archer": { + "encounter": { + 1: "Before you go any further, let's see how you far against us, Team Rocket!", + 2: "I have received reports that your skills are not insignificant. Let's see if they are true.", + 3: "I am Archer, an Admin of Team Rocket. And I do not go easy on enemies of our organization." + }, + "victory": { + 1: "What a blunder!", + 2: "With my current skills, I was not up to the task after all.", + 3: "F-forgive me, Giovanni... For me to be defeated by a mere trainer..." + }, + }, + "ariana": { + "encounter": { + 1: `Hold it right there! We can't someone on the loose." + $It's harmful to Team Rocket's pride, you see.`, + 2: `I don't know or care if what I'm doing is right or wrong... + $I just put my faith in Giovanni and do as I am told`, + 3: "Your trip ends here. I'm going to take you down!" + }, + "victory": { + 1: `Tch, you really are strong. It's too bad. + $If you were to join Team Rocket, you could become an Executive.`, + 2: "I... I'm shattered...", + 3: "Aaaieeeee! This can't be happening! I fought hard, but I still lost…" + }, + }, + "proton": { + "encounter": { + 1: "What do you want? If you interrupt our work, don't expect any mercy!", + 2: `What do we have here? I am often labeled as the scariest and cruelest guy in Team Rocket… + $I strongly urge you not to interfere with our business!`, + 3: "I am Proton, an Admin of Team Rocket. I am here to put an end to your meddling!" + }, + "victory": { + 1: "The fortress came down!", + 2: "You may have won this time… But all you did was make Team Rocket's wrath grow…", + 3: "I am defeated… But I will not forget this!" + }, + }, + + "petrel": { + "encounter": { + 1: `Muhahaha, we've been waiting for you. Me? You don't know who I am? It is me, Giovanni. + $The majestic Giovanni himself! Wahahaha! …Huh? I don't sound anything like Giovanni? + $I don't even look like Giovanni? How come? I've worked so hard to mimic him!`, + 2: "I am Petrel, an Admin of Team Rocket. I will not allow you to interfere with our plans!", + 3: "Rocket Executive Petrel will deal with this intruder!" + }, + "victory": { + 1: "OK, OK. I'll tell you where he is.", + 2: "I… I couldn't do a thing… Giovanni, please forgive me…", + 3: "No, I can't let this affect me. I have to inform the others…" + }, + }, + "tabitha": { + "encounter": { + 1: "Hehehe! So you've come all the way here! But you're too late!", + 2: `Hehehe... Got here already, did you? We underestimated you! But this is it! + $I'm a cut above the Grunts you've seen so far. I'm not stalling for time. + $I'm going to pulverize you!`, + 3: "I'm going to give you a little taste of pain! Resign yourself to it!" + }, + "victory": { + 1: `Hehehe! You might have beaten me, but you don't stand a chance against the Boss! + $If you get lost now, you won't have to face a sound whipping!`, + 2: "Hehehe... So, I lost, too...", + 3: "Ahya! How could this be? For an Admin like me to lose to some random trainer..." + }, + }, + "courtney": { + "encounter": { + 1: "The thing...The thing that you hold...That is what... That's what we of Team Magma seek...", + 2: "... Well then...Deleting...", + 3: "...Ha. ...Analyzing... ...Hah♪" + }, + "victory": { + 1: "... ...Change...the world.", + 2: `As anticipated. Unanticipated. You. Target lock...completed. + $Commencing...experiment. You. Forever. Aha... ♪`, + 3: "...Again? That's unanticipated. ...I knew it. You...are interesting! ...Haha. ♪" + }, + }, + "shelly": { + "encounter": { + 1: `Ahahahaha! You're going to meddle in Team Aqua's affairs? + $You're either absolutely fearless, simply ignorant, or both! + $You're so cute, you're disgusting! I'll put you down`, + 2: "What's this? Who's this spoiled brat?", + 3: "Cool your jets. Be patient. I'll crush you shortly." + }, + "victory": { + 1: `Ahahahaha! We got meddled with unexpectedly! We're out of options. + $We'll have to pull out. But this isn't the last you'll see of Team Aqua! + $We have other plans! Don't you forget it!`, + 2: "Ahhh?! Did I go too easy on you?!", + 3: `Uh. Are you telling me you've upped your game even more during the fight? + $You're a brat with a bright future… My Pokémon and I don't have any strength left to fight… + $Go on… Go and be destroyed by Archie.` + }, + }, + "matt": { + "encounter": { + 1: "Hoohahaha! What, you got a screw loose or something? Look at you, little Makuhita person!", + 2: "Oho! You! You're that funny kid!", + 3: "What are you doing here? Did you follow us?" + }, + "victory": { + 1: "All right then, until the Boss has time for you, I'll be your opponent!", + 2: `I can feel it! I can feel it, all right! The strength coming offa you! + $More! I still want more! But looks like we're outta time...`, + 3: "That was fun! I knew you'd show me a good time! I look forward to facing you again someday!" + }, + }, + "mars": { + "encounter": { + 1: "I'm Mars, one of Team Galactic's top Commanders.", + 2: "Team Galactic's vision for the future is unwavering. Opposition will be crushed without mercy!", + 3: "Feeling nervous? You should be!" + }, + "victory": { + 1: "This can't be happening! How did I lose?!", + 2: "You have some skill, I'll give you that.", + 3: "Defeated... This was a costly mistake." + } + }, + "jupiter": { + "encounter": { + 1: "Jupiter, Commander of Team Galactic, at your service.", + 2: "Resistance is futile. Team Galactic will prevail!", + 3: "You're trembling... scared already?" + }, + "victory": { + 1: "No way... I lost?!", + 2: "Impressive, you've got guts!", + 3: "Losing like this... How embarrassing." + } + }, + "saturn": { + "encounter": { + 1: "I am Saturn, Commander of Team Galactic.", + 2: "Our mission is absolute. Any hindrance will be obliterated!", + 3: "Is that fear I see in your eyes?" + }, + "victory": { + 1: "Impossible... Defeated by you?!", + 2: "You have proven yourself a worthy adversary.", + 3: "Bestowed in defeat... This is unacceptable." + }}, + "zinzolin": { + "encounter": { + 1: "You could become a threat to Team Plasma, so we will eliminate you here and now!", + 2: "Oh, for crying out loud... I didn't expect to have to battle in this freezing cold!", + 3: "You're an impressive Trainer to have made it this far. But it ends here." + }, + "victory": { + 1: "Ghetsis... I have failed you...", + 2: "It's bitter cold. I'm shivering. I'm suffering. Yet, I still stand victorious.", + 3: "Hmph. You're a smarter Trainer than I expected, but not smart enough." + } + }, + "rood": { + "encounter": { + 1: "You are a threat to Team Plasma. We cannot let you walk away from here and now!", + 2: "Oh, this icy wind... I never thought I'd have to fight here!", + 3: "You are a remarkable Trainer to have made it this far. But this is where it ends." + }, + "victory": { + 1: "Ghetsis... I have failed my mission...", + 2: "The cold is piercing. I'm shivering. I'm suffering. Yet, I have triumphed.", + 3: "Hm. You are a talented Trainer, but unfortunately not talented enough." + } + }, + "xerosic": { + "encounter": { + 1: "Ah ha ha! It would be my pleasure. Come on, little Trainer! Let's see what you've got!", + 2: "Hmm... You're more powerful than you look. I wonder how much energy there is inside you.", + 3: "I've been waiting for you! I need to do a little research on you! Come, let us begin!" + }, + "victory": { + 1: "Ah, you're quite strong. Oh yes—very strong, indeed.", + 2: "Ding-ding-ding! You did it! To the victor go the spoils!", + 3: "Wonderful! Amazing! You have tremendous skill and bravery!" + } + }, + "bryony": { + "encounter": { + 1: "I am Bryony, and it would be my pleasure to battle you. Show me what you've got.", + 2: "Impressive... You're more powerful than you appear. Let's see the true extent of your energy.", + 3: "I've anticipated your arrival. It's time for a little test. Shall we begin?" + }, + "victory": { + 1: "You're quite strong. Oh yes—very strong, indeed.", + 2: "Ding-ding-ding! You've done well. Victory is yours.", + 3: "Wonderful! Remarkable! Your skill and bravery are commendable." + } + }, "rocket_grunt": { "encounter": { 1: "Prepare for trouble!" @@ -391,18 +589,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "Team Rocket blasting off again!" }, }, - "rocket_admin": { - "encounter": { - 1: "Oh? You managed to get this far? You must be quite the trainer.", - 2: "That's quite enough of you playing hero, kid.", - 3: "I'll show you how scary an angry adult can be!" - }, - "victory": { - 1: "No! Forgive me Giovanni!", - 2: "How could this be?", - 3: "Urgh... You were too strong..." - }, - }, "magma_grunt": { "encounter": { 1: " If you get in the way of Team Magma, don’t expect any mercy!" @@ -411,18 +597,7 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "Huh? I lost?!" }, }, - "magma_admin": { - "encounter": { - 1: "Hehehe! So you've come all the way here! But you're too late!", - 2: "You're going to meddle in Team Magma's affairs? You're so cute you're disgusting! I'll put you down kiddy!", - 3: "I'm going to give you a little taste of pain! Resign yourself to it!" - }, - "victory": { - 1: "Hehehe... So I lost...", - 2: "You're disgustingly strong!", - 3: "Ahahaha! Ouch!" - }, - }, + "aqua_grunt": { "encounter": { 1: "No one who crosses Team Aqua gets any mercy, not even kids!" @@ -431,18 +606,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "You're kidding me!" }, }, - "aqua_admin": { - "encounter": { - 1: "I'm a cut above the grunts you've seen so far. I'm going to puvlerize you!", - 2: "Hahn? What's this? Who's this spoiled brat?", - 3: "What are you doing here? Did you follow us?" - }, - "victory": { - 1: "So I lost too...", - 2: "Ahhh?! Did I go too easy on you?!", - 3: "Wh-what was that?" - }, - }, "galactic_grunt": { "encounter": { 1: "Don't mess with Team Galactic!" @@ -451,18 +614,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "Shut down..." }, }, - "galactic_admin": { - "encounter": { - 1: "I'm one of Team Galactic's Commanders.", - 2: "Anything that opposes Team Galactic must be crushed! Even the very thought of opposition will not be tolerated!", - 3: "What's the matter? Don't tell me you're shaking?" - }, - "victory": { - 1: "This can't be?! I lost?! You... you uppity brat!", - 2: "You, my friend, are tough!", - 3: "Losing to some child... Being careless cost me too much." - }, - }, "plasma_grunt": { "encounter": { 1: "We won't tolerate people who have different ideas!" @@ -471,18 +622,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "Plasmaaaaaaaaa!" }, }, - "plasma_sage": { - "encounter": { - 1: "You could become a threat to Team Plasma, so we will eliminate you here!", - 2: "Oh, for crying out loud... I didn't expect to have to fight!", - 3: "You're an impressive Trainer to have made it this far." - }, - "victory": { - 1: "Ghetsis...", - 2: "It's bitter cold. I'm shivering. I'm suffering.", - 3: "Hmph. You're a smarter Trainer than I expected." - }, - }, "flare_grunt": { "encounter": { 1: "Fashion is most important to us!" @@ -491,18 +630,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "The future doesn't look bright for me." }, }, - "flare_admin": { - "encounter": { - 1: "Ah ha ha! It would be my pleasure. Come on, little Trainer! Let's see what you've got!", - 2: "Hmm... You're more powerful than you look. I wonder how much energy there is inside you.", - 3: "I've been waiting for you! I need to do a little research on you! Come, let us begin!" - }, - "victory": { - 1: "You're quite strong. Oh yes-very strong, indeed.", - 2: "Ding-ding-ding! Yup, you did it! To the victor goes the spoils!", - 3: "Wonderful! Amazing! You have tremendous skill and bravery!" - }, - }, "rocket_boss_giovanni_1": { "encounter": { 1: "So! I must say, I am impressed you got here!" @@ -2605,7 +2732,7 @@ export const PGFbattleSpecDialogue: SimpleTranslationEntries = PGMbattleSpecDial // Dialogue that does not fit into any other category (e.g. tutorial messages, or the end of the game). For when the player character is male export const PGMmiscDialogue: SimpleTranslationEntries = { "ending": - `@c{smile}Oh? You won?@d{96} @c{smile_eclosed}I guess I should've known.\nBut, you're back now. + `@c{smile}Oh? You won?@d{96} @c{smile_eclosed}I guess I should've known.\nBut, you're back now. $@c{smile}It's over.@d{64} You ended the loop. $@c{serious_smile_fists}You fulfilled your dream too, didn't you?\nYou didn't lose even once. $@c{neutral}I'm the only one who'll remember what you did.@d{96}\nI guess that's okay, isn't it? @@ -2613,7 +2740,7 @@ export const PGMmiscDialogue: SimpleTranslationEntries = { $@c{smile_eclosed}Anyway, I've had about enough of this place, haven't you? Let's head home. $@c{serious_smile_fists}Maybe when we get back, we can have another battle?\nIf you're up to it.`, "ending_female": - `@c{shock}You're back?@d{32} Does that mean…@d{96} you won?!\n@c{smile_ehalf}I should have known you had it in you. + `@c{shock}You're back?@d{32} Does that mean…@d{96} you won?!\n@c{smile_ehalf}I should have known you had it in you. $@c{smile_eclosed}Of course… I always had that feeling.\n@c{smile}It's over now, right? You ended the loop. $@c{smile_ehalf}You fulfilled your dream too, didn't you?\nYou didn't lose even once. $I'll be the only one to remember what you did.\n@c{angry_mopen}I'll try not to forget! diff --git a/src/locales/ja/trainers.ts b/src/locales/ja/trainers.ts index 9b06f3bdf7f..a40fabaeacc 100644 --- a/src/locales/ja/trainers.ts +++ b/src/locales/ja/trainers.ts @@ -1,4 +1,4 @@ -import { SimpleTranslationEntries } from "#app/interfaces/locales"; +import {SimpleTranslationEntries} from "#app/interfaces/locales"; // Titles of special trainers like gym leaders, elite four, and the champion export const titles: SimpleTranslationEntries = { @@ -19,6 +19,19 @@ export const titles: SimpleTranslationEntries = { "galactic_boss": "Team Galactic Boss", "plasma_boss": "Team Plasma Boss", "flare_boss": "Team Flare Boss", + + "rocket_admin": "Team Rocket Admin", + "rocket_admin_female": "Team Rocket Admin", + "magma_admin": "Team Magma Admin", + "magma_admin_female": "Team Magma Admin", + "aqua_admin": "Team Aqua Admin", + "aqua_admin_female": "Team Aqua Admin", + "galactic_commander": "Team Galactic Commander", + "galactic_commander_female": "Team Galactic Commander", + "plasma_sage": "Team Plasma Sage", + "plasma_admin": "Team Plasma Admin", + "flare_admin": "Team Flare Admin", + "flare_admin_female": "Team Flare Admin", // Maybe if we add the evil teams we can add "Team Rocket" and "Team Aqua" etc. here as well as "Team Rocket Boss" and "Team Aqua Admin" etc. } as const; @@ -128,32 +141,21 @@ export const trainerClasses: SimpleTranslationEntries = { "rocket_grunt": "Rocket Grunt", "rocket_grunts": "Rocket Grunts", "rocket_grunt_female": "Rocket Grunt", - "rocket_admin": "Rocket Admin", - "rocket_admin_female": "Rocket Admin", "magma_grunt": "Magma Grunt", "magma_grunt_female": "Magma Grunt", "magma_grunts": "Magma Grunts", - "magma_admin": "Magma Admin", - "magma_admin_female": "Magma Admin", "aqua_grunt": "Aqua Grunt", "aqua_grunt_female": "Aqua Grunt", "aqua_grunts": "Aqua Grunts", - "aqua_admin": "Aqua Admin", - "aqua_admin_female": "Aqua Admin", "galactic_grunt": "Galactic Grunt", "galactic_grunt_female": "Galactic Grunt", "galactic_grunts": "Galactic Grunts", - "galactic_admin": "Galactic Admin", - "galactic_admin_female": "Galactic Admin", "plasma_grunt": "Plasma Grunt", "plasma_grunt_female": "Plasma Grunt", "plasma_grunts": "Plasma Grunts", - "plasma_sage": "Plasma Sage", "flare_grunt": "Flare Grunt", "flare_grunt_female": "Flare Grunt", "flare_grunts": "Flare Grunts", - "flare_admin": "Flare Admin", - "flare_admin_female": "Flare Admin", } as const; // Names of special trainers like gym leaders, elite four, and the champion @@ -282,6 +284,24 @@ export const trainerNames: SimpleTranslationEntries = { "leon": "Leon", "rival": "Finn", "rival_female": "Ivy", + + // Evil Team Admins + "archer": "Archer", + "ariana": "Ariana", + "proton": "Proton", + "petrel": "Petrel", + "tabitha": "Tabitha", + "courtney": "Courtney", + "shelly": "Shelly", + "matt": "Matt", + "mars": "Mars", + "jupiter": "Jupiter", + "saturn": "Saturn", + "zinzolin": "Zinzolin", + "rood": "Rood", + "xerosic": "Xerosic", + "bryony": "Bryony", + "maxie": "Maxie", "archie": "Archie", "cyrus": "Cyrus", diff --git a/src/locales/ko/dialogue.ts b/src/locales/ko/dialogue.ts index 8e7f09ff373..e032ec14844 100644 --- a/src/locales/ko/dialogue.ts +++ b/src/locales/ko/dialogue.ts @@ -383,6 +383,203 @@ export const PGMdialogue: DialogueTranslationEntries = { 3: "내가 뱃멀미가 나는 것 같군…" }, }, + "archer": { + "encounter": { + 1: "더 나아가기 전에 우리 로켓단과 맞설 만한지 한 번 봅시다!", + 2: "당신의 실력이 예사롭지 않다는 소식을 들었습니다. 정말인지 한 번 보지요.", + 3: "…저는 로켓단의 간부 아폴로. 우리 조직의 적에게는 봐 주지 않습니다!" + }, + "victory": { + 1: "…이런 실수를 하다니!", + 2: "역시 지금의 저는 무리였군요…", + 3: "비, 비주기님, 용서해주십시오…제가 일개 트레이너한테 당하다니…" + }, + }, + "ariana": { + "encounter": { + 1: `거기까지다~!! 너 같은 놈을 언제까지고 설치게 두었다가는 + $로켓단의 프라이드는 상처 입고 상처 입어서 상처투성이가 돼 버린다고-!`, + 2: `내가 하는 일이 옳은지 그른지는 상관 없어… + $그저 비주기님을 믿고 따르는 것 뿐이니까-!`, + 3: "네 여정은 여기서 끝이야. 내가 널 이길 테니까-!" + }, + "victory": { + 1: `어머, 강하군. 안타깝네. + $네가 로켓단에 있었다면 간부가 될 수 있었을 텐데.`, + 2: "사…산산조각났네…", + 3: "으이이이익! 온 힘을 다해서 싸웠는데…이래도 이길 수 없다니!" + }, + }, + "proton": { + "encounter": { + 1: "뭐죠? 우리 일에 끼어든다면 자비를 바라지 마십시오!", + 2: `뭐죠? 나는 로켓단에서 제일 냉혹하다고 불리는 남자… + $우리 일을 방해하도록 그냥 놔두지 않겠습니다!`, + 3: "나는 로켓단의 간부 랜스. 당신의 참견도 여기까지입니다!" + }, + "victory": { + 1: "요새가 무너져내렸네요…", + 2: "나한테 이긴 건 결국 로켓단의 분노를 강하게 했을 뿐이예요…", + 3: "나는 졌지만, 결코 이 일을 잊지 않을 겁니다!" + }, + }, + + "petrel": { + "encounter": { + 1: `후후훗, 잘 왔구나. 오잉? 내가 누군지 알아? 비주기야. + $비주기님이라고, 우-하하! …엥? 전혀 안 닮았다고? + $비주기님으로는 안 보인다고? 제길- 열심히 연습했는데!`, + 2: "나는 로켓단의 간부 람다. 우리 계획을 방해하는 건 용납할 수 없다!", + 3: "이 로켓단 간부 람다가 네놈 불청객을 처리해 주지!" + }, + "victory": { + 1: "조…좋아. 비주기님이 어디 계신지 알려주지.", + 2: "크으으… 이 내가 당해낼 수 없다니… 비주기님, 용서해주십시오…", + 3: "안돼, 이런다고 나한테 어쩔 수는 없어. 다른 사람들에게 알려야겠어…" + }, + }, + "tabitha": { + "encounter": { + 1: "우효효효! 그래 당신 여기까지 왔구나! 그치만 늦었어요!", + 2: `우효효… 벌써 여기까지 왔네요? 우리가 당신을 과소평가했어요. 하지만 이제 시작입니다! + $이 호걸님은 이제까지 본 조무래기들과는 차원이 다르답니다! 우물쭈물 시간을 끌지 않아요. + $확실하게 보내주마! 우효효효효효효!!`, + 3: "여기서 어른의 무서움을 제대로 알려주지! 받아랏-!" + }, + "victory": { + 1: `우효효! 이 호걸은 이겼을지 몰라도 마적님한테는 안 될 겁니다! + $차라리 여기서 졌다면 무자비한 채찍질은 피했을텐데 말이죠!`, + 2: "우효~! 이야 이건 예상 밖의 전개인데!?", + 3: "우효! 어떻게?! 이 호걸님이 이런 일개 트레이너에게…" + }, + }, + "courtney": { + "encounter": { + 1: "…그 …네가 가진 …우리…마그마단이 원하는 것", + 2: "…………그럼 …………삭제하겠습니다", + 3: "……애널라이즈 ……하고 싶어 ……아하하하♪" + }, + "victory": { + 1: "……바꿔줘 ……세계를", + 2: `………예상대로 ………예상외 ………너 …………타깃 록 ………했으니까 + $……엑스페리먼트 ……할 테니까 ………너를………계속………아핫…♪`, + 3: "……또 ……예상외 ………… ……역시 ……너…재미있어…! ………아하하…♪" + }, + }, + "shelly": { + "encounter": { + 1: `엥? 우리 아쿠아단의 일에 끼어들겠다고? + $…좋아! 기본적인 예의도 모르는 애송이한테는 제대로 그 버릇을 고쳐줘야지… + $겁먹고 도망쳐도 용서 따위 없을 줄 알아! 우하하하!`, + 2: "아앙? 뭐야? 이 건방진 꼬맹이는…", + 3: "침착해. 조급해 하지 말라고… 금방 박살내 줄 테니까." + }, + "victory": { + 1: `아아아아앙!? 예상치 못하게 방해받았잖아! 어쩔 수 없네. + $여기선 물러나야겠네. 그렇지만 네가 아쿠아단을 만나는 게 이게 마지막은 아닐 거야. + $우리는 다른 계획도 있거든! 잊지 마!`, + 2: "크윽…!? 너무 봐줬나…!", + 3: `…으윽 …싸우면서 더욱 실력이 좋아졌다고…!? + $장래가 무서워지는 애송이네… …나와 내 포켓몬들은 더 이상 싸울 힘이 남아 있지 않아. + $…가 …가서 아강님한테 아주 혼쭐이나 나 버려.` + }, + }, + "matt": { + "encounter": { + 1: "후하하하하하! 뭐라 떠들고 있는 거야! 너 생긴 게 마크탕이랑 똑같네!", + 2: "음음! 네 녀석은! 재미있는 녀석!", + 3: "뭐야?! 우릴 따라온 거냐!" + }, + "victory": { + 1: "…그래서 말이지, 리더님이 시간이 나실 때까진 내가 상대해 주마!", + 2: `확 확 느껴지는데! 네놈들의 강함이 말이야! + $제대로 붙었다고 하기엔 조금 모자라지만 이제 타임오버 같네…`, + 3: "재밌는데!! 역시 재미있어! 넌! 또 붙게 될 때를 기대하고 있겠어!" + }, + }, + "mars": { + "encounter": { + 1: "난 갤럭시단 간부인 마스! 강하고 아름답지!", + 2: "갤럭시단의 미래에 대한 비전은 흔들림 없지. 방해한다면 무자비하게 짓밟아 주마!", + 3: "두렵지 않아? 넌 그래야만 할 걸!" + }, + "victory": { + 1: "갤럭시단의 간부로서… 이런 일은 있을 수 없어!!", + 2: "넌 능력 있구나. 그건 인정하지.", + 3: "아-이런 이런! 졌잖아!" + } + }, + "jupiter": { + "encounter": { + 1: "무슨 볼일이라도? 좋아! 갤럭시단 간부인 나 주피터가 상대해주지.", + 2: "발버둥쳐 봐야 소용 없어. 갤럭시단이 승리할 거니까!", + 3: "너 떨고 있네… 무서운 거지?" + }, + "victory": { + 1: "일개 트레이너에게 지다니 방심이란 무섭구나.", + 2: "다음에는 내가 울려 주고 말겠어!", + 3: "흥! 강하네. 하지만 보스는 당할 수 없어" + } + }, + "saturn": { + "encounter": { + 1: "나는 갤럭시단의 간부 새턴. 모든 것은 모두를 위해 그리고 갤럭시단을 위해!", + 2: "갤럭시단을 방해한다면 일말의 가능성도 모두 제거한다!", + 3: "여기까지 왔으니 갤럭시단 나름의 접대를 해 주지." + }, + "victory": { + 1: "이럴 수가… 너한테 졌다고?!", + 2: "…역시 강해! 갤럭시단에 맞설 만하군.", + 3: "강하다! 하지만 불쌍하군." + }}, + "zinzolin": { + "encounter": { + 1: "너는 플라스마단에게 있어 불안요소가 될 것이다. 여기서 제거하겠다!", + 2: "이런 이런… 내가 이런 곳에서 싸워야만 하다니!", + 3: "여기까지 오다니 대단한 트레이너군. 그러나 여기가 끝이다." + }, + "victory": { + 1: "게치스님… 제가 실패했습니다…", + 2: "그건 그렇고 힘들구먼. 나는 떨고 있다. 괴롭지만 살아 있다. 그것이야말로 살아 있다는 실감!", + 3: "흐음. 의외로 똑똑한 트레이너군. 하지만 생각만큼은 아니야." + } + }, + "rood": { + "encounter": { + 1: "너는 플라스마단에 위협이 되는구나. 너라는 트레이너가 어떤 인물인지 승부로 알아봐야겠다.", + 2: "오호! 싸늘하구먼… 이런 곳에서 싸울 줄이야!", + 3: "너는 여기까지 온 것으로 보니 뛰어난 트레이너구나. 그렇다만 이젠 끝이다." + }, + "victory": { + 1: "게치스님… 임무를 실패했습니다…", + 2: "나는 떨고 있다. 나는 괴롭지만 이겨냈다.", + 3: "음… 너는 재능이 있는 트레이너구나. 하지만 충분하지는 않다." + } + }, + "xerosic": { + "encounter": { + 1: "오오- 네 소문은 많이 들었다. 자, 이리 와 보거라!", + 2: "너 강하구나. 에너지를 얼마나 갖고 있지?", + 3: "기다리고 있었어! 너를 조사하겠다. 자 시작한다!" + }, + "victory": { + 1: "강하구나, 너는. 응, 정말 강해, 너는.", + 2: "뭣이라! 넌 굉장하군! 너의 포켓몬도 대단하군!", + 3: "굉장하구나 너! 아주 굉장해! 나는 너를 인정하겠다!" + } + }, + "bryony": { + "encounter": { + 1: "나는 바라. 당신과 싸울 수 있어 기쁘군요. 한 번 보여주시죠.", + 2: "인상적이군요… 보기보다 강해요. 에너지가 어디까지 뻗어나가는지 봅시다.", + 3: "도착할 줄 알았습니다. 시작할까요?" + }, + "victory": { + 1: "어라? 이길 확률은 어디까지나 확률. 절대적이진 않네.", + 2: "확률을 무시하는 트레이너, 네 파워의 원천은 뭐지?", + 3: "놀랍군! 칭찬할 만 해." + } + }, "rocket_grunt": { "encounter": { 1: "트러블에 대비하도록!" @@ -391,18 +588,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "로켓단은 다시 떠오를 거니까!" }, }, - "rocket_admin": { - "encounter": { - 1: "어라 어라… 결국 여기까지 오셨습니까? 꽤 우수한 트레이너인가 보군요.", - 2: "영웅 놀이는 여기까지랍니다, 꼬마야.", - 3: "어른이 화를 내면 무섭다는 걸 보여 드리죠!" - }, - "victory": { - 1: "크으… 비주기님 용서해 주세요…!", - 2: "어떻게 이런 일이…", - 3: "아아… 넌 너무 강하다…" - }, - }, "magma_grunt": { "encounter": { 1: " 마그마단을 방해한다면, 자비는 없닷!" @@ -411,18 +596,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "하? 내가 졌어?!" }, }, - "magma_admin": { - "encounter": { - 1: "……아하… ……역시 왔네…그치만 안타깝게 됐어……다 끝났거든", - 2: "……남은……내 일은……너를……막는 것", - 3: "……너랑……인게이지……하고 싶어……아하하하" - }, - "victory": { - 1: "……룰루리", - 2: "……재밌쪄", - 3: "…하아하아……으…하아하아…" - }, - }, "aqua_grunt": { "encounter": { 1: "아쿠아단을 넘본 사람에게는 자비는 없다, 꼬마도 마찬가지야!" @@ -431,18 +604,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "말도 안돼!" }, }, - "aqua_admin": { - "encounter": { - 1: "각오하는 게 좋을 거야! 네 얼굴이 눈물로 범벅이 되게 해주겠어!", - 2: "아앙? 뭐야? 이 건방진 꼬맹이는…", - 3: "…아니 넌!? 일부러 여기까지 쫓아온 거야?" - }, - "victory": { - 1: "하아… 하아…완전 지쳤어", - 2: "크윽…!? 너무 봐줬나…!", - 3: "뭐…뭐라고!?" - }, - }, "galactic_grunt": { "encounter": { 1: "갤럭시단을 방해하지 마!" @@ -451,18 +612,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "사격 중지…… " }, }, - "galactic_admin": { - "encounter": { - 1: "나는 갤럭시단에 있는 간부 중의 한 명.", - 2: "갤럭시단을 방해한다면 일말의 가능성도 모두 제거한다!!", - 3: "왜 그래? 설마 떨고 있는 거야?" - }, - "victory": { - 1: "설마! 내가 졌다고!? 건방진 아이로구나!!", - 2: "…역시 강해!", - 3: "어린아이에게 지다니… 방심이란 무섭구나." - }, - }, "plasma_grunt": { "encounter": { 1: "다른 생각을 가진사람들은 용납하지 않겠다!" @@ -471,18 +620,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "플라-스마-!" }, }, - "plasma_sage": { - "encounter": { - 1: "너는 플라스마단에게 있어 불안요소가 될 것이다. 여기서 제거하겠다!", - 2: "이런 이런… 내가 싸워야만 하다니.", - 3: "여기까지 오다니 대단한 트레이너군." - }, - "victory": { - 1: "게치스…", - 2: "그건 그렇고 춥구먼. 나는 떨고 있다. 괴롭지만 살아 있다.", - 3: "흐음. 의외로 똑똑한 트레이너군." - }, - }, "flare_grunt": { "encounter": { 1: "패션이 우리한텐 가장 중요하다고!" @@ -491,18 +628,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "미래가 밝아 보이질 않네." }, }, - "flare_admin": { - "encounter": { - 1: "왔다! 왔구나! 자! 자! 아직 끝나지 않았다!", - 2: "너 강하구나. 에너지를 얼마나 갖고 있지?", - 3: "기다리고 있었어! 너를 조사하겠다. 자 시작한다!" - }, - "victory": { - 1: "강하구나, 너는. 응, 정말 강해, 너는.", - 2: "그렇지만 보스의 꿈이 이루어져 아름다운 세상이 태어날 것이다!", - 3: "굉장하구나 너! 아주 굉장해! 나는 너를 인정하겠다" - }, - }, "rocket_boss_giovanni_1": { "encounter": { 1: "그래서! 여기까지 오다니, 감탄이 절로 나오는군!" diff --git a/src/locales/ko/trainers.ts b/src/locales/ko/trainers.ts index 1671dd7a45b..b34530eb24c 100644 --- a/src/locales/ko/trainers.ts +++ b/src/locales/ko/trainers.ts @@ -19,6 +19,19 @@ export const titles: SimpleTranslationEntries = { "galactic_boss": "갤럭시단 보스", "plasma_boss": "플라스마단 보스", "flare_boss": "플레어단 보스", + + "rocket_admin": "로켓단 간부", + "rocket_admin_female": "로켓단 간부", + "magma_admin": "마그마단 간부", + "magma_admin_female": "마그마단 간부", + "aqua_admin": "아쿠아단 간부", + "aqua_admin_female": "아쿠아단 간부", + "galactic_commander": "갤럭시단 간부", + "galactic_commander_female": "갤럭시단 간부", + "plasma_sage": "플라스마단 현인", + "plasma_admin": "플라스마단 간부", + "flare_admin": "플레어단 간부", + "flare_admin_female": "플레어단 간부", // Maybe if we add the evil teams we can add "Team Rocket" and "Team Aqua" etc. here as well as "Team Rocket Boss" and "Team Aqua Admin" etc. } as const; @@ -128,32 +141,22 @@ export const trainerClasses: SimpleTranslationEntries = { "rocket_grunt": "로켓단 조무래기", "rocket_grunt_female": "로켓단 조무래기", "rocket_grunts": "로켓단 조무래기들", - "rocket_admin": "로켓단 간부", - "rocket_admin_female": "로켓단 간부", "magma_grunt": "마그마단 조무래기", "magma_grunt_female": "마그마단 조무래기", "magma_grunts": "마그마단 조무래기들", - "magma_admin": "마그마단 간부", - "magma_admin_female": "마그마단 간부", "aqua_grunt": "아쿠아단 조무래기", "aqua_grunt_female": "아쿠아단 조무래기", "aqua_grunts": "아쿠아단 조무래기들", - "aqua_admin": "아쿠아단 간부", - "aqua_admin_female": "아쿠아단 간부", "galactic_grunt": "갤럭시단 조무래기", "galactic_grunt_female": "갤럭시단 조무래기", "galactic_grunts": "갤럭시단 조무래기들", - "galactic_admin": "갤럭시단 간부", - "galactic_admin_female": "갤럭시단 간부", "plasma_grunt": "플라스마단 조무래기", "plasma_grunt_female": "플라스마단 조무래기", "plasma_grunts": "플라스마단 조무래기들", - "plasma_sage": "플라스마단 현인", "flare_grunt": "플레어단 조무래기", "flare_grunt_female": "플레어단 조무래기", "flare_grunts": "플레어단 조무래기들", - "flare_admin": "플레어단 간부", - "flare_admin_female": "플레어단 간부", + } as const; // Names of special trainers like gym leaders, elite four, and the champion @@ -282,6 +285,25 @@ export const trainerNames: SimpleTranslationEntries = { "leon": "단델", "rival": "핀", "rival_female": "아이비", + + // Evil Team Admins + "archer": "아폴로", + "ariana": "아테나", + "proton": "랜스", + "petrel": "람다", + "tabitha": "호걸", + "courtney": "구열", + "shelly": "이연", + "matt": "해조", + "mars": "마스", + "jupiter": "주피터", + "saturn": "새턴", + "zinzolin": "비오", + "rood": "로트", + "xerosic": "크세로시키", + "bryony": "바라", + + "maxie": "마적", "archie": "아강", "cyrus": "태홍", diff --git a/src/locales/pt_BR/dialogue.ts b/src/locales/pt_BR/dialogue.ts index 3325cf81cf9..cbd781009e5 100644 --- a/src/locales/pt_BR/dialogue.ts +++ b/src/locales/pt_BR/dialogue.ts @@ -383,6 +383,203 @@ export const PGMdialogue: DialogueTranslationEntries = { 3: "Estou achando que quem tá enjoado sou eu..." }, }, + "archer": { + "encounter": { + 1: "Before you go any further, let's see how you far against us, Team Rocket!", + 2: "I have received reports that your skills are not insignificant. Let's see if they are true.", + 3: "I am Archer, an Admin of Team Rocket. And I do not go easy on enemies of our organization." + }, + "victory": { + 1: "What a blunder!", + 2: "With my current skills, I was not up to the task after all.", + 3: "F-forgive me, Giovanni... For me to be defeated by a mere trainer..." + }, + }, + "ariana": { + "encounter": { + 1: `Hold it right there! We can't someone on the loose." + $It's harmful to Team Rocket's pride, you see.`, + 2: `I don't know or care if what I'm doing is right or wrong... + $I just put my faith in Giovanni and do as I am told`, + 3: "Your trip ends here. I'm going to take you down!" + }, + "victory": { + 1: `Tch, you really are strong. It's too bad. + $If you were to join Team Rocket, you could become an Executive.`, + 2: "I... I'm shattered...", + 3: "Aaaieeeee! This can't be happening! I fought hard, but I still lost…" + }, + }, + "proton": { + "encounter": { + 1: "What do you want? If you interrupt our work, don't expect any mercy!", + 2: `What do we have here? I am often labeled as the scariest and cruelest guy in Team Rocket… + $I strongly urge you not to interfere with our business!`, + 3: "I am Proton, an Admin of Team Rocket. I am here to put an end to your meddling!" + }, + "victory": { + 1: "The fortress came down!", + 2: "You may have won this time… But all you did was make Team Rocket's wrath grow…", + 3: "I am defeated… But I will not forget this!" + }, + }, + + "petrel": { + "encounter": { + 1: `Muhahaha, we've been waiting for you. Me? You don't know who I am? It is me, Giovanni. + $The majestic Giovanni himself! Wahahaha! …Huh? I don't sound anything like Giovanni? + $I don't even look like Giovanni? How come? I've worked so hard to mimic him!`, + 2: "I am Petrel, an Admin of Team Rocket. I will not allow you to interfere with our plans!", + 3: "Rocket Executive Petrel will deal with this intruder!" + }, + "victory": { + 1: "OK, OK. I'll tell you where he is.", + 2: "I… I couldn't do a thing… Giovanni, please forgive me…", + 3: "No, I can't let this affect me. I have to inform the others…" + }, + }, + "tabitha": { + "encounter": { + 1: "Hehehe! So you've come all the way here! But you're too late!", + 2: `Hehehe... Got here already, did you? We underestimated you! But this is it! + $I'm a cut above the Grunts you've seen so far. I'm not stalling for time. + $I'm going to pulverize you!`, + 3: "I'm going to give you a little taste of pain! Resign yourself to it!" + }, + "victory": { + 1: `Hehehe! You might have beaten me, but you don't stand a chance against the Boss! + $If you get lost now, you won't have to face a sound whipping!`, + 2: "Hehehe... So, I lost, too...", + 3: "Ahya! How could this be? For an Admin like me to lose to some random trainer..." + }, + }, + "courtney": { + "encounter": { + 1: "The thing...The thing that you hold...That is what... That's what we of Team Magma seek...", + 2: "... Well then...Deleting...", + 3: "...Ha. ...Analyzing... ...Hah♪" + }, + "victory": { + 1: "... ...Change...the world.", + 2: `As anticipated. Unanticipated. You. Target lock...completed. + $Commencing...experiment. You. Forever. Aha... ♪`, + 3: "...Again? That's unanticipated. ...I knew it. You...are interesting! ...Haha. ♪" + }, + }, + "shelly": { + "encounter": { + 1: `Ahahahaha! You're going to meddle in Team Aqua's affairs? + $You're either absolutely fearless, simply ignorant, or both! + $You're so cute, you're disgusting! I'll put you down`, + 2: "What's this? Who's this spoiled brat?", + 3: "Cool your jets. Be patient. I'll crush you shortly." + }, + "victory": { + 1: `Ahahahaha! We got meddled with unexpectedly! We're out of options. + $We'll have to pull out. But this isn't the last you'll see of Team Aqua! + $We have other plans! Don't you forget it!`, + 2: "Ahhh?! Did I go too easy on you?!", + 3: `Uh. Are you telling me you've upped your game even more during the fight? + $You're a brat with a bright future… My Pokémon and I don't have any strength left to fight… + $Go on… Go and be destroyed by Archie.` + }, + }, + "matt": { + "encounter": { + 1: "Hoohahaha! What, you got a screw loose or something? Look at you, little Makuhita person!", + 2: "Oho! You! You're that funny kid!", + 3: "What are you doing here? Did you follow us?" + }, + "victory": { + 1: "All right then, until the Boss has time for you, I'll be your opponent!", + 2: `I can feel it! I can feel it, all right! The strength coming offa you! + $More! I still want more! But looks like we're outta time...`, + 3: "That was fun! I knew you'd show me a good time! I look forward to facing you again someday!" + }, + }, + "mars": { + "encounter": { + 1: "I'm Mars, one of Team Galactic's top Commanders.", + 2: "Team Galactic's vision for the future is unwavering. Opposition will be crushed without mercy!", + 3: "Feeling nervous? You should be!" + }, + "victory": { + 1: "This can't be happening! How did I lose?!", + 2: "You have some skill, I'll give you that.", + 3: "Defeated... This was a costly mistake." + } + }, + "jupiter": { + "encounter": { + 1: "Jupiter, Commander of Team Galactic, at your service.", + 2: "Resistance is futile. Team Galactic will prevail!", + 3: "You're trembling... scared already?" + }, + "victory": { + 1: "No way... I lost?!", + 2: "Impressive, you've got guts!", + 3: "Losing like this... How embarrassing." + } + }, + "saturn": { + "encounter": { + 1: "I am Saturn, Commander of Team Galactic.", + 2: "Our mission is absolute. Any hindrance will be obliterated!", + 3: "Is that fear I see in your eyes?" + }, + "victory": { + 1: "Impossible... Defeated by you?!", + 2: "You have proven yourself a worthy adversary.", + 3: "Bestowed in defeat... This is unacceptable." + }}, + "zinzolin": { + "encounter": { + 1: "You could become a threat to Team Plasma, so we will eliminate you here and now!", + 2: "Oh, for crying out loud... I didn't expect to have to battle in this freezing cold!", + 3: "You're an impressive Trainer to have made it this far. But it ends here." + }, + "victory": { + 1: "Ghetsis... I have failed you...", + 2: "It's bitter cold. I'm shivering. I'm suffering. Yet, I still stand victorious.", + 3: "Hmph. You're a smarter Trainer than I expected, but not smart enough." + } + }, + "rood": { + "encounter": { + 1: "You are a threat to Team Plasma. We cannot let you walk away from here and now!", + 2: "Oh, this icy wind... I never thought I'd have to fight here!", + 3: "You are a remarkable Trainer to have made it this far. But this is where it ends." + }, + "victory": { + 1: "Ghetsis... I have failed my mission...", + 2: "The cold is piercing. I'm shivering. I'm suffering. Yet, I have triumphed.", + 3: "Hm. You are a talented Trainer, but unfortunately not talented enough." + } + }, + "xerosic": { + "encounter": { + 1: "Ah ha ha! It would be my pleasure. Come on, little Trainer! Let's see what you've got!", + 2: "Hmm... You're more powerful than you look. I wonder how much energy there is inside you.", + 3: "I've been waiting for you! I need to do a little research on you! Come, let us begin!" + }, + "victory": { + 1: "Ah, you're quite strong. Oh yes—very strong, indeed.", + 2: "Ding-ding-ding! You did it! To the victor go the spoils!", + 3: "Wonderful! Amazing! You have tremendous skill and bravery!" + } + }, + "bryony": { + "encounter": { + 1: "I am Bryony, and it would be my pleasure to battle you. Show me what you've got.", + 2: "Impressive... You're more powerful than you appear. Let's see the true extent of your energy.", + 3: "I've anticipated your arrival. It's time for a little test. Shall we begin?" + }, + "victory": { + 1: "You're quite strong. Oh yes—very strong, indeed.", + 2: "Ding-ding-ding! You've done well. Victory is yours.", + 3: "Wonderful! Remarkable! Your skill and bravery are commendable." + } + }, "rocket_grunt": { "encounter": { 1: "Se prepara pra encrenca!" diff --git a/src/locales/pt_BR/trainers.ts b/src/locales/pt_BR/trainers.ts index 32cc46300d5..e920d07a22a 100644 --- a/src/locales/pt_BR/trainers.ts +++ b/src/locales/pt_BR/trainers.ts @@ -19,6 +19,19 @@ export const titles: SimpleTranslationEntries = { "galactic_boss": "Chefe da Equipe Galáctica", "plasma_boss": "Chefe da Equipe Plasma", "flare_boss": "Chefe da Equipe Flare", + + "rocket_admin": "Team Rocket Admin", + "rocket_admin_female": "Team Rocket Admin", + "magma_admin": "Team Magma Admin", + "magma_admin_female": "Team Magma Admin", + "aqua_admin": "Team Aqua Admin", + "aqua_admin_female": "Team Aqua Admin", + "galactic_commander": "Team Galactic Commander", + "galactic_commander_female": "Team Galactic Commander", + "plasma_sage": "Team Plasma Sage", + "plasma_admin": "Team Plasma Admin", + "flare_admin": "Team Flare Admin", + "flare_admin_female": "Team Flare Admin", // Maybe if we add the evil teams we can add "Team Rocket" and "Team Aqua" etc. here as well as "Team Rocket Boss" and "Team Aqua Admin" etc. } as const; @@ -128,32 +141,21 @@ export const trainerClasses: SimpleTranslationEntries = { "rocket_grunt": "Recruta da Equipe Rocket", "rocket_grunt_female": "Recruta da Equipe Rocket", "rocket_grunts": "Recrutas da Equipe Rocket", - "rocket_admin": "Rocket Admin", - "rocket_admin_female": "Rocket Admin", "magma_grunt": "Recruta da Equipe Magma", "magma_grunt_female": "Recruta da Equipe Magma", "magma_grunts": "Recrutas da Equipe Magma", - "magma_admin": "Magma Admin", - "magma_admin_female": "Magma Admin", "aqua_grunt": "Recruta da Equipe Aqua", "aqua_grunt_female": "Recruta da Equipe Aqua", "aqua_grunts": "Recrutas da Equipe Aqua", - "aqua_admin": "Aqua Admin", - "aqua_admin_female": "Aqua Admin", "galactic_grunt": "Recruta da Equipe Galáctica", "galactic_grunt_female": "Recruta da Equipe Galáctica", "galactic_grunts": "Recrutas da Equipe Galáctica", - "galactic_admin": "Galactic Admin", - "galactic_admin_female": "Galactic Admin", "plasma_grunt": "Recruta da Equipe Plasma", "plasma_grunt_female": "Recruta da Equipe Plasma", "plasma_grunts": "Recrutas da Equipe Plasma", - "plasma_sage": "Plasma Sage", "flare_grunt": "Recruta da Equipe Flare", "flare_grunt_female": "Recruta da Equipe Flare", "flare_grunts": "Recrutas da Equipe Flare", - "flare_admin": "Flare Admin", - "flare_admin_female": "Flare Admin", } as const; // Names of special trainers like gym leaders, elite four, and the champion @@ -282,6 +284,24 @@ export const trainerNames: SimpleTranslationEntries = { "leon": "Leon", "rival": "Finn", "rival_female": "Ivy", + + // Evil Team Admins + "archer": "Archer", + "ariana": "Ariana", + "proton": "Proton", + "petrel": "Petrel", + "tabitha": "Tabitha", + "courtney": "Courtney", + "shelly": "Shelly", + "matt": "Matt", + "mars": "Mars", + "jupiter": "Jupiter", + "saturn": "Saturn", + "zinzolin": "Zinzolin", + "rood": "Rood", + "xerosic": "Xerosic", + "bryony": "Bryony", + "maxie": "Maxie", "archie": "Archie", "cyrus": "Cyrus", diff --git a/src/locales/zh_CN/dialogue.ts b/src/locales/zh_CN/dialogue.ts index 50d6c5f4333..597b26dd639 100644 --- a/src/locales/zh_CN/dialogue.ts +++ b/src/locales/zh_CN/dialogue.ts @@ -382,6 +382,203 @@ export const PGMdialogue: DialogueTranslationEntries = { 3: "好像是我晕船了…" }, }, + "archer": { + "encounter": { + 1: "Before you go any further, let's see how you far against us, Team Rocket!", + 2: "I have received reports that your skills are not insignificant. Let's see if they are true.", + 3: "I am Archer, an Admin of Team Rocket. And I do not go easy on enemies of our organization." + }, + "victory": { + 1: "What a blunder!", + 2: "With my current skills, I was not up to the task after all.", + 3: "F-forgive me, Giovanni... For me to be defeated by a mere trainer..." + }, + }, + "ariana": { + "encounter": { + 1: `Hold it right there! We can't someone on the loose." + $It's harmful to Team Rocket's pride, you see.`, + 2: `I don't know or care if what I'm doing is right or wrong... + $I just put my faith in Giovanni and do as I am told`, + 3: "Your trip ends here. I'm going to take you down!" + }, + "victory": { + 1: `Tch, you really are strong. It's too bad. + $If you were to join Team Rocket, you could become an Executive.`, + 2: "I... I'm shattered...", + 3: "Aaaieeeee! This can't be happening! I fought hard, but I still lost…" + }, + }, + "proton": { + "encounter": { + 1: "What do you want? If you interrupt our work, don't expect any mercy!", + 2: `What do we have here? I am often labeled as the scariest and cruelest guy in Team Rocket… + $I strongly urge you not to interfere with our business!`, + 3: "I am Proton, an Admin of Team Rocket. I am here to put an end to your meddling!" + }, + "victory": { + 1: "The fortress came down!", + 2: "You may have won this time… But all you did was make Team Rocket's wrath grow…", + 3: "I am defeated… But I will not forget this!" + }, + }, + + "petrel": { + "encounter": { + 1: `Muhahaha, we've been waiting for you. Me? You don't know who I am? It is me, Giovanni. + $The majestic Giovanni himself! Wahahaha! …Huh? I don't sound anything like Giovanni? + $I don't even look like Giovanni? How come? I've worked so hard to mimic him!`, + 2: "I am Petrel, an Admin of Team Rocket. I will not allow you to interfere with our plans!", + 3: "Rocket Executive Petrel will deal with this intruder!" + }, + "victory": { + 1: "OK, OK. I'll tell you where he is.", + 2: "I… I couldn't do a thing… Giovanni, please forgive me…", + 3: "No, I can't let this affect me. I have to inform the others…" + }, + }, + "tabitha": { + "encounter": { + 1: "Hehehe! So you've come all the way here! But you're too late!", + 2: `Hehehe... Got here already, did you? We underestimated you! But this is it! + $I'm a cut above the Grunts you've seen so far. I'm not stalling for time. + $I'm going to pulverize you!`, + 3: "I'm going to give you a little taste of pain! Resign yourself to it!" + }, + "victory": { + 1: `Hehehe! You might have beaten me, but you don't stand a chance against the Boss! + $If you get lost now, you won't have to face a sound whipping!`, + 2: "Hehehe... So, I lost, too...", + 3: "Ahya! How could this be? For an Admin like me to lose to some random trainer..." + }, + }, + "courtney": { + "encounter": { + 1: "The thing...The thing that you hold...That is what... That's what we of Team Magma seek...", + 2: "... Well then...Deleting...", + 3: "...Ha. ...Analyzing... ...Hah♪" + }, + "victory": { + 1: "... ...Change...the world.", + 2: `As anticipated. Unanticipated. You. Target lock...completed. + $Commencing...experiment. You. Forever. Aha... ♪`, + 3: "...Again? That's unanticipated. ...I knew it. You...are interesting! ...Haha. ♪" + }, + }, + "shelly": { + "encounter": { + 1: `Ahahahaha! You're going to meddle in Team Aqua's affairs? + $You're either absolutely fearless, simply ignorant, or both! + $You're so cute, you're disgusting! I'll put you down`, + 2: "What's this? Who's this spoiled brat?", + 3: "Cool your jets. Be patient. I'll crush you shortly." + }, + "victory": { + 1: `Ahahahaha! We got meddled with unexpectedly! We're out of options. + $We'll have to pull out. But this isn't the last you'll see of Team Aqua! + $We have other plans! Don't you forget it!`, + 2: "Ahhh?! Did I go too easy on you?!", + 3: `Uh. Are you telling me you've upped your game even more during the fight? + $You're a brat with a bright future… My Pokémon and I don't have any strength left to fight… + $Go on… Go and be destroyed by Archie.` + }, + }, + "matt": { + "encounter": { + 1: "Hoohahaha! What, you got a screw loose or something? Look at you, little Makuhita person!", + 2: "Oho! You! You're that funny kid!", + 3: "What are you doing here? Did you follow us?" + }, + "victory": { + 1: "All right then, until the Boss has time for you, I'll be your opponent!", + 2: `I can feel it! I can feel it, all right! The strength coming offa you! + $More! I still want more! But looks like we're outta time...`, + 3: "That was fun! I knew you'd show me a good time! I look forward to facing you again someday!" + }, + }, + "mars": { + "encounter": { + 1: "I'm Mars, one of Team Galactic's top Commanders.", + 2: "Team Galactic's vision for the future is unwavering. Opposition will be crushed without mercy!", + 3: "Feeling nervous? You should be!" + }, + "victory": { + 1: "This can't be happening! How did I lose?!", + 2: "You have some skill, I'll give you that.", + 3: "Defeated... This was a costly mistake." + } + }, + "jupiter": { + "encounter": { + 1: "Jupiter, Commander of Team Galactic, at your service.", + 2: "Resistance is futile. Team Galactic will prevail!", + 3: "You're trembling... scared already?" + }, + "victory": { + 1: "No way... I lost?!", + 2: "Impressive, you've got guts!", + 3: "Losing like this... How embarrassing." + } + }, + "saturn": { + "encounter": { + 1: "I am Saturn, Commander of Team Galactic.", + 2: "Our mission is absolute. Any hindrance will be obliterated!", + 3: "Is that fear I see in your eyes?" + }, + "victory": { + 1: "Impossible... Defeated by you?!", + 2: "You have proven yourself a worthy adversary.", + 3: "Bestowed in defeat... This is unacceptable." + }}, + "zinzolin": { + "encounter": { + 1: "You could become a threat to Team Plasma, so we will eliminate you here and now!", + 2: "Oh, for crying out loud... I didn't expect to have to battle in this freezing cold!", + 3: "You're an impressive Trainer to have made it this far. But it ends here." + }, + "victory": { + 1: "Ghetsis... I have failed you...", + 2: "It's bitter cold. I'm shivering. I'm suffering. Yet, I still stand victorious.", + 3: "Hmph. You're a smarter Trainer than I expected, but not smart enough." + } + }, + "rood": { + "encounter": { + 1: "You are a threat to Team Plasma. We cannot let you walk away from here and now!", + 2: "Oh, this icy wind... I never thought I'd have to fight here!", + 3: "You are a remarkable Trainer to have made it this far. But this is where it ends." + }, + "victory": { + 1: "Ghetsis... I have failed my mission...", + 2: "The cold is piercing. I'm shivering. I'm suffering. Yet, I have triumphed.", + 3: "Hm. You are a talented Trainer, but unfortunately not talented enough." + } + }, + "xerosic": { + "encounter": { + 1: "Ah ha ha! It would be my pleasure. Come on, little Trainer! Let's see what you've got!", + 2: "Hmm... You're more powerful than you look. I wonder how much energy there is inside you.", + 3: "I've been waiting for you! I need to do a little research on you! Come, let us begin!" + }, + "victory": { + 1: "Ah, you're quite strong. Oh yes—very strong, indeed.", + 2: "Ding-ding-ding! You did it! To the victor go the spoils!", + 3: "Wonderful! Amazing! You have tremendous skill and bravery!" + } + }, + "bryony": { + "encounter": { + 1: "I am Bryony, and it would be my pleasure to battle you. Show me what you've got.", + 2: "Impressive... You're more powerful than you appear. Let's see the true extent of your energy.", + 3: "I've anticipated your arrival. It's time for a little test. Shall we begin?" + }, + "victory": { + 1: "You're quite strong. Oh yes—very strong, indeed.", + 2: "Ding-ding-ding! You've done well. Victory is yours.", + 3: "Wonderful! Remarkable! Your skill and bravery are commendable." + } + }, "rocket_grunt": { "encounter": { 1: "你要有麻烦了!" @@ -390,18 +587,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "好讨厌的感觉啊!" }, }, - "rocket_admin": { - "encounter": { - 1: "Oh? You managed to get this far? You must be quite the trainer.", - 2: "That's quite enough of you playing hero, kid.", - 3: "I'll show you how scary an angry adult can be!" - }, - "victory": { - 1: "No! Forgive me Giovanni!", - 2: "How could this be?", - 3: "Urgh... You were too strong..." - }, - }, "magma_grunt": { "encounter": { 1: "如果你挡在熔岩队路上,那就别指望我们手下留情!" @@ -410,18 +595,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "哈?我输了?!" }, }, - "magma_admin": { - "encounter": { - 1: "Hehehe! So you've come all the way here! But you're too late!", - 2: "You're going to meddle in Team Magma's affairs? You're so cute you're disgusting! I'll put you down kiddy!", - 3: "I'm going to give you a little taste of pain! Resign yourself to it!" - }, - "victory": { - 1: "Hehehe... So I lost...", - 2: "You're disgustingly strong!", - 3: "Ahahaha! Ouch!" - }, - }, "aqua_grunt": { "encounter": { 1: "即使是小孩,如果要和海洋队作对,也别指望我们手下留情!" @@ -430,18 +603,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "你在开玩笑吧?" }, }, - "aqua_admin": { - "encounter": { - 1: "I'm a cut above the grunts you've seen so far. I'm going to puvlerize you!", - 2: "Hahn? What's this? Who's this spoiled brat?", - 3: "What are you doing here? Did you follow us?" - }, - "victory": { - 1: "So I lost too...", - 2: "Ahhh?! Did I go too easy on you?!", - 3: "Wh-what was that?" - }, - }, "galactic_grunt": { "encounter": { 1: "别惹银河队!" @@ -450,18 +611,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "停机了…" }, }, - "galactic_admin": { - "encounter": { - 1: "I'm one of Team Galactic's Commanders.", - 2: "Anything that opposes Team Galactic must be crushed! Even the very thought of opposition will not be tolerated!", - 3: "What's the matter? Don't tell me you're shaking?" - }, - "victory": { - 1: "This can't be?! I lost?! You... you uppity brat!", - 2: "You, my friend, are tough!", - 3: "Losing to some child... Being careless cost me too much." - }, - }, "plasma_grunt": { "encounter": { 1: "异端不共戴天!" @@ -470,18 +619,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "等离子子子子子子!" }, }, - "plasma_sage": { - "encounter": { - 1: "You could become a threat to Team Plasma, so we will eliminate you here!", - 2: "Oh, for crying out loud... I didn't expect to have to fight!", - 3: "You're an impressive Trainer to have made it this far." - }, - "victory": { - 1: "Ghetsis...", - 2: "It's bitter cold. I'm shivering. I'm suffering.", - 3: "Hmph. You're a smarter Trainer than I expected." - }, - }, "flare_grunt": { "encounter": { 1: "时尚最重要!" @@ -490,18 +627,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "未来一片黑暗啊…" }, }, - "flare_admin": { - "encounter": { - 1: "Ah ha ha! It would be my pleasure. Come on, little Trainer! Let's see what you've got!", - 2: "Hmm... You're more powerful than you look. I wonder how much energy there is inside you.", - 3: "I've been waiting for you! I need to do a little research on you! Come, let us begin!" - }, - "victory": { - 1: "You're quite strong. Oh yes-very strong, indeed.", - 2: "Ding-ding-ding! Yup, you did it! To the victor goes the spoils!", - 3: "Wonderful! Amazing! You have tremendous skill and bravery!" - }, - }, "rocket_boss_giovanni_1": { "encounter": { 1: "我不得不说,能来到这里,你的确很不简单!" diff --git a/src/locales/zh_CN/trainers.ts b/src/locales/zh_CN/trainers.ts index 1d32fdf6e02..eb27d2c0c0a 100644 --- a/src/locales/zh_CN/trainers.ts +++ b/src/locales/zh_CN/trainers.ts @@ -19,6 +19,19 @@ export const titles: SimpleTranslationEntries = { "galactic_boss": "银河队老大", "plasma_boss": "等离子队老大", "flare_boss": "闪焰队老大", + + "rocket_admin": "Team Rocket Admin", + "rocket_admin_female": "Team Rocket Admin", + "magma_admin": "Team Magma Admin", + "magma_admin_female": "Team Magma Admin", + "aqua_admin": "Team Aqua Admin", + "aqua_admin_female": "Team Aqua Admin", + "galactic_commander": "Team Galactic Commander", + "galactic_commander_female": "Team Galactic Commander", + "plasma_sage": "Team Plasma Sage", + "plasma_admin": "Team Plasma Admin", + "flare_admin": "Team Flare Admin", + "flare_admin_female": "Team Flare Admin", // Maybe if we add the evil teams we can add "Team Rocket" and "Team Aqua" etc. here as well as "Team Rocket Boss" and "Team Aqua Admin" etc. } as const; @@ -128,32 +141,21 @@ export const trainerClasses: SimpleTranslationEntries = { "rocket_grunt": "火箭队手下", "rocket_grunt_female": "火箭队手下", "rocket_grunts": "火箭队手下们", - "rocket_admin": "Rocket Admin", - "rocket_admin_female": "Rocket Admin", "magma_grunt": "熔岩队手下", "magma_grunt_female": "熔岩队手下", "magma_grunts": "熔岩队手下们", - "magma_admin": "Magma Admin", - "magma_admin_female": "Magma Admin", "aqua_grunt": "海洋队手下", "aqua_grunt_female": "海洋队手下", "aqua_grunts": "海洋队手下们", - "aqua_admin": "Aqua Admin", - "aqua_admin_female": "Aqua Admin", "galactic_grunt": "银河队手下", "galactic_grunt_female": "银河队手下", "galactic_grunts": "银河队手下们", - "galactic_admin": "Galactic Admin", - "galactic_admin_female": "Galactic Admin", "plasma_grunt": "等离子队手下", "plasma_grunt_female": "等离子队手下", "plasma_grunts": "等离子队手下们", - "plasma_sage": "Plasma Sage", "flare_grunt": "闪焰队手下", "flare_grunt_female": "闪焰队手下", "flare_grunts": "闪焰队手下们", - "flare_admin": "Flare Admin", - "flare_admin_female": "Flare Admin", } as const; // Names of special trainers like gym leaders, elite four, and the champion @@ -339,6 +341,23 @@ export const trainerNames: SimpleTranslationEntries = { "rival": "芬恩", "rival_female": "艾薇", + // Evil Team Admins + "archer": "Archer", + "ariana": "Ariana", + "proton": "Proton", + "petrel": "Petrel", + "tabitha": "Tabitha", + "courtney": "Courtney", + "shelly": "Shelly", + "matt": "Matt", + "mars": "Mars", + "jupiter": "Jupiter", + "saturn": "Saturn", + "zinzolin": "Zinzolin", + "rood": "Rood", + "xerosic": "Xerosic", + "bryony": "Bryony", + // ---- 组织老大 Bosses ---- "maxie": "赤焰松", "archie": "水梧桐", diff --git a/src/locales/zh_TW/dialogue.ts b/src/locales/zh_TW/dialogue.ts index 530906eda5b..16dad83599e 100644 --- a/src/locales/zh_TW/dialogue.ts +++ b/src/locales/zh_TW/dialogue.ts @@ -382,6 +382,203 @@ export const PGMdialogue: DialogueTranslationEntries = { 3: "好像是我暈船了…" }, }, + "archer": { + "encounter": { + 1: "Before you go any further, let's see how you far against us, Team Rocket!", + 2: "I have received reports that your skills are not insignificant. Let's see if they are true.", + 3: "I am Archer, an Admin of Team Rocket. And I do not go easy on enemies of our organization." + }, + "victory": { + 1: "What a blunder!", + 2: "With my current skills, I was not up to the task after all.", + 3: "F-forgive me, Giovanni... For me to be defeated by a mere trainer..." + }, + }, + "ariana": { + "encounter": { + 1: `Hold it right there! We can't someone on the loose." + $It's harmful to Team Rocket's pride, you see.`, + 2: `I don't know or care if what I'm doing is right or wrong... + $I just put my faith in Giovanni and do as I am told`, + 3: "Your trip ends here. I'm going to take you down!" + }, + "victory": { + 1: `Tch, you really are strong. It's too bad. + $If you were to join Team Rocket, you could become an Executive.`, + 2: "I... I'm shattered...", + 3: "Aaaieeeee! This can't be happening! I fought hard, but I still lost…" + }, + }, + "proton": { + "encounter": { + 1: "What do you want? If you interrupt our work, don't expect any mercy!", + 2: `What do we have here? I am often labeled as the scariest and cruelest guy in Team Rocket… + $I strongly urge you not to interfere with our business!`, + 3: "I am Proton, an Admin of Team Rocket. I am here to put an end to your meddling!" + }, + "victory": { + 1: "The fortress came down!", + 2: "You may have won this time… But all you did was make Team Rocket's wrath grow…", + 3: "I am defeated… But I will not forget this!" + }, + }, + + "petrel": { + "encounter": { + 1: `Muhahaha, we've been waiting for you. Me? You don't know who I am? It is me, Giovanni. + $The majestic Giovanni himself! Wahahaha! …Huh? I don't sound anything like Giovanni? + $I don't even look like Giovanni? How come? I've worked so hard to mimic him!`, + 2: "I am Petrel, an Admin of Team Rocket. I will not allow you to interfere with our plans!", + 3: "Rocket Executive Petrel will deal with this intruder!" + }, + "victory": { + 1: "OK, OK. I'll tell you where he is.", + 2: "I… I couldn't do a thing… Giovanni, please forgive me…", + 3: "No, I can't let this affect me. I have to inform the others…" + }, + }, + "tabitha": { + "encounter": { + 1: "Hehehe! So you've come all the way here! But you're too late!", + 2: `Hehehe... Got here already, did you? We underestimated you! But this is it! + $I'm a cut above the Grunts you've seen so far. I'm not stalling for time. + $I'm going to pulverize you!`, + 3: "I'm going to give you a little taste of pain! Resign yourself to it!" + }, + "victory": { + 1: `Hehehe! You might have beaten me, but you don't stand a chance against the Boss! + $If you get lost now, you won't have to face a sound whipping!`, + 2: "Hehehe... So, I lost, too...", + 3: "Ahya! How could this be? For an Admin like me to lose to some random trainer..." + }, + }, + "courtney": { + "encounter": { + 1: "The thing...The thing that you hold...That is what... That's what we of Team Magma seek...", + 2: "... Well then...Deleting...", + 3: "...Ha. ...Analyzing... ...Hah♪" + }, + "victory": { + 1: "... ...Change...the world.", + 2: `As anticipated. Unanticipated. You. Target lock...completed. + $Commencing...experiment. You. Forever. Aha... ♪`, + 3: "...Again? That's unanticipated. ...I knew it. You...are interesting! ...Haha. ♪" + }, + }, + "shelly": { + "encounter": { + 1: `Ahahahaha! You're going to meddle in Team Aqua's affairs? + $You're either absolutely fearless, simply ignorant, or both! + $You're so cute, you're disgusting! I'll put you down`, + 2: "What's this? Who's this spoiled brat?", + 3: "Cool your jets. Be patient. I'll crush you shortly." + }, + "victory": { + 1: `Ahahahaha! We got meddled with unexpectedly! We're out of options. + $We'll have to pull out. But this isn't the last you'll see of Team Aqua! + $We have other plans! Don't you forget it!`, + 2: "Ahhh?! Did I go too easy on you?!", + 3: `Uh. Are you telling me you've upped your game even more during the fight? + $You're a brat with a bright future… My Pokémon and I don't have any strength left to fight… + $Go on… Go and be destroyed by Archie.` + }, + }, + "matt": { + "encounter": { + 1: "Hoohahaha! What, you got a screw loose or something? Look at you, little Makuhita person!", + 2: "Oho! You! You're that funny kid!", + 3: "What are you doing here? Did you follow us?" + }, + "victory": { + 1: "All right then, until the Boss has time for you, I'll be your opponent!", + 2: `I can feel it! I can feel it, all right! The strength coming offa you! + $More! I still want more! But looks like we're outta time...`, + 3: "That was fun! I knew you'd show me a good time! I look forward to facing you again someday!" + }, + }, + "mars": { + "encounter": { + 1: "I'm Mars, one of Team Galactic's top Commanders.", + 2: "Team Galactic's vision for the future is unwavering. Opposition will be crushed without mercy!", + 3: "Feeling nervous? You should be!" + }, + "victory": { + 1: "This can't be happening! How did I lose?!", + 2: "You have some skill, I'll give you that.", + 3: "Defeated... This was a costly mistake." + } + }, + "jupiter": { + "encounter": { + 1: "Jupiter, Commander of Team Galactic, at your service.", + 2: "Resistance is futile. Team Galactic will prevail!", + 3: "You're trembling... scared already?" + }, + "victory": { + 1: "No way... I lost?!", + 2: "Impressive, you've got guts!", + 3: "Losing like this... How embarrassing." + } + }, + "saturn": { + "encounter": { + 1: "I am Saturn, Commander of Team Galactic.", + 2: "Our mission is absolute. Any hindrance will be obliterated!", + 3: "Is that fear I see in your eyes?" + }, + "victory": { + 1: "Impossible... Defeated by you?!", + 2: "You have proven yourself a worthy adversary.", + 3: "Bestowed in defeat... This is unacceptable." + }}, + "zinzolin": { + "encounter": { + 1: "You could become a threat to Team Plasma, so we will eliminate you here and now!", + 2: "Oh, for crying out loud... I didn't expect to have to battle in this freezing cold!", + 3: "You're an impressive Trainer to have made it this far. But it ends here." + }, + "victory": { + 1: "Ghetsis... I have failed you...", + 2: "It's bitter cold. I'm shivering. I'm suffering. Yet, I still stand victorious.", + 3: "Hmph. You're a smarter Trainer than I expected, but not smart enough." + } + }, + "rood": { + "encounter": { + 1: "You are a threat to Team Plasma. We cannot let you walk away from here and now!", + 2: "Oh, this icy wind... I never thought I'd have to fight here!", + 3: "You are a remarkable Trainer to have made it this far. But this is where it ends." + }, + "victory": { + 1: "Ghetsis... I have failed my mission...", + 2: "The cold is piercing. I'm shivering. I'm suffering. Yet, I have triumphed.", + 3: "Hm. You are a talented Trainer, but unfortunately not talented enough." + } + }, + "xerosic": { + "encounter": { + 1: "Ah ha ha! It would be my pleasure. Come on, little Trainer! Let's see what you've got!", + 2: "Hmm... You're more powerful than you look. I wonder how much energy there is inside you.", + 3: "I've been waiting for you! I need to do a little research on you! Come, let us begin!" + }, + "victory": { + 1: "Ah, you're quite strong. Oh yes—very strong, indeed.", + 2: "Ding-ding-ding! You did it! To the victor go the spoils!", + 3: "Wonderful! Amazing! You have tremendous skill and bravery!" + } + }, + "bryony": { + "encounter": { + 1: "I am Bryony, and it would be my pleasure to battle you. Show me what you've got.", + 2: "Impressive... You're more powerful than you appear. Let's see the true extent of your energy.", + 3: "I've anticipated your arrival. It's time for a little test. Shall we begin?" + }, + "victory": { + 1: "You're quite strong. Oh yes—very strong, indeed.", + 2: "Ding-ding-ding! You've done well. Victory is yours.", + 3: "Wonderful! Remarkable! Your skill and bravery are commendable." + } + }, "rocket_grunt": { "encounter": { 1: "Prepare for trouble!" @@ -390,18 +587,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "Team Rocket blasting off again!" }, }, - "rocket_admin": { - "encounter": { - 1: "Oh? You managed to get this far? You must be quite the trainer.", - 2: "That's quite enough of you playing hero, kid.", - 3: "I'll show you how scary an angry adult can be!" - }, - "victory": { - 1: "No! Forgive me Giovanni!", - 2: "How could this be?", - 3: "Urgh... You were too strong..." - }, - }, "magma_grunt": { "encounter": { 1: " If you get in the way of Team Magma, don’t expect any mercy!" @@ -410,18 +595,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "Huh? I lost?!" }, }, - "magma_admin": { - "encounter": { - 1: "Hehehe! So you've come all the way here! But you're too late!", - 2: "You're going to meddle in Team Magma's affairs? You're so cute you're disgusting! I'll put you down kiddy!", - 3: "I'm going to give you a little taste of pain! Resign yourself to it!" - }, - "victory": { - 1: "Hehehe... So I lost...", - 2: "You're disgustingly strong!", - 3: "Ahahaha! Ouch!" - }, - }, "aqua_grunt": { "encounter": { 1: "No one who crosses Team Aqua gets any mercy, not even kids!" @@ -430,18 +603,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "You're kidding me!" }, }, - "aqua_admin": { - "encounter": { - 1: "I'm a cut above the grunts you've seen so far. I'm going to puvlerize you!", - 2: "Hahn? What's this? Who's this spoiled brat?", - 3: "What are you doing here? Did you follow us?" - }, - "victory": { - 1: "So I lost too...", - 2: "Ahhh?! Did I go too easy on you?!", - 3: "Wh-what was that?" - }, - }, "galactic_grunt": { "encounter": { 1: "Don't mess with Team Galactic!" @@ -450,18 +611,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "Shut down..." }, }, - "galactic_admin": { - "encounter": { - 1: "I'm one of Team Galactic's Commanders.", - 2: "Anything that opposes Team Galactic must be crushed! Even the very thought of opposition will not be tolerated!", - 3: "What's the matter? Don't tell me you're shaking?" - }, - "victory": { - 1: "This can't be?! I lost?! You... you uppity brat!", - 2: "You, my friend, are tough!", - 3: "Losing to some child... Being careless cost me too much." - }, - }, "plasma_grunt": { "encounter": { 1: "We won't tolerate people who have different ideas!" @@ -470,18 +619,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "Plasmaaaaaaaaa!" }, }, - "plasma_sage": { - "encounter": { - 1: "You could become a threat to Team Plasma, so we will eliminate you here!", - 2: "Oh, for crying out loud... I didn't expect to have to fight!", - 3: "You're an impressive Trainer to have made it this far." - }, - "victory": { - 1: "Ghetsis...", - 2: "It's bitter cold. I'm shivering. I'm suffering.", - 3: "Hmph. You're a smarter Trainer than I expected." - }, - }, "flare_grunt": { "encounter": { 1: "Fashion is most important to us!" @@ -490,18 +627,6 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "The future doesn't look bright for me." }, }, - "flare_admin": { - "encounter": { - 1: "Ah ha ha! It would be my pleasure. Come on, little Trainer! Let's see what you've got!", - 2: "Hmm... You're more powerful than you look. I wonder how much energy there is inside you.", - 3: "I've been waiting for you! I need to do a little research on you! Come, let us begin!" - }, - "victory": { - 1: "You're quite strong. Oh yes-very strong, indeed.", - 2: "Ding-ding-ding! Yup, you did it! To the victor goes the spoils!", - 3: "Wonderful! Amazing! You have tremendous skill and bravery!" - }, - }, "rocket_boss_giovanni_1": { "encounter": { 1: "So! I must say, I am impressed you got here!" diff --git a/src/locales/zh_TW/trainers.ts b/src/locales/zh_TW/trainers.ts index 0efae11bbea..48159efd1c6 100644 --- a/src/locales/zh_TW/trainers.ts +++ b/src/locales/zh_TW/trainers.ts @@ -13,6 +13,25 @@ export const titles: SimpleTranslationEntries = { "rival": "勁敵", "professor": "博士", "frontier_brain": "開拓頭腦", + "rocket_boss": "Team Rocket Boss", + "magma_boss": "Team Magma Boss", + "aqua_boss": "Team Aqua Boss", + "galactic_boss": "Team Galactic Boss", + "plasma_boss": "Team Plasma Boss", + "flare_boss": "Team Flare Boss", + + "rocket_admin": "Team Rocket Admin", + "rocket_admin_female": "Team Rocket Admin", + "magma_admin": "Team Magma Admin", + "magma_admin_female": "Team Magma Admin", + "aqua_admin": "Team Aqua Admin", + "aqua_admin_female": "Team Aqua Admin", + "galactic_commander": "Team Galactic Commander", + "galactic_commander_female": "Team Galactic Commander", + "plasma_sage": "Team Plasma Sage", + "plasma_admin": "Team Plasma Admin", + "flare_admin": "Team Flare Admin", + "flare_admin_female": "Team Flare Admin", // Maybe if we add the evil teams we can add "Team Rocket" and "Team Aqua" etc. here as well as "Team Rocket Boss" and "Team Aqua Admin" etc. } as const; @@ -120,32 +139,21 @@ export const trainerClasses: SimpleTranslationEntries = { "workers": "工人組合", "youngster": "短褲小子", "rocket_grunts": "火箭队手下們", - "rocket_admin": "Rocket Admin", - "rocket_admin_female": "Rocket Admin", "magma_grunt": "熔岩队手下", "magma_grunt_female": "熔岩队手下", "magma_grunts": "熔岩队手下們", - "magma_admin": "Magma Admin", - "magma_admin_female": "Magma Admin", "aqua_grunt": "海洋队手下", "aqua_grunt_female": "海洋队手下", "aqua_grunts": "海洋队手下們", - "aqua_admin": "Aqua Admin", - "aqua_admin_female": "Aqua Admin", "galactic_grunt": "银河队手下", "galactic_grunt_female": "银河队手下", "galactic_grunts": "银河队手下們", - "galactic_admin": "Galactic Admin", - "galactic_admin_female": "Galactic Admin", "plasma_grunt": "等离子队手下", "plasma_grunt_female": "等离子队手下", "plasma_grunts": "等离子队手下們", - "plasma_sage": "Plasma Sage", "flare_grunt": "闪焰队手下", "flare_grunt_female": "闪焰队手下", "flare_grunts": "闪焰队手下們", - "flare_admin": "Flare Admin", - "flare_admin_female": "Flare Admin", } as const; // Names of special trainers like gym leaders, elite four, and the champion @@ -331,6 +339,29 @@ export const trainerNames: SimpleTranslationEntries = { "rival": "芬恩", "rival_female": "艾薇", + // Evil Team Admins + "archer": "Archer", + "ariana": "Ariana", + "proton": "Proton", + "petrel": "Petrel", + "tabitha": "Tabitha", + "courtney": "Courtney", + "shelly": "Shelly", + "matt": "Matt", + "mars": "Mars", + "jupiter": "Jupiter", + "saturn": "Saturn", + "zinzolin": "Zinzolin", + "rood": "Rood", + "xerosic": "Xerosic", + "bryony": "Bryony", + + "maxie": "Maxie", + "archie": "Archie", + "cyrus": "Cyrus", + "ghetsis": "Ghetsis", + "lysandre": "Lysandre", + // Double Names "blue_red_double": "青綠 & 赤紅", "red_blue_double": "赤紅 & 青綠", diff --git a/src/system/voucher.ts b/src/system/voucher.ts index 2238a95e690..b06e6e5309e 100644 --- a/src/system/voucher.ts +++ b/src/system/voucher.ts @@ -105,7 +105,7 @@ export function initVouchers() { } const bossTrainerTypes = Object.keys(trainerConfigs) - .filter(tt => trainerConfigs[tt].isBoss && trainerConfigs[tt].getDerivedType() !== TrainerType.RIVAL); + .filter(tt => trainerConfigs[tt].isBoss && trainerConfigs[tt].getDerivedType() !== TrainerType.RIVAL && trainerConfigs[tt].hasVoucher); for (const trainerType of bossTrainerTypes) { const voucherType = trainerConfigs[trainerType].moneyMultiplier < 10 From db3fae118008e49105ae8c908677c113d9884950 Mon Sep 17 00:00:00 2001 From: Chapybara-jp Date: Wed, 7 Aug 2024 16:38:11 +0200 Subject: [PATCH 009/282] [Localization(ja)] Update ability.ts (#3401) - Changed description of Honey Gather, Ball Fetch and Pickup to properly reflect how they function in PokeRogue. --- src/locales/ja/ability.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/locales/ja/ability.ts b/src/locales/ja/ability.ts index d5644e2ba5e..043ca6a53ac 100644 --- a/src/locales/ja/ability.ts +++ b/src/locales/ja/ability.ts @@ -211,7 +211,7 @@ export const ability: AbilityTranslationEntries = { }, pickup: { name: "ものひろい", - description: "相手の 使った 道具を 拾ってくることが ある。 冒険中も 拾ってくる。", + description: "戦闘が 終わったとき 相手の 持った 道具を 一つ 拾ってくることが ある。", }, truant: { name: "なまけ", @@ -471,7 +471,7 @@ export const ability: AbilityTranslationEntries = { }, honeyGather: { name: "みつあつめ", - description: "戦闘が 終わったとき あまいミツを 拾うことが ある。", + description: "戦闘が 終わったとき あまいミツを 拾う。そのあまいミツが 売られて お金を もらう。", }, frisk: { name: "おみとおし", @@ -947,7 +947,7 @@ export const ability: AbilityTranslationEntries = { }, ballFetch: { name: "たまひろい", - description: "道具を 持っていない 場合 1回目に 投げて 失敗 した モンスターボールを 拾ってくる。", + description: "1回目に 投げて 失敗 した モンスターボールを 拾ってくる。", }, cottonDown: { name: "わたげ", From 548bd8978fb9f4bb7699c92c3cb506948011091c Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Wed, 7 Aug 2024 07:59:28 -0700 Subject: [PATCH 010/282] [Move] Add type immunity removal moves (Foresight, Odor Sleuth, Miracle Eye) (#3379) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Update Foresight PR to current beta Implements Foresight, Miracle Eye, and Odor Sleuth * Add placeholder i18n strings * Minor tsdoc updates * Fix placement of evasion level modifier, add tests * Add first batch of translations Co-authored-by: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> Co-authored-by: Lugiad' Co-authored-by: José Ricardo Fleury Oliveira * Second batch of translations Co-authored-by: Enoch Co-authored-by: mercurius-00 <80205689+mercurius-00@users.noreply.github.com> * Add Catalan and Japanese translation placeholder strings * Fix issue caused by merge --------- Co-authored-by: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> Co-authored-by: Lugiad' Co-authored-by: José Ricardo Fleury Oliveira Co-authored-by: Enoch Co-authored-by: mercurius-00 <80205689+mercurius-00@users.noreply.github.com> --- src/data/battler-tags.ts | 45 +++++++++++++++++++ src/data/move.ts | 39 ++++++++++++++-- src/enums/battler-tag-type.ts | 2 + src/field/pokemon.ts | 11 ++++- src/locales/ca-ES/move-trigger.ts | 1 + src/locales/de/move-trigger.ts | 1 + src/locales/en/move-trigger.ts | 1 + src/locales/es/move-trigger.ts | 1 + src/locales/fr/move-trigger.ts | 1 + src/locales/it/move-trigger.ts | 1 + src/locales/ja/move-trigger.ts | 1 + src/locales/ko/move-trigger.ts | 1 + src/locales/pt_BR/move-trigger.ts | 1 + src/locales/zh_CN/move-trigger.ts | 1 + src/locales/zh_TW/move-trigger.ts | 1 + src/test/moves/foresight.test.ts | 72 ++++++++++++++++++++++++++++++ src/test/moves/miracle_eye.test.ts | 51 +++++++++++++++++++++ 17 files changed, 227 insertions(+), 4 deletions(-) create mode 100644 src/test/moves/foresight.test.ts create mode 100644 src/test/moves/miracle_eye.test.ts diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index 4fad0ddbd08..dd5ab8938ae 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -1680,6 +1680,47 @@ export class GulpMissileTag extends BattlerTag { } } +/** + * Tag that makes the target drop all of it type immunities + * and all accuracy checks ignore its evasiveness stat. + * + * Applied by moves: {@linkcode Moves.ODOR_SLEUTH | Odor Sleuth}, + * {@linkcode Moves.MIRACLE_EYE | Miracle Eye} and {@linkcode Moves.FORESIGHT | Foresight}. + * + * @extends BattlerTag + * @see {@linkcode ignoreImmunity} + */ +export class ExposedTag extends BattlerTag { + private defenderType: Type; + private allowedTypes: Type[]; + + constructor(tagType: BattlerTagType, sourceMove: Moves, defenderType: Type, allowedTypes: Type[]) { + super(tagType, BattlerTagLapseType.CUSTOM, 1, sourceMove); + this.defenderType = defenderType; + this.allowedTypes = allowedTypes; + } + + /** + * When given a battler tag or json representing one, load the data for it. + * @param {BattlerTag | any} source A battler tag + */ + loadTag(source: BattlerTag | any): void { + super.loadTag(source); + this.defenderType = source.defenderType as Type; + this.allowedTypes = source.allowedTypes as Type[]; + } + + /** + * @param types {@linkcode Type} of the defending Pokemon + * @param moveType {@linkcode Type} of the move targetting it + * @returns `true` if the move should be allowed to target the defender. + */ + ignoreImmunity(type: Type, moveType: Type): boolean { + return type === this.defenderType && this.allowedTypes.includes(moveType); + } +} + + export function getBattlerTag(tagType: BattlerTagType, turnCount: number, sourceMove: Moves, sourceId: number): BattlerTag { switch (tagType) { case BattlerTagType.RECHARGING: @@ -1801,6 +1842,10 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: number, source return new StockpilingTag(sourceMove); case BattlerTagType.OCTOLOCK: return new OctolockTag(sourceId); + case BattlerTagType.IGNORE_GHOST: + return new ExposedTag(tagType, sourceMove, Type.GHOST, [Type.NORMAL, Type.FIGHTING]); + case BattlerTagType.IGNORE_DARK: + return new ExposedTag(tagType, sourceMove, Type.DARK, [Type.PSYCHIC]); case BattlerTagType.GULP_MISSILE_ARROKUDA: case BattlerTagType.GULP_MISSILE_PIKACHU: return new GulpMissileTag(tagType, sourceMove); diff --git a/src/data/move.ts b/src/data/move.ts index dbb29d4c9d1..589c169805d 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -5979,6 +5979,39 @@ export class ResistLastMoveTypeAttr extends MoveEffectAttr { } } +/** + * Drops the target's immunity to types it is immune to + * and makes its evasiveness be ignored during accuracy + * checks. Used by: {@linkcode Moves.ODOR_SLEUTH | Odor Sleuth}, {@linkcode Moves.MIRACLE_EYE | Miracle Eye} and {@linkcode Moves.FORESIGHT | Foresight} + * + * @extends AddBattlerTagAttr + * @see {@linkcode apply} + */ +export class ExposedMoveAttr extends AddBattlerTagAttr { + constructor(tagType: BattlerTagType) { + super(tagType, false, true); + } + + /** + * Applies {@linkcode ExposedTag} to the target. + * @param user {@linkcode Pokemon} using this move + * @param target {@linkcode Pokemon} target of this move + * @param move {@linkcode Move} being used + * @param args N/A + * @returns `true` if the function succeeds + */ + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { + if (!super.apply(user, target, move, args)) { + return false; + } + + user.scene.queueMessage(i18next.t("moveTriggers:exposedMove", { pokemonName: getPokemonNameWithAffix(user), targetPokemonName: getPokemonNameWithAffix(target)})); + + return true; + } +} + + const unknownTypeCondition: MoveConditionFunc = (user, target, move) => !user.getTypes().includes(Type.UNKNOWN); export type MoveTargetSet = { @@ -6575,7 +6608,7 @@ export function initMoves() { .attr(StatusEffectAttr, StatusEffect.PARALYSIS) .ballBombMove(), new StatusMove(Moves.FORESIGHT, Type.NORMAL, -1, 40, -1, 0, 2) - .unimplemented(), + .attr(ExposedMoveAttr, BattlerTagType.IGNORE_GHOST), new SelfStatusMove(Moves.DESTINY_BOND, Type.GHOST, -1, 5, -1, 0, 2) .ignoresProtect() .attr(DestinyBondAttr), @@ -6935,7 +6968,7 @@ export function initMoves() { .attr(StatChangeAttr, BattleStat.SPATK, -2, true) .attr(HealStatusEffectAttr, true, StatusEffect.FREEZE), new StatusMove(Moves.ODOR_SLEUTH, Type.NORMAL, -1, 40, -1, 0, 3) - .unimplemented(), + .attr(ExposedMoveAttr, BattlerTagType.IGNORE_GHOST), new AttackMove(Moves.ROCK_TOMB, Type.ROCK, MoveCategory.PHYSICAL, 60, 95, 15, 100, 0, 3) .attr(StatChangeAttr, BattleStat.SPD, -1) .makesContact(false), @@ -7045,7 +7078,7 @@ export function initMoves() { .attr(AddArenaTagAttr, ArenaTagType.GRAVITY, 5) .target(MoveTarget.BOTH_SIDES), new StatusMove(Moves.MIRACLE_EYE, Type.PSYCHIC, -1, 40, -1, 0, 4) - .unimplemented(), + .attr(ExposedMoveAttr, BattlerTagType.IGNORE_DARK), new AttackMove(Moves.WAKE_UP_SLAP, Type.FIGHTING, MoveCategory.PHYSICAL, 70, 100, 10, -1, 0, 4) .attr(MovePowerMultiplierAttr, (user, target, move) => targetSleptOrComatoseCondition(user, target, move) ? 2 : 1) .attr(HealStatusEffectAttr, false, StatusEffect.SLEEP), diff --git a/src/enums/battler-tag-type.ts b/src/enums/battler-tag-type.ts index eeba56d6532..405e8cc4822 100644 --- a/src/enums/battler-tag-type.ts +++ b/src/enums/battler-tag-type.ts @@ -63,6 +63,8 @@ export enum BattlerTagType { STOCKPILING = "STOCKPILING", RECEIVE_DOUBLE_DAMAGE = "RECEIVE_DOUBLE_DAMAGE", ALWAYS_GET_HIT = "ALWAYS_GET_HIT", + IGNORE_GHOST = "IGNORE_GHOST", + IGNORE_DARK = "IGNORE_DARK", GULP_MISSILE_ARROKUDA = "GULP_MISSILE_ARROKUDA", GULP_MISSILE_PIKACHU = "GULP_MISSILE_PIKACHU" } diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index ea7acc12588..a53076bc856 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -19,7 +19,7 @@ import { pokemonEvolutions, pokemonPrevolutions, SpeciesFormEvolution, SpeciesEv import { reverseCompatibleTms, tmSpecies, tmPoolTiers } from "../data/tms"; import { DamagePhase, FaintPhase, LearnMovePhase, MoveEffectPhase, ObtainStatusEffectPhase, StatChangePhase, SwitchSummonPhase, ToggleDoublePositionPhase, MoveEndPhase } from "../phases"; import { BattleStat } from "../data/battle-stat"; -import { BattlerTag, BattlerTagLapseType, EncoreTag, GroundedTag, HighestStatBoostTag, TypeImmuneTag, getBattlerTag, SemiInvulnerableTag, TypeBoostTag } from "../data/battler-tags"; +import { BattlerTag, BattlerTagLapseType, EncoreTag, GroundedTag, HighestStatBoostTag, TypeImmuneTag, getBattlerTag, SemiInvulnerableTag, TypeBoostTag, ExposedTag } from "../data/battler-tags"; import { WeatherType } from "../data/weather"; import { TempBattleStat } from "../data/temp-battle-stat"; import { ArenaTagSide, NoCritTag, WeakenMoveScreenTag } from "../data/arena-tag"; @@ -1259,6 +1259,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { if (ignoreImmunity.value) { return 1; } + + const exposedTags = this.findTags(tag => tag instanceof ExposedTag) as ExposedTag[]; + if (exposedTags.some(t => t.ignoreImmunity(defType, moveType))) { + return 1; + } } return getTypeDamageMultiplier(moveType, defType); @@ -1865,6 +1870,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { applyMoveAttrs(IgnoreOpponentStatChangesAttr, this, target, sourceMove, targetEvasionLevel); this.scene.applyModifiers(TempBattleStatBoosterModifier, this.isPlayer(), TempBattleStat.ACC, userAccuracyLevel); + if (target.findTag(t => t instanceof ExposedTag)) { + targetEvasionLevel.value = Math.min(0, targetEvasionLevel.value); + } + const accuracyMultiplier = new Utils.NumberHolder(1); if (userAccuracyLevel.value !== targetEvasionLevel.value) { accuracyMultiplier.value = userAccuracyLevel.value > targetEvasionLevel.value diff --git a/src/locales/ca-ES/move-trigger.ts b/src/locales/ca-ES/move-trigger.ts index 1d9d6459d83..7977cca29d4 100644 --- a/src/locales/ca-ES/move-trigger.ts +++ b/src/locales/ca-ES/move-trigger.ts @@ -59,4 +59,5 @@ export const moveTriggers: SimpleTranslationEntries = { "copyType": "{{pokemonName}}'s type became the same as\n{{targetPokemonName}}'s type!", "suppressAbilities": "{{pokemonName}}'s ability\nwas suppressed!", "swapArenaTags": "{{pokemonName}} swapped the battle effects affecting each side of the field!", + "exposedMove": "{{pokemonName}} identified\n{{targetPokemonName}}!", } as const; diff --git a/src/locales/de/move-trigger.ts b/src/locales/de/move-trigger.ts index 427ec6acbde..e8f3298308a 100644 --- a/src/locales/de/move-trigger.ts +++ b/src/locales/de/move-trigger.ts @@ -59,4 +59,5 @@ export const moveTriggers: SimpleTranslationEntries = { "copyType": "{{pokemonName}} hat den Typ von {{targetPokemonName}} angenommen!", "suppressAbilities": "Die Fähigkeit von {{pokemonName}} wirkt nicht mehr!", "swapArenaTags": "{{pokemonName}} hat die Effekte, die auf den beiden Seiten des Kampffeldes wirken, miteinander getauscht!", + "exposedMove": "{{pokemonName}} erkennt {{targetPokemonName}}!", } as const; diff --git a/src/locales/en/move-trigger.ts b/src/locales/en/move-trigger.ts index 1d9d6459d83..7977cca29d4 100644 --- a/src/locales/en/move-trigger.ts +++ b/src/locales/en/move-trigger.ts @@ -59,4 +59,5 @@ export const moveTriggers: SimpleTranslationEntries = { "copyType": "{{pokemonName}}'s type became the same as\n{{targetPokemonName}}'s type!", "suppressAbilities": "{{pokemonName}}'s ability\nwas suppressed!", "swapArenaTags": "{{pokemonName}} swapped the battle effects affecting each side of the field!", + "exposedMove": "{{pokemonName}} identified\n{{targetPokemonName}}!", } as const; diff --git a/src/locales/es/move-trigger.ts b/src/locales/es/move-trigger.ts index 3ff93997cc2..9fef0194b87 100644 --- a/src/locales/es/move-trigger.ts +++ b/src/locales/es/move-trigger.ts @@ -59,4 +59,5 @@ export const moveTriggers: SimpleTranslationEntries = { "copyType": "{{pokemonName}}'s type\nchanged to match {{targetPokemonName}}'s!", "suppressAbilities": "{{pokemonName}}'s ability\nwas suppressed!", "swapArenaTags": "{{pokemonName}} swapped the battle effects affecting each side of the field!", + "exposedMove": "{{pokemonName}} identified\n{{targetPokemonName}}!", } as const; diff --git a/src/locales/fr/move-trigger.ts b/src/locales/fr/move-trigger.ts index d1fbda50b03..d611e19d61a 100644 --- a/src/locales/fr/move-trigger.ts +++ b/src/locales/fr/move-trigger.ts @@ -59,4 +59,5 @@ export const moveTriggers: SimpleTranslationEntries = { "copyType": "{{pokemonName}} prend le type\nde {{targetPokemonName}} !", "suppressAbilities": "Le talent de {{pokemonName}}\na été rendu inactif !", "swapArenaTags": "Les effets affectant chaque côté du terrain\nont été échangés par {{pokemonName}} !", + "exposedMove": "{{targetPokemonName}} est identifié\npar {{pokemonName}} !", } as const; diff --git a/src/locales/it/move-trigger.ts b/src/locales/it/move-trigger.ts index 60679d844c0..98fd37defc4 100644 --- a/src/locales/it/move-trigger.ts +++ b/src/locales/it/move-trigger.ts @@ -59,4 +59,5 @@ export const moveTriggers: SimpleTranslationEntries = { "copyType": "{{pokemonName}} assume il tipo\ndi {{targetPokemonName}}!", "suppressAbilities": "L’abilità di {{pokemonName}}\nperde ogni efficacia!", "swapArenaTags": "{{pokemonName}} ha invertito gli effetti attivi\nnelle due metà del campo!", + "exposedMove": "{{pokemonName}} identified\n{{targetPokemonName}}!", } as const; diff --git a/src/locales/ja/move-trigger.ts b/src/locales/ja/move-trigger.ts index 720ae5df5a8..c0d06b78bf9 100644 --- a/src/locales/ja/move-trigger.ts +++ b/src/locales/ja/move-trigger.ts @@ -59,4 +59,5 @@ export const moveTriggers: SimpleTranslationEntries = { "copyType": "{{pokemonName}}は {{targetPokemonName}}と\n同じタイプに なった!", "suppressAbilities": "{{pokemonName}}の とくせいが きかなくなった!", "swapArenaTags": "{{pokemonName}}は\nおたがいの ばのこうかを いれかえた!", + "exposedMove": "{{pokemonName}} identified\n{{targetPokemonName}}!", } as const; diff --git a/src/locales/ko/move-trigger.ts b/src/locales/ko/move-trigger.ts index 9ebf08b1017..364cb730889 100644 --- a/src/locales/ko/move-trigger.ts +++ b/src/locales/ko/move-trigger.ts @@ -59,4 +59,5 @@ export const moveTriggers: SimpleTranslationEntries = { "copyType": "{{pokemonName}}[[는]]\n{{targetPokemonName}}[[와]] 같은 타입이 되었다!", "suppressAbilities": "{{pokemonName}}의\n특성이 효과를 발휘하지 못하게 되었다!", "swapArenaTags": "{{pokemonName}}[[는]]\n서로의 필드 효과를 교체했다!", + "exposedMove": "{{pokemonName}}[[는]]\n{{targetPokemonName}}의 정체를 꿰뚫어 보았다!", } as const; diff --git a/src/locales/pt_BR/move-trigger.ts b/src/locales/pt_BR/move-trigger.ts index c6f35d8f6d1..579638b00c3 100644 --- a/src/locales/pt_BR/move-trigger.ts +++ b/src/locales/pt_BR/move-trigger.ts @@ -59,4 +59,5 @@ export const moveTriggers: SimpleTranslationEntries = { "copyType": "O tipo de {{pokemonName}}\nmudou para combinar com {{targetPokemonName}}!", "suppressAbilities": "A habilidade de {{pokemonName}}\nfoi suprimida!", "swapArenaTags": "{{pokemonName}} trocou os efeitos de batalha que afetam cada lado do campo!", + "exposedMove": "{{pokemonName}} identificou\n{{targetPokemonName}}!", } as const; diff --git a/src/locales/zh_CN/move-trigger.ts b/src/locales/zh_CN/move-trigger.ts index 0efe24f76f0..23ded8cfb25 100644 --- a/src/locales/zh_CN/move-trigger.ts +++ b/src/locales/zh_CN/move-trigger.ts @@ -59,4 +59,5 @@ export const moveTriggers: SimpleTranslationEntries = { "copyType": "{{pokemonName}}\n变成了{{targetPokemonName}}的属性!", "suppressAbilities": "{{pokemonName}}的特性\n变得无效了!", "swapArenaTags": "{{pokemonName}}\n交换了双方的场地效果!", + "exposedMove": "{{pokemonName}}识破了\n{{targetPokemonName}}的原型!", } as const; diff --git a/src/locales/zh_TW/move-trigger.ts b/src/locales/zh_TW/move-trigger.ts index 019aa84390c..ea355515f71 100644 --- a/src/locales/zh_TW/move-trigger.ts +++ b/src/locales/zh_TW/move-trigger.ts @@ -59,4 +59,5 @@ export const moveTriggers: SimpleTranslationEntries = { "copyType": "{{pokemonName}}變成了{{targetPokemonName}}的屬性!", "suppressAbilities": "{{pokemonName}}的特性\n變得無效了!", "swapArenaTags": "{{pokemonName}}\n交換了雙方的場地效果!", + "exposedMove": "{{pokemonName}}識破了\n{{targetPokemonName}}的原形!", } as const; diff --git a/src/test/moves/foresight.test.ts b/src/test/moves/foresight.test.ts new file mode 100644 index 00000000000..4a2b4f8af03 --- /dev/null +++ b/src/test/moves/foresight.test.ts @@ -0,0 +1,72 @@ +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; +import Phaser from "phaser"; +import GameManager from "#test/utils/gameManager"; +import { Species } from "#app/enums/species.js"; +import { SPLASH_ONLY } from "../utils/testUtils"; +import { Moves } from "#app/enums/moves.js"; +import { getMovePosition } from "../utils/gameManagerUtils"; +import { MoveEffectPhase } from "#app/phases.js"; + +describe("Internals", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .disableCrits() + .enemySpecies(Species.GASTLY) + .enemyMoveset(SPLASH_ONLY) + .enemyLevel(5) + .starterSpecies(Species.MAGIKARP) + .moveset([Moves.FORESIGHT, Moves.QUICK_ATTACK, Moves.MACH_PUNCH]); + }); + + it("should allow Normal and Fighting moves to hit Ghost types", async () => { + await game.startBattle(); + + const enemy = game.scene.getEnemyPokemon(); + + game.doAttack(getMovePosition(game.scene, 0, Moves.QUICK_ATTACK)); + await game.toNextTurn(); + expect(enemy.hp).toBe(enemy.getMaxHp()); + + game.doAttack(getMovePosition(game.scene, 0, Moves.FORESIGHT)); + await game.toNextTurn(); + game.doAttack(getMovePosition(game.scene, 0, Moves.QUICK_ATTACK)); + await game.toNextTurn(); + + expect(enemy.hp).toBeLessThan(enemy.getMaxHp()); + enemy.hp = enemy.getMaxHp(); + + game.doAttack(getMovePosition(game.scene, 0, Moves.MACH_PUNCH)); + await game.phaseInterceptor.to(MoveEffectPhase); + + expect(enemy.hp).toBeLessThan(enemy.getMaxHp()); + }); + + it("should ignore target's evasiveness boosts", async () => { + game.override.enemyMoveset(Array(4).fill(Moves.MINIMIZE)); + await game.startBattle(); + + const pokemon = game.scene.getPlayerPokemon(); + vi.spyOn(pokemon, "getAccuracyMultiplier"); + + game.doAttack(getMovePosition(game.scene, 0, Moves.FORESIGHT)); + await game.toNextTurn(); + game.doAttack(getMovePosition(game.scene, 0, Moves.QUICK_ATTACK)); + await game.phaseInterceptor.to(MoveEffectPhase); + + expect(pokemon.getAccuracyMultiplier).toHaveReturnedWith(1); + }); +}); diff --git a/src/test/moves/miracle_eye.test.ts b/src/test/moves/miracle_eye.test.ts new file mode 100644 index 00000000000..188c5736fc4 --- /dev/null +++ b/src/test/moves/miracle_eye.test.ts @@ -0,0 +1,51 @@ +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import Phaser from "phaser"; +import GameManager from "#test/utils/gameManager"; +import { Species } from "#app/enums/species.js"; +import { SPLASH_ONLY } from "../utils/testUtils"; +import { Moves } from "#app/enums/moves.js"; +import { getMovePosition } from "../utils/gameManagerUtils"; +import { MoveEffectPhase } from "#app/phases.js"; + +describe("Internals", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .disableCrits() + .enemySpecies(Species.UMBREON) + .enemyMoveset(SPLASH_ONLY) + .enemyLevel(5) + .starterSpecies(Species.MAGIKARP) + .moveset([Moves.MIRACLE_EYE, Moves.CONFUSION]); + }); + + it("should allow Psychic moves to hit Dark types", async () => { + await game.startBattle(); + + const enemy = game.scene.getEnemyPokemon(); + + game.doAttack(getMovePosition(game.scene, 0, Moves.CONFUSION)); + await game.toNextTurn(); + expect(enemy.hp).toBe(enemy.getMaxHp()); + + game.doAttack(getMovePosition(game.scene, 0, Moves.MIRACLE_EYE)); + await game.toNextTurn(); + game.doAttack(getMovePosition(game.scene, 0, Moves.CONFUSION)); + await game.phaseInterceptor.to(MoveEffectPhase); + + expect(enemy.hp).toBeLessThan(enemy.getMaxHp()); + }); +}); From 555d33c16c825a2b417ff634a5e896cee442de76 Mon Sep 17 00:00:00 2001 From: Chapybara-jp Date: Wed, 7 Aug 2024 17:46:39 +0200 Subject: [PATCH 011/282] [Localization(ja)] Update move.ts (#3403) * Update move.ts * Update move.ts --- src/locales/ja/move.ts | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/src/locales/ja/move.ts b/src/locales/ja/move.ts index 31c73a1efe6..1b46e10be3a 100644 --- a/src/locales/ja/move.ts +++ b/src/locales/ja/move.ts @@ -671,7 +671,7 @@ export const move: MoveTranslationEntries = { }, thief: { name: "どろぼう", - effect: "攻撃と 同時に 道具を 盗む。自分が 道具を 持っている 場合は 盗めない。" + effect: "攻撃と 同時に 道具を 盗もうとする。 盗む 可能性は 30%。" }, spiderWeb: { name: "クモのす", @@ -1371,7 +1371,7 @@ export const move: MoveTranslationEntries = { }, covet: { name: "ほしがる", - effect: "かわいく あまえながら 相手に ちかづき 持っている 道具を うばう。" + effect: "かわいく あまえながら 相手に ちかづき 持っている 道具を うばおうとする。 うばう 可能性は 30%。" }, voltTackle: { name: "ボルテッカー", @@ -2927,7 +2927,7 @@ export const move: MoveTranslationEntries = { }, pikaPapow: { name: "ピカピカサンダー", - effect: "ピカチュウの トレーナーへの 大好きな 気持ちが 強いほど 威力が あがる 電撃。 必ず 命中する。" + effect: "トレーナーへの 大好きな 気持ちが 強いほど 威力が あがる 電撃。 必ず 命中する。" }, bouncyBubble: { name: "いきいきバブル", @@ -2975,7 +2975,7 @@ export const move: MoveTranslationEntries = { }, dynamaxCannon: { name: "ダイマックスほう", - effect: "体内で 凝縮した エネルギーを コアから 放って 攻撃する。" + effect: "コアから ビームを 放つ。相手の レベルが 過度に 上がっている 場合は 与える ダメージが 最大 2倍に 増える。" }, snipeShot: { name: "ねらいうち", @@ -3715,23 +3715,23 @@ export const move: MoveTranslationEntries = { }, blazingTorque: { name: "バーンアクセル", - effect: "The user revs their blazing engine into the target. This may also leave the target with a burn." // 説明文がゲームにない(NPC専用) + effect: "メラメラの エンジンを 吹かして 相手に ぶつかる。やけど状態に することが ある。" }, wickedTorque: { name: "ダークアクセル", - effect: "The user revs their engine into the target with malicious intent. This may put the target to sleep." // 説明文がゲームにない(NPC専用) + effect: "悪意で エンジンを 吹かして 相手に ぶつかる。眠り状態に することが ある。" }, noxiousTorque: { name: "ポイズンアクセル", - effect: "The user revs their poisonous engine into the target. This may also poison the target." // 説明文がゲームにない(NPC専用) + effect: "有毒な エンジンを 吹かして 相手に ぶつかる。毒状態に することが ある。" }, combatTorque: { name: "ファイトアクセル", - effect: "The user revs their engine forcefully into the target. This may also leave the target with paralysis." // 説明文がゲームにない(NPC専用) + effect: "力いっぱい エンジンを 吹かして 相手に ぶつかる。まひ状態に することが ある。" }, magicalTorque: { name: "マジカルアクセル", - effect: "The user revs their fae-like engine into the target. This may also confuse the target." // 説明文がゲームにない(NPC専用) + effect: "幻想的な エンジンを 吹かして 相手に ぶつかる。混乱させることが ある。" }, bloodMoon: { name: "ブラッドムーン", From a07d2c57a44361f4ad48e024067c9b7638c0d84d Mon Sep 17 00:00:00 2001 From: flx-sta <50131232+flx-sta@users.noreply.github.com> Date: Wed, 7 Aug 2024 09:23:12 -0700 Subject: [PATCH 012/282] [Refactor] use typescript `strict-null` (#3259) * TS: enable strict-null * fix battle-scene.ts * fix voucher.ts * adapt more files to strict-null * adapt more files to strict-null ( 2) * adapt ability.ts to strict-null * adapt `arena.ts` to strict-null * adapt TagAddedEvent constructor to strict-null * adapt phases.ts.to strict-null * adapt status-effect.ts to strict-null * adapt `account.ts` to strict-null * adapt `configHandler.ts` to strict-null * adapt `ability.ts` to strict-null * adapt `biomes.ts` to strict-null * adapt `challenge.ts` to strict-null * adapt `daily-run.ts` to strict-null * adapt `nature.ts` to strict-null * adapt `pokemon-forms.ts` to strict-null * adapt `tainer-names.ts` to strict-null * adapt `types.ts` to strict-null * adapt `weather.ts` to strict-null * adapt `egg-hatch-phase.ts` to strict-null * adapt `evolution-phase.ts` to strict-null * adapt `pokemon-sprite-sparkle-handler.ts` to strict-null * adapt `evolution-phase.ts` to strict-null * adapt `game-mode.ts` to strict-null * adapt `utils.ts` to strict-null * adapt `voucher-ui-handler.ts` to strict-null * adapt `src/ui/unavailable-modal-ui-handler.ts` to strict-null * adapt `src/ui/ui.ts` to strict-null * adapt `src/ui/ui-theme.ts` to strict-null * adapt `src/ui/title-ui-handler.ts` to strict-null * adapt `src/ui/time-of-day-widget.ts` to strict-null * adapt `src/ui/text.ts` to strict-null * adapt `src/ui/target-select-ui-handler.ts` to strict-null * adapt `src/ui/settings/settings-keyboard-ui-handler.ts` to strict-null * adapt more files to strict-null (3) * adapt more files to strict-null (4) * adapt more files (mostly tests) to strict-null (5) * adapt more files to strict-null (6) * adapt more files to strict-null (7) * Update `src/data/pokemon-evolutions.ts` for strict-null Partial update `src/data/pokemon-species.ts` for strict-null * adapt more files to strict-null (8) * adapt more files to strict-null (9) * Strict some more nulls (still a few errors remaining) * adapt rest of the files to strict-null (9) * fix tests (check for null instead of undefined) * repalce a lot of `??` with bangs And added TODO notice as usual * fix more tests * all tests pass now * fix broken game-loop after trainer battle add some console.warn for missing cases and falling back to default * remove guessed fallback from utils.rgbHexToRgba * add TODO for this.currentBattle = null * adjust getPokemonById() return to include `null` * fix compilation errors * add test for pokemon.trySetStatus * `chanceMultiplier` shouldn't be optional * allow `null` for currentPhase * adjust hasExpSprite logic for no keymatch found * reduce bang usage in account.updateUserInfo() * fix new strict-null issues after merge * fix `strict-null` issues in dropdown.ts and sand_spit.test.ts * fix egg-gacha * adapt gul_missile.test.ts to strict-null * fix move.ts strict-null * fix i18n.ts strict-null * fix strict-null issues * fix baton_pass test after accidentially breaking it * chore: fix compiler errors * revert accidential changes in baton_pass.test.ts --------- Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> --- src/@types/common.ts | 3 + src/account.ts | 12 +- src/battle-scene.ts | 92 ++-- src/battle.ts | 33 +- src/configs/inputs/configHandler.ts | 28 +- src/data/ability.ts | 168 ++++---- src/data/arena-tag.ts | 86 ++-- src/data/battle-anims.ts | 123 +++--- src/data/battler-tags.ts | 53 ++- src/data/berry.ts | 8 +- src/data/biomes.ts | 2 +- src/data/challenge.ts | 11 +- src/data/daily-run.ts | 6 +- src/data/egg.ts | 51 ++- src/data/move.ts | 283 ++++++------ src/data/nature.ts | 4 +- src/data/pokemon-evolutions.ts | 62 +-- src/data/pokemon-forms.ts | 12 +- src/data/pokemon-species.ts | 106 ++--- src/data/status-effect.ts | 8 +- src/data/trainer-config.ts | 23 +- src/data/trainer-names.ts | 12 +- src/data/type.ts | 2 + src/data/weather.ts | 20 +- src/egg-hatch-phase.ts | 10 +- src/events/arena.ts | 4 +- src/evolution-phase.ts | 8 +- src/field/arena.ts | 43 +- src/field/damage-number-handler.ts | 12 +- src/field/pokemon-sprite-sparkle-handler.ts | 2 +- src/field/pokemon.ts | 253 ++++++----- src/field/trainer.ts | 17 +- src/game-mode.ts | 6 +- src/inputs-controller.ts | 20 +- src/loading-scene.ts | 4 +- src/messages.ts | 5 +- src/modifier/modifier-type.ts | 120 +++--- src/modifier/modifier.ts | 61 +-- src/overrides.ts | 12 +- src/phases.ts | 404 +++++++++--------- src/pipelines/sprite.ts | 2 +- src/plugins/i18n.ts | 2 +- src/system/achv.ts | 7 +- src/system/arena-data.ts | 8 +- src/system/game-data.ts | 102 +++-- src/system/modifier-data.ts | 6 +- src/system/pokemon-data.ts | 6 +- src/system/voucher.ts | 7 +- src/test/abilities/battle_bond.test.ts | 12 +- src/test/abilities/disguise.test.ts | 20 +- src/test/abilities/dry_skin.test.ts | 12 +- src/test/abilities/gulp_missile.test.ts | 30 +- src/test/abilities/hustle.test.ts | 10 +- src/test/abilities/ice_face.test.ts | 46 +- src/test/abilities/libero.test.ts | 34 +- src/test/abilities/magic_guard.test.ts | 73 ++-- src/test/abilities/parental_bond.test.ts | 84 ++-- src/test/abilities/pastel_veil.test.ts | 4 +- src/test/abilities/power_construct.test.ts | 10 +- src/test/abilities/protean.test.ts | 34 +- src/test/abilities/quick_draw.test.ts | 12 +- src/test/abilities/sand_spit.test.ts | 2 +- src/test/abilities/sap_sipper.test.ts | 2 +- src/test/abilities/schooling.test.ts | 2 +- src/test/abilities/serene_grace.test.ts | 6 +- src/test/abilities/sheer_force.test.ts | 16 +- src/test/abilities/shield_dust.test.ts | 4 +- src/test/abilities/shields_down.test.ts | 2 +- src/test/abilities/steely_spirit.test.ts | 6 +- src/test/abilities/sweet_veil.test.ts | 2 +- src/test/abilities/unseen_fist.test.ts | 4 +- src/test/abilities/wind_power.test.ts | 10 +- src/test/abilities/wind_rider.test.ts | 14 +- src/test/abilities/zen_mode.test.ts | 2 +- src/test/abilities/zero_to_hero.test.ts | 2 +- src/test/account.spec.ts | 14 +- src/test/achievements/achievement.test.ts | 8 +- src/test/arena/weather_strong_winds.test.ts | 16 +- src/test/battle/battle.test.ts | 12 +- src/test/battle/special_battle.test.ts | 18 +- src/test/battlerTags/octolock.test.ts | 4 +- src/test/battlerTags/stockpiling.test.ts | 10 +- src/test/evolution.test.ts | 4 +- src/test/evolutions/evolutions.test.ts | 6 +- src/test/field/pokemon.test.ts | 31 ++ src/test/final_boss.test.ts | 6 +- src/test/internals.test.ts | 4 +- src/test/items/exp_booster.test.ts | 2 +- src/test/items/leek.test.ts | 8 +- src/test/items/leftovers.test.ts | 2 +- src/test/items/light_ball.test.ts | 8 +- src/test/items/metal_powder.test.ts | 8 +- src/test/items/quick_powder.test.ts | 8 +- src/test/items/scope_lens.test.ts | 2 +- src/test/items/thick_club.test.ts | 12 +- src/test/items/toxic_orb.test.ts | 2 +- src/test/localization/terrain.test.ts | 14 +- src/test/moves/astonish.test.ts | 4 +- src/test/moves/aurora_veil.test.ts | 8 +- src/test/moves/baton_pass.test.ts | 13 +- src/test/moves/beat_up.test.ts | 10 +- src/test/moves/belly_drum.test.ts | 8 +- src/test/moves/ceaseless_edge.test.ts | 4 +- src/test/moves/clangorous_soul.test.ts | 8 +- src/test/moves/double_team.test.ts | 4 +- src/test/moves/dragon_rage.test.ts | 2 +- src/test/moves/dynamax_cannon.test.ts | 10 +- src/test/moves/fillet_away.test.ts | 8 +- src/test/moves/fissure.test.ts | 2 +- src/test/moves/flower_shield.test.ts | 12 +- src/test/moves/foresight.test.ts | 4 +- src/test/moves/fusion_bolt.test.ts | 2 +- src/test/moves/fusion_flare.test.ts | 4 +- src/test/moves/gastro_acid.test.ts | 2 +- src/test/moves/glaive_rush.test.ts | 18 +- src/test/moves/hard_press.test.ts | 6 +- src/test/moves/hyper_beam.test.ts | 4 +- src/test/moves/light_screen.test.ts | 6 +- src/test/moves/lucky_chant.test.ts | 6 +- src/test/moves/make_it_rain.test.ts | 4 +- src/test/moves/miracle_eye.test.ts | 2 +- src/test/moves/purify.test.ts | 8 +- src/test/moves/reflect.test.ts | 6 +- src/test/moves/roost.test.ts | 2 +- src/test/moves/spit_up.test.ts | 24 +- src/test/moves/stockpile.test.ts | 10 +- src/test/moves/swallow.test.ts | 24 +- src/test/moves/tailwind.test.ts | 4 +- src/test/moves/thousand_arrows.test.ts | 8 +- src/test/moves/tidy_up.test.ts | 2 +- src/test/moves/u_turn.test.ts | 20 +- src/test/settingMenu/helpers/menuManip.ts | 6 +- .../settingMenu/rebinding_setting.test.ts | 14 +- src/test/sprites/pokemonSprite.test.ts | 11 +- src/test/ui/starter-select.test.ts | 66 +-- src/test/utils/TextInterceptor.ts | 4 +- src/test/utils/gameManager.ts | 10 +- src/test/utils/gameManagerUtils.ts | 3 +- src/test/utils/inputsHandler.ts | 23 +- src/test/utils/mocks/mockClock.ts | 2 +- src/test/utils/mocks/mockConsoleLog.ts | 4 +- src/test/utils/mocks/mockGameObject.ts | 3 + src/test/utils/mocks/mockTextureManager.ts | 3 +- .../mocks/mocksContainer/mockContainer.ts | 5 +- .../mocks/mocksContainer/mockGraphics.ts | 6 +- .../mocks/mocksContainer/mockRectangle.ts | 6 +- .../utils/mocks/mocksContainer/mockSprite.ts | 6 +- .../utils/mocks/mocksContainer/mockText.ts | 5 +- src/test/utils/overridesHelper.ts | 2 +- src/test/utils/phaseInterceptor.ts | 4 +- src/timed-event-manager.ts | 20 +- src/touch-controls.ts | 4 +- src/ui/ability-bar.ts | 4 +- src/ui/abstact-option-select-ui-handler.ts | 14 +- src/ui/achv-bar.ts | 5 +- src/ui/achvs-ui-handler.ts | 6 +- src/ui/awaitable-ui-handler.ts | 2 +- src/ui/ball-ui-handler.ts | 2 +- src/ui/battle-info.ts | 18 +- src/ui/battle-message-ui-handler.ts | 16 +- src/ui/bgm-bar.ts | 2 +- src/ui/candy-bar.ts | 6 +- src/ui/challenges-select-ui-handler.ts | 12 +- src/ui/command-ui-handler.ts | 2 +- src/ui/daily-run-scoreboard.ts | 4 +- src/ui/dropdown.ts | 10 +- src/ui/egg-gacha-ui-handler.ts | 16 +- src/ui/egg-hatch-scene-handler.ts | 2 +- src/ui/evolution-scene-handler.ts | 2 + src/ui/fight-ui-handler.ts | 8 +- src/ui/filter-bar.ts | 2 +- src/ui/form-modal-ui-handler.ts | 2 +- src/ui/game-stats-ui-handler.ts | 4 +- src/ui/login-form-ui-handler.ts | 2 +- src/ui/menu-ui-handler.ts | 26 +- src/ui/message-ui-handler.ts | 22 +- src/ui/modal-ui-handler.ts | 2 +- src/ui/modifier-select-ui-handler.ts | 21 +- src/ui/move-info-overlay.ts | 4 +- src/ui/party-exp-bar.ts | 4 +- src/ui/party-ui-handler.ts | 38 +- src/ui/pokeball-tray.ts | 2 +- src/ui/pokemon-icon-anim-handler.ts | 14 +- src/ui/pokemon-info-container.ts | 14 +- src/ui/registration-form-ui-handler.ts | 2 +- src/ui/save-slot-select-ui-handler.ts | 26 +- .../settings/abstract-binding-ui-handler.ts | 16 +- .../abstract-control-settings-ui-handler.ts | 16 +- .../settings/abstract-settings-ui-handler.ts | 8 +- src/ui/settings/gamepad-binding-ui-handler.ts | 2 +- .../settings/keyboard-binding-ui-handler.ts | 2 +- .../settings/settings-keyboard-ui-handler.ts | 8 +- src/ui/starter-select-ui-handler.ts | 168 ++++---- src/ui/summary-ui-handler.ts | 125 +++--- src/ui/target-select-ui-handler.ts | 6 +- src/ui/text.ts | 2 +- src/ui/time-of-day-widget.ts | 5 +- src/ui/title-ui-handler.ts | 4 +- src/ui/ui-theme.ts | 2 +- src/ui/ui.ts | 18 +- src/ui/unavailable-modal-ui-handler.ts | 2 +- src/ui/vouchers-ui-handler.ts | 6 +- src/utils.ts | 16 +- tsconfig.json | 2 +- 204 files changed, 2217 insertions(+), 1956 deletions(-) create mode 100644 src/@types/common.ts create mode 100644 src/test/field/pokemon.test.ts create mode 100644 src/test/utils/mocks/mockGameObject.ts diff --git a/src/@types/common.ts b/src/@types/common.ts new file mode 100644 index 00000000000..6868d766008 --- /dev/null +++ b/src/@types/common.ts @@ -0,0 +1,3 @@ +import BattleScene from "#app/battle-scene.js"; + +export type ConditionFn = (scene: BattleScene, args?: any[]) => boolean; diff --git a/src/account.ts b/src/account.ts index 7fd1d208496..6682e3e0b7c 100644 --- a/src/account.ts +++ b/src/account.ts @@ -8,7 +8,7 @@ export interface UserInfo { googleId: string; } -export let loggedInUser: UserInfo = null; +export let loggedInUser: UserInfo | null = null; // This is a random string that is used to identify the client session - unique per session (tab or window) so that the game will only save on the one that the server is expecting export const clientSessionId = Utils.randomString(32); @@ -30,11 +30,13 @@ export function updateUserInfo(): Promise<[boolean, integer]> { loggedInUser.lastSessionSlot = lastSessionSlot; // Migrate old data from before the username was appended [ "data", "sessionData", "sessionData1", "sessionData2", "sessionData3", "sessionData4" ].map(d => { - if (localStorage.hasOwnProperty(d)) { - if (localStorage.hasOwnProperty(`${d}_${loggedInUser.username}`)) { - localStorage.setItem(`${d}_${loggedInUser.username}_bak`, localStorage.getItem(`${d}_${loggedInUser.username}`)); + const lsItem = localStorage.getItem(d); + if (lsItem && !!loggedInUser?.username) { + const lsUserItem = localStorage.getItem(`${d}_${loggedInUser.username}`); + if (lsUserItem) { + localStorage.setItem(`${d}_${loggedInUser.username}_bak`, lsUserItem); } - localStorage.setItem(`${d}_${loggedInUser.username}`, localStorage.getItem(d)); + localStorage.setItem(`${d}_${loggedInUser.username}`, lsItem); localStorage.removeItem(d); } }); diff --git a/src/battle-scene.ts b/src/battle-scene.ts index f54ff92e324..4269edecfaf 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -106,8 +106,8 @@ export default class BattleScene extends SceneBase { public inputController: InputsController; public uiInputs: UiInputs; - public sessionPlayTime: integer = null; - public lastSavePlayTime: integer = null; + public sessionPlayTime: integer | null = null; + public lastSavePlayTime: integer | null = null; public masterVolume: number = 0.5; public bgmVolume: number = 1; public seVolume: number = 1; @@ -192,8 +192,8 @@ export default class BattleScene extends SceneBase { private phaseQueuePrependSpliceIndex: integer; private nextCommandPhaseQueue: Phase[]; - private currentPhase: Phase; - private standbyPhase: Phase; + private currentPhase: Phase | null; + private standbyPhase: Phase | null; public field: Phaser.GameObjects.Container; public fieldUI: Phaser.GameObjects.Container; public charSprite: CharSprite; @@ -213,7 +213,7 @@ export default class BattleScene extends SceneBase { public score: integer; public lockModifierTiers: boolean; public trainer: Phaser.GameObjects.Sprite; - public lastEnemyTrainer: Trainer; + public lastEnemyTrainer: Trainer | null; public currentBattle: Battle; public pokeballCounts: PokeballCounts; public money: integer; @@ -251,7 +251,7 @@ export default class BattleScene extends SceneBase { public spritePipeline: SpritePipeline; private bgm: AnySound; - private bgmResumeTimer: Phaser.Time.TimerEvent; + private bgmResumeTimer: Phaser.Time.TimerEvent | null; private bgmCache: Set = new Set(); private playTimeTimer: Phaser.Time.TimerEvent; @@ -700,7 +700,11 @@ export default class BattleScene extends SceneBase { hasExpSprite(key: string): boolean { const keyMatch = /^pkmn__?(back__)?(shiny__)?(female__)?(\d+)(\-.*?)?(?:_[1-3])?$/g.exec(key); - let k = keyMatch[4]; + if (!keyMatch) { + return false; + } + + let k = keyMatch[4]!; if (keyMatch[2]) { k += "s"; } @@ -723,7 +727,7 @@ export default class BattleScene extends SceneBase { return this.party; } - getPlayerPokemon(): PlayerPokemon { + getPlayerPokemon(): PlayerPokemon | undefined { return this.getPlayerField().find(p => p.isActive()); } @@ -740,7 +744,7 @@ export default class BattleScene extends SceneBase { return this.currentBattle?.enemyParty || []; } - getEnemyPokemon(): EnemyPokemon { + getEnemyPokemon(): EnemyPokemon | undefined { return this.getEnemyField().find(p => p.isActive()); } @@ -782,12 +786,12 @@ export default class BattleScene extends SceneBase { return activeOnly ? this.infoToggles.filter(t => t?.isActive()) : this.infoToggles; } - getPokemonById(pokemonId: integer): Pokemon { + getPokemonById(pokemonId: integer): Pokemon | null { const findInParty = (party: Pokemon[]) => party.find(p => p.id === pokemonId); - return findInParty(this.getParty()) || findInParty(this.getEnemyParty()); + return (findInParty(this.getParty()) || findInParty(this.getEnemyParty())) ?? null; } - addPlayerPokemon(species: PokemonSpecies, level: integer, abilityIndex: integer, formIndex: integer, gender?: Gender, shiny?: boolean, variant?: Variant, ivs?: integer[], nature?: Nature, dataSource?: Pokemon | PokemonData, postProcess?: (playerPokemon: PlayerPokemon) => void): PlayerPokemon { + addPlayerPokemon(species: PokemonSpecies, level: integer, abilityIndex?: integer, formIndex?: integer, gender?: Gender, shiny?: boolean, variant?: Variant, ivs?: integer[], nature?: Nature, dataSource?: Pokemon | PokemonData, postProcess?: (playerPokemon: PlayerPokemon) => void): PlayerPokemon { const pokemon = new PlayerPokemon(this, species, level, abilityIndex, formIndex, gender, shiny, variant, ivs, nature, dataSource); if (postProcess) { postProcess(pokemon); @@ -957,7 +961,8 @@ export default class BattleScene extends SceneBase { p.destroy(); } - this.currentBattle = null; + //@ts-ignore - allowing `null` for currentBattle causes a lot of trouble + this.currentBattle = null; // TODO: resolve ts-ignore this.biomeWaveText.setText(startingWave.toString()); this.biomeWaveText.setVisible(false); @@ -1021,14 +1026,14 @@ export default class BattleScene extends SceneBase { } } - newBattle(waveIndex?: integer, battleType?: BattleType, trainerData?: TrainerData, double?: boolean): Battle { + newBattle(waveIndex?: integer, battleType?: BattleType, trainerData?: TrainerData, double?: boolean): Battle | null { const _startingWave = Overrides.STARTING_WAVE_OVERRIDE || startingWave; const newWaveIndex = waveIndex || ((this.currentBattle?.waveIndex || (_startingWave - 1)) + 1); - let newDouble: boolean; + let newDouble: boolean | undefined; let newBattleType: BattleType; - let newTrainer: Trainer; + let newTrainer: Trainer | undefined; - let battleConfig: FixedBattleConfig = null; + let battleConfig: FixedBattleConfig | null = null; this.resetSeed(newWaveIndex); @@ -1038,7 +1043,7 @@ export default class BattleScene extends SceneBase { battleConfig = this.gameMode.getFixedBattle(newWaveIndex); newDouble = battleConfig.double; newBattleType = battleConfig.battleType; - this.executeWithSeedOffset(() => newTrainer = battleConfig.getTrainer(this), (battleConfig.seedOffsetWaveIndex || newWaveIndex) << 8); + this.executeWithSeedOffset(() => newTrainer = battleConfig?.getTrainer(this), (battleConfig.seedOffsetWaveIndex || newWaveIndex) << 8); if (newTrainer) { this.field.add(newTrainer); } @@ -1078,7 +1083,7 @@ export default class BattleScene extends SceneBase { playerField.forEach(p => applyAbAttrs(DoubleBattleChanceAbAttr, p, null, doubleChance)); newDouble = !Utils.randSeedInt(doubleChance.value); } else if (newBattleType === BattleType.TRAINER) { - newDouble = newTrainer.variant === TrainerVariant.DOUBLE; + newDouble = newTrainer?.variant === TrainerVariant.DOUBLE; } } else if (!battleConfig) { newDouble = !!double; @@ -1309,7 +1314,7 @@ export default class BattleScene extends SceneBase { return 5; } - let isBoss: boolean; + let isBoss: boolean | undefined; if (forceBoss || (species && (species.subLegendary || species.legendary || species.mythical))) { isBoss = true; } else { @@ -1608,7 +1613,7 @@ export default class BattleScene extends SceneBase { randomSpecies(waveIndex: integer, level: integer, fromArenaPool?: boolean, speciesFilter?: PokemonSpeciesFilter, filterAllEvolutions?: boolean): PokemonSpecies { if (fromArenaPool) { - return this.arena.randomSpecies(waveIndex, level,null , getPartyLuckValue(this.party)); + return this.arena.randomSpecies(waveIndex, level, undefined , getPartyLuckValue(this.party)); } const filteredSpecies = speciesFilter ? [...new Set(allSpecies.filter(s => s.isCatchable()).filter(speciesFilter).map(s => { if (!filterAllEvolutions) { @@ -1966,11 +1971,11 @@ export default class BattleScene extends SceneBase { } /* Phase Functions */ - getCurrentPhase(): Phase { + getCurrentPhase(): Phase | null { return this.currentPhase; } - getStandbyPhase(): Phase { + getStandbyPhase(): Phase | null { return this.standbyPhase; } @@ -2048,7 +2053,10 @@ export default class BattleScene extends SceneBase { } if (this.phaseQueuePrepend.length) { while (this.phaseQueuePrepend.length) { - this.phaseQueue.unshift(this.phaseQueuePrepend.pop()); + const poppedPhase = this.phaseQueuePrepend.pop(); + if (poppedPhase) { + this.phaseQueue.unshift(poppedPhase); + } } } if (!this.phaseQueue.length) { @@ -2056,23 +2064,26 @@ export default class BattleScene extends SceneBase { // Clear the conditionalQueue if there are no phases left in the phaseQueue this.conditionalQueue = []; } - this.currentPhase = this.phaseQueue.shift(); + + this.currentPhase = this.phaseQueue.shift() ?? null; // Check if there are any conditional phases queued if (this.conditionalQueue?.length) { // Retrieve the first conditional phase from the queue const conditionalPhase = this.conditionalQueue.shift(); // Evaluate the condition associated with the phase - if (conditionalPhase[0]()) { + if (conditionalPhase?.[0]()) { // If the condition is met, add the phase to the phase queue this.pushPhase(conditionalPhase[1]); - } else { + } else if (conditionalPhase) { // If the condition is not met, re-add the phase back to the front of the conditional queue this.conditionalQueue.unshift(conditionalPhase); + } else { + console.warn("condition phase is undefined/null!", conditionalPhase); } } - this.currentPhase.start(); + this.currentPhase?.start(); } overridePhase(phase: Phase): boolean { @@ -2087,7 +2098,7 @@ export default class BattleScene extends SceneBase { return true; } - findPhase(phaseFilter: (phase: Phase) => boolean): Phase { + findPhase(phaseFilter: (phase: Phase) => boolean): Phase | undefined { return this.phaseQueue.find(phaseFilter); } @@ -2146,7 +2157,7 @@ export default class BattleScene extends SceneBase { * @param promptDelay optional param for MessagePhase constructor * @param defer boolean for which queue to add it to, false -> add to PhaseQueuePrepend, true -> nextCommandPhaseQueue */ - queueMessage(message: string, callbackDelay?: integer, prompt?: boolean, promptDelay?: integer, defer?: boolean) { + queueMessage(message: string, callbackDelay?: integer | null, prompt?: boolean | null, promptDelay?: integer | null, defer?: boolean | null) { const phase = new MessagePhase(this, message, callbackDelay, prompt, promptDelay); if (!defer) { // adds to the end of PhaseQueuePrepend @@ -2182,7 +2193,10 @@ export default class BattleScene extends SceneBase { return Math.floor(moneyValue / 10) * 10; } - addModifier(modifier: Modifier, ignoreUpdate?: boolean, playSound?: boolean, virtual?: boolean, instant?: boolean): Promise { + addModifier(modifier: Modifier | null, ignoreUpdate?: boolean, playSound?: boolean, virtual?: boolean, instant?: boolean): Promise { + if (!modifier) { + return Promise.resolve(false); + } return new Promise(resolve => { let success = false; const soundName = modifier.type.soundName; @@ -2202,7 +2216,7 @@ export default class BattleScene extends SceneBase { } } else if (!virtual) { const defaultModifierType = getDefaultModifierTypeForTier(modifier.type.tier); - this.queueMessage(`The stack for this item is full.\n You will receive ${defaultModifierType.name} instead.`, null, true); + this.queueMessage(`The stack for this item is full.\n You will receive ${defaultModifierType.name} instead.`, undefined, true); return this.addModifier(defaultModifierType.newModifier(), ignoreUpdate, playSound, false, instant).then(success => resolve(success)); } @@ -2302,7 +2316,7 @@ export default class BattleScene extends SceneBase { return new Promise(resolve => { const source = itemModifier.pokemonId ? itemModifier.getPokemon(target.scene) : null; const cancelled = new Utils.BooleanHolder(false); - Utils.executeIf(source && source.isPlayer() !== target.isPlayer(), () => applyAbAttrs(BlockItemTheftAbAttr, source, cancelled)).then(() => { + Utils.executeIf(!!source && source.isPlayer() !== target.isPlayer(), () => applyAbAttrs(BlockItemTheftAbAttr, source! /* checked in condition*/, cancelled)).then(() => { if (cancelled.value) { return resolve(false); } @@ -2383,7 +2397,7 @@ export default class BattleScene extends SceneBase { } party.forEach((enemyPokemon: EnemyPokemon, i: integer) => { - const isBoss = enemyPokemon.isBoss() || (this.currentBattle.battleType === BattleType.TRAINER && this.currentBattle.trainer.config.isBoss); + const isBoss = enemyPokemon.isBoss() || (this.currentBattle.battleType === BattleType.TRAINER && this.currentBattle.trainer?.config.isBoss); let upgradeChance = 32; if (isBoss) { upgradeChance /= 2; @@ -2391,9 +2405,9 @@ export default class BattleScene extends SceneBase { if (isFinalBoss) { upgradeChance /= 8; } - const modifierChance = this.gameMode.getEnemyModifierChance(isBoss); + const modifierChance = this.gameMode.getEnemyModifierChance(isBoss!); // TODO: is this bang correct? let pokemonModifierChance = modifierChance; - if (this.currentBattle.battleType === BattleType.TRAINER) + if (this.currentBattle.battleType === BattleType.TRAINER && this.currentBattle.trainer) pokemonModifierChance = Math.ceil(pokemonModifierChance * this.currentBattle.trainer.getPartyMemberModifierChanceMultiplier(i)); // eslint-disable-line let count = 0; for (let c = 0; c < chances; c++) { @@ -2512,7 +2526,7 @@ export default class BattleScene extends SceneBase { return (player ? this.modifiers : this.enemyModifiers).filter(m => (modifierFilter as ModifierPredicate)(m)); } - findModifier(modifierFilter: ModifierPredicate, player: boolean = true): PersistentModifier { + findModifier(modifierFilter: ModifierPredicate, player: boolean = true): PersistentModifier | undefined { return (player ? this.modifiers : this.enemyModifiers).find(m => (modifierFilter as ModifierPredicate)(m)); } @@ -2548,7 +2562,7 @@ export default class BattleScene extends SceneBase { return appliedModifiers; } - applyModifier(modifierType: Constructor, player: boolean = true, ...args: any[]): PersistentModifier { + applyModifier(modifierType: Constructor, player: boolean = true, ...args: any[]): PersistentModifier | null { const modifiers = (player ? this.modifiers : this.enemyModifiers).filter(m => m instanceof modifierType && m.shouldApply(args)); for (const modifier of modifiers) { if (modifier.apply(args)) { @@ -2635,7 +2649,7 @@ export default class BattleScene extends SceneBase { initFinalBossPhaseTwo(pokemon: Pokemon): void { if (pokemon instanceof EnemyPokemon && pokemon.isBoss() && !pokemon.formIndex && pokemon.bossSegmentIndex < 1) { this.fadeOutBgm(Utils.fixedInt(2000), false); - this.ui.showDialogue(battleSpecDialogue[BattleSpec.FINAL_BOSS].firstStageWin, pokemon.species.name, null, () => { + this.ui.showDialogue(battleSpecDialogue[BattleSpec.FINAL_BOSS].firstStageWin, pokemon.species.name, undefined, () => { this.addEnemyModifier(getModifierType(modifierTypes.MINI_BLACK_HOLE).newModifier(pokemon) as PersistentModifier, false, true); pokemon.generateAndPopulateMoveset(1); this.setFieldScale(0.75); diff --git a/src/battle.ts b/src/battle.ts index 8a1309938f7..0b3b256f3df 100644 --- a/src/battle.ts +++ b/src/battle.ts @@ -39,7 +39,7 @@ export interface TurnCommand { } interface TurnCommands { - [key: integer]: TurnCommand + [key: integer]: TurnCommand | null } export default class Battle { @@ -47,8 +47,8 @@ export default class Battle { public waveIndex: integer; public battleType: BattleType; public battleSpec: BattleSpec; - public trainer: Trainer; - public enemyLevels: integer[]; + public trainer: Trainer | null; + public enemyLevels: integer[] | undefined; public enemyParty: EnemyPokemon[]; public seenEnemyPartyMemberIds: Set; public double: boolean; @@ -62,26 +62,26 @@ export default class Battle { public escapeAttempts: integer; public lastMove: Moves; public battleSeed: string; - private battleSeedState: string; + private battleSeedState: string | null; public moneyScattered: number; - public lastUsedPokeball: PokeballType; + public lastUsedPokeball: PokeballType | null; public playerFaints: number; // The amount of times pokemon on the players side have fainted public enemyFaints: number; // The amount of times pokemon on the enemies side have fainted private rngCounter: integer = 0; - constructor(gameMode: GameMode, waveIndex: integer, battleType: BattleType, trainer: Trainer, double: boolean) { + constructor(gameMode: GameMode, waveIndex: integer, battleType: BattleType, trainer?: Trainer, double?: boolean) { this.gameMode = gameMode; this.waveIndex = waveIndex; this.battleType = battleType; - this.trainer = trainer; + this.trainer = trainer!; //TODO: is this bang correct? this.initBattleSpec(); this.enemyLevels = battleType !== BattleType.TRAINER ? new Array(double ? 2 : 1).fill(null).map(() => this.getLevelForWave()) - : trainer.getPartyLevels(this.waveIndex); + : trainer?.getPartyLevels(this.waveIndex); this.enemyParty = []; this.seenEnemyPartyMemberIds = new Set(); - this.double = double; + this.double = double!; //TODO: is this bang correct? this.enemySwitchCounter = 0; this.turn = 0; this.playerParticipantIds = new Set(); @@ -159,6 +159,7 @@ export default class Battle { addPostBattleLoot(enemyPokemon: EnemyPokemon): void { this.postBattleLoot.push(...enemyPokemon.scene.findModifiers(m => m instanceof PokemonHeldItemModifier && m.pokemonId === enemyPokemon.id && m.isTransferrable, false).map(i => { const ret = i as PokemonHeldItemModifier; + //@ts-ignore - this is awful to fix/change ret.pokemonId = null; return ret; })); @@ -177,7 +178,7 @@ export default class Battle { const userLocale = navigator.language || "en-US"; const formattedMoneyAmount = moneyAmount.value.toLocaleString(userLocale); const message = i18next.t("battle:moneyPickedUp", { moneyAmount: formattedMoneyAmount }); - scene.queueMessage(message, null, true); + scene.queueMessage(message, undefined, true); scene.currentBattle.moneyScattered = 0; } @@ -200,16 +201,16 @@ export default class Battle { scene.updateScoreText(); } - getBgmOverride(scene: BattleScene): string { + getBgmOverride(scene: BattleScene): string | null { const battlers = this.enemyParty.slice(0, this.getBattlerCount()); if (this.battleType === BattleType.TRAINER) { - if (!this.started && this.trainer.config.encounterBgm && this.trainer.getEncounterMessages()?.length) { - return `encounter_${this.trainer.getEncounterBgm()}`; + if (!this.started && this.trainer?.config.encounterBgm && this.trainer?.getEncounterMessages()?.length) { + return `encounter_${this.trainer?.getEncounterBgm()}`; } if (scene.musicPreference === 0) { - return this.trainer.getBattleBgm(); + return this.trainer?.getBattleBgm()!; // TODO: is this bang correct? } else { - return this.trainer.getMixedBattleBgm(); + return this.trainer?.getMixedBattleBgm()!; // TODO: is this bang correct? } } else if (this.gameMode.isClassic && this.waveIndex > 195 && this.battleSpec !== BattleSpec.FINAL_BOSS) { return "end_summit"; @@ -382,7 +383,7 @@ export default class Battle { export class FixedBattle extends Battle { constructor(scene: BattleScene, waveIndex: integer, config: FixedBattleConfig) { - super(scene.gameMode, waveIndex, config.battleType, config.battleType === BattleType.TRAINER ? config.getTrainer(scene) : null, config.double); + super(scene.gameMode, waveIndex, config.battleType, config.battleType === BattleType.TRAINER ? config.getTrainer(scene) : undefined, config.double); if (config.getEnemyParty) { this.enemyParty = config.getEnemyParty(scene); } diff --git a/src/configs/inputs/configHandler.ts b/src/configs/inputs/configHandler.ts index a67c45fd413..45fb033e9fa 100644 --- a/src/configs/inputs/configHandler.ts +++ b/src/configs/inputs/configHandler.ts @@ -20,7 +20,7 @@ export function getKeyWithKeycode(config, keycode) { */ export function getSettingNameWithKeycode(config, keycode) { const key = getKeyWithKeycode(config, keycode); - return config.custom[key]; + return key ? config.custom[key] : null; } /** @@ -32,7 +32,7 @@ export function getSettingNameWithKeycode(config, keycode) { */ export function getIconWithKeycode(config, keycode) { const key = getKeyWithKeycode(config, keycode); - return config.icons[key]; + return key ? config.icons[key] : null; } /** @@ -122,15 +122,21 @@ export function assign(config, settingNameTarget, keycode): boolean { // if it was already bound, we delete the bind if (previousSettingName) { const previousKey = getKeyWithSettingName(config, previousSettingName); - config.custom[previousKey] = -1; + if (previousKey) { + config.custom[previousKey] = -1; + } } // then, we need to delete the current key for this settingName const currentKey = getKeyWithSettingName(config, settingNameTarget); - config.custom[currentKey] = -1; + if (currentKey) { + config.custom[currentKey] = -1; + } // then, the new key is assigned to the new settingName const newKey = getKeyWithKeycode(config, keycode); - config.custom[newKey] = settingNameTarget; + if (newKey) { + config.custom[newKey] = settingNameTarget; + } return true; } @@ -145,8 +151,12 @@ export function swap(config, settingNameTarget, keycode) { const new_key = getKeyWithKeycode(config, keycode); const new_settingName = getSettingNameWithKey(config, new_key); - config.custom[prev_key] = new_settingName; - config.custom[new_key] = prev_settingName; + if (prev_key) { + config.custom[prev_key] = new_settingName; + } + if (new_key) { + config.custom[new_key] = prev_settingName; + } return true; } @@ -161,7 +171,9 @@ export function deleteBind(config, settingName) { if (config.blacklist.includes(key)) { return false; } - config.custom[key] = -1; + if (key) { + config.custom[key] = -1; + } return true; } diff --git a/src/data/ability.ts b/src/data/ability.ts index b483998612e..f4701d3a4e1 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -120,7 +120,7 @@ export class Ability implements Localizable { type AbAttrApplyFunc = (attr: TAttr, passive: boolean) => boolean | Promise; type AbAttrCondition = (pokemon: Pokemon) => boolean; -type PokemonAttackCondition = (user: Pokemon, target: Pokemon, move: Move) => boolean; +type PokemonAttackCondition = (user: Pokemon | null, target: Pokemon | null, move: Move) => boolean; type PokemonDefendCondition = (target: Pokemon, user: Pokemon, move: Move) => boolean; type PokemonStatChangeCondition = (target: Pokemon, statsChanged: BattleStat[], levels: integer) => boolean; @@ -132,11 +132,11 @@ export abstract class AbAttr { this.showAbility = showAbility; } - apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise { + apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder | null, args: any[]): boolean | Promise { return false; } - getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]): string { + getTriggerMessage(_pokemon: Pokemon, _abilityName: string, ..._args: any[]): string | null { return null; } @@ -226,7 +226,7 @@ export class PostBattleInitStatChangeAbAttr extends PostBattleInitAbAttr { } for (const statChangePhase of statChangePhases) { - if (!this.selfTarget && !statChangePhase.getPokemon().summonData) { + if (!this.selfTarget && !statChangePhase.getPokemon()?.summonData) { pokemon.scene.pushPhase(statChangePhase); } else { // TODO: This causes the ability bar to be shown at the wrong time pokemon.scene.unshiftPhase(statChangePhase); @@ -240,7 +240,7 @@ export class PostBattleInitStatChangeAbAttr extends PostBattleInitAbAttr { type PreDefendAbAttrCondition = (pokemon: Pokemon, attacker: Pokemon, move: Move) => boolean; export class PreDefendAbAttr extends AbAttr { - applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise { + applyPreDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move | null, cancelled: Utils.BooleanHolder | null, args: any[]): boolean | Promise { return false; } } @@ -352,14 +352,14 @@ export class PreDefendMoveDamageToOneAbAttr extends ReceivedMoveDamageMultiplier * @see {@linkcode getCondition} */ export class TypeImmunityAbAttr extends PreDefendAbAttr { - private immuneType: Type; - private condition: AbAttrCondition; + private immuneType: Type | null; + private condition: AbAttrCondition | null; - constructor(immuneType: Type, condition?: AbAttrCondition) { + constructor(immuneType: Type | null, condition?: AbAttrCondition) { super(); this.immuneType = immuneType; - this.condition = condition; + this.condition = condition!; // TODO: is this bang correct? } /** @@ -386,7 +386,7 @@ export class TypeImmunityAbAttr extends PreDefendAbAttr { return false; } - getCondition(): AbAttrCondition { + override getCondition(): AbAttrCondition | null { return this.condition; } } @@ -491,7 +491,7 @@ export class NonSuperEffectiveImmunityAbAttr extends TypeImmunityAbAttr { } export class PostDefendAbAttr extends AbAttr { - applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean | Promise { + applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean | Promise { return false; } } @@ -881,7 +881,7 @@ export class EffectSporeAbAttr extends PostDefendContactApplyStatusEffectAbAttr export class PostDefendContactApplyTagChanceAbAttr extends PostDefendAbAttr { private chance: integer; private tagType: BattlerTagType; - private turnCount: integer; + private turnCount: integer | undefined; constructor(chance: integer, tagType: BattlerTagType, turnCount?: integer) { super(); @@ -918,7 +918,7 @@ export class PostDefendCritStatChangeAbAttr extends PostDefendAbAttr { } getCondition(): AbAttrCondition { - return (pokemon: Pokemon) => pokemon.turnData.attacksReceived.length && pokemon.turnData.attacksReceived[pokemon.turnData.attacksReceived.length - 1].critical; + return (pokemon: Pokemon) => pokemon.turnData.attacksReceived.length !== 0 && pokemon.turnData.attacksReceived[pokemon.turnData.attacksReceived.length - 1].critical; } } @@ -1109,7 +1109,7 @@ export class PostStatChangeStatChangeAbAttr extends PostStatChangeAbAttr { } export class PreAttackAbAttr extends AbAttr { - applyPreAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: Move, args: any[]): boolean | Promise { + applyPreAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon | null, move: Move, args: any[]): boolean | Promise { return false; } } @@ -1122,7 +1122,7 @@ export class PreAttackAbAttr extends AbAttr { export class MoveEffectChanceMultiplierAbAttr extends AbAttr { private chanceMultiplier: number; - constructor(chanceMultiplier?: number) { + constructor(chanceMultiplier: number) { super(true); this.chanceMultiplier = chanceMultiplier; } @@ -1503,7 +1503,7 @@ export class FieldMovePowerBoostAbAttr extends AbAttr { this.powerMultiplier = powerMultiplier; } - applyPreAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: Move, args: any[]): boolean { + applyPreAttack(pokemon: Pokemon | null, passive: boolean | null, defender: Pokemon | null, move: Move, args: any[]): boolean { if (this.condition(pokemon, defender, move)) { (args[0] as Utils.NumberHolder).value *= this.powerMultiplier; @@ -1557,14 +1557,14 @@ export class AllyMoveCategoryPowerBoostAbAttr extends FieldMovePowerBoostAbAttr export class BattleStatMultiplierAbAttr extends AbAttr { private battleStat: BattleStat; private multiplier: number; - private condition: PokemonAttackCondition; + private condition: PokemonAttackCondition | null; constructor(battleStat: BattleStat, multiplier: number, condition?: PokemonAttackCondition) { super(false); this.battleStat = battleStat; this.multiplier = multiplier; - this.condition = condition; + this.condition = condition!; // TODO: is this bang correct? } applyBattleStat(pokemon: Pokemon, passive: boolean, battleStat: BattleStat, statValue: Utils.NumberHolder, args: any[]): boolean | Promise { @@ -1593,7 +1593,7 @@ export class PostAttackAbAttr extends AbAttr { * applying the effect of any inherited class. This can be changed by providing a different {@link attackCondition} to the constructor. See {@link ConfusionOnStatusEffectAbAttr} * for an example of an effect that does not require a damaging move. */ - applyPostAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean | Promise { + applyPostAttack(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean | Promise { // When attackRequired is true, we require the move to be an attack move and to deal damage before checking secondary requirements. // If attackRequired is false, we always defer to the secondary requirements. if (this.attackCondition(pokemon, defender, move)) { @@ -1606,18 +1606,18 @@ export class PostAttackAbAttr extends AbAttr { /** * This method is only called after {@link applyPostAttack} has already been applied. Use this for handling checks specific to the ability in question. */ - applyPostAttackAfterMoveTypeCheck(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean | Promise { + applyPostAttackAfterMoveTypeCheck(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean | Promise { return false; } } export class PostAttackStealHeldItemAbAttr extends PostAttackAbAttr { - private stealCondition: PokemonAttackCondition; + private stealCondition: PokemonAttackCondition | null; constructor(stealCondition?: PokemonAttackCondition) { super(); - this.stealCondition = stealCondition; + this.stealCondition = stealCondition!; // TODO: is this bang correct? } applyPostAttackAfterMoveTypeCheck(pokemon: Pokemon, passive: boolean, defender: Pokemon, move: Move, hitResult: HitResult, args: any[]): Promise { @@ -1701,12 +1701,12 @@ export class PostAttackApplyBattlerTagAbAttr extends PostAttackAbAttr { } export class PostDefendStealHeldItemAbAttr extends PostDefendAbAttr { - private condition: PokemonDefendCondition; + private condition: PokemonDefendCondition | null; constructor(condition?: PokemonDefendCondition) { super(); - this.condition = condition; + this.condition = condition!; // TODO: is this bang correct? } applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): Promise { @@ -2197,17 +2197,17 @@ export class PostSummonCopyAbilityAbAttr extends PostSummonAbAttr { } if ( - target.getAbility().hasAttr(UncopiableAbilityAbAttr) && + target!.getAbility().hasAttr(UncopiableAbilityAbAttr) && // Wonder Guard is normally uncopiable so has the attribute, but Trace specifically can copy it - !(pokemon.hasAbility(Abilities.TRACE) && target.getAbility().id === Abilities.WONDER_GUARD) + !(pokemon.hasAbility(Abilities.TRACE) && target!.getAbility().id === Abilities.WONDER_GUARD) ) { return false; } - this.target = target; - this.targetAbilityName = allAbilities[target.getAbility().id].name; - pokemon.summonData.ability = target.getAbility().id; - setAbilityRevealed(target); + this.target = target!; + this.targetAbilityName = allAbilities[target!.getAbility().id].name; + pokemon.summonData.ability = target!.getAbility().id; + setAbilityRevealed(target!); pokemon.updateInfo(); return true; @@ -2254,7 +2254,7 @@ export class PostSummonUserFieldRemoveStatusEffectAbAttr extends PostSummonAbAtt } for (const pokemon of allowedParty) { - if (this.statusEffect.includes(pokemon.status?.effect)) { + if (pokemon.status && this.statusEffect.includes(pokemon.status.effect)) { pokemon.scene.queueMessage(getStatusEffectHealText(pokemon.status.effect, getPokemonNameWithAffix(pokemon))); pokemon.resetStatus(false); pokemon.updateInfo(); @@ -2310,6 +2310,7 @@ export class PostSummonTransformAbAttr extends PostSummonAbAttr { target = targets[0]; } + target = target!; // compiler doesn't know its guranteed to be defined pokemon.summonData.speciesForm = target.getSpeciesForm(); pokemon.summonData.fusionSpeciesForm = target.getFusionSpeciesForm(); pokemon.summonData.ability = target.getAbility().id; @@ -2317,7 +2318,7 @@ export class PostSummonTransformAbAttr extends PostSummonAbAttr { pokemon.summonData.fusionGender = target.getFusionGender(); pokemon.summonData.stats = [ pokemon.stats[Stat.HP] ].concat(target.stats.slice(1)); pokemon.summonData.battleStats = target.summonData.battleStats.slice(0); - pokemon.summonData.moveset = target.getMoveset().map(m => new PokemonMove(m.moveId, m.ppUsed, m.ppUp)); + pokemon.summonData.moveset = target.getMoveset().map(m => new PokemonMove(m!.moveId, m!.ppUsed, m!.ppUp)); // TODO: are those bangs correct? pokemon.summonData.types = target.getTypes(); pokemon.scene.playSound("PRSFX- Transform"); @@ -2364,7 +2365,7 @@ export class PreSwitchOutClearWeatherAbAttr extends PreSwitchOutAbAttr { * @returns {boolean} Returns true if the weather clears, otherwise false. */ applyPreSwitchOut(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise { - const weatherType = pokemon.scene.arena.weather.weatherType; + const weatherType = pokemon.scene.arena.weather?.weatherType; let turnOffWeather = false; // Clear weather only if user's ability matches the weather and no other pokemon has the ability. @@ -2445,18 +2446,18 @@ export class PreSwitchOutFormChangeAbAttr extends PreSwitchOutAbAttr { } export class PreStatChangeAbAttr extends AbAttr { - applyPreStatChange(pokemon: Pokemon, passive: boolean, stat: BattleStat, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise { + applyPreStatChange(pokemon: Pokemon | null, passive: boolean, stat: BattleStat, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise { return false; } } export class ProtectStatAbAttr extends PreStatChangeAbAttr { - private protectedStat: BattleStat; + private protectedStat: BattleStat | null; constructor(protectedStat?: BattleStat) { super(); - this.protectedStat = protectedStat; + this.protectedStat = protectedStat!; // TODO: is this bang correct? } applyPreStatChange(pokemon: Pokemon, passive: boolean, stat: BattleStat, cancelled: Utils.BooleanHolder, args: any[]): boolean { @@ -2472,7 +2473,7 @@ export class ProtectStatAbAttr extends PreStatChangeAbAttr { return i18next.t("abilityTriggers:protectStat", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName, - statName: this.protectedStat !== undefined ? getBattleStatName(this.protectedStat) : i18next.t("battle:stats") + statName: this.protectedStat ? getBattleStatName(this.protectedStat) : i18next.t("battle:stats") }); } } @@ -2512,7 +2513,7 @@ export class ConfusionOnStatusEffectAbAttr extends PostAttackAbAttr { } export class PreSetStatusAbAttr extends AbAttr { - applyPreSetStatus(pokemon: Pokemon, passive: boolean, effect: StatusEffect, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise { + applyPreSetStatus(pokemon: Pokemon, passive: boolean, effect: StatusEffect | undefined, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise { return false; } } @@ -2723,7 +2724,7 @@ export class BlockStatusDamageAbAttr extends AbAttr { * @returns Returns true if status damage is blocked */ apply(pokemon: Pokemon, passive: boolean, cancelled: Utils.BooleanHolder, args: any[]): boolean { - if (this.effects.includes(pokemon.status?.effect)) { + if (pokemon.status && this.effects.includes(pokemon.status.effect)) { cancelled.value = true; return true; } @@ -2762,7 +2763,7 @@ export class IncrementMovePriorityAbAttr extends AbAttr { export class IgnoreContactAbAttr extends AbAttr { } export class PreWeatherEffectAbAttr extends AbAttr { - applyPreWeatherEffect(pokemon: Pokemon, passive: boolean, weather: Weather, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise { + applyPreWeatherEffect(pokemon: Pokemon, passive: boolean, weather: Weather | null, cancelled: Utils.BooleanHolder, args: any[]): boolean | Promise { return false; } } @@ -2793,7 +2794,7 @@ export class SuppressWeatherEffectAbAttr extends PreWeatherEffectAbAttr { constructor(affectsImmutable?: boolean) { super(); - this.affectsImmutable = affectsImmutable; + this.affectsImmutable = affectsImmutable!; // TODO: is this bang correct? } applyPreWeatherEffect(pokemon: Pokemon, passive: boolean, weather: Weather, cancelled: Utils.BooleanHolder, args: any[]): boolean { @@ -2844,7 +2845,7 @@ function getWeatherCondition(...weatherTypes: WeatherType[]): AbAttrCondition { return false; } const weatherType = pokemon.scene.arena.weather?.weatherType; - return weatherType && weatherTypes.indexOf(weatherType) > -1; + return !!weatherType && weatherTypes.indexOf(weatherType) > -1; }; } @@ -2853,15 +2854,15 @@ function getAnticipationCondition(): AbAttrCondition { for (const opponent of pokemon.getOpponents()) { for (const move of opponent.moveset) { // move is super effective - if (move.getMove() instanceof AttackMove && pokemon.getAttackTypeEffectiveness(move.getMove().type, opponent, true) >= 2) { + if (move!.getMove() instanceof AttackMove && pokemon.getAttackTypeEffectiveness(move!.getMove().type, opponent, true) >= 2) { // TODO: is this bang correct? return true; } // move is a OHKO - if (move.getMove().hasAttr(OneHitKOAttr)) { + if (move!.getMove().hasAttr(OneHitKOAttr)) { // TODO: is this bang correct? return true; } // edge case for hidden power, type is computed - if (move.getMove().id === Moves.HIDDEN_POWER) { + if (move!.getMove().id === Moves.HIDDEN_POWER) { // TODO: is this bang correct? const iv_val = Math.floor(((opponent.ivs[Stat.HP] & 1) +(opponent.ivs[Stat.ATK] & 1) * 2 +(opponent.ivs[Stat.DEF] & 1) * 4 @@ -2909,21 +2910,21 @@ export class ForewarnAbAttr extends PostSummonAbAttr { let movePower = 0; for (const opponent of pokemon.getOpponents()) { for (const move of opponent.moveset) { - if (move.getMove() instanceof StatusMove) { + if (move!.getMove() instanceof StatusMove) { // TODO: is this bang correct? movePower = 1; - } else if (move.getMove().hasAttr(OneHitKOAttr)) { + } else if (move!.getMove().hasAttr(OneHitKOAttr)) { // TODO: is this bang correct? movePower = 150; - } else if (move.getMove().id === Moves.COUNTER || move.getMove().id === Moves.MIRROR_COAT || move.getMove().id === Moves.METAL_BURST) { + } else if (move!.getMove().id === Moves.COUNTER || move!.getMove().id === Moves.MIRROR_COAT || move!.getMove().id === Moves.METAL_BURST) { // TODO: are those bangs correct? movePower = 120; - } else if (move.getMove().power === -1) { + } else if (move!.getMove().power === -1) { // TODO: is this bang correct? movePower = 80; } else { - movePower = move.getMove().power; + movePower = move!.getMove().power; // TODO: is this bang correct? } if (movePower > maxPowerSeen) { maxPowerSeen = movePower; - maxMove = move.getName(); + maxMove = move!.getName(); // TODO: is this bang correct? } } } @@ -2984,7 +2985,7 @@ export class PostWeatherLapseAbAttr extends AbAttr { this.weatherTypes = weatherTypes; } - applyPostWeatherLapse(pokemon: Pokemon, passive: boolean, weather: Weather, args: any[]): boolean | Promise { + applyPostWeatherLapse(pokemon: Pokemon, passive: boolean, weather: Weather | null, args: any[]): boolean | Promise { return false; } @@ -3067,7 +3068,7 @@ export class PostTerrainChangeAddBattlerTagAttr extends PostTerrainChangeAbAttr function getTerrainCondition(...terrainTypes: TerrainType[]): AbAttrCondition { return (pokemon: Pokemon) => { const terrainType = pokemon.scene.arena.terrain?.terrainType; - return terrainType && terrainTypes.indexOf(terrainType) > -1; + return !!terrainType && terrainTypes.indexOf(terrainType) > -1; }; } @@ -3099,7 +3100,7 @@ export class PostTurnStatusHealAbAttr extends PostTurnAbAttr { * @returns Returns true if healed from status, false if not */ applyPostTurn(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise { - if (this.effects.includes(pokemon.status?.effect)) { + if (pokemon.status && this.effects.includes(pokemon.status.effect)) { if (!pokemon.isFullHp()) { const scene = pokemon.scene; const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name; @@ -3335,7 +3336,7 @@ export class FetchBallAbAttr extends PostTurnAbAttr { */ applyPostTurn(pokemon: Pokemon, passive: boolean, args: any[]): boolean { const lastUsed = pokemon.scene.currentBattle.lastUsedPokeball; - if (lastUsed !== null && pokemon.isPlayer) { + if (lastUsed !== null && !!pokemon.isPlayer) { pokemon.scene.pokeballCounts[lastUsed]++; pokemon.scene.currentBattle.lastUsedPokeball = null; pokemon.scene.queueMessage(i18next.t("abilityTriggers:fetchBall", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), pokeballName: getPokeballName(lastUsed) })); @@ -3616,7 +3617,8 @@ export class PostBattleLootAbAttr extends PostBattleAbAttr { const postBattleLoot = pokemon.scene.currentBattle.postBattleLoot; if (postBattleLoot.length) { const randItem = Utils.randSeedItem(postBattleLoot); - if (pokemon.scene.tryTransferHeldItemModifier(randItem, pokemon, true, 1, true)) { + //@ts-ignore - TODO see below + if (pokemon.scene.tryTransferHeldItemModifier(randItem, pokemon, true, 1, true)) { // TODO: fix. This is a promise!? postBattleLoot.splice(postBattleLoot.indexOf(randItem), 1); pokemon.scene.queueMessage(i18next.t("abilityTriggers:postBattleLoot", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), itemName: randItem.type.name })); return true; @@ -3648,7 +3650,7 @@ export class PostFaintClearWeatherAbAttr extends PostFaintAbAttr { * @returns {boolean} Returns true if the weather clears, otherwise false. */ applyPostFaint(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { - const weatherType = pokemon.scene.arena.weather.weatherType; + const weatherType = pokemon.scene.arena.weather?.weatherType; let turnOffWeather = false; // Clear weather only if user's ability matches the weather and no other pokemon has the ability. @@ -4120,7 +4122,7 @@ export class BypassSpeedChanceAbAttr extends AbAttr { const turnCommand = pokemon.scene.currentBattle.turnCommands[pokemon.getBattlerIndex()]; const isCommandFight = turnCommand?.command === Command.FIGHT; - const move = allMoves[turnCommand.move?.move]; + const move = turnCommand?.move?.move ?allMoves[turnCommand.move.move] : null; const isDamageMove = move?.category === MoveCategory.PHYSICAL || move?.category === MoveCategory.SPECIAL; if (isCommandFight && isDamageMove) { @@ -4139,14 +4141,14 @@ export class BypassSpeedChanceAbAttr extends AbAttr { async function applyAbAttrsInternal( attrType: Constructor, - pokemon: Pokemon, + pokemon: Pokemon | null, applyFunc: AbAttrApplyFunc, args: any[], showAbilityInstant: boolean = false, quiet: boolean = false, ) { for (const passive of [false, true]) { - if (!pokemon.canApplyAbility(passive)) { + if (!pokemon?.canApplyAbility(passive)) { continue; } @@ -4194,7 +4196,7 @@ async function applyAbAttrsInternal( } } -export function applyAbAttrs(attrType: Constructor, pokemon: Pokemon, cancelled: Utils.BooleanHolder, ...args: any[]): Promise { +export function applyAbAttrs(attrType: Constructor, pokemon: Pokemon, cancelled: Utils.BooleanHolder | null, ...args: any[]): Promise { return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.apply(pokemon, passive, cancelled, args), args); } @@ -4204,13 +4206,13 @@ export function applyPostBattleInitAbAttrs(attrType: Constructor, - pokemon: Pokemon, attacker: Pokemon, move: Move, cancelled: Utils.BooleanHolder, ...args: any[]): Promise { + pokemon: Pokemon, attacker: Pokemon, move: Move | null, cancelled: Utils.BooleanHolder | null, ...args: any[]): Promise { const simulated = args.length > 1 && args[1]; return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreDefend(pokemon, passive, attacker, move, cancelled, args), args, false, simulated); } export function applyPostDefendAbAttrs(attrType: Constructor, - pokemon: Pokemon, attacker: Pokemon, move: Move, hitResult: HitResult, ...args: any[]): Promise { + pokemon: Pokemon, attacker: Pokemon, move: Move, hitResult: HitResult | null, ...args: any[]): Promise { return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostDefend(pokemon, passive, attacker, move, hitResult, args), args); } @@ -4240,12 +4242,12 @@ export function applyFieldBattleStatMultiplierAbAttrs(attrType: Constructor, - pokemon: Pokemon, defender: Pokemon, move: Move, ...args: any[]): Promise { + pokemon: Pokemon, defender: Pokemon | null, move: Move, ...args: any[]): Promise { return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreAttack(pokemon, passive, defender, move, args), args); } export function applyPostAttackAbAttrs(attrType: Constructor, - pokemon: Pokemon, defender: Pokemon, move: Move, hitResult: HitResult, ...args: any[]): Promise { + pokemon: Pokemon, defender: Pokemon, move: Move, hitResult: HitResult | null, ...args: any[]): Promise { return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostAttack(pokemon, passive, defender, move, hitResult, args), args); } @@ -4270,7 +4272,7 @@ export function applyPreSwitchOutAbAttrs(attrType: Constructor, - pokemon: Pokemon, stat: BattleStat, cancelled: Utils.BooleanHolder, ...args: any[]): Promise { + pokemon: Pokemon | null, stat: BattleStat, cancelled: Utils.BooleanHolder, ...args: any[]): Promise { return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreStatChange(pokemon, passive, stat, cancelled, args), args); } @@ -4280,7 +4282,7 @@ export function applyPostStatChangeAbAttrs(attrType: Constructor, - pokemon: Pokemon, effect: StatusEffect, cancelled: Utils.BooleanHolder, ...args: any[]): Promise { + pokemon: Pokemon, effect: StatusEffect | undefined, cancelled: Utils.BooleanHolder, ...args: any[]): Promise { const simulated = args.length > 1 && args[1]; return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreSetStatus(pokemon, passive, effect, cancelled, args), args, false, !simulated); } @@ -4291,7 +4293,7 @@ export function applyPreApplyBattlerTagAbAttrs(attrType: Constructor, - pokemon: Pokemon, weather: Weather, cancelled: Utils.BooleanHolder, ...args: any[]): Promise { + pokemon: Pokemon, weather: Weather | null, cancelled: Utils.BooleanHolder, ...args: any[]): Promise { return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPreWeatherEffect(pokemon, passive, weather, cancelled, args), args, true); } @@ -4306,7 +4308,7 @@ export function applyPostWeatherChangeAbAttrs(attrType: Constructor, - pokemon: Pokemon, weather: Weather, ...args: any[]): Promise { + pokemon: Pokemon, weather: Weather | null, ...args: any[]): Promise { return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostWeatherLapse(pokemon, passive, weather, args), args); } @@ -4595,8 +4597,8 @@ export function initAbilities() { .attr(TypeImmunityStatChangeAbAttr, Type.ELECTRIC, BattleStat.SPD, 1) .ignorable(), new Ability(Abilities.RIVALRY, 4) - .attr(MovePowerBoostAbAttr, (user, target, move) => user.gender !== Gender.GENDERLESS && target.gender !== Gender.GENDERLESS && user.gender === target.gender, 1.25, true) - .attr(MovePowerBoostAbAttr, (user, target, move) => user.gender !== Gender.GENDERLESS && target.gender !== Gender.GENDERLESS && user.gender !== target.gender, 0.75), + .attr(MovePowerBoostAbAttr, (user, target, move) => user?.gender !== Gender.GENDERLESS && target?.gender !== Gender.GENDERLESS && user?.gender === target?.gender, 1.25, true) + .attr(MovePowerBoostAbAttr, (user, target, move) => user?.gender !== Gender.GENDERLESS && target?.gender !== Gender.GENDERLESS && user?.gender !== target?.gender, 0.75), new Ability(Abilities.STEADFAST, 4) .attr(FlinchStatChangeAbAttr, BattleStat.SPD, 1), new Ability(Abilities.SNOW_CLOAK, 4) @@ -4686,7 +4688,8 @@ export function initAbilities() { .attr(IgnoreOpponentStatChangesAbAttr) .ignorable(), new Ability(Abilities.TINTED_LENS, 4) - .attr(DamageBoostAbAttr, 2, (user, target, move) => target.getAttackTypeEffectiveness(move.type, user) <= 0.5), + //@ts-ignore + .attr(DamageBoostAbAttr, 2, (user, target, move) => target.getAttackTypeEffectiveness(move.type, user) <= 0.5), // TODO: fix TS issues new Ability(Abilities.FILTER, 4) .attr(ReceivedMoveDamageMultiplierAbAttr,(target, user, move) => target.getAttackTypeEffectiveness(move.type, user) >= 2, 0.75) .ignorable(), @@ -4768,9 +4771,9 @@ export function initAbilities() { .attr(ReceivedMoveDamageMultiplierAbAttr,(target, user, move) => target.isFullHp(), 0.5) .ignorable(), new Ability(Abilities.TOXIC_BOOST, 5) - .attr(MovePowerBoostAbAttr, (user, target, move) => move.category === MoveCategory.PHYSICAL && (user.status?.effect === StatusEffect.POISON || user.status?.effect === StatusEffect.TOXIC), 1.5), + .attr(MovePowerBoostAbAttr, (user, target, move) => move.category === MoveCategory.PHYSICAL && (user?.status?.effect === StatusEffect.POISON || user?.status?.effect === StatusEffect.TOXIC), 1.5), new Ability(Abilities.FLARE_BOOST, 5) - .attr(MovePowerBoostAbAttr, (user, target, move) => move.category === MoveCategory.SPECIAL && user.status?.effect === StatusEffect.BURN, 1.5), + .attr(MovePowerBoostAbAttr, (user, target, move) => move.category === MoveCategory.SPECIAL && user?.status?.effect === StatusEffect.BURN, 1.5), new Ability(Abilities.HARVEST, 5) .attr( PostTurnLootAbAttr, @@ -4803,7 +4806,8 @@ export function initAbilities() { .attr(WonderSkinAbAttr) .ignorable(), new Ability(Abilities.ANALYTIC, 5) - .attr(MovePowerBoostAbAttr, (user, target, move) => !!target.getLastXMoves(1).find(m => m.turn === target.scene.currentBattle.turn) || user.scene.currentBattle.turnCommands[target.getBattlerIndex()].command !== Command.FIGHT, 1.3), + //@ts-ignore + .attr(MovePowerBoostAbAttr, (user, target, move) => !!target?.getLastXMoves(1).find(m => m.turn === target?.scene.currentBattle.turn) || user.scene.currentBattle.turnCommands[target.getBattlerIndex()].command !== Command.FIGHT, 1.3), // TODO fix TS issues new Ability(Abilities.ILLUSION, 5) .attr(UncopiableAbilityAbAttr) .attr(UnswappableAbilityAbAttr) @@ -4953,7 +4957,7 @@ export function initAbilities() { new Ability(Abilities.WATER_COMPACTION, 7) .attr(PostDefendStatChangeAbAttr, (target, user, move) => move.type === Type.WATER && move.category !== MoveCategory.STATUS, BattleStat.DEF, 2), new Ability(Abilities.MERCILESS, 7) - .attr(ConditionalCritAbAttr, (user, target, move) => target.status?.effect === StatusEffect.TOXIC || target.status?.effect === StatusEffect.POISON), + .attr(ConditionalCritAbAttr, (user, target, move) => target?.status?.effect === StatusEffect.TOXIC || target?.status?.effect === StatusEffect.POISON), new Ability(Abilities.SHIELDS_DOWN, 7) .attr(PostBattleInitFormChangeAbAttr, () => 0) .attr(PostSummonFormChangeAbAttr, p => p.formIndex % 7 + (p.getHpRatio() <= 0.5 ? 7 : 0)) @@ -4965,7 +4969,8 @@ export function initAbilities() { .bypassFaint() .partial(), new Ability(Abilities.STAKEOUT, 7) - .attr(MovePowerBoostAbAttr, (user, target, move) => user.scene.currentBattle.turnCommands[target.getBattlerIndex()].command === Command.POKEMON, 2), + //@ts-ignore + .attr(MovePowerBoostAbAttr, (user, target, move) => user.scene.currentBattle.turnCommands[target.getBattlerIndex()].command === Command.POKEMON, 2), // TODO: fix TS issues new Ability(Abilities.WATER_BUBBLE, 7) .attr(ReceivedTypeDamageMultiplierAbAttr, Type.FIRE, 0.5) .attr(MoveTypePowerBoostAbAttr, Type.WATER, 2) @@ -5105,7 +5110,8 @@ export function initAbilities() { new Ability(Abilities.PRISM_ARMOR, 7) .attr(ReceivedMoveDamageMultiplierAbAttr,(target, user, move) => target.getAttackTypeEffectiveness(move.type, user) >= 2, 0.75), new Ability(Abilities.NEUROFORCE, 7) - .attr(MovePowerBoostAbAttr, (user, target, move) => target.getAttackTypeEffectiveness(move.type, user) >= 2, 1.25), + //@ts-ignore + .attr(MovePowerBoostAbAttr, (user, target, move) => target.getAttackTypeEffectiveness(move.type, user) >= 2, 1.25), // TODO: fix TS issues new Ability(Abilities.INTREPID_SWORD, 8) .attr(PostSummonStatChangeAbAttr, BattleStat.ATK, 1, true) .condition(getOncePerBattleCondition(Abilities.INTREPID_SWORD)), @@ -5192,8 +5198,10 @@ export function initAbilities() { .attr(UserFieldStatusEffectImmunityAbAttr, StatusEffect.POISON, StatusEffect.TOXIC) .ignorable(), new Ability(Abilities.HUNGER_SWITCH, 8) - .attr(PostTurnFormChangeAbAttr, p => p.getFormKey ? 0 : 1) - .attr(PostTurnFormChangeAbAttr, p => p.getFormKey ? 1 : 0) + //@ts-ignore + .attr(PostTurnFormChangeAbAttr, p => p.getFormKey ? 0 : 1) // TODO: fix ts-ignore + //@ts-ignore + .attr(PostTurnFormChangeAbAttr, p => p.getFormKey ? 1 : 0) // TODO: fix ts-ignore .attr(UncopiableAbilityAbAttr) .attr(UnswappableAbilityAbAttr) .attr(NoTransformAbilityAbAttr) diff --git a/src/data/arena-tag.ts b/src/data/arena-tag.ts index 9c846d2f3cb..7c67271b0dc 100644 --- a/src/data/arena-tag.ts +++ b/src/data/arena-tag.ts @@ -25,12 +25,12 @@ export enum ArenaTagSide { export abstract class ArenaTag { public tagType: ArenaTagType; public turnCount: integer; - public sourceMove: Moves; - public sourceId: integer; + public sourceMove?: Moves; + public sourceId?: integer; public side: ArenaTagSide; - constructor(tagType: ArenaTagType, turnCount: integer, sourceMove: Moves, sourceId?: integer, side: ArenaTagSide = ArenaTagSide.BOTH) { + constructor(tagType: ArenaTagType, turnCount: integer, sourceMove: Moves | undefined, sourceId?: integer, side: ArenaTagSide = ArenaTagSide.BOTH) { this.tagType = tagType; this.turnCount = turnCount; this.sourceMove = sourceMove; @@ -56,7 +56,7 @@ export abstract class ArenaTag { return this.turnCount < 1 || !!(--this.turnCount); } - getMoveName(): string { + getMoveName(): string | null { return this.sourceMove ? allMoves[this.sourceMove].name : null; @@ -75,9 +75,14 @@ export class MistTag extends ArenaTag { onAdd(arena: Arena, quiet: boolean = false): void { super.onAdd(arena); - const source = arena.scene.getPokemonById(this.sourceId); - if (!quiet) { - arena.scene.queueMessage(i18next.t("arenaTag:mistOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(source) })); + if (this.sourceId) { + const source = arena.scene.getPokemonById(this.sourceId); + + if (!quiet && source) { + arena.scene.queueMessage(i18next.t("arenaTag:mistOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(source) })); + } else if (!quiet) { + console.warn("Failed to get source for MistTag onAdd"); + } } } @@ -280,8 +285,14 @@ class MatBlockTag extends ConditionalProtectTag { } onAdd(arena: Arena) { - const source = arena.scene.getPokemonById(this.sourceId); - arena.scene.queueMessage(i18next.t("arenaTag:matBlockOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(source) })); + if (this.sourceId) { + const source = arena.scene.getPokemonById(this.sourceId); + if (source) { + arena.scene.queueMessage(i18next.t("arenaTag:matBlockOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(source) })); + } else { + console.warn("Failed to get source for MatBlockTag onAdd"); + } + } } } @@ -328,9 +339,9 @@ export class NoCritTag extends ArenaTag { /** Queues a message upon removing this effect from the field */ onRemove(arena: Arena): void { - const source = arena.scene.getPokemonById(this.sourceId); + const source = arena.scene.getPokemonById(this.sourceId!); // TODO: is this bang correct? arena.scene.queueMessage(i18next.t("arenaTag:noCritOnRemove", { - pokemonNameWithAffix: getPokemonNameWithAffix(source), + pokemonNameWithAffix: getPokemonNameWithAffix(source ?? undefined), moveName: this.getMoveName() })); } @@ -350,10 +361,16 @@ class WishTag extends ArenaTag { } onAdd(arena: Arena): void { - const user = arena.scene.getPokemonById(this.sourceId); - this.battlerIndex = user.getBattlerIndex(); - this.triggerMessage = i18next.t("arenaTag:wishTagOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(user) }); - this.healHp = Math.max(Math.floor(user.getMaxHp() / 2), 1); + if (this.sourceId) { + const user = arena.scene.getPokemonById(this.sourceId); + if (user) { + this.battlerIndex = user.getBattlerIndex(); + this.triggerMessage = i18next.t("arenaTag:wishTagOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(user) }); + this.healHp = Math.max(Math.floor(user.getMaxHp() / 2), 1); + } else { + console.warn("Failed to get source for WishTag onAdd"); + } + } } onRemove(arena: Arena): void { @@ -494,8 +511,8 @@ class SpikesTag extends ArenaTrapTag { onAdd(arena: Arena, quiet: boolean = false): void { super.onAdd(arena); - const source = arena.scene.getPokemonById(this.sourceId); - if (!quiet) { + const source = this.sourceId ? arena.scene.getPokemonById(this.sourceId) : null; + if (!quiet && source) { arena.scene.queueMessage(i18next.t("arenaTag:spikesOnAdd", { moveName: this.getMoveName(), opponentDesc: source.getOpponentDescriptor() })); } } @@ -539,8 +556,8 @@ class ToxicSpikesTag extends ArenaTrapTag { onAdd(arena: Arena, quiet: boolean = false): void { super.onAdd(arena); - const source = arena.scene.getPokemonById(this.sourceId); - if (!quiet) { + const source = this.sourceId ? arena.scene.getPokemonById(this.sourceId) : null; + if (!quiet && source) { arena.scene.queueMessage(i18next.t("arenaTag:toxicSpikesOnAdd", { moveName: this.getMoveName(), opponentDesc: source.getOpponentDescriptor() })); } } @@ -589,7 +606,7 @@ class ToxicSpikesTag extends ArenaTrapTag { class DelayedAttackTag extends ArenaTag { public targetIndex: BattlerIndex; - constructor(tagType: ArenaTagType, sourceMove: Moves, sourceId: integer, targetIndex: BattlerIndex) { + constructor(tagType: ArenaTagType, sourceMove: Moves | undefined, sourceId: integer, targetIndex: BattlerIndex) { super(tagType, 3, sourceMove, sourceId); this.targetIndex = targetIndex; @@ -599,7 +616,7 @@ class DelayedAttackTag extends ArenaTag { const ret = super.lapse(arena); if (!ret) { - arena.scene.unshiftPhase(new MoveEffectPhase(arena.scene, this.sourceId, [ this.targetIndex ], new PokemonMove(this.sourceMove, 0, 0, true))); + arena.scene.unshiftPhase(new MoveEffectPhase(arena.scene, this.sourceId!, [ this.targetIndex ], new PokemonMove(this.sourceMove!, 0, 0, true))); // TODO: are those bangs correct? } return ret; @@ -621,8 +638,8 @@ class StealthRockTag extends ArenaTrapTag { onAdd(arena: Arena, quiet: boolean = false): void { super.onAdd(arena); - const source = arena.scene.getPokemonById(this.sourceId); - if (!quiet) { + const source = this.sourceId ? arena.scene.getPokemonById(this.sourceId) : null; + if (!quiet && source) { arena.scene.queueMessage(i18next.t("arenaTag:stealthRockOnAdd", { opponentDesc: source.getOpponentDescriptor() })); } } @@ -630,7 +647,7 @@ class StealthRockTag extends ArenaTrapTag { getDamageHpRatio(pokemon: Pokemon): number { const effectiveness = pokemon.getAttackTypeEffectiveness(Type.ROCK, undefined, true); - let damageHpRatio: number; + let damageHpRatio: number = 0; switch (effectiveness) { case 0: @@ -696,8 +713,8 @@ class StickyWebTag extends ArenaTrapTag { onAdd(arena: Arena, quiet: boolean = false): void { super.onAdd(arena); - const source = arena.scene.getPokemonById(this.sourceId); - if (!quiet) { + const source = this.sourceId ? arena.scene.getPokemonById(this.sourceId) : null; + if (!quiet && source) { arena.scene.queueMessage(i18next.t("arenaTag:stickyWebOnAdd", { moveName: this.getMoveName(), opponentDesc: source.getOpponentDescriptor() })); } } @@ -735,7 +752,10 @@ export class TrickRoomTag extends ArenaTag { } onAdd(arena: Arena): void { - arena.scene.queueMessage(i18next.t("arenaTag:trickRoomOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(arena.scene.getPokemonById(this.sourceId)) })); + const source = this.sourceId ? arena.scene.getPokemonById(this.sourceId) : null; + if (source) { + arena.scene.queueMessage(i18next.t("arenaTag:trickRoomOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(source) })); + } } onRemove(arena: Arena): void { @@ -782,8 +802,8 @@ class TailwindTag extends ArenaTag { arena.scene.queueMessage(i18next.t(`arenaTag:tailwindOnAdd${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`)); } - const source = arena.scene.getPokemonById(this.sourceId); - const party = source.isPlayer() ? source.scene.getPlayerField() : source.scene.getEnemyField(); + const source = arena.scene.getPokemonById(this.sourceId!); //TODO: this bang is questionable! + const party = (source?.isPlayer() ? source.scene.getPlayerField() : source?.scene.getEnemyField()) ?? []; for (const pokemon of party) { // Apply the CHARGED tag to party members with the WIND_POWER ability @@ -824,7 +844,7 @@ class HappyHourTag extends ArenaTag { } } -export function getArenaTag(tagType: ArenaTagType, turnCount: integer, sourceMove: Moves, sourceId: integer, targetIndex?: BattlerIndex, side: ArenaTagSide = ArenaTagSide.BOTH): ArenaTag { +export function getArenaTag(tagType: ArenaTagType, turnCount: integer, sourceMove: Moves | undefined, sourceId: integer, targetIndex?: BattlerIndex, side: ArenaTagSide = ArenaTagSide.BOTH): ArenaTag | null { switch (tagType) { case ArenaTagType.MIST: return new MistTag(turnCount, sourceId, side); @@ -837,7 +857,7 @@ export function getArenaTag(tagType: ArenaTagType, turnCount: integer, sourceMov case ArenaTagType.CRAFTY_SHIELD: return new CraftyShieldTag(sourceId, side); case ArenaTagType.NO_CRIT: - return new NoCritTag(turnCount, sourceMove, sourceId, side); + return new NoCritTag(turnCount, sourceMove!, sourceId, side); // TODO: is this bang correct? case ArenaTagType.MUD_SPORT: return new MudSportTag(turnCount, sourceId); case ArenaTagType.WATER_SPORT: @@ -848,7 +868,7 @@ export function getArenaTag(tagType: ArenaTagType, turnCount: integer, sourceMov return new ToxicSpikesTag(sourceId, side); case ArenaTagType.FUTURE_SIGHT: case ArenaTagType.DOOM_DESIRE: - return new DelayedAttackTag(tagType, sourceMove, sourceId, targetIndex); + return new DelayedAttackTag(tagType, sourceMove, sourceId, targetIndex!); // TODO:questionable bang case ArenaTagType.WISH: return new WishTag(turnCount, sourceId, side); case ArenaTagType.STEALTH_ROCK: @@ -869,5 +889,7 @@ export function getArenaTag(tagType: ArenaTagType, turnCount: integer, sourceMov return new TailwindTag(turnCount, sourceId, side); case ArenaTagType.HAPPY_HOUR: return new HappyHourTag(turnCount, sourceId, side); + default: + return null; } } diff --git a/src/data/battle-anims.ts b/src/data/battle-anims.ts index d4dbb8ec350..d9fc87c67c7 100644 --- a/src/data/battle-anims.ts +++ b/src/data/battle-anims.ts @@ -128,7 +128,7 @@ export class AnimConfig { for (const fte of Object.keys(frameTimedEvents)) { const timedEvents: AnimTimedEvent[] = []; for (const te of frameTimedEvents[fte]) { - let timedEvent: AnimTimedEvent; + let timedEvent: AnimTimedEvent | undefined; switch (te.eventType) { case "AnimTimedSoundEvent": timedEvent = new AnimTimedSoundEvent(te.frameIndex, te.resourceName, te); @@ -140,7 +140,8 @@ export class AnimConfig { timedEvent = new AnimTimedUpdateBgEvent(te.frameIndex, te.resourceName, te); break; } - timedEvents.push(timedEvent); + + timedEvent && timedEvents.push(timedEvent); } this.frameTimedEvents.set(parseInt(fte), timedEvents); } @@ -330,7 +331,7 @@ class AnimTimedSoundEvent extends AnimTimedEvent { } return Math.ceil((scene.sound.get(this.resourceName).totalDuration * 1000) / 33.33); } else { - return Math.ceil((battleAnim.user.cry(soundConfig).totalDuration * 1000) / 33.33); + return Math.ceil((battleAnim.user!.cry(soundConfig).totalDuration * 1000) / 33.33); // TODO: is the bang behind user correct? } } @@ -441,15 +442,15 @@ class AnimTimedAddBgEvent extends AnimTimedBgEvent { } } -export const moveAnims = new Map(); -export const chargeAnims = new Map(); +export const moveAnims = new Map(); +export const chargeAnims = new Map(); export const commonAnims = new Map(); export function initCommonAnims(scene: BattleScene): Promise { return new Promise(resolve => { const commonAnimNames = Utils.getEnumKeys(CommonAnim); const commonAnimIds = Utils.getEnumValues(CommonAnim); - const commonAnimFetches = []; + const commonAnimFetches: Promise>[] = []; for (let ca = 0; ca < commonAnimIds.length; ca++) { const commonAnimId = commonAnimIds[ca]; commonAnimFetches.push(scene.cachedFetch(`./battle-anims/common-${commonAnimNames[ca].toLowerCase().replace(/\_/g, "-")}.json`) @@ -572,7 +573,7 @@ export function loadMoveAnimAssets(scene: BattleScene, moveIds: Moves[], startLo const chargeAttr = allMoves[moveId].getAttrs(ChargeAttr)[0] || allMoves[moveId].getAttrs(DelayedAttackAttr)[0]; if (chargeAttr) { const moveChargeAnims = chargeAnims.get(chargeAttr.chargeAnim); - moveAnimations.push(moveChargeAnims instanceof AnimConfig ? moveChargeAnims : moveChargeAnims[0]); + moveAnimations.push(moveChargeAnims instanceof AnimConfig ? moveChargeAnims : moveChargeAnims![0]); // TODO: is the bang correct? if (Array.isArray(moveChargeAnims)) { moveAnimations.push(moveChargeAnims[1]); } @@ -668,21 +669,21 @@ interface SpriteCache { } export abstract class BattleAnim { - public user: Pokemon; - public target: Pokemon; + public user: Pokemon | null; + public target: Pokemon | null; public sprites: Phaser.GameObjects.Sprite[]; public bgSprite: Phaser.GameObjects.TileSprite | Phaser.GameObjects.Rectangle; private srcLine: number[]; private dstLine: number[]; - constructor(user: Pokemon, target: Pokemon) { - this.user = user; - this.target = target; + constructor(user?: Pokemon, target?: Pokemon) { + this.user = user!; // TODO: is this bang correct? + this.target = target!; // TODO: is this bang correct? this.sprites = []; } - abstract getAnim(): AnimConfig; + abstract getAnim(): AnimConfig | null; abstract isOppAnim(): boolean; @@ -705,12 +706,12 @@ export abstract class BattleAnim { const user = !isOppAnim ? this.user : this.target; const target = !isOppAnim ? this.target : this.user; - const userInitialX = user.x; - const userInitialY = user.y; - const userHalfHeight = user.getSprite().displayHeight / 2; - const targetInitialX = target.x; - const targetInitialY = target.y; - const targetHalfHeight = target.getSprite().displayHeight / 2; + const userInitialX = user!.x; // TODO: is this bang correct? + const userInitialY = user!.y; // TODO: is this bang correct? + const userHalfHeight = user!.getSprite().displayHeight! / 2; // TODO: is this bang correct? + const targetInitialX = target!.x; // TODO: is this bang correct? + const targetInitialY = target!.y; // TODO: is this bang correct? + const targetHalfHeight = target!.getSprite().displayHeight! / 2; // TODO: is this bang correct? let g = 0; let u = 0; @@ -742,7 +743,7 @@ export abstract class BattleAnim { } const angle = -frame.angle; const key = frame.target === AnimFrameTarget.GRAPHIC ? g++ : frame.target === AnimFrameTarget.USER ? u++ : t++; - ret.get(frame.target).set(key, { x: x, y: y, scaleX: scaleX, scaleY: scaleY, angle: angle }); + ret.get(frame.target)!.set(key, { x: x, y: y, scaleX: scaleX, scaleY: scaleY, angle: angle }); // TODO: is the bang correct? } return ret; @@ -750,10 +751,10 @@ export abstract class BattleAnim { play(scene: BattleScene, callback?: Function) { const isOppAnim = this.isOppAnim(); - const user = !isOppAnim ? this.user : this.target; + const user = !isOppAnim ? this.user! : this.target!; // TODO: are those bangs correct? const target = !isOppAnim ? this.target : this.user; - if (!target.isOnField()) { + if (!target?.isOnField()) { if (callback) { callback(); } @@ -781,7 +782,7 @@ export abstract class BattleAnim { targetSprite.setAlpha(1); targetSprite.pipelineData["tone"] = [ 0.0, 0.0, 0.0, 0.0 ]; targetSprite.setAngle(0); - if (!this.isHideUser()) { + if (!this.isHideUser() && userSprite) { userSprite.setVisible(true); } if (!this.isHideTarget() && (targetSprite !== userSprite || !this.isHideUser())) { @@ -814,20 +815,20 @@ export abstract class BattleAnim { this.srcLine = [ userFocusX, userFocusY, targetFocusX, targetFocusY ]; this.dstLine = [ userInitialX, userInitialY, targetInitialX, targetInitialY ]; - let r = anim.frames.length; + let r = anim!.frames.length; // TODO: is this bang correct? let f = 0; scene.tweens.addCounter({ duration: Utils.getFrameMs(3), - repeat: anim.frames.length, + repeat: anim!.frames.length, // TODO: is this bang correct? onRepeat: () => { if (!f) { userSprite.setVisible(false); targetSprite.setVisible(false); } - const spriteFrames = anim.frames[f]; - const frameData = this.getGraphicFrameData(scene, anim.frames[f]); + const spriteFrames = anim!.frames[f]; // TODO: is the bang correcT? + const frameData = this.getGraphicFrameData(scene, anim!.frames[f]); // TODO: is the bang correct? let u = 0; let t = 0; let g = 0; @@ -840,9 +841,9 @@ export abstract class BattleAnim { const sprites = spriteCache[isUser ? AnimFrameTarget.USER : AnimFrameTarget.TARGET]; const spriteSource = isUser ? userSprite : targetSprite; if ((isUser ? u : t) === sprites.length) { - const sprite = scene.addPokemonSprite(isUser ? user : target, 0, 0, spriteSource.texture, spriteSource.frame.name, true); - [ "spriteColors", "fusionSpriteColors" ].map(k => sprite.pipelineData[k] = (isUser ? user : target).getSprite().pipelineData[k]); - sprite.setPipelineData("spriteKey", (isUser ? user : target).getBattleSpriteKey()); + const sprite = scene.addPokemonSprite(isUser ? user! : target, 0, 0, spriteSource!.texture, spriteSource!.frame.name, true); // TODO: are those bangs correct? + [ "spriteColors", "fusionSpriteColors" ].map(k => sprite.pipelineData[k] = (isUser ? user! : target).getSprite().pipelineData[k]); // TODO: are those bangs correct? + sprite.setPipelineData("spriteKey", (isUser ? user! : target).getBattleSpriteKey()); sprite.setPipelineData("shiny", (isUser ? user : target).shiny); sprite.setPipelineData("variant", (isUser ? user : target).variant); sprite.setPipelineData("ignoreFieldPos", true); @@ -853,7 +854,7 @@ export abstract class BattleAnim { const spriteIndex = isUser ? u++ : t++; const pokemonSprite = sprites[spriteIndex]; - const graphicFrameData = frameData.get(frame.target).get(spriteIndex); + const graphicFrameData = frameData.get(frame.target)!.get(spriteIndex)!; // TODO: are the bangs correct? pokemonSprite.setPosition(graphicFrameData.x, graphicFrameData.y - ((spriteSource.height / 2) * (spriteSource.parentContainer.scale - 1))); pokemonSprite.setAngle(graphicFrameData.angle); @@ -868,7 +869,7 @@ export abstract class BattleAnim { } else { const sprites = spriteCache[AnimFrameTarget.GRAPHIC]; if (g === sprites.length) { - const newSprite: Phaser.GameObjects.Sprite = scene.addFieldSprite(0, 0, anim.graphic, 1); + const newSprite: Phaser.GameObjects.Sprite = scene.addFieldSprite(0, 0, anim!.graphic, 1); // TODO: is the bang correct? sprites.push(newSprite); scene.field.add(newSprite); spritePriorities.push(1); @@ -881,7 +882,7 @@ export abstract class BattleAnim { const setSpritePriority = (priority: integer) => { switch (priority) { case 0: - scene.field.moveBelow(moveSprite as Phaser.GameObjects.GameObject, scene.getEnemyPokemon() || scene.getPlayerPokemon()); + scene.field.moveBelow(moveSprite as Phaser.GameObjects.GameObject, scene.getEnemyPokemon() || scene.getPlayerPokemon()!); // TODO: is this bang correct? break; case 1: scene.field.moveTo(moveSprite, scene.field.getAll().length - 1); @@ -892,11 +893,11 @@ export abstract class BattleAnim { if (this.bgSprite) { scene.field.moveAbove(moveSprite as Phaser.GameObjects.GameObject, this.bgSprite); } else { - scene.field.moveBelow(moveSprite as Phaser.GameObjects.GameObject, this.user); + scene.field.moveBelow(moveSprite as Phaser.GameObjects.GameObject, this.user!); // TODO: is this bang correct? } break; case AnimFocus.TARGET: - scene.field.moveBelow(moveSprite as Phaser.GameObjects.GameObject, this.target); + scene.field.moveBelow(moveSprite as Phaser.GameObjects.GameObject, this.target!); // TODO: is this bang correct? break; default: setSpritePriority(1); @@ -906,10 +907,10 @@ export abstract class BattleAnim { case 3: switch (frame.focus) { case AnimFocus.USER: - scene.field.moveAbove(moveSprite as Phaser.GameObjects.GameObject, this.user); + scene.field.moveAbove(moveSprite as Phaser.GameObjects.GameObject, this.user!); // TODO: is this bang correct? break; case AnimFocus.TARGET: - scene.field.moveAbove(moveSprite as Phaser.GameObjects.GameObject, this.target); + scene.field.moveAbove(moveSprite as Phaser.GameObjects.GameObject, this.target!); // TODO: is this bang correct? break; default: setSpritePriority(1); @@ -925,7 +926,7 @@ export abstract class BattleAnim { moveSprite.setFrame(frame.graphicFrame); //console.log(AnimFocus[frame.focus]); - const graphicFrameData = frameData.get(frame.target).get(graphicIndex); + const graphicFrameData = frameData.get(frame.target)!.get(graphicIndex)!; // TODO: are those bangs correct? moveSprite.setPosition(graphicFrameData.x, graphicFrameData.y); moveSprite.setAngle(graphicFrameData.angle); moveSprite.setScale(graphicFrameData.scaleX, graphicFrameData.scaleY); @@ -935,8 +936,8 @@ export abstract class BattleAnim { moveSprite.setBlendMode(frame.blendType === AnimBlendType.NORMAL ? Phaser.BlendModes.NORMAL : frame.blendType === AnimBlendType.ADD ? Phaser.BlendModes.ADD : Phaser.BlendModes.DIFFERENCE); } } - if (anim.frameTimedEvents.has(f)) { - for (const event of anim.frameTimedEvents.get(f)) { + if (anim?.frameTimedEvents.has(f)) { + for (const event of anim.frameTimedEvents.get(f)!) { // TODO: is this bang correct? r = Math.max((anim.frames.length - f) + event.execute(scene, this), r); } } @@ -980,16 +981,16 @@ export abstract class BattleAnim { } export class CommonBattleAnim extends BattleAnim { - public commonAnim: CommonAnim; + public commonAnim: CommonAnim | null; - constructor(commonAnim: CommonAnim, user: Pokemon, target?: Pokemon) { + constructor(commonAnim: CommonAnim | null, user: Pokemon, target?: Pokemon) { super(user, target || user); this.commonAnim = commonAnim; } - getAnim(): AnimConfig { - return commonAnims.get(this.commonAnim); + getAnim(): AnimConfig | null { + return this.commonAnim ? commonAnims.get(this.commonAnim)! : null; // TODO: is this bang correct? } isOppAnim(): boolean { @@ -1009,11 +1010,11 @@ export class MoveAnim extends BattleAnim { getAnim(): AnimConfig { return moveAnims.get(this.move) instanceof AnimConfig ? moveAnims.get(this.move) as AnimConfig - : moveAnims.get(this.move)[this.user.isPlayer() ? 0 : 1] as AnimConfig; + : moveAnims.get(this.move)![this.user?.isPlayer() ? 0 : 1] as AnimConfig; // TODO: is this bang correct? } isOppAnim(): boolean { - return !this.user.isPlayer() && Array.isArray(moveAnims.get(this.move)); + return !this.user?.isPlayer() && Array.isArray(moveAnims.get(this.move)); } protected isHideUser(): boolean { @@ -1035,13 +1036,13 @@ export class MoveChargeAnim extends MoveAnim { } isOppAnim(): boolean { - return !this.user.isPlayer() && Array.isArray(chargeAnims.get(this.chargeAnim)); + return !this.user?.isPlayer() && Array.isArray(chargeAnims.get(this.chargeAnim)); } getAnim(): AnimConfig { return chargeAnims.get(this.chargeAnim) instanceof AnimConfig ? chargeAnims.get(this.chargeAnim) as AnimConfig - : chargeAnims.get(this.chargeAnim)[this.user.isPlayer() ? 0 : 1] as AnimConfig; + : chargeAnims.get(this.chargeAnim)![this.user?.isPlayer() ? 0 : 1] as AnimConfig; // TODO: is this bang correct? } } @@ -1059,19 +1060,19 @@ export async function populateAnims() { moveNameToId[moveName] = move; } - const seNames = [];//(await fs.readdir('./public/audio/se/battle_anims/')).map(se => se.toString()); + const seNames: string[] = [];//(await fs.readdir('./public/audio/se/battle_anims/')).map(se => se.toString()); - const animsData = [];//battleAnimRawData.split('!ruby/array:PBAnimation').slice(1); + const animsData : any[] = [];//battleAnimRawData.split('!ruby/array:PBAnimation').slice(1); // TODO: add a proper type for (let a = 0; a < animsData.length; a++) { const fields = animsData[a].split("@").slice(1); const nameField = fields.find(f => f.startsWith("name: ")); - let isOppMove: boolean; - let commonAnimId: CommonAnim; - let chargeAnimId: ChargeAnim; + let isOppMove: boolean | undefined; + let commonAnimId: CommonAnim | undefined; + let chargeAnimId: ChargeAnim | undefined; if (!nameField.startsWith("name: Move:") && !(isOppMove = nameField.startsWith("name: OppMove:"))) { - const nameMatch = commonNamePattern.exec(nameField); + const nameMatch = commonNamePattern.exec(nameField)!; // TODO: is this bang correct? const name = nameMatch[2].toLowerCase(); if (commonAnimMatchNames.indexOf(name) > -1) { commonAnimId = commonAnimIds[commonAnimMatchNames.indexOf(name)]; @@ -1128,14 +1129,14 @@ export async function populateAnims() { for (let t = 0; t < timingEntries.length; t++) { const timingData = timingEntries[t].replace(/\n/g, " ").replace(/[ ]{2,}/g, " ").replace(/[a-z]+: ! '', /ig, "").replace(/name: (.*?),/, "name: \"$1\",") .replace(/flashColor: !ruby\/object:Color { alpha: ([\d\.]+), blue: ([\d\.]+), green: ([\d\.]+), red: ([\d\.]+)}/, "flashRed: $4, flashGreen: $3, flashBlue: $2, flashAlpha: $1"); - const frameIndex = parseInt(/frame: (\d+)/.exec(timingData)[1]); - let resourceName = /name: "(.*?)"/.exec(timingData)[1].replace("''", ""); - const timingType = parseInt(/timingType: (\d)/.exec(timingData)[1]); - let timedEvent: AnimTimedEvent; + const frameIndex = parseInt(/frame: (\d+)/.exec(timingData)![1]); // TODO: is the bang correct? + let resourceName = /name: "(.*?)"/.exec(timingData)![1].replace("''", ""); // TODO: is the bang correct? + const timingType = parseInt(/timingType: (\d)/.exec(timingData)![1]); // TODO: is the bang correct? + let timedEvent: AnimTimedEvent | undefined; switch (timingType) { case 0: if (resourceName && resourceName.indexOf(".") === -1) { - let ext: string; + let ext: string | undefined; [ "wav", "mp3", "m4a" ].every(e => { if (seNames.indexOf(`${resourceName}.${e}`) > -1) { ext = e; @@ -1162,7 +1163,7 @@ export async function populateAnims() { } const propPattern = /([a-z]+): (.*?)(?:,|\})/ig; let propMatch: RegExpExecArray; - while ((propMatch = propPattern.exec(timingData))) { + while ((propMatch = propPattern.exec(timingData)!)) { // TODO: is this bang correct? const prop = propMatch[1]; let value: any = propMatch[2]; switch (prop) { @@ -1194,7 +1195,7 @@ export async function populateAnims() { if (!anim.frameTimedEvents.has(frameIndex)) { anim.frameTimedEvents.set(frameIndex, []); } - anim.frameTimedEvents.get(frameIndex).push(timedEvent); + anim.frameTimedEvents.get(frameIndex)!.push(timedEvent); // TODO: is this bang correct? } break; case "position": diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index dd5ab8938ae..c25407d0599 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -36,11 +36,11 @@ export class BattlerTag { public sourceMove: Moves; public sourceId?: number; - constructor(tagType: BattlerTagType, lapseType: BattlerTagLapseType | BattlerTagLapseType[], turnCount: number, sourceMove: Moves, sourceId?: number) { + constructor(tagType: BattlerTagType, lapseType: BattlerTagLapseType | BattlerTagLapseType[], turnCount: number, sourceMove?: Moves, sourceId?: number) { this.tagType = tagType; this.lapseTypes = Array.isArray(lapseType) ? lapseType : [ lapseType ]; this.turnCount = turnCount; - this.sourceMove = sourceMove; + this.sourceMove = sourceMove!; // TODO: is this bang correct? this.sourceId = sourceId; } @@ -66,7 +66,7 @@ export class BattlerTag { return false; } - getMoveName(): string { + getMoveName(): string | null { return this.sourceMove ? allMoves[this.sourceMove].name : null; @@ -299,12 +299,12 @@ export class DestinyBondTag extends BattlerTag { if (lapseType !== BattlerTagLapseType.CUSTOM) { return super.lapse(pokemon, lapseType); } - const source = pokemon.scene.getPokemonById(this.sourceId); - if (!source.isFainted()) { + const source = this.sourceId ? pokemon.scene.getPokemonById(this.sourceId) : null; + if (!source?.isFainted()) { return true; } - if (source.getAlly() === pokemon) { + if (source?.getAlly() === pokemon) { return false; } @@ -330,7 +330,19 @@ export class InfatuatedTag extends BattlerTag { } canAdd(pokemon: Pokemon): boolean { - return pokemon.isOppositeGender(pokemon.scene.getPokemonById(this.sourceId)); + if (this.sourceId) { + const pkm = pokemon.scene.getPokemonById(this.sourceId); + + if (pkm) { + return pokemon.isOppositeGender(pkm); + } else { + console.warn("canAdd: this.sourceId is not a valid pokemon id!", this.sourceId); + return false; + } + } else { + console.warn("canAdd: this.sourceId is undefined"); + return false; + } } onAdd(pokemon: Pokemon): void { @@ -339,7 +351,7 @@ export class InfatuatedTag extends BattlerTag { pokemon.scene.queueMessage( i18next.t("battle:battlerTagsInfatuatedOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), - sourcePokemonName: getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId)) + sourcePokemonName: getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId!) ?? undefined) // TODO: is that bang correct? }) ); } @@ -357,7 +369,7 @@ export class InfatuatedTag extends BattlerTag { pokemon.scene.queueMessage( i18next.t("battle:battlerTagsInfatuatedLapse", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), - sourcePokemonName: getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId)) + sourcePokemonName: getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId!) ?? undefined) // TODO: is that bang correct? }) ); pokemon.scene.unshiftPhase(new CommonAnimPhase(pokemon.scene, pokemon.getBattlerIndex(), undefined, CommonAnim.ATTRACT)); @@ -410,7 +422,7 @@ export class SeedTag extends BattlerTag { super.onAdd(pokemon); pokemon.scene.queueMessage(i18next.t("battle:battlerTagsSeededOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) })); - this.sourceIndex = pokemon.scene.getPokemonById(this.sourceId).getBattlerIndex(); + this.sourceIndex = pokemon.scene.getPokemonById(this.sourceId!)!.getBattlerIndex(); // TODO: are those bangs correct? } lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { @@ -556,11 +568,11 @@ export class EncoreTag extends BattlerTag { const movePhase = pokemon.scene.findPhase(m => m instanceof MovePhase && m.pokemon === pokemon); if (movePhase) { - const movesetMove = pokemon.getMoveset().find(m => m.moveId === this.moveId); + const movesetMove = pokemon.getMoveset().find(m => m!.moveId === this.moveId); // TODO: is this bang correct? if (movesetMove) { const lastMove = pokemon.getLastXMoves(1)[0]; pokemon.scene.tryReplacePhase((m => m instanceof MovePhase && m.pokemon === pokemon), - new MovePhase(pokemon.scene, pokemon, lastMove.targets, movesetMove)); + new MovePhase(pokemon.scene, pokemon, lastMove.targets!, movesetMove)); // TODO: is this bang correct? } } } @@ -580,7 +592,7 @@ export class HelpingHandTag extends BattlerTag { onAdd(pokemon: Pokemon): void { pokemon.scene.queueMessage( i18next.t("battle:battlerTagsHelpingHandOnAdd", { - pokemonNameWithAffix: getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId)), + pokemonNameWithAffix: getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId!) ?? undefined), // TODO: is that bang correct? pokemonName: getPokemonNameWithAffix(pokemon) }) ); @@ -800,7 +812,7 @@ export class BindTag extends DamagingTrapTag { getTrapMessage(pokemon: Pokemon): string { return i18next.t("battle:battlerTagsBindOnTrap", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), - sourcePokemonName: getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId)), + sourcePokemonName: getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId!) ?? undefined), // TODO: is that bang correct? moveName: this.getMoveName() }); } @@ -814,7 +826,7 @@ export class WrapTag extends DamagingTrapTag { getTrapMessage(pokemon: Pokemon): string { return i18next.t("battle:battlerTagsWrapOnTrap", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), - sourcePokemonName: getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId)) + sourcePokemonName: getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId!) ?? undefined), // TODO: is that bang correct? }); } } @@ -848,7 +860,7 @@ export class ClampTag extends DamagingTrapTag { getTrapMessage(pokemon: Pokemon): string { return i18next.t("battle:battlerTagsClampOnTrap", { - sourcePokemonNameWithAffix: getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId)), + sourcePokemonNameWithAffix: getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId!) ?? undefined), // TODO: is that bang correct? pokemonName: getPokemonNameWithAffix(pokemon), }); } @@ -895,7 +907,7 @@ export class ThunderCageTag extends DamagingTrapTag { getTrapMessage(pokemon: Pokemon): string { return i18next.t("battle:battlerTagsThunderCageOnTrap", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), - sourcePokemonNameWithAffix: getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId)) + sourcePokemonNameWithAffix: getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId!) ?? undefined), // TODO: is that bang correct? }); } } @@ -908,7 +920,7 @@ export class InfestationTag extends DamagingTrapTag { getTrapMessage(pokemon: Pokemon): string { return i18next.t("battle:battlerTagsInfestationOnTrap", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), - sourcePokemonNameWithAffix: getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId)) + sourcePokemonNameWithAffix: getPokemonNameWithAffix(pokemon.scene.getPokemonById(this.sourceId!) ?? undefined), // TODO: is that bang correct? }); } } @@ -1242,6 +1254,7 @@ export class HighestStatBoostTag extends AbilityBattlerTag { return highestValue; }, 0); + highestStat = highestStat!; // tell TS compiler it's defined! this.stat = highestStat; switch (this.stat) { @@ -1427,7 +1440,7 @@ export class SaltCuredTag extends BattlerTag { super.onAdd(pokemon); pokemon.scene.queueMessage(i18next.t("battle:battlerTagsSaltCuredOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) })); - this.sourceIndex = pokemon.scene.getPokemonById(this.sourceId).getBattlerIndex(); + this.sourceIndex = pokemon.scene.getPokemonById(this.sourceId!)!.getBattlerIndex(); // TODO: are those bangs correct? } lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { @@ -1474,7 +1487,7 @@ export class CursedTag extends BattlerTag { onAdd(pokemon: Pokemon): void { super.onAdd(pokemon); - this.sourceIndex = pokemon.scene.getPokemonById(this.sourceId).getBattlerIndex(); + this.sourceIndex = pokemon.scene.getPokemonById(this.sourceId!)!.getBattlerIndex(); // TODO: are those bangs correct? } lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { diff --git a/src/data/berry.ts b/src/data/berry.ts index 5ca64544544..30b89848452 100644 --- a/src/data/berry.ts +++ b/src/data/berry.ts @@ -54,7 +54,7 @@ export function getBerryPredicate(berryType: BerryType): BerryPredicate { return (pokemon: Pokemon) => { const threshold = new Utils.NumberHolder(0.25); applyAbAttrs(ReduceBerryUseThresholdAbAttr, pokemon, null, threshold); - return !!pokemon.getMoveset().find(m => !m.getPpRatio()); + return !!pokemon.getMoveset().find(m => !m?.getPpRatio()); }; } } @@ -120,10 +120,10 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc { if (pokemon.battleData) { pokemon.battleData.berriesEaten.push(berryType); } - const ppRestoreMove = pokemon.getMoveset().find(m => !m.getPpRatio()) ? pokemon.getMoveset().find(m => !m.getPpRatio()) : pokemon.getMoveset().find(m => m.getPpRatio() < 1); + const ppRestoreMove = pokemon.getMoveset().find(m => !m?.getPpRatio()) ? pokemon.getMoveset().find(m => !m?.getPpRatio()) : pokemon.getMoveset().find(m => m!.getPpRatio() < 1); // TODO: is this bang correct? if (ppRestoreMove !== undefined) { - ppRestoreMove.ppUsed = Math.max(ppRestoreMove.ppUsed - 10, 0); - pokemon.scene.queueMessage(i18next.t("battle:ppHealBerry", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: ppRestoreMove.getName(), berryName: getBerryName(berryType) })); + ppRestoreMove!.ppUsed = Math.max(ppRestoreMove!.ppUsed - 10, 0); + pokemon.scene.queueMessage(i18next.t("battle:ppHealBerry", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: ppRestoreMove!.getName(), berryName: getBerryName(berryType) })); } }; } diff --git a/src/data/biomes.ts b/src/data/biomes.ts index 479e0994cb6..ed579112249 100644 --- a/src/data/biomes.ts +++ b/src/data/biomes.ts @@ -7705,7 +7705,7 @@ export function initBiomes() { ? pokemonEvolutions[speciesId] : []; - if (!biomeEntries.filter(b => b[0] !== Biome.END).length && !speciesEvolutions.filter(es => !!((pokemonBiomes.find(p => p[0] === es.speciesId))[3] as any[]).filter(b => b[0] !== Biome.END).length).length) { + if (!biomeEntries.filter(b => b[0] !== Biome.END).length && !speciesEvolutions.filter(es => !!((pokemonBiomes.find(p => p[0] === es.speciesId)!)[3] as any[]).filter(b => b[0] !== Biome.END).length).length) { // TODO: is the bang on the `find()` correct? uncatchableSpecies.push(speciesId); } diff --git a/src/data/challenge.ts b/src/data/challenge.ts index 7bea68e36c7..5f17fdedb78 100644 --- a/src/data/challenge.ts +++ b/src/data/challenge.ts @@ -412,7 +412,7 @@ export class SingleGenerationChallenge extends Challenge { const speciesToCheck = [pokemon.speciesId]; while (speciesToCheck.length) { const checking = speciesToCheck.pop(); - if (pokemonEvolutions.hasOwnProperty(checking) && checkPokemonEvolutions) { + if (checking && pokemonEvolutions.hasOwnProperty(checking) && checkPokemonEvolutions) { pokemonEvolutions[checking].forEach(e => { speciesToCheck.push(e.speciesId); generations.push(getPokemonSpecies(e.speciesId).generation); @@ -430,7 +430,7 @@ export class SingleGenerationChallenge extends Challenge { applyPokemonInBattle(pokemon: Pokemon, valid: Utils.BooleanHolder): boolean { const baseGeneration = pokemon.species.speciesId === Species.VICTINI ? 5 : getPokemonSpecies(pokemon.species.speciesId).generation; - const fusionGeneration = pokemon.isFusion() ? pokemon.fusionSpecies.speciesId === Species.VICTINI ? 5 : getPokemonSpecies(pokemon.fusionSpecies.speciesId).generation : 0; + const fusionGeneration = pokemon.isFusion() ? pokemon.fusionSpecies?.speciesId === Species.VICTINI ? 5 : getPokemonSpecies(pokemon.fusionSpecies!.speciesId).generation : 0; // TODO: is the bang on fusionSpecies correct? if (pokemon.isPlayer() && (baseGeneration !== this.value || (pokemon.isFusion() && fusionGeneration !== this.value))) { valid.value = false; return true; @@ -542,13 +542,13 @@ export class SingleTypeChallenge extends Challenge { const speciesToCheck = [pokemon.speciesId]; while (speciesToCheck.length) { const checking = speciesToCheck.pop(); - if (pokemonEvolutions.hasOwnProperty(checking) && checkPokemonEvolutions) { + if (checking && pokemonEvolutions.hasOwnProperty(checking) && checkPokemonEvolutions) { pokemonEvolutions[checking].forEach(e => { speciesToCheck.push(e.speciesId); types.push(getPokemonSpecies(e.speciesId).type1, getPokemonSpecies(e.speciesId).type2); }); } - if (pokemonFormChanges.hasOwnProperty(checking) && checkPokemonForms) { + if (checking && pokemonFormChanges.hasOwnProperty(checking) && checkPokemonForms) { pokemonFormChanges[checking].forEach(f1 => { getPokemonSpecies(checking).forms.forEach(f2 => { if (f1.formKey === f2.formKey) { @@ -568,10 +568,11 @@ export class SingleTypeChallenge extends Challenge { applyPokemonInBattle(pokemon: Pokemon, valid: Utils.BooleanHolder): boolean { if (pokemon.isPlayer() && !pokemon.isOfType(this.value - 1, false, false, true) - && !SingleTypeChallenge.TYPE_OVERRIDES.some(o => o.type === (this.value - 1) && (pokemon.isFusion() && o.fusion ? pokemon.fusionSpecies : pokemon.species).speciesId === o.species)) { + && !SingleTypeChallenge.TYPE_OVERRIDES.some(o => o.type === (this.value - 1) && (pokemon.isFusion() && o.fusion ? pokemon.fusionSpecies! : pokemon.species).speciesId === o.species)) { // TODO: is the bang on fusionSpecies correct? valid.value = false; return true; } + return false; } /** diff --git a/src/data/daily-run.ts b/src/data/daily-run.ts index 4b741b6f473..b7e03b4b189 100644 --- a/src/data/daily-run.ts +++ b/src/data/daily-run.ts @@ -11,15 +11,15 @@ export interface DailyRunConfig { starters: Starter; } -export function fetchDailyRunSeed(): Promise { - return new Promise((resolve, reject) => { +export function fetchDailyRunSeed(): Promise { + return new Promise((resolve, reject) => { Utils.apiFetch("daily/seed").then(response => { if (!response.ok) { resolve(null); return; } return response.text(); - }).then(seed => resolve(seed)) + }).then(seed => resolve(seed!)) // TODO: is this bang correct? .catch(err => reject(err)); }); } diff --git a/src/data/egg.ts b/src/data/egg.ts index cb889951488..9c76591f01b 100644 --- a/src/data/egg.ts +++ b/src/data/egg.ts @@ -140,30 +140,30 @@ export class Egg { constructor(eggOptions?: IEggOptions) { //if (eggOptions.tier && eggOptions.species) throw Error("Error egg can't have species and tier as option. only choose one of them.") - this._sourceType = eggOptions.sourceType ?? undefined; + this._sourceType = eggOptions?.sourceType!; // TODO: is this bang correct? // Ensure _sourceType is defined before invoking rollEggTier(), as it is referenced - this._tier = eggOptions.tier ?? (Overrides.EGG_TIER_OVERRIDE ?? this.rollEggTier()); + this._tier = eggOptions?.tier ?? (Overrides.EGG_TIER_OVERRIDE ?? this.rollEggTier()); // If egg was pulled, check if egg pity needs to override the egg tier - if (eggOptions.pulled) { + if (eggOptions?.pulled) { // Needs this._tier and this._sourceType to work - this.checkForPityTierOverrides(eggOptions.scene); + this.checkForPityTierOverrides(eggOptions.scene!); // TODO: is this bang correct? } - this._id = eggOptions.id ?? Utils.randInt(EGG_SEED, EGG_SEED * this._tier); + this._id = eggOptions?.id ?? Utils.randInt(EGG_SEED, EGG_SEED * this._tier); - this._sourceType = eggOptions.sourceType ?? undefined; - this._hatchWaves = eggOptions.hatchWaves ?? this.getEggTierDefaultHatchWaves(); - this._timestamp = eggOptions.timestamp ?? new Date().getTime(); + this._sourceType = eggOptions?.sourceType ?? undefined; + this._hatchWaves = eggOptions?.hatchWaves ?? this.getEggTierDefaultHatchWaves(); + this._timestamp = eggOptions?.timestamp ?? new Date().getTime(); // First roll shiny and variant so we can filter if species with an variant exist - this._isShiny = eggOptions.isShiny ?? (Overrides.EGG_SHINY_OVERRIDE || this.rollShiny()); - this._variantTier = eggOptions.variantTier ?? (Overrides.EGG_VARIANT_OVERRIDE ?? this.rollVariant()); - this._species = eggOptions.species ?? this.rollSpecies(eggOptions.scene); + this._isShiny = eggOptions?.isShiny ?? (Overrides.EGG_SHINY_OVERRIDE || this.rollShiny()); + this._variantTier = eggOptions?.variantTier ?? (Overrides.EGG_VARIANT_OVERRIDE ?? this.rollVariant()); + this._species = eggOptions?.species ?? this.rollSpecies(eggOptions!.scene!)!; // TODO: Are those bangs correct? - this._overrideHiddenAbility = eggOptions.overrideHiddenAbility ?? false; + this._overrideHiddenAbility = eggOptions?.overrideHiddenAbility ?? false; // Override egg tier and hatchwaves if species was given - if (eggOptions.species) { + if (eggOptions?.species) { this._tier = this.getEggTierFromSpeciesStarterValue(); this._hatchWaves = eggOptions.hatchWaves ?? this.getEggTierDefaultHatchWaves(); } @@ -174,10 +174,10 @@ export class Egg { this._variantTier = VariantTier.COMMON; } // Needs this._tier so it needs to be generated afer the tier override if bought from same species - this._eggMoveIndex = eggOptions.eggMoveIndex ?? this.rollEggMoveIndex(); - if (eggOptions.pulled) { - this.increasePullStatistic(eggOptions.scene); - this.addEggToGameData(eggOptions.scene); + this._eggMoveIndex = eggOptions?.eggMoveIndex ?? this.rollEggMoveIndex(); + if (eggOptions?.pulled) { + this.increasePullStatistic(eggOptions.scene!); // TODO: is this bang correct? + this.addEggToGameData(eggOptions.scene!); // TODO: is this bang correct? } } @@ -202,7 +202,7 @@ export class Egg { // Legacy egg wants to hatch. Generate missing properties if (!this._species) { this._isShiny = this.rollShiny(); - this._species = this.rollSpecies(scene); + this._species = this.rollSpecies(scene!)!; // TODO: are these bangs correct? } let pokemonSpecies = getPokemonSpecies(this._species); @@ -213,7 +213,7 @@ export class Egg { // Sets the hidden ability if a hidden ability exists and the override is set // or if the same species egg hits the chance - let abilityIndex = undefined; + let abilityIndex: number | undefined = undefined; if (pokemonSpecies.abilityHidden && (this._overrideHiddenAbility || (this._sourceType === EggSourceType.SAME_SPECIES_EGG && !Utils.randSeedInt(SAME_SPECIES_EGG_HA_RATE)))) { abilityIndex = 2; @@ -277,6 +277,9 @@ export class Egg { return i18next.t("egg:gachaTypeShiny"); case EggSourceType.GACHA_MOVE: return i18next.t("egg:gachaTypeMove"); + default: + console.warn("getEggTypeDescriptor case not defined. Returning default empty string"); + return ""; } } @@ -326,9 +329,9 @@ export class Egg { return tierValue >= 52 + tierValueOffset ? EggTier.COMMON : tierValue >= 8 + tierValueOffset ? EggTier.GREAT : tierValue >= 1 + tierValueOffset ? EggTier.ULTRA : EggTier.MASTER; } - private rollSpecies(scene: BattleScene): Species { + private rollSpecies(scene: BattleScene): Species | null { if (!scene) { - return undefined; + return null; } /** * Manaphy eggs have a 1/8 chance of being Manaphy and 7/8 chance of being Phione @@ -400,7 +403,7 @@ export class Egg { * and being the same each time */ let totalWeight = 0; - const speciesWeights = []; + const speciesWeights : number[] = []; for (const speciesId of speciesPool) { let weight = Math.floor((((maxStarterValue - speciesStarters[speciesId]) / ((maxStarterValue - minStarterValue) + 1)) * 1.5 + 1) * 100); const species = getPokemonSpecies(speciesId); @@ -420,6 +423,7 @@ export class Egg { break; } } + species = species!; // tell TS compiled it's defined now! if (!!scene.gameData.dexData[species].caughtAttr || scene.gameData.eggs.some(e => e.species === species)) { scene.gameData.unlockPity[this.tier] = Math.min(scene.gameData.unlockPity[this.tier] + 1, 10); @@ -517,6 +521,8 @@ export class Egg { if (speciesStartValue >= 8) { return EggTier.MASTER; } + + return EggTier.COMMON; } //// @@ -541,6 +547,7 @@ export function getLegendaryGachaSpeciesForTimestamp(scene: BattleScene, timesta scene.executeWithSeedOffset(() => { ret = Phaser.Math.RND.shuffle(legendarySpecies)[index]; }, offset, EGG_SEED.toString()); + ret = ret!; // tell TS compiler it's return ret; } diff --git a/src/data/move.ts b/src/data/move.ts index 589c169805d..b5ca217a73e 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -180,7 +180,7 @@ export default class Move implements Localizable { * @returns the first {@linkcode MoveAttr} element in attrs that makes the input function return true */ findAttr(attrPredicate: (attr: MoveAttr) => boolean): MoveAttr { - return this.attrs.find(attrPredicate); + return this.attrs.find(attrPredicate)!; // TODO: is the bang correct? } /** @@ -361,7 +361,7 @@ export default class Move implements Localizable { * @param makesContact The value (boolean) to set the flag to * @returns The {@linkcode Move} that called this function */ - makesContact(makesContact?: boolean): this { + makesContact(makesContact: boolean = true): this { // TODO: is true the correct default? this.setFlag(MoveFlags.MAKES_CONTACT, makesContact); return this; } @@ -372,7 +372,7 @@ export default class Move implements Localizable { * example: @see {@linkcode Moves.CURSE} * @returns The {@linkcode Move} that called this function */ - ignoresProtect(ignoresProtect?: boolean): this { + ignoresProtect(ignoresProtect: boolean = true): this { // TODO: is `true` the correct default? this.setFlag(MoveFlags.IGNORE_PROTECT, ignoresProtect); return this; } @@ -383,7 +383,7 @@ export default class Move implements Localizable { * example: @see {@linkcode Moves.NATURE_POWER} * @returns The {@linkcode Move} that called this function */ - ignoresVirtual(ignoresVirtual?: boolean): this { + ignoresVirtual(ignoresVirtual: boolean = true): this { // TODO: is `true` the correct default? this.setFlag(MoveFlags.IGNORE_VIRTUAL, ignoresVirtual); return this; } @@ -394,7 +394,7 @@ export default class Move implements Localizable { * example: @see {@linkcode Moves.UPROAR} * @returns The {@linkcode Move} that called this function */ - soundBased(soundBased?: boolean): this { + soundBased(soundBased: boolean = true): this { // TODO: is `true` the correct default? this.setFlag(MoveFlags.SOUND_BASED, soundBased); return this; } @@ -405,7 +405,7 @@ export default class Move implements Localizable { * example: @see {@linkcode Moves.TELEPORT} * @returns The {@linkcode Move} that called this function */ - hidesUser(hidesUser?: boolean): this { + hidesUser(hidesUser: boolean = true): this { // TODO: is `true` the correct default? this.setFlag(MoveFlags.HIDE_USER, hidesUser); return this; } @@ -416,7 +416,7 @@ export default class Move implements Localizable { * example: @see {@linkcode Moves.WHIRLWIND} * @returns The {@linkcode Move} that called this function */ - hidesTarget(hidesTarget?: boolean): this { + hidesTarget(hidesTarget: boolean = true): this { // TODO: is `true` the correct default? this.setFlag(MoveFlags.HIDE_TARGET, hidesTarget); return this; } @@ -427,7 +427,7 @@ export default class Move implements Localizable { * example: @see {@linkcode Moves.BITE} * @returns The {@linkcode Move} that called this function */ - bitingMove(bitingMove?: boolean): this { + bitingMove(bitingMove: boolean = true): this { // TODO: is `true` the correct default? this.setFlag(MoveFlags.BITING_MOVE, bitingMove); return this; } @@ -438,7 +438,7 @@ export default class Move implements Localizable { * example: @see {@linkcode Moves.WATER_PULSE} * @returns The {@linkcode Move} that called this function */ - pulseMove(pulseMove?: boolean): this { + pulseMove(pulseMove: boolean = true): this { // TODO: is `true` the correct default? this.setFlag(MoveFlags.PULSE_MOVE, pulseMove); return this; } @@ -449,7 +449,7 @@ export default class Move implements Localizable { * example: @see {@linkcode Moves.DRAIN_PUNCH} * @returns The {@linkcode Move} that called this function */ - punchingMove(punchingMove?: boolean): this { + punchingMove(punchingMove: boolean = true): this { // TODO: is `true` the correct default? this.setFlag(MoveFlags.PUNCHING_MOVE, punchingMove); return this; } @@ -460,7 +460,7 @@ export default class Move implements Localizable { * example: @see {@linkcode Moves.X_SCISSOR} * @returns The {@linkcode Move} that called this function */ - slicingMove(slicingMove?: boolean): this { + slicingMove(slicingMove: boolean = true): this { // TODO: is `true` the correct default? this.setFlag(MoveFlags.SLICING_MOVE, slicingMove); return this; } @@ -471,7 +471,7 @@ export default class Move implements Localizable { * @param recklessMove The value to set the flag to * @returns The {@linkcode Move} that called this function */ - recklessMove(recklessMove?: boolean): this { + recklessMove(recklessMove: boolean = true): this { // TODO: is `true` the correct default? this.setFlag(MoveFlags.RECKLESS_MOVE, recklessMove); return this; } @@ -482,7 +482,7 @@ export default class Move implements Localizable { * example: @see {@linkcode Moves.ELECTRO_BALL} * @returns The {@linkcode Move} that called this function */ - ballBombMove(ballBombMove?: boolean): this { + ballBombMove(ballBombMove: boolean = true): this { // TODO: is `true` the correct default? this.setFlag(MoveFlags.BALLBOMB_MOVE, ballBombMove); return this; } @@ -493,7 +493,7 @@ export default class Move implements Localizable { * example: @see {@linkcode Moves.STUN_SPORE} * @returns The {@linkcode Move} that called this function */ - powderMove(powderMove?: boolean): this { + powderMove(powderMove: boolean = true): this { // TODO: is `true` the correct default? this.setFlag(MoveFlags.POWDER_MOVE, powderMove); return this; } @@ -504,7 +504,7 @@ export default class Move implements Localizable { * example: @see {@linkcode Moves.PETAL_DANCE} * @returns The {@linkcode Move} that called this function */ - danceMove(danceMove?: boolean): this { + danceMove(danceMove: boolean = true): this { // TODO: is `true` the correct default? this.setFlag(MoveFlags.DANCE_MOVE, danceMove); return this; } @@ -515,7 +515,7 @@ export default class Move implements Localizable { * example: @see {@linkcode Moves.HURRICANE} * @returns The {@linkcode Move} that called this function */ - windMove(windMove?: boolean): this { + windMove(windMove: boolean = true): this { // TODO: is `true` the correct default? this.setFlag(MoveFlags.WIND_MOVE, windMove); return this; } @@ -526,7 +526,7 @@ export default class Move implements Localizable { * example: @see {@linkcode Moves.ABSORB} * @returns The {@linkcode Move} that called this function */ - triageMove(triageMove?: boolean): this { + triageMove(triageMove: boolean = true): this { // TODO: is `true` the correct default? this.setFlag(MoveFlags.TRIAGE_MOVE, triageMove); return this; } @@ -537,7 +537,7 @@ export default class Move implements Localizable { * example: @see {@linkcode Moves.SUNSTEEL_STRIKE} * @returns The {@linkcode Move} that called this function */ - ignoresAbilities(ignoresAbilities?: boolean): this { + ignoresAbilities(ignoresAbilities: boolean = true): this { // TODO: is `true` the correct default? this.setFlag(MoveFlags.IGNORE_ABILITIES, ignoresAbilities); return this; } @@ -548,7 +548,7 @@ export default class Move implements Localizable { * example: @see {@linkcode Moves.TRIPLE_AXEL} * @returns The {@linkcode Move} that called this function */ - checkAllHits(checkAllHits?: boolean): this { + checkAllHits(checkAllHits: boolean = true): this { // TODO: is `true` the correct default? this.setFlag(MoveFlags.CHECK_ALL_HITS, checkAllHits); return this; } @@ -559,7 +559,7 @@ export default class Move implements Localizable { * example: @see {@linkcode Moves.METAL_BURST} * @returns The {@linkcode Move} that called this function */ - redirectCounter(redirectCounter?: boolean): this { + redirectCounter(redirectCounter: boolean = true): this { // TODO: is `true` the correct default? this.setFlag(MoveFlags.REDIRECT_COUNTER, redirectCounter); return this; } @@ -571,7 +571,7 @@ export default class Move implements Localizable { * @param target {@linkcode Pokemon} the Pokemon receiving the move * @returns boolean */ - checkFlag(flag: MoveFlags, user: Pokemon, target: Pokemon): boolean { + checkFlag(flag: MoveFlags, user: Pokemon, target: Pokemon | null): boolean { // special cases below, eg: if the move flag is MAKES_CONTACT, and the user pokemon has an ability that ignores contact (like "Long Reach"), then overrides and move does not make contact switch (flag) { case MoveFlags.MAKES_CONTACT: @@ -870,7 +870,7 @@ export abstract class MoveAttr { * @param args Set of unique arguments needed by this attribute * @returns true if application of the ability succeeds */ - apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean | Promise { + apply(user: Pokemon | null, target: Pokemon | null, move: Move, args: any[]): boolean | Promise { return true; } @@ -878,7 +878,7 @@ export abstract class MoveAttr { * @virtual * @returns the {@linkcode MoveCondition} or {@linkcode MoveConditionFunc} for this {@linkcode Move} */ - getCondition(): MoveCondition | MoveConditionFunc { + getCondition(): MoveCondition | MoveConditionFunc | null { return null; } @@ -954,14 +954,14 @@ export class MoveEffectAttr extends MoveAttr { * @param args Set of unique arguments needed by this attribute * @returns true if basic application of the ability attribute should be possible */ - canApply(user: Pokemon, target: Pokemon, move: Move, args: any[]) { + canApply(user: Pokemon, target: Pokemon, move: Move, args?: any[]) { return !! (this.selfTarget ? user.hp && !user.getTag(BattlerTagType.FRENZY) : target.hp) && (this.selfTarget || !target.getTag(BattlerTagType.PROTECTED) || move.checkFlag(MoveFlags.IGNORE_PROTECT, user, target)); } /** Applies move effects so long as they are able based on {@linkcode canApply} */ - apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean | Promise { + apply(user: Pokemon, target: Pokemon, move: Move, args?: any[]): boolean | Promise { return this.canApply(user, target, move, args); } @@ -1408,10 +1408,10 @@ export class PartyStatusCureAttr extends MoveEffectAttr { /** Skips mons with this ability, ie. Soundproof */ private abilityCondition: Abilities; - constructor(message: string, abilityCondition: Abilities) { + constructor(message: string | null, abilityCondition: Abilities) { super(); - this.message = message; + this.message = message!; // TODO: is this bang correct? this.abilityCondition = abilityCondition; } @@ -1428,6 +1428,7 @@ export class PartyStatusCureAttr extends MoveEffectAttr { return false; } this.addPartyCurePhase(user); + return true; } addPartyCurePhase(user: Pokemon) { @@ -1583,16 +1584,16 @@ export class SandHealAttr extends WeatherHealAttr { */ export class BoostHealAttr extends HealAttr { /** Healing received when {@linkcode condition} is false */ - private normalHealRatio?: number; + private normalHealRatio: number; /** Healing received when {@linkcode condition} is true */ - private boostedHealRatio?: number; + private boostedHealRatio: number; /** The lambda expression to check against when boosting the healing value */ private condition?: MoveConditionFunc; constructor(normalHealRatio?: number, boostedHealRatio?: number, showAnim?: boolean, selfTarget?: boolean, condition?: MoveConditionFunc) { super(normalHealRatio, showAnim, selfTarget); - this.normalHealRatio = normalHealRatio; - this.boostedHealRatio = boostedHealRatio; + this.normalHealRatio = normalHealRatio!; // TODO: is this bang correct? + this.boostedHealRatio = boostedHealRatio!; // TODO: is this bang correct? this.condition = condition; } @@ -1604,7 +1605,7 @@ export class BoostHealAttr extends HealAttr { * @returns true if the move was successful */ apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - const healRatio = this.condition(user, target, move) ? this.boostedHealRatio : this.normalHealRatio; + const healRatio: number = (this.condition ? this.condition(user, target, move) : false) ? this.boostedHealRatio : this.normalHealRatio; this.addHealPhase(target, healRatio); return true; } @@ -1643,13 +1644,13 @@ export class HealOnAllyAttr extends HealAttr { export class HitHealAttr extends MoveEffectAttr { private healRatio: number; private message: string; - private healStat: Stat; + private healStat: Stat | null; - constructor(healRatio?: number, healStat?: Stat) { + constructor(healRatio?: number | null, healStat?: Stat) { super(true, MoveEffectTrigger.HIT); - this.healRatio = healRatio || 0.5; - this.healStat = healStat || null; + this.healRatio = healRatio!; // TODO: is this bang correct? + this.healStat = healStat!; // TODO: is this bang correct? } /** * Heals the user the determined amount and possibly displays a message about regaining health. @@ -1665,7 +1666,7 @@ export class HitHealAttr extends MoveEffectAttr { let healAmount = 0; let message = ""; const reverseDrain = target.hasAbilityWithAttr(ReverseDrainAbAttr, false); - if (this.healStat) { + if (this.healStat !== null) { // Strength Sap formula healAmount = target.getBattleStat(this.healStat); message = i18next.t("battle:drainMessage", {pokemonName: getPokemonNameWithAffix(target)}); @@ -1677,11 +1678,11 @@ export class HitHealAttr extends MoveEffectAttr { if (reverseDrain) { if (user.hasAbilityWithAttr(BlockNonDirectDamageAbAttr)) { healAmount = 0; - message = null; + message = ""; } else { user.turnData.damageTaken += healAmount; healAmount = healAmount * -1; - message = null; + message = ""; } } user.scene.unshiftPhase(new PokemonHealPhase(user.scene, user.getBattlerIndex(), healAmount, message, false, true)); @@ -1850,14 +1851,14 @@ export class WaterShurikenMultiHitTypeAttr extends ChangeMultiHitTypeAttr { export class StatusEffectAttr extends MoveEffectAttr { public effect: StatusEffect; - public cureTurn: integer; + public cureTurn: integer | null; public overrideStatus: boolean; constructor(effect: StatusEffect, selfTarget?: boolean, cureTurn?: integer, overrideStatus?: boolean) { super(selfTarget, MoveEffectTrigger.HIT); this.effect = effect; - this.cureTurn = cureTurn; + this.cureTurn = cureTurn!; // TODO: is this bang correct? this.overrideStatus = !!overrideStatus; } @@ -1875,7 +1876,7 @@ export class StatusEffectAttr extends MoveEffectAttr { } if ((!pokemon.status || (pokemon.status.effect === this.effect && moveChance < 0)) && pokemon.trySetStatus(this.effect, true, user, this.cureTurn)) { - applyPostAttackAbAttrs(ConfusionOnStatusEffectAbAttr, user, target, move, null,this.effect); + applyPostAttackAbAttrs(ConfusionOnStatusEffectAbAttr, user, target, move, null, this.effect); return true; } } @@ -1914,12 +1915,13 @@ export class PsychoShiftEffectAttr extends MoveEffectAttr { } apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - const statusToApply: StatusEffect = user.status?.effect ?? (user.hasAbility(Abilities.COMATOSE) ? StatusEffect.SLEEP : undefined); + const statusToApply: StatusEffect | undefined = user.status?.effect ?? (user.hasAbility(Abilities.COMATOSE) ? StatusEffect.SLEEP : undefined); if (target.status) { return false; } - if (!target.status || (target.status.effect === statusToApply && move.chance < 0)) { + //@ts-ignore - how can target.status.effect be checked when we return `false` before when it's defined? + if (!target.status || (target.status.effect === statusToApply && move.chance < 0)) { // TODO: resolve ts-ignore const statusAfflictResult = target.trySetStatus(statusToApply, true, user); if (statusAfflictResult) { if (user.status) { @@ -1960,7 +1962,7 @@ export class StealHeldItemChanceAttr extends MoveEffectAttr { const heldItems = this.getTargetHeldItems(target).filter(i => i.isTransferrable); if (heldItems.length) { const poolType = target.isPlayer() ? ModifierPoolType.PLAYER : target.hasTrainer() ? ModifierPoolType.TRAINER : ModifierPoolType.WILD; - const highestItemTier = heldItems.map(m => m.type.getOrInferTier(poolType)).reduce((highestTier, tier) => Math.max(tier, highestTier), 0); + const highestItemTier = heldItems.map(m => m.type.getOrInferTier(poolType)).reduce((highestTier, tier) => Math.max(tier!, highestTier), 0); // TODO: is the bang after tier correct? const tierHeldItems = heldItems.filter(m => m.type.getOrInferTier(poolType) === highestItemTier); const stolenItem = tierHeldItems[user.randSeedInt(tierHeldItems.length)]; user.scene.tryTransferHeldItemModifier(stolenItem, user, false).then(success => { @@ -2073,10 +2075,9 @@ export class RemoveHeldItemAttr extends MoveEffectAttr { * Attribute that causes targets of the move to eat a berry. Used for Teatime, Stuff Cheeks */ export class EatBerryAttr extends MoveEffectAttr { - protected chosenBerry: BerryModifier; + protected chosenBerry: BerryModifier | undefined; constructor() { super(true, MoveEffectTrigger.HIT); - this.chosenBerry = undefined; } /** * Causes the target to eat a berry. @@ -2111,16 +2112,16 @@ export class EatBerryAttr extends MoveEffectAttr { } reduceBerryModifier(target: Pokemon) { - if (this.chosenBerry.stackCount === 1) { + if (this.chosenBerry?.stackCount === 1) { target.scene.removeModifier(this.chosenBerry, !target.isPlayer()); - } else { + } else if (this.chosenBerry !== undefined && this.chosenBerry.stackCount > 1) { this.chosenBerry.stackCount--; } target.scene.updateModifiers(target.isPlayer()); } eatBerry(consumer: Pokemon) { - getBerryEffectFunc(this.chosenBerry.berryType)(consumer); // consumer eats the berry + getBerryEffectFunc(this.chosenBerry!.berryType)(consumer); // consumer eats the berry applyAbAttrs(HealFromBerryUseAbAttr, consumer, new Utils.BooleanHolder(false)); } } @@ -2351,20 +2352,20 @@ export class OverrideMoveEffectAttr extends MoveAttr { export class ChargeAttr extends OverrideMoveEffectAttr { public chargeAnim: ChargeAnim; private chargeText: string; - private tagType: BattlerTagType; + private tagType: BattlerTagType | null; private chargeEffect: boolean; public sameTurn: boolean; - public followUpPriority: integer; + public followUpPriority: integer | null; - constructor(chargeAnim: ChargeAnim, chargeText: string, tagType?: BattlerTagType, chargeEffect: boolean = false, sameTurn: boolean = false, followUpPriority?: integer) { + constructor(chargeAnim: ChargeAnim, chargeText: string, tagType?: BattlerTagType | null, chargeEffect: boolean = false, sameTurn: boolean = false, followUpPriority?: integer) { super(); this.chargeAnim = chargeAnim; this.chargeText = chargeText; - this.tagType = tagType; + this.tagType = tagType!; // TODO: is this bang correct? this.chargeEffect = chargeEffect; this.sameTurn = sameTurn; - this.followUpPriority = followUpPriority; + this.followUpPriority = followUpPriority!; // TODO: is this bang correct? } apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): Promise { @@ -2383,11 +2384,11 @@ export class ChargeAttr extends OverrideMoveEffectAttr { user.pushMoveHistory({ move: move.id, targets: [ target.getBattlerIndex() ], result: MoveResult.OTHER }); user.getMoveQueue().push({ move: move.id, targets: [ target.getBattlerIndex() ], ignorePP: true }); if (this.sameTurn) { - let movesetMove = user.moveset.find(m => m.moveId === move.id); + let movesetMove = user.moveset.find(m => m?.moveId === move.id); if (!movesetMove) { // account for any move that calls a ChargeAttr move when the ChargeAttr move does not exist in moveset movesetMove = new PokemonMove(move.id, 0, 0, true); } - user.scene.pushMovePhase(new MovePhase(user.scene, user, [ target.getBattlerIndex() ], movesetMove, true), this.followUpPriority); + user.scene.pushMovePhase(new MovePhase(user.scene, user, [ target.getBattlerIndex() ], movesetMove, true), this.followUpPriority!); // TODO: is this bang correct? } user.addTag(BattlerTagType.CHARGING, 1, move.id, user.id); resolve(true); @@ -2399,7 +2400,7 @@ export class ChargeAttr extends OverrideMoveEffectAttr { }); } - usedChargeEffect(user: Pokemon, target: Pokemon, move: Move): boolean { + usedChargeEffect(user: Pokemon, target: Pokemon | null, move: Move): boolean { if (!this.chargeEffect) { return false; } @@ -2488,7 +2489,7 @@ export class DelayedAttackAttr extends OverrideMoveEffectAttr { resolve(true); }); } else { - user.scene.ui.showText(i18next.t("moveTriggers:tookMoveAttack", {pokemonName: getPokemonNameWithAffix(user.scene.getPokemonById(target.id)), moveName: move.name}), null, () => resolve(true)); + user.scene.ui.showText(i18next.t("moveTriggers:tookMoveAttack", {pokemonName: getPokemonNameWithAffix(user.scene.getPokemonById(target.id) ?? undefined), moveName: move.name}), null, () => resolve(true)); } }); } @@ -2497,20 +2498,20 @@ export class DelayedAttackAttr extends OverrideMoveEffectAttr { export class StatChangeAttr extends MoveEffectAttr { public stats: BattleStat[]; public levels: integer; - private condition: MoveConditionFunc; + private condition: MoveConditionFunc | null; private showMessage: boolean; - constructor(stats: BattleStat | BattleStat[], levels: integer, selfTarget?: boolean, condition?: MoveConditionFunc, showMessage: boolean = true, firstHitOnly: boolean = false, moveEffectTrigger: MoveEffectTrigger = MoveEffectTrigger.HIT, firstTargetOnly: boolean = false) { + constructor(stats: BattleStat | BattleStat[], levels: integer, selfTarget?: boolean, condition?: MoveConditionFunc | null, showMessage: boolean = true, firstHitOnly: boolean = false, moveEffectTrigger: MoveEffectTrigger = MoveEffectTrigger.HIT, firstTargetOnly: boolean = false) { super(selfTarget, moveEffectTrigger, firstHitOnly, false, firstTargetOnly); this.stats = typeof(stats) === "number" ? [ stats as BattleStat ] : stats as BattleStat[]; this.levels = levels; - this.condition = condition || null; + this.condition = condition!; // TODO: is this bang correct? this.showMessage = showMessage; } - apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean | Promise { + apply(user: Pokemon, target: Pokemon, move: Move, args?: any[]): boolean | Promise { if (!super.apply(user, target, move, args) || (this.condition && !this.condition(user, target, move))) { return false; } @@ -2574,7 +2575,7 @@ export class StatChangeAttr extends MoveEffectAttr { export class PostVictoryStatChangeAttr extends MoveAttr { private stats: BattleStat[]; private levels: integer; - private condition: MoveConditionFunc; + private condition: MoveConditionFunc | null; private showMessage: boolean; constructor(stats: BattleStat | BattleStat[], levels: integer, selfTarget?: boolean, condition?: MoveConditionFunc, showMessage: boolean = true, firstHitOnly: boolean = false) { @@ -2583,7 +2584,7 @@ export class PostVictoryStatChangeAttr extends MoveAttr { ? [ stats as BattleStat ] : stats as BattleStat[]; this.levels = levels; - this.condition = condition || null; + this.condition = condition!; // TODO: is this bang correct? this.showMessage = showMessage; } applyPostVictory(user: Pokemon, target: Pokemon, move: Move): void { @@ -2591,7 +2592,7 @@ export class PostVictoryStatChangeAttr extends MoveAttr { return; } const statChangeAttr = new StatChangeAttr(this.stats, this.levels, this.showMessage); - statChangeAttr.apply(user, target, move, undefined); + statChangeAttr.apply(user, target, move); } } @@ -2751,7 +2752,7 @@ export class HpSplitAttr extends MoveEffectAttr { return resolve(false); } - const infoUpdates = []; + const infoUpdates: Promise[] = []; const hpValue = Math.floor((target.hp + user.hp) / 2); if (user.hp < hpValue) { @@ -2803,7 +2804,7 @@ export class LessPPMorePowerAttr extends VariablePowerAttr { */ apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { const ppMax = move.pp; - const ppUsed = user.moveset.find((m) => m.moveId === move.id).ppUsed; + const ppUsed = user.moveset.find((m) => m?.moveId === move.id)?.ppUsed!; // TODO: is the bang correct? let ppRemains = ppMax - ppUsed; /** Reduce to 0 to avoid negative numbers if user has 1PP before attack and target has Ability.PRESSURE */ @@ -2870,6 +2871,7 @@ const beatUpFunc = (user: Pokemon, allyIndex: number): number => { } return (pokemon.species.getBaseStat(Stat.ATK) / 10) + 5; } + return 0; }; export class BeatUpAttr extends VariablePowerAttr { @@ -2896,7 +2898,7 @@ export class BeatUpAttr extends VariablePowerAttr { } const doublePowerChanceMessageFunc = (user: Pokemon, target: Pokemon, move: Move) => { - let message: string = null; + let message: string = ""; user.scene.executeWithSeedOffset(() => { const rand = Utils.randSeedInt(100); if (rand < move.chance) { @@ -2910,7 +2912,7 @@ export class DoublePowerChanceAttr extends VariablePowerAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { let rand: integer; user.scene.executeWithSeedOffset(() => rand = Utils.randSeedInt(100), user.scene.currentBattle.turn << 6, user.scene.waveSeed); - if (rand < move.chance) { + if (rand! < move.chance) { const power = args[0] as Utils.NumberHolder; power.value *= 2; return true; @@ -2926,9 +2928,9 @@ export abstract class ConsecutiveUsePowerMultiplierAttr extends MovePowerMultipl const moveHistory = user.getLastXMoves(limit + 1).slice(1); let count = 0; - let turnMove: TurnMove; + let turnMove: TurnMove | undefined; - while (((turnMove = moveHistory.shift())?.move === move.id || (comboMoves.length && comboMoves.includes(turnMove?.move))) && (!resetOnFail || turnMove.result === MoveResult.SUCCESS)) { + while (((turnMove = moveHistory.shift())?.move === move.id || (comboMoves.length && comboMoves.includes(turnMove?.move!))) && (!resetOnFail || turnMove?.result === MoveResult.SUCCESS)) { // TODO: is this bang correct? if (count < (limit - 1)) { count++; } else if (resetOnLimit) { @@ -3181,7 +3183,7 @@ const magnitudeMessageFunc = (user: Pokemon, target: Pokemon, move: Move) => { message = i18next.t("moveTriggers:magnitudeMessage", {magnitude: m + 4}); }, user.scene.currentBattle.turn << 6, user.scene.waveSeed); - return message; + return message!; }; export class MagnitudePowerAttr extends VariablePowerAttr { @@ -3197,7 +3199,7 @@ export class MagnitudePowerAttr extends VariablePowerAttr { let m = 0; for (; m < magnitudeThresholds.length; m++) { - if (rand < magnitudeThresholds[m]) { + if (rand! < magnitudeThresholds[m]) { break; } } @@ -3360,7 +3362,7 @@ export class SpitUpPowerAttr extends VariablePowerAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { const stockpilingTag = user.getTag(StockpilingTag); - if (stockpilingTag?.stockpiledCount > 0) { + if (stockpilingTag !== null && stockpilingTag.stockpiledCount > 0) { const power = args[0] as Utils.IntegerHolder; power.value = this.multiplier * stockpilingTag.stockpiledCount; return true; @@ -3378,7 +3380,7 @@ export class SwallowHealAttr extends HealAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { const stockpilingTag = user.getTag(StockpilingTag); - if (stockpilingTag?.stockpiledCount > 0) { + if (stockpilingTag !== null && stockpilingTag?.stockpiledCount > 0) { const stockpiled = stockpilingTag.stockpiledCount; let healRatio: number; @@ -3400,7 +3402,10 @@ export class SwallowHealAttr extends HealAttr { } } -const hasStockpileStacksCondition: MoveConditionFunc = (user) => user.getTag(StockpilingTag)?.stockpiledCount > 0; +const hasStockpileStacksCondition: MoveConditionFunc = (user) => { + const hasStockpilingTag = user.getTag(StockpilingTag); + return !!hasStockpilingTag && hasStockpilingTag.stockpiledCount > 0; +}; /** * Attribute used for multi-hit moves that increase power in increments of the @@ -3471,13 +3476,13 @@ export class LastMoveDoublePowerAttr extends VariablePowerAttr { const enemy = user.getOpponent(0); const pokemonActed: Pokemon[] = []; - if (enemy.turnData.acted) { + if (enemy?.turnData.acted) { pokemonActed.push(enemy); } if (user.scene.currentBattle.double) { const userAlly = user.getAlly(); - const enemyAlly = enemy.getAlly(); + const enemyAlly = enemy?.getAlly(); if (userAlly && userAlly.turnData.acted) { pokemonActed.push(userAlly); @@ -3751,7 +3756,7 @@ export class VariableMoveTypeAttr extends MoveAttr { export class FormChangeItemTypeAttr extends VariableMoveTypeAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { if ([user.species.speciesId, user.fusionSpecies?.speciesId].includes(Species.ARCEUS) || [user.species.speciesId, user.fusionSpecies?.speciesId].includes(Species.SILVALLY)) { - const form = user.species.speciesId === Species.ARCEUS || user.species.speciesId === Species.SILVALLY ? user.formIndex : user.fusionSpecies.formIndex; + const form = user.species.speciesId === Species.ARCEUS || user.species.speciesId === Species.SILVALLY ? user.formIndex : user.fusionSpecies?.formIndex!; // TODO: is this bang correct? move.type = Type[Type[form]]; return true; @@ -3764,7 +3769,7 @@ export class FormChangeItemTypeAttr extends VariableMoveTypeAttr { export class TechnoBlastTypeAttr extends VariableMoveTypeAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { if ([user.species.speciesId, user.fusionSpecies?.speciesId].includes(Species.GENESECT)) { - const form = user.species.speciesId === Species.GENESECT ? user.formIndex : user.fusionSpecies.formIndex; + const form = user.species.speciesId === Species.GENESECT ? user.formIndex : user.fusionSpecies?.formIndex; switch (form) { case 1: // Shock Drive @@ -3793,7 +3798,7 @@ export class TechnoBlastTypeAttr extends VariableMoveTypeAttr { export class AuraWheelTypeAttr extends VariableMoveTypeAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { if ([user.species.speciesId, user.fusionSpecies?.speciesId].includes(Species.MORPEKO)) { - const form = user.species.speciesId === Species.MORPEKO ? user.formIndex : user.fusionSpecies.formIndex; + const form = user.species.speciesId === Species.MORPEKO ? user.formIndex : user.fusionSpecies?.formIndex; switch (form) { case 1: // Hangry Mode @@ -3813,7 +3818,7 @@ export class AuraWheelTypeAttr extends VariableMoveTypeAttr { export class RagingBullTypeAttr extends VariableMoveTypeAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { if ([user.species.speciesId, user.fusionSpecies?.speciesId].includes(Species.PALDEA_TAUROS)) { - const form = user.species.speciesId === Species.PALDEA_TAUROS ? user.formIndex : user.fusionSpecies.formIndex; + const form = user.species.speciesId === Species.PALDEA_TAUROS ? user.formIndex : user.fusionSpecies?.formIndex; switch (form) { case 1: // Blaze breed @@ -3836,7 +3841,7 @@ export class RagingBullTypeAttr extends VariableMoveTypeAttr { export class IvyCudgelTypeAttr extends VariableMoveTypeAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { if ([user.species.speciesId, user.fusionSpecies?.speciesId].includes(Species.OGERPON)) { - const form = user.species.speciesId === Species.OGERPON ? user.formIndex : user.fusionSpecies.formIndex; + const form = user.species.speciesId === Species.OGERPON ? user.formIndex : user.fusionSpecies?.formIndex; switch (form) { case 1: // Wellspring Mask @@ -4125,23 +4130,23 @@ export class DisableMoveAttr extends MoveEffectAttr { } const moveQueue = target.getLastXMoves(); - let turnMove: TurnMove; + let turnMove: TurnMove | undefined; while (moveQueue.length) { turnMove = moveQueue.shift(); - if (turnMove.virtual) { + if (turnMove?.virtual) { continue; } - const moveIndex = target.getMoveset().findIndex(m => m.moveId === turnMove.move); + const moveIndex = target.getMoveset().findIndex(m => m?.moveId === turnMove?.move); if (moveIndex === -1) { return false; } const disabledMove = target.getMoveset()[moveIndex]; - target.summonData.disabledMove = disabledMove.moveId; + target.summonData.disabledMove = disabledMove?.moveId!; // TODO: is this bang correct? target.summonData.disabledTurns = 4; - user.scene.queueMessage(i18next.t("abilityTriggers:postDefendMoveDisable", { pokemonNameWithAffix: getPokemonNameWithAffix(target), moveName: disabledMove.getName()})); + user.scene.queueMessage(i18next.t("abilityTriggers:postDefendMoveDisable", { pokemonNameWithAffix: getPokemonNameWithAffix(target), moveName: disabledMove?.getName()})); return true; } @@ -4150,26 +4155,28 @@ export class DisableMoveAttr extends MoveEffectAttr { } getCondition(): MoveConditionFunc { - return (user, target, move) => { + return (user, target, move): boolean => { // TODO: Not sure what to do here if (target.summonData.disabledMove || target.isMax()) { return false; } const moveQueue = target.getLastXMoves(); - let turnMove: TurnMove; + let turnMove: TurnMove | undefined; while (moveQueue.length) { turnMove = moveQueue.shift(); - if (turnMove.virtual) { + if (turnMove?.virtual) { continue; } - const move = target.getMoveset().find(m => m.moveId === turnMove.move); + const move = target.getMoveset().find(m => m?.moveId === turnMove?.move); if (!move) { continue; } return true; } + + return false; }; } @@ -4242,13 +4249,13 @@ export class AddBattlerTagAttr extends MoveEffectAttr { return false; } - getCondition(): MoveConditionFunc { + getCondition(): MoveConditionFunc | null { return this.failOnOverlap ? (user, target, move) => !(this.selfTarget ? user : target).getTag(this.tagType) : null; } - getTagTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): integer { + getTagTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): integer | void { switch (this.tagType) { case BattlerTagType.RECHARGING: case BattlerTagType.PERISH_SONG: @@ -4296,7 +4303,7 @@ export class AddBattlerTagAttr extends MoveEffectAttr { if (moveChance < 0) { moveChance = 100; } - return Math.floor(this.getTagTargetBenefitScore(user, target, move) * (moveChance / 100)); + return Math.floor(this.getTagTargetBenefitScore(user, target, move)! * (moveChance / 100)); // TODO: is the bang correct? } } @@ -4444,11 +4451,11 @@ export class ProtectAttr extends AddBattlerTagAttr { return ((user, target, move): boolean => { let timesUsed = 0; const moveHistory = user.getLastXMoves(); - let turnMove: TurnMove; + let turnMove: TurnMove | undefined; while (moveHistory.length) { turnMove = moveHistory.shift(); - if (!allMoves[turnMove.move].hasAttr(ProtectAttr) || turnMove.result !== MoveResult.SUCCESS) { + if (!allMoves[turnMove?.move!].hasAttr(ProtectAttr) || turnMove?.result !== MoveResult.SUCCESS) { // TODO: is the bang correct? break; } timesUsed++; @@ -4521,11 +4528,11 @@ export class AddArenaTagAttr extends MoveEffectAttr { private failOnOverlap: boolean; public selfSideTarget: boolean; - constructor(tagType: ArenaTagType, turnCount?: integer, failOnOverlap: boolean = false, selfSideTarget: boolean = false) { + constructor(tagType: ArenaTagType, turnCount?: integer | null, failOnOverlap: boolean = false, selfSideTarget: boolean = false) { super(true, MoveEffectTrigger.POST_APPLY); this.tagType = tagType; - this.turnCount = turnCount; + this.turnCount = turnCount!; // TODO: is the bang correct? this.failOnOverlap = failOnOverlap; this.selfSideTarget = selfSideTarget; } @@ -4543,7 +4550,7 @@ export class AddArenaTagAttr extends MoveEffectAttr { return false; } - getCondition(): MoveConditionFunc { + getCondition(): MoveConditionFunc | null { return this.failOnOverlap ? (user, target, move) => !user.scene.arena.getTagOnSide(this.tagType, target.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY) : null; @@ -4716,13 +4723,13 @@ export class SwapArenaTagsAttr extends MoveEffectAttr { if (tagPlayerTemp) { for (const swapTagsType of tagPlayerTemp) { user.scene.arena.removeTagOnSide(swapTagsType.tagType, ArenaTagSide.PLAYER, true); - user.scene.arena.addTag(swapTagsType.tagType, swapTagsType.turnCount, swapTagsType.sourceMove, swapTagsType.sourceId, ArenaTagSide.ENEMY, true); + user.scene.arena.addTag(swapTagsType.tagType, swapTagsType.turnCount, swapTagsType.sourceMove, swapTagsType.sourceId!, ArenaTagSide.ENEMY, true); // TODO: is the bang correct? } } if (tagEnemyTemp) { for (const swapTagsType of tagEnemyTemp) { user.scene.arena.removeTagOnSide(swapTagsType.tagType, ArenaTagSide.ENEMY, true); - user.scene.arena.addTag(swapTagsType.tagType, swapTagsType.turnCount, swapTagsType.sourceMove, swapTagsType.sourceId, ArenaTagSide.PLAYER, true); + user.scene.arena.addTag(swapTagsType.tagType, swapTagsType.turnCount, swapTagsType.sourceMove, swapTagsType.sourceId!, ArenaTagSide.PLAYER, true); // TODO: is the bang correct? } } @@ -4836,7 +4843,7 @@ export class ForceSwitchOutAttr extends MoveEffectAttr { if (switchOutTarget.hp > 0) { // for opponent switching out - user.scene.prependToPhase(new SwitchSummonPhase(user.scene, switchOutTarget.getFieldIndex(), user.scene.currentBattle.trainer.getNextSummonIndex((switchOutTarget as EnemyPokemon).trainerSlot), false, this.batonPass, false), MoveEndPhase); + user.scene.prependToPhase(new SwitchSummonPhase(user.scene, switchOutTarget.getFieldIndex(), (user.scene.currentBattle.trainer ? user.scene.currentBattle.trainer.getNextSummonIndex((switchOutTarget as EnemyPokemon).trainerSlot) : 0), false, this.batonPass, false), MoveEndPhase); } } else { // Switch out logic for everything else @@ -4926,7 +4933,7 @@ export class RemoveTypeAttr extends MoveEffectAttr { return false; } - if (user.isTerastallized && user.getTeraType() === this.removedType) { // active tera types cannot be removed + if (user.isTerastallized() && user.getTeraType() === this.removedType) { // active tera types cannot be removed return false; } @@ -5048,7 +5055,7 @@ export class FirstMoveTypeAttr extends MoveEffectAttr { return false; } - const firstMoveType = target.getMoveset()[0].getMove().type; + const firstMoveType = target.getMoveset()[0]?.getMove().type!; // TODO: is this bang correct? user.summonData.types = [ firstMoveType ]; user.scene.queueMessage(i18next.t("battle:transformedIntoType", {pokemonName: getPokemonNameWithAffix(user), type: i18next.t(`pokemonInfo:Type.${Type[firstMoveType]}`)})); @@ -5057,21 +5064,21 @@ export class FirstMoveTypeAttr extends MoveEffectAttr { } export class RandomMovesetMoveAttr extends OverrideMoveEffectAttr { - private enemyMoveset: boolean; + private enemyMoveset: boolean | null; constructor(enemyMoveset?: boolean) { super(); - this.enemyMoveset = enemyMoveset; + this.enemyMoveset = enemyMoveset!; // TODO: is this bang correct? } apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { const moveset = (!this.enemyMoveset ? user : target).getMoveset(); - const moves = moveset.filter(m => !m.getMove().hasFlag(MoveFlags.IGNORE_VIRTUAL)); + const moves = moveset.filter(m => !m?.getMove().hasFlag(MoveFlags.IGNORE_VIRTUAL)); if (moves.length) { const move = moves[user.randSeedInt(moves.length)]; - const moveIndex = moveset.findIndex(m => m.moveId === move.moveId); - const moveTargets = getMoveTargets(user, move.moveId); + const moveIndex = moveset.findIndex(m => m?.moveId === move?.moveId); + const moveTargets = getMoveTargets(user, move?.moveId!); // TODO: is this bang correct? if (!moveTargets.targets.length) { return false; } @@ -5092,8 +5099,8 @@ export class RandomMovesetMoveAttr extends OverrideMoveEffectAttr { } } const targets = selectTargets; - user.getMoveQueue().push({ move: move.moveId, targets: targets, ignorePP: true }); - user.scene.unshiftPhase(new MovePhase(user.scene, user, targets, moveset[moveIndex], true)); + user.getMoveQueue().push({ move: move?.moveId!, targets: targets, ignorePP: true }); // TODO: is this bang correct? + user.scene.unshiftPhase(new MovePhase(user.scene, user, targets, moveset[moveIndex]!, true)); // There's a PR to re-do the move(s) that use this Attr, gonna put `!` for now return true; } @@ -5335,12 +5342,12 @@ export class ReducePpMoveAttr extends MoveEffectAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { // Null checks can be skipped due to condition function const lastMove = target.getLastXMoves().find(() => true); - const movesetMove = target.getMoveset().find(m => m.moveId === lastMove.move); - const lastPpUsed = movesetMove.ppUsed; - movesetMove.ppUsed = Math.min(movesetMove.ppUsed + this.reduction, movesetMove.getMovePp()); + const movesetMove = target.getMoveset().find(m => m?.moveId === lastMove?.move); + const lastPpUsed = movesetMove?.ppUsed!; // TODO: is the bang correct? + movesetMove!.ppUsed = Math.min((movesetMove?.ppUsed!) + this.reduction, movesetMove?.getMovePp()!); // TODO: is the bang correct? - const message = i18next.t("battle:ppReduced", {targetName: getPokemonNameWithAffix(target), moveName: movesetMove.getName(), reduction: movesetMove.ppUsed - lastPpUsed}); - user.scene.eventTarget.dispatchEvent(new MoveUsedEvent(target?.id, movesetMove.getMove(), movesetMove.ppUsed)); + const message = i18next.t("battle:ppReduced", {targetName: getPokemonNameWithAffix(target), moveName: movesetMove?.getName(), reduction: (movesetMove?.ppUsed!) - lastPpUsed}); // TODO: is the bang correct? + user.scene.eventTarget.dispatchEvent(new MoveUsedEvent(target?.id, movesetMove?.getMove()!, movesetMove?.ppUsed!)); // TODO: are these bangs correct? user.scene.queueMessage(message); return true; @@ -5350,7 +5357,7 @@ export class ReducePpMoveAttr extends MoveEffectAttr { return (user, target, move) => { const lastMove = target.getLastXMoves().find(() => true); if (lastMove) { - const movesetMove = target.getMoveset().find(m => m.moveId === lastMove.move); + const movesetMove = target.getMoveset().find(m => m?.moveId === lastMove.move); return !!movesetMove?.getPpRatio(); } return false; @@ -5360,7 +5367,7 @@ export class ReducePpMoveAttr extends MoveEffectAttr { getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): number { const lastMove = target.getLastXMoves().find(() => true); if (lastMove) { - const movesetMove = target.getMoveset().find(m => m.moveId === lastMove.move); + const movesetMove = target.getMoveset().find(m => m?.moveId === lastMove.move); if (movesetMove) { const maxPp = movesetMove.getMovePp(); const ppLeft = maxPp - movesetMove.ppUsed; @@ -5397,7 +5404,7 @@ export class AttackReducePpMoveAttr extends ReducePpMoveAttr { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { const lastMove = target.getLastXMoves().find(() => true); if (lastMove) { - const movesetMove = target.getMoveset().find(m => m.moveId === lastMove.move); + const movesetMove = target.getMoveset().find(m => m?.moveId === lastMove.move); if (Boolean(movesetMove?.getPpRatio())) { super.apply(user, target, move, args); } @@ -5443,7 +5450,7 @@ export class MovesetCopyMoveAttr extends OverrideMoveEffectAttr { const copiedMove = allMoves[targetMoves[0].move]; - const thisMoveIndex = user.getMoveset().findIndex(m => m.moveId === move.id); + const thisMoveIndex = user.getMoveset().findIndex(m => m?.moveId === move.id); if (thisMoveIndex === -1) { return false; @@ -5494,7 +5501,7 @@ export class SketchAttr extends MoveEffectAttr { } const sketchedMove = allMoves[targetMove.move]; - const sketchIndex = user.getMoveset().findIndex(m => m.moveId === move.id); + const sketchIndex = user.getMoveset().findIndex(m => m?.moveId === move.id); if (sketchIndex === -1) { return false; } @@ -5533,7 +5540,7 @@ export class SketchAttr extends MoveEffectAttr { return false; } - if (user.getMoveset().find(m => m.moveId === targetMove.move)) { + if (user.getMoveset().find(m => m?.moveId === targetMove.move)) { return false; } @@ -5722,7 +5729,7 @@ export class TransformAttr extends MoveEffectAttr { user.summonData.fusionGender = target.getFusionGender(); user.summonData.stats = [ user.stats[Stat.HP] ].concat(target.stats.slice(1)); user.summonData.battleStats = target.summonData.battleStats.slice(0); - user.summonData.moveset = target.getMoveset().map(m => new PokemonMove(m.moveId, m.ppUsed, m.ppUp)); + user.summonData.moveset = target.getMoveset().map(m => new PokemonMove(m?.moveId!, m?.ppUsed, m?.ppUp)); // TODO: is this bang correct? user.summonData.types = target.getTypes(); user.scene.queueMessage(i18next.t("moveTriggers:transformedIntoTarget", {pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target)})); @@ -5790,7 +5797,7 @@ export class LastResortAttr extends MoveAttr { getCondition(): MoveConditionFunc { return (user: Pokemon, target: Pokemon, move: Move) => { const uniqueUsedMoveIds = new Set(); - const movesetMoveIds = user.getMoveset().map(m => m.moveId); + const movesetMoveIds = user.getMoveset().map(m => m?.moveId); user.getMoveHistory().map(m => { if (m.move !== move.id && movesetMoveIds.find(mm => mm === m.move)) { uniqueUsedMoveIds.add(m.move); @@ -5864,7 +5871,7 @@ const targetSleptOrComatoseCondition: MoveConditionFunc = (user: Pokemon, target export type MoveAttrFilter = (attr: MoveAttr) => boolean; -function applyMoveAttrsInternal(attrFilter: MoveAttrFilter, user: Pokemon, target: Pokemon, move: Move, args: any[]): Promise { +function applyMoveAttrsInternal(attrFilter: MoveAttrFilter, user: Pokemon | null, target: Pokemon | null, move: Move, args: any[]): Promise { return new Promise(resolve => { const attrPromises: Promise[] = []; const moveAttrs = move.attrs.filter(a => attrFilter(a)); @@ -5878,11 +5885,11 @@ function applyMoveAttrsInternal(attrFilter: MoveAttrFilter, user: Pokemon, targe }); } -export function applyMoveAttrs(attrType: Constructor, user: Pokemon, target: Pokemon, move: Move, ...args: any[]): Promise { +export function applyMoveAttrs(attrType: Constructor, user: Pokemon | null, target: Pokemon | null, move: Move, ...args: any[]): Promise { return applyMoveAttrsInternal((attr: MoveAttr) => attr instanceof attrType, user, target, move, args); } -export function applyFilteredMoveAttrs(attrFilter: MoveAttrFilter, user: Pokemon, target: Pokemon, move: Move, ...args: any[]): Promise { +export function applyFilteredMoveAttrs(attrFilter: MoveAttrFilter, user: Pokemon, target: Pokemon | null, move: Move, ...args: any[]): Promise { return applyMoveAttrsInternal(attrFilter, user, target, move, args); } @@ -6889,7 +6896,7 @@ export function initMoves() { .unimplemented(), new SelfStatusMove(Moves.REFRESH, Type.NORMAL, -1, 20, -1, 0, 3) .attr(HealStatusEffectAttr, true, StatusEffect.PARALYSIS, StatusEffect.POISON, StatusEffect.TOXIC, StatusEffect.BURN) - .condition((user, target, move) => user.status && (user.status.effect === StatusEffect.PARALYSIS || user.status.effect === StatusEffect.POISON || user.status.effect === StatusEffect.TOXIC || user.status.effect === StatusEffect.BURN)), + .condition((user, target, move) => !!user.status && (user.status.effect === StatusEffect.PARALYSIS || user.status.effect === StatusEffect.POISON || user.status.effect === StatusEffect.TOXIC || user.status.effect === StatusEffect.BURN)), new SelfStatusMove(Moves.GRUDGE, Type.GHOST, -1, 5, -1, 0, 3) .unimplemented(), new SelfStatusMove(Moves.SNATCH, Type.DARK, -1, 10, -1, 4, 3) @@ -6952,7 +6959,7 @@ export function initMoves() { .attr(FlinchAttr), new AttackMove(Moves.WEATHER_BALL, Type.NORMAL, MoveCategory.SPECIAL, 50, 100, 10, -1, 0, 3) .attr(WeatherBallTypeAttr) - .attr(MovePowerMultiplierAttr, (user, target, move) => [WeatherType.SUNNY, WeatherType.RAIN, WeatherType.SANDSTORM, WeatherType.HAIL, WeatherType.SNOW, WeatherType.FOG, WeatherType.HEAVY_RAIN, WeatherType.HARSH_SUN].includes(user.scene.arena.weather?.weatherType) && !user.scene.arena.weather?.isEffectSuppressed(user.scene) ? 2 : 1) + .attr(MovePowerMultiplierAttr, (user, target, move) => [WeatherType.SUNNY, WeatherType.RAIN, WeatherType.SANDSTORM, WeatherType.HAIL, WeatherType.SNOW, WeatherType.FOG, WeatherType.HEAVY_RAIN, WeatherType.HARSH_SUN].includes(user.scene.arena.weather?.weatherType!) && !user.scene.arena.weather?.isEffectSuppressed(user.scene) ? 2 : 1) // TODO: is this bang correct? .ballBombMove(), new StatusMove(Moves.AROMATHERAPY, Type.GRASS, -1, 5, -1, 0, 3) .attr(PartyStatusCureAttr, i18next.t("moveTriggers:soothingAromaWaftedThroughArea"), Abilities.SAP_SIPPER) @@ -7120,7 +7127,7 @@ export function initMoves() { new AttackMove(Moves.CLOSE_COMBAT, Type.FIGHTING, MoveCategory.PHYSICAL, 120, 100, 5, -1, 0, 4) .attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF ], -1, true), new AttackMove(Moves.PAYBACK, Type.DARK, MoveCategory.PHYSICAL, 50, 100, 10, -1, 0, 4) - .attr(MovePowerMultiplierAttr, (user, target, move) => target.getLastXMoves(1).find(m => m.turn === target.scene.currentBattle.turn) || user.scene.currentBattle.turnCommands[target.getBattlerIndex()].command === Command.BALL ? 2 : 1), + .attr(MovePowerMultiplierAttr, (user, target, move) => target.getLastXMoves(1).find(m => m.turn === target.scene.currentBattle.turn) || user.scene.currentBattle.turnCommands[target.getBattlerIndex()]?.command === Command.BALL ? 2 : 1), new AttackMove(Moves.ASSURANCE, Type.DARK, MoveCategory.PHYSICAL, 60, 100, 10, -1, 0, 4) .attr(MovePowerMultiplierAttr, (user, target, move) => target.turnData.damageTaken > 0 ? 2 : 1), new StatusMove(Moves.EMBARGO, Type.DARK, 100, 15, -1, 0, 4) @@ -7135,7 +7142,7 @@ export function initMoves() { if (user.status?.effect && isNonVolatileStatusEffect(user.status.effect)) { statusToApply = user.status.effect; } - return statusToApply && target.canSetStatus(statusToApply, false, false, user); + return !!statusToApply && target.canSetStatus(statusToApply, false, false, user); } ), new AttackMove(Moves.TRUMP_CARD, Type.NORMAL, MoveCategory.SPECIAL, -1, -1, 5, -1, 0, 4) @@ -7173,7 +7180,7 @@ export function initMoves() { new StatusMove(Moves.WORRY_SEED, Type.GRASS, 100, 10, -1, 0, 4) .attr(AbilityChangeAttr, Abilities.INSOMNIA), new AttackMove(Moves.SUCKER_PUNCH, Type.DARK, MoveCategory.PHYSICAL, 70, 100, 5, -1, 1, 4) - .condition((user, target, move) => user.scene.currentBattle.turnCommands[target.getBattlerIndex()].command === Command.FIGHT && !target.turnData.acted && allMoves[user.scene.currentBattle.turnCommands[target.getBattlerIndex()].move.move].category !== MoveCategory.STATUS), + .condition((user, target, move) => user.scene.currentBattle.turnCommands[target.getBattlerIndex()]?.command === Command.FIGHT && !target.turnData.acted && allMoves[user.scene.currentBattle.turnCommands[target.getBattlerIndex()]?.move?.move!].category !== MoveCategory.STATUS), // TODO: is this bang correct? new StatusMove(Moves.TOXIC_SPIKES, Type.POISON, -1, 20, -1, 0, 4) .attr(AddArenaTrapTagAttr, ArenaTagType.TOXIC_SPIKES) .target(MoveTarget.ENEMY_SIDE), @@ -8016,7 +8023,7 @@ export function initMoves() { new AttackMove(Moves.SMART_STRIKE, Type.STEEL, MoveCategory.PHYSICAL, 70, -1, 10, -1, 0, 7), new StatusMove(Moves.PURIFY, Type.POISON, -1, 20, -1, 0, 7) .condition( - (user: Pokemon, target: Pokemon, move: Move) => isNonVolatileStatusEffect(target.status?.effect)) + (user: Pokemon, target: Pokemon, move: Move) => isNonVolatileStatusEffect(target.status?.effect!)) // TODO: is this bang correct? .attr(HealAttr, 0.5) .attr(HealStatusEffectAttr, false, ...getNonVolatileStatusEffects()) .triageMove(), @@ -8738,7 +8745,7 @@ export function initMoves() { .slicingMove(), new AttackMove(Moves.HYDRO_STEAM, Type.WATER, MoveCategory.SPECIAL, 80, 100, 15, -1, 0, 9) .attr(IgnoreWeatherTypeDebuffAttr, WeatherType.SUNNY) - .attr(MovePowerMultiplierAttr, (user, target, move) => [WeatherType.SUNNY, WeatherType.HARSH_SUN].includes(user.scene.arena.weather?.weatherType) && !user.scene.arena.weather?.isEffectSuppressed(user.scene) ? 1.5 : 1), + .attr(MovePowerMultiplierAttr, (user, target, move) => [WeatherType.SUNNY, WeatherType.HARSH_SUN].includes(user.scene.arena.weather?.weatherType!) && !user.scene.arena.weather?.isEffectSuppressed(user.scene) ? 1.5 : 1), // TODO: is this bang correct? new AttackMove(Moves.RUINATION, Type.DARK, MoveCategory.SPECIAL, -1, 90, 10, -1, 0, 9) .attr(TargetHalfHpDamageAttr), new AttackMove(Moves.COLLISION_COURSE, Type.FIGHTING, MoveCategory.PHYSICAL, 100, 100, 5, -1, 0, 9) @@ -8846,7 +8853,7 @@ export function initMoves() { new SelfStatusMove(Moves.BURNING_BULWARK, Type.FIRE, -1, 10, -1, 4, 9) .attr(ProtectAttr, BattlerTagType.BURNING_BULWARK), new AttackMove(Moves.THUNDERCLAP, Type.ELECTRIC, MoveCategory.SPECIAL, 70, 100, 5, -1, 1, 9) - .condition((user, target, move) => user.scene.currentBattle.turnCommands[target.getBattlerIndex()].command === Command.FIGHT && !target.turnData.acted && allMoves[user.scene.currentBattle.turnCommands[target.getBattlerIndex()].move.move].category !== MoveCategory.STATUS), + .condition((user, target, move) => user.scene.currentBattle.turnCommands[target.getBattlerIndex()]?.command === Command.FIGHT && !target.turnData.acted && allMoves[user.scene.currentBattle.turnCommands[target.getBattlerIndex()]?.move?.move!].category !== MoveCategory.STATUS), // TODO: is this bang correct? new AttackMove(Moves.MIGHTY_CLEAVE, Type.ROCK, MoveCategory.PHYSICAL, 95, 100, 5, -1, 0, 9) .slicingMove() .ignoresProtect(), @@ -8873,7 +8880,7 @@ export function initMoves() { .partial(), new AttackMove(Moves.UPPER_HAND, Type.FIGHTING, MoveCategory.PHYSICAL, 65, 100, 15, 100, 3, 9) .attr(FlinchAttr) - .condition((user, target, move) => user.scene.currentBattle.turnCommands[target.getBattlerIndex()].command === Command.FIGHT && !target.turnData.acted && allMoves[user.scene.currentBattle.turnCommands[target.getBattlerIndex()].move.move].category !== MoveCategory.STATUS && allMoves[user.scene.currentBattle.turnCommands[target.getBattlerIndex()].move.move].priority > 0 ) + .condition((user, target, move) => user.scene.currentBattle.turnCommands[target.getBattlerIndex()]?.command === Command.FIGHT && !target.turnData.acted && allMoves[user.scene.currentBattle.turnCommands[target.getBattlerIndex()]?.move?.move!].category !== MoveCategory.STATUS && allMoves[user.scene.currentBattle.turnCommands[target.getBattlerIndex()]?.move?.move!].priority > 0 ) // TODO: is this bang correct? //TODO: Should also apply when target move priority increased by ability ex. gale wings .partial(), new AttackMove(Moves.MALIGNANT_CHAIN, Type.POISON, MoveCategory.SPECIAL, 100, 100, 5, 50, 0, 9) diff --git a/src/data/nature.ts b/src/data/nature.ts index 1ae3b76a6b6..72e5bb7863c 100644 --- a/src/data/nature.ts +++ b/src/data/nature.ts @@ -15,8 +15,8 @@ export function getNatureName(nature: Nature, includeStatEffects: boolean = fals } if (includeStatEffects) { const stats = Utils.getEnumValues(Stat).slice(1); - let increasedStat: Stat = null; - let decreasedStat: Stat = null; + let increasedStat: Stat | null = null; + let decreasedStat: Stat | null = null; for (const stat of stats) { const multiplier = getNatureStatMultiplier(nature, stat); if (multiplier > 1) { diff --git a/src/data/pokemon-evolutions.ts b/src/data/pokemon-evolutions.ts index 236d174492f..e7baf608b97 100644 --- a/src/data/pokemon-evolutions.ts +++ b/src/data/pokemon-evolutions.ts @@ -59,26 +59,26 @@ export type EvolutionConditionEnforceFunc = (p: Pokemon) => void; export class SpeciesFormEvolution { public speciesId: Species; - public preFormKey: string; - public evoFormKey: string; + public preFormKey: string | null; + public evoFormKey: string | null; public level: integer; - public item: EvolutionItem; - public condition: SpeciesEvolutionCondition; - public wildDelay: SpeciesWildEvolutionDelay; + public item: EvolutionItem | null; + public condition: SpeciesEvolutionCondition | null; + public wildDelay: SpeciesWildEvolutionDelay | null; - constructor(speciesId: Species, preFormKey: string, evoFormKey: string, level: integer, item: EvolutionItem, condition: SpeciesEvolutionCondition, wildDelay?: SpeciesWildEvolutionDelay) { + constructor(speciesId: Species, preFormKey: string | null, evoFormKey: string | null, level: integer, item: EvolutionItem | null, condition: SpeciesEvolutionCondition | null, wildDelay?: SpeciesWildEvolutionDelay | null) { this.speciesId = speciesId; this.preFormKey = preFormKey; this.evoFormKey = evoFormKey; this.level = level; this.item = item || EvolutionItem.NONE; this.condition = condition; - this.wildDelay = wildDelay || SpeciesWildEvolutionDelay.NONE; + this.wildDelay = wildDelay!; // TODO: is this bang correct? } } export class SpeciesEvolution extends SpeciesFormEvolution { - constructor(speciesId: Species, level: integer, item: EvolutionItem, condition: SpeciesEvolutionCondition, wildDelay?: SpeciesWildEvolutionDelay) { + constructor(speciesId: Species, level: integer, item: EvolutionItem | null, condition: SpeciesEvolutionCondition | null, wildDelay?: SpeciesWildEvolutionDelay | null) { super(speciesId, null, null, level, item, condition, wildDelay); } } @@ -95,7 +95,7 @@ export class FusionSpeciesFormEvolution extends SpeciesFormEvolution { export class SpeciesEvolutionCondition { public predicate: EvolutionConditionPredicate; - public enforceFunc: EvolutionConditionEnforceFunc; + public enforceFunc: EvolutionConditionEnforceFunc | undefined; constructor(predicate: EvolutionConditionPredicate, enforceFunc?: EvolutionConditionEnforceFunc) { this.predicate = predicate; @@ -1264,17 +1264,17 @@ export const pokemonEvolutions: PokemonEvolutions = { new SpeciesEvolution(Species.EXEGGUTOR, 1, EvolutionItem.LEAF_STONE, null, SpeciesWildEvolutionDelay.LONG) ], [Species.TANGELA]: [ - new SpeciesEvolution(Species.TANGROWTH, 34, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m.moveId === Moves.ANCIENT_POWER).length > 0), SpeciesWildEvolutionDelay.LONG) + new SpeciesEvolution(Species.TANGROWTH, 34, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.ANCIENT_POWER).length > 0), SpeciesWildEvolutionDelay.LONG) ], [Species.LICKITUNG]: [ - new SpeciesEvolution(Species.LICKILICKY, 32, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m.moveId === Moves.ROLLOUT).length > 0), SpeciesWildEvolutionDelay.LONG) + new SpeciesEvolution(Species.LICKILICKY, 32, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.ROLLOUT).length > 0), SpeciesWildEvolutionDelay.LONG) ], [Species.STARYU]: [ new SpeciesEvolution(Species.STARMIE, 1, EvolutionItem.WATER_STONE, null, SpeciesWildEvolutionDelay.LONG) ], [Species.EEVEE]: [ - new SpeciesFormEvolution(Species.SYLVEON, "", "", 1, null, new SpeciesFriendshipEvolutionCondition(70, p => !!p.getMoveset().find(m => m.getMove().type === Type.FAIRY)), SpeciesWildEvolutionDelay.LONG), - new SpeciesFormEvolution(Species.SYLVEON, "partner", "", 1, null, new SpeciesFriendshipEvolutionCondition(70, p => !!p.getMoveset().find(m => m.getMove().type === Type.FAIRY)), SpeciesWildEvolutionDelay.LONG), + new SpeciesFormEvolution(Species.SYLVEON, "", "", 1, null, new SpeciesFriendshipEvolutionCondition(70, p => !!p.getMoveset().find(m => m?.getMove().type === Type.FAIRY)), SpeciesWildEvolutionDelay.LONG), + new SpeciesFormEvolution(Species.SYLVEON, "partner", "", 1, null, new SpeciesFriendshipEvolutionCondition(70, p => !!p.getMoveset().find(m => m?.getMove().type === Type.FAIRY)), SpeciesWildEvolutionDelay.LONG), new SpeciesFormEvolution(Species.ESPEON, "", "", 1, null, new SpeciesFriendshipEvolutionCondition(70, p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAY), SpeciesWildEvolutionDelay.LONG), new SpeciesFormEvolution(Species.ESPEON, "partner", "", 1, null, new SpeciesFriendshipEvolutionCondition(70, p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAY), SpeciesWildEvolutionDelay.LONG), new SpeciesFormEvolution(Species.UMBREON, "", "", 1, null, new SpeciesFriendshipEvolutionCondition(70, p => p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT), SpeciesWildEvolutionDelay.LONG), @@ -1294,13 +1294,13 @@ export const pokemonEvolutions: PokemonEvolutions = { new SpeciesEvolution(Species.TOGEKISS, 1, EvolutionItem.SHINY_STONE, null, SpeciesWildEvolutionDelay.VERY_LONG) ], [Species.AIPOM]: [ - new SpeciesEvolution(Species.AMBIPOM, 32, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m.moveId === Moves.DOUBLE_HIT).length > 0), SpeciesWildEvolutionDelay.LONG) + new SpeciesEvolution(Species.AMBIPOM, 32, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.DOUBLE_HIT).length > 0), SpeciesWildEvolutionDelay.LONG) ], [Species.SUNKERN]: [ new SpeciesEvolution(Species.SUNFLORA, 1, EvolutionItem.SUN_STONE, null, SpeciesWildEvolutionDelay.LONG) ], [Species.YANMA]: [ - new SpeciesEvolution(Species.YANMEGA, 33, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m.moveId === Moves.ANCIENT_POWER).length > 0), SpeciesWildEvolutionDelay.LONG) + new SpeciesEvolution(Species.YANMEGA, 33, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.ANCIENT_POWER).length > 0), SpeciesWildEvolutionDelay.LONG) ], [Species.MURKROW]: [ new SpeciesEvolution(Species.HONCHKROW, 1, EvolutionItem.DUSK_STONE, null, SpeciesWildEvolutionDelay.VERY_LONG) @@ -1309,17 +1309,17 @@ export const pokemonEvolutions: PokemonEvolutions = { new SpeciesEvolution(Species.MISMAGIUS, 1, EvolutionItem.DUSK_STONE, null, SpeciesWildEvolutionDelay.VERY_LONG) ], [Species.GIRAFARIG]: [ - new SpeciesEvolution(Species.FARIGIRAF, 32, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m.moveId === Moves.TWIN_BEAM).length > 0), SpeciesWildEvolutionDelay.LONG) + new SpeciesEvolution(Species.FARIGIRAF, 32, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.TWIN_BEAM).length > 0), SpeciesWildEvolutionDelay.LONG) ], [Species.DUNSPARCE]: [ new SpeciesFormEvolution(Species.DUDUNSPARCE, "", "three-segment", 32, null, new SpeciesEvolutionCondition(p => { let ret = false; - if (p.moveset.filter(m => m.moveId === Moves.HYPER_DRILL).length > 0) { + if (p.moveset.filter(m => m?.moveId === Moves.HYPER_DRILL).length > 0) { p.scene.executeWithSeedOffset(() => ret = !Utils.randSeedInt(4), p.id); } return ret; }), SpeciesWildEvolutionDelay.LONG), - new SpeciesEvolution(Species.DUDUNSPARCE, 32, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m.moveId === Moves.HYPER_DRILL).length > 0), SpeciesWildEvolutionDelay.LONG) + new SpeciesEvolution(Species.DUDUNSPARCE, 32, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.HYPER_DRILL).length > 0), SpeciesWildEvolutionDelay.LONG) ], [Species.GLIGAR]: [ new SpeciesEvolution(Species.GLISCOR, 1, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT /* Razor fang at night*/), SpeciesWildEvolutionDelay.LONG) @@ -1331,10 +1331,10 @@ export const pokemonEvolutions: PokemonEvolutions = { new SpeciesEvolution(Species.URSALUNA, 1, EvolutionItem.PEAT_BLOCK, null, SpeciesWildEvolutionDelay.VERY_LONG) //Ursaring does not evolve into Bloodmoon Ursaluna ], [Species.PILOSWINE]: [ - new SpeciesEvolution(Species.MAMOSWINE, 1, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m.moveId === Moves.ANCIENT_POWER).length > 0), SpeciesWildEvolutionDelay.VERY_LONG) + new SpeciesEvolution(Species.MAMOSWINE, 1, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.ANCIENT_POWER).length > 0), SpeciesWildEvolutionDelay.VERY_LONG) ], [Species.STANTLER]: [ - new SpeciesEvolution(Species.WYRDEER, 25, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m.moveId === Moves.PSYSHIELD_BASH).length > 0), SpeciesWildEvolutionDelay.VERY_LONG) + new SpeciesEvolution(Species.WYRDEER, 25, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.PSYSHIELD_BASH).length > 0), SpeciesWildEvolutionDelay.VERY_LONG) ], [Species.LOMBRE]: [ new SpeciesEvolution(Species.LUDICOLO, 1, EvolutionItem.WATER_STONE, null, SpeciesWildEvolutionDelay.LONG) @@ -1352,11 +1352,11 @@ export const pokemonEvolutions: PokemonEvolutions = { new SpeciesEvolution(Species.ROSERADE, 1, EvolutionItem.SHINY_STONE, null, SpeciesWildEvolutionDelay.VERY_LONG) ], [Species.BONSLY]: [ - new SpeciesEvolution(Species.SUDOWOODO, 1, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m.moveId === Moves.MIMIC).length > 0), SpeciesWildEvolutionDelay.MEDIUM) + new SpeciesEvolution(Species.SUDOWOODO, 1, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.MIMIC).length > 0), SpeciesWildEvolutionDelay.MEDIUM) ], [Species.MIME_JR]: [ - new SpeciesEvolution(Species.GALAR_MR_MIME, 1, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m.moveId === Moves.MIMIC).length > 0 && (p.scene.arena.biomeType === Biome.ICE_CAVE || p.scene.arena.biomeType === Biome.SNOWY_FOREST)), SpeciesWildEvolutionDelay.MEDIUM), - new SpeciesEvolution(Species.MR_MIME, 1, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m.moveId === Moves.MIMIC).length > 0), SpeciesWildEvolutionDelay.MEDIUM) + new SpeciesEvolution(Species.GALAR_MR_MIME, 1, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.MIMIC).length > 0 && (p.scene.arena.biomeType === Biome.ICE_CAVE || p.scene.arena.biomeType === Biome.SNOWY_FOREST)), SpeciesWildEvolutionDelay.MEDIUM), + new SpeciesEvolution(Species.MR_MIME, 1, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.MIMIC).length > 0), SpeciesWildEvolutionDelay.MEDIUM) ], [Species.PANSAGE]: [ new SpeciesEvolution(Species.SIMISAGE, 1, EvolutionItem.LEAF_STONE, null, SpeciesWildEvolutionDelay.LONG) @@ -1411,10 +1411,10 @@ export const pokemonEvolutions: PokemonEvolutions = { new SpeciesFormEvolution(Species.LYCANROC, "", "midnight", 25, null, new SpeciesEvolutionCondition(p => (p.scene.arena.getTimeOfDay() === TimeOfDay.DUSK || p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT) && (p.formIndex === 0)), null) ], [Species.STEENEE]: [ - new SpeciesEvolution(Species.TSAREENA, 28, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m.moveId === Moves.STOMP).length > 0), SpeciesWildEvolutionDelay.LONG) + new SpeciesEvolution(Species.TSAREENA, 28, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.STOMP).length > 0), SpeciesWildEvolutionDelay.LONG) ], [Species.POIPOLE]: [ - new SpeciesEvolution(Species.NAGANADEL, 1, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m.moveId === Moves.DRAGON_PULSE).length > 0), SpeciesWildEvolutionDelay.LONG) + new SpeciesEvolution(Species.NAGANADEL, 1, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.DRAGON_PULSE).length > 0), SpeciesWildEvolutionDelay.LONG) ], [Species.ALOLA_SANDSHREW]: [ new SpeciesEvolution(Species.ALOLA_SANDSLASH, 1, EvolutionItem.ICE_STONE, null, SpeciesWildEvolutionDelay.LONG) @@ -1428,7 +1428,7 @@ export const pokemonEvolutions: PokemonEvolutions = { new SpeciesEvolution(Species.APPLETUN, 1, EvolutionItem.SWEET_APPLE, null, SpeciesWildEvolutionDelay.LONG) ], [Species.CLOBBOPUS]: [ - new SpeciesEvolution(Species.GRAPPLOCT, 35, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m.moveId === Moves.TAUNT).length > 0), SpeciesWildEvolutionDelay.MEDIUM) + new SpeciesEvolution(Species.GRAPPLOCT, 35, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.TAUNT).length > 0), SpeciesWildEvolutionDelay.MEDIUM) ], [Species.SINISTEA]: [ new SpeciesFormEvolution(Species.POLTEAGEIST, "phony", "phony", 1, EvolutionItem.CRACKED_POT, null, SpeciesWildEvolutionDelay.LONG), @@ -1462,7 +1462,7 @@ export const pokemonEvolutions: PokemonEvolutions = { new SpeciesEvolution(Species.HISUI_ELECTRODE, 1, EvolutionItem.LEAF_STONE, null, SpeciesWildEvolutionDelay.LONG) ], [Species.HISUI_QWILFISH]: [ - new SpeciesEvolution(Species.OVERQWIL, 28, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m.moveId === Moves.BARB_BARRAGE).length > 0), SpeciesWildEvolutionDelay.LONG) + new SpeciesEvolution(Species.OVERQWIL, 28, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.BARB_BARRAGE).length > 0), SpeciesWildEvolutionDelay.LONG) ], [Species.HISUI_SNEASEL]: [ new SpeciesEvolution(Species.SNEASLER, 1, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAY /* Razor claw at day*/), SpeciesWildEvolutionDelay.LONG) @@ -1485,7 +1485,7 @@ export const pokemonEvolutions: PokemonEvolutions = { new SpeciesFormEvolution(Species.SINISTCHA, "artisan", "masterpiece", 1, EvolutionItem.MASTERPIECE_TEACUP, null, SpeciesWildEvolutionDelay.LONG) ], [Species.DIPPLIN]: [ - new SpeciesEvolution(Species.HYDRAPPLE, 1, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m.moveId === Moves.DRAGON_CHEER).length > 0), SpeciesWildEvolutionDelay.VERY_LONG) + new SpeciesEvolution(Species.HYDRAPPLE, 1, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.DRAGON_CHEER).length > 0), SpeciesWildEvolutionDelay.VERY_LONG) ], [Species.KADABRA]: [ new SpeciesEvolution(Species.ALAKAZAM, 1, EvolutionItem.LINKING_CORD, null, SpeciesWildEvolutionDelay.VERY_LONG) @@ -1501,7 +1501,7 @@ export const pokemonEvolutions: PokemonEvolutions = { ], [Species.ONIX]: [ new SpeciesEvolution(Species.STEELIX, 1, EvolutionItem.LINKING_CORD, new SpeciesEvolutionCondition( - p => p.moveset.filter(m => m.getMove().type === Type.STEEL).length > 0), + p => p.moveset.filter(m => m?.getMove().type === Type.STEEL).length > 0), SpeciesWildEvolutionDelay.VERY_LONG) ], [Species.RHYDON]: [ @@ -1512,7 +1512,7 @@ export const pokemonEvolutions: PokemonEvolutions = { ], [Species.SCYTHER]: [ new SpeciesEvolution(Species.SCIZOR, 1, EvolutionItem.LINKING_CORD, new SpeciesEvolutionCondition( - p => p.moveset.filter(m => m.getMove().type === Type.STEEL).length > 0), + p => p.moveset.filter(m => m?.getMove().type === Type.STEEL).length > 0), SpeciesWildEvolutionDelay.VERY_LONG), new SpeciesEvolution(Species.KLEAVOR, 1, EvolutionItem.BLACK_AUGURITE, null, SpeciesWildEvolutionDelay.VERY_LONG) ], @@ -1566,7 +1566,7 @@ export const pokemonEvolutions: PokemonEvolutions = { new SpeciesEvolution(Species.ALOLA_GOLEM, 1, EvolutionItem.LINKING_CORD, null, SpeciesWildEvolutionDelay.VERY_LONG) ], [Species.PRIMEAPE]: [ - new SpeciesEvolution(Species.ANNIHILAPE, 35, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m.moveId === Moves.RAGE_FIST).length > 0), SpeciesWildEvolutionDelay.VERY_LONG) + new SpeciesEvolution(Species.ANNIHILAPE, 35, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.RAGE_FIST).length > 0), SpeciesWildEvolutionDelay.VERY_LONG) ], [Species.GOLBAT]: [ new SpeciesEvolution(Species.CROBAT, 1, null, new SpeciesFriendshipEvolutionCondition(110), SpeciesWildEvolutionDelay.VERY_LONG) diff --git a/src/data/pokemon-forms.ts b/src/data/pokemon-forms.ts index 7e29ea994e9..a55b9186839 100644 --- a/src/data/pokemon-forms.ts +++ b/src/data/pokemon-forms.ts @@ -181,7 +181,7 @@ export class SpeciesFormChange { return true; } - findTrigger(triggerType: Constructor): SpeciesFormChangeTrigger { + findTrigger(triggerType: Constructor): SpeciesFormChangeTrigger | null { if (!this.trigger.hasTriggerType(triggerType)) { return null; } @@ -189,7 +189,7 @@ export class SpeciesFormChange { const trigger = this.trigger; if (trigger instanceof SpeciesFormChangeCompoundTrigger) { - return trigger.triggers.find(t => t.hasTriggerType(triggerType)); + return trigger.triggers.find(t => t.hasTriggerType(triggerType))!; // TODO: is this bang correct? } return trigger; @@ -198,11 +198,11 @@ export class SpeciesFormChange { export class SpeciesFormChangeCondition { public predicate: SpeciesFormChangeConditionPredicate; - public enforceFunc: SpeciesFormChangeConditionEnforceFunc; + public enforceFunc: SpeciesFormChangeConditionEnforceFunc | null; constructor(predicate: SpeciesFormChangeConditionPredicate, enforceFunc?: SpeciesFormChangeConditionEnforceFunc) { this.predicate = predicate; - this.enforceFunc = enforceFunc; + this.enforceFunc = enforceFunc!; // TODO: is this bang correct? } } @@ -314,7 +314,7 @@ export class SpeciesFormChangeMoveLearnedTrigger extends SpeciesFormChangeTrigge } canChange(pokemon: Pokemon): boolean { - return (!!pokemon.moveset.filter(m => m.moveId === this.move).length) === this.known; + return (!!pokemon.moveset.filter(m => m?.moveId === this.move).length) === this.known; } } @@ -332,7 +332,7 @@ export abstract class SpeciesFormChangeMoveTrigger extends SpeciesFormChangeTrig export class SpeciesFormChangePreMoveTrigger extends SpeciesFormChangeMoveTrigger { canChange(pokemon: Pokemon): boolean { const command = pokemon.scene.currentBattle.turnCommands[pokemon.getBattlerIndex()]; - return command?.move && this.movePredicate(command.move.move) === this.used; + return !!command?.move && this.movePredicate(command.move.move) === this.used; } } diff --git a/src/data/pokemon-species.ts b/src/data/pokemon-species.ts index fa6587145ad..837cad4a0df 100644 --- a/src/data/pokemon-species.ts +++ b/src/data/pokemon-species.ts @@ -28,21 +28,21 @@ export enum Region { PALDEA } -export function getPokemonSpecies(species: Species): PokemonSpecies { +export function getPokemonSpecies(species: Species | Species[]): PokemonSpecies { // If a special pool (named trainers) is used here it CAN happen that they have a array as species (which means choose one of those two). So we catch that with this code block if (Array.isArray(species)) { // Pick a random species from the list species = species[Math.floor(Math.random() * species.length)]; } if (species >= 2000) { - return allSpecies.find(s => s.speciesId === species); + return allSpecies.find(s => s.speciesId === species)!; // TODO: is this bang correct? } return allSpecies[species - 1]; } export function getPokemonSpeciesForm(species: Species, formIndex: integer): PokemonSpeciesForm { const retSpecies: PokemonSpecies = species >= 2000 - ? allSpecies.find(s => s.speciesId === species) + ? allSpecies.find(s => s.speciesId === species)! // TODO: is the bang correct? : allSpecies[species - 1]; if (formIndex < retSpecies.forms?.length) { return retSpecies.forms[formIndex]; @@ -97,7 +97,7 @@ export function getFusedSpeciesName(speciesAName: string, speciesBName: string): fragB = fragB.slice(1); } else { const newCharMatch = new RegExp(`[^${lastCharA}]`).exec(fragB); - if (newCharMatch?.index > 0) { + if (newCharMatch?.index !== undefined && newCharMatch.index > 0) { fragB = fragB.slice(newCharMatch.index); } } @@ -125,7 +125,7 @@ export abstract class PokemonSpeciesForm { public formIndex: integer; public generation: integer; public type1: Type; - public type2: Type; + public type2: Type | null; public height: number; public weight: number; public ability1: Abilities; @@ -139,7 +139,7 @@ export abstract class PokemonSpeciesForm { public genderDiffs: boolean; public isStarterSelectable: boolean; - constructor(type1: Type, type2: Type, height: number, weight: number, ability1: Abilities, ability2: Abilities, abilityHidden: Abilities, + constructor(type1: Type, type2: Type | null, height: number, weight: number, ability1: Abilities, ability2: Abilities, abilityHidden: Abilities, baseTotal: integer, baseHp: integer, baseAtk: integer, baseDef: integer, baseSpatk: integer, baseSpdef: integer, baseSpd: integer, catchRate: integer, baseFriendship: integer, baseExp: integer, genderDiffs: boolean, isStarterSelectable: boolean) { this.type1 = type1; @@ -267,7 +267,7 @@ export abstract class PokemonSpeciesForm { return `${/_[1-3]$/.test(spriteId) ? "variant/" : ""}${spriteId}`; } - getSpriteId(female: boolean, formIndex?: integer, shiny?: boolean, variant?: integer, back?: boolean): string { + getSpriteId(female: boolean, formIndex?: integer, shiny?: boolean, variant: integer = 0, back?: boolean): string { if (formIndex === undefined || this instanceof PokemonForm) { formIndex = this.formIndex; } @@ -281,7 +281,7 @@ export abstract class PokemonSpeciesForm { `${back ? "back__" : ""}${baseSpriteKey}`.split("__").map(p => config ? config = config[p] : null); const variantSet = config as VariantSet; - return `${back ? "back__" : ""}${shiny && (!variantSet || (!variant && !variantSet[variant || 0])) ? "shiny__" : ""}${baseSpriteKey}${shiny && variantSet && variantSet[variant || 0] === 2 ? `_${variant + 1}` : ""}`; + return `${back ? "back__" : ""}${shiny && (!variantSet || (!variant && !variantSet[variant || 0])) ? "shiny__" : ""}${baseSpriteKey}${shiny && variantSet && variantSet[variant] === 2 ? `_${variant + 1}` : ""}`; } getSpriteKey(female: boolean, formIndex?: integer, shiny?: boolean, variant?: integer): string { @@ -297,10 +297,10 @@ export abstract class PokemonSpeciesForm { * @returns species id if no additional forms, index with formkey if a pokemon with a form */ getVariantDataIndex(formIndex?: integer) { - let formkey = null; - let variantDataIndex: integer|string = this.speciesId; + let formkey: string | null = null; + let variantDataIndex: integer | string = this.speciesId; const species = getPokemonSpecies(this.speciesId); - if (species.forms.length > 0) { + if (species.forms.length > 0 && formIndex !== undefined) { formkey = species.forms[formIndex]?.formSpriteKey; if (formkey) { variantDataIndex = `${this.speciesId}-${formkey}`; @@ -311,7 +311,7 @@ export abstract class PokemonSpeciesForm { getIconAtlasKey(formIndex?: integer, shiny?: boolean, variant?: integer): string { const variantDataIndex = this.getVariantDataIndex(formIndex); - const isVariant = shiny && variantData[variantDataIndex] && variantData[variantDataIndex][variant]; + const isVariant = shiny && variantData[variantDataIndex] && (variant !== undefined && variantData[variantDataIndex][variant]); return `pokemon_icons_${this.generation}${isVariant ? "v" : ""}`; } @@ -324,7 +324,7 @@ export abstract class PokemonSpeciesForm { let ret = this.speciesId.toString(); - const isVariant = shiny && variantData[variantDataIndex] && variantData[variantDataIndex][variant]; + const isVariant = shiny && variantData[variantDataIndex] && (variant !== undefined && variantData[variantDataIndex][variant]); if (shiny && !isVariant) { ret += "s"; @@ -382,7 +382,7 @@ export abstract class PokemonSpeciesForm { let ret = speciesId.toString(); const forms = getPokemonSpecies(speciesId).forms; if (forms.length) { - if (formIndex >= forms.length) { + if (formIndex !== undefined && formIndex >= forms.length) { console.warn(`Attempted accessing form with index ${formIndex} of species ${getPokemonSpecies(speciesId).getName()} with only ${forms.length || 0} forms`); formIndex = Math.min(formIndex, forms.length - 1); } @@ -478,7 +478,7 @@ export abstract class PokemonSpeciesForm { let config = variantData; spritePath.split("/").map(p => config ? config = config[p] : null); const variantSet = config as VariantSet; - if (variantSet && variantSet[variant] === 1) { + if (variantSet && (variant !== undefined && variantSet[variant] === 1)) { const populateVariantColors = (key: string): Promise => { return new Promise(resolve => { if (variantColorCache.hasOwnProperty(key)) { @@ -507,7 +507,7 @@ export abstract class PokemonSpeciesForm { cry(scene: BattleScene, soundConfig?: Phaser.Types.Sound.SoundConfig, ignorePlay?: boolean): AnySound { const cryKey = this.getCryKey(this.formIndex); - let cry = scene.sound.get(cryKey) as AnySound; + let cry: AnySound | null = scene.sound.get(cryKey) as AnySound; if (cry?.pendingRemove) { cry = null; } @@ -532,30 +532,32 @@ export abstract class PokemonSpeciesForm { const frame = sourceFrame; canvas.width = frame.width; canvas.height = frame.height; - context.drawImage(sourceImage, frame.cutX, frame.cutY, frame.width, frame.height, 0, 0, frame.width, frame.height); - const imageData = context.getImageData(frame.cutX, frame.cutY, frame.width, frame.height); - const pixelData = imageData.data; + context?.drawImage(sourceImage, frame.cutX, frame.cutY, frame.width, frame.height, 0, 0, frame.width, frame.height); + const imageData = context?.getImageData(frame.cutX, frame.cutY, frame.width, frame.height); + const pixelData = imageData?.data; + const pixelColors: number[] = []; - for (let i = 0; i < pixelData.length; i += 4) { - if (pixelData[i + 3]) { - const pixel = pixelData.slice(i, i + 4); - const [ r, g, b, a ] = pixel; - if (!spriteColors.find(c => c[0] === r && c[1] === g && c[2] === b)) { - spriteColors.push([ r, g, b, a ]); + if (pixelData?.length !== undefined) { + for (let i = 0; i < pixelData.length; i += 4) { + if (pixelData[i + 3]) { + const pixel = pixelData.slice(i, i + 4); + const [ r, g, b, a ] = pixel; + if (!spriteColors.find(c => c[0] === r && c[1] === g && c[2] === b)) { + spriteColors.push([ r, g, b, a ]); + } } } - } - const pixelColors = []; - for (let i = 0; i < pixelData.length; i += 4) { - const total = pixelData.slice(i, i + 3).reduce((total: integer, value: integer) => total + value, 0); - if (!total) { - continue; + for (let i = 0; i < pixelData.length; i += 4) { + const total = pixelData.slice(i, i + 3).reduce((total: integer, value: integer) => total + value, 0); + if (!total) { + continue; + } + pixelColors.push(argbFromRgba({ r: pixelData[i], g: pixelData[i + 1], b: pixelData[i + 2], a: pixelData[i + 3] })); } - pixelColors.push(argbFromRgba({ r: pixelData[i], g: pixelData[i + 1], b: pixelData[i + 2], a: pixelData[i + 3] })); } - let paletteColors: Map; + let paletteColors: Map = new Map(); const originalRandom = Math.random; Math.random = () => Phaser.Math.RND.realInRange(0, 1); @@ -577,15 +579,15 @@ export default class PokemonSpecies extends PokemonSpeciesForm implements Locali public mythical: boolean; public species: string; public growthRate: GrowthRate; - public malePercent: number; + public malePercent: number | null; public genderDiffs: boolean; public canChangeForm: boolean; public forms: PokemonForm[]; constructor(id: Species, generation: integer, subLegendary: boolean, legendary: boolean, mythical: boolean, species: string, - type1: Type, type2: Type, height: number, weight: number, ability1: Abilities, ability2: Abilities, abilityHidden: Abilities, + type1: Type, type2: Type | null, height: number, weight: number, ability1: Abilities, ability2: Abilities, abilityHidden: Abilities, baseTotal: integer, baseHp: integer, baseAtk: integer, baseDef: integer, baseSpatk: integer, baseSpdef: integer, baseSpd: integer, - catchRate: integer, baseFriendship: integer, baseExp: integer, growthRate: GrowthRate, malePercent: number, + catchRate: integer, baseFriendship: integer, baseExp: integer, growthRate: GrowthRate, malePercent: number | null, genderDiffs: boolean, canChangeForm?: boolean, ...forms: PokemonForm[]) { super(type1, type2, height, weight, ability1, ability2, abilityHidden, baseTotal, baseHp, baseAtk, baseDef, baseSpatk, baseSpdef, baseSpd, catchRate, baseFriendship, baseExp, genderDiffs, false); @@ -614,7 +616,7 @@ export default class PokemonSpecies extends PokemonSpeciesForm implements Locali getName(formIndex?: integer): string { if (formIndex !== undefined && this.forms.length) { const form = this.forms[formIndex]; - let key: string; + let key: string | null; switch (form.formKey) { case SpeciesFormKey.MEGA: case SpeciesFormKey.PRIMAL: @@ -626,6 +628,8 @@ export default class PokemonSpecies extends PokemonSpeciesForm implements Locali default: if (form.formKey.indexOf(SpeciesFormKey.GIGANTAMAX) > -1) { key = "gigantamax"; + } else { + key = null; } } @@ -713,11 +717,11 @@ export default class PokemonSpecies extends PokemonSpeciesForm implements Locali evolutionChance = Math.min(minChance + easeInFunc(Math.min(level - ev.level, maxLevelDiff) / maxLevelDiff) * (1 - minChance), 1); } } else { - const preferredMinLevel = Math.max((ev.level - 1) + ev.wildDelay * this.getStrengthLevelDiff(strength), 1); + const preferredMinLevel = Math.max((ev.level - 1) + (ev.wildDelay!) * this.getStrengthLevelDiff(strength), 1); // TODO: is the bang correct? let evolutionLevel = Math.max(ev.level > 1 ? ev.level : Math.floor(preferredMinLevel / 2), 1); if (ev.level <= 1 && pokemonPrevolutions.hasOwnProperty(this.speciesId)) { - const prevolutionLevel = pokemonEvolutions[pokemonPrevolutions[this.speciesId]].find(ev => ev.speciesId === this.speciesId).level; + const prevolutionLevel = pokemonEvolutions[pokemonPrevolutions[this.speciesId]].find(ev => ev.speciesId === this.speciesId)!.level; // TODO: is the bang correct? if (prevolutionLevel > 1) { evolutionLevel = prevolutionLevel; } @@ -750,15 +754,15 @@ export default class PokemonSpecies extends PokemonSpeciesForm implements Locali for (const weight of evolutionPool.keys()) { if (randValue < weight) { - return getPokemonSpecies(evolutionPool.get(weight)).getSpeciesForLevel(level, true, forTrainer, strength); + return getPokemonSpecies(evolutionPool.get(weight)!).getSpeciesForLevel(level, true, forTrainer, strength); // TODO: is the bang correct? } } return this.speciesId; } - getEvolutionLevels() { - const evolutionLevels = []; + getEvolutionLevels(): [Species, integer][] { + const evolutionLevels: [Species, integer][] = []; //console.log(Species[this.speciesId], pokemonEvolutions[this.speciesId]) @@ -778,8 +782,8 @@ export default class PokemonSpecies extends PokemonSpeciesForm implements Locali return evolutionLevels; } - getPrevolutionLevels() { - const prevolutionLevels = []; + getPrevolutionLevels(): [Species, integer][] { + const prevolutionLevels: [Species, integer][] = []; const allEvolvingPokemon = Object.keys(pokemonEvolutions); for (const p of allEvolvingPokemon) { @@ -801,18 +805,18 @@ export default class PokemonSpecies extends PokemonSpeciesForm implements Locali // This could definitely be written better and more accurate to the getSpeciesForLevel logic, but it is only for generating movesets for evolved Pokemon getSimulatedEvolutionChain(currentLevel: integer, forTrainer: boolean = false, isBoss: boolean = false, player: boolean = false): [Species, integer][] { - const ret = []; + const ret: [Species, integer][] = []; if (pokemonPrevolutions.hasOwnProperty(this.speciesId)) { const prevolutionLevels = this.getPrevolutionLevels().reverse(); const levelDiff = player ? 0 : forTrainer || isBoss ? forTrainer && isBoss ? 2.5 : 5 : 10; ret.push([ prevolutionLevels[0][0], 1 ]); for (let l = 1; l < prevolutionLevels.length; l++) { const evolution = pokemonEvolutions[prevolutionLevels[l - 1][0]].find(e => e.speciesId === prevolutionLevels[l][0]); - ret.push([ prevolutionLevels[l][0], Math.min(Math.max(evolution.level + Math.round(Utils.randSeedGauss(0.5, 1 + levelDiff * 0.2) * Math.max(evolution.wildDelay, 0.5) * 5) - 1, 2, evolution.level), currentLevel - 1) ]); + ret.push([ prevolutionLevels[l][0], Math.min(Math.max((evolution?.level!) + Math.round(Utils.randSeedGauss(0.5, 1 + levelDiff * 0.2) * Math.max((evolution?.wildDelay!), 0.5) * 5) - 1, 2, (evolution?.level!)), currentLevel - 1) ]); // TODO: are those bangs correct? } const lastPrevolutionLevel = ret[prevolutionLevels.length - 1][1]; const evolution = pokemonEvolutions[prevolutionLevels[prevolutionLevels.length - 1][0]].find(e => e.speciesId === this.speciesId); - ret.push([ this.speciesId, Math.min(Math.max(lastPrevolutionLevel + Math.round(Utils.randSeedGauss(0.5, 1 + levelDiff * 0.2) * Math.max(evolution.wildDelay, 0.5) * 5), lastPrevolutionLevel + 1, evolution.level), currentLevel) ]); + ret.push([ this.speciesId, Math.min(Math.max(lastPrevolutionLevel + Math.round(Utils.randSeedGauss(0.5, 1 + levelDiff * 0.2) * Math.max((evolution?.wildDelay!), 0.5) * 5), lastPrevolutionLevel + 1, (evolution?.level!)), currentLevel) ]); // TODO: are those bangs correct? } else { ret.push([ this.speciesId, 1 ]); } @@ -853,7 +857,7 @@ export default class PokemonSpecies extends PokemonSpeciesForm implements Locali } getFormSpriteKey(formIndex?: integer) { - if (this.forms.length && formIndex >= this.forms.length) { + if (this.forms.length && (formIndex !== undefined && formIndex >= this.forms.length)) { console.warn(`Attempted accessing form with index ${formIndex} of species ${this.getName()} with only ${this.forms.length || 0} forms`); formIndex = Math.min(formIndex, this.forms.length - 1); } @@ -866,14 +870,14 @@ export default class PokemonSpecies extends PokemonSpeciesForm implements Locali export class PokemonForm extends PokemonSpeciesForm { public formName: string; public formKey: string; - public formSpriteKey: string; + public formSpriteKey: string | null; // This is a collection of form keys that have in-run form changes, but should still be separately selectable from the start screen private starterSelectableKeys: string[] = ["10", "50", "10-pc", "50-pc", "red", "orange", "yellow", "green", "blue", "indigo", "violet"]; - constructor(formName: string, formKey: string, type1: Type, type2: Type, height: number, weight: number, ability1: Abilities, ability2: Abilities, abilityHidden: Abilities, + constructor(formName: string, formKey: string, type1: Type, type2: Type | null, height: number, weight: number, ability1: Abilities, ability2: Abilities, abilityHidden: Abilities, baseTotal: integer, baseHp: integer, baseAtk: integer, baseDef: integer, baseSpatk: integer, baseSpdef: integer, baseSpd: integer, - catchRate: integer, baseFriendship: integer, baseExp: integer, genderDiffs?: boolean, formSpriteKey?: string, isStarterSelectable?: boolean, ) { + catchRate: integer, baseFriendship: integer, baseExp: integer, genderDiffs?: boolean, formSpriteKey?: string | null, isStarterSelectable?: boolean, ) { super(type1, type2, height, weight, ability1, ability2, abilityHidden, baseTotal, baseHp, baseAtk, baseDef, baseSpatk, baseSpdef, baseSpd, catchRate, baseFriendship, baseExp, !!genderDiffs, (!!isStarterSelectable || !formKey)); this.formName = formName; diff --git a/src/data/status-effect.ts b/src/data/status-effect.ts index 65caf58ccb9..828c52cae13 100644 --- a/src/data/status-effect.ts +++ b/src/data/status-effect.ts @@ -7,12 +7,12 @@ export { StatusEffect }; export class Status { public effect: StatusEffect; public turnCount: integer; - public cureTurn: integer; + public cureTurn: integer | null; constructor(effect: StatusEffect, turnCount: integer = 0, cureTurn?: integer) { this.effect = effect; this.turnCount = turnCount === undefined ? 0 : turnCount; - this.cureTurn = cureTurn; + this.cureTurn = cureTurn!; // TODO: is this bang correct? } incrementTurn(): void { @@ -24,7 +24,7 @@ export class Status { } } -function getStatusEffectMessageKey(statusEffect: StatusEffect): string { +function getStatusEffectMessageKey(statusEffect: StatusEffect | undefined): string { switch (statusEffect) { case StatusEffect.POISON: return "statusEffect:poison"; @@ -43,7 +43,7 @@ function getStatusEffectMessageKey(statusEffect: StatusEffect): string { } } -export function getStatusEffectObtainText(statusEffect: StatusEffect, pokemonNameWithAffix: string, sourceText?: string): string { +export function getStatusEffectObtainText(statusEffect: StatusEffect | undefined, pokemonNameWithAffix: string, sourceText?: string): string { if (!sourceText) { const i18nKey = `${getStatusEffectMessageKey(statusEffect)}.obtain`as ParseKeys; return i18next.t(i18nKey, { pokemonNameWithAffix: pokemonNameWithAffix }); diff --git a/src/data/trainer-config.ts b/src/data/trainer-config.ts index 87d1901eb01..5f47ce42a62 100644 --- a/src/data/trainer-config.ts +++ b/src/data/trainer-config.ts @@ -288,7 +288,7 @@ export class TrainerConfig { * @param trainerTypeToDeriveFrom - The trainer type to derive from. (If null, the this.trainerType property will be used.) * @returns {TrainerType} - The derived trainer type. */ - getDerivedType(trainerTypeToDeriveFrom: TrainerType = null): TrainerType { + getDerivedType(trainerTypeToDeriveFrom: TrainerType | null = null): TrainerType { let trainerType = trainerTypeToDeriveFrom ? trainerTypeToDeriveFrom : this.trainerType; switch (trainerType) { case TrainerType.RIVAL_2: @@ -361,7 +361,7 @@ export class TrainerConfig { this.nameFemale = i18next.t("trainerNames:rival_female"); } else { // Otherwise, assign the provided female name. - this.nameFemale = nameFemale; + this.nameFemale = nameFemale!; // TODO: is this bang correct? } // Indicate that this trainer configuration includes genders. @@ -587,6 +587,9 @@ export class TrainerConfig { }; } } + + console.warn(`Evil team admin for ${team} not found. Returning empty species pools.`); + return []; } /** @@ -715,7 +718,7 @@ export class TrainerConfig { this.setVictoryBgm("victory_gym"); this.setGenModifiersFunc(party => { const waveIndex = party[0].scene.currentBattle.waveIndex; - return getRandomTeraModifiers(party, waveIndex >= 100 ? 1 : 0, specialtyTypes.length ? specialtyTypes : null); + return getRandomTeraModifiers(party, waveIndex >= 100 ? 1 : 0, specialtyTypes.length ? specialtyTypes : undefined); }); return this; @@ -749,7 +752,7 @@ export class TrainerConfig { // Set species filter and specialty types if provided, otherwise filter by base total. if (specialtyTypes.length) { - this.setSpeciesFilter(p => specialtyTypes.find(t => p.isOfType(t)) && p.baseTotal >= 450); + this.setSpeciesFilter(p => specialtyTypes.some(t => p.isOfType(t)) && p.baseTotal >= 450); this.setSpecialtyTypes(...specialtyTypes); } else { this.setSpeciesFilter(p => p.baseTotal >= 450); @@ -772,7 +775,7 @@ export class TrainerConfig { this.setHasVoucher(true); this.setBattleBgm("battle_unova_elite"); this.setVictoryBgm("victory_gym"); - this.setGenModifiersFunc(party => getRandomTeraModifiers(party, 2, specialtyTypes.length ? specialtyTypes : null)); + this.setGenModifiersFunc(party => getRandomTeraModifiers(party, 2, specialtyTypes.length ? specialtyTypes : undefined)); return this; } @@ -897,7 +900,7 @@ export class TrainerConfig { start: 1, end: 128 }) - : null; + : ""; console.warn = originalWarn; if (!(scene.anims.exists(trainerKey))) { scene.anims.create({ @@ -983,7 +986,7 @@ function getRandomTeraModifiers(party: EnemyPokemon[], count: integer, types?: T for (let t = 0; t < Math.min(count, party.length); t++) { const randomIndex = Utils.randSeedItem(partyMemberIndexes); partyMemberIndexes.splice(partyMemberIndexes.indexOf(randomIndex), 1); - ret.push(modifierTypes.TERA_SHARD().generateType(null, [Utils.randSeedItem(types ? types : party[randomIndex].getTypes())]).withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(party[randomIndex]) as PersistentModifier); + ret.push(modifierTypes.TERA_SHARD().generateType([], [Utils.randSeedItem(types ? types : party[randomIndex].getTypes())])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(party[randomIndex]) as PersistentModifier); // TODO: is the bang correct? } return ret; } @@ -1594,7 +1597,7 @@ export const trainerConfigs: TrainerConfigs = { .setSpeciesFilter(species => species.baseTotal >= 540) .setGenModifiersFunc(party => { const starter = party[0]; - return [modifierTypes.TERA_SHARD().generateType(null, [starter.species.type1]).withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(starter) as PersistentModifier]; + return [modifierTypes.TERA_SHARD().generateType([], [starter.species.type1])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(starter) as PersistentModifier]; // TODO: is the bang correct? }), [TrainerType.RIVAL_5]: new TrainerConfig(++t).setName("Finn").setHasGenders("Ivy").setHasCharSprite().setTitle("Rival").setBoss().setStaticParty().setMoneyMultiplier(2.25).setEncounterBgm(TrainerType.RIVAL).setBattleBgm("battle_rival_3").setMixedBattleBgm("battle_rival_3").setPartyTemplates(trainerPartyTemplates.RIVAL_5) .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.VENUSAUR, Species.CHARIZARD, Species.BLASTOISE, Species.MEGANIUM, Species.TYPHLOSION, Species.FERALIGATR, Species.SCEPTILE, Species.BLAZIKEN, Species.SWAMPERT, Species.TORTERRA, Species.INFERNAPE, Species.EMPOLEON, Species.SERPERIOR, Species.EMBOAR, Species.SAMUROTT, Species.CHESNAUGHT, Species.DELPHOX, Species.GRENINJA, Species.DECIDUEYE, Species.INCINEROAR, Species.PRIMARINA, Species.RILLABOOM, Species.CINDERACE, Species.INTELEON, Species.MEOWSCARADA, Species.SKELEDIRGE, Species.QUAQUAVAL], TrainerSlot.TRAINER, true, @@ -1610,7 +1613,7 @@ export const trainerConfigs: TrainerConfigs = { })) .setGenModifiersFunc(party => { const starter = party[0]; - return [modifierTypes.TERA_SHARD().generateType(null, [starter.species.type1]).withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(starter) as PersistentModifier]; + return [modifierTypes.TERA_SHARD().generateType([], [starter.species.type1])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(starter) as PersistentModifier]; //TODO: is the bang correct? }), [TrainerType.RIVAL_6]: new TrainerConfig(++t).setName("Finn").setHasGenders("Ivy").setHasCharSprite().setTitle("Rival").setBoss().setStaticParty().setMoneyMultiplier(3).setEncounterBgm("final").setBattleBgm("battle_rival_3").setMixedBattleBgm("battle_rival_3").setPartyTemplates(trainerPartyTemplates.RIVAL_6) .setPartyMemberFunc(0, getRandomPartyMemberFunc([Species.VENUSAUR, Species.CHARIZARD, Species.BLASTOISE, Species.MEGANIUM, Species.TYPHLOSION, Species.FERALIGATR, Species.SCEPTILE, Species.BLAZIKEN, Species.SWAMPERT, Species.TORTERRA, Species.INFERNAPE, Species.EMPOLEON, Species.SERPERIOR, Species.EMBOAR, Species.SAMUROTT, Species.CHESNAUGHT, Species.DELPHOX, Species.GRENINJA, Species.DECIDUEYE, Species.INCINEROAR, Species.PRIMARINA, Species.RILLABOOM, Species.CINDERACE, Species.INTELEON, Species.MEOWSCARADA, Species.SKELEDIRGE, Species.QUAQUAVAL], TrainerSlot.TRAINER, true, @@ -1636,7 +1639,7 @@ export const trainerConfigs: TrainerConfigs = { })) .setGenModifiersFunc(party => { const starter = party[0]; - return [modifierTypes.TERA_SHARD().generateType(null, [starter.species.type1]).withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(starter) as PersistentModifier]; + return [modifierTypes.TERA_SHARD().generateType([], [starter.species.type1])!.withIdFromFunc(modifierTypes.TERA_SHARD).newModifier(starter) as PersistentModifier]; // TODO: is the bang correct? }), [TrainerType.ROCKET_BOSS_GIOVANNI_1]: new TrainerConfig(t = TrainerType.ROCKET_BOSS_GIOVANNI_1).setName("Giovanni").initForEvilTeamLeader("Rocket Boss", []).setMixedBattleBgm("battle_rocket_boss").setVictoryBgm("victory_team_plasma") diff --git a/src/data/trainer-names.ts b/src/data/trainer-names.ts index b986378ee47..447f9fd4284 100644 --- a/src/data/trainer-names.ts +++ b/src/data/trainer-names.ts @@ -3,7 +3,7 @@ import * as Utils from "../utils"; class TrainerNameConfig { public urls: string[]; - public femaleUrls: string[]; + public femaleUrls: string[] | null; constructor(type: TrainerType, ...urls: string[]) { this.urls = urls.length ? urls : [ Utils.toReadableString(TrainerType[type]).replace(/ /g, "_") ]; @@ -136,8 +136,11 @@ function fetchAndPopulateTrainerNames(url: string, parser: DOMParser, trainerNam .then(html => { console.log(url); const htmlDoc = parser.parseFromString(html, "text/html"); - const trainerListHeader = htmlDoc.querySelector("#Trainer_list").parentElement; - const elements = [...trainerListHeader.parentElement.childNodes]; + const trainerListHeader = htmlDoc.querySelector("#Trainer_list")?.parentElement; + if (!trainerListHeader) { + return []; + } + const elements = [...(trainerListHeader?.parentElement?.childNodes ?? [])]; const startChildIndex = elements.indexOf(trainerListHeader); const endChildIndex = elements.findIndex(h => h.nodeName === "H2" && elements.indexOf(h) > startChildIndex); const tables = elements.filter(t => { @@ -152,6 +155,9 @@ function fetchAndPopulateTrainerNames(url: string, parser: DOMParser, trainerNam const trainerRows = [...table.querySelectorAll("tr:not(:first-child)")].filter(r => r.children.length === 9); for (const row of trainerRows) { const nameCell = row.firstElementChild; + if (!nameCell) { + continue; + } const content = nameCell.innerHTML; if (content.indexOf(" -1) { const female = /♀/.test(content); diff --git a/src/data/type.ts b/src/data/type.ts index 1330eb83f4b..7a9f7f3605e 100644 --- a/src/data/type.ts +++ b/src/data/type.ts @@ -499,6 +499,8 @@ export function getTypeDamageMultiplier(attackType: integer, defType: integer): case Type.STELLAR: return 1; } + + return 0; } /** diff --git a/src/data/weather.ts b/src/data/weather.ts index 901ad08d164..2421f719e6e 100644 --- a/src/data/weather.ts +++ b/src/data/weather.ts @@ -103,7 +103,7 @@ export class Weather { const field = scene.getField(true); for (const pokemon of field) { - let suppressWeatherEffectAbAttr = pokemon.getAbility().getAttrs(SuppressWeatherEffectAbAttr)[0]; + let suppressWeatherEffectAbAttr: SuppressWeatherEffectAbAttr | null = pokemon.getAbility().getAttrs(SuppressWeatherEffectAbAttr)[0]; if (!suppressWeatherEffectAbAttr) { suppressWeatherEffectAbAttr = pokemon.hasPassive() ? pokemon.getPassiveAbility().getAttrs(SuppressWeatherEffectAbAttr)[0] : null; } @@ -116,7 +116,7 @@ export class Weather { } } -export function getWeatherStartMessage(weatherType: WeatherType): string { +export function getWeatherStartMessage(weatherType: WeatherType): string | null { switch (weatherType) { case WeatherType.SUNNY: return i18next.t("weather:sunnyStartMessage"); @@ -141,7 +141,7 @@ export function getWeatherStartMessage(weatherType: WeatherType): string { return null; } -export function getWeatherLapseMessage(weatherType: WeatherType): string { +export function getWeatherLapseMessage(weatherType: WeatherType): string | null { switch (weatherType) { case WeatherType.SUNNY: return i18next.t("weather:sunnyLapseMessage"); @@ -166,7 +166,7 @@ export function getWeatherLapseMessage(weatherType: WeatherType): string { return null; } -export function getWeatherDamageMessage(weatherType: WeatherType, pokemon: Pokemon): string { +export function getWeatherDamageMessage(weatherType: WeatherType, pokemon: Pokemon): string | null { switch (weatherType) { case WeatherType.SANDSTORM: return i18next.t("weather:sandstormDamageMessage", {pokemonNameWithAffix: getPokemonNameWithAffix(pokemon)}); @@ -177,7 +177,7 @@ export function getWeatherDamageMessage(weatherType: WeatherType, pokemon: Pokem return null; } -export function getWeatherClearMessage(weatherType: WeatherType): string { +export function getWeatherClearMessage(weatherType: WeatherType): string | null { switch (weatherType) { case WeatherType.SUNNY: return i18next.t("weather:sunnyClearMessage"); @@ -202,7 +202,7 @@ export function getWeatherClearMessage(weatherType: WeatherType): string { return null; } -export function getTerrainStartMessage(terrainType: TerrainType): string { +export function getTerrainStartMessage(terrainType: TerrainType): string | null { switch (terrainType) { case TerrainType.MISTY: return i18next.t("terrain:mistyStartMessage"); @@ -212,10 +212,13 @@ export function getTerrainStartMessage(terrainType: TerrainType): string { return i18next.t("terrain:grassyStartMessage"); case TerrainType.PSYCHIC: return i18next.t("terrain:psychicStartMessage"); + default: + console.warn("getTerrainStartMessage not defined. Using default null"); + return null; } } -export function getTerrainClearMessage(terrainType: TerrainType): string { +export function getTerrainClearMessage(terrainType: TerrainType): string | null { switch (terrainType) { case TerrainType.MISTY: return i18next.t("terrain:mistyClearMessage"); @@ -225,6 +228,9 @@ export function getTerrainClearMessage(terrainType: TerrainType): string { return i18next.t("terrain:grassyClearMessage"); case TerrainType.PSYCHIC: return i18next.t("terrain:psychicClearMessage"); + default: + console.warn("getTerrainClearMessage not defined. Using default null"); + return null; } } diff --git a/src/egg-hatch-phase.ts b/src/egg-hatch-phase.ts index 3965eae74f6..73c88cbde37 100644 --- a/src/egg-hatch-phase.ts +++ b/src/egg-hatch-phase.ts @@ -84,7 +84,7 @@ export class EggHatchPhase extends Phase { this.scene.gameData.eggs.splice(eggIndex, 1); - this.scene.fadeOutBgm(null, false); + this.scene.fadeOutBgm(undefined, false); this.eggHatchHandler = this.scene.ui.getHandler() as EggHatchSceneHandler; @@ -234,8 +234,8 @@ export class EggHatchPhase extends Phase { ease: "Sine.easeInOut", duration: 250, onComplete: () => { - count++; - if (count < repeatCount) { + count!++; + if (count! < repeatCount!) { // we know they are defined return this.doEggShake(intensity, repeatCount, count).then(() => resolve()); } this.scene.tweens.add({ @@ -347,7 +347,7 @@ export class EggHatchPhase extends Phase { this.scene.gameData.updateSpeciesDexIvs(this.pokemon.species.speciesId, this.pokemon.ivs); this.scene.gameData.setPokemonCaught(this.pokemon, true, true).then(() => { this.scene.gameData.setEggMoveUnlocked(this.pokemon.species, this.eggMoveIndex).then(() => { - this.scene.ui.showText(null, 0); + this.scene.ui.showText("", 0); this.end(); }); }); @@ -447,6 +447,6 @@ export class EggHatchPhase extends Phase { }, this.egg.id, EGG_SEED.toString()); - return ret; + return ret!; } } diff --git a/src/events/arena.ts b/src/events/arena.ts index 67b423f3b75..9fbbe572601 100644 --- a/src/events/arena.ts +++ b/src/events/arena.ts @@ -81,8 +81,8 @@ export class TagAddedEvent extends ArenaEvent { this.arenaTagType = arenaTagType; this.arenaTagSide = arenaTagSide; - this.arenaTagLayers = arenaTagLayers; - this.arenaTagMaxLayers = arenaTagMaxLayers; + this.arenaTagLayers = arenaTagLayers!; // TODO: is this bang correct? + this.arenaTagMaxLayers = arenaTagMaxLayers!; // TODO: is this bang correct? } } /** diff --git a/src/evolution-phase.ts b/src/evolution-phase.ts index 7633fbb3fdd..7b50a6368f6 100644 --- a/src/evolution-phase.ts +++ b/src/evolution-phase.ts @@ -16,7 +16,7 @@ export class EvolutionPhase extends Phase { protected pokemon: PlayerPokemon; protected lastLevel: integer; - private evolution: SpeciesFormEvolution; + private evolution: SpeciesFormEvolution | null; protected evolutionContainer: Phaser.GameObjects.Container; protected evolutionBaseBg: Phaser.GameObjects.Image; @@ -28,7 +28,7 @@ export class EvolutionPhase extends Phase { protected pokemonEvoSprite: Phaser.GameObjects.Sprite; protected pokemonEvoTintSprite: Phaser.GameObjects.Sprite; - constructor(scene: BattleScene, pokemon: PlayerPokemon, evolution: SpeciesFormEvolution, lastLevel: integer) { + constructor(scene: BattleScene, pokemon: PlayerPokemon, evolution: SpeciesFormEvolution | null, lastLevel: integer) { super(scene); this.pokemon = pokemon; @@ -53,7 +53,7 @@ export class EvolutionPhase extends Phase { return this.end(); } - this.scene.fadeOutBgm(null, false); + this.scene.fadeOutBgm(undefined, false); const evolutionHandler = this.scene.ui.getHandler() as EvolutionSceneHandler; @@ -195,7 +195,7 @@ export class EvolutionPhase extends Phase { this.scene.ui.showText(i18next.t("menu:stoppedEvolving", { pokemonName: preName }), null, () => { this.scene.ui.showText(i18next.t("menu:pauseEvolutionsQuestion", { pokemonName: preName }), null, () => { const end = () => { - this.scene.ui.showText(null, 0); + this.scene.ui.showText("", 0); this.scene.playBgm(); evolvedPokemon.destroy(); this.end(); diff --git a/src/field/arena.ts b/src/field/arena.ts index cb045cc76ac..923a0a4e286 100644 --- a/src/field/arena.ts +++ b/src/field/arena.ts @@ -25,8 +25,8 @@ import { TrainerType } from "#enums/trainer-type"; export class Arena { public scene: BattleScene; public biomeType: Biome; - public weather: Weather; - public terrain: Terrain; + public weather: Weather | null; + public terrain: Terrain | null; public tags: ArenaTag[]; public bgm: string; public ignoreAbilities: boolean; @@ -121,7 +121,7 @@ export class Arena { } } - ret = getPokemonSpecies(species); + ret = getPokemonSpecies(species!); if (ret.subLegendary || ret.legendary || ret.mythical) { switch (true) { @@ -292,7 +292,7 @@ export class Arena { trySetWeatherOverride(weather: WeatherType): boolean { this.weather = new Weather(weather, 0); this.scene.unshiftPhase(new CommonAnimPhase(this.scene, undefined, undefined, CommonAnim.SUNNY + (weather - 1))); - this.scene.queueMessage(getWeatherStartMessage(weather)); + this.scene.queueMessage(getWeatherStartMessage(weather)!); // TODO: is this bang correct? return true; } @@ -314,13 +314,13 @@ export class Arena { const oldWeatherType = this.weather?.weatherType || WeatherType.NONE; this.weather = weather ? new Weather(weather, hasPokemonSource ? 5 : 0) : null; - this.eventTarget.dispatchEvent(new WeatherChangedEvent(oldWeatherType, this.weather?.weatherType, this.weather?.turnsLeft)); + this.eventTarget.dispatchEvent(new WeatherChangedEvent(oldWeatherType, this.weather?.weatherType!, this.weather?.turnsLeft!)); // TODO: is this bang correct? if (this.weather) { this.scene.unshiftPhase(new CommonAnimPhase(this.scene, undefined, undefined, CommonAnim.SUNNY + (weather - 1))); - this.scene.queueMessage(getWeatherStartMessage(weather)); + this.scene.queueMessage(getWeatherStartMessage(weather)!); // TODO: is this bang correct? } else { - this.scene.queueMessage(getWeatherClearMessage(oldWeatherType)); + this.scene.queueMessage(getWeatherClearMessage(oldWeatherType)!); // TODO: is this bang correct? } this.scene.getField(true).filter(p => p.isOnField()).map(pokemon => { @@ -339,15 +339,15 @@ export class Arena { const oldTerrainType = this.terrain?.terrainType || TerrainType.NONE; this.terrain = terrain ? new Terrain(terrain, hasPokemonSource ? 5 : 0) : null; - this.eventTarget.dispatchEvent(new TerrainChangedEvent(oldTerrainType,this.terrain?.terrainType, this.terrain?.turnsLeft)); + this.eventTarget.dispatchEvent(new TerrainChangedEvent(oldTerrainType,this.terrain?.terrainType!, this.terrain?.turnsLeft!)); // TODO: are those bangs correct? if (this.terrain) { if (!ignoreAnim) { this.scene.unshiftPhase(new CommonAnimPhase(this.scene, undefined, undefined, CommonAnim.MISTY_TERRAIN + (terrain - 1))); } - this.scene.queueMessage(getTerrainStartMessage(terrain)); + this.scene.queueMessage(getTerrainStartMessage(terrain)!); // TODO: is this bang correct? } else { - this.scene.queueMessage(getTerrainClearMessage(oldTerrainType)); + this.scene.queueMessage(getTerrainClearMessage(oldTerrainType)!); // TODO: is this bang correct? } this.scene.getField(true).filter(p => p.isOnField()).map(pokemon => { @@ -554,7 +554,7 @@ export class Arena { this.applyTagsForSide(tagType, ArenaTagSide.BOTH, ...args); } - addTag(tagType: ArenaTagType, turnCount: integer, sourceMove: Moves, sourceId: integer, side: ArenaTagSide = ArenaTagSide.BOTH, quiet: boolean = false, targetIndex?: BattlerIndex): boolean { + addTag(tagType: ArenaTagType, turnCount: integer, sourceMove: Moves | undefined, sourceId: integer, side: ArenaTagSide = ArenaTagSide.BOTH, quiet: boolean = false, targetIndex?: BattlerIndex): boolean { const existingTag = this.getTagOnSide(tagType, side); if (existingTag) { existingTag.onOverlap(this); @@ -568,21 +568,23 @@ export class Arena { } const newTag = getArenaTag(tagType, turnCount || 0, sourceMove, sourceId, targetIndex, side); - this.tags.push(newTag); - newTag.onAdd(this, quiet); + if (newTag) { + this.tags.push(newTag); + newTag.onAdd(this, quiet); - const { layers = 0, maxLayers = 0 } = newTag instanceof ArenaTrapTag ? newTag : {}; + const { layers = 0, maxLayers = 0 } = newTag instanceof ArenaTrapTag ? newTag : {}; - this.eventTarget.dispatchEvent(new TagAddedEvent(newTag.tagType, newTag.side, newTag.turnCount, layers, maxLayers)); + this.eventTarget.dispatchEvent(new TagAddedEvent(newTag.tagType, newTag.side, newTag.turnCount, layers, maxLayers)); + } return true; } - getTag(tagType: ArenaTagType | Constructor): ArenaTag { + getTag(tagType: ArenaTagType | Constructor): ArenaTag | undefined { return this.getTagOnSide(tagType, ArenaTagSide.BOTH); } - getTagOnSide(tagType: ArenaTagType | Constructor, side: ArenaTagSide): ArenaTag { + getTagOnSide(tagType: ArenaTagType | Constructor, side: ArenaTagSide): ArenaTag | undefined { return typeof(tagType) === "string" ? this.tags.find(t => t.tagType === tagType && (side === ArenaTagSide.BOTH || t.side === ArenaTagSide.BOTH || t.side === side)) : this.tags.find(t => t instanceof tagType && (side === ArenaTagSide.BOTH || t.side === ArenaTagSide.BOTH || t.side === side)); @@ -724,6 +726,9 @@ export class Arena { return 0.000; case Biome.SNOWY_FOREST: return 3.047; + default: + console.warn(`missing bgm loop-point for biome "${Biome[this.biomeType]}" (=${this.biomeType})`); + return 0; } } } @@ -777,12 +782,12 @@ export class ArenaBase extends Phaser.GameObjects.Container { this.player = player; - this.base = scene.addFieldSprite(0, 0, "plains_a", null, 1); + this.base = scene.addFieldSprite(0, 0, "plains_a", undefined, 1); this.base.setOrigin(0, 0); this.props = !player ? new Array(3).fill(null).map(() => { - const ret = scene.addFieldSprite(0, 0, "plains_b", null, 1); + const ret = scene.addFieldSprite(0, 0, "plains_b", undefined, 1); ret.setOrigin(0, 0); ret.setVisible(false); return ret; diff --git a/src/field/damage-number-handler.ts b/src/field/damage-number-handler.ts index 4af219a60b9..ae0692da342 100644 --- a/src/field/damage-number-handler.ts +++ b/src/field/damage-number-handler.ts @@ -3,6 +3,8 @@ import Pokemon, { DamageResult, HitResult } from "./pokemon"; import * as Utils from "../utils"; import { BattlerIndex } from "../battle"; +type TextAndShadowArr = [ string | null, string | null ]; + export default class DamageNumberHandler { private damageNumbers: Map; @@ -24,7 +26,7 @@ export default class DamageNumberHandler { damageNumber.setOrigin(0.5, 1); damageNumber.setScale(baseScale); - let [ textColor, shadowColor ] = [ null, null ]; + let [ textColor, shadowColor ] : TextAndShadowArr = [ null, null ]; switch (result) { case HitResult.SUPER_EFFECTIVE: @@ -62,12 +64,12 @@ export default class DamageNumberHandler { this.damageNumbers.set(battlerIndex, []); } - const yOffset = this.damageNumbers.get(battlerIndex).length * -10; + const yOffset = this.damageNumbers.get(battlerIndex)!.length * -10; if (yOffset) { damageNumber.y += yOffset; } - this.damageNumbers.get(battlerIndex).push(damageNumber); + this.damageNumbers.get(battlerIndex)!.push(damageNumber); if (scene.damageNumbersMode === 1) { scene.tweens.add({ @@ -83,7 +85,7 @@ export default class DamageNumberHandler { alpha: 0, ease: "Sine.easeIn", onComplete: () => { - this.damageNumbers.get(battlerIndex).splice(this.damageNumbers.get(battlerIndex).indexOf(damageNumber), 1); + this.damageNumbers.get(battlerIndex)!.splice(this.damageNumbers.get(battlerIndex)!.indexOf(damageNumber), 1); damageNumber.destroy(true); } }); @@ -167,7 +169,7 @@ export default class DamageNumberHandler { delay: Utils.fixedInt(500), alpha: 0, onComplete: () => { - this.damageNumbers.get(battlerIndex).splice(this.damageNumbers.get(battlerIndex).indexOf(damageNumber), 1); + this.damageNumbers.get(battlerIndex)!.splice(this.damageNumbers.get(battlerIndex)!.indexOf(damageNumber), 1); damageNumber.destroy(true); } } diff --git a/src/field/pokemon-sprite-sparkle-handler.ts b/src/field/pokemon-sprite-sparkle-handler.ts index 5312dd18727..ccf6a098667 100644 --- a/src/field/pokemon-sprite-sparkle-handler.ts +++ b/src/field/pokemon-sprite-sparkle-handler.ts @@ -35,7 +35,7 @@ export default class PokemonSpriteSparkleHandler { const ratioX = s.width / width; const ratioY = s.height / height; const pixel = texture.manager.getPixel(pixelX, pixelY, texture.key, "__BASE"); - if (pixel.alpha) { + if (pixel?.alpha) { const [ xOffset, yOffset ] = [ -s.originX * s.width, -s.originY * s.height]; const sparkle = (s.scene as BattleScene).addFieldSprite(((pokemon?.x || 0) + s.x + pixelX * ratioX + xOffset), ((pokemon?.y || 0) + s.y + pixelY * ratioY + yOffset), "tera_sparkle"); sparkle.pipelineData["ignoreTimeTint"] = s.pipelineData["ignoreTimeTint"]; diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index a53076bc856..84058cc656f 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -79,8 +79,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { public ivs: integer[]; public nature: Nature; public natureOverride: Nature | -1; - public moveset: PokemonMove[]; - public status: Status; + public moveset: (PokemonMove | null)[]; + public status: Status | null; public friendship: integer; public metLevel: integer; public metBiome: Biome | -1; @@ -89,7 +89,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { public pauseEvolutions: boolean; public pokerus: boolean; - public fusionSpecies: PokemonSpecies; + public fusionSpecies: PokemonSpecies | null; public fusionFormIndex: integer; public fusionAbilityIndex: integer; public fusionShiny: boolean; @@ -97,7 +97,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { public fusionGender: Gender; public fusionLuck: integer; - private summonDataPrimer: PokemonSummonData; + private summonDataPrimer: PokemonSummonData | null; public summonData: PokemonSummonData; public battleData: PokemonBattleData; @@ -107,7 +107,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { public fieldPosition: FieldPosition; public maskEnabled: boolean; - public maskSprite: Phaser.GameObjects.Sprite; + public maskSprite: Phaser.GameObjects.Sprite | null; private shinySparkle: Phaser.GameObjects.Sprite; @@ -169,7 +169,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { this.nickname = dataSource.nickname; this.natureOverride = dataSource.natureOverride !== undefined ? dataSource.natureOverride : -1; this.moveset = dataSource.moveset; - this.status = dataSource.status; + this.status = dataSource.status!; // TODO: is this bang correct? this.friendship = dataSource.friendship !== undefined ? dataSource.friendship : this.species.baseFriendship; this.metLevel = dataSource.metLevel || 5; this.luck = dataSource.luck; @@ -177,7 +177,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { this.metSpecies = dataSource.metSpecies ?? (this.metBiome !== -1 ? this.species.speciesId : this.species.getRootSpeciesId(true)); this.pauseEvolutions = dataSource.pauseEvolutions; this.pokerus = !!dataSource.pokerus; - this.fusionSpecies = dataSource.fusionSpecies instanceof PokemonSpecies ? dataSource.fusionSpecies : getPokemonSpecies(dataSource.fusionSpecies); + this.fusionSpecies = dataSource.fusionSpecies instanceof PokemonSpecies ? dataSource.fusionSpecies : dataSource.fusionSpecies ? getPokemonSpecies(dataSource.fusionSpecies) : null; this.fusionFormIndex = dataSource.fusionFormIndex; this.fusionAbilityIndex = dataSource.fusionAbilityIndex; this.fusionShiny = dataSource.fusionShiny; @@ -350,7 +350,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { loadAssets(ignoreOverride: boolean = true): Promise { return new Promise(resolve => { - const moveIds = this.getMoveset().map(m => m.getMove().id); + const moveIds = this.getMoveset().map(m => m!.getMove().id); // TODO: is this bang correct? Promise.allSettled(moveIds.map(m => initMoveAnim(this.scene, m))) .then(() => { loadMoveAnimAssets(this.scene, moveIds); @@ -438,7 +438,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return this.species.forms[this.formIndex].formKey; } - getFusionFormKey(): string { + getFusionFormKey(): string | null { if (!this.fusionSpecies) { return null; } @@ -527,7 +527,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return this.summonData.fusionSpeciesForm; } if (!this.fusionSpecies?.forms?.length || this.fusionFormIndex >= this.fusionSpecies?.forms.length) { - return this.fusionSpecies; + //@ts-ignore + return this.fusionSpecies; // TODO: I don't even know how to fix this... A complete cluster of classes involved + null } return this.fusionSpecies?.forms[this.fusionFormIndex]; } @@ -536,7 +537,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return this.getAt(0) as Phaser.GameObjects.Sprite; } - getTintSprite(): Phaser.GameObjects.Sprite { + getTintSprite(): Phaser.GameObjects.Sprite | null { return !this.maskEnabled ? this.getAt(1) as Phaser.GameObjects.Sprite : this.maskSprite; @@ -562,7 +563,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } updateSpritePipelineData(): void { - [ this.getSprite(), this.getTintSprite() ].map(s => s.pipelineData["teraColor"] = getTypeRgb(this.getTeraType())); + [ this.getSprite(), this.getTintSprite() ].filter(s => !!s).map(s => s.pipelineData["teraColor"] = getTypeRgb(this.getTeraType())); this.updateInfo(true); } @@ -610,7 +611,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } playAnim(): void { - this.tryPlaySprite(this.getSprite(), this.getTintSprite(), this.getBattleSpriteKey()); + this.tryPlaySprite(this.getSprite(), this.getTintSprite()!, this.getBattleSpriteKey()); // TODO: is the bag correct? } getFieldPositionOffset(): [ number, number ] { @@ -870,7 +871,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { abstract isBoss(): boolean; - getMoveset(ignoreOverride?: boolean): PokemonMove[] { + getMoveset(ignoreOverride?: boolean): (PokemonMove | null)[] { const ret = !ignoreOverride && this.summonData?.moveset ? this.summonData.moveset : this.moveset; @@ -921,7 +922,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { if (this.metBiome === -1) { levelMoves = this.getUnlockedEggMoves().concat(levelMoves); } - return levelMoves.filter(lm => !this.moveset.some(m => m.moveId === lm)); + return levelMoves.filter(lm => !this.moveset.some(m => m?.moveId === lm)); } /** @@ -932,7 +933,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * @returns array of {@linkcode Type} */ getTypes(includeTeraType = false, forDefend: boolean = false, ignoreOverride?: boolean): Type[] { - const types = []; + const types : Type[] = []; if (includeTeraType) { const teraType = this.getTeraType(); @@ -942,7 +943,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } if (!types.length || !includeTeraType) { - if (!ignoreOverride && this.summonData?.types) { + if (!ignoreOverride && this.summonData?.types && this.summonData.types.length !== 0) { this.summonData.types.forEach(t => types.push(t)); } else { const speciesForm = this.getSpeciesForm(ignoreOverride); @@ -1115,7 +1116,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return false; } } - return (this.hp || ability.isBypassFaint) && !ability.conditions.find(condition => !condition(this)); + return (!!this.hp || ability.isBypassFaint) && !ability.conditions.find(condition => !condition(this)); } /** @@ -1242,7 +1243,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { ? moveOrType : undefined; const moveType = (moveOrType instanceof Move) - ? move.type + ? move!.type // TODO: is this bang correct? : moveOrType; if (moveType === Type.STELLAR) { @@ -1285,7 +1286,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } } - return multiplier; + return multiplier as TypeDamageMultiplier; } /** @@ -1327,7 +1328,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return (atkScore + defScore) * hpDiffRatio; } - getEvolution(): SpeciesFormEvolution { + getEvolution(): SpeciesFormEvolution | null { if (pokemonEvolutions.hasOwnProperty(this.species.speciesId)) { const evolutions = pokemonEvolutions[this.species.speciesId]; for (const e of evolutions) { @@ -1339,7 +1340,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } } - if (this.isFusion() && pokemonEvolutions.hasOwnProperty(this.fusionSpecies.speciesId)) { + if (this.isFusion() && this.fusionSpecies && pokemonEvolutions.hasOwnProperty(this.fusionSpecies.speciesId)) { const fusionEvolutions = pokemonEvolutions[this.fusionSpecies.speciesId].map(e => new FusionSpeciesFormEvolution(this.species.speciesId, e)); for (const fe of fusionEvolutions) { if (!fe.item && this.level >= fe.level && (!fe.preFormKey || this.getFusionFormKey() === fe.preFormKey)) { @@ -1549,7 +1550,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } clearFusionSpecies(): void { - this.fusionSpecies = undefined; + this.fusionSpecies = null; this.fusionFormIndex = 0; this.fusionAbilityIndex = 0; this.fusionShiny = false; @@ -1709,9 +1710,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { // Sqrt the weight of any damaging moves with overlapping types. This is about a 0.05 - 0.1 multiplier. // Other damaging moves 2x weight if 0-1 damaging moves, 0.5x if 2, 0.125x if 3. These weights double if STAB. // Status moves remain unchanged on weight, this encourages 1-2 - movePool = baseWeights.filter(m => !this.moveset.some(mo => m[0] === mo.moveId)).map(m => [m[0], this.moveset.some(mo => mo.getMove().category !== MoveCategory.STATUS && mo.getMove().type === allMoves[m[0]].type) ? Math.ceil(Math.sqrt(m[1])) : allMoves[m[0]].category !== MoveCategory.STATUS ? Math.ceil(m[1]/Math.max(Math.pow(4, this.moveset.filter(mo => mo.getMove().power > 1).length)/8,0.5) * (this.isOfType(allMoves[m[0]].type) ? 2 : 1)) : m[1]]); + movePool = baseWeights.filter(m => !this.moveset.some(mo => m[0] === mo?.moveId)).map(m => [m[0], this.moveset.some(mo => mo?.getMove().category !== MoveCategory.STATUS && mo?.getMove().type === allMoves[m[0]].type) ? Math.ceil(Math.sqrt(m[1])) : allMoves[m[0]].category !== MoveCategory.STATUS ? Math.ceil(m[1]/Math.max(Math.pow(4, this.moveset.filter(mo => (mo?.getMove().power!) > 1).length)/8,0.5) * (this.isOfType(allMoves[m[0]].type) ? 2 : 1)) : m[1]]); // TODO: is this bang correct? } else { // Non-trainer pokemon just use normal weights - movePool = baseWeights.filter(m => !this.moveset.some(mo => m[0] === mo.moveId)); + movePool = baseWeights.filter(m => !this.moveset.some(mo => m[0] === mo?.moveId)); } const totalWeight = movePool.reduce((v, m) => v + m[1], 0); let rand = Utils.randSeedInt(totalWeight); @@ -1729,7 +1730,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { const move = this.getMoveset().length > moveIndex ? this.getMoveset()[moveIndex] : null; - return move?.isUsable(this, ignorePp); + return move?.isUsable(this, ignorePp)!; // TODO: is this bang correct? } showInfo(): void { @@ -1812,7 +1813,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { this.levelExp = this.exp - getLevelTotalExp(this.level, this.species.growthRate); } - getOpponent(targetIndex: integer): Pokemon { + getOpponent(targetIndex: integer): Pokemon | null { const ret = this.getOpponents()[targetIndex]; if (ret.summonData) { return ret; @@ -1977,7 +1978,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { this.scene.applyModifiers(CritBoosterModifier, source.isPlayer(), source, critLevel); this.scene.applyModifiers(TempBattleStatBoosterModifier, source.isPlayer(), TempBattleStat.CRIT, critLevel); const bonusCrit = new Utils.BooleanHolder(false); - if (applyAbAttrs(BonusCritAbAttr, source, null, bonusCrit)) { + //@ts-ignore + if (applyAbAttrs(BonusCritAbAttr, source, null, bonusCrit)) { // TODO: resolve ts-ignore. This is a promise. Checking a promise is bogus. if (bonusCrit.value) { critLevel.value += 1; } @@ -2000,7 +2002,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { isCritical = false; } } - const sourceAtk = new Utils.IntegerHolder(source.getBattleStat(isPhysical ? Stat.ATK : Stat.SPATK, this, null, isCritical)); + const sourceAtk = new Utils.IntegerHolder(source.getBattleStat(isPhysical ? Stat.ATK : Stat.SPATK, this, undefined, isCritical)); const targetDef = new Utils.IntegerHolder(this.getBattleStat(isPhysical ? Stat.DEF : Stat.SPDEF, source, move, isCritical)); const criticalMultiplier = new Utils.NumberHolder(isCritical ? 1.5 : 1); applyAbAttrs(MultCritAbAttr, source, null, criticalMultiplier); @@ -2088,6 +2090,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { isCritical = false; result = HitResult.EFFECTIVE; } + result = result!; // telling TS compiler that result is defined! if (!result) { if (!typeMultiplier.value) { @@ -2192,7 +2195,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } if (damage) { - const attacker = this.scene.getPokemonById(source.id); + const attacker = this.scene.getPokemonById(source.id)!; // TODO: is this bang correct? destinyTag?.lapse(attacker, BattlerTagLapseType.CUSTOM); } } @@ -2292,7 +2295,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { isMax(): boolean { const maxForms = [SpeciesFormKey.GIGANTAMAX, SpeciesFormKey.GIGANTAMAX_RAPID, SpeciesFormKey.GIGANTAMAX_SINGLE, SpeciesFormKey.ETERNAMAX] as string[]; - return maxForms.includes(this.getFormKey()) || maxForms.includes(this.getFusionFormKey()); + return maxForms.includes(this.getFormKey()) || (!!this.getFusionFormKey() && maxForms.includes(this.getFusionFormKey()!)); } addTag(tagType: BattlerTagType, turnCount: integer = 0, sourceMove?: Moves, sourceId?: integer): boolean { @@ -2302,7 +2305,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return false; } - const newTag = getBattlerTag(tagType, turnCount, sourceMove, sourceId); + const newTag = getBattlerTag(tagType, turnCount, sourceMove!, sourceId!); // TODO: are the bangs correct? const cancelled = new Utils.BooleanHolder(false); applyPreApplyBattlerTagAbAttrs(BattlerTagImmunityAbAttr, this, newTag, cancelled); @@ -2321,18 +2324,19 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } /** @overload */ - getTag(tagType: BattlerTagType): BattlerTag; + getTag(tagType: BattlerTagType): BattlerTag | null; /** @overload */ - getTag(tagType: Constructor): T; + getTag(tagType: Constructor): T | null; - getTag(tagType: BattlerTagType | Constructor): BattlerTag { + getTag(tagType: BattlerTagType | Constructor): BattlerTag | null { if (!this.summonData) { return null; } - return tagType instanceof Function + return (tagType instanceof Function ? this.summonData.tags.find(t => t instanceof tagType) - : this.summonData.tags.find(t => t.tagType === tagType); + : this.summonData.tags.find(t => t.tagType === tagType) + )!; // TODO: is this bang correct? } findTag(tagFilter: ((tag: BattlerTag) => boolean)) { @@ -2436,7 +2440,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { this.getMoveHistory().push(turnMove); } - getLastXMoves(turnCount?: integer): TurnMove[] { + getLastXMoves(turnCount: integer = 0): TurnMove[] { const moveHistory = this.getMoveHistory(); return moveHistory.slice(turnCount >= 0 ? Math.max(moveHistory.length - (turnCount || 1), 0) : 0, moveHistory.length).reverse(); } @@ -2514,9 +2518,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { let frameThreshold: number; sprite.anims.pause(); - tintSprite.anims.pause(); + tintSprite?.anims.pause(); - let faintCryTimer = this.scene.time.addEvent({ + let faintCryTimer : Phaser.Time.TimerEvent | null = this.scene.time.addEvent({ delay: Utils.fixedInt(delay), repeat: -1, callback: () => { @@ -2526,7 +2530,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { while (frameProgress > frameThreshold) { if (sprite.anims.duration) { sprite.anims.nextFrame(); - tintSprite.anims.nextFrame(); + tintSprite?.anims.nextFrame(); } frameProgress -= frameThreshold; } @@ -2534,7 +2538,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { rate *= 0.99; cry.setRate(rate); } else { - faintCryTimer.destroy(); + faintCryTimer?.destroy(); faintCryTimer = null; if (callback) { callback(); @@ -2593,9 +2597,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { let frameThreshold: number; sprite.anims.pause(); - tintSprite.anims.pause(); + tintSprite?.anims.pause(); - let faintCryTimer = this.scene.time.addEvent({ + let faintCryTimer: Phaser.Time.TimerEvent | null = this.scene.time.addEvent({ delay: Utils.fixedInt(delay), repeat: -1, callback: () => { @@ -2605,7 +2609,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { while (frameProgress > frameThreshold) { if (sprite.anims.duration) { sprite.anims.nextFrame(); - tintSprite.anims.nextFrame(); + tintSprite?.anims.nextFrame(); } frameProgress -= frameThreshold; } @@ -2622,7 +2626,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { fusionCry.setRate(rate); } if ((!cry || cry.pendingRemove) && (!fusionCry || fusionCry.pendingRemove)) { - faintCryTimer.destroy(); + faintCryTimer?.destroy(); faintCryTimer = null; if (callback) { callback(); @@ -2653,7 +2657,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return this.gender !== Gender.GENDERLESS && pokemon.gender === (this.gender === Gender.MALE ? Gender.FEMALE : Gender.MALE); } - canSetStatus(effect: StatusEffect, quiet: boolean = false, overrideStatus: boolean = false, sourcePokemon: Pokemon = null): boolean { + canSetStatus(effect: StatusEffect | undefined, quiet: boolean = false, overrideStatus: boolean = false, sourcePokemon: Pokemon | null = null): boolean { if (effect !== StatusEffect.FAINT) { if (overrideStatus ? this.status?.effect === effect : this.status) { return false; @@ -2704,7 +2708,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } break; case StatusEffect.FREEZE: - if (this.isOfType(Type.ICE) || [WeatherType.SUNNY, WeatherType.HARSH_SUN].includes(this.scene?.arena.weather?.weatherType)) { + if (this.isOfType(Type.ICE) || (this.scene?.arena?.weather?.weatherType &&[WeatherType.SUNNY, WeatherType.HARSH_SUN].includes(this.scene.arena.weather.weatherType))) { return false; } break; @@ -2728,7 +2732,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return true; } - trySetStatus(effect: StatusEffect, asPhase: boolean = false, sourcePokemon: Pokemon = null, cureTurn: integer = 0, sourceText: string = null): boolean { + trySetStatus(effect: StatusEffect | undefined, asPhase: boolean = false, sourcePokemon: Pokemon | null = null, cureTurn: integer | null = 0, sourceText: string | null = null): boolean { if (!this.canSetStatus(effect, asPhase, false, sourcePokemon)) { return false; } @@ -2742,7 +2746,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } if (asPhase) { - this.scene.unshiftPhase(new ObtainStatusEffectPhase(this.scene, this.getBattlerIndex(), effect, cureTurn, sourceText, sourcePokemon)); + this.scene.unshiftPhase(new ObtainStatusEffectPhase(this.scene, this.getBattlerIndex(), effect, cureTurn, sourceText!, sourcePokemon!)); // TODO: are these bangs correct? return true; } @@ -2770,6 +2774,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } } + statusCureTurn = statusCureTurn!; // tell TS compiler it's defined + effect = effect!; // If `effect` is undefined then `trySetStatus()` will have already returned early via the `canSetStatus()` call this.status = new Status(effect, 0, statusCureTurn?.value); if (effect !== StatusEffect.FAINT) { @@ -2790,7 +2796,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { if (!revive && lastStatus === StatusEffect.FAINT) { return; } - this.status = undefined; + this.status = null; if (lastStatus === StatusEffect.SLEEP) { this.setFrameRate(12); if (this.getTag(BattlerTagType.NIGHTMARE)) { @@ -2858,16 +2864,16 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { setFrameRate(frameRate: integer) { this.scene.anims.get(this.getBattleSpriteKey()).frameRate = frameRate; this.getSprite().play(this.getBattleSpriteKey()); - this.getTintSprite().play(this.getBattleSpriteKey()); + this.getTintSprite()?.play(this.getBattleSpriteKey()); } tint(color: number, alpha?: number, duration?: integer, ease?: string) { const tintSprite = this.getTintSprite(); - tintSprite.setTintFill(color); - tintSprite.setVisible(true); + tintSprite?.setTintFill(color); + tintSprite?.setVisible(true); if (duration) { - tintSprite.setAlpha(0); + tintSprite?.setAlpha(0); this.scene.tweens.add({ targets: tintSprite, @@ -2876,7 +2882,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { ease: ease || "Linear" }); } else { - tintSprite.setAlpha(alpha); + tintSprite?.setAlpha(alpha); } } @@ -2890,32 +2896,32 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { duration: duration, ease: ease || "Linear", onComplete: () => { - tintSprite.setVisible(false); - tintSprite.setAlpha(1); + tintSprite?.setVisible(false); + tintSprite?.setAlpha(1); } }); } else { - tintSprite.setVisible(false); - tintSprite.setAlpha(1); + tintSprite?.setVisible(false); + tintSprite?.setAlpha(1); } } enableMask() { if (!this.maskEnabled) { this.maskSprite = this.getTintSprite(); - this.maskSprite.setVisible(true); - this.maskSprite.setPosition(this.x * this.parentContainer.scale + this.parentContainer.x, + this.maskSprite?.setVisible(true); + this.maskSprite?.setPosition(this.x * this.parentContainer.scale + this.parentContainer.x, this.y * this.parentContainer.scale + this.parentContainer.y); - this.maskSprite.setScale(this.getSpriteScale() * this.parentContainer.scale); + this.maskSprite?.setScale(this.getSpriteScale() * this.parentContainer.scale); this.maskEnabled = true; } } disableMask() { if (this.maskEnabled) { - this.maskSprite.setVisible(false); - this.maskSprite.setPosition(0, 0); - this.maskSprite.setScale(this.getSpriteScale()); + this.maskSprite?.setVisible(false); + this.maskSprite?.setPosition(0, 0); + this.maskSprite?.setScale(this.getSpriteScale()); this.maskSprite = null; this.maskEnabled = false; } @@ -2930,7 +2936,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { updateFusionPalette(ignoreOveride?: boolean): void { if (!this.getFusionSpeciesForm(ignoreOveride)) { - [ this.getSprite(), this.getTintSprite() ].map(s => { + [ this.getSprite(), this.getTintSprite() ].filter(s => !!s).map(s => { s.pipelineData[`spriteColors${ignoreOveride && this.summonData?.speciesForm ? "Base" : ""}`] = []; s.pipelineData[`fusionSpriteColors${ignoreOveride && this.summonData?.speciesForm ? "Base" : ""}`] = []; }); @@ -2966,9 +2972,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { const frame = [ sourceFrame, sourceBackFrame, fusionFrame, fusionBackFrame ][c]; canv.width = frame.width; canv.height = frame.height; - context.drawImage([ sourceImage, sourceBackImage, fusionImage, fusionBackImage ][c], frame.cutX, frame.cutY, frame.width, frame.height, 0, 0, frame.width, frame.height); - const imageData = context.getImageData(frame.cutX, frame.cutY, frame.width, frame.height); - pixelData.push(imageData.data); + + if (context) { + context.drawImage([ sourceImage, sourceBackImage, fusionImage, fusionBackImage ][c], frame.cutX, frame.cutY, frame.width, frame.height, 0, 0, frame.width, frame.height); + const imageData = context.getImageData(frame.cutX, frame.cutY, frame.width, frame.height); + pixelData.push(imageData.data); + } }); for (let f = 0; f < 2; f++) { @@ -2988,7 +2997,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { const color = Utils.rgbaToInt([r, g, b, a]); if (variantColorSet.has(color)) { const mappedPixel = variantColorSet.get(color); - [ r, g, b, a ] = mappedPixel; + if (mappedPixel) { + [ r, g, b, a ] = mappedPixel; + } } } if (!spriteColors.find(c => c[0] === r && c[1] === g && c[2] === b)) { @@ -3000,7 +3011,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { const fusionSpriteColors = JSON.parse(JSON.stringify(spriteColors)); - const pixelColors = []; + const pixelColors: number[] = []; for (let f = 0; f < 2; f++) { for (let i = 0; i < pixelData[f].length; i += 4) { const total = pixelData[f].slice(i, i + 3).reduce((total: integer, value: integer) => total + value, 0); @@ -3011,7 +3022,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } } - const fusionPixelColors = []; + const fusionPixelColors : number[] = []; for (let f = 0; f < 2; f++) { const variantColors = variantColorCache[!f ? fusionSpriteKey : fusionBackSpriteKey]; const variantColorSet = new Map(); @@ -3030,7 +3041,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { const color = Utils.rgbaToInt([r, g, b, a]); if (variantColorSet.has(color)) { const mappedPixel = variantColorSet.get(color); - [ r, g, b, a ] = mappedPixel; + if (mappedPixel) { + [ r, g, b, a ] = mappedPixel; + } } } fusionPixelColors.push(argbFromRgba({ r, g, b, a })); @@ -3050,9 +3063,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { Math.random = originalRandom; + paletteColors = paletteColors!; // tell TS compiler that paletteColors is defined! + fusionPaletteColors = fusionPaletteColors!; // TS compiler that fusionPaletteColors is defined! const [ palette, fusionPalette ] = [ paletteColors, fusionPaletteColors ] .map(paletteColors => { - let keys = Array.from(paletteColors.keys()).sort((a: integer, b: integer) => paletteColors.get(a) < paletteColors.get(b) ? 1 : -1); + let keys = Array.from(paletteColors.keys()).sort((a: integer, b: integer) => paletteColors.get(a)! < paletteColors.get(b)! ? 1 : -1); let rgbaColors: Map; let hsvColors: Map; @@ -3065,19 +3080,19 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { map.set(k, Object.values(rgbaFromArgb(k))); return map; }, new Map()); hsvColors = Array.from(rgbaColors.keys()).reduce((map: Map, k: number) => { - const rgb = rgbaColors.get(k).slice(0, 3); + const rgb = rgbaColors.get(k)!.slice(0, 3); map.set(k, Utils.rgbToHsv(rgb[0], rgb[1], rgb[2])); return map; }, new Map()); for (let c = keys.length - 1; c >= 0; c--) { - const hsv = hsvColors.get(keys[c]); + const hsv = hsvColors.get(keys[c])!; for (let c2 = 0; c2 < c; c2++) { - const hsv2 = hsvColors.get(keys[c2]); + const hsv2 = hsvColors.get(keys[c2])!; const diff = Math.abs(hsv[0] - hsv2[0]); if (diff < 30 || diff >= 330) { if (mappedColors.has(keys[c])) { - mappedColors.get(keys[c]).push(keys[c2]); + mappedColors.get(keys[c])!.push(keys[c2]); } else { mappedColors.set(keys[c], [ keys[c2] ]); } @@ -3087,10 +3102,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } mappedColors.forEach((values: integer[], key: integer) => { - const keyColor = rgbaColors.get(key); - const valueColors = values.map(v => rgbaColors.get(v)); + const keyColor = rgbaColors.get(key)!; + const valueColors = values.map(v => rgbaColors.get(v)!); const color = keyColor.slice(0); - let count = paletteColors.get(key); + let count = paletteColors.get(key)!; for (const value of values) { const valueCount = paletteColors.get(value); if (!valueCount) { @@ -3100,10 +3115,10 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } for (let c = 0; c < 3; c++) { - color[c] *= (paletteColors.get(key) / count); + color[c] *= (paletteColors.get(key)! / count); values.forEach((value: integer, i: integer) => { if (paletteColors.has(value)) { - const valueCount = paletteColors.get(value); + const valueCount = paletteColors.get(value)!; color[c] += valueColors[i][c] * (valueCount / count); } }); @@ -3121,7 +3136,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { paletteColors.set(argbFromRgba({ r: color[0], g: color[1], b: color[2], a: color[3] }), count); }); - keys = Array.from(paletteColors.keys()).sort((a: integer, b: integer) => paletteColors.get(a) < paletteColors.get(b) ? 1 : -1); + keys = Array.from(paletteColors.keys()).sort((a: integer, b: integer) => paletteColors.get(a)! < paletteColors.get(b)! ? 1 : -1); } while (mappedColors.size); return keys.map(c => Object.values(rgbaFromArgb(c))); @@ -3152,7 +3167,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } } - [ this.getSprite(), this.getTintSprite() ].map(s => { + [ this.getSprite(), this.getTintSprite() ].filter(s => !!s).map(s => { s.pipelineData[`spriteColors${ignoreOveride && this.summonData?.speciesForm ? "Base" : ""}`] = spriteColors; s.pipelineData[`fusionSpriteColors${ignoreOveride && this.summonData?.speciesForm ? "Base" : ""}`] = fusionSpriteColors; }); @@ -3216,7 +3231,7 @@ export default interface Pokemon { export class PlayerPokemon extends Pokemon { public compatibleTms: Moves[]; - constructor(scene: BattleScene, species: PokemonSpecies, level: integer, abilityIndex: integer, formIndex: integer, gender: Gender, shiny: boolean, variant: Variant, ivs: integer[], nature: Nature, dataSource: Pokemon | PokemonData) { + constructor(scene: BattleScene, species: PokemonSpecies, level: integer, abilityIndex?: integer, formIndex?: integer, gender?: Gender, shiny?: boolean, variant?: Variant, ivs?: integer[], nature?: Nature, dataSource?: Pokemon | PokemonData) { super(scene, 106, 148, species, level, abilityIndex, formIndex, gender, shiny, variant, ivs, nature, dataSource); if (Overrides.STATUS_OVERRIDE) { @@ -3320,11 +3335,11 @@ export class PlayerPokemon extends Pokemon { addFriendship(friendship: integer): void { const starterSpeciesId = this.species.getRootSpeciesId(); - const fusionStarterSpeciesId = this.isFusion() ? this.fusionSpecies.getRootSpeciesId() : 0; + const fusionStarterSpeciesId = this.isFusion() && this.fusionSpecies ? this.fusionSpecies.getRootSpeciesId() : 0; const starterData = [ this.scene.gameData.starterData[starterSpeciesId], fusionStarterSpeciesId ? this.scene.gameData.starterData[fusionStarterSpeciesId] : null - ].filter(d => d); + ].filter(d => !!d); const amount = new Utils.IntegerHolder(friendship); const starterAmount = new Utils.IntegerHolder(Math.floor(friendship * (this.scene.gameMode.isClassic && friendship > 0 ? 2 : 1) / (fusionStarterSpeciesId ? 2 : 1))); if (amount.value > 0) { @@ -3388,7 +3403,10 @@ export class PlayerPokemon extends Pokemon { }); } - getPossibleEvolution(evolution: SpeciesFormEvolution): Promise { + getPossibleEvolution(evolution: SpeciesFormEvolution | null): Promise { + if (!evolution) { + return new Promise(resolve => resolve(this)); + } return new Promise(resolve => { const evolutionSpecies = getPokemonSpecies(evolution.speciesId); const isFusion = evolution instanceof FusionSpeciesFormEvolution; @@ -3409,7 +3427,10 @@ export class PlayerPokemon extends Pokemon { }); } - evolve(evolution: SpeciesFormEvolution, preEvolution: PokemonSpeciesForm): Promise { + evolve(evolution: SpeciesFormEvolution | null, preEvolution: PokemonSpeciesForm): Promise { + if (!evolution) { + return new Promise(resolve => resolve()); + } return new Promise(resolve => { this.pauseEvolutions = false; // Handles Nincada evolving into Ninjask + Shedinja @@ -3421,7 +3442,7 @@ export class PlayerPokemon extends Pokemon { this.fusionSpecies = getPokemonSpecies(evolution.speciesId); } if (evolution.preFormKey !== null) { - const formIndex = Math.max((!isFusion ? this.species : this.fusionSpecies).forms.findIndex(f => f.formKey === evolution.evoFormKey), 0); + const formIndex = Math.max((!isFusion || !this.fusionSpecies ? this.species : this.fusionSpecies).forms.findIndex(f => f.formKey === evolution.evoFormKey), 0); if (!isFusion) { this.formIndex = formIndex; } else { @@ -3477,10 +3498,10 @@ export class PlayerPokemon extends Pokemon { const isFusion = evolution instanceof FusionSpeciesFormEvolution; const evoSpecies = (!isFusion ? this.species : this.fusionSpecies); - if (evoSpecies.speciesId === Species.NINCADA && evolution.speciesId === Species.NINJASK) { + if (evoSpecies?.speciesId === Species.NINCADA && evolution.speciesId === Species.NINJASK) { const newEvolution = pokemonEvolutions[evoSpecies.speciesId][1]; - if (newEvolution.condition.predicate(this)) { + if (newEvolution.condition?.predicate(this)) { const newPokemon = this.scene.addPlayerPokemon(this.species, this.level, this.abilityIndex, this.formIndex, undefined, this.shiny, this.variant, this.ivs, this.nature); newPokemon.natureOverride = this.natureOverride; newPokemon.passive = this.passive; @@ -3576,7 +3597,7 @@ export class PlayerPokemon extends Pokemon { if (!this.isFainted()) { // If this Pokemon hasn't fainted, make sure the HP wasn't set over the new maximum this.hp = Math.min(this.hp, this.stats[Stat.HP]); - this.status = getRandomStatus(this.status, pokemon.status); // Get a random valid status between the two + this.status = getRandomStatus(this.status!, pokemon.status!); // Get a random valid status between the two // TODO: are the bangs correct? } else if (!pokemon.isFainted()) { // If this Pokemon fainted but the other hasn't, make sure the HP wasn't set to zero this.hp = Math.max(this.hp, 1); @@ -3601,7 +3622,7 @@ export class PlayerPokemon extends Pokemon { this.scene.removePartyMemberModifiers(fusedPartyMemberIndex); this.scene.getParty().splice(fusedPartyMemberIndex, 1)[0]; const newPartyMemberIndex = this.scene.getParty().indexOf(this); - pokemon.getMoveset(true).map(m => this.scene.unshiftPhase(new LearnMovePhase(this.scene, newPartyMemberIndex, m.getMove().id))); + pokemon.getMoveset(true).map(m => this.scene.unshiftPhase(new LearnMovePhase(this.scene, newPartyMemberIndex, m!.getMove().id))); // TODO: is the bang correct? pokemon.destroy(); this.updateFusionPalette(); resolve(); @@ -3621,9 +3642,9 @@ export class PlayerPokemon extends Pokemon { /** Returns a deep copy of this Pokemon's moveset array */ copyMoveset(): PokemonMove[] { - const newMoveset = []; + const newMoveset : PokemonMove[] = []; this.moveset.forEach(move => - newMoveset.push(new PokemonMove(move.moveId, 0, move.ppUp, move.virtual))); + newMoveset.push(new PokemonMove(move!.moveId, 0, move!.ppUp, move!.virtual))); // TODO: are those bangs correct? return newMoveset; } @@ -3637,9 +3658,9 @@ export class EnemyPokemon extends Pokemon { /** To indicate of the instance was populated with a dataSource -> e.g. loaded & populated from session data */ public readonly isPopulatedFromDataSource: boolean; - constructor(scene: BattleScene, species: PokemonSpecies, level: integer, trainerSlot: TrainerSlot, boss: boolean, dataSource: PokemonData) { + constructor(scene: BattleScene, species: PokemonSpecies, level: integer, trainerSlot: TrainerSlot, boss: boolean, dataSource?: PokemonData) { super(scene, 236, 84, species, level, dataSource?.abilityIndex, dataSource?.formIndex, - dataSource?.gender, dataSource ? dataSource.shiny : false, dataSource ? dataSource.variant : undefined, null, dataSource ? dataSource.nature : undefined, dataSource); + dataSource?.gender, dataSource ? dataSource.shiny : false, dataSource ? dataSource.variant : undefined, undefined, dataSource ? dataSource.nature : undefined, dataSource); this.trainerSlot = trainerSlot; this.isPopulatedFromDataSource = !!dataSource; // if a dataSource is provided, then it was populated from dataSource @@ -3672,7 +3693,7 @@ export class EnemyPokemon extends Pokemon { let speciesId = species.speciesId; while ((prevolution = pokemonPrevolutions[speciesId])) { const evolution = pokemonEvolutions[prevolution].find(pe => pe.speciesId === speciesId && (!pe.evoFormKey || pe.evoFormKey === this.getFormKey())); - if (evolution.condition?.enforceFunc) { + if (evolution?.condition?.enforceFunc) { evolution.condition.enforceFunc(this); } speciesId = prevolution; @@ -3748,7 +3769,7 @@ export class EnemyPokemon extends Pokemon { getNextMove(): QueuedMove { // If this Pokemon has a move already queued, return it. const queuedMove = this.getMoveQueue().length - ? this.getMoveset().find(m => m.moveId === this.getMoveQueue()[0].move) + ? this.getMoveset().find(m => m?.moveId === this.getMoveQueue()[0].move) : null; if (queuedMove) { if (queuedMove.isUsable(this, this.getMoveQueue()[0].ignorePP)) { @@ -3760,24 +3781,24 @@ export class EnemyPokemon extends Pokemon { } // Filter out any moves this Pokemon cannot use - const movePool = this.getMoveset().filter(m => m.isUsable(this)); + const movePool = this.getMoveset().filter(m => m?.isUsable(this)); // If no moves are left, use Struggle. Otherwise, continue with move selection if (movePool.length) { // If there's only 1 move in the move pool, use it. if (movePool.length === 1) { - return { move: movePool[0].moveId, targets: this.getNextTargets(movePool[0].moveId) }; + return { move: movePool[0]!.moveId, targets: this.getNextTargets(movePool[0]!.moveId) }; // TODO: are the bangs correct? } // If a move is forced because of Encore, use it. const encoreTag = this.getTag(EncoreTag) as EncoreTag; if (encoreTag) { - const encoreMove = movePool.find(m => m.moveId === encoreTag.moveId); + const encoreMove = movePool.find(m => m?.moveId === encoreTag.moveId); if (encoreMove) { return { move: encoreMove.moveId, targets: this.getNextTargets(encoreMove.moveId) }; } } switch (this.aiType) { case AiType.RANDOM: // No enemy should spawn with this AI type in-game - const moveId = movePool[this.scene.randBattleSeedInt(movePool.length)].moveId; + const moveId = movePool[this.scene.randBattleSeedInt(movePool.length)]!.moveId; // TODO: is the bang correct? return { move: moveId, targets: this.getNextTargets(moveId) }; case AiType.SMART_RANDOM: case AiType.SMART: @@ -3787,9 +3808,9 @@ export class EnemyPokemon extends Pokemon { * For more information on how benefit scores are calculated, see `docs/enemy-ai.md`. */ const moveScores = movePool.map(() => 0); - const moveTargets = Object.fromEntries(movePool.map(m => [ m.moveId, this.getNextTargets(m.moveId) ])); + const moveTargets = Object.fromEntries(movePool.map(m => [ m!.moveId, this.getNextTargets(m!.moveId) ])); // TODO: are those bangs correct? for (const m in movePool) { - const pokemonMove = movePool[m]; + const pokemonMove = movePool[m]!; // TODO: is the bang correct? const move = pokemonMove.getMove(); let moveScore = moveScores[m]; @@ -3870,8 +3891,8 @@ export class EnemyPokemon extends Pokemon { r++; } } - console.log(movePool.map(m => m.getName()), moveScores, r, sortedMovePool.map(m => m.getName())); - return { move: sortedMovePool[r].moveId, targets: moveTargets[sortedMovePool[r].moveId] }; + console.log(movePool.map(m => m!.getName()), moveScores, r, sortedMovePool.map(m => m!.getName())); // TODO: are those bangs correct? + return { move: sortedMovePool[r]!.moveId, targets: moveTargets[sortedMovePool[r]!.moveId] }; } } @@ -3934,7 +3955,7 @@ export class EnemyPokemon extends Pokemon { } const thresholds: integer[] = []; - let totalWeight: integer; + let totalWeight: integer = 0; targetWeights.reduce((total: integer, w: integer) => { total += w; thresholds.push(total); @@ -3948,7 +3969,7 @@ export class EnemyPokemon extends Pokemon { * is greater than that random number. */ const randValue = this.scene.randBattleSeedInt(totalWeight); - let targetIndex: integer; + let targetIndex: integer = 0; thresholds.every((t, i) => { if (randValue >= t) { @@ -4124,7 +4145,7 @@ export class EnemyPokemon extends Pokemon { addToParty(pokeballType: PokeballType) { const party = this.scene.getParty(); - let ret: PlayerPokemon = null; + let ret: PlayerPokemon | null = null; if (party.length < 6) { this.pokeball = pokeballType; @@ -4173,15 +4194,15 @@ export class PokemonSummonData { public abilitySuppressed: boolean = false; public abilitiesApplied: Abilities[] = []; - public speciesForm: PokemonSpeciesForm; + public speciesForm: PokemonSpeciesForm | null; public fusionSpeciesForm: PokemonSpeciesForm; public ability: Abilities = Abilities.NONE; public gender: Gender; public fusionGender: Gender; public stats: integer[]; - public moveset: PokemonMove[]; + public moveset: (PokemonMove | null)[]; // If not initialized this value will not be populated from save data. - public types: Type[] = null; + public types: Type[] = []; } export class PokemonBattleData { diff --git a/src/field/trainer.ts b/src/field/trainer.ts index 470e8d2267f..1348749d964 100644 --- a/src/field/trainer.ts +++ b/src/field/trainer.ts @@ -208,7 +208,7 @@ export default class Trainer extends Phaser.GameObjects.Container { } getPartyLevels(waveIndex: integer): integer[] { - const ret = []; + const ret: number[] = []; const partyTemplate = this.getPartyTemplate(); const difficultyWaveIndex = this.scene.gameMode.getWaveForDifficulty(waveIndex); @@ -257,7 +257,7 @@ export default class Trainer extends Phaser.GameObjects.Container { genPartyMember(index: integer): EnemyPokemon { const battle = this.scene.currentBattle; - const level = battle.enemyLevels[index]; + const level = battle.enemyLevels?.[index]!; // TODO: is this bang correct? let ret: EnemyPokemon; @@ -290,7 +290,7 @@ export default class Trainer extends Phaser.GameObjects.Container { } // Create an empty species pool (which will be set to one of the species pools based on the index) - let newSpeciesPool = []; + let newSpeciesPool: Species[] = []; let useNewSpeciesPool = false; // If we are in a double battle of named trainers, we need to use alternate species pools (generate half the party from each trainer) @@ -315,7 +315,7 @@ export default class Trainer extends Phaser.GameObjects.Container { return !species.some(s => AlreadyUsedSpecies.includes(s)); } return !AlreadyUsedSpecies.includes(species); - }); + }).flat(); // Filter out the species that are already in the enemy party from the partner trainer species pool const speciesPoolPartnerFiltered = speciesPoolPartner.filter(species => { @@ -324,7 +324,7 @@ export default class Trainer extends Phaser.GameObjects.Container { return !species.some(s => AlreadyUsedSpecies.includes(s)); } return !AlreadyUsedSpecies.includes(species); - }); + }).flat(); // If the index is even, use the species pool for the main trainer (that way he only uses his own pokemon in battle) @@ -370,7 +370,7 @@ export default class Trainer extends Phaser.GameObjects.Container { ret = this.scene.addEnemyPokemon(species, level, !this.isDouble() || !(index % 2) ? TrainerSlot.TRAINER : TrainerSlot.TRAINER_PARTNER); }, this.config.hasStaticParty ? this.config.getDerivedType() + ((index + 1) << 8) : this.scene.currentBattle.waveIndex + (this.config.getDerivedType() << 10) + (((!this.config.useSameSeedForAllMembers ? index : 0) + 1) << 8)); - return ret; + return ret!; // TODO: is this bang correct? } @@ -481,7 +481,7 @@ export default class Trainer extends Phaser.GameObjects.Container { if (maxScorePartyMemberIndexes.length > 1) { let rand: integer; this.scene.executeWithSeedOffset(() => rand = Utils.randSeedInt(maxScorePartyMemberIndexes.length), this.scene.currentBattle.turn << 2); - return maxScorePartyMemberIndexes[rand]; + return maxScorePartyMemberIndexes[rand!]; } return maxScorePartyMemberIndexes[0]; @@ -499,6 +499,9 @@ export default class Trainer extends Phaser.GameObjects.Container { return 0.45; case PartyMemberStrength.STRONGER: return 0.375; + default: + console.warn("getPartyMemberModifierChanceMultiplier not defined. Using default 0"); + return 0; } } diff --git a/src/game-mode.ts b/src/game-mode.ts index 010cae03e5e..2475cb5cfb4 100644 --- a/src/game-mode.ts +++ b/src/game-mode.ts @@ -167,7 +167,7 @@ export class GameMode implements GameModeConfig { } } - getOverrideSpecies(waveIndex: integer): PokemonSpecies { + getOverrideSpecies(waveIndex: integer): PokemonSpecies | null { if (this.isDaily && this.isWaveFinal(waveIndex)) { const allFinalBossSpecies = allSpecies.filter(s => (s.subLegendary || s.legendary || s.mythical) && s.baseTotal >= 600 && s.speciesId !== Species.ETERNATUS && s.speciesId !== Species.ARCEUS); @@ -210,7 +210,7 @@ export class GameMode implements GameModeConfig { * @returns true if waveIndex is a multiple of 50 in Endless */ isEndlessBoss(waveIndex: integer): boolean { - return waveIndex % 50 && + return !!(waveIndex % 50) && (this.modeId === GameModes.ENDLESS || this.modeId === GameModes.SPLICED_ENDLESS); } @@ -267,6 +267,8 @@ export class GameMode implements GameModeConfig { return 5000; case GameModes.DAILY: return 2500; + default: + return 0; } } diff --git a/src/inputs-controller.ts b/src/inputs-controller.ts index 834ca233942..331d491b807 100644 --- a/src/inputs-controller.ts +++ b/src/inputs-controller.ts @@ -154,7 +154,7 @@ export class InputsController { }); if (typeof this.scene.input.gamepad !== "undefined") { - this.scene.input.gamepad.on("connected", function (thisGamepad) { + this.scene.input.gamepad?.on("connected", function (thisGamepad) { if (!thisGamepad) { return; } @@ -163,23 +163,23 @@ export class InputsController { this.onReconnect(thisGamepad); }, this); - this.scene.input.gamepad.on("disconnected", function (thisGamepad) { + this.scene.input.gamepad?.on("disconnected", function (thisGamepad) { this.onDisconnect(thisGamepad); // when a gamepad is disconnected }, this); // Check to see if the gamepad has already been setup by the browser - this.scene.input.gamepad.refreshPads(); - if (this.scene.input.gamepad.total) { + this.scene.input.gamepad?.refreshPads(); + if (this.scene.input.gamepad?.total) { this.refreshGamepads(); for (const thisGamepad of this.gamepads) { this.scene.input.gamepad.emit("connected", thisGamepad); } } - this.scene.input.gamepad.on("down", this.gamepadButtonDown, this); - this.scene.input.gamepad.on("up", this.gamepadButtonUp, this); - this.scene.input.keyboard.on("keydown", this.keyboardKeyDown, this); - this.scene.input.keyboard.on("keyup", this.keyboardKeyUp, this); + this.scene.input.gamepad?.on("down", this.gamepadButtonDown, this); + this.scene.input.gamepad?.on("up", this.gamepadButtonUp, this); + this.scene.input.keyboard?.on("keydown", this.keyboardKeyDown, this); + this.scene.input.keyboard?.on("keyup", this.keyboardKeyUp, this); } this.touchControls = new TouchControl(this.scene); } @@ -338,9 +338,9 @@ export class InputsController { */ refreshGamepads(): void { // Sometimes, gamepads are undefined. For some reason. - this.gamepads = this.scene.input.gamepad.gamepads.filter(function (el) { + this.gamepads = this.scene.input.gamepad?.gamepads.filter(function (el) { return el !== null; - }); + })!; // TODO: is this bang correct? for (const [index, thisGamepad] of this.gamepads.entries()) { thisGamepad.index = index; // Overwrite the gamepad index, in case we had undefined gamepads earlier diff --git a/src/loading-scene.ts b/src/loading-scene.ts index 5275411055e..c00112318c8 100644 --- a/src/loading-scene.ts +++ b/src/loading-scene.ts @@ -453,8 +453,8 @@ export class LoadingScene extends SceneBase { // videos do not need to be preloaded intro.loadURL("images/intro_dark.mp4", true); if (mobile) { - intro.video.setAttribute("webkit-playsinline", "webkit-playsinline"); - intro.video.setAttribute("playsinline", "playsinline"); + intro.video?.setAttribute("webkit-playsinline", "webkit-playsinline"); + intro.video?.setAttribute("playsinline", "playsinline"); } intro.play(); }); diff --git a/src/messages.ts b/src/messages.ts index 555a6f30ef1..b9bf94802f7 100644 --- a/src/messages.ts +++ b/src/messages.ts @@ -7,7 +7,10 @@ import i18next from "i18next"; * @param pokemon {@linkcode Pokemon} name and battle context will be retrieved from this instance * @returns {string} ex: "Wild Gengar", "Ectoplasma sauvage" */ -export function getPokemonNameWithAffix(pokemon: Pokemon): string { +export function getPokemonNameWithAffix(pokemon: Pokemon | undefined): string { + if (!pokemon) { + return "Missigno"; + } // TODO: little easter-egg, lol switch (pokemon.scene.currentBattle.battleSpec) { case BattleSpec.DEFAULT: return !pokemon.isPlayer() diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index 6123ecd3b80..a6117d09ffe 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -51,13 +51,13 @@ export class ModifierType { public group: string; public soundName: string; public tier: ModifierTier; - protected newModifierFunc: NewModifierFunc; + protected newModifierFunc: NewModifierFunc | null; - constructor(localeKey: string, iconImage: string, newModifierFunc: NewModifierFunc, group?: string, soundName?: string) { - this.localeKey = localeKey; - this.iconImage = iconImage; - this.group = group || ""; - this.soundName = soundName || "restore"; + constructor(localeKey: string | null, iconImage: string | null, newModifierFunc: NewModifierFunc | null, group?: string, soundName?: string) { + this.localeKey = localeKey!; // TODO: is this bang correct? + this.iconImage = iconImage!; // TODO: is this bang correct? + this.group = group!; // TODO: is this bang correct? + this.soundName = soundName ?? "restore"; this.newModifierFunc = newModifierFunc; } @@ -73,7 +73,7 @@ export class ModifierType { this.tier = tier; } - getOrInferTier(poolType: ModifierPoolType = ModifierPoolType.PLAYER): ModifierTier { + getOrInferTier(poolType: ModifierPoolType = ModifierPoolType.PLAYER): ModifierTier | null { if (this.tier) { return this.tier; } @@ -111,16 +111,16 @@ export class ModifierType { } withIdFromFunc(func: ModifierTypeFunc): ModifierType { - this.id = Object.keys(modifierTypes).find(k => modifierTypes[k] === func); + this.id = Object.keys(modifierTypes).find(k => modifierTypes[k] === func)!; // TODO: is this bang correct? return this; } - newModifier(...args: any[]): Modifier { - return this.newModifierFunc(this, args); + newModifier(...args: any[]): Modifier | null { + return this.newModifierFunc && this.newModifierFunc(this, args); } } -type ModifierTypeGeneratorFunc = (party: Pokemon[], pregenArgs?: any[]) => ModifierType; +type ModifierTypeGeneratorFunc = (party: Pokemon[], pregenArgs?: any[]) => ModifierType | null; export class ModifierTypeGenerator extends ModifierType { private genTypeFunc: ModifierTypeGeneratorFunc; @@ -197,7 +197,7 @@ class AddVoucherModifierType extends ModifierType { } export class PokemonModifierType extends ModifierType { - public selectFilter: PokemonSelectFilter; + public selectFilter: PokemonSelectFilter | undefined; constructor(localeKey: string, iconImage: string, newModifierFunc: NewModifierFunc, selectFilter?: PokemonSelectFilter, group?: string, soundName?: string) { super(localeKey, iconImage, newModifierFunc, group, soundName); @@ -298,7 +298,7 @@ export class PokemonStatusHealModifierType extends PokemonModifierType { } export abstract class PokemonMoveModifierType extends PokemonModifierType { - public moveSelectFilter: PokemonMoveSelectFilter; + public moveSelectFilter: PokemonMoveSelectFilter | undefined; constructor(localeKey: string, iconImage: string, newModifierFunc: NewModifierFunc, selectFilter?: PokemonSelectFilter, moveSelectFilter?: PokemonMoveSelectFilter, group?: string) { super(localeKey, iconImage, newModifierFunc, selectFilter, group); @@ -338,7 +338,7 @@ export class PokemonAllMovePpRestoreModifierType extends PokemonModifierType { constructor(localeKey: string, iconImage: string, restorePoints: integer) { super(localeKey, iconImage, (_type, args) => new Modifiers.PokemonAllMovePpRestoreModifier(this, (args[0] as PlayerPokemon).id, this.restorePoints), (pokemon: PlayerPokemon) => { - if (!pokemon.getMoveset().filter(m => m.ppUsed).length) { + if (!pokemon.getMoveset().filter(m => m?.ppUsed).length) { return PartyUiHandler.NoEffectMessage; } return null; @@ -518,7 +518,7 @@ export class AttackTypeBoosterModifierType extends PokemonHeldItemModifierType i public boostPercent: integer; constructor(moveType: Type, boostPercent: integer) { - super("", `${getAttackTypeBoosterItemName(moveType).replace(/[ \-]/g, "_").toLowerCase()}`, + super("", `${getAttackTypeBoosterItemName(moveType)?.replace(/[ \-]/g, "_").toLowerCase()}`, (_type, args) => new Modifiers.AttackTypeBoosterModifier(this, (args[0] as Pokemon).id, moveType, boostPercent)); this.moveType = moveType; @@ -526,7 +526,7 @@ export class AttackTypeBoosterModifierType extends PokemonHeldItemModifierType i } get name(): string { - return i18next.t(`modifierType:AttackTypeBoosterItem.${getAttackTypeBoosterItemName(this.moveType).replace(/[ \-]/g, "_").toLowerCase()}`); + return i18next.t(`modifierType:AttackTypeBoosterItem.${getAttackTypeBoosterItemName(this.moveType)?.replace(/[ \-]/g, "_").toLowerCase()}`); } getDescription(scene: BattleScene): string { @@ -638,7 +638,7 @@ class AllPokemonFullHpRestoreModifierType extends ModifierType { constructor(localeKey: string, iconImage: string, descriptionKey?: string, newModifierFunc?: NewModifierFunc) { super(localeKey, iconImage, newModifierFunc || ((_type, _args) => new Modifiers.PokemonHpRestoreModifier(this, -1, 0, 100, false))); - this.descriptionKey = descriptionKey; + this.descriptionKey = descriptionKey!; // TODO: is this bang correct? } getDescription(scene: BattleScene): string { @@ -773,7 +773,7 @@ export class EvolutionItemModifierType extends PokemonModifierType implements Ge if (pokemonEvolutions.hasOwnProperty(pokemon.species.speciesId) && pokemonEvolutions[pokemon.species.speciesId].filter(e => e.item === this.evolutionItem && (!e.condition || e.condition.predicate(pokemon))).length && (pokemon.getFormKey() !== SpeciesFormKey.GIGANTAMAX)) { return null; - } else if (pokemon.isFusion() && pokemonEvolutions.hasOwnProperty(pokemon.fusionSpecies.speciesId) && pokemonEvolutions[pokemon.fusionSpecies.speciesId].filter(e => e.item === this.evolutionItem + } else if (pokemon.isFusion() && pokemon.fusionSpecies && pokemonEvolutions.hasOwnProperty(pokemon.fusionSpecies.speciesId) && pokemonEvolutions[pokemon.fusionSpecies.speciesId].filter(e => e.item === this.evolutionItem && (!e.condition || e.condition.predicate(pokemon))).length && (pokemon.getFusionFormKey() !== SpeciesFormKey.GIGANTAMAX)) { return null; } @@ -859,7 +859,7 @@ class AttackTypeBoosterModifierTypeGenerator extends ModifierTypeGenerator { return new AttackTypeBoosterModifierType(pregenArgs[0] as Type, 20); } - const attackMoveTypes = party.map(p => p.getMoveset().map(m => m.getMove()).filter(m => m instanceof AttackMove).map(m => m.type)).flat(); + const attackMoveTypes = party.map(p => p.getMoveset().map(m => m?.getMove()).filter(m => m instanceof AttackMove).map(m => m.type)).flat(); if (!attackMoveTypes.length) { return null; } @@ -868,8 +868,8 @@ class AttackTypeBoosterModifierTypeGenerator extends ModifierTypeGenerator { let totalWeight = 0; for (const t of attackMoveTypes) { if (attackMoveTypeWeights.has(t)) { - if (attackMoveTypeWeights.get(t) < 3) { - attackMoveTypeWeights.set(t, attackMoveTypeWeights.get(t) + 1); + if (attackMoveTypeWeights.get(t)! < 3) { // attackMoveTypeWeights.has(t) was checked before + attackMoveTypeWeights.set(t, attackMoveTypeWeights.get(t)! + 1); } else { continue; } @@ -889,7 +889,7 @@ class AttackTypeBoosterModifierTypeGenerator extends ModifierTypeGenerator { let weight = 0; for (const t of attackMoveTypeWeights.keys()) { - const typeWeight = attackMoveTypeWeights.get(t); + const typeWeight = attackMoveTypeWeights.get(t)!; // guranteed to be defined if (randInt <= weight + typeWeight) { type = t; break; @@ -897,7 +897,7 @@ class AttackTypeBoosterModifierTypeGenerator extends ModifierTypeGenerator { weight += typeWeight; } - return new AttackTypeBoosterModifierType(type, 20); + return new AttackTypeBoosterModifierType(type!, 20); }); } } @@ -930,7 +930,7 @@ class SpeciesStatBoosterModifierTypeGenerator extends ModifierTypeGenerator { for (const p of party) { const speciesId = p.getSpeciesForm(true).speciesId; const fusionSpeciesId = p.isFusion() ? p.getFusionSpeciesForm(true).speciesId : null; - const hasFling = p.getMoveset(true).some(m => m.moveId === Moves.FLING); + const hasFling = p.getMoveset(true).some(m => m?.moveId === Moves.FLING); for (const i in values) { const checkedSpecies = values[i].species; @@ -980,7 +980,7 @@ class SpeciesStatBoosterModifierTypeGenerator extends ModifierTypeGenerator { class TmModifierTypeGenerator extends ModifierTypeGenerator { constructor(tier: ModifierTier) { super((party: Pokemon[]) => { - const partyMemberCompatibleTms = party.map(p => (p as PlayerPokemon).compatibleTms.filter(tm => !p.moveset.find(m => m.moveId === tm))); + const partyMemberCompatibleTms = party.map(p => (p as PlayerPokemon).compatibleTms.filter(tm => !p.moveset.find(m => m?.moveId === tm))); const tierUniqueCompatibleTms = partyMemberCompatibleTms.flat().filter(tm => tmPoolTiers[tm] === tier).filter(tm => !allMoves[tm].name.endsWith(" (N)")).filter((tm, i, array) => array.indexOf(tm) === i); if (!tierUniqueCompatibleTms.length) { return null; @@ -1003,17 +1003,17 @@ class EvolutionItemModifierTypeGenerator extends ModifierTypeGenerator { const evolutions = pokemonEvolutions[p.species.speciesId]; return evolutions.filter(e => e.item !== EvolutionItem.NONE && (e.evoFormKey === null || (e.preFormKey || "") === p.getFormKey()) && (!e.condition || e.condition.predicate(p))); }).flat(), - party.filter(p => p.isFusion() && pokemonEvolutions.hasOwnProperty(p.fusionSpecies.speciesId)).map(p => { - const evolutions = pokemonEvolutions[p.fusionSpecies.speciesId]; + party.filter(p => p.isFusion() && p.fusionSpecies && pokemonEvolutions.hasOwnProperty(p.fusionSpecies.speciesId)).map(p => { + const evolutions = pokemonEvolutions[p.fusionSpecies!.speciesId]; return evolutions.filter(e => e.item !== EvolutionItem.NONE && (e.evoFormKey === null || (e.preFormKey || "") === p.getFusionFormKey()) && (!e.condition || e.condition.predicate(p))); }).flat() - ].flat().flatMap(e => e.item).filter(i => (i > 50) === rare); + ].flat().flatMap(e => e.item).filter(i => (!!i && i > 50) === rare); if (!evolutionItemPool.length) { return null; } - return new EvolutionItemModifierType(evolutionItemPool[Utils.randSeedInt(evolutionItemPool.length)]); + return new EvolutionItemModifierType(evolutionItemPool[Utils.randSeedInt(evolutionItemPool.length)]!); // TODO: is the bang correct? }); } } @@ -1156,7 +1156,7 @@ class WeightedModifierType { constructor(modifierTypeFunc: ModifierTypeFunc, weight: integer | WeightedModifierTypeWeightFunc, maxWeight?: integer) { this.modifierType = modifierTypeFunc(); - this.modifierType.id = Object.keys(modifierTypes).find(k => modifierTypes[k] === modifierTypeFunc); + this.modifierType.id = Object.keys(modifierTypes).find(k => modifierTypes[k] === modifierTypeFunc)!; // TODO: is this bang correct? this.weight = weight; this.maxWeight = maxWeight || (!(weight instanceof Function) ? weight : 0); } @@ -1410,7 +1410,7 @@ export const modifierTypes = { VOUCHER_PLUS: () => new AddVoucherModifierType(VoucherType.PLUS, 1), VOUCHER_PREMIUM: () => new AddVoucherModifierType(VoucherType.PREMIUM, 1), - GOLDEN_POKEBALL: () => new ModifierType("modifierType:ModifierType.GOLDEN_POKEBALL", "pb_gold", (type, _args) => new Modifiers.ExtraModifierModifier(type), null, "pb_bounce_1"), + GOLDEN_POKEBALL: () => new ModifierType("modifierType:ModifierType.GOLDEN_POKEBALL", "pb_gold", (type, _args) => new Modifiers.ExtraModifierModifier(type), undefined, "pb_bounce_1"), ENEMY_DAMAGE_BOOSTER: () => new ModifierType("modifierType:ModifierType.ENEMY_DAMAGE_BOOSTER", "wl_item_drop", (type, _args) => new Modifiers.EnemyDamageBoosterModifier(type, 5)), ENEMY_DAMAGE_REDUCTION: () => new ModifierType("modifierType:ModifierType.ENEMY_DAMAGE_REDUCTION", "wl_guard_spec", (type, _args) => new Modifiers.EnemyDamageReducerModifier(type, 2.5)), @@ -1451,11 +1451,11 @@ const modifierPool: ModifierPool = { return thresholdPartyMemberCount; }, 3), new WeightedModifierType(modifierTypes.ETHER, (party: Pokemon[]) => { - const thresholdPartyMemberCount = Math.min(party.filter(p => p.hp && p.getMoveset().filter(m => m.ppUsed && (m.getMovePp() - m.ppUsed) <= 5).length).length, 3); + const thresholdPartyMemberCount = Math.min(party.filter(p => p.hp && p.getMoveset().filter(m => m?.ppUsed && (m.getMovePp() - m.ppUsed) <= 5).length).length, 3); return thresholdPartyMemberCount * 3; }, 9), new WeightedModifierType(modifierTypes.MAX_ETHER, (party: Pokemon[]) => { - const thresholdPartyMemberCount = Math.min(party.filter(p => p.hp && p.getMoveset().filter(m => m.ppUsed && (m.getMovePp() - m.ppUsed) <= 5).length).length, 3); + const thresholdPartyMemberCount = Math.min(party.filter(p => p.hp && p.getMoveset().filter(m => m?.ppUsed && (m.getMovePp() - m.ppUsed) <= 5).length).length, 3); return thresholdPartyMemberCount; }, 3), new WeightedModifierType(modifierTypes.LURE, 2), @@ -1471,7 +1471,7 @@ const modifierPool: ModifierPool = { new WeightedModifierType(modifierTypes.FULL_HEAL, (party: Pokemon[]) => { const statusEffectPartyMemberCount = Math.min(party.filter(p => p.hp && !!p.status && !p.getHeldItems().some(i => { if (i instanceof Modifiers.TurnStatusEffectModifier) { - return (i as Modifiers.TurnStatusEffectModifier).getStatusEffect() === p.status.effect; + return (i as Modifiers.TurnStatusEffectModifier).getStatusEffect() === p.status?.effect; } return false; })).length, 3); @@ -1499,7 +1499,7 @@ const modifierPool: ModifierPool = { new WeightedModifierType(modifierTypes.FULL_RESTORE, (party: Pokemon[]) => { const statusEffectPartyMemberCount = Math.min(party.filter(p => p.hp && !!p.status && !p.getHeldItems().some(i => { if (i instanceof Modifiers.TurnStatusEffectModifier) { - return (i as Modifiers.TurnStatusEffectModifier).getStatusEffect() === p.status.effect; + return (i as Modifiers.TurnStatusEffectModifier).getStatusEffect() === p.status?.effect; } return false; })).length, 3); @@ -1507,11 +1507,11 @@ const modifierPool: ModifierPool = { return thresholdPartyMemberCount; }, 3), new WeightedModifierType(modifierTypes.ELIXIR, (party: Pokemon[]) => { - const thresholdPartyMemberCount = Math.min(party.filter(p => p.hp && p.getMoveset().filter(m => m.ppUsed && (m.getMovePp() - m.ppUsed) <= 5).length).length, 3); + const thresholdPartyMemberCount = Math.min(party.filter(p => p.hp && p.getMoveset().filter(m => m?.ppUsed && (m.getMovePp() - m.ppUsed) <= 5).length).length, 3); return thresholdPartyMemberCount * 3; }, 9), new WeightedModifierType(modifierTypes.MAX_ELIXIR, (party: Pokemon[]) => { - const thresholdPartyMemberCount = Math.min(party.filter(p => p.hp && p.getMoveset().filter(m => m.ppUsed && (m.getMovePp() - m.ppUsed) <= 5).length).length, 3); + const thresholdPartyMemberCount = Math.min(party.filter(p => p.hp && p.getMoveset().filter(m => m?.ppUsed && (m.getMovePp() - m.ppUsed) <= 5).length).length, 3); return thresholdPartyMemberCount; }, 3), new WeightedModifierType(modifierTypes.DIRE_HIT, 4), @@ -1555,19 +1555,19 @@ const modifierPool: ModifierPool = { const checkedAbilities = [Abilities.QUICK_FEET, Abilities.GUTS, Abilities.MARVEL_SCALE, Abilities.TOXIC_BOOST, Abilities.POISON_HEAL, Abilities.MAGIC_GUARD]; const checkedMoves = [Moves.FACADE, Moves.TRICK, Moves.FLING, Moves.SWITCHEROO, Moves.PSYCHO_SHIFT]; // If a party member doesn't already have one of these two orbs and has one of the above moves or abilities, the orb can appear - return party.some(p => !p.getHeldItems().some(i => i instanceof Modifiers.TurnStatusEffectModifier) && (checkedAbilities.some(a => p.hasAbility(a, false, true)) || p.getMoveset(true).some(m => checkedMoves.includes(m.moveId)))) ? 10 : 0; + return party.some(p => !p.getHeldItems().some(i => i instanceof Modifiers.TurnStatusEffectModifier) && (checkedAbilities.some(a => p.hasAbility(a, false, true)) || p.getMoveset(true).some(m => m && checkedMoves.includes(m.moveId)))) ? 10 : 0; }, 10), new WeightedModifierType(modifierTypes.FLAME_ORB, (party: Pokemon[]) => { const checkedAbilities = [Abilities.QUICK_FEET, Abilities.GUTS, Abilities.MARVEL_SCALE, Abilities.FLARE_BOOST, Abilities.MAGIC_GUARD]; const checkedMoves = [Moves.FACADE, Moves.TRICK, Moves.FLING, Moves.SWITCHEROO, Moves.PSYCHO_SHIFT]; // If a party member doesn't already have one of these two orbs and has one of the above moves or abilities, the orb can appear - return party.some(p => !p.getHeldItems().some(i => i instanceof Modifiers.TurnStatusEffectModifier) && (checkedAbilities.some(a => p.hasAbility(a, false, true)) || p.getMoveset(true).some(m => checkedMoves.includes(m.moveId)))) ? 10 : 0; + return party.some(p => !p.getHeldItems().some(i => i instanceof Modifiers.TurnStatusEffectModifier) && (checkedAbilities.some(a => p.hasAbility(a, false, true)) || p.getMoveset(true).some(m => m && checkedMoves.includes(m.moveId)))) ? 10 : 0; }, 10), new WeightedModifierType(modifierTypes.WHITE_HERB, (party: Pokemon[]) => { const checkedAbilities = [Abilities.WEAK_ARMOR, Abilities.CONTRARY, Abilities.MOODY, Abilities.ANGER_SHELL, Abilities.COMPETITIVE, Abilities.DEFIANT]; const weightMultiplier = party.filter( p => !p.getHeldItems().some(i => i instanceof Modifiers.PokemonResetNegativeStatStageModifier && i.stackCount >= i.getMaxHeldItemCount(p)) && - (checkedAbilities.some(a => p.hasAbility(a, false, true)) || p.getMoveset(true).some(m => selfStatLowerMoves.includes(m.moveId)))).length; + (checkedAbilities.some(a => p.hasAbility(a, false, true)) || p.getMoveset(true).some(m => m && selfStatLowerMoves.includes(m.moveId)))).length; // If a party member has one of the above moves or abilities and doesn't have max herbs, the herb will appear more frequently return 0 * (weightMultiplier ? 2 : 1) + (weightMultiplier ? weightMultiplier * 0 : 0); }, 10), @@ -1722,10 +1722,10 @@ const enemyBuffModifierPool: ModifierPool = { ].map(m => { m.setTier(ModifierTier.ULTRA); return m; }), - [ModifierTier.ROGUE]: [ ].map(m => { + [ModifierTier.ROGUE]: [ ].map((m: WeightedModifierType) => { m.setTier(ModifierTier.ROGUE); return m; }), - [ModifierTier.MASTER]: [ ].map(m => { + [ModifierTier.MASTER]: [ ].map((m: WeightedModifierType) => { m.setTier(ModifierTier.MASTER); return m; }) }; @@ -1770,7 +1770,7 @@ const dailyStarterModifierPool: ModifierPool = { export function getModifierType(modifierTypeFunc: ModifierTypeFunc): ModifierType { const modifierType = modifierTypeFunc(); if (!modifierType.id) { - modifierType.id = Object.keys(modifierTypes).find(k => modifierTypes[k] === modifierTypeFunc); + modifierType.id = Object.keys(modifierTypes).find(k => modifierTypes[k] === modifierTypeFunc)!; // TODO: is this bang correct? } return modifierType; } @@ -1893,12 +1893,14 @@ export function getPlayerModifierTypeOptions(count: integer, party: PlayerPokemo const options: ModifierTypeOption[] = []; const retryCount = Math.min(count * 5, 50); new Array(count).fill(0).map((_, i) => { - let candidate = getNewModifierTypeOption(party, ModifierPoolType.PLAYER, modifierTiers?.length > i ? modifierTiers[i] : undefined); + let candidate = getNewModifierTypeOption(party, ModifierPoolType.PLAYER, modifierTiers && modifierTiers.length > i ? modifierTiers[i] : undefined); let r = 0; - while (options.length && ++r < retryCount && options.filter(o => o.type.name === candidate.type.name || o.type.group === candidate.type.group).length) { - candidate = getNewModifierTypeOption(party, ModifierPoolType.PLAYER, candidate.type.tier, candidate.upgradeCount); + while (options.length && ++r < retryCount && options.filter(o => o.type?.name === candidate?.type?.name || o.type?.group === candidate?.type?.group).length) { + candidate = getNewModifierTypeOption(party, ModifierPoolType.PLAYER, candidate?.type?.tier, candidate?.upgradeCount); + } + if (candidate) { + options.push(candidate); } - options.push(candidate); }); // OVERRIDE IF NECESSARY @@ -1950,21 +1952,21 @@ export function getPlayerShopModifierTypeOptionsForWave(waveIndex: integer, base export function getEnemyBuffModifierForWave(tier: ModifierTier, enemyModifiers: Modifiers.PersistentModifier[], scene: BattleScene): Modifiers.EnemyPersistentModifier { const tierStackCount = tier === ModifierTier.ULTRA ? 5 : tier === ModifierTier.GREAT ? 3 : 1; const retryCount = 50; - let candidate = getNewModifierTypeOption(null, ModifierPoolType.ENEMY_BUFF, tier); + let candidate = getNewModifierTypeOption([], ModifierPoolType.ENEMY_BUFF, tier); let r = 0; - let matchingModifier: Modifiers.PersistentModifier; - while (++r < retryCount && (matchingModifier = enemyModifiers.find(m => m.type.id === candidate.type.id)) && matchingModifier.getMaxStackCount(scene) < matchingModifier.stackCount + (r < 10 ? tierStackCount : 1)) { - candidate = getNewModifierTypeOption(null, ModifierPoolType.ENEMY_BUFF, tier); + let matchingModifier: Modifiers.PersistentModifier | undefined; + while (++r < retryCount && (matchingModifier = enemyModifiers.find(m => m.type.id === candidate?.type?.id)) && matchingModifier.getMaxStackCount(scene) < matchingModifier.stackCount + (r < 10 ? tierStackCount : 1)) { + candidate = getNewModifierTypeOption([], ModifierPoolType.ENEMY_BUFF, tier); } - const modifier = candidate.type.newModifier() as Modifiers.EnemyPersistentModifier; + const modifier = candidate?.type?.newModifier() as Modifiers.EnemyPersistentModifier; modifier.stackCount = tierStackCount; return modifier; } export function getEnemyModifierTypesForWave(waveIndex: integer, count: integer, party: EnemyPokemon[], poolType: ModifierPoolType.WILD | ModifierPoolType.TRAINER, upgradeChance: integer = 0): PokemonHeldItemModifierType[] { - const ret = new Array(count).fill(0).map(() => getNewModifierTypeOption(party, poolType, undefined, upgradeChance && !Utils.randSeedInt(upgradeChance) ? 1 : 0).type as PokemonHeldItemModifierType); + const ret = new Array(count).fill(0).map(() => getNewModifierTypeOption(party, poolType, undefined, upgradeChance && !Utils.randSeedInt(upgradeChance) ? 1 : 0)?.type as PokemonHeldItemModifierType); if (!(waveIndex % 1000)) { ret.push(getModifierType(modifierTypes.MINI_BLACK_HOLE) as PokemonHeldItemModifierType); } @@ -1977,7 +1979,7 @@ export function getDailyRunStarterModifiers(party: PlayerPokemon[]): Modifiers.P for (let m = 0; m < 3; m++) { const tierValue = Utils.randSeedInt(64); const tier = tierValue > 25 ? ModifierTier.COMMON : tierValue > 12 ? ModifierTier.GREAT : tierValue > 4 ? ModifierTier.ULTRA : tierValue ? ModifierTier.ROGUE : ModifierTier.MASTER; - const modifier = getNewModifierTypeOption(party, ModifierPoolType.DAILY_STARTER, tier).type.newModifier(p) as Modifiers.PokemonHeldItemModifier; + const modifier = getNewModifierTypeOption(party, ModifierPoolType.DAILY_STARTER, tier)?.type?.newModifier(p) as Modifiers.PokemonHeldItemModifier; ret.push(modifier); } } @@ -1985,7 +1987,7 @@ export function getDailyRunStarterModifiers(party: PlayerPokemon[]): Modifiers.P return ret; } -function getNewModifierTypeOption(party: Pokemon[], poolType: ModifierPoolType, tier?: ModifierTier, upgradeCount?: integer, retryCount: integer = 0): ModifierTypeOption { +function getNewModifierTypeOption(party: Pokemon[], poolType: ModifierPoolType, tier?: ModifierTier, upgradeCount?: integer, retryCount: integer = 0): ModifierTypeOption | null { const player = !poolType; const pool = getModifierPoolForType(poolType); let thresholds: object; @@ -2052,7 +2054,7 @@ function getNewModifierTypeOption(party: Pokemon[], poolType: ModifierPoolType, const tierThresholds = Object.keys(thresholds[tier]); const totalWeight = parseInt(tierThresholds[tierThresholds.length - 1]); const value = Utils.randSeedInt(totalWeight); - let index: integer; + let index: integer | undefined; for (const t of tierThresholds) { const threshold = parseInt(t); if (value < threshold) { @@ -2068,7 +2070,7 @@ function getNewModifierTypeOption(party: Pokemon[], poolType: ModifierPoolType, if (player) { console.log(index, ignoredPoolIndexes[tier].filter(i => i <= index).length, ignoredPoolIndexes[tier]); } - let modifierType: ModifierType = (pool[tier][index]).modifierType; + let modifierType: ModifierType | null = (pool[tier][index]).modifierType; if (modifierType instanceof ModifierTypeGenerator) { modifierType = (modifierType as ModifierTypeGenerator).generateType(party); if (modifierType === null) { @@ -2081,7 +2083,7 @@ function getNewModifierTypeOption(party: Pokemon[], poolType: ModifierPoolType, console.log(modifierType, !player ? "(enemy)" : ""); - return new ModifierTypeOption(modifierType as ModifierType, upgradeCount); + return new ModifierTypeOption(modifierType as ModifierType, upgradeCount!); // TODO: is this bang correct? } export function getDefaultModifierTypeForTier(tier: ModifierTier): ModifierType { @@ -2093,7 +2095,7 @@ export function getDefaultModifierTypeForTier(tier: ModifierTier): ModifierType } export class ModifierTypeOption { - public type: ModifierType; + public type: ModifierType | null; public upgradeCount: integer; public cost: integer; diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index 91041dc7564..6ff2d3c9718 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -33,16 +33,16 @@ export type ModifierPredicate = (modifier: Modifier) => boolean; const iconOverflowIndex = 24; -export const modifierSortFunc = (a: Modifier, b: Modifier) => { +export const modifierSortFunc = (a: Modifier, b: Modifier): number => { const itemNameMatch = a.type.name.localeCompare(b.type.name); const typeNameMatch = a.constructor.name.localeCompare(b.constructor.name); - const aId = a instanceof PokemonHeldItemModifier ? a.pokemonId : 4294967295; - const bId = b instanceof PokemonHeldItemModifier ? b.pokemonId : 4294967295; + const aId = a instanceof PokemonHeldItemModifier && a.pokemonId ? a.pokemonId : 4294967295; + const bId = b instanceof PokemonHeldItemModifier && b.pokemonId ? b.pokemonId : 4294967295; //First sort by pokemonID if (aId < bId) { return 1; - } else if (aId>bId) { + } else if (aId > bId) { return -1; } else if (aId === bId) { //Then sort by item type @@ -52,6 +52,8 @@ export const modifierSortFunc = (a: Modifier, b: Modifier) => { } else { return typeNameMatch; } + } else { + return 0; } }; @@ -150,7 +152,7 @@ export abstract class PersistentModifier extends Modifier { public stackCount: integer; public virtualStackCount: integer; - constructor(type: ModifierType, stackCount: integer) { + constructor(type: ModifierType, stackCount?: integer) { super(type); this.stackCount = stackCount === undefined ? 1 : stackCount; this.virtualStackCount = 0; @@ -221,7 +223,7 @@ export abstract class PersistentModifier extends Modifier { return container; } - getIconStackText(scene: BattleScene, virtual?: boolean): Phaser.GameObjects.BitmapText { + getIconStackText(scene: BattleScene, virtual?: boolean): Phaser.GameObjects.BitmapText | null { if (this.getMaxStackCount(scene) === 1 || (virtual && !this.virtualStackCount)) { return null; } @@ -295,7 +297,7 @@ export abstract class LapsingPersistentModifier extends PersistentModifier { constructor(type: ModifierTypes.ModifierType, battlesLeft?: integer, stackCount?: integer) { super(type, stackCount); - this.battlesLeft = battlesLeft; + this.battlesLeft = battlesLeft!; // TODO: is this bang correct? } lapse(args: any[]): boolean { @@ -306,7 +308,7 @@ export abstract class LapsingPersistentModifier extends PersistentModifier { const container = super.getIcon(scene); const battleCountText = addTextObject(scene, 27, 0, this.battlesLeft.toString(), TextStyle.PARTY, { fontSize: "66px", color: "#f89890" }); - battleCountText.setShadow(0, 0, null); + battleCountText.setShadow(0, 0); battleCountText.setStroke("#984038", 16); battleCountText.setOrigin(1, 0); container.add(battleCountText); @@ -472,7 +474,7 @@ export abstract class PokemonHeldItemModifier extends PersistentModifier { public pokemonId: integer; readonly isTransferrable: boolean = true; - constructor(type: ModifierType, pokemonId: integer, stackCount: integer) { + constructor(type: ModifierType, pokemonId: integer, stackCount?: integer) { super(type, stackCount); this.pokemonId = pokemonId; @@ -489,11 +491,11 @@ export abstract class PokemonHeldItemModifier extends PersistentModifier { } shouldApply(args: any[]): boolean { - return super.shouldApply(args) && args.length && args[0] instanceof Pokemon && (this.pokemonId === -1 || (args[0] as Pokemon).id === this.pokemonId); + return super.shouldApply(args) && args.length !== 0 && args[0] instanceof Pokemon && (this.pokemonId === -1 || (args[0] as Pokemon).id === this.pokemonId); } isIconVisible(scene: BattleScene): boolean { - return this.getPokemon(scene).isOnField(); + return !!(this.getPokemon(scene)?.isOnField()); } getIcon(scene: BattleScene, forSummary?: boolean): Phaser.GameObjects.Container { @@ -501,9 +503,10 @@ export abstract class PokemonHeldItemModifier extends PersistentModifier { if (!forSummary) { const pokemon = this.getPokemon(scene); - const pokemonIcon = scene.addPokemonIcon(pokemon, -2, 10, 0, 0.5); - - container.add(pokemonIcon); + if (pokemon) { + const pokemonIcon = scene.addPokemonIcon(pokemon, -2, 10, 0, 0.5); + container.add(pokemonIcon); + } const item = scene.add.sprite(16, this.virtualStackCount ? 8 : 16, "items"); item.setScale(0.5); @@ -527,8 +530,8 @@ export abstract class PokemonHeldItemModifier extends PersistentModifier { return container; } - getPokemon(scene: BattleScene): Pokemon { - return scene.getPokemonById(this.pokemonId); + getPokemon(scene: BattleScene): Pokemon | undefined { + return this.pokemonId ? scene.getPokemonById(this.pokemonId) ?? undefined : undefined; } getScoreMultiplier(): number { @@ -562,7 +565,7 @@ export abstract class PokemonHeldItemModifier extends PersistentModifier { return this.getMaxHeldItemCount(pokemon); } - abstract getMaxHeldItemCount(pokemon: Pokemon): integer; + abstract getMaxHeldItemCount(pokemon?: Pokemon): integer; } export abstract class LapsingPokemonHeldItemModifier extends PokemonHeldItemModifier { @@ -572,7 +575,7 @@ export abstract class LapsingPokemonHeldItemModifier extends PokemonHeldItemModi constructor(type: ModifierTypes.ModifierType, pokemonId: integer, battlesLeft?: integer, stackCount?: integer) { super(type, pokemonId, stackCount); - this.battlesLeft = battlesLeft; + this.battlesLeft = battlesLeft!; // TODO: is this bang correct? } lapse(args: any[]): boolean { @@ -582,9 +585,9 @@ export abstract class LapsingPokemonHeldItemModifier extends PokemonHeldItemModi getIcon(scene: BattleScene, forSummary?: boolean): Phaser.GameObjects.Container { const container = super.getIcon(scene, forSummary); - if (this.getPokemon(scene).isPlayer()) { + if (this.getPokemon(scene)?.isPlayer()) { const battleCountText = addTextObject(scene, 27, 0, this.battlesLeft.toString(), TextStyle.PARTY, { fontSize: "66px", color: "#f89890" }); - battleCountText.setShadow(0, 0, null); + battleCountText.setShadow(0, 0); battleCountText.setStroke("#984038", 16); battleCountText.setOrigin(1, 0); container.add(battleCountText); @@ -1442,7 +1445,7 @@ export abstract class ConsumablePokemonModifier extends ConsumableModifier { } shouldApply(args: any[]): boolean { - return args.length && args[0] instanceof PlayerPokemon && (this.pokemonId === -1 || (args[0] as PlayerPokemon).id === this.pokemonId); + return args.length !== 0 && args[0] instanceof PlayerPokemon && (this.pokemonId === -1 || (args[0] as PlayerPokemon).id === this.pokemonId); } getPokemon(scene: BattleScene) { @@ -1519,7 +1522,7 @@ export class PokemonPpRestoreModifier extends ConsumablePokemonMoveModifier { apply(args: any[]): boolean { const pokemon = args[0] as Pokemon; - const move = pokemon.getMoveset()[this.moveIndex]; + const move = pokemon.getMoveset()[this.moveIndex]!; //TODO: is the bang correct? move.ppUsed = this.restorePoints > -1 ? Math.max(move.ppUsed - this.restorePoints, 0) : 0; return true; @@ -1538,7 +1541,7 @@ export class PokemonAllMovePpRestoreModifier extends ConsumablePokemonModifier { apply(args: any[]): boolean { const pokemon = args[0] as Pokemon; for (const move of pokemon.getMoveset()) { - move.ppUsed = this.restorePoints > -1 ? Math.max(move.ppUsed - this.restorePoints, 0) : 0; + move!.ppUsed = this.restorePoints > -1 ? Math.max(move!.ppUsed - this.restorePoints, 0) : 0; // TODO: are those bangs correct? } return true; @@ -1556,7 +1559,7 @@ export class PokemonPpUpModifier extends ConsumablePokemonMoveModifier { apply(args: any[]): boolean { const pokemon = args[0] as Pokemon; - const move = pokemon.getMoveset()[this.moveIndex]; + const move = pokemon.getMoveset()[this.moveIndex]!; // TODO: is the bang correct? move.ppUp = Math.min(move.ppUp + this.upPoints, 3); return true; @@ -1658,7 +1661,7 @@ export class EvolutionItemModifier extends ConsumablePokemonModifier { : null; if (!matchingEvolution && pokemon.isFusion()) { - matchingEvolution = pokemonEvolutions[pokemon.fusionSpecies.speciesId].find(e => e.item === (this.type as ModifierTypes.EvolutionItemModifierType).evolutionItem + matchingEvolution = pokemonEvolutions[pokemon.fusionSpecies!.speciesId].find(e => e.item === (this.type as ModifierTypes.EvolutionItemModifierType).evolutionItem // TODO: is the bang correct? && (e.evoFormKey === null || (e.preFormKey || "") === pokemon.getFusionFormKey()) && (!e.condition || e.condition.predicate(pokemon))); if (matchingEvolution) { @@ -2135,7 +2138,7 @@ export class MoneyInterestModifier extends PersistentModifier { const userLocale = navigator.language || "en-US"; const formattedMoneyAmount = interestAmount.toLocaleString(userLocale); const message = i18next.t("modifier:moneyInterestApply", { moneyAmount: formattedMoneyAmount, typeName: this.type.name }); - scene.queueMessage(message, null, true); + scene.queueMessage(message, undefined, true); return true; } @@ -2290,7 +2293,7 @@ export abstract class HeldItemTransferModifier extends PokemonHeldItemModifier { const transferredModifierTypes: ModifierTypes.ModifierType[] = []; const itemModifiers = pokemon.scene.findModifiers(m => m instanceof PokemonHeldItemModifier && m.pokemonId === targetPokemon.id && m.isTransferrable, targetPokemon.isPlayer()) as PokemonHeldItemModifier[]; - let highestItemTier = itemModifiers.map(m => m.type.getOrInferTier(poolType)).reduce((highestTier, tier) => Math.max(tier, highestTier), 0); + let highestItemTier = itemModifiers.map(m => m.type.getOrInferTier(poolType)).reduce((highestTier, tier) => Math.max(tier!, highestTier), 0); // TODO: is this bang correct? let tierItemModifiers = itemModifiers.filter(m => m.type.getOrInferTier(poolType) === highestItemTier); const heldItemTransferPromises: Promise[] = []; @@ -2782,8 +2785,8 @@ export function overrideHeldItems(scene: BattleScene, pokemon: Pokemon, player: const modifierType: ModifierType = modifierTypes[itemName](); // we retrieve the item in the list let itemModifier: PokemonHeldItemModifier; if (modifierType instanceof ModifierTypes.ModifierTypeGenerator) { - const pregenArgs = "type" in item ? [item.type] : null; - itemModifier = modifierType.generateType(null, pregenArgs).withIdFromFunc(modifierTypes[itemName]).newModifier(pokemon) as PokemonHeldItemModifier; + const pregenArgs = "type" in item ? [item.type] : undefined; + itemModifier = modifierType.generateType([], pregenArgs)?.withIdFromFunc(modifierTypes[itemName]).newModifier(pokemon) as PokemonHeldItemModifier; } else { itemModifier = modifierType.withIdFromFunc(modifierTypes[itemName]).newModifier(pokemon) as PokemonHeldItemModifier; } diff --git a/src/overrides.ts b/src/overrides.ts index 9dd394354aa..88db105475c 100644 --- a/src/overrides.ts +++ b/src/overrides.ts @@ -48,9 +48,9 @@ class DefaultOverrides { readonly BATTLE_TYPE_OVERRIDE: "double" | "single" | null = null; readonly STARTING_WAVE_OVERRIDE: integer = 0; readonly STARTING_BIOME_OVERRIDE: Biome = Biome.TOWN; - readonly ARENA_TINT_OVERRIDE: TimeOfDay = null; + readonly ARENA_TINT_OVERRIDE: TimeOfDay | null = null; /** Multiplies XP gained by this value including 0. Set to null to ignore the override */ - readonly XP_MULTIPLIER_OVERRIDE: number = null; + readonly XP_MULTIPLIER_OVERRIDE: number | null = null; /** default 1000 */ readonly STARTING_MONEY_OVERRIDE: integer = 0; /** Sets all shop item prices to 0 */ @@ -96,7 +96,7 @@ class DefaultOverrides { readonly ABILITY_OVERRIDE: Abilities = Abilities.NONE; readonly PASSIVE_ABILITY_OVERRIDE: Abilities = Abilities.NONE; readonly STATUS_OVERRIDE: StatusEffect = StatusEffect.NONE; - readonly GENDER_OVERRIDE: Gender = null; + readonly GENDER_OVERRIDE: Gender | null = null; readonly MOVESET_OVERRIDE: Array = []; readonly SHINY_OVERRIDE: boolean = false; readonly VARIANT_OVERRIDE: Variant = 0; @@ -109,7 +109,7 @@ class DefaultOverrides { readonly OPP_ABILITY_OVERRIDE: Abilities = Abilities.NONE; readonly OPP_PASSIVE_ABILITY_OVERRIDE: Abilities = Abilities.NONE; readonly OPP_STATUS_OVERRIDE: StatusEffect = StatusEffect.NONE; - readonly OPP_GENDER_OVERRIDE: Gender = null; + readonly OPP_GENDER_OVERRIDE: Gender | null = null; readonly OPP_MOVESET_OVERRIDE: Array = []; readonly OPP_SHINY_OVERRIDE: boolean = false; readonly OPP_VARIANT_OVERRIDE: Variant = 0; @@ -119,9 +119,9 @@ class DefaultOverrides { // EGG OVERRIDES // ------------- readonly EGG_IMMEDIATE_HATCH_OVERRIDE: boolean = false; - readonly EGG_TIER_OVERRIDE: EggTier = null; + readonly EGG_TIER_OVERRIDE: EggTier | null = null; readonly EGG_SHINY_OVERRIDE: boolean = false; - readonly EGG_VARIANT_OVERRIDE: VariantTier = null; + readonly EGG_VARIANT_OVERRIDE: VariantTier | null = null; readonly EGG_FREE_GACHA_PULLS_OVERRIDE: boolean = false; readonly EGG_GACHA_PULL_COUNT_OVERRIDE: number = 0; diff --git a/src/phases.ts b/src/phases.ts index f561ea6f3fc..7397974846f 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -194,7 +194,7 @@ export class TitlePhase extends Phase { this.scene.playBgm("title", true); - this.scene.gameData.getSession(loggedInUser.lastSessionSlot).then(sessionData => { + this.scene.gameData.getSession(loggedInUser!.lastSessionSlot).then(sessionData => { // TODO: is this bang correct? if (sessionData) { this.lastSessionData = sessionData; const biomeKey = getBiomeKey(sessionData.arena.biome); @@ -210,11 +210,11 @@ export class TitlePhase extends Phase { showOptions(): void { const options: OptionSelectItem[] = []; - if (loggedInUser.lastSessionSlot > -1) { + if (loggedInUser && loggedInUser.lastSessionSlot > -1) { options.push({ - label: i18next.t("continue", null, { ns: "menu"}), + label: i18next.t("continue", {ns: "menu"}), handler: () => { - this.loadSaveSlot(this.lastSessionData ? -1 : loggedInUser.lastSessionSlot); + this.loadSaveSlot(this.lastSessionData || !loggedInUser ? -1 : loggedInUser.lastSessionSlot); return true; } }); @@ -318,9 +318,9 @@ export class TitlePhase extends Phase { } loadSaveSlot(slotId: integer): void { - this.scene.sessionSlotId = slotId > -1 ? slotId : loggedInUser.lastSessionSlot; + this.scene.sessionSlotId = slotId > -1 || !loggedInUser ? slotId : loggedInUser.lastSessionSlot; this.scene.ui.setMode(Mode.MESSAGE); - this.scene.gameData.loadSession(this.scene, slotId, slotId === -1 ? this.lastSessionData : null).then((success: boolean) => { + this.scene.gameData.loadSession(this.scene, slotId, slotId === -1 ? this.lastSessionData : undefined).then((success: boolean) => { if (success) { this.loaded = true; this.scene.ui.showText(i18next.t("menu:sessionSuccess"), null, () => this.end()); @@ -370,7 +370,8 @@ export class TitlePhase extends Phase { regenerateModifierPoolThresholds(party, ModifierPoolType.DAILY_STARTER); const modifiers: Modifier[] = Array(3).fill(null).map(() => modifierTypes.EXP_SHARE().withIdFromFunc(modifierTypes.EXP_SHARE).newModifier()) .concat(Array(3).fill(null).map(() => modifierTypes.GOLDEN_EXP_CHARM().withIdFromFunc(modifierTypes.GOLDEN_EXP_CHARM).newModifier())) - .concat(getDailyRunStarterModifiers(party)); + .concat(getDailyRunStarterModifiers(party)) + .filter((m) => m !== null); for (const m of modifiers) { this.scene.addModifier(m, true, false, false, true); @@ -392,7 +393,7 @@ export class TitlePhase extends Phase { // If Online, calls seed fetch from db to generate daily run. If Offline, generates a daily run based on current date. if (!Utils.isLocal) { fetchDailyRunSeed().then(seed => { - generateDaily(seed); + generateDaily(seed!); // TODO: is this bang correct? }).catch(err => { console.error("Failed to load daily run:\n", err); }); @@ -461,12 +462,12 @@ export class UnavailablePhase extends Phase { } export class ReloadSessionPhase extends Phase { - private systemDataStr: string; + private systemDataStr: string | null; constructor(scene: BattleScene, systemDataStr?: string) { super(scene); - this.systemDataStr = systemDataStr; + this.systemDataStr = systemDataStr!; // TODO: is this bang correct? } start(): void { @@ -599,9 +600,9 @@ export class SelectStarterPhase extends Phase { let starterFormIndex = Math.min(starterProps.formIndex, Math.max(starter.species.forms.length - 1, 0)); if ( starter.species.speciesId in Overrides.STARTER_FORM_OVERRIDES && - starter.species.forms[Overrides.STARTER_FORM_OVERRIDES[starter.species.speciesId]] + starter.species.forms[Overrides.STARTER_FORM_OVERRIDES[starter.species.speciesId]!] ) { - starterFormIndex = Overrides.STARTER_FORM_OVERRIDES[starter.species.speciesId]; + starterFormIndex = Overrides.STARTER_FORM_OVERRIDES[starter.species.speciesId]!; } let starterGender = starter.species.malePercent !== null @@ -612,7 +613,7 @@ export class SelectStarterPhase extends Phase { } const starterIvs = this.scene.gameData.dexData[starter.species.speciesId].ivs.slice(0); const starterPokemon = this.scene.addPlayerPokemon(starter.species, this.scene.gameMode.getStartingLevel(), starter.abilityIndex, starterFormIndex, starterGender, starterProps.shiny, starterProps.variant, starterIvs, starter.nature); - starterPokemon.tryPopulateMoveset(starter.moveset); + starter.moveset && starterPokemon.tryPopulateMoveset(starter.moveset); if (starter.passive) { starterPokemon.passive = true; } @@ -657,8 +658,8 @@ export class BattlePhase extends Phase { } showEnemyTrainer(trainerSlot: TrainerSlot = TrainerSlot.NONE): void { - const sprites = this.scene.currentBattle.trainer.getSprites(); - const tintSprites = this.scene.currentBattle.trainer.getTintSprites(); + const sprites = this.scene.currentBattle.trainer?.getSprites()!; // TODO: is this bang correct? + const tintSprites = this.scene.currentBattle.trainer?.getTintSprites()!; // TODO: is this bang correct? for (let i = 0; i < sprites.length; i++) { const visible = !trainerSlot || !i === (trainerSlot === TrainerSlot.TRAINER) || sprites.length < 2; [sprites[i], tintSprites[i]].map(sprite => { @@ -738,11 +739,11 @@ export abstract class PokemonPhase extends FieldPhase { public player: boolean; public fieldIndex: integer; - constructor(scene: BattleScene, battlerIndex: BattlerIndex | integer) { + constructor(scene: BattleScene, battlerIndex?: BattlerIndex | integer) { super(scene); if (battlerIndex === undefined) { - battlerIndex = scene.getField().find(p => p?.isActive()).getBattlerIndex(); + battlerIndex = scene.getField().find(p => p?.isActive())!.getBattlerIndex(); // TODO: is the bang correct here? } this.battlerIndex = battlerIndex; @@ -750,11 +751,11 @@ export abstract class PokemonPhase extends FieldPhase { this.fieldIndex = battlerIndex % 2; } - getPokemon() { + getPokemon(): Pokemon { if (this.battlerIndex > BattlerIndex.ENEMY_2) { - return this.scene.getPokemonById(this.battlerIndex); + return this.scene.getPokemonById(this.battlerIndex)!; //TODO: is this bang correct? } - return this.scene.getField()[this.battlerIndex]; + return this.scene.getField()[this.battlerIndex]!; //TODO: is this bang correct? } } @@ -825,16 +826,16 @@ export class EncounterPhase extends BattlePhase { this.scene.unshiftPhase(new GameOverPhase(this.scene)); } - const loadEnemyAssets = []; + const loadEnemyAssets: Promise[] = []; const battle = this.scene.currentBattle; let totalBst = 0; - battle.enemyLevels.forEach((level, e) => { + battle.enemyLevels?.forEach((level, e) => { if (!this.loaded) { if (battle.battleType === BattleType.TRAINER) { - battle.enemyParty[e] = battle.trainer.genPartyMember(e); + battle.enemyParty[e] = battle.trainer?.genPartyMember(e)!; // TODO:: is the bang correct here? } else { const enemySpecies = this.scene.randomSpecies(battle.waveIndex, level, true); battle.enemyParty[e] = this.scene.addEnemyPokemon(enemySpecies, level, TrainerSlot.NONE, !!this.scene.getEncounterBossSegments(battle.waveIndex, level, enemySpecies)); @@ -881,7 +882,7 @@ export class EncounterPhase extends BattlePhase { } if (battle.battleType === BattleType.TRAINER) { - loadEnemyAssets.push(battle.trainer.loadAssets().then(() => battle.trainer.initSprite())); + loadEnemyAssets.push(battle.trainer?.loadAssets().then(() => battle.trainer?.initSprite())!); // TODO: is this bang correct? } else { // This block only applies for double battles to init the boss segments (idk why it's split up like this) if (battle.enemyParty.filter(p => p.isBoss()).length > 1) { @@ -908,7 +909,7 @@ export class EncounterPhase extends BattlePhase { enemyPokemon.tint(0, 0.5); } else if (battle.battleType === BattleType.TRAINER) { enemyPokemon.setVisible(false); - this.scene.currentBattle.trainer.tint(0, 0.5); + this.scene.currentBattle.trainer?.tint(0, 0.5); } if (battle.double) { enemyPokemon.setFieldPosition(e ? FieldPosition.RIGHT : FieldPosition.LEFT); @@ -923,7 +924,8 @@ export class EncounterPhase extends BattlePhase { this.scene.ui.setMode(Mode.MESSAGE).then(() => { if (!this.loaded) { - this.scene.gameData.saveAll(this.scene, true, battle.waveIndex % 10 === 1 || this.scene.lastSavePlayTime >= 300).then(success => { + //@ts-ignore + this.scene.gameData.saveAll(this.scene, true, battle.waveIndex % 10 === 1 || this.scene.lastSavePlayTime >= 300).then(success => { // TODO: get rid of ts-ignore this.scene.disableMenu = false; if (!success) { return this.scene.reset(true); @@ -980,10 +982,10 @@ export class EncounterPhase extends BattlePhase { if (this.scene.currentBattle.battleType === BattleType.TRAINER) { if (this.scene.currentBattle.double) { - return i18next.t("battle:trainerAppearedDouble", { trainerName: this.scene.currentBattle.trainer.getName(TrainerSlot.NONE, true) }); + return i18next.t("battle:trainerAppearedDouble", { trainerName: this.scene.currentBattle.trainer?.getName(TrainerSlot.NONE, true) }); } else { - return i18next.t("battle:trainerAppeared", { trainerName: this.scene.currentBattle.trainer.getName(TrainerSlot.NONE, true) }); + return i18next.t("battle:trainerAppeared", { trainerName: this.scene.currentBattle.trainer?.getName(TrainerSlot.NONE, true) }); } } @@ -1012,8 +1014,8 @@ export class EncounterPhase extends BattlePhase { } } else if (this.scene.currentBattle.battleType === BattleType.TRAINER) { const trainer = this.scene.currentBattle.trainer; - trainer.untint(100, "Sine.easeOut"); - trainer.playAnim(); + trainer?.untint(100, "Sine.easeOut"); + trainer?.playAnim(); const doSummon = () => { this.scene.currentBattle.started = true; @@ -1036,21 +1038,21 @@ export class EncounterPhase extends BattlePhase { } }; - const encounterMessages = this.scene.currentBattle.trainer.getEncounterMessages(); + const encounterMessages = this.scene.currentBattle.trainer?.getEncounterMessages(); if (!encounterMessages?.length) { doSummon(); } else { let message: string; this.scene.executeWithSeedOffset(() => message = Utils.randSeedItem(encounterMessages), this.scene.currentBattle.waveIndex); - + message = message!; // tell TS compiler it's defined now const showDialogueAndSummon = () => { - this.scene.ui.showDialogue(message, trainer.getName(TrainerSlot.NONE, true), null, () => { + this.scene.ui.showDialogue(message, trainer?.getName(TrainerSlot.NONE, true), null, () => { this.scene.charSprite.hide().then(() => this.scene.hideFieldOverlay(250).then(() => doSummon())); }); }; - if (this.scene.currentBattle.trainer.config.hasCharSprite && !this.scene.ui.shouldSkipDialogue(message)) { - this.scene.showFieldOverlay(500).then(() => this.scene.charSprite.showCharacter(trainer.getKey(), getCharVariantFromDialogue(encounterMessages[0])).then(() => showDialogueAndSummon())); + if (this.scene.currentBattle.trainer?.config.hasCharSprite && !this.scene.ui.shouldSkipDialogue(message)) { + this.scene.showFieldOverlay(500).then(() => this.scene.charSprite.showCharacter(trainer?.getKey()!, getCharVariantFromDialogue(encounterMessages[0])).then(() => showDialogueAndSummon())); // TODO: is this bang correct? } else { showDialogueAndSummon(); } @@ -1128,7 +1130,7 @@ export class EncounterPhase extends BattlePhase { case BattleSpec.FINAL_BOSS: const enemy = this.scene.getEnemyPokemon(); this.scene.ui.showText(this.getEncounterMessage(), null, () => { - this.scene.ui.showDialogue(battleSpecDialogue[BattleSpec.FINAL_BOSS].encounter, enemy.species.name, null, () => { + this.scene.ui.showDialogue(battleSpecDialogue[BattleSpec.FINAL_BOSS].encounter, enemy?.species.name, null, () => { this.doEncounterCommon(false); }); }, 1500, true); @@ -1261,14 +1263,14 @@ export class SelectBiomePhase extends BattlePhase { } else if (this.scene.gameMode.hasRandomBiomes) { setNextBiome(this.generateNextBiome()); } else if (Array.isArray(biomeLinks[currentBiome])) { - let biomes: Biome[]; + let biomes: Biome[] = []; this.scene.executeWithSeedOffset(() => { biomes = (biomeLinks[currentBiome] as (Biome | [Biome, integer])[]) .filter(b => !Array.isArray(b) || !Utils.randSeedInt(b[1])) .map(b => !Array.isArray(b) ? b : b[0]); }, this.scene.currentBattle.waveIndex); if (biomes.length > 1 && this.scene.findModifier(m => m instanceof MapModifier)) { - let biomeChoices: Biome[]; + let biomeChoices: Biome[] = []; this.scene.executeWithSeedOffset(() => { biomeChoices = (!Array.isArray(biomeLinks[currentBiome]) ? [biomeLinks[currentBiome] as Biome] @@ -1437,7 +1439,7 @@ export class SummonPhase extends PartyMemberPokemonPhase { }); this.scene.time.delayedCall(750, () => this.summon()); } else { - const trainerName = this.scene.currentBattle.trainer.getName(!(this.fieldIndex % 2) ? TrainerSlot.TRAINER : TrainerSlot.TRAINER_PARTNER); + const trainerName = this.scene.currentBattle.trainer?.getName(!(this.fieldIndex % 2) ? TrainerSlot.TRAINER : TrainerSlot.TRAINER_PARTNER); const pokemonName = this.getPokemon().getNameToRender(); const message = i18next.t("battle:trainerSendOut", { trainerName, pokemonName }); @@ -1581,7 +1583,8 @@ export class SwitchSummonPhase extends SummonPhase { preSummon(): void { if (!this.player) { if (this.slotIndex === -1) { - this.slotIndex = this.scene.currentBattle.trainer.getNextSummonIndex(!this.fieldIndex ? TrainerSlot.TRAINER : TrainerSlot.TRAINER_PARTNER); + //@ts-ignore + this.slotIndex = this.scene.currentBattle.trainer?.getNextSummonIndex(!this.fieldIndex ? TrainerSlot.TRAINER : TrainerSlot.TRAINER_PARTNER); // TODO: what would be the default trainer-slot fallback? } if (this.slotIndex > -1) { this.showEnemyTrainer(!(this.fieldIndex % 2) ? TrainerSlot.TRAINER : TrainerSlot.TRAINER_PARTNER); @@ -1607,7 +1610,7 @@ export class SwitchSummonPhase extends SummonPhase { this.scene.ui.showText(this.player ? i18next.t("battle:playerComeBack", { pokemonName: getPokemonNameWithAffix(pokemon) }) : i18next.t("battle:trainerComeBack", { - trainerName: this.scene.currentBattle.trainer.getName(!(this.fieldIndex % 2) ? TrainerSlot.TRAINER : TrainerSlot.TRAINER_PARTNER), + trainerName: this.scene.currentBattle.trainer?.getName(!(this.fieldIndex % 2) ? TrainerSlot.TRAINER : TrainerSlot.TRAINER_PARTNER), pokemonName: getPokemonNameWithAffix(pokemon) }) ); @@ -1650,7 +1653,7 @@ export class SwitchSummonPhase extends SummonPhase { this.scene.ui.showText(this.player ? i18next.t("battle:playerGo", { pokemonName: getPokemonNameWithAffix(switchedInPokemon) }) : i18next.t("battle:trainerGo", { - trainerName: this.scene.currentBattle.trainer.getName(!(this.fieldIndex % 2) ? TrainerSlot.TRAINER : TrainerSlot.TRAINER_PARTNER), + trainerName: this.scene.currentBattle.trainer?.getName(!(this.fieldIndex % 2) ? TrainerSlot.TRAINER : TrainerSlot.TRAINER_PARTNER), pokemonName: this.getPokemon().getNameToRender() }) ); @@ -1929,8 +1932,8 @@ export class CommandPhase extends FieldPhase { this.fieldIndex = FieldPosition.CENTER; } else { const allyCommand = this.scene.currentBattle.turnCommands[this.fieldIndex - 1]; - if (allyCommand.command === Command.BALL || allyCommand.command === Command.RUN) { - this.scene.currentBattle.turnCommands[this.fieldIndex] = { command: allyCommand.command, skip: true }; + if (allyCommand?.command === Command.BALL || allyCommand?.command === Command.RUN) { + this.scene.currentBattle.turnCommands[this.fieldIndex] = { command: allyCommand?.command, skip: true }; } } } @@ -1944,8 +1947,8 @@ export class CommandPhase extends FieldPhase { const moveQueue = playerPokemon.getMoveQueue(); while (moveQueue.length && moveQueue[0] - && moveQueue[0].move && (!playerPokemon.getMoveset().find(m => m.moveId === moveQueue[0].move) - || !playerPokemon.getMoveset()[playerPokemon.getMoveset().findIndex(m => m.moveId === moveQueue[0].move)].isUsable(playerPokemon, moveQueue[0].ignorePP))) { + && moveQueue[0].move && (!playerPokemon.getMoveset().find(m => m?.moveId === moveQueue[0].move) + || !playerPokemon.getMoveset()[playerPokemon.getMoveset().findIndex(m => m?.moveId === moveQueue[0].move)]!.isUsable(playerPokemon, moveQueue[0].ignorePP))) { // TODO: is the bang correct? moveQueue.shift(); } @@ -1954,8 +1957,8 @@ export class CommandPhase extends FieldPhase { if (!queuedMove.move) { this.handleCommand(Command.FIGHT, -1, false); } else { - const moveIndex = playerPokemon.getMoveset().findIndex(m => m.moveId === queuedMove.move); - if (moveIndex > -1 && playerPokemon.getMoveset()[moveIndex].isUsable(playerPokemon, queuedMove.ignorePP)) { + const moveIndex = playerPokemon.getMoveset().findIndex(m => m?.moveId === queuedMove.move); + if (moveIndex > -1 && playerPokemon.getMoveset()[moveIndex]!.isUsable(playerPokemon, queuedMove.ignorePP)) { // TODO: is the bang correct? this.handleCommand(Command.FIGHT, moveIndex, queuedMove.ignorePP, { targets: queuedMove.targets, multiple: queuedMove.targets.length > 1 }); } else { this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); @@ -1976,8 +1979,8 @@ export class CommandPhase extends FieldPhase { let useStruggle = false; if (cursor === -1 || playerPokemon.trySelectMove(cursor, args[0] as boolean) || - (useStruggle = cursor > -1 && !playerPokemon.getMoveset().filter(m => m.isUsable(playerPokemon)).length)) { - const moveId = !useStruggle ? cursor > -1 ? playerPokemon.getMoveset()[cursor].moveId : Moves.NONE : Moves.STRUGGLE; + (useStruggle = cursor > -1 && !playerPokemon.getMoveset().filter(m => m?.isUsable(playerPokemon)).length)) { + const moveId = !useStruggle ? cursor > -1 ? playerPokemon.getMoveset()[cursor]!.moveId : Moves.NONE : Moves.STRUGGLE; // TODO: is the bang correct? const turnCommand: TurnCommand = { command: Command.FIGHT, cursor: cursor, move: { move: moveId, targets: [], ignorePP: args[0] }, args: args }; const moveTargets: MoveTargetSet = args.length < 3 ? getMoveTargets(playerPokemon, moveId) : args[2]; if (!moveId) { @@ -1988,16 +1991,16 @@ export class CommandPhase extends FieldPhase { this.scene.unshiftPhase(new SelectTargetPhase(this.scene, this.fieldIndex)); } if (moveTargets.targets.length <= 1 || moveTargets.multiple) { - turnCommand.move.targets = moveTargets.targets; + turnCommand.move!.targets = moveTargets.targets; //TODO: is the bang correct here? } else if (playerPokemon.getTag(BattlerTagType.CHARGING) && playerPokemon.getMoveQueue().length >= 1) { - turnCommand.move.targets = playerPokemon.getMoveQueue()[0].targets; + turnCommand.move!.targets = playerPokemon.getMoveQueue()[0].targets; //TODO: is the bang correct here? } else { this.scene.unshiftPhase(new SelectTargetPhase(this.scene, this.fieldIndex)); } this.scene.currentBattle.turnCommands[this.fieldIndex] = turnCommand; success = true; } else if (cursor < playerPokemon.getMoveset().length) { - const move = playerPokemon.getMoveset()[cursor]; + const move = playerPokemon.getMoveset()[cursor]!; //TODO: is this bang correct? this.scene.ui.setMode(Mode.MESSAGE); // Decides between a Disabled, Not Implemented, or No PP translation message @@ -2017,14 +2020,14 @@ export class CommandPhase extends FieldPhase { this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); this.scene.ui.setMode(Mode.MESSAGE); this.scene.ui.showText(i18next.t("battle:noPokeballForce"), null, () => { - this.scene.ui.showText(null, 0); + this.scene.ui.showText("", 0); this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); }, null, true); } else if (this.scene.currentBattle.battleType === BattleType.TRAINER) { this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); this.scene.ui.setMode(Mode.MESSAGE); this.scene.ui.showText(i18next.t("battle:noPokeballTrainer"), null, () => { - this.scene.ui.showText(null, 0); + this.scene.ui.showText("", 0); this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); }, null, true); } else { @@ -2033,23 +2036,23 @@ export class CommandPhase extends FieldPhase { this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); this.scene.ui.setMode(Mode.MESSAGE); this.scene.ui.showText(i18next.t("battle:noPokeballMulti"), null, () => { - this.scene.ui.showText(null, 0); + this.scene.ui.showText("", 0); this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); }, null, true); } else if (cursor < 5) { const targetPokemon = this.scene.getEnemyField().find(p => p.isActive(true)); - if (targetPokemon.isBoss() && targetPokemon.bossSegmentIndex >= 1 && !targetPokemon.hasAbility(Abilities.WONDER_GUARD, false, true) && cursor < PokeballType.MASTER_BALL) { + if (targetPokemon?.isBoss() && targetPokemon?.bossSegmentIndex >= 1 && !targetPokemon?.hasAbility(Abilities.WONDER_GUARD, false, true) && cursor < PokeballType.MASTER_BALL) { this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); this.scene.ui.setMode(Mode.MESSAGE); this.scene.ui.showText(i18next.t("battle:noPokeballStrong"), null, () => { - this.scene.ui.showText(null, 0); + this.scene.ui.showText("", 0); this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); }, null, true); } else { this.scene.currentBattle.turnCommands[this.fieldIndex] = { command: Command.BALL, cursor: cursor }; - this.scene.currentBattle.turnCommands[this.fieldIndex].targets = targets; + this.scene.currentBattle.turnCommands[this.fieldIndex]!.targets = targets; if (this.fieldIndex) { - this.scene.currentBattle.turnCommands[this.fieldIndex - 1].skip = true; + this.scene.currentBattle.turnCommands[this.fieldIndex - 1]!.skip = true; } success = true; } @@ -2063,14 +2066,14 @@ export class CommandPhase extends FieldPhase { this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); this.scene.ui.setMode(Mode.MESSAGE); this.scene.ui.showText(i18next.t("battle:noEscapeForce"), null, () => { - this.scene.ui.showText(null, 0); + this.scene.ui.showText("", 0); this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); }, null, true); } else if (!isSwitch && this.scene.currentBattle.battleType === BattleType.TRAINER) { this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); this.scene.ui.setMode(Mode.MESSAGE); this.scene.ui.showText(i18next.t("battle:noEscapeTrainer"), null, () => { - this.scene.ui.showText(null, 0); + this.scene.ui.showText("", 0); this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); }, null, true); } else { @@ -2086,10 +2089,10 @@ export class CommandPhase extends FieldPhase { : { command: Command.RUN }; success = true; if (!isSwitch && this.fieldIndex) { - this.scene.currentBattle.turnCommands[this.fieldIndex - 1].skip = true; + this.scene.currentBattle.turnCommands[this.fieldIndex - 1]!.skip = true; } } else if (trapTag) { - if (trapTag.sourceMove === Moves.INGRAIN && this.scene.getPokemonById(trapTag.sourceId).isOfType(Type.GHOST)) { + if (trapTag.sourceMove === Moves.INGRAIN && trapTag.sourceId && this.scene.getPokemonById(trapTag.sourceId)?.isOfType(Type.GHOST)) { success = true; this.scene.currentBattle.turnCommands[this.fieldIndex] = isSwitch ? { command: Command.POKEMON, cursor: cursor, args: args } @@ -2102,13 +2105,13 @@ export class CommandPhase extends FieldPhase { } this.scene.ui.showText( i18next.t("battle:noEscapePokemon", { - pokemonName: getPokemonNameWithAffix(this.scene.getPokemonById(trapTag.sourceId)), + pokemonName: trapTag.sourceId && this.scene.getPokemonById(trapTag.sourceId) ? getPokemonNameWithAffix(this.scene.getPokemonById(trapTag.sourceId)!) : "", moveName: trapTag.getMoveName(), escapeVerb: isSwitch ? i18next.t("battle:escapeVerbSwitch") : i18next.t("battle:escapeVerbFlee") }), null, () => { - this.scene.ui.showText(null, 0); + this.scene.ui.showText("", 0); if (!isSwitch) { this.scene.ui.setMode(Mode.COMMAND, this.fieldIndex); } @@ -2118,11 +2121,11 @@ export class CommandPhase extends FieldPhase { break; } - if (success) { + if (success!) { // TODO: is the bang correct? this.end(); } - return success; + return success!; // TODO: is the bang correct? } cancel() { @@ -2142,9 +2145,9 @@ export class CommandPhase extends FieldPhase { return false; } - const moveIndex = pokemon.getMoveset().findIndex(m => m.moveId === encoreTag.moveId); + const moveIndex = pokemon.getMoveset().findIndex(m => m?.moveId === encoreTag.moveId); - if (moveIndex === -1 || !pokemon.getMoveset()[moveIndex].isUsable(pokemon)) { + if (moveIndex === -1 || !pokemon.getMoveset()[moveIndex]!.isUsable(pokemon)) { // TODO: is this bang correct? return false; } @@ -2254,17 +2257,17 @@ export class SelectTargetPhase extends PokemonPhase { super.start(); const turnCommand = this.scene.currentBattle.turnCommands[this.fieldIndex]; - const move = turnCommand.move?.move; + const move = turnCommand?.move?.move; this.scene.ui.setMode(Mode.TARGET_SELECT, this.fieldIndex, move, (targets: BattlerIndex[]) => { this.scene.ui.setMode(Mode.MESSAGE); if (targets.length < 1) { this.scene.currentBattle.turnCommands[this.fieldIndex] = null; this.scene.unshiftPhase(new CommandPhase(this.scene, this.fieldIndex)); } else { - turnCommand.targets = targets; + turnCommand!.targets = targets; //TODO: is the bang correct here? } - if (turnCommand.command === Command.BALL && this.fieldIndex) { - this.scene.currentBattle.turnCommands[this.fieldIndex - 1].skip = true; + if (turnCommand?.command === Command.BALL && this.fieldIndex) { + this.scene.currentBattle.turnCommands[this.fieldIndex - 1]!.skip = true; //TODO: is the bang correct here? } this.end(); }); @@ -2297,24 +2300,24 @@ export class TurnStartPhase extends FieldPhase { const aCommand = this.scene.currentBattle.turnCommands[a]; const bCommand = this.scene.currentBattle.turnCommands[b]; - if (aCommand.command !== bCommand.command) { - if (aCommand.command === Command.FIGHT) { + if (aCommand?.command !== bCommand?.command) { + if (aCommand?.command === Command.FIGHT) { return 1; - } else if (bCommand.command === Command.FIGHT) { + } else if (bCommand?.command === Command.FIGHT) { return -1; } - } else if (aCommand.command === Command.FIGHT) { - const aMove = allMoves[aCommand.move.move]; - const bMove = allMoves[bCommand.move.move]; + } else if (aCommand?.command === Command.FIGHT) { + const aMove = allMoves[aCommand.move!.move];//TODO: is the bang correct here? + const bMove = allMoves[bCommand!.move!.move];//TODO: is the bang correct here? const aPriority = new Utils.IntegerHolder(aMove.priority); const bPriority = new Utils.IntegerHolder(bMove.priority); - applyMoveAttrs(IncrementMovePriorityAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === a), null, aMove, aPriority); - applyMoveAttrs(IncrementMovePriorityAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === b), null, bMove, bPriority); + applyMoveAttrs(IncrementMovePriorityAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === a)!, null, aMove, aPriority); //TODO: is the bang correct here? + applyMoveAttrs(IncrementMovePriorityAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === b)!, null, bMove, bPriority); //TODO: is the bang correct here? - applyAbAttrs(IncrementMovePriorityAbAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === a), null, aMove, aPriority); - applyAbAttrs(IncrementMovePriorityAbAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === b), null, bMove, bPriority); + applyAbAttrs(IncrementMovePriorityAbAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === a)!, null, aMove, aPriority); //TODO: is the bang correct here? + applyAbAttrs(IncrementMovePriorityAbAttr, this.scene.getField().find(p => p?.isActive() && p.getBattlerIndex() === b)!, null, bMove, bPriority); //TODO: is the bang correct here? if (aPriority.value !== bPriority.value) { return aPriority.value < bPriority.value ? 1 : -1; @@ -2338,34 +2341,34 @@ export class TurnStartPhase extends FieldPhase { const pokemon = field[o]; const turnCommand = this.scene.currentBattle.turnCommands[o]; - if (turnCommand.skip) { + if (turnCommand?.skip) { continue; } - switch (turnCommand.command) { + switch (turnCommand?.command) { case Command.FIGHT: const queuedMove = turnCommand.move; pokemon.turnData.order = orderIndex++; if (!queuedMove) { continue; } - const move = pokemon.getMoveset().find(m => m.moveId === queuedMove.move) || new PokemonMove(queuedMove.move); + const move = pokemon.getMoveset().find(m => m?.moveId === queuedMove.move) || new PokemonMove(queuedMove.move); if (pokemon.isPlayer()) { if (turnCommand.cursor === -1) { - this.scene.pushPhase(new MovePhase(this.scene, pokemon, turnCommand.targets || turnCommand.move.targets, move)); + this.scene.pushPhase(new MovePhase(this.scene, pokemon, turnCommand.targets || turnCommand.move!.targets, move));//TODO: is the bang correct here? } else { - const playerPhase = new MovePhase(this.scene, pokemon, turnCommand.targets || turnCommand.move.targets, move, false, queuedMove.ignorePP); + const playerPhase = new MovePhase(this.scene, pokemon, turnCommand.targets || turnCommand.move!.targets, move, false, queuedMove.ignorePP);//TODO: is the bang correct here? this.scene.pushPhase(playerPhase); } } else { - this.scene.pushPhase(new MovePhase(this.scene, pokemon, turnCommand.targets || turnCommand.move.targets, move, false, queuedMove.ignorePP)); + this.scene.pushPhase(new MovePhase(this.scene, pokemon, turnCommand.targets || turnCommand.move!.targets, move, false, queuedMove.ignorePP));//TODO: is the bang correct here? } break; case Command.BALL: - this.scene.unshiftPhase(new AttemptCapturePhase(this.scene, turnCommand.targets[0] % 2, turnCommand.cursor)); + this.scene.unshiftPhase(new AttemptCapturePhase(this.scene, turnCommand.targets![0] % 2, turnCommand.cursor!));//TODO: is the bang correct here? break; case Command.POKEMON: - this.scene.unshiftPhase(new SwitchSummonPhase(this.scene, pokemon.getFieldIndex(), turnCommand.cursor, true, turnCommand.args[0] as boolean, pokemon.isPlayer())); + this.scene.unshiftPhase(new SwitchSummonPhase(this.scene, pokemon.getFieldIndex(), turnCommand.cursor!, true, turnCommand.args![0] as boolean, pokemon.isPlayer()));//TODO: is the bang correct here? break; case Command.RUN: let runningPokemon = pokemon; @@ -2573,13 +2576,13 @@ export class NewBattlePhase extends BattlePhase { } export class CommonAnimPhase extends PokemonPhase { - private anim: CommonAnim; - private targetIndex: integer; + private anim: CommonAnim | null; + private targetIndex: integer | undefined; - constructor(scene: BattleScene, battlerIndex: BattlerIndex, targetIndex: BattlerIndex, anim: CommonAnim) { + constructor(scene: BattleScene, battlerIndex?: BattlerIndex, targetIndex?: BattlerIndex | undefined, anim?: CommonAnim) { super(scene, battlerIndex); - this.anim = anim; + this.anim = anim!; // TODO: is this bang correct? this.targetIndex = targetIndex; } @@ -2651,8 +2654,8 @@ export class MovePhase extends BattlePhase { this.scene.arena.setIgnoreAbilities(); } } else { - this.pokemon.turnData.hitsLeft = undefined; - this.pokemon.turnData.hitCount = undefined; + this.pokemon.turnData.hitsLeft = 0; // TODO: is `0` correct? + this.pokemon.turnData.hitCount = 0; // TODO: is `0` correct? } // Move redirection abilities (ie. Storm Drain) only support single target moves @@ -2690,7 +2693,8 @@ export class MovePhase extends BattlePhase { if (this.scene.currentBattle.double && this.move.getMove().hasFlag(MoveFlags.REDIRECT_COUNTER)) { if (this.scene.getField()[this.targets[0]].hp === 0) { const opposingField = this.pokemon.isPlayer() ? this.scene.getEnemyField() : this.scene.getPlayerField(); - this.targets[0] = opposingField.find(p => p.hp > 0)?.getBattlerIndex(); + //@ts-ignore + this.targets[0] = opposingField.find(p => p.hp > 0)?.getBattlerIndex(); //TODO: fix ts-ignore } } } @@ -2764,7 +2768,7 @@ export class MovePhase extends BattlePhase { return this.end(); } - if (!moveQueue.length || !moveQueue.shift().ignorePP) { // using .shift here clears out two turn moves once they've been used + if (!moveQueue.length || !moveQueue.shift()?.ignorePP) { // using .shift here clears out two turn moves once they've been used this.move.usePp(ppUsed); this.scene.eventTarget.dispatchEvent(new MoveUsedEvent(this.pokemon?.id, this.move.getMove(), this.move.ppUsed)); } @@ -2782,7 +2786,7 @@ export class MovePhase extends BattlePhase { } else if (success && this.scene.arena.isMoveTerrainCancelled(this.pokemon, this.targets, this.move.getMove())) { success = false; if (failedText === null) { - failedText = getTerrainBlockMessage(targets[0], this.scene.arena.terrain.terrainType); + failedText = getTerrainBlockMessage(targets[0], this.scene.arena.terrain?.terrainType!); // TODO: is this bang correct? } } @@ -2882,10 +2886,10 @@ export class MovePhase extends BattlePhase { pokemonNameWithAffix: getPokemonNameWithAffix(this.pokemon), moveName: this.move.getName() }), 500); - applyMoveAttrs(PreMoveMessageAttr, this.pokemon, this.pokemon.getOpponents().find(() => true), this.move.getMove()); + applyMoveAttrs(PreMoveMessageAttr, this.pokemon, this.pokemon.getOpponents().find(() => true)!, this.move.getMove()); //TODO: is the bang correct here? } - showFailedText(failedText: string = null): void { + showFailedText(failedText: string | null = null): void { this.scene.queueMessage(failedText || i18next.t("battle:attackFailed")); } @@ -2929,7 +2933,7 @@ export class MoveEffectPhase extends PokemonPhase { const move = this.move.getMove(); // Assume single target for override - applyMoveAttrs(OverrideMoveEffectAttr, user, this.getTarget(), move, overridden, this.move.virtual).then(() => { + applyMoveAttrs(OverrideMoveEffectAttr, user, this.getTarget() ?? null, move, overridden, this.move.virtual).then(() => { if (overridden.value) { return this.end(); @@ -2940,7 +2944,7 @@ export class MoveEffectPhase extends PokemonPhase { if (user.turnData.hitsLeft === undefined) { const hitCount = new Utils.IntegerHolder(1); // Assume single target for multi hit - applyMoveAttrs(MultiHitAttr, user, this.getTarget(), move, hitCount); + applyMoveAttrs(MultiHitAttr, user, this.getTarget() ?? null, move, hitCount); applyPreAttackAbAttrs(AddSecondStrikeAbAttr, user, null, move, targets.length, hitCount, new Utils.IntegerHolder(0)); if (move instanceof AttackMove && !move.hasAttr(FixedDamageAttr)) { this.scene.applyModifiers(PokemonMultiHitModifier, user.isPlayer(), user, hitCount, new Utils.IntegerHolder(0)); @@ -2951,11 +2955,11 @@ export class MoveEffectPhase extends PokemonPhase { const moveHistoryEntry = { move: this.move.moveId, targets: this.targets, result: MoveResult.PENDING, virtual: this.move.virtual }; const targetHitChecks = Object.fromEntries(targets.map(p => [p.getBattlerIndex(), this.hitCheck(p)])); - const activeTargets = targets.map(t => t.isActive(true)); - if (!activeTargets.length || (!move.hasAttr(VariableTargetAttr) && !move.isMultiTarget() && !targetHitChecks[this.targets[0]])) { + const hasActiveTargets = targets.some(t => t.isActive(true)); + if (!hasActiveTargets || (!move.hasAttr(VariableTargetAttr) && !move.isMultiTarget() && !targetHitChecks[this.targets[0]])) { this.stopMultiHit(); - if (activeTargets.length) { - this.scene.queueMessage(i18next.t("battle:attackMissed", { pokemonNameWithAffix: getPokemonNameWithAffix(this.getTarget()) })); + if (hasActiveTargets) { + this.scene.queueMessage(i18next.t("battle:attackMissed", { pokemonNameWithAffix: this.getTarget()? getPokemonNameWithAffix(this.getTarget()!) : "" })); moveHistoryEntry.result = MoveResult.MISS; applyMoveAttrs(MissEffectAttr, user, null, move); } else { @@ -2969,7 +2973,7 @@ export class MoveEffectPhase extends PokemonPhase { const applyAttrs: Promise[] = []; // Move animation only needs one target - new MoveAnim(move.id as Moves, user, this.getTarget()?.getBattlerIndex()).play(this.scene, () => { + new MoveAnim(move.id as Moves, user, this.getTarget()?.getBattlerIndex()!).play(this.scene, () => { // TODO: is the bang correct here? /** Has the move successfully hit a target (for damage) yet? */ let hasHit: boolean = false; for (const target of targets) { @@ -3018,7 +3022,7 @@ export class MoveEffectPhase extends PokemonPhase { applyFilteredMoveAttrs((attr: MoveAttr) => attr instanceof MoveEffectAttr && attr.trigger === MoveEffectTrigger.PRE_APPLY && (!attr.firstHitOnly || firstHit) && (!attr.lastHitOnly || lastHit) && hitResult !== HitResult.NO_EFFECT, user, target, move).then(() => { if (hitResult !== HitResult.FAIL) { - const chargeEffect = !!move.getAttrs(ChargeAttr).find(ca => ca.usedChargeEffect(user, this.getTarget(), move)); + const chargeEffect = !!move.getAttrs(ChargeAttr).find(ca => ca.usedChargeEffect(user, this.getTarget() ?? null, move)); // Charge attribute with charge effect takes all effect attributes and applies them to charge stage, so ignore them if this is present Utils.executeIf(!chargeEffect, () => applyFilteredMoveAttrs((attr: MoveAttr) => attr instanceof MoveEffectAttr && attr.trigger === MoveEffectTrigger.POST_APPLY && attr.selfTarget && (!attr.firstHitOnly || firstHit) && (!attr.lastHitOnly || lastHit), user, target, move)).then(() => { @@ -3082,13 +3086,13 @@ export class MoveEffectPhase extends PokemonPhase { move.type = move.defaultType; const user = this.getUserPokemon(); if (user) { - if (--user.turnData.hitsLeft >= 1 && this.getTarget()?.isActive()) { + if (user.turnData.hitsLeft && --user.turnData.hitsLeft >= 1 && this.getTarget()?.isActive()) { this.scene.unshiftPhase(this.getNewHitPhase()); } else { // Queue message for number of hits made by multi-move // If multi-hit attack only hits once, still want to render a message - const hitsTotal = user.turnData.hitCount - Math.max(user.turnData.hitsLeft, 0); - if (hitsTotal > 1 || user.turnData.hitsLeft > 0) { + const hitsTotal = user.turnData.hitCount! - Math.max(user.turnData.hitsLeft!, 0); // TODO: are those bangs correct? + if (hitsTotal > 1 || (user.turnData.hitsLeft && user.turnData.hitsLeft > 0)) { // If there are multiple hits, or if there are hits of the multi-hit move left this.scene.queueMessage(i18next.t("battle:attackHitsCount", { count: hitsTotal })); } @@ -3105,7 +3109,7 @@ export class MoveEffectPhase extends PokemonPhase { return true; } - const user = this.getUserPokemon(); + const user = this.getUserPokemon()!; // TODO: is this bang correct? // Hit check only calculated on first hit for multi-hit moves unless flag is set to check all hits. // However, if an ability with the MaxMultiHitAbAttr, namely Skill Link, is present, act as a normal @@ -3134,7 +3138,7 @@ export class MoveEffectPhase extends PokemonPhase { return false; } - const moveAccuracy = this.move.getMove().calculateBattleAccuracy(user, target); + const moveAccuracy = this.move.getMove().calculateBattleAccuracy(user!, target); // TODO: is the bang correct here? if (moveAccuracy === -1) { return true; @@ -3143,12 +3147,12 @@ export class MoveEffectPhase extends PokemonPhase { const accuracyMultiplier = user.getAccuracyMultiplier(target, this.move.getMove()); const rand = user.randSeedInt(100, 1); - return rand <= moveAccuracy * accuracyMultiplier; + return rand <= moveAccuracy * (accuracyMultiplier!); // TODO: is this bang correct? } - getUserPokemon(): Pokemon { + getUserPokemon(): Pokemon | undefined { if (this.battlerIndex > BattlerIndex.ENEMY_2) { - return this.scene.getPokemonById(this.battlerIndex); + return this.scene.getPokemonById(this.battlerIndex) ?? undefined; } return (this.player ? this.scene.getPlayerField() : this.scene.getEnemyField())[this.fieldIndex]; } @@ -3157,7 +3161,7 @@ export class MoveEffectPhase extends PokemonPhase { return this.scene.getField(true).filter(p => this.targets.indexOf(p.getBattlerIndex()) > -1); } - getTarget(): Pokemon { + getTarget(): Pokemon | undefined { return this.getTargets().find(() => true); } @@ -3178,8 +3182,8 @@ export class MoveEffectPhase extends PokemonPhase { * targets, completely cancel all subsequent strikes. */ if (!target || this.targets.length === 0 ) { - this.getUserPokemon().turnData.hitCount = 1; - this.getUserPokemon().turnData.hitsLeft = 1; + this.getUserPokemon()!.turnData.hitCount = 1; // TODO: is the bang correct here? + this.getUserPokemon()!.turnData.hitsLeft = 1; // TODO: is the bang correct here? } } @@ -3233,7 +3237,7 @@ export class MoveAnimTestPhase extends BattlePhase { initMoveAnim(this.scene, moveId).then(() => { loadMoveAnimAssets(this.scene, [moveId], true) .then(() => { - new MoveAnim(moveId, player ? this.scene.getPlayerPokemon() : this.scene.getEnemyPokemon(), (player !== (allMoves[moveId] instanceof SelfStatusMove) ? this.scene.getEnemyPokemon() : this.scene.getPlayerPokemon()).getBattlerIndex()).play(this.scene, () => { + new MoveAnim(moveId, player ? this.scene.getPlayerPokemon()! : this.scene.getEnemyPokemon()!, (player !== (allMoves[moveId] instanceof SelfStatusMove) ? this.scene.getEnemyPokemon()! : this.scene.getPlayerPokemon()!).getBattlerIndex()).play(this.scene, () => { // TODO: are the bangs correct here? if (player) { this.playMoveAnim(moveQueue, false); } else { @@ -3259,16 +3263,19 @@ export class ShowAbilityPhase extends PokemonPhase { const pokemon = this.getPokemon(); - this.scene.abilityBar.showAbility(pokemon, this.passive); - if (pokemon.battleData) { - pokemon.battleData.abilityRevealed = true; + if (pokemon) { + this.scene.abilityBar.showAbility(pokemon, this.passive); + + if (pokemon?.battleData) { + pokemon.battleData.abilityRevealed = true; + } } this.end(); } } -export type StatChangeCallback = (target: Pokemon, changed: BattleStat[], relativeChanges: number[]) => void; +export type StatChangeCallback = (target: Pokemon | null, changed: BattleStat[], relativeChanges: number[]) => void; export class StatChangePhase extends PokemonPhase { private stats: BattleStat[]; @@ -3277,10 +3284,10 @@ export class StatChangePhase extends PokemonPhase { private showMessage: boolean; private ignoreAbilities: boolean; private canBeCopied: boolean; - private onChange: StatChangeCallback; + private onChange: StatChangeCallback | null; - constructor(scene: BattleScene, battlerIndex: BattlerIndex, selfTarget: boolean, stats: BattleStat[], levels: integer, showMessage: boolean = true, ignoreAbilities: boolean = false, canBeCopied: boolean = true, onChange: StatChangeCallback = null) { + constructor(scene: BattleScene, battlerIndex: BattlerIndex, selfTarget: boolean, stats: BattleStat[], levels: integer, showMessage: boolean = true, ignoreAbilities: boolean = false, canBeCopied: boolean = true, onChange: StatChangeCallback | null = null) { super(scene, battlerIndex); this.selfTarget = selfTarget; @@ -3329,9 +3336,9 @@ export class StatChangePhase extends PokemonPhase { } const battleStats = this.getPokemon().summonData.battleStats; - const relLevels = filteredStats.map(stat => (levels.value >= 1 ? Math.min(battleStats[stat] + levels.value, 6) : Math.max(battleStats[stat] + levels.value, -6)) - battleStats[stat]); + const relLevels = filteredStats.map(stat => (levels.value >= 1 ? Math.min(battleStats![stat] + levels.value, 6) : Math.max(battleStats![stat] + levels.value, -6)) - battleStats![stat]); - this.onChange?.(this.getPokemon(), filteredStats, relLevels); + this.onChange && this.onChange(this.getPokemon(), filteredStats, relLevels); const end = () => { if (this.showMessage) { @@ -3393,7 +3400,7 @@ export class StatChangePhase extends PokemonPhase { this.scene.playSound(`stat_${levels.value >= 1 ? "up" : "down"}`); - statSprite.setMask(new Phaser.Display.Masks.BitmapMask(this.scene, pokemonMaskSprite)); + statSprite.setMask(new Phaser.Display.Masks.BitmapMask(this.scene, pokemonMaskSprite ?? undefined)); this.scene.tweens.add({ targets: statSprite, @@ -3426,7 +3433,7 @@ export class StatChangePhase extends PokemonPhase { getRandomStat(): BattleStat { const allStats = Utils.getEnumValues(BattleStat); - return allStats[this.getPokemon().randSeedInt(BattleStat.SPD + 1)]; + return this.getPokemon() ? allStats[this.getPokemon()!.randSeedInt(BattleStat.SPD + 1)] : BattleStat.ATK; // TODO: return default ATK on random? idk... } aggregateStatChanges(random: boolean = false): void { @@ -3491,7 +3498,7 @@ export class StatChangePhase extends PokemonPhase { } export class WeatherEffectPhase extends CommonAnimPhase { - public weather: Weather; + public weather: Weather | null; constructor(scene: BattleScene) { super(scene, undefined, undefined, CommonAnim.SUNNY + ((scene?.arena?.weather?.weatherType || WeatherType.NONE) - 1)); @@ -3519,7 +3526,7 @@ export class WeatherEffectPhase extends CommonAnimPhase { const inflictDamage = (pokemon: Pokemon) => { const cancelled = new Utils.BooleanHolder(false); - applyPreWeatherEffectAbAttrs(PreWeatherDamageAbAttr, pokemon, this.weather, cancelled); + applyPreWeatherEffectAbAttrs(PreWeatherDamageAbAttr, pokemon, this.weather , cancelled); applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled); if (cancelled.value) { @@ -3528,12 +3535,12 @@ export class WeatherEffectPhase extends CommonAnimPhase { const damage = Math.ceil(pokemon.getMaxHp() / 16); - this.scene.queueMessage(getWeatherDamageMessage(this.weather.weatherType, pokemon)); + this.scene.queueMessage(getWeatherDamageMessage(this.weather?.weatherType!, pokemon)!); // TODO: are those bangs correct? pokemon.damageAndUpdate(damage, HitResult.EFFECTIVE, false, false, true); }; this.executeForAll((pokemon: Pokemon) => { - const immune = !pokemon || !!pokemon.getTypes(true, true).filter(t => this.weather.isTypeDamageImmune(t)).length; + const immune = !pokemon || !!pokemon.getTypes(true, true).filter(t => this.weather?.isTypeDamageImmune(t)).length; if (!immune) { inflictDamage(pokemon); } @@ -3541,7 +3548,7 @@ export class WeatherEffectPhase extends CommonAnimPhase { } } - this.scene.ui.showText(getWeatherLapseMessage(this.weather.weatherType), null, () => { + this.scene.ui.showText(getWeatherLapseMessage(this.weather.weatherType)!, null, () => { // TODO: is this bang correct? this.executeForAll((pokemon: Pokemon) => applyPostWeatherLapseAbAttrs(PostWeatherLapseAbAttr, pokemon, this.weather)); super.start(); @@ -3550,31 +3557,31 @@ export class WeatherEffectPhase extends CommonAnimPhase { } export class ObtainStatusEffectPhase extends PokemonPhase { - private statusEffect: StatusEffect; - private cureTurn: integer; - private sourceText: string; - private sourcePokemon: Pokemon; + private statusEffect: StatusEffect | undefined; + private cureTurn: integer | null; + private sourceText: string | null; + private sourcePokemon: Pokemon | null; - constructor(scene: BattleScene, battlerIndex: BattlerIndex, statusEffect: StatusEffect, cureTurn?: integer, sourceText?: string, sourcePokemon?: Pokemon) { + constructor(scene: BattleScene, battlerIndex: BattlerIndex, statusEffect?: StatusEffect, cureTurn?: integer | null, sourceText?: string, sourcePokemon?: Pokemon) { super(scene, battlerIndex); this.statusEffect = statusEffect; - this.cureTurn = cureTurn; - this.sourceText = sourceText; - this.sourcePokemon = sourcePokemon; // For tracking which Pokemon caused the status effect + this.cureTurn = cureTurn!; // TODO: is this bang correct? + this.sourceText = sourceText!; // TODO: is this bang correct? + this.sourcePokemon = sourcePokemon!; // For tracking which Pokemon caused the status effect // TODO: is this bang correct? } start() { const pokemon = this.getPokemon(); - if (!pokemon.status) { - if (pokemon.trySetStatus(this.statusEffect, false, this.sourcePokemon)) { + if (!pokemon?.status) { + if (pokemon?.trySetStatus(this.statusEffect, false, this.sourcePokemon)) { if (this.cureTurn) { - pokemon.status.cureTurn = this.cureTurn; + pokemon.status!.cureTurn = this.cureTurn; // TODO: is this bang correct? } pokemon.updateInfo(true); - new CommonBattleAnim(CommonAnim.POISON + (this.statusEffect - 1), pokemon).play(this.scene, () => { - this.scene.queueMessage(getStatusEffectObtainText(this.statusEffect, getPokemonNameWithAffix(pokemon), this.sourceText)); - if (pokemon.status.isPostTurn()) { + new CommonBattleAnim(CommonAnim.POISON + (this.statusEffect! - 1), pokemon).play(this.scene, () => { + this.scene.queueMessage(getStatusEffectObtainText(this.statusEffect, getPokemonNameWithAffix(pokemon), this.sourceText ?? undefined)); + if (pokemon.status?.isPostTurn()) { this.scene.pushPhase(new PostTurnStatusEffectPhase(this.scene, this.battlerIndex)); } this.end(); @@ -3640,17 +3647,17 @@ export class PostTurnStatusEffectPhase extends PokemonPhase { export class MessagePhase extends Phase { private text: string; - private callbackDelay: integer; - private prompt: boolean; - private promptDelay: integer; + private callbackDelay: integer | null; + private prompt: boolean | null; + private promptDelay: integer | null; - constructor(scene: BattleScene, text: string, callbackDelay?: integer, prompt?: boolean, promptDelay?: integer) { + constructor(scene: BattleScene, text: string, callbackDelay?: integer | null, prompt?: boolean | null, promptDelay?: integer | null) { super(scene); this.text = text; - this.callbackDelay = callbackDelay; - this.prompt = prompt; - this.promptDelay = promptDelay; + this.callbackDelay = callbackDelay!; // TODO: is this bang correct? + this.prompt = prompt!; // TODO: is this bang correct? + this.promptDelay = promptDelay!; // TODO: is this bang correct? } start() { @@ -3758,7 +3765,7 @@ export class FaintPhase extends PokemonPhase { constructor(scene: BattleScene, battlerIndex: BattlerIndex, preventEndure?: boolean) { super(scene, battlerIndex); - this.preventEndure = preventEndure; + this.preventEndure = preventEndure!; // TODO: is this bang correct? } start() { @@ -3795,7 +3802,7 @@ export class FaintPhase extends PokemonPhase { if (pokemon.turnData?.attacksReceived?.length) { const lastAttack = pokemon.turnData.attacksReceived[0]; - applyPostFaintAbAttrs(PostFaintAbAttr, pokemon, this.scene.getPokemonById(lastAttack.sourceId), new PokemonMove(lastAttack.move).getMove(), lastAttack.result); + applyPostFaintAbAttrs(PostFaintAbAttr, pokemon, this.scene.getPokemonById(lastAttack.sourceId)!, new PokemonMove(lastAttack.move).getMove(), lastAttack.result); // TODO: is this bang correct? } const alivePlayField = this.scene.getField(true); @@ -3916,7 +3923,7 @@ export class VictoryPhase extends PokemonPhase { const multipleParticipantExpBonusModifier = this.scene.findModifier(m => m instanceof MultipleParticipantExpBonusModifier) as MultipleParticipantExpBonusModifier; const nonFaintedPartyMembers = party.filter(p => p.hp); const expPartyMembers = nonFaintedPartyMembers.filter(p => p.level < this.scene.getMaxExpLevel()); - const partyMemberExp = []; + const partyMemberExp: number[] = []; if (participantIds.size) { let expValue = this.getPokemon().getExpValue(); @@ -3968,7 +3975,7 @@ export class VictoryPhase extends PokemonPhase { const medianLevel = Math.floor(totalLevel / expPartyMembers.length); - const recipientExpPartyMemberIndexes = []; + const recipientExpPartyMemberIndexes: number[] = []; expPartyMembers.forEach((expPartyMember, epm) => { if (expPartyMember.level <= medianLevel) { recipientExpPartyMemberIndexes.push(epm); @@ -4043,39 +4050,40 @@ export class TrainerVictoryPhase extends BattlePhase { start() { this.scene.disableMenu = true; - this.scene.playBgm(this.scene.currentBattle.trainer.config.victoryBgm); + this.scene.playBgm(this.scene.currentBattle.trainer?.config.victoryBgm); - this.scene.unshiftPhase(new MoneyRewardPhase(this.scene, this.scene.currentBattle.trainer.config.moneyMultiplier)); + this.scene.unshiftPhase(new MoneyRewardPhase(this.scene, this.scene.currentBattle.trainer?.config.moneyMultiplier!)); // TODO: is this bang correct? - const modifierRewardFuncs = this.scene.currentBattle.trainer.config.modifierRewardFuncs; + const modifierRewardFuncs = this.scene.currentBattle.trainer?.config.modifierRewardFuncs!; // TODO: is this bang correct? for (const modifierRewardFunc of modifierRewardFuncs) { this.scene.unshiftPhase(new ModifierRewardPhase(this.scene, modifierRewardFunc)); } - const trainerType = this.scene.currentBattle.trainer.config.trainerType; + const trainerType = this.scene.currentBattle.trainer?.config.trainerType!; // TODO: is this bang correct? if (vouchers.hasOwnProperty(TrainerType[trainerType])) { - if (!this.scene.validateVoucher(vouchers[TrainerType[trainerType]]) && this.scene.currentBattle.trainer.config.isBoss) { + if (!this.scene.validateVoucher(vouchers[TrainerType[trainerType]]) && this.scene.currentBattle.trainer?.config.isBoss) { this.scene.unshiftPhase(new ModifierRewardPhase(this.scene, [modifierTypes.VOUCHER, modifierTypes.VOUCHER, modifierTypes.VOUCHER_PLUS, modifierTypes.VOUCHER_PREMIUM][vouchers[TrainerType[trainerType]].voucherType])); } } - this.scene.ui.showText(i18next.t("battle:trainerDefeated", { trainerName: this.scene.currentBattle.trainer.getName(TrainerSlot.NONE, true) }), null, () => { - const victoryMessages = this.scene.currentBattle.trainer.getVictoryMessages(); + this.scene.ui.showText(i18next.t("battle:trainerDefeated", { trainerName: this.scene.currentBattle.trainer?.getName(TrainerSlot.NONE, true) }), null, () => { + const victoryMessages = this.scene.currentBattle.trainer?.getVictoryMessages()!; // TODO: is this bang correct? let message: string; this.scene.executeWithSeedOffset(() => message = Utils.randSeedItem(victoryMessages), this.scene.currentBattle.waveIndex); + message = message!; // tell TS compiler it's defined now const showMessage = () => { const originalFunc = showMessageOrEnd; - showMessageOrEnd = () => this.scene.ui.showDialogue(message, this.scene.currentBattle.trainer.getName(), null, originalFunc); + showMessageOrEnd = () => this.scene.ui.showDialogue(message, this.scene.currentBattle.trainer?.getName(), null, originalFunc); showMessageOrEnd(); }; let showMessageOrEnd = () => this.end(); if (victoryMessages?.length) { - if (this.scene.currentBattle.trainer.config.hasCharSprite && !this.scene.ui.shouldSkipDialogue(message)) { + if (this.scene.currentBattle.trainer?.config.hasCharSprite && !this.scene.ui.shouldSkipDialogue(message)) { const originalFunc = showMessageOrEnd; showMessageOrEnd = () => this.scene.charSprite.hide().then(() => this.scene.hideFieldOverlay(250).then(() => originalFunc())); - this.scene.showFieldOverlay(500).then(() => this.scene.charSprite.showCharacter(this.scene.currentBattle.trainer.getKey(), getCharVariantFromDialogue(victoryMessages[0])).then(() => showMessage())); + this.scene.showFieldOverlay(500).then(() => this.scene.charSprite.showCharacter(this.scene.currentBattle.trainer?.getKey()!, getCharVariantFromDialogue(victoryMessages[0])).then(() => showMessage())); // TODO: is this bang correct? } else { showMessage(); } @@ -4136,7 +4144,7 @@ export class ModifierRewardPhase extends BattlePhase { const newModifier = this.modifierType.newModifier(); this.scene.addModifier(newModifier).then(() => { this.scene.playSound("item_fanfare"); - this.scene.ui.showText(i18next.t("battle:rewardGain", { modifierName: newModifier.type.name }), null, () => resolve(), null, true); + this.scene.ui.showText(i18next.t("battle:rewardGain", { modifierName: newModifier?.type.name }), null, () => resolve(), null, true); }); }); } @@ -4154,7 +4162,7 @@ export class GameOverModifierRewardPhase extends ModifierRewardPhase { this.scene.playSound("level_up_fanfare"); this.scene.ui.setMode(Mode.MESSAGE); this.scene.ui.fadeIn(250).then(() => { - this.scene.ui.showText(i18next.t("battle:rewardGain", { modifierName: newModifier.type.name }), null, () => { + this.scene.ui.showText(i18next.t("battle:rewardGain", { modifierName: newModifier?.type.name }), null, () => { this.scene.time.delayedCall(1500, () => this.scene.arenaBg.setVisible(true)); resolve(); }, null, true, 1500); @@ -4182,7 +4190,7 @@ export class RibbonModifierRewardPhase extends ModifierRewardPhase { this.scene.ui.showText(i18next.t("battle:beatModeFirstTime", { speciesName: this.species.name, gameMode: this.scene.gameMode.getName(), - newModifier: newModifier.type.name + newModifier: newModifier?.type.name }), null, () => { resolve(); }, null, true, 1500); @@ -4423,12 +4431,12 @@ export class UnlockPhase extends Phase { } export class PostGameOverPhase extends Phase { - private endCardPhase: EndCardPhase; + private endCardPhase: EndCardPhase | null; - constructor(scene: BattleScene, endCardPhase: EndCardPhase) { + constructor(scene: BattleScene, endCardPhase?: EndCardPhase) { super(scene); - this.endCardPhase = endCardPhase; + this.endCardPhase = endCardPhase!; // TODO: is this bang correct? } start() { @@ -4454,8 +4462,8 @@ export class PostGameOverPhase extends Phase { this.scene.ui.fadeOut(500).then(() => { this.scene.ui.getMessageHandler().bg.setVisible(true); - this.endCardPhase.endCard.destroy(); - this.endCardPhase.text.destroy(); + this.endCardPhase?.endCard.destroy(); + this.endCardPhase?.text.destroy(); saveAndReset(); }); } else { @@ -4734,7 +4742,7 @@ export class LearnMovePhase extends PlayerPartyMemberPokemonPhase { } this.scene.ui.setMode(messageMode).then(() => { this.scene.ui.showText(i18next.t("battle:countdownPoof"), null, () => { - this.scene.ui.showText(i18next.t("battle:learnMoveForgetSuccess", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: pokemon.moveset[moveIndex].getName() }), null, () => { + this.scene.ui.showText(i18next.t("battle:learnMoveForgetSuccess", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: pokemon.moveset[moveIndex]!.getName() }), null, () => { // TODO: is the bang correct? this.scene.ui.showText(i18next.t("battle:learnMoveAnd"), null, () => { pokemon.setMove(moveIndex, Moves.NONE); this.scene.unshiftPhase(new LearnMovePhase(this.scene, this.partyMemberIndex, this.moveId)); @@ -4756,14 +4764,14 @@ export class LearnMovePhase extends PlayerPartyMemberPokemonPhase { export class PokemonHealPhase extends CommonAnimPhase { private hpHealed: integer; - private message: string; + private message: string | null; private showFullHpMessage: boolean; private skipAnim: boolean; private revive: boolean; private healStatus: boolean; private preventFullHeal: boolean; - constructor(scene: BattleScene, battlerIndex: BattlerIndex, hpHealed: integer, message: string, showFullHpMessage: boolean, skipAnim: boolean = false, revive: boolean = false, healStatus: boolean = false, preventFullHeal: boolean = false) { + constructor(scene: BattleScene, battlerIndex: BattlerIndex, hpHealed: integer, message: string | null, showFullHpMessage: boolean, skipAnim: boolean = false, revive: boolean = false, healStatus: boolean = false, preventFullHeal: boolean = false) { super(scene, battlerIndex, undefined, CommonAnim.HEALTH_UP); this.hpHealed = hpHealed; @@ -5171,7 +5179,7 @@ export class SelectModifierPhase extends BattlePhase { super(scene); this.rerollCount = rerollCount; - this.modifierTiers = modifierTiers; + this.modifierTiers = modifierTiers!; // TODO: is this bang correct? } start() { @@ -5214,7 +5222,7 @@ export class SelectModifierPhase extends BattlePhase { return false; } else { this.scene.reroll = true; - this.scene.unshiftPhase(new SelectModifierPhase(this.scene, this.rerollCount + 1, typeOptions.map(o => o.type.tier))); + this.scene.unshiftPhase(new SelectModifierPhase(this.scene, this.rerollCount + 1, typeOptions.map(o => o.type?.tier).filter(t => t !== undefined) as ModifierTier[])); this.scene.ui.clearText(); this.scene.ui.setMode(Mode.MESSAGE).then(() => super.end()); if (!Overrides.WAIVE_ROLL_FEE_OVERRIDE) { @@ -5252,17 +5260,21 @@ export class SelectModifierPhase extends BattlePhase { } return true; case 1: - modifierType = typeOptions[cursor].type; + if (typeOptions[cursor].type) { + modifierType = typeOptions[cursor].type; + } break; default: const shopOptions = getPlayerShopModifierTypeOptionsForWave(this.scene.currentBattle.waveIndex, this.scene.getWaveMoneyAmount(1)); const shopOption = shopOptions[rowCursor > 2 || shopOptions.length <= SHOP_OPTIONS_ROW_LIMIT ? cursor : cursor + SHOP_OPTIONS_ROW_LIMIT]; - modifierType = shopOption.type; + if (shopOption.type) { + modifierType = shopOption.type; + } cost = shopOption.cost; break; } - if (cost && (this.scene.money < cost) && !Overrides.WAIVE_ROLL_FEE_OVERRIDE) { + if (cost! && (this.scene.money < cost) && !Overrides.WAIVE_ROLL_FEE_OVERRIDE) { // TODO: is the bang on cost correct? this.scene.ui.playError(); return false; } @@ -5297,12 +5309,12 @@ export class SelectModifierPhase extends BattlePhase { } }; - if (modifierType instanceof PokemonModifierType) { + if (modifierType! instanceof PokemonModifierType) { //TODO: is the bang correct? if (modifierType instanceof FusePokemonModifierType) { this.scene.ui.setModeWithoutClear(Mode.PARTY, PartyUiMode.SPLICE, -1, (fromSlotIndex: integer, spliceSlotIndex: integer) => { if (spliceSlotIndex !== undefined && fromSlotIndex < 6 && spliceSlotIndex < 6 && fromSlotIndex !== spliceSlotIndex) { this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer()).then(() => { - const modifier = modifierType.newModifier(party[fromSlotIndex], party[spliceSlotIndex]); + const modifier = modifierType.newModifier(party[fromSlotIndex], party[spliceSlotIndex])!; //TODO: is the bang correct? applyModifier(modifier, true); }); } else { @@ -5330,7 +5342,7 @@ export class SelectModifierPhase extends BattlePhase { ? modifierType.newModifier(party[slotIndex]) : modifierType.newModifier(party[slotIndex], option as integer) : modifierType.newModifier(party[slotIndex], option - PartyOption.MOVE_1); - applyModifier(modifier, true); + applyModifier(modifier!, true); // TODO: is the bang correct? }); } else { this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, this.getRerollCost(typeOptions, this.scene.lockModifierTiers)); @@ -5338,10 +5350,10 @@ export class SelectModifierPhase extends BattlePhase { }, pokemonModifierType.selectFilter, modifierType instanceof PokemonMoveModifierType ? (modifierType as PokemonMoveModifierType).moveSelectFilter : undefined, tmMoveId, isPpRestoreModifier); } } else { - applyModifier(modifierType.newModifier()); + applyModifier(modifierType!.newModifier()!); // TODO: is the bang correct? } - return !cost; + return !cost!;// TODO: is the bang correct? }; this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, this.getRerollCost(typeOptions, this.scene.lockModifierTiers)); } @@ -5361,7 +5373,7 @@ export class SelectModifierPhase extends BattlePhase { } else if (lockRarities) { const tierValues = [50, 125, 300, 750, 2000]; for (const opt of typeOptions) { - baseValue += tierValues[opt.type.tier]; + baseValue += opt.type?.tier ? tierValues[opt.type.tier] : 0; } } else { baseValue = 250; @@ -5496,7 +5508,7 @@ export class PartyHealPhase extends BattlePhase { pokemon.hp = pokemon.getMaxHp(); pokemon.resetStatus(); for (const move of pokemon.moveset) { - move.ppUsed = 0; + move!.ppUsed = 0; // TODO: is this bang correct? } pokemon.updateInfo(true); } diff --git a/src/pipelines/sprite.ts b/src/pipelines/sprite.ts index 741c31183d4..c9a76dc50a4 100644 --- a/src/pipelines/sprite.ts +++ b/src/pipelines/sprite.ts @@ -377,7 +377,7 @@ export default class SpritePipeline extends FieldSpritePipeline { this.set2f("texSize", sprite.texture.source[0].width, sprite.texture.source[0].height); this.set1f("yOffset", sprite.height - sprite.frame.height * (isEntityObj ? sprite.parentContainer.scale : sprite.scale)); this.set4fv("tone", tone); - this.bindTexture(this.game.textures.get("tera").source[0].glTexture, 1); + this.bindTexture(this.game.textures.get("tera").source[0].glTexture!, 1); // TODO: is this bang correct? if ((gameObject.scene as BattleScene).fusionPaletteSwaps) { const spriteColors = ((ignoreOverride && data["spriteColorsBase"]) || data["spriteColors"] || []) as number[][]; diff --git a/src/plugins/i18n.ts b/src/plugins/i18n.ts index 54dc545868c..82cde7cd2ad 100644 --- a/src/plugins/i18n.ts +++ b/src/plugins/i18n.ts @@ -157,7 +157,7 @@ export async function initI18n(): Promise { postProcess: ["korean-postposition"], }); - await initFonts(localStorage.getItem("prLang")); + await initFonts(localStorage.getItem("prLang") ?? undefined); } export default i18next; diff --git a/src/system/achv.ts b/src/system/achv.ts index 0dcf74ce3a5..b1f575fb31c 100644 --- a/src/system/achv.ts +++ b/src/system/achv.ts @@ -6,6 +6,7 @@ import * as Utils from "../utils"; import { PlayerGender } from "#enums/player-gender"; import { ParseKeys } from "i18next"; import { Challenge, FreshStartChallenge, SingleGenerationChallenge, SingleTypeChallenge } from "#app/data/challenge.js"; +import { ConditionFn } from "#app/@types/common.js"; export enum AchvTier { COMMON, @@ -27,9 +28,9 @@ export class Achv { public hasParent: boolean; public parentId: string; - private conditionFunc: (scene: BattleScene, args: any[]) => boolean; + private conditionFunc: ConditionFn | undefined; - constructor(localizationKey:string, name: string, description: string, iconImage: string, score: integer, conditionFunc?: (scene: BattleScene, args: any[]) => boolean) { + constructor(localizationKey:string, name: string, description: string, iconImage: string, score: integer, conditionFunc?: ConditionFn) { this.name = name; this.description = description; this.iconImage = iconImage; @@ -63,7 +64,7 @@ export class Achv { return this; } - validate(scene: BattleScene, args: any[]): boolean { + validate(scene: BattleScene, args?: any[]): boolean { return !this.conditionFunc || this.conditionFunc(scene, args); } diff --git a/src/system/arena-data.ts b/src/system/arena-data.ts index f6db53d7f7f..886129edcf6 100644 --- a/src/system/arena-data.ts +++ b/src/system/arena-data.ts @@ -6,15 +6,15 @@ import { Terrain } from "#app/data/terrain.js"; export default class ArenaData { public biome: Biome; - public weather: Weather; - public terrain: Terrain; + public weather: Weather | null; + public terrain: Terrain | null; public tags: ArenaTag[]; constructor(source: Arena | any) { const sourceArena = source instanceof Arena ? source as Arena : null; this.biome = sourceArena ? sourceArena.biomeType : source.biome; - this.weather = sourceArena ? sourceArena.weather : source.weather ? new Weather(source.weather.weatherType, source.weather.turnsLeft) : undefined; - this.terrain = sourceArena ? sourceArena.terrain : source.terrain ? new Terrain(source.terrain.terrainType, source.terrain.turnsLeft) : undefined; + this.weather = sourceArena ? sourceArena.weather : source.weather ? new Weather(source.weather.weatherType, source.weather.turnsLeft) : null; + this.terrain = sourceArena ? sourceArena.terrain : source.terrain ? new Terrain(source.terrain.terrainType, source.terrain.turnsLeft) : null; this.tags = sourceArena ? sourceArena.tags : []; } } diff --git a/src/system/game-data.ts b/src/system/game-data.ts index 161b5a2c49b..2cc6ab93c61 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -41,6 +41,8 @@ import { Moves } from "#enums/moves"; import { PlayerGender } from "#enums/player-gender"; import { Species } from "#enums/species"; import { applyChallenges, ChallengeType } from "#app/data/challenge.js"; +import { WeatherType } from "#app/enums/weather-type.js"; +import { TerrainType } from "#app/data/terrain.js"; export const defaultStarterSpecies: Species[] = [ Species.BULBASAUR, Species.CHARMANDER, Species.SQUIRTLE, @@ -78,7 +80,7 @@ export function getDataTypeKey(dataType: GameDataType, slotId: integer = 0): str export function encrypt(data: string, bypassLogin: boolean): string { return (bypassLogin ? (data: string) => btoa(data) - : (data: string) => AES.encrypt(data, saveKey))(data); + : (data: string) => AES.encrypt(data, saveKey))(data) as unknown as string; // TODO: is this correct? } export function decrypt(data: string, bypassLogin: boolean): string { @@ -230,7 +232,7 @@ export class StarterPrefs { } export interface StarterDataEntry { - moveset: StarterMoveset | StarterFormMoveData; + moveset: StarterMoveset | StarterFormMoveData | null; eggMoves: integer; candyCount: integer; friendship: integer; @@ -279,7 +281,7 @@ export class GameData { public gender: PlayerGender; public dexData: DexData; - private defaultDexData: DexData; + private defaultDexData: DexData | null; public starterData: StarterData; @@ -352,7 +354,7 @@ export class GameData { const maxIntAttrValue = 0x80000000; const systemData = JSON.stringify(data, (k: any, v: any) => typeof v === "bigint" ? v <= maxIntAttrValue ? Number(v) : v.toString() : v); - localStorage.setItem(`data_${loggedInUser.username}`, encrypt(systemData, bypassLogin)); + localStorage.setItem(`data_${loggedInUser?.username}`, encrypt(systemData, bypassLogin)); if (!bypassLogin) { Utils.apiPost(`savedata/system/update?clientSessionId=${clientSessionId}`, systemData, undefined, true) @@ -384,7 +386,7 @@ export class GameData { return new Promise(resolve => { console.log("Client Session:", clientSessionId); - if (bypassLogin && !localStorage.getItem(`data_${loggedInUser.username}`)) { + if (bypassLogin && !localStorage.getItem(`data_${loggedInUser?.username}`)) { return resolve(false); } @@ -404,11 +406,11 @@ export class GameData { return resolve(false); } - const cachedSystem = localStorage.getItem(`data_${loggedInUser.username}`); - this.initSystem(response, cachedSystem ? AES.decrypt(cachedSystem, saveKey).toString(enc.Utf8) : null).then(resolve); + const cachedSystem = localStorage.getItem(`data_${loggedInUser?.username}`); + this.initSystem(response, cachedSystem ? AES.decrypt(cachedSystem, saveKey).toString(enc.Utf8) : undefined).then(resolve); }); } else { - this.initSystem(decrypt(localStorage.getItem(`data_${loggedInUser.username}`), bypassLogin)).then(resolve); + this.initSystem(decrypt(localStorage.getItem(`data_${loggedInUser?.username}`)!, bypassLogin)).then(resolve); // TODO: is this bang correct? } }); } @@ -431,7 +433,7 @@ export class GameData { console.debug(systemData); - localStorage.setItem(`data_${loggedInUser.username}`, encrypt(systemDataStr, bypassLogin)); + localStorage.setItem(`data_${loggedInUser?.username}`, encrypt(systemDataStr, bypassLogin)); /*const versions = [ this.scene.game.config.gameVersion, data.gameVersion || '0.0.0' ]; @@ -606,9 +608,9 @@ export class GameData { if (bypassLogin) { return; } - localStorage.removeItem(`data_${loggedInUser.username}`); + localStorage.removeItem(`data_${loggedInUser?.username}`); for (let s = 0; s < 5; s++) { - localStorage.removeItem(`sessionData${s ? s : ""}_${loggedInUser.username}`); + localStorage.removeItem(`sessionData${s ? s : ""}_${loggedInUser?.username}`); } } @@ -621,7 +623,7 @@ export class GameData { public saveSetting(setting: string, valueIndex: integer): boolean { let settings: object = {}; if (localStorage.hasOwnProperty("settings")) { - settings = JSON.parse(localStorage.getItem("settings")); + settings = JSON.parse(localStorage.getItem("settings")!); // TODO: is this bang correct? } setSetting(this.scene, setting, valueIndex); @@ -644,7 +646,7 @@ export class GameData { const key = deviceName.toLowerCase(); // Convert the gamepad name to lowercase to use as a key let mappingConfigs: object = {}; // Initialize an empty object to hold the mapping configurations if (localStorage.hasOwnProperty("mappingConfigs")) {// Check if 'mappingConfigs' exists in localStorage - mappingConfigs = JSON.parse(localStorage.getItem("mappingConfigs")); + mappingConfigs = JSON.parse(localStorage.getItem("mappingConfigs")!); // TODO: is this bang correct? } // Parse the existing 'mappingConfigs' from localStorage if (!mappingConfigs[key]) { mappingConfigs[key] = {}; @@ -669,7 +671,7 @@ export class GameData { return false; } // If 'mappingConfigs' does not exist, return false - const mappingConfigs = JSON.parse(localStorage.getItem("mappingConfigs")); // Parse the existing 'mappingConfigs' from localStorage + const mappingConfigs = JSON.parse(localStorage.getItem("mappingConfigs")!); // Parse the existing 'mappingConfigs' from localStorage // TODO: is this bang correct? for (const key of Object.keys(mappingConfigs)) {// Iterate over the keys of the mapping configurations this.scene.inputController.injectConfig(key, mappingConfigs[key]); @@ -684,6 +686,7 @@ export class GameData { } // If 'mappingConfigs' does not exist, return false localStorage.removeItem("mappingConfigs"); this.scene.inputController.resetConfigs(); + return true; // TODO: is `true` the correct return value? } /** @@ -703,7 +706,7 @@ export class GameData { let settingsControls: object = {}; // Initialize an empty object to hold the gamepad settings if (localStorage.hasOwnProperty(localStoragePropertyName)) { // Check if 'settingsControls' exists in localStorage - settingsControls = JSON.parse(localStorage.getItem(localStoragePropertyName)); // Parse the existing 'settingsControls' from localStorage + settingsControls = JSON.parse(localStorage.getItem(localStoragePropertyName)!); // Parse the existing 'settingsControls' from localStorage // TODO: is this bang correct? } if (device === Device.GAMEPAD) { @@ -734,11 +737,13 @@ export class GameData { return false; } - const settings = JSON.parse(localStorage.getItem("settings")); + const settings = JSON.parse(localStorage.getItem("settings")!); // TODO: is this bang correct? for (const setting of Object.keys(settings)) { setSetting(this.scene, setting, settings[setting]); } + + return true; // TODO: is `true` the correct return value? } private loadGamepadSettings(): boolean { @@ -747,18 +752,20 @@ export class GameData { if (!localStorage.hasOwnProperty("settingsGamepad")) { return false; } - const settingsGamepad = JSON.parse(localStorage.getItem("settingsGamepad")); + const settingsGamepad = JSON.parse(localStorage.getItem("settingsGamepad")!); // TODO: is this bang correct? for (const setting of Object.keys(settingsGamepad)) { setSettingGamepad(this.scene, setting as SettingGamepad, settingsGamepad[setting]); } + + return true; // TODO: is `true` the correct return value? } public saveTutorialFlag(tutorial: Tutorial, flag: boolean): boolean { const key = getDataTypeKey(GameDataType.TUTORIALS); let tutorials: object = {}; if (localStorage.hasOwnProperty(key)) { - tutorials = JSON.parse(localStorage.getItem(key)); + tutorials = JSON.parse(localStorage.getItem(key)!); // TODO: is this bang correct? } Object.keys(Tutorial).map(t => t as Tutorial).forEach(t => { @@ -784,7 +791,7 @@ export class GameData { return ret; } - const tutorials = JSON.parse(localStorage.getItem(key)); + const tutorials = JSON.parse(localStorage.getItem(key)!); // TODO: is this bang correct? for (const tutorial of Object.keys(tutorials)) { ret[tutorial] = tutorials[tutorial]; @@ -812,7 +819,7 @@ export class GameData { return ret; } - const dialogues = JSON.parse(localStorage.getItem(key)); + const dialogues = JSON.parse(localStorage.getItem(key)!); // TODO: is this bang correct? for (const dialogue of Object.keys(dialogues)) { ret[dialogue] = dialogues[dialogue]; @@ -843,7 +850,7 @@ export class GameData { } as SessionSaveData; } - getSession(slotId: integer): Promise { + getSession(slotId: integer): Promise { return new Promise(async (resolve, reject) => { if (slotId < 0) { return resolve(null); @@ -858,7 +865,7 @@ export class GameData { } }; - if (!bypassLogin && !localStorage.getItem(`sessionData${slotId ? slotId : ""}_${loggedInUser.username}`)) { + if (!bypassLogin && !localStorage.getItem(`sessionData${slotId ? slotId : ""}_${loggedInUser?.username}`)) { Utils.apiFetch(`savedata/session/get?slot=${slotId}&clientSessionId=${clientSessionId}`, true) .then(response => response.text()) .then(async response => { @@ -867,12 +874,12 @@ export class GameData { return resolve(null); } - localStorage.setItem(`sessionData${slotId ? slotId : ""}_${loggedInUser.username}`, encrypt(response, bypassLogin)); + localStorage.setItem(`sessionData${slotId ? slotId : ""}_${loggedInUser?.username}`, encrypt(response, bypassLogin)); await handleSessionData(response); }); } else { - const sessionData = localStorage.getItem(`sessionData${slotId ? slotId : ""}_${loggedInUser.username}`); + const sessionData = localStorage.getItem(`sessionData${slotId ? slotId : ""}_${loggedInUser?.username}`); if (sessionData) { await handleSessionData(decrypt(sessionData, bypassLogin)); } else { @@ -934,7 +941,7 @@ export class GameData { const battleType = sessionData.battleType || 0; const trainerConfig = sessionData.trainer ? trainerConfigs[sessionData.trainer.trainerType] : null; - const battle = scene.newBattle(sessionData.waveIndex, battleType, sessionData.trainer, battleType === BattleType.TRAINER ? trainerConfig?.doubleOnly || sessionData.trainer?.variant === TrainerVariant.DOUBLE : sessionData.enemyParty.length > 1); + const battle = scene.newBattle(sessionData.waveIndex, battleType, sessionData.trainer, battleType === BattleType.TRAINER ? trainerConfig?.doubleOnly || sessionData.trainer?.variant === TrainerVariant.DOUBLE : sessionData.enemyParty.length > 1)!; // TODO: is this bang correct? battle.enemyLevels = sessionData.enemyParty.map(p => p.level); scene.arena.init(); @@ -950,10 +957,10 @@ export class GameData { }); scene.arena.weather = sessionData.arena.weather; - scene.arena.eventTarget.dispatchEvent(new WeatherChangedEvent(null, scene.arena.weather?.weatherType, scene.arena.weather?.turnsLeft)); + scene.arena.eventTarget.dispatchEvent(new WeatherChangedEvent(WeatherType.NONE, scene.arena.weather?.weatherType!, scene.arena.weather?.turnsLeft!)); // TODO: is this bang correct? scene.arena.terrain = sessionData.arena.terrain; - scene.arena.eventTarget.dispatchEvent(new TerrainChangedEvent(null, scene.arena.terrain?.terrainType, scene.arena.terrain?.turnsLeft)); + scene.arena.eventTarget.dispatchEvent(new TerrainChangedEvent(TerrainType.NONE, scene.arena.terrain?.terrainType!, scene.arena.terrain?.turnsLeft!)); // TODO: is this bang correct? // TODO //scene.arena.tags = sessionData.arena.tags; @@ -983,7 +990,7 @@ export class GameData { initSessionFromData(sessionData); } else { this.getSession(slotId) - .then(data => initSessionFromData(data)) + .then(data => data && initSessionFromData(data)) .catch(err => { reject(err); return; @@ -999,7 +1006,7 @@ export class GameData { deleteSession(slotId: integer): Promise { return new Promise(resolve => { if (bypassLogin) { - localStorage.removeItem(`sessionData${this.scene.sessionSlotId ? this.scene.sessionSlotId : ""}_${loggedInUser.username}`); + localStorage.removeItem(`sessionData${this.scene.sessionSlotId ? this.scene.sessionSlotId : ""}_${loggedInUser?.username}`); return resolve(true); } @@ -1009,8 +1016,8 @@ export class GameData { } Utils.apiFetch(`savedata/session/delete?slot=${slotId}&clientSessionId=${clientSessionId}`, true).then(response => { if (response.ok) { - loggedInUser.lastSessionSlot = -1; - localStorage.removeItem(`sessionData${this.scene.sessionSlotId ? this.scene.sessionSlotId : ""}_${loggedInUser.username}`); + loggedInUser!.lastSessionSlot = -1; // TODO: is the bang correct? + localStorage.removeItem(`sessionData${this.scene.sessionSlotId ? this.scene.sessionSlotId : ""}_${loggedInUser?.username}`); resolve(true); } return response.text(); @@ -1040,7 +1047,7 @@ export class GameData { if (sessionData.gameMode === GameModes.DAILY) { if (localStorage.hasOwnProperty("daily")) { - daily = JSON.parse(atob(localStorage.getItem("daily"))); + daily = JSON.parse(atob(localStorage.getItem("daily")!)); // TODO: is this bang correct? if (daily.includes(seed)) { return resolve(false); } else { @@ -1062,7 +1069,7 @@ export class GameData { tryClearSession(scene: BattleScene, slotId: integer): Promise<[success: boolean, newClear: boolean]> { return new Promise<[boolean, boolean]>(resolve => { if (bypassLogin) { - localStorage.removeItem(`sessionData${slotId ? slotId : ""}_${loggedInUser.username}`); + localStorage.removeItem(`sessionData${slotId ? slotId : ""}_${loggedInUser?.username}`); return resolve([true, true]); } @@ -1073,8 +1080,8 @@ export class GameData { const sessionData = this.getSessionSaveData(scene); Utils.apiPost(`savedata/session/clear?slot=${slotId}&trainerId=${this.trainerId}&secretId=${this.secretId}&clientSessionId=${clientSessionId}`, JSON.stringify(sessionData), undefined, true).then(response => { if (response.ok) { - loggedInUser.lastSessionSlot = -1; - localStorage.removeItem(`sessionData${this.scene.sessionSlotId ? this.scene.sessionSlotId : ""}_${loggedInUser.username}`); + loggedInUser!.lastSessionSlot = -1; // TODO: is the bang correct? + localStorage.removeItem(`sessionData${this.scene.sessionSlotId ? this.scene.sessionSlotId : ""}_${loggedInUser?.username}`); } return response.json(); }).then(jsonResponse => { @@ -1161,10 +1168,10 @@ export class GameData { if (sync) { this.scene.ui.savingIcon.show(); } - const sessionData = useCachedSession ? this.parseSessionData(decrypt(localStorage.getItem(`sessionData${scene.sessionSlotId ? scene.sessionSlotId : ""}_${loggedInUser.username}`), bypassLogin)) : this.getSessionSaveData(scene); + const sessionData = useCachedSession ? this.parseSessionData(decrypt(localStorage.getItem(`sessionData${scene.sessionSlotId ? scene.sessionSlotId : ""}_${loggedInUser?.username}`)!, bypassLogin)) : this.getSessionSaveData(scene); // TODO: is this bang correct? const maxIntAttrValue = 0x80000000; - const systemData = useCachedSystem ? this.parseSystemData(decrypt(localStorage.getItem(`data_${loggedInUser.username}`), bypassLogin)) : this.getSystemSaveData(); + const systemData = useCachedSystem ? this.parseSystemData(decrypt(localStorage.getItem(`data_${loggedInUser?.username}`)!, bypassLogin)) : this.getSystemSaveData(); // TODO: is this bang correct? const request = { system: systemData, @@ -1173,9 +1180,9 @@ export class GameData { clientSessionId: clientSessionId }; - localStorage.setItem(`data_${loggedInUser.username}`, encrypt(JSON.stringify(systemData, (k: any, v: any) => typeof v === "bigint" ? v <= maxIntAttrValue ? Number(v) : v.toString() : v), bypassLogin)); + localStorage.setItem(`data_${loggedInUser?.username}`, encrypt(JSON.stringify(systemData, (k: any, v: any) => typeof v === "bigint" ? v <= maxIntAttrValue ? Number(v) : v.toString() : v), bypassLogin)); - localStorage.setItem(`sessionData${scene.sessionSlotId ? scene.sessionSlotId : ""}_${loggedInUser.username}`, encrypt(JSON.stringify(sessionData), bypassLogin)); + localStorage.setItem(`sessionData${scene.sessionSlotId ? scene.sessionSlotId : ""}_${loggedInUser?.username}`, encrypt(JSON.stringify(sessionData), bypassLogin)); console.debug("Session data saved"); @@ -1212,7 +1219,7 @@ export class GameData { public tryExportData(dataType: GameDataType, slotId: integer = 0): Promise { return new Promise(resolve => { - const dataKey: string = `${getDataTypeKey(dataType, slotId)}_${loggedInUser.username}`; + const dataKey: string = `${getDataTypeKey(dataType, slotId)}_${loggedInUser?.username}`; const handleData = (dataStr: string) => { switch (dataType) { case GameDataType.SYSTEM: @@ -1251,7 +1258,7 @@ export class GameData { } public importData(dataType: GameDataType, slotId: integer = 0): void { - const dataKey = `${getDataTypeKey(dataType, slotId)}_${loggedInUser.username}`; + const dataKey = `${getDataTypeKey(dataType, slotId)}_${loggedInUser?.username}`; let saveFile: any = document.getElementById("saveFile"); if (saveFile) { @@ -1270,7 +1277,7 @@ export class GameData { reader.onload = (_ => { return e => { let dataName: string; - let dataStr = AES.decrypt(e.target.result.toString(), saveKey).toString(enc.Utf8); + let dataStr = AES.decrypt(e.target?.result?.toString()!, saveKey).toString(enc.Utf8); // TODO: is this bang correct? let valid = false; try { dataName = GameDataType[dataType].toLowerCase(); @@ -1293,10 +1300,11 @@ export class GameData { console.error(ex); } - const displayError = (error: string) => this.scene.ui.showText(error, null, () => this.scene.ui.showText(null, 0), Utils.fixedInt(1500)); + const displayError = (error: string) => this.scene.ui.showText(error, null, () => this.scene.ui.showText("", 0), Utils.fixedInt(1500)); + dataName = dataName!; // tell TS compiler that dataName is defined! if (!valid) { - return this.scene.ui.showText(`Your ${dataName} data could not be loaded. It may be corrupted.`, null, () => this.scene.ui.showText(null, 0), Utils.fixedInt(1500)); + return this.scene.ui.showText(`Your ${dataName} data could not be loaded. It may be corrupted.`, null, () => this.scene.ui.showText("", 0), Utils.fixedInt(1500)); } this.scene.ui.showText(`Your ${dataName} data will be overridden and the page will reload. Proceed?`, null, () => { @@ -1329,7 +1337,7 @@ export class GameData { } }, () => { this.scene.ui.revertMode(); - this.scene.ui.showText(null, 0); + this.scene.ui.showText("", 0); }, false, -98); }); }; @@ -1652,7 +1660,7 @@ export class GameData { return dexAttr & DexAttr.SHINY ? dexAttr & DexAttr.VARIANT_3 ? 3 : dexAttr & DexAttr.VARIANT_2 ? 2 : 1 : 0; } - getNaturesForAttr(natureAttr: integer): Nature[] { + getNaturesForAttr(natureAttr: integer = 0): Nature[] { const ret: Nature[] = []; for (let n = 0; n < 25; n++) { if (natureAttr & (1 << (n + 1))) { @@ -1707,7 +1715,7 @@ export class GameData { entry.hatchedCount = 0; } if (!entry.hasOwnProperty("natureAttr") || (entry.caughtAttr && !entry.natureAttr)) { - entry.natureAttr = this.defaultDexData[k].natureAttr || (1 << Utils.randInt(25, 1)); + entry.natureAttr = this.defaultDexData?.[k].natureAttr || (1 << Utils.randInt(25, 1)); } } } diff --git a/src/system/modifier-data.ts b/src/system/modifier-data.ts index 6f169280da1..0f3e28fe11c 100644 --- a/src/system/modifier-data.ts +++ b/src/system/modifier-data.ts @@ -1,6 +1,6 @@ import BattleScene from "../battle-scene"; import { PersistentModifier } from "../modifier/modifier"; -import { GeneratedPersistentModifierType, ModifierTypeGenerator, getModifierTypeFuncById } from "../modifier/modifier-type"; +import { GeneratedPersistentModifierType, ModifierType, ModifierTypeGenerator, getModifierTypeFuncById } from "../modifier/modifier-type"; export default class ModifierData { private player: boolean; @@ -27,14 +27,14 @@ export default class ModifierData { this.className = sourceModifier ? sourceModifier.constructor.name : source.className; } - toModifier(scene: BattleScene, constructor: any): PersistentModifier { + toModifier(scene: BattleScene, constructor: any): PersistentModifier | null { const typeFunc = getModifierTypeFuncById(this.typeId); if (!typeFunc) { return null; } try { - let type = typeFunc(); + let type: ModifierType | null = typeFunc(); type.id = this.typeId; if (type instanceof ModifierTypeGenerator) { diff --git a/src/system/pokemon-data.ts b/src/system/pokemon-data.ts index ca072c9eec8..8f094379434 100644 --- a/src/system/pokemon-data.ts +++ b/src/system/pokemon-data.ts @@ -33,8 +33,8 @@ export default class PokemonData { public ivs: integer[]; public nature: Nature; public natureOverride: Nature | -1; - public moveset: PokemonMove[]; - public status: Status; + public moveset: (PokemonMove | null)[]; + public status: Status | null; public friendship: integer; public metLevel: integer; public metBiome: Biome | -1; @@ -117,7 +117,7 @@ export default class PokemonData { if (!forHistory) { this.status = source.status ? new Status(source.status.effect, source.status.turnCount, source.status.cureTurn) - : undefined; + : null; } this.summonData = new PokemonSummonData(); diff --git a/src/system/voucher.ts b/src/system/voucher.ts index b06e6e5309e..0c71e3c0286 100644 --- a/src/system/voucher.ts +++ b/src/system/voucher.ts @@ -3,6 +3,7 @@ import i18next from "i18next"; import { Achv, AchvTier, achvs, getAchievementDescription } from "./achv"; import { PlayerGender } from "#enums/player-gender"; import { TrainerType } from "#enums/trainer-type"; +import { ConditionFn } from "#app/@types/common.js"; export enum VoucherType { REGULAR, @@ -16,15 +17,15 @@ export class Voucher { public voucherType: VoucherType; public description: string; - private conditionFunc: (scene: BattleScene, args: any[]) => boolean; + private conditionFunc: ConditionFn | undefined; - constructor(voucherType: VoucherType, description: string, conditionFunc?: (scene: BattleScene, args: any[]) => boolean) { + constructor(voucherType: VoucherType, description: string, conditionFunc?: ConditionFn) { this.description = description; this.voucherType = voucherType; this.conditionFunc = conditionFunc; } - validate(scene: BattleScene, args: any[]): boolean { + validate(scene: BattleScene, args?: any[]): boolean { return !this.conditionFunc || this.conditionFunc(scene, args); } diff --git a/src/test/abilities/battle_bond.test.ts b/src/test/abilities/battle_bond.test.ts index ce41f9b6603..1a5c71b4c15 100644 --- a/src/test/abilities/battle_bond.test.ts +++ b/src/test/abilities/battle_bond.test.ts @@ -46,12 +46,12 @@ describe("Abilities - BATTLE BOND", () => { await game.startBattle([Species.MAGIKARP, Species.GRENINJA]); const greninja = game.scene.getParty().find((p) => p.species.speciesId === Species.GRENINJA); - expect(greninja).not.toBe(undefined); - expect(greninja.formIndex).toBe(ashForm); + expect(greninja).toBeDefined(); + expect(greninja!.formIndex).toBe(ashForm); - greninja.hp = 0; - greninja.status = new Status(StatusEffect.FAINT); - expect(greninja.isFainted()).toBe(true); + greninja!.hp = 0; + greninja!.status = new Status(StatusEffect.FAINT); + expect(greninja!.isFainted()).toBe(true); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); await game.doKillOpponents(); @@ -59,7 +59,7 @@ describe("Abilities - BATTLE BOND", () => { game.doSelectModifier(); await game.phaseInterceptor.to(QuietFormChangePhase); - expect(greninja.formIndex).toBe(baseForm); + expect(greninja!.formIndex).toBe(baseForm); }, TIMEOUT ); diff --git a/src/test/abilities/disguise.test.ts b/src/test/abilities/disguise.test.ts index 3a6fd540d27..09a0dbf7f8a 100644 --- a/src/test/abilities/disguise.test.ts +++ b/src/test/abilities/disguise.test.ts @@ -47,11 +47,11 @@ describe("Abilities - DISGUISE", () => { const mimikyu = game.scene.getParty().find((p) => p.species.speciesId === Species.MIMIKYU); expect(mimikyu).not.toBe(undefined); - expect(mimikyu.formIndex).toBe(bustedForm); + expect(mimikyu!.formIndex).toBe(bustedForm); - mimikyu.hp = 0; - mimikyu.status = new Status(StatusEffect.FAINT); - expect(mimikyu.isFainted()).toBe(true); + mimikyu!.hp = 0; + mimikyu!.status = new Status(StatusEffect.FAINT); + expect(mimikyu!.isFainted()).toBe(true); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); await game.doKillOpponents(); @@ -59,7 +59,7 @@ describe("Abilities - DISGUISE", () => { game.doSelectModifier(); await game.phaseInterceptor.to(QuietFormChangePhase); - expect(mimikyu.formIndex).toBe(baseForm); + expect(mimikyu!.formIndex).toBe(baseForm); }, TIMEOUT ); @@ -80,17 +80,17 @@ describe("Abilities - DISGUISE", () => { await game.startBattle([Species.MIMIKYU]); - const mimikyu = game.scene.getPlayerPokemon(); - const damage = (Math.floor(mimikyu.getMaxHp()/8)); + const mimikyu = game.scene.getPlayerPokemon()!; + const damage = (Math.floor(mimikyu!.getMaxHp()/8)); expect(mimikyu).not.toBe(undefined); - expect(mimikyu.formIndex).toBe(baseForm); + expect(mimikyu!.formIndex).toBe(baseForm); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); await game.phaseInterceptor.to(TurnEndPhase); - expect(mimikyu.formIndex).toBe(bustedForm); - expect(game.scene.getEnemyPokemon().turnData.currDamageDealt).toBe(damage); + expect(mimikyu!.formIndex).toBe(bustedForm); + expect(game.scene.getEnemyPokemon()!.turnData.currDamageDealt).toBe(damage); }, TIMEOUT ); diff --git a/src/test/abilities/dry_skin.test.ts b/src/test/abilities/dry_skin.test.ts index 6da5ad08571..20b85eab767 100644 --- a/src/test/abilities/dry_skin.test.ts +++ b/src/test/abilities/dry_skin.test.ts @@ -38,7 +38,7 @@ describe("Abilities - Dry Skin", () => { await game.startBattle(); - const enemy = game.scene.getEnemyPokemon(); + const enemy = game.scene.getEnemyPokemon()!; expect(enemy).not.toBe(undefined); // first turn @@ -59,7 +59,7 @@ describe("Abilities - Dry Skin", () => { await game.startBattle(); - const enemy = game.scene.getEnemyPokemon(); + const enemy = game.scene.getEnemyPokemon()!; expect(enemy).not.toBe(undefined); enemy.hp = 1; @@ -82,7 +82,7 @@ describe("Abilities - Dry Skin", () => { await game.startBattle(); - const enemy = game.scene.getEnemyPokemon(); + const enemy = game.scene.getEnemyPokemon()!; const initialHP = 1000; enemy.hp = initialHP; @@ -108,7 +108,7 @@ describe("Abilities - Dry Skin", () => { await game.startBattle(); - const enemy = game.scene.getEnemyPokemon(); + const enemy = game.scene.getEnemyPokemon()!; expect(enemy).not.toBe(undefined); enemy.hp = 1; @@ -123,7 +123,7 @@ describe("Abilities - Dry Skin", () => { await game.startBattle(); - const enemy = game.scene.getEnemyPokemon(); + const enemy = game.scene.getEnemyPokemon()!; expect(enemy).not.toBe(undefined); enemy.hp = 1; @@ -139,7 +139,7 @@ describe("Abilities - Dry Skin", () => { await game.startBattle(); - const enemy = game.scene.getEnemyPokemon(); + const enemy = game.scene.getEnemyPokemon()!; expect(enemy).not.toBe(undefined); enemy.hp = 1; diff --git a/src/test/abilities/gulp_missile.test.ts b/src/test/abilities/gulp_missile.test.ts index f9329017006..b64cbe2ef10 100644 --- a/src/test/abilities/gulp_missile.test.ts +++ b/src/test/abilities/gulp_missile.test.ts @@ -58,7 +58,7 @@ describe("Abilities - Gulp Missile", () => { it("changes to Gulping Form if HP is over half when Surf or Dive is used", async () => { await game.startBattle([Species.CRAMORANT]); - const cramorant = game.scene.getPlayerPokemon(); + const cramorant = game.scene.getPlayerPokemon()!; game.doAttack(getMovePosition(game.scene, 0, Moves.DIVE)); await game.toNextTurn(); @@ -72,7 +72,7 @@ describe("Abilities - Gulp Missile", () => { it("changes to Gorging Form if HP is under half when Surf or Dive is used", async () => { await game.startBattle([Species.CRAMORANT]); - const cramorant = game.scene.getPlayerPokemon(); + const cramorant = game.scene.getPlayerPokemon()!; vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.49); expect(cramorant.getHpRatio()).toBe(.49); @@ -88,7 +88,7 @@ describe("Abilities - Gulp Missile", () => { game.override.enemyMoveset(Array(4).fill(Moves.TACKLE)); await game.startBattle([Species.CRAMORANT]); - const enemy = game.scene.getEnemyPokemon(); + const enemy = game.scene.getEnemyPokemon()!; vi.spyOn(enemy, "damageAndUpdate"); game.doAttack(getMovePosition(game.scene, 0, Moves.SURF)); @@ -101,7 +101,7 @@ describe("Abilities - Gulp Missile", () => { game.override.enemyMoveset(Array(4).fill(Moves.TAIL_WHIP)); await game.startBattle([Species.CRAMORANT]); - const cramorant = game.scene.getPlayerPokemon(); + const cramorant = game.scene.getPlayerPokemon()!; vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.55); game.doAttack(getMovePosition(game.scene, 0, Moves.SURF)); @@ -120,8 +120,8 @@ describe("Abilities - Gulp Missile", () => { game.override.enemyMoveset(Array(4).fill(Moves.TACKLE)); await game.startBattle([Species.CRAMORANT]); - const cramorant = game.scene.getPlayerPokemon(); - const enemy = game.scene.getEnemyPokemon(); + const cramorant = game.scene.getPlayerPokemon()!; + const enemy = game.scene.getEnemyPokemon()!; vi.spyOn(enemy, "damageAndUpdate"); vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.55); @@ -144,8 +144,8 @@ describe("Abilities - Gulp Missile", () => { game.override.enemyMoveset(Array(4).fill(Moves.TACKLE)); await game.startBattle([Species.CRAMORANT]); - const cramorant = game.scene.getPlayerPokemon(); - const enemy = game.scene.getEnemyPokemon(); + const cramorant = game.scene.getPlayerPokemon()!; + const enemy = game.scene.getEnemyPokemon()!; vi.spyOn(enemy, "damageAndUpdate"); vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.45); @@ -159,7 +159,7 @@ describe("Abilities - Gulp Missile", () => { await game.phaseInterceptor.to(TurnEndPhase); expect(enemy.damageAndUpdate).toHaveReturnedWith(getEffectDamage(enemy)); - expect(enemy.status.effect).toBe(StatusEffect.PARALYSIS); + expect(enemy.status?.effect).toBe(StatusEffect.PARALYSIS); expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_PIKACHU)).toBeUndefined(); expect(cramorant.formIndex).toBe(NORMAL_FORM); }); @@ -172,7 +172,7 @@ describe("Abilities - Gulp Missile", () => { .enemyLevel(5); await game.startBattle([Species.CRAMORANT]); - const cramorant = game.scene.getPlayerPokemon(); + const cramorant = game.scene.getPlayerPokemon()!; game.doAttack(getMovePosition(game.scene, 0, Moves.DIVE)); await game.toNextTurn(); @@ -194,8 +194,8 @@ describe("Abilities - Gulp Missile", () => { game.override.enemyMoveset(Array(4).fill(Moves.TACKLE)).enemyAbility(Abilities.MAGIC_GUARD); await game.startBattle([Species.CRAMORANT]); - const cramorant = game.scene.getPlayerPokemon(); - const enemy = game.scene.getEnemyPokemon(); + const cramorant = game.scene.getPlayerPokemon()!; + const enemy = game.scene.getEnemyPokemon()!; vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.55); @@ -218,7 +218,7 @@ describe("Abilities - Gulp Missile", () => { game.override.enemyMoveset(Array(4).fill(Moves.GASTRO_ACID)); await game.startBattle([Species.CRAMORANT]); - const cramorant = game.scene.getPlayerPokemon(); + const cramorant = game.scene.getPlayerPokemon()!; vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.55); game.doAttack(getMovePosition(game.scene, 0, Moves.SURF)); @@ -238,7 +238,7 @@ describe("Abilities - Gulp Missile", () => { game.override.enemyMoveset(Array(4).fill(Moves.SKILL_SWAP)); await game.startBattle([Species.CRAMORANT]); - const cramorant = game.scene.getPlayerPokemon(); + const cramorant = game.scene.getPlayerPokemon()!; vi.spyOn(cramorant, "getHpRatio").mockReturnValue(.55); game.doAttack(getMovePosition(game.scene, 0, Moves.SURF)); @@ -261,6 +261,6 @@ describe("Abilities - Gulp Missile", () => { game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); await game.phaseInterceptor.to(TurnStartPhase); - expect(game.scene.getEnemyPokemon().hasAbility(Abilities.GULP_MISSILE)).toBe(false); + expect(game.scene.getEnemyPokemon()?.hasAbility(Abilities.GULP_MISSILE)).toBe(false); }); }); diff --git a/src/test/abilities/hustle.test.ts b/src/test/abilities/hustle.test.ts index 63e54dfb157..4434dc62a6b 100644 --- a/src/test/abilities/hustle.test.ts +++ b/src/test/abilities/hustle.test.ts @@ -38,7 +38,7 @@ describe("Abilities - Hustle", () => { it("increases the user's Attack stat by 50%", async () => { await game.startBattle([Species.PIKACHU]); - const pikachu = game.scene.getPlayerPokemon(); + const pikachu = game.scene.getPlayerPokemon()!; const atk = pikachu.stats[Stat.ATK]; vi.spyOn(pikachu, "getBattleStat"); @@ -53,7 +53,7 @@ describe("Abilities - Hustle", () => { it("lowers the accuracy of the user's physical moves by 20%", async () => { await game.startBattle([Species.PIKACHU]); - const pikachu = game.scene.getPlayerPokemon(); + const pikachu = game.scene.getPlayerPokemon()!; vi.spyOn(pikachu, "getAccuracyMultiplier"); @@ -65,7 +65,7 @@ describe("Abilities - Hustle", () => { it("does not affect non-physical moves", async () => { await game.startBattle([Species.PIKACHU]); - const pikachu = game.scene.getPlayerPokemon(); + const pikachu = game.scene.getPlayerPokemon()!; const spatk = pikachu.stats[Stat.SPATK]; vi.spyOn(pikachu, "getBattleStat"); @@ -83,8 +83,8 @@ describe("Abilities - Hustle", () => { game.override.enemyLevel(30); await game.startBattle([Species.PIKACHU]); - const pikachu = game.scene.getPlayerPokemon(); - const enemyPokemon = game.scene.getEnemyPokemon(); + const pikachu = game.scene.getPlayerPokemon()!; + const enemyPokemon = game.scene.getEnemyPokemon()!; vi.spyOn(pikachu, "getAccuracyMultiplier"); vi.spyOn(allMoves[Moves.FISSURE], "calculateBattleAccuracy"); diff --git a/src/test/abilities/ice_face.test.ts b/src/test/abilities/ice_face.test.ts index a08a6a01b60..cdf8d5928ee 100644 --- a/src/test/abilities/ice_face.test.ts +++ b/src/test/abilities/ice_face.test.ts @@ -40,11 +40,11 @@ describe("Abilities - Ice Face", () => { await game.phaseInterceptor.to(MoveEndPhase); - const eiscue = game.scene.getEnemyPokemon(); + const eiscue = game.scene.getEnemyPokemon()!; expect(eiscue.isFullHp()).toBe(true); expect(eiscue.formIndex).toBe(noiceForm); - expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBe(undefined); + expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBeUndefined(); }); it("takes no damage from the first hit of multihit physical move and transforms to Noice", async () => { @@ -54,7 +54,7 @@ describe("Abilities - Ice Face", () => { game.doAttack(getMovePosition(game.scene, 0, Moves.SURGING_STRIKES)); - const eiscue = game.scene.getEnemyPokemon(); + const eiscue = game.scene.getEnemyPokemon()!; expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBeDefined(); // First hit @@ -82,7 +82,7 @@ describe("Abilities - Ice Face", () => { await game.phaseInterceptor.to(MoveEndPhase); - const eiscue = game.scene.getEnemyPokemon(); + const eiscue = game.scene.getEnemyPokemon()!; expect(eiscue.getTag(BattlerTagType.ICE_FACE)).not.toBe(undefined); expect(eiscue.formIndex).toBe(icefaceForm); @@ -96,7 +96,7 @@ describe("Abilities - Ice Face", () => { await game.phaseInterceptor.to(MoveEndPhase); - const eiscue = game.scene.getEnemyPokemon(); + const eiscue = game.scene.getEnemyPokemon()!; expect(eiscue.getTag(BattlerTagType.ICE_FACE)).not.toBe(undefined); expect(eiscue.formIndex).toBe(icefaceForm); @@ -112,15 +112,15 @@ describe("Abilities - Ice Face", () => { await game.phaseInterceptor.to(MoveEndPhase); - const eiscue = game.scene.getEnemyPokemon(); + const eiscue = game.scene.getEnemyPokemon()!; expect(eiscue.isFullHp()).toBe(true); expect(eiscue.formIndex).toBe(noiceForm); - expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBe(undefined); + expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBeUndefined(); await game.phaseInterceptor.to(MoveEndPhase); - expect(eiscue.getTag(BattlerTagType.ICE_FACE)).not.toBe(undefined); + expect(eiscue.getTag(BattlerTagType.ICE_FACE)).not.toBeNull(); expect(eiscue.formIndex).toBe(icefaceForm); }); @@ -133,9 +133,9 @@ describe("Abilities - Ice Face", () => { game.doAttack(getMovePosition(game.scene, 0, Moves.SNOWSCAPE)); await game.phaseInterceptor.to(TurnEndPhase); - let eiscue = game.scene.getPlayerPokemon(); + let eiscue = game.scene.getPlayerPokemon()!; - expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBe(undefined); + expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBeUndefined(); expect(eiscue.formIndex).toBe(noiceForm); expect(eiscue.isFullHp()).toBe(true); @@ -145,7 +145,7 @@ describe("Abilities - Ice Face", () => { game.doSwitchPokemon(1); await game.phaseInterceptor.to(QuietFormChangePhase); - eiscue = game.scene.getPlayerPokemon(); + eiscue = game.scene.getPlayerPokemon()!; expect(eiscue.formIndex).toBe(icefaceForm); expect(eiscue.getTag(BattlerTagType.ICE_FACE)).not.toBe(undefined); @@ -158,17 +158,17 @@ describe("Abilities - Ice Face", () => { await game.startBattle([Species.EISCUE]); game.doAttack(getMovePosition(game.scene, 0, Moves.HAIL)); - const eiscue = game.scene.getPlayerPokemon(); + const eiscue = game.scene.getPlayerPokemon()!; await game.phaseInterceptor.to(QuietFormChangePhase); expect(eiscue.formIndex).toBe(noiceForm); - expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBe(undefined); + expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBeUndefined(); await game.phaseInterceptor.to(TurnEndPhase); expect(eiscue.formIndex).toBe(noiceForm); - expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBe(undefined); + expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBeUndefined(); }); it("persists form change when switched out", async () => { @@ -179,9 +179,9 @@ describe("Abilities - Ice Face", () => { game.doAttack(getMovePosition(game.scene, 0, Moves.ICE_BEAM)); await game.phaseInterceptor.to(TurnEndPhase); - let eiscue = game.scene.getPlayerPokemon(); + let eiscue = game.scene.getPlayerPokemon()!; - expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBe(undefined); + expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBeUndefined(); expect(eiscue.formIndex).toBe(noiceForm); expect(eiscue.isFullHp()).toBe(true); @@ -192,7 +192,7 @@ describe("Abilities - Ice Face", () => { eiscue = game.scene.getParty()[1]; expect(eiscue.formIndex).toBe(noiceForm); - expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBe(undefined); + expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBeUndefined(); }); it("reverts to Ice Face on arena reset", async () => { @@ -205,10 +205,10 @@ describe("Abilities - Ice Face", () => { await game.startBattle([Species.EISCUE]); - const eiscue = game.scene.getPlayerPokemon(); + const eiscue = game.scene.getPlayerPokemon()!; expect(eiscue.formIndex).toBe(noiceForm); - expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBe(undefined); + expect(eiscue.getTag(BattlerTagType.ICE_FACE)).toBeUndefined(); game.doAttack(getMovePosition(game.scene, 0, Moves.ICE_BEAM)); await game.doKillOpponents(); @@ -229,7 +229,7 @@ describe("Abilities - Ice Face", () => { await game.phaseInterceptor.to(TurnEndPhase); - const eiscue = game.scene.getEnemyPokemon(); + const eiscue = game.scene.getEnemyPokemon()!; expect(eiscue.getTag(BattlerTagType.ICE_FACE)).not.toBe(undefined); expect(eiscue.formIndex).toBe(icefaceForm); @@ -245,7 +245,7 @@ describe("Abilities - Ice Face", () => { await game.phaseInterceptor.to(TurnEndPhase); - const eiscue = game.scene.getEnemyPokemon(); + const eiscue = game.scene.getEnemyPokemon()!; expect(eiscue.getTag(BattlerTagType.ICE_FACE)).not.toBe(undefined); expect(eiscue.formIndex).toBe(icefaceForm); @@ -261,10 +261,10 @@ describe("Abilities - Ice Face", () => { await game.phaseInterceptor.to(TurnInitPhase); - const eiscue = game.scene.getEnemyPokemon(); + const eiscue = game.scene.getEnemyPokemon()!; expect(eiscue.getTag(BattlerTagType.ICE_FACE)).not.toBe(undefined); expect(eiscue.formIndex).toBe(icefaceForm); - expect(game.scene.getPlayerPokemon().hasAbility(Abilities.TRACE)).toBe(true); + expect(game.scene.getPlayerPokemon()!.hasAbility(Abilities.TRACE)).toBe(true); }); }); diff --git a/src/test/abilities/libero.test.ts b/src/test/abilities/libero.test.ts index c38ec082169..e4d99d5b56c 100644 --- a/src/test/abilities/libero.test.ts +++ b/src/test/abilities/libero.test.ts @@ -46,7 +46,7 @@ describe("Abilities - Protean", () => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); @@ -64,7 +64,7 @@ describe("Abilities - Protean", () => { await game.startBattle([Species.MAGIKARP, Species.BULBASAUR]); - let leadPokemon = game.scene.getPlayerPokemon(); + let leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); @@ -86,7 +86,7 @@ describe("Abilities - Protean", () => { game.doSwitchPokemon(1); await game.toNextTurn(); - leadPokemon = game.scene.getPlayerPokemon(); + leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); @@ -104,7 +104,7 @@ describe("Abilities - Protean", () => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); game.scene.arena.weather = new Weather(WeatherType.SUNNY); @@ -128,7 +128,7 @@ describe("Abilities - Protean", () => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); @@ -150,7 +150,7 @@ describe("Abilities - Protean", () => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); game.scene.arena.biomeType = Biome.MOUNTAIN; @@ -169,7 +169,7 @@ describe("Abilities - Protean", () => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.DIG)); @@ -188,7 +188,7 @@ describe("Abilities - Protean", () => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); @@ -196,7 +196,7 @@ describe("Abilities - Protean", () => { vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValueOnce(false); await game.phaseInterceptor.to(TurnEndPhase); - const enemyPokemon = game.scene.getEnemyPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon.isFullHp()).toBe(true); testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.TACKLE); }, @@ -211,7 +211,7 @@ describe("Abilities - Protean", () => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); @@ -230,7 +230,7 @@ describe("Abilities - Protean", () => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); @@ -248,7 +248,7 @@ describe("Abilities - Protean", () => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); leadPokemon.summonData.types = [allMoves[Moves.SPLASH].defaultType]; @@ -267,7 +267,7 @@ describe("Abilities - Protean", () => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); vi.spyOn(leadPokemon, "isTerastallized").mockReturnValue(true); @@ -287,7 +287,7 @@ describe("Abilities - Protean", () => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.STRUGGLE)); @@ -305,7 +305,7 @@ describe("Abilities - Protean", () => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.BURN_UP)); @@ -324,7 +324,7 @@ describe("Abilities - Protean", () => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.TRICK_OR_TREAT)); @@ -342,7 +342,7 @@ describe("Abilities - Protean", () => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.CURSE)); diff --git a/src/test/abilities/magic_guard.test.ts b/src/test/abilities/magic_guard.test.ts index 18e28284f72..23b3bad828f 100644 --- a/src/test/abilities/magic_guard.test.ts +++ b/src/test/abilities/magic_guard.test.ts @@ -53,9 +53,10 @@ describe("Abilities - Magic Guard", () => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; - const enemyPokemon = game.scene.getEnemyPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon()!; + expect(enemyPokemon).toBeDefined(); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); @@ -79,7 +80,7 @@ describe("Abilities - Magic Guard", () => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); @@ -91,7 +92,7 @@ describe("Abilities - Magic Guard", () => { * - The Pokemon's CatchRateMultiplier should be 1.5 */ expect(leadPokemon.hp).toBe(leadPokemon.getMaxHp()); - expect(getStatusEffectCatchRateMultiplier(leadPokemon.status.effect)).toBe(1.5); + expect(getStatusEffectCatchRateMultiplier(leadPokemon.status!.effect)).toBe(1.5); }, TIMEOUT ); @@ -103,7 +104,7 @@ describe("Abilities - Magic Guard", () => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); @@ -127,7 +128,7 @@ describe("Abilities - Magic Guard", () => { game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); - const enemyPokemon = game.scene.getEnemyPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon()!; await game.phaseInterceptor.to(TurnEndPhase); @@ -138,7 +139,7 @@ describe("Abilities - Magic Guard", () => { * - The enemy Pokemon's hypothetical CatchRateMultiplier should be 1.5 */ expect(enemyPokemon.hp).toBe(enemyPokemon.getMaxHp()); - expect(getStatusEffectCatchRateMultiplier(enemyPokemon.status.effect)).toBe(1.5); + expect(getStatusEffectCatchRateMultiplier(enemyPokemon.status!.effect)).toBe(1.5); }, TIMEOUT ); @@ -151,9 +152,9 @@ describe("Abilities - Magic Guard", () => { game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); - const enemyPokemon = game.scene.getEnemyPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon()!; - const toxicStartCounter = enemyPokemon.status.turnCount; + const toxicStartCounter = enemyPokemon.status!.turnCount; //should be 0 await game.phaseInterceptor.to(TurnEndPhase); @@ -165,23 +166,23 @@ describe("Abilities - Magic Guard", () => { * - The enemy Pokemon's hypothetical CatchRateMultiplier should be 1.5 */ expect(enemyPokemon.hp).toBe(enemyPokemon.getMaxHp()); - expect(enemyPokemon.status.turnCount).toBeGreaterThan(toxicStartCounter); - expect(getStatusEffectCatchRateMultiplier(enemyPokemon.status.effect)).toBe(1.5); + expect(enemyPokemon.status!.turnCount).toBeGreaterThan(toxicStartCounter); + expect(getStatusEffectCatchRateMultiplier(enemyPokemon.status!.effect)).toBe(1.5); }, TIMEOUT ); it("Magic Guard prevents damage caused by entry hazards", async () => { //Adds and applies Spikes to both sides of the arena - const newTag = getArenaTag(ArenaTagType.SPIKES, 5, Moves.SPIKES, 0, 0, ArenaTagSide.BOTH); + const newTag = getArenaTag(ArenaTagType.SPIKES, 5, Moves.SPIKES, 0, 0, ArenaTagSide.BOTH)!; game.scene.arena.tags.push(newTag); await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); - const enemyPokemon = game.scene.getEnemyPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon()!; await game.phaseInterceptor.to(TurnEndPhase); @@ -197,17 +198,17 @@ describe("Abilities - Magic Guard", () => { it("Magic Guard does not prevent poison from Toxic Spikes", async () => { //Adds and applies Spikes to both sides of the arena - const playerTag = getArenaTag(ArenaTagType.TOXIC_SPIKES, 5, Moves.TOXIC_SPIKES, 0, 0, ArenaTagSide.PLAYER); - const enemyTag = getArenaTag(ArenaTagType.TOXIC_SPIKES, 5, Moves.TOXIC_SPIKES, 0, 0, ArenaTagSide.ENEMY); + const playerTag = getArenaTag(ArenaTagType.TOXIC_SPIKES, 5, Moves.TOXIC_SPIKES, 0, 0, ArenaTagSide.PLAYER)!; + const enemyTag = getArenaTag(ArenaTagType.TOXIC_SPIKES, 5, Moves.TOXIC_SPIKES, 0, 0, ArenaTagSide.ENEMY)!; game.scene.arena.tags.push(playerTag); game.scene.arena.tags.push(enemyTag); await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); - const enemyPokemon = game.scene.getEnemyPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon()!; await game.phaseInterceptor.to(TurnEndPhase); @@ -217,8 +218,8 @@ describe("Abilities - Magic Guard", () => { * - The player Pokemon (with Magic Guard) has not taken damage from poison * - The enemy Pokemon (without Magic Guard) has taken damage from poison */ - expect(leadPokemon.status.effect).toBe(StatusEffect.POISON); - expect(enemyPokemon.status.effect).toBe(StatusEffect.POISON); + expect(leadPokemon.status!.effect).toBe(StatusEffect.POISON); + expect(enemyPokemon.status!.effect).toBe(StatusEffect.POISON); expect(leadPokemon.hp).toBe(leadPokemon.getMaxHp()); expect(enemyPokemon.hp).toBeLessThan(enemyPokemon.getMaxHp()); }, TIMEOUT @@ -230,11 +231,11 @@ describe("Abilities - Magic Guard", () => { game.override.moveset([Moves.CURSE]); game.override.enemyAbility(Abilities.MAGIC_GUARD); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; game.doAttack(getMovePosition(game.scene, 0, Moves.CURSE)); - const enemyPokemon = game.scene.getEnemyPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon()!; await game.phaseInterceptor.to(TurnEndPhase); @@ -254,7 +255,7 @@ describe("Abilities - Magic Guard", () => { game.override.moveset([Moves.HIGH_JUMP_KICK]); await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; game.doAttack(getMovePosition(game.scene, 0, Moves.HIGH_JUMP_KICK)); await game.phaseInterceptor.to(MoveEffectPhase, false); @@ -274,7 +275,7 @@ describe("Abilities - Magic Guard", () => { game.override.moveset([Moves.TAKE_DOWN]); await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; game.doAttack(getMovePosition(game.scene, 0, Moves.TAKE_DOWN)); @@ -292,7 +293,7 @@ describe("Abilities - Magic Guard", () => { game.override.moveset([Moves.STRUGGLE]); await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; game.doAttack(getMovePosition(game.scene, 0, Moves.STRUGGLE)); @@ -311,7 +312,7 @@ describe("Abilities - Magic Guard", () => { game.override.moveset([Moves.STEEL_BEAM]); await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; game.doAttack(getMovePosition(game.scene, 0, Moves.STEEL_BEAM)); @@ -339,7 +340,7 @@ describe("Abilities - Magic Guard", () => { game.override.moveset([Moves.BELLY_DRUM]); await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; game.doAttack(getMovePosition(game.scene, 0, Moves.BELLY_DRUM)); @@ -362,7 +363,7 @@ describe("Abilities - Magic Guard", () => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); @@ -374,7 +375,7 @@ describe("Abilities - Magic Guard", () => { * - The player Pokemon is asleep */ expect(leadPokemon.hp).toBe(leadPokemon.getMaxHp()); - expect(leadPokemon.status.effect).toBe(StatusEffect.SLEEP); + expect(leadPokemon.status!.effect).toBe(StatusEffect.SLEEP); }, TIMEOUT ); @@ -385,9 +386,9 @@ describe("Abilities - Magic Guard", () => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; - const enemyPokemon = game.scene.getEnemyPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon()!; enemyPokemon.hp = 1; game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); @@ -410,9 +411,9 @@ describe("Abilities - Magic Guard", () => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; - const enemyPokemon = game.scene.getEnemyPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon()!; game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); await game.phaseInterceptor.to(TurnEndPhase); @@ -434,9 +435,9 @@ describe("Abilities - Magic Guard", () => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; - const enemyPokemon = game.scene.getEnemyPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon()!; game.doAttack(getMovePosition(game.scene, 0, Moves.ABSORB)); await game.phaseInterceptor.to(TurnEndPhase); @@ -457,7 +458,7 @@ describe("Abilities - Magic Guard", () => { game.override.weather(WeatherType.SUNNY); await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); await game.phaseInterceptor.to(TurnEndPhase); diff --git a/src/test/abilities/parental_bond.test.ts b/src/test/abilities/parental_bond.test.ts index 45d65fca083..1fb27ad7e1f 100644 --- a/src/test/abilities/parental_bond.test.ts +++ b/src/test/abilities/parental_bond.test.ts @@ -47,10 +47,10 @@ describe("Abilities - Parental Bond", () => { await game.startBattle([Species.CHARIZARD]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - const enemyPokemon = game.scene.getEnemyPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).not.toBe(undefined); let enemyStartingHp = enemyPokemon.hp; @@ -80,10 +80,10 @@ describe("Abilities - Parental Bond", () => { await game.startBattle([Species.CHARIZARD]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - const enemyPokemon = game.scene.getEnemyPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.POWER_UP_PUNCH)); @@ -102,10 +102,10 @@ describe("Abilities - Parental Bond", () => { await game.startBattle([Species.CHARIZARD]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - const enemyPokemon = game.scene.getEnemyPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.BABY_DOLL_EYES)); @@ -122,10 +122,10 @@ describe("Abilities - Parental Bond", () => { await game.startBattle([Species.CHARIZARD]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - const enemyPokemon = game.scene.getEnemyPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.DOUBLE_HIT)); @@ -147,10 +147,10 @@ describe("Abilities - Parental Bond", () => { await game.startBattle([Species.CHARIZARD]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - const enemyPokemon = game.scene.getEnemyPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.SELF_DESTRUCT)); @@ -168,10 +168,10 @@ describe("Abilities - Parental Bond", () => { await game.startBattle([Species.CHARIZARD]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - const enemyPokemon = game.scene.getEnemyPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.ROLLOUT)); @@ -192,10 +192,10 @@ describe("Abilities - Parental Bond", () => { await game.startBattle([Species.CHARIZARD]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - const enemyPokemon = game.scene.getEnemyPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).not.toBe(undefined); const enemyStartingHp = enemyPokemon.hp; @@ -215,10 +215,10 @@ describe("Abilities - Parental Bond", () => { await game.startBattle([Species.CHARIZARD]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - const enemyPokemon = game.scene.getEnemyPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).not.toBe(undefined); const playerStartingHp = leadPokemon.hp; @@ -268,10 +268,10 @@ describe("Abilities - Parental Bond", () => { await game.startBattle([Species.CHARIZARD]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - const enemyPokemon = game.scene.getEnemyPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.EARTHQUAKE)); @@ -288,10 +288,10 @@ describe("Abilities - Parental Bond", () => { await game.startBattle([Species.PIDGEOT]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - const enemyPokemon = game.scene.getEnemyPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.MIND_BLOWN)); @@ -314,10 +314,10 @@ describe("Abilities - Parental Bond", () => { await game.startBattle([Species.CHARIZARD]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - const enemyPokemon = game.scene.getEnemyPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.BURN_UP)); @@ -342,10 +342,10 @@ describe("Abilities - Parental Bond", () => { await game.startBattle([Species.CHARIZARD]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - const enemyPokemon = game.scene.getEnemyPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); @@ -364,10 +364,10 @@ describe("Abilities - Parental Bond", () => { await game.startBattle([Species.CHARIZARD]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - const enemyPokemon = game.scene.getEnemyPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).not.toBe(undefined); const enemyStartingHp = enemyPokemon.hp; @@ -395,10 +395,10 @@ describe("Abilities - Parental Bond", () => { await game.startBattle([Species.CHARIZARD]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - const enemyPokemon = game.scene.getEnemyPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).not.toBe(undefined); const enemyStartingHp = enemyPokemon.hp; @@ -425,10 +425,10 @@ describe("Abilities - Parental Bond", () => { await game.startBattle([Species.CHARIZARD]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - const enemyPokemon = game.scene.getEnemyPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.HYPER_BEAM)); @@ -455,10 +455,10 @@ describe("Abilities - Parental Bond", () => { await game.startBattle([Species.CHARIZARD]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - const enemyPokemon = game.scene.getEnemyPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.ANCHOR_SHOT)); @@ -487,10 +487,10 @@ describe("Abilities - Parental Bond", () => { await game.startBattle([Species.CHARIZARD]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - const enemyPokemon = game.scene.getEnemyPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.SMACK_DOWN)); @@ -516,10 +516,10 @@ describe("Abilities - Parental Bond", () => { await game.startBattle([Species.CHARIZARD, Species.BLASTOISE]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - const enemyPokemon = game.scene.getEnemyPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.U_TURN)); @@ -542,10 +542,10 @@ describe("Abilities - Parental Bond", () => { await game.startBattle([Species.CHARIZARD]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - const enemyPokemon = game.scene.getEnemyPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.WAKE_UP_SLAP)); @@ -572,10 +572,10 @@ describe("Abilities - Parental Bond", () => { await game.startBattle([Species.CHARIZARD]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - const enemyPokemon = game.scene.getEnemyPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); @@ -594,10 +594,10 @@ describe("Abilities - Parental Bond", () => { await game.startBattle([Species.CHARIZARD]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - const enemyPokemon = game.scene.getEnemyPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.WATER_GUN)); diff --git a/src/test/abilities/pastel_veil.test.ts b/src/test/abilities/pastel_veil.test.ts index 8035d54a7e5..e3d52a720b3 100644 --- a/src/test/abilities/pastel_veil.test.ts +++ b/src/test/abilities/pastel_veil.test.ts @@ -51,7 +51,7 @@ describe("Abilities - Pastel Veil", () => { it("it heals the poisoned status condition of allies if user is sent out into battle", async () => { await game.startBattle([Species.MAGIKARP, Species.MAGIKARP, Species.GALAR_PONYTA]); - const ponyta = game.scene.getParty().find(p => p.species.speciesId === Species.GALAR_PONYTA); + const ponyta = game.scene.getParty().find(p => p.species.speciesId === Species.GALAR_PONYTA)!; vi.spyOn(ponyta, "getAbility").mockReturnValue(allAbilities[Abilities.PASTEL_VEIL]); @@ -66,7 +66,7 @@ describe("Abilities - Pastel Veil", () => { const poisonedMon = game.scene.getPlayerField().find(p => p.status?.effect === StatusEffect.POISON); await game.phaseInterceptor.to(CommandPhase); - game.doAttack(getMovePosition(game.scene, (poisonedMon.getBattlerIndex() as BattlerIndex.PLAYER | BattlerIndex.PLAYER_2), Moves.SPLASH)); + game.doAttack(getMovePosition(game.scene, (poisonedMon!.getBattlerIndex() as BattlerIndex.PLAYER | BattlerIndex.PLAYER_2), Moves.SPLASH)); game.doSwitchPokemon(2); await game.phaseInterceptor.to(TurnEndPhase); diff --git a/src/test/abilities/power_construct.test.ts b/src/test/abilities/power_construct.test.ts index 769499c0e53..dd8fd836e51 100644 --- a/src/test/abilities/power_construct.test.ts +++ b/src/test/abilities/power_construct.test.ts @@ -47,11 +47,11 @@ describe("Abilities - POWER CONSTRUCT", () => { const zygarde = game.scene.getParty().find((p) => p.species.speciesId === Species.ZYGARDE); expect(zygarde).not.toBe(undefined); - expect(zygarde.formIndex).toBe(completeForm); + expect(zygarde!.formIndex).toBe(completeForm); - zygarde.hp = 0; - zygarde.status = new Status(StatusEffect.FAINT); - expect(zygarde.isFainted()).toBe(true); + zygarde!.hp = 0; + zygarde!.status = new Status(StatusEffect.FAINT); + expect(zygarde!.isFainted()).toBe(true); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); await game.doKillOpponents(); @@ -59,7 +59,7 @@ describe("Abilities - POWER CONSTRUCT", () => { game.doSelectModifier(); await game.phaseInterceptor.to(QuietFormChangePhase); - expect(zygarde.formIndex).toBe(baseForm); + expect(zygarde!.formIndex).toBe(baseForm); }, TIMEOUT ); diff --git a/src/test/abilities/protean.test.ts b/src/test/abilities/protean.test.ts index 7c6cca2eccd..63d1a0ea719 100644 --- a/src/test/abilities/protean.test.ts +++ b/src/test/abilities/protean.test.ts @@ -46,7 +46,7 @@ describe("Abilities - Protean", () => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); @@ -64,7 +64,7 @@ describe("Abilities - Protean", () => { await game.startBattle([Species.MAGIKARP, Species.BULBASAUR]); - let leadPokemon = game.scene.getPlayerPokemon(); + let leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); @@ -86,7 +86,7 @@ describe("Abilities - Protean", () => { game.doSwitchPokemon(1); await game.toNextTurn(); - leadPokemon = game.scene.getPlayerPokemon(); + leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); @@ -104,7 +104,7 @@ describe("Abilities - Protean", () => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); game.scene.arena.weather = new Weather(WeatherType.SUNNY); @@ -128,7 +128,7 @@ describe("Abilities - Protean", () => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); @@ -150,7 +150,7 @@ describe("Abilities - Protean", () => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); game.scene.arena.biomeType = Biome.MOUNTAIN; @@ -169,7 +169,7 @@ describe("Abilities - Protean", () => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.DIG)); @@ -188,7 +188,7 @@ describe("Abilities - Protean", () => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); @@ -196,7 +196,7 @@ describe("Abilities - Protean", () => { vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValueOnce(false); await game.phaseInterceptor.to(TurnEndPhase); - const enemyPokemon = game.scene.getEnemyPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon.isFullHp()).toBe(true); testPokemonTypeMatchesDefaultMoveType(leadPokemon, Moves.TACKLE); }, @@ -211,7 +211,7 @@ describe("Abilities - Protean", () => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); @@ -230,7 +230,7 @@ describe("Abilities - Protean", () => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); @@ -248,7 +248,7 @@ describe("Abilities - Protean", () => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); leadPokemon.summonData.types = [allMoves[Moves.SPLASH].defaultType]; @@ -267,7 +267,7 @@ describe("Abilities - Protean", () => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); vi.spyOn(leadPokemon, "isTerastallized").mockReturnValue(true); @@ -287,7 +287,7 @@ describe("Abilities - Protean", () => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.STRUGGLE)); @@ -305,7 +305,7 @@ describe("Abilities - Protean", () => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.BURN_UP)); @@ -324,7 +324,7 @@ describe("Abilities - Protean", () => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.TRICK_OR_TREAT)); @@ -342,7 +342,7 @@ describe("Abilities - Protean", () => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.CURSE)); diff --git a/src/test/abilities/quick_draw.test.ts b/src/test/abilities/quick_draw.test.ts index 56f21cab838..75bb9ec6a0a 100644 --- a/src/test/abilities/quick_draw.test.ts +++ b/src/test/abilities/quick_draw.test.ts @@ -41,8 +41,8 @@ describe("Abilities - Quick Draw", () => { test("makes pokemon going first in its priority bracket", async () => { await game.startBattle(); - const pokemon = game.scene.getPlayerPokemon(); - const enemy = game.scene.getEnemyPokemon(); + const pokemon = game.scene.getPlayerPokemon()!; + const enemy = game.scene.getEnemyPokemon()!; pokemon.hp = 1; enemy.hp = 1; @@ -61,8 +61,8 @@ describe("Abilities - Quick Draw", () => { }, async () => { await game.startBattle(); - const pokemon = game.scene.getPlayerPokemon(); - const enemy = game.scene.getEnemyPokemon(); + const pokemon = game.scene.getPlayerPokemon()!; + const enemy = game.scene.getEnemyPokemon()!; pokemon.hp = 1; enemy.hp = 1; @@ -81,8 +81,8 @@ describe("Abilities - Quick Draw", () => { await game.startBattle(); - const pokemon = game.scene.getPlayerPokemon(); - const enemy = game.scene.getEnemyPokemon(); + const pokemon = game.scene.getPlayerPokemon()!; + const enemy = game.scene.getEnemyPokemon()!; pokemon.hp = 1; enemy.hp = 1; diff --git a/src/test/abilities/sand_spit.test.ts b/src/test/abilities/sand_spit.test.ts index dacfe7ad27e..d3d1a8e0028 100644 --- a/src/test/abilities/sand_spit.test.ts +++ b/src/test/abilities/sand_spit.test.ts @@ -42,7 +42,7 @@ describe("Ability Timing", () => { game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); await game.toNextTurn(); - expect(game.scene.arena.weather.weatherType).toBe(WeatherType.SANDSTORM); + expect(game.scene.arena.weather?.weatherType).toBe(WeatherType.SANDSTORM); }, 20000); it("should not trigger when targetted with status moves", async() => { diff --git a/src/test/abilities/sap_sipper.test.ts b/src/test/abilities/sap_sipper.test.ts index 20a677a3244..6fbe57978e9 100644 --- a/src/test/abilities/sap_sipper.test.ts +++ b/src/test/abilities/sap_sipper.test.ts @@ -87,7 +87,7 @@ describe("Abilities - Sap Sipper", () => { await game.phaseInterceptor.to(TurnEndPhase); expect(game.scene.arena.terrain).toBeDefined(); - expect(game.scene.arena.terrain.terrainType).toBe(TerrainType.GRASSY); + expect(game.scene.arena.terrain!.terrainType).toBe(TerrainType.GRASSY); expect(game.scene.getEnemyParty()[0].summonData.battleStats[BattleStat.ATK]).toBe(0); }); diff --git a/src/test/abilities/schooling.test.ts b/src/test/abilities/schooling.test.ts index 7671534a549..e55b7795006 100644 --- a/src/test/abilities/schooling.test.ts +++ b/src/test/abilities/schooling.test.ts @@ -45,7 +45,7 @@ describe("Abilities - SCHOOLING", () => { await game.startBattle([Species.MAGIKARP, Species.WISHIWASHI]); - const wishiwashi = game.scene.getParty().find((p) => p.species.speciesId === Species.WISHIWASHI); + const wishiwashi = game.scene.getParty().find((p) => p.species.speciesId === Species.WISHIWASHI)!; expect(wishiwashi).not.toBe(undefined); expect(wishiwashi.formIndex).toBe(schoolForm); diff --git a/src/test/abilities/serene_grace.test.ts b/src/test/abilities/serene_grace.test.ts index 3e8ff0bbea0..c486604e4f9 100644 --- a/src/test/abilities/serene_grace.test.ts +++ b/src/test/abilities/serene_grace.test.ts @@ -66,8 +66,8 @@ describe("Abilities - Serene Grace", () => { expect(move.id).toBe(Moves.AIR_SLASH); const chance = new Utils.IntegerHolder(move.chance); - console.log(move.chance + " Their ability is " + phase.getUserPokemon().getAbility().name); - applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon(), null, chance, move, phase.getTarget(), false); + console.log(move.chance + " Their ability is " + phase.getUserPokemon()!.getAbility().name); + applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, chance, move, phase.getTarget(), false); expect(chance.value).toBe(30); }, 20000); @@ -99,7 +99,7 @@ describe("Abilities - Serene Grace", () => { expect(move.id).toBe(Moves.AIR_SLASH); const chance = new Utils.IntegerHolder(move.chance); - applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon(), null, chance, move, phase.getTarget(), false); + applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, chance, move, phase.getTarget(), false); expect(chance.value).toBe(60); }, 20000); diff --git a/src/test/abilities/sheer_force.test.ts b/src/test/abilities/sheer_force.test.ts index d3e1ae904cc..3f1bcadd43f 100644 --- a/src/test/abilities/sheer_force.test.ts +++ b/src/test/abilities/sheer_force.test.ts @@ -69,8 +69,8 @@ describe("Abilities - Sheer Force", () => { const power = new Utils.IntegerHolder(move.power); const chance = new Utils.IntegerHolder(move.chance); - applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon(), null, chance, move, phase.getTarget(), false); - applyPreAttackAbAttrs(MovePowerBoostAbAttr, phase.getUserPokemon(), phase.getTarget(), move, power); + applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, chance, move, phase.getTarget(), false); + applyPreAttackAbAttrs(MovePowerBoostAbAttr, phase.getUserPokemon()!, phase.getTarget()!, move, power); expect(chance.value).toBe(0); expect(power.value).toBe(move.power * 5461/4096); @@ -108,8 +108,8 @@ describe("Abilities - Sheer Force", () => { const power = new Utils.IntegerHolder(move.power); const chance = new Utils.IntegerHolder(move.chance); - applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon(), null, chance, move, phase.getTarget(), false); - applyPreAttackAbAttrs(MovePowerBoostAbAttr, phase.getUserPokemon(), phase.getTarget(), move, power); + applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, chance, move, phase.getTarget(), false); + applyPreAttackAbAttrs(MovePowerBoostAbAttr, phase.getUserPokemon()!, phase.getTarget()!, move, power); expect(chance.value).toBe(-1); expect(power.value).toBe(move.power); @@ -147,8 +147,8 @@ describe("Abilities - Sheer Force", () => { const power = new Utils.IntegerHolder(move.power); const chance = new Utils.IntegerHolder(move.chance); - applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon(), null, chance, move, phase.getTarget(), false); - applyPreAttackAbAttrs(MovePowerBoostAbAttr, phase.getUserPokemon(), phase.getTarget(), move, power); + applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, chance, move, phase.getTarget(), false); + applyPreAttackAbAttrs(MovePowerBoostAbAttr, phase.getUserPokemon()!, phase.getTarget()!, move, power); expect(chance.value).toBe(-1); expect(power.value).toBe(move.power); @@ -187,8 +187,8 @@ describe("Abilities - Sheer Force", () => { //Disable color change due to being hit by Sheer Force const power = new Utils.IntegerHolder(move.power); const chance = new Utils.IntegerHolder(move.chance); - const user = phase.getUserPokemon(); - const target = phase.getTarget(); + const user = phase.getUserPokemon()!; + const target = phase.getTarget()!; const opponentType = target.getTypes()[0]; applyAbAttrs(MoveEffectChanceMultiplierAbAttr, user, null, chance, move, target, false); diff --git a/src/test/abilities/shield_dust.test.ts b/src/test/abilities/shield_dust.test.ts index f6906cb7b85..c7e62b333d7 100644 --- a/src/test/abilities/shield_dust.test.ts +++ b/src/test/abilities/shield_dust.test.ts @@ -67,8 +67,8 @@ describe("Abilities - Shield Dust", () => { expect(move.id).toBe(Moves.AIR_SLASH); const chance = new Utils.IntegerHolder(move.chance); - applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon(), null, chance, move, phase.getTarget(), false); - applyPreDefendAbAttrs(IgnoreMoveEffectsAbAttr, phase.getTarget(),phase.getUserPokemon(),null,null, chance); + applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, chance, move, phase.getTarget(), false); + applyPreDefendAbAttrs(IgnoreMoveEffectsAbAttr, phase.getTarget()!, phase.getUserPokemon()!, null!, null!, chance); expect(chance.value).toBe(0); }, 20000); diff --git a/src/test/abilities/shields_down.test.ts b/src/test/abilities/shields_down.test.ts index 64904c80032..4d85e8aa47c 100644 --- a/src/test/abilities/shields_down.test.ts +++ b/src/test/abilities/shields_down.test.ts @@ -45,7 +45,7 @@ describe("Abilities - SHIELDS DOWN", () => { await game.startBattle([Species.MAGIKARP, Species.MINIOR]); - const minior = game.scene.getParty().find((p) => p.species.speciesId === Species.MINIOR); + const minior = game.scene.getParty().find((p) => p.species.speciesId === Species.MINIOR)!; expect(minior).not.toBe(undefined); expect(minior.formIndex).toBe(coreForm); diff --git a/src/test/abilities/steely_spirit.test.ts b/src/test/abilities/steely_spirit.test.ts index e21067539df..5d5514bc3a1 100644 --- a/src/test/abilities/steely_spirit.test.ts +++ b/src/test/abilities/steely_spirit.test.ts @@ -40,7 +40,7 @@ describe("Abilities - Steely Spirit", () => { it("increases Steel-type moves' power used by the user and its allies by 50%", async () => { await game.startBattle([Species.PIKACHU, Species.SHUCKLE]); const boostSource = game.scene.getPlayerField()[1]; - const enemyToCheck = game.scene.getEnemyPokemon(); + const enemyToCheck = game.scene.getEnemyPokemon()!; vi.spyOn(boostSource, "getAbility").mockReturnValue(allAbilities[Abilities.STEELY_SPIRIT]); @@ -57,7 +57,7 @@ describe("Abilities - Steely Spirit", () => { it("stacks if multiple users with this ability are on the field.", async () => { await game.startBattle([Species.PIKACHU, Species.PIKACHU]); - const enemyToCheck = game.scene.getEnemyPokemon(); + const enemyToCheck = game.scene.getEnemyPokemon()!; game.scene.getPlayerField().forEach(p => { vi.spyOn(p, "getAbility").mockReturnValue(allAbilities[Abilities.STEELY_SPIRIT]); @@ -79,7 +79,7 @@ describe("Abilities - Steely Spirit", () => { it("does not take effect when suppressed", async () => { await game.startBattle([Species.PIKACHU, Species.SHUCKLE]); const boostSource = game.scene.getPlayerField()[1]; - const enemyToCheck = game.scene.getEnemyPokemon(); + const enemyToCheck = game.scene.getEnemyPokemon()!; vi.spyOn(boostSource, "getAbility").mockReturnValue(allAbilities[Abilities.STEELY_SPIRIT]); expect(boostSource.hasAbility(Abilities.STEELY_SPIRIT)).toBe(true); diff --git a/src/test/abilities/sweet_veil.test.ts b/src/test/abilities/sweet_veil.test.ts index 19c1210b443..03e9452a358 100644 --- a/src/test/abilities/sweet_veil.test.ts +++ b/src/test/abilities/sweet_veil.test.ts @@ -92,7 +92,7 @@ describe("Abilities - Sweet Veil", () => { await game.phaseInterceptor.to(TurnEndPhase); - const drowsyMon = game.scene.getPlayerField().find(p => !!p.getTag(BattlerTagType.DROWSY)); + const drowsyMon = game.scene.getPlayerField().find(p => !!p.getTag(BattlerTagType.DROWSY))!; await game.phaseInterceptor.to(CommandPhase); game.doAttack(getMovePosition(game.scene, (drowsyMon.getBattlerIndex() as BattlerIndex.PLAYER | BattlerIndex.PLAYER_2), Moves.SPLASH)); diff --git a/src/test/abilities/unseen_fist.test.ts b/src/test/abilities/unseen_fist.test.ts index 0ee4dbef513..a6cad8b03ce 100644 --- a/src/test/abilities/unseen_fist.test.ts +++ b/src/test/abilities/unseen_fist.test.ts @@ -72,10 +72,10 @@ async function testUnseenFistHitResult(game: GameManager, attackMove: Moves, pro await game.startBattle(); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; expect(leadPokemon).not.toBe(undefined); - const enemyPokemon = game.scene.getEnemyPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon).not.toBe(undefined); const enemyStartingHp = enemyPokemon.hp; diff --git a/src/test/abilities/wind_power.test.ts b/src/test/abilities/wind_power.test.ts index 8a4c2969cc4..670544a89ef 100644 --- a/src/test/abilities/wind_power.test.ts +++ b/src/test/abilities/wind_power.test.ts @@ -34,7 +34,7 @@ describe("Abilities - Wind Power", () => { it("it becomes charged when hit by wind moves", async () => { await game.startBattle([Species.MAGIKARP]); - const shiftry = game.scene.getEnemyPokemon(); + const shiftry = game.scene.getEnemyPokemon()!; expect(shiftry.getTag(BattlerTagType.CHARGED)).toBeUndefined(); @@ -49,7 +49,7 @@ describe("Abilities - Wind Power", () => { game.override.enemySpecies(Species.MAGIKARP); await game.startBattle([Species.SHIFTRY]); - const shiftry = game.scene.getPlayerPokemon(); + const shiftry = game.scene.getPlayerPokemon()!; expect(shiftry.getTag(BattlerTagType.CHARGED)).toBeUndefined(); @@ -64,8 +64,8 @@ describe("Abilities - Wind Power", () => { game.override.ability(Abilities.WIND_POWER); await game.startBattle([Species.SHIFTRY]); - const magikarp = game.scene.getEnemyPokemon(); - const shiftry = game.scene.getPlayerPokemon(); + const magikarp = game.scene.getEnemyPokemon()!; + const shiftry = game.scene.getPlayerPokemon()!; expect(shiftry.getTag(BattlerTagType.CHARGED)).toBeUndefined(); expect(magikarp.getTag(BattlerTagType.CHARGED)).toBeUndefined(); @@ -82,7 +82,7 @@ describe("Abilities - Wind Power", () => { game.override.enemySpecies(Species.MAGIKARP); await game.startBattle([Species.SHIFTRY]); - const shiftry = game.scene.getPlayerPokemon(); + const shiftry = game.scene.getPlayerPokemon()!; expect(shiftry.getTag(BattlerTagType.CHARGED)).toBeUndefined(); diff --git a/src/test/abilities/wind_rider.test.ts b/src/test/abilities/wind_rider.test.ts index 855def63b6f..e27349efe41 100644 --- a/src/test/abilities/wind_rider.test.ts +++ b/src/test/abilities/wind_rider.test.ts @@ -34,7 +34,7 @@ describe("Abilities - Wind Rider", () => { it("takes no damage from wind moves and its Attack is increased by one stage when hit by one", async () => { await game.startBattle([Species.MAGIKARP]); - const shiftry = game.scene.getEnemyPokemon(); + const shiftry = game.scene.getEnemyPokemon()!; expect(shiftry.summonData.battleStats[BattleStat.ATK]).toBe(0); @@ -51,7 +51,7 @@ describe("Abilities - Wind Rider", () => { game.override.enemySpecies(Species.MAGIKARP); await game.startBattle([Species.SHIFTRY]); - const shiftry = game.scene.getPlayerPokemon(); + const shiftry = game.scene.getPlayerPokemon()!; expect(shiftry.summonData.battleStats[BattleStat.ATK]).toBe(0); @@ -67,8 +67,8 @@ describe("Abilities - Wind Rider", () => { game.override.enemySpecies(Species.MAGIKARP); await game.startBattle([Species.SHIFTRY]); - const magikarp = game.scene.getEnemyPokemon(); - const shiftry = game.scene.getPlayerPokemon(); + const magikarp = game.scene.getEnemyPokemon()!; + const shiftry = game.scene.getPlayerPokemon()!; expect(shiftry.summonData.battleStats[BattleStat.ATK]).toBe(0); expect(magikarp.summonData.battleStats[BattleStat.ATK]).toBe(0); @@ -85,8 +85,8 @@ describe("Abilities - Wind Rider", () => { game.override.enemySpecies(Species.MAGIKARP); await game.startBattle([Species.SHIFTRY]); - const magikarp = game.scene.getEnemyPokemon(); - const shiftry = game.scene.getPlayerPokemon(); + const magikarp = game.scene.getEnemyPokemon()!; + const shiftry = game.scene.getPlayerPokemon()!; expect(shiftry.summonData.battleStats[BattleStat.ATK]).toBe(0); expect(magikarp.summonData.battleStats[BattleStat.ATK]).toBe(0); @@ -103,7 +103,7 @@ describe("Abilities - Wind Rider", () => { game.override.enemySpecies(Species.MAGIKARP); await game.startBattle([Species.SHIFTRY]); - const shiftry = game.scene.getPlayerPokemon(); + const shiftry = game.scene.getPlayerPokemon()!; expect(shiftry.summonData.battleStats[BattleStat.ATK]).toBe(0); expect(shiftry.isFullHp()).toBe(true); diff --git a/src/test/abilities/zen_mode.test.ts b/src/test/abilities/zen_mode.test.ts index 01d3724825c..63c6a3d4acf 100644 --- a/src/test/abilities/zen_mode.test.ts +++ b/src/test/abilities/zen_mode.test.ts @@ -150,7 +150,7 @@ describe("Abilities - ZEN MODE", () => { await game.startBattle([Species.MAGIKARP, Species.DARMANITAN]); - const darmanitan = game.scene.getParty().find((p) => p.species.speciesId === Species.DARMANITAN); + const darmanitan = game.scene.getParty().find((p) => p.species.speciesId === Species.DARMANITAN)!; expect(darmanitan).not.toBe(undefined); expect(darmanitan.formIndex).toBe(zenForm); diff --git a/src/test/abilities/zero_to_hero.test.ts b/src/test/abilities/zero_to_hero.test.ts index 409fb35a78c..c58761ce621 100644 --- a/src/test/abilities/zero_to_hero.test.ts +++ b/src/test/abilities/zero_to_hero.test.ts @@ -45,7 +45,7 @@ describe("Abilities - ZERO TO HERO", () => { await game.startBattle([Species.MAGIKARP, Species.PALAFIN]); - const palafin = game.scene.getParty().find((p) => p.species.speciesId === Species.PALAFIN); + const palafin = game.scene.getParty().find((p) => p.species.speciesId === Species.PALAFIN)!; expect(palafin).not.toBe(undefined); expect(palafin.formIndex).toBe(heroForm); diff --git a/src/test/account.spec.ts b/src/test/account.spec.ts index 28e48ce9933..d5d0458c7e8 100644 --- a/src/test/account.spec.ts +++ b/src/test/account.spec.ts @@ -8,21 +8,21 @@ describe("account", () => { it("should set loggedInUser to Guest and lastSessionSlot to -1", () => { initLoggedInUser(); - expect(loggedInUser.username).toBe("Guest"); - expect(loggedInUser.lastSessionSlot).toBe(-1); + expect(loggedInUser!.username).toBe("Guest"); + expect(loggedInUser!.lastSessionSlot).toBe(-1); }); }); describe("updateUserInfo", () => { - it("should set loggedInUser to Guest if bypassLogin is true", async () => { + it("should set loggedInUser! to Guest if bypassLogin is true", async () => { vi.spyOn(battleScene, "bypassLogin", "get").mockReturnValue(true); const [success, status] = await updateUserInfo(); expect(success).toBe(true); expect(status).toBe(200); - expect(loggedInUser.username).toBe("Guest"); - expect(loggedInUser.lastSessionSlot).toBe(-1); + expect(loggedInUser!.username).toBe("Guest"); + expect(loggedInUser!.lastSessionSlot).toBe(-1); }); it("should fetch user info from the API if bypassLogin is false", async () => { @@ -43,8 +43,8 @@ describe("account", () => { expect(success).toBe(true); expect(status).toBe(200); - expect(loggedInUser.username).toBe("test"); - expect(loggedInUser.lastSessionSlot).toBe(99); + expect(loggedInUser!.username).toBe("test"); + expect(loggedInUser!.lastSessionSlot).toBe(99); }); it("should handle resolved API errors", async () => { diff --git a/src/test/achievements/achievement.test.ts b/src/test/achievements/achievement.test.ts index 14466a71086..5cd9c4d4094 100644 --- a/src/test/achievements/achievement.test.ts +++ b/src/test/achievements/achievement.test.ts @@ -3,12 +3,12 @@ import { Achv, AchvTier, DamageAchv, HealAchv, LevelAchv, ModifierAchv, MoneyAch import GameManager from "#test/utils/gameManager"; import { IntegerHolder, NumberHolder } from "#app/utils.js"; import Phaser from "phaser"; -import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import BattleScene from "../../battle-scene"; describe("check some Achievement related stuff", () => { it ("should check Achievement creation", () => { - const ach = new MoneyAchv("", "Achievement", 1000, null, 100); + const ach = new MoneyAchv("", "Achievement", 1000, null!, 100); expect(ach.name).toBe("Achievement"); }); }); @@ -58,7 +58,7 @@ describe("Achv", () => { }); it("should validate the achievement based on the condition function", () => { - const conditionFunc = jest.fn((scene: BattleScene, args: any[]) => args[0] === 10); + const conditionFunc = vi.fn((scene: BattleScene, args: any[]) => args[0] === 10); const achv = new Achv("", "Test Achievement", "Test Description", "test_icon", 10, conditionFunc); expect(achv.validate(new BattleScene(), [5])).toBe(false); @@ -196,7 +196,7 @@ describe("ModifierAchv", () => { it("should validate the achievement based on the modifier function", () => { const modifierAchv = new ModifierAchv("", "Test Modifier Achievement", "Test Description", "modifier_icon", 10, () => true); const scene = new BattleScene(); - const modifier = new TurnHeldItemTransferModifier(null, 3, 1); + const modifier = new TurnHeldItemTransferModifier(null!, 3, 1); expect(modifierAchv.validate(scene, [modifier])).toBe(true); }); diff --git a/src/test/arena/weather_strong_winds.test.ts b/src/test/arena/weather_strong_winds.test.ts index 0fd45173033..d9f626cfb83 100644 --- a/src/test/arena/weather_strong_winds.test.ts +++ b/src/test/arena/weather_strong_winds.test.ts @@ -35,8 +35,8 @@ describe("Weather - Strong Winds", () => { game.override.enemySpecies(Species.RAYQUAZA); await game.startBattle([Species.PIKACHU]); - const pikachu = game.scene.getPlayerPokemon(); - const enemy = game.scene.getEnemyPokemon(); + const pikachu = game.scene.getPlayerPokemon()!; + const enemy = game.scene.getEnemyPokemon()!; game.doAttack(getMovePosition(game.scene, 0, Moves.THUNDERBOLT)); @@ -46,8 +46,8 @@ describe("Weather - Strong Winds", () => { it("electric type move is neutral for flying type pokemon", async () => { await game.startBattle([Species.PIKACHU]); - const pikachu = game.scene.getPlayerPokemon(); - const enemy = game.scene.getEnemyPokemon(); + const pikachu = game.scene.getPlayerPokemon()!; + const enemy = game.scene.getEnemyPokemon()!; game.doAttack(getMovePosition(game.scene, 0, Moves.THUNDERBOLT)); @@ -57,8 +57,8 @@ describe("Weather - Strong Winds", () => { it("ice type move is neutral for flying type pokemon", async () => { await game.startBattle([Species.PIKACHU]); - const pikachu = game.scene.getPlayerPokemon(); - const enemy = game.scene.getEnemyPokemon(); + const pikachu = game.scene.getPlayerPokemon()!; + const enemy = game.scene.getEnemyPokemon()!; game.doAttack(getMovePosition(game.scene, 0, Moves.ICE_BEAM)); @@ -68,8 +68,8 @@ describe("Weather - Strong Winds", () => { it("rock type move is neutral for flying type pokemon", async () => { await game.startBattle([Species.PIKACHU]); - const pikachu = game.scene.getPlayerPokemon(); - const enemy = game.scene.getEnemyPokemon(); + const pikachu = game.scene.getPlayerPokemon()!; + const enemy = game.scene.getEnemyPokemon()!; game.doAttack(getMovePosition(game.scene, 0, Moves.ROCK_SLIDE)); diff --git a/src/test/battle/battle.test.ts b/src/test/battle/battle.test.ts index 21b890d9cf0..a4713f90506 100644 --- a/src/test/battle/battle.test.ts +++ b/src/test/battle/battle.test.ts @@ -90,7 +90,7 @@ describe("Test Battle Phase", () => { it("newGame one-liner", async() => { await game.startBattle(); expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); - expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); + expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); it("do attack wave 3 - single battle - regular - OHKO", async() => { @@ -218,7 +218,7 @@ describe("Test Battle Phase", () => { Species.CHARIZARD, ]); expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); - expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); + expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); it("1vs1", async() => { @@ -230,7 +230,7 @@ describe("Test Battle Phase", () => { Species.BLASTOISE, ]); expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); - expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); + expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); it("2vs2", async() => { @@ -244,7 +244,7 @@ describe("Test Battle Phase", () => { Species.CHARIZARD, ]); expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); - expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); + expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); it("4vs2", async() => { @@ -260,7 +260,7 @@ describe("Test Battle Phase", () => { Species.GABITE, ]); expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); - expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); + expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); it("kill opponent pokemon", async() => { @@ -342,7 +342,7 @@ describe("Test Battle Phase", () => { .startingHeldItems([{ name: "TEMP_STAT_BOOSTER", type: TempBattleStat.ACC }]); await game.startBattle(); - game.scene.getPlayerPokemon().hp = 1; + game.scene.getPlayerPokemon()!.hp = 1; game.doAttack(getMovePosition(game.scene, 0, moveToUse)); await game.phaseInterceptor.to(BattleEndPhase); diff --git a/src/test/battle/special_battle.test.ts b/src/test/battle/special_battle.test.ts index b8a29e82f69..6130df703f5 100644 --- a/src/test/battle/special_battle.test.ts +++ b/src/test/battle/special_battle.test.ts @@ -40,7 +40,7 @@ describe("Test Battle Phase", () => { Species.CHARIZARD, ]); expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); - expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); + expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); it("startBattle 2vs2 boss", async() => { @@ -52,7 +52,7 @@ describe("Test Battle Phase", () => { Species.CHARIZARD, ]); expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); - expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); + expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); it("startBattle 2vs2 trainer", async() => { @@ -64,7 +64,7 @@ describe("Test Battle Phase", () => { Species.CHARIZARD, ]); expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); - expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); + expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); it("startBattle 2vs1 trainer", async() => { @@ -76,7 +76,7 @@ describe("Test Battle Phase", () => { Species.CHARIZARD, ]); expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); - expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); + expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); it("startBattle 2vs1 rival", async() => { @@ -88,7 +88,7 @@ describe("Test Battle Phase", () => { Species.CHARIZARD, ]); expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); - expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); + expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); it("startBattle 2vs2 rival", async() => { @@ -100,7 +100,7 @@ describe("Test Battle Phase", () => { Species.CHARIZARD, ]); expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); - expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); + expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); it("startBattle 1vs1 trainer", async() => { @@ -111,7 +111,7 @@ describe("Test Battle Phase", () => { Species.BLASTOISE, ]); expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); - expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); + expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); it("startBattle 2vs2 trainer", async() => { @@ -123,7 +123,7 @@ describe("Test Battle Phase", () => { Species.CHARIZARD, ]); expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); - expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); + expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); it("startBattle 4vs2 trainer", async() => { @@ -137,7 +137,7 @@ describe("Test Battle Phase", () => { Species.GABITE, ]); expect(game.scene.ui?.getMode()).toBe(Mode.COMMAND); - expect(game.scene.getCurrentPhase().constructor.name).toBe(CommandPhase.name); + expect(game.scene.getCurrentPhase()!.constructor.name).toBe(CommandPhase.name); }, 20000); }); diff --git a/src/test/battlerTags/octolock.test.ts b/src/test/battlerTags/octolock.test.ts index 4c1c58d4345..369a84e21fa 100644 --- a/src/test/battlerTags/octolock.test.ts +++ b/src/test/battlerTags/octolock.test.ts @@ -6,7 +6,7 @@ import { StatChangePhase } from "#app/phases.js"; import { BattleStat } from "#app/data/battle-stat.js"; import { BattlerTagType } from "#app/enums/battler-tag-type.js"; -jest.mock("#app/battle-scene.js"); +vi.mock("#app/battle-scene.js"); describe("BattlerTag - OctolockTag", () => { describe("lapse behavior", () => { @@ -49,7 +49,7 @@ describe("BattlerTag - OctolockTag", () => { it("cannot be added to pokemon who are octolocked", { timeout: 2000 }, async => { const mockPokemon = { - getTag: vi.fn().mockReturnValue(new BattlerTag(null, null, null, null)) as Pokemon["getTag"], + getTag: vi.fn().mockReturnValue(new BattlerTag(null!, null!, null!, null!)) as Pokemon["getTag"], } as Pokemon; const subject = new OctolockTag(1); diff --git a/src/test/battlerTags/stockpiling.test.ts b/src/test/battlerTags/stockpiling.test.ts index 5cf07c47ce1..005f1e1593c 100644 --- a/src/test/battlerTags/stockpiling.test.ts +++ b/src/test/battlerTags/stockpiling.test.ts @@ -27,7 +27,7 @@ describe("BattlerTag - StockpilingTag", () => { expect((phase as StatChangePhase)["levels"]).toEqual(1); expect((phase as StatChangePhase)["stats"]).toEqual(expect.arrayContaining([BattleStat.DEF, BattleStat.SPDEF])); - (phase as StatChangePhase)["onChange"](mockPokemon, [BattleStat.DEF, BattleStat.SPDEF], [1, 1]); + (phase as StatChangePhase)["onChange"]!(mockPokemon, [BattleStat.DEF, BattleStat.SPDEF], [1, 1]); }); subject.onAdd(mockPokemon); @@ -54,7 +54,7 @@ describe("BattlerTag - StockpilingTag", () => { expect((phase as StatChangePhase)["levels"]).toEqual(1); expect((phase as StatChangePhase)["stats"]).toEqual(expect.arrayContaining([BattleStat.DEF, BattleStat.SPDEF])); - (phase as StatChangePhase)["onChange"](mockPokemon, [BattleStat.DEF, BattleStat.SPDEF], [1, 1]); + (phase as StatChangePhase)["onChange"]!(mockPokemon, [BattleStat.DEF, BattleStat.SPDEF], [1, 1]); }); subject.onAdd(mockPokemon); @@ -79,7 +79,7 @@ describe("BattlerTag - StockpilingTag", () => { expect((phase as StatChangePhase)["levels"]).toEqual(1); expect((phase as StatChangePhase)["stats"]).toEqual(expect.arrayContaining([BattleStat.DEF, BattleStat.SPDEF])); - (phase as StatChangePhase)["onChange"](mockPokemon, [BattleStat.DEF, BattleStat.SPDEF], [1, 1]); + (phase as StatChangePhase)["onChange"]!(mockPokemon, [BattleStat.DEF, BattleStat.SPDEF], [1, 1]); }); subject.onOverlap(mockPokemon); @@ -109,7 +109,7 @@ describe("BattlerTag - StockpilingTag", () => { expect((phase as StatChangePhase)["stats"]).toEqual(expect.arrayContaining([BattleStat.DEF, BattleStat.SPDEF])); // def doesn't change - (phase as StatChangePhase)["onChange"](mockPokemon, [BattleStat.SPDEF], [1]); + (phase as StatChangePhase)["onChange"]!(mockPokemon, [BattleStat.SPDEF], [1]); }); subject.onAdd(mockPokemon); @@ -121,7 +121,7 @@ describe("BattlerTag - StockpilingTag", () => { expect((phase as StatChangePhase)["stats"]).toEqual(expect.arrayContaining([BattleStat.DEF, BattleStat.SPDEF])); // def doesn't change - (phase as StatChangePhase)["onChange"](mockPokemon, [BattleStat.SPDEF], [1]); + (phase as StatChangePhase)["onChange"]!(mockPokemon, [BattleStat.SPDEF], [1]); }); subject.onOverlap(mockPokemon); diff --git a/src/test/evolution.test.ts b/src/test/evolution.test.ts index acb012741ff..c8ebffa6119 100644 --- a/src/test/evolution.test.ts +++ b/src/test/evolution.test.ts @@ -64,7 +64,7 @@ describe("Evolution", () => { it("should handle illegal abilityIndex values", async () => { await game.runToSummon([Species.SQUIRTLE]); - const squirtle = game.scene.getPlayerPokemon(); + const squirtle = game.scene.getPlayerPokemon()!; squirtle.abilityIndex = 5; squirtle.evolve(pokemonEvolutions[Species.SQUIRTLE][0], squirtle.getSpeciesForm()); @@ -74,7 +74,7 @@ describe("Evolution", () => { it("should handle nincada's unique evolution", async () => { await game.runToSummon([Species.NINCADA]); - const nincada = game.scene.getPlayerPokemon(); + const nincada = game.scene.getPlayerPokemon()!; nincada.abilityIndex = 2; nincada.evolve(pokemonEvolutions[Species.NINCADA][0], nincada.getSpeciesForm()); diff --git a/src/test/evolutions/evolutions.test.ts b/src/test/evolutions/evolutions.test.ts index e6e9e0d56e2..af43e91b059 100644 --- a/src/test/evolutions/evolutions.test.ts +++ b/src/test/evolutions/evolutions.test.ts @@ -34,14 +34,14 @@ describe("Evolution tests", () => { * 1, 2 or 3, it's a 4 family maushold */ await game.startBattle([Species.TANDEMAUS]); // starts us off with a tandemaus - const playerPokemon = game.scene.getPlayerPokemon(); + const playerPokemon = game.scene.getPlayerPokemon()!; playerPokemon.level = 25; // tandemaus evolves at level 25 vi.spyOn(Utils, "randSeedInt").mockReturnValue(0); // setting the random generator to be 0 to force a three family maushold - const threeForm = playerPokemon.getEvolution(); + const threeForm = playerPokemon.getEvolution()!; expect(threeForm.evoFormKey).toBe("three"); // as per pokemon-forms, the evoFormKey for 3 family mausholds is "three" for (let f = 1; f < 4; f++) { vi.spyOn(Utils, "randSeedInt").mockReturnValue(f); // setting the random generator to 1, 2 and 3 to force 4 family mausholds - const fourForm = playerPokemon.getEvolution(); + const fourForm = playerPokemon.getEvolution()!; expect(fourForm.evoFormKey).toBe(null); // meanwhile, according to the pokemon-forms, the evoFormKey for a 4 family maushold is null } }, 5000); diff --git a/src/test/field/pokemon.test.ts b/src/test/field/pokemon.test.ts new file mode 100644 index 00000000000..2220a6f613e --- /dev/null +++ b/src/test/field/pokemon.test.ts @@ -0,0 +1,31 @@ +import { Species } from "#app/enums/species.js"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import GameManager from "../utils/gameManager"; + +describe("Spec - Pokemon", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + }); + + it("should not crash when trying to set status of undefined", async () => { + await game.runToSummon([Species.ABRA]); + + const pkm = game.scene.getPlayerPokemon()!; + expect(pkm).toBeDefined(); + + expect(pkm.trySetStatus(undefined)).toBe(true); + }); +}); diff --git a/src/test/final_boss.test.ts b/src/test/final_boss.test.ts index bc950e45767..c087bd5ba82 100644 --- a/src/test/final_boss.test.ts +++ b/src/test/final_boss.test.ts @@ -35,7 +35,7 @@ describe("Final Boss", () => { expect(game.scene.currentBattle.waveIndex).toBe(FinalWave.Classic); expect(game.scene.arena.biomeType).toBe(Biome.END); - expect(game.scene.getEnemyPokemon().species.speciesId).toBe(Species.ETERNATUS); + expect(game.scene.getEnemyPokemon()!.species.speciesId).toBe(Species.ETERNATUS); }); it("should NOT spawn Eternatus before wave 200 in END biome", async () => { @@ -44,7 +44,7 @@ describe("Final Boss", () => { expect(game.scene.currentBattle.waveIndex).not.toBe(FinalWave.Classic); expect(game.scene.arena.biomeType).toBe(Biome.END); - expect(game.scene.getEnemyPokemon().species.speciesId).not.toBe(Species.ETERNATUS); + expect(game.scene.getEnemyPokemon()!.species.speciesId).not.toBe(Species.ETERNATUS); }); it("should NOT spawn Eternatus outside of END biome", async () => { @@ -53,7 +53,7 @@ describe("Final Boss", () => { expect(game.scene.currentBattle.waveIndex).toBe(FinalWave.Classic); expect(game.scene.arena.biomeType).not.toBe(Biome.END); - expect(game.scene.getEnemyPokemon().species.speciesId).not.toBe(Species.ETERNATUS); + expect(game.scene.getEnemyPokemon()!.species.speciesId).not.toBe(Species.ETERNATUS); }); it.todo("should change form on direct hit down to last boss fragment", () => {}); diff --git a/src/test/internals.test.ts b/src/test/internals.test.ts index 2ada42d0c8c..d186849830d 100644 --- a/src/test/internals.test.ts +++ b/src/test/internals.test.ts @@ -24,7 +24,7 @@ describe("Internals", () => { it("should provide Eevee with 3 defined abilities", async () => { await game.runToSummon([Species.EEVEE]); - const eevee = game.scene.getPlayerPokemon(); + const eevee = game.scene.getPlayerPokemon()!; expect(eevee.getSpeciesForm().getAbilityCount()).toBe(3); @@ -35,7 +35,7 @@ describe("Internals", () => { it("should set Eeeve abilityIndex between 0-2", async () => { await game.runToSummon([Species.EEVEE]); - const eevee = game.scene.getPlayerPokemon(); + const eevee = game.scene.getPlayerPokemon()!; expect(eevee.abilityIndex).toBeGreaterThanOrEqual(0); expect(eevee.abilityIndex).toBeLessThanOrEqual(2); diff --git a/src/test/items/exp_booster.test.ts b/src/test/items/exp_booster.test.ts index 7ea457eda1f..3348304b2e7 100644 --- a/src/test/items/exp_booster.test.ts +++ b/src/test/items/exp_booster.test.ts @@ -31,7 +31,7 @@ describe("EXP Modifier Items", () => { game.override.startingHeldItems([{name: "LUCKY_EGG"}, {name: "GOLDEN_EGG"}]); await game.startBattle(); - const partyMember = game.scene.getPlayerPokemon(); + const partyMember = game.scene.getPlayerPokemon()!; const modifierBonusExp = new Utils.NumberHolder(1); partyMember.scene.applyModifiers(PokemonExpBoosterModifier, true, partyMember, modifierBonusExp); expect(modifierBonusExp.value).toBe(2.4); diff --git a/src/test/items/leek.test.ts b/src/test/items/leek.test.ts index 8532f0df8d9..2cfd4d8dc64 100644 --- a/src/test/items/leek.test.ts +++ b/src/test/items/leek.test.ts @@ -56,7 +56,7 @@ describe("Items - Leek", () => { Species.FARFETCHD ]); - const partyMember = game.scene.getPlayerPokemon(); + const partyMember = game.scene.getPlayerPokemon()!; // Making sure modifier is not applied without holding item const critLevel = new Utils.IntegerHolder(0); @@ -76,7 +76,7 @@ describe("Items - Leek", () => { Species.GALAR_FARFETCHD ]); - const partyMember = game.scene.getPlayerPokemon(); + const partyMember = game.scene.getPlayerPokemon()!; // Making sure modifier is not applied without holding item const critLevel = new Utils.IntegerHolder(0); @@ -96,7 +96,7 @@ describe("Items - Leek", () => { Species.SIRFETCHD ]); - const partyMember = game.scene.getPlayerPokemon(); + const partyMember = game.scene.getPlayerPokemon()!; // Making sure modifier is not applied without holding item const critLevel = new Utils.IntegerHolder(0); @@ -186,7 +186,7 @@ describe("Items - Leek", () => { Species.PIKACHU ]); - const partyMember = game.scene.getPlayerPokemon(); + const partyMember = game.scene.getPlayerPokemon()!; // Making sure modifier is not applied without holding item const critLevel = new Utils.IntegerHolder(0); diff --git a/src/test/items/leftovers.test.ts b/src/test/items/leftovers.test.ts index 6850528a664..e791c4426a1 100644 --- a/src/test/items/leftovers.test.ts +++ b/src/test/items/leftovers.test.ts @@ -40,7 +40,7 @@ describe("Items - Leftovers", () => { // Make sure leftovers are there expect(game.scene.modifiers[0].type.id).toBe("LEFTOVERS"); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; // We should have full hp expect(leadPokemon.isFullHp()).toBe(true); diff --git a/src/test/items/light_ball.test.ts b/src/test/items/light_ball.test.ts index fef5793d26c..ff7dfa4eba5 100644 --- a/src/test/items/light_ball.test.ts +++ b/src/test/items/light_ball.test.ts @@ -83,7 +83,7 @@ describe("Items - Light Ball", () => { expect(spAtkValue.value / spAtkStat).toBe(1); // Giving Eviolite to party member and testing if it applies - partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType(null, ["LIGHT_BALL"]).newModifier(partyMember), true); + partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType([], ["LIGHT_BALL"])!.newModifier(partyMember), true); partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue); partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPATK, spAtkValue); @@ -122,7 +122,7 @@ describe("Items - Light Ball", () => { expect(spAtkValue.value / spAtkStat).toBe(1); // Giving Eviolite to party member and testing if it applies - partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType(null, ["LIGHT_BALL"]).newModifier(partyMember), true); + partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType([], ["LIGHT_BALL"])!.newModifier(partyMember), true); partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue); partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPATK, spAtkValue); @@ -161,7 +161,7 @@ describe("Items - Light Ball", () => { expect(spAtkValue.value / spAtkStat).toBe(1); // Giving Eviolite to party member and testing if it applies - partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType(null, ["LIGHT_BALL"]).newModifier(partyMember), true); + partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType([], ["LIGHT_BALL"])!.newModifier(partyMember), true); partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue); partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPATK, spAtkValue); @@ -189,7 +189,7 @@ describe("Items - Light Ball", () => { expect(spAtkValue.value / spAtkStat).toBe(1); // Giving Eviolite to party member and testing if it applies - partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType(null, ["LIGHT_BALL"]).newModifier(partyMember), true); + partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType([], ["LIGHT_BALL"])!.newModifier(partyMember), true); partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue); partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPATK, spAtkValue); diff --git a/src/test/items/metal_powder.test.ts b/src/test/items/metal_powder.test.ts index da5d9109c9a..966762e4175 100644 --- a/src/test/items/metal_powder.test.ts +++ b/src/test/items/metal_powder.test.ts @@ -79,7 +79,7 @@ describe("Items - Metal Powder", () => { expect(defValue.value / defStat).toBe(1); // Giving Eviolite to party member and testing if it applies - partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType(null, ["METAL_POWDER"]).newModifier(partyMember), true); + partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType([], ["METAL_POWDER"])!.newModifier(partyMember), true); partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.DEF, defValue); expect(defValue.value / defStat).toBe(2); @@ -112,7 +112,7 @@ describe("Items - Metal Powder", () => { expect(defValue.value / defStat).toBe(1); // Giving Eviolite to party member and testing if it applies - partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType(null, ["METAL_POWDER"]).newModifier(partyMember), true); + partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType([], ["METAL_POWDER"])!.newModifier(partyMember), true); partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.DEF, defValue); expect(defValue.value / defStat).toBe(2); @@ -145,7 +145,7 @@ describe("Items - Metal Powder", () => { expect(defValue.value / defStat).toBe(1); // Giving Eviolite to party member and testing if it applies - partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType(null, ["METAL_POWDER"]).newModifier(partyMember), true); + partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType([], ["METAL_POWDER"])!.newModifier(partyMember), true); partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.DEF, defValue); expect(defValue.value / defStat).toBe(2); @@ -167,7 +167,7 @@ describe("Items - Metal Powder", () => { expect(defValue.value / defStat).toBe(1); // Giving Eviolite to party member and testing if it applies - partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType(null, ["METAL_POWDER"]).newModifier(partyMember), true); + partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType([], ["METAL_POWDER"])!.newModifier(partyMember), true); partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.DEF, defValue); expect(defValue.value / defStat).toBe(1); diff --git a/src/test/items/quick_powder.test.ts b/src/test/items/quick_powder.test.ts index 939d25070bc..d2435dab431 100644 --- a/src/test/items/quick_powder.test.ts +++ b/src/test/items/quick_powder.test.ts @@ -79,7 +79,7 @@ describe("Items - Quick Powder", () => { expect(spdValue.value / spdStat).toBe(1); // Giving Eviolite to party member and testing if it applies - partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType(null, ["QUICK_POWDER"]).newModifier(partyMember), true); + partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType([], ["QUICK_POWDER"])!.newModifier(partyMember), true); partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPD, spdValue); expect(spdValue.value / spdStat).toBe(2); @@ -112,7 +112,7 @@ describe("Items - Quick Powder", () => { expect(spdValue.value / spdStat).toBe(1); // Giving Eviolite to party member and testing if it applies - partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType(null, ["QUICK_POWDER"]).newModifier(partyMember), true); + partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType([], ["QUICK_POWDER"])!.newModifier(partyMember), true); partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPD, spdValue); expect(spdValue.value / spdStat).toBe(2); @@ -145,7 +145,7 @@ describe("Items - Quick Powder", () => { expect(spdValue.value / spdStat).toBe(1); // Giving Eviolite to party member and testing if it applies - partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType(null, ["QUICK_POWDER"]).newModifier(partyMember), true); + partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType([], ["QUICK_POWDER"])!.newModifier(partyMember), true); partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPD, spdValue); expect(spdValue.value / spdStat).toBe(2); @@ -167,7 +167,7 @@ describe("Items - Quick Powder", () => { expect(spdValue.value / spdStat).toBe(1); // Giving Eviolite to party member and testing if it applies - partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType(null, ["QUICK_POWDER"]).newModifier(partyMember), true); + partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType([], ["QUICK_POWDER"])!.newModifier(partyMember), true); partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.SPD, spdValue); expect(spdValue.value / spdStat).toBe(1); diff --git a/src/test/items/scope_lens.test.ts b/src/test/items/scope_lens.test.ts index 72dc838548e..60f7aec171b 100644 --- a/src/test/items/scope_lens.test.ts +++ b/src/test/items/scope_lens.test.ts @@ -55,7 +55,7 @@ describe("Items - Scope Lens", () => { Species.GASTLY ]); - const partyMember = game.scene.getPlayerPokemon(); + const partyMember = game.scene.getPlayerPokemon()!; // Making sure modifier is not applied without holding item const critLevel = new Utils.IntegerHolder(0); diff --git a/src/test/items/thick_club.test.ts b/src/test/items/thick_club.test.ts index 6b56cf98099..841cd7c90ac 100644 --- a/src/test/items/thick_club.test.ts +++ b/src/test/items/thick_club.test.ts @@ -79,7 +79,7 @@ describe("Items - Thick Club", () => { expect(atkValue.value / atkStat).toBe(1); // Giving Eviolite to party member and testing if it applies - partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType(null, ["THICK_CLUB"]).newModifier(partyMember), true); + partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType([], ["THICK_CLUB"])!.newModifier(partyMember), true); partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue); expect(atkValue.value / atkStat).toBe(2); @@ -101,7 +101,7 @@ describe("Items - Thick Club", () => { expect(atkValue.value / atkStat).toBe(1); // Giving Eviolite to party member and testing if it applies - partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType(null, ["THICK_CLUB"]).newModifier(partyMember), true); + partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType([], ["THICK_CLUB"])!.newModifier(partyMember), true); partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue); expect(atkValue.value / atkStat).toBe(2); @@ -123,7 +123,7 @@ describe("Items - Thick Club", () => { expect(atkValue.value / atkStat).toBe(1); // Giving Eviolite to party member and testing if it applies - partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType(null, ["THICK_CLUB"]).newModifier(partyMember), true); + partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType([], ["THICK_CLUB"])!.newModifier(partyMember), true); partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue); expect(atkValue.value / atkStat).toBe(2); @@ -160,7 +160,7 @@ describe("Items - Thick Club", () => { expect(atkValue.value / atkStat).toBe(1); // Giving Eviolite to party member and testing if it applies - partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType(null, ["THICK_CLUB"]).newModifier(partyMember), true); + partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType([], ["THICK_CLUB"])!.newModifier(partyMember), true); partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue); expect(atkValue.value / atkStat).toBe(2); @@ -197,7 +197,7 @@ describe("Items - Thick Club", () => { expect(atkValue.value / atkStat).toBe(1); // Giving Eviolite to party member and testing if it applies - partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType(null, ["THICK_CLUB"]).newModifier(partyMember), true); + partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType([], ["THICK_CLUB"])!.newModifier(partyMember), true); partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue); expect(atkValue.value / atkStat).toBe(2); @@ -219,7 +219,7 @@ describe("Items - Thick Club", () => { expect(atkValue.value / atkStat).toBe(1); // Giving Eviolite to party member and testing if it applies - partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType(null, ["THICK_CLUB"]).newModifier(partyMember), true); + partyMember.scene.addModifier(modifierTypes.SPECIES_STAT_BOOSTER().generateType([], ["THICK_CLUB"])!.newModifier(partyMember), true); partyMember.scene.applyModifiers(SpeciesStatBoosterModifier, true, partyMember, Stat.ATK, atkValue); expect(atkValue.value / atkStat).toBe(1); diff --git a/src/test/items/toxic_orb.test.ts b/src/test/items/toxic_orb.test.ts index b5e9b6c4d65..69f55cb2bbc 100644 --- a/src/test/items/toxic_orb.test.ts +++ b/src/test/items/toxic_orb.test.ts @@ -72,6 +72,6 @@ describe("Items - Toxic orb", () => { const message2 = game.textInterceptor.getLatestMessage(); expect(message2).toContain("is hurt"); expect(message2).toContain("by poison"); - expect(game.scene.getParty()[0].status.effect).toBe(StatusEffect.TOXIC); + expect(game.scene.getParty()[0].status!.effect).toBe(StatusEffect.TOXIC); }, 20000); }); diff --git a/src/test/localization/terrain.test.ts b/src/test/localization/terrain.test.ts index f97b7813948..c072f9cc9ab 100644 --- a/src/test/localization/terrain.test.ts +++ b/src/test/localization/terrain.test.ts @@ -37,18 +37,18 @@ describe("terrain", () => { mockI18next(); const text = getTerrainStartMessage(terrainType); - expect(text).toBe(undefined); + expect(text).toBeNull(); }); it("should return the clear text", () => { mockI18next(); const text = getTerrainClearMessage(terrainType); - expect(text).toBe(undefined); + expect(text).toBeNull(); }); it("should return the block text", async () => { await game.startBattle([Species.MAGIKARP]); - const pokemon = game.scene.getPlayerPokemon(); + const pokemon = game.scene.getPlayerPokemon()!; mockI18next(); const text = getTerrainBlockMessage(pokemon, terrainType); expect(text).toBe("terrain:defaultBlockMessage"); @@ -80,7 +80,7 @@ describe("terrain", () => { it("should return the block text", async () => { await game.startBattle([Species.MAGIKARP]); - const pokemon = game.scene.getPlayerPokemon(); + const pokemon = game.scene.getPlayerPokemon()!; mockI18next(); const text = getTerrainBlockMessage(pokemon, terrainType); expect(text).toBe("terrain:mistyBlockMessage"); @@ -112,7 +112,7 @@ describe("terrain", () => { it("should return the block text", async () => { await game.startBattle([Species.MAGIKARP]); - const pokemon = game.scene.getPlayerPokemon(); + const pokemon = game.scene.getPlayerPokemon()!; mockI18next(); const text = getTerrainBlockMessage(pokemon, terrainType); expect(text).toBe("terrain:defaultBlockMessage"); @@ -144,7 +144,7 @@ describe("terrain", () => { it("should return the block text", async () => { await game.startBattle([Species.MAGIKARP]); - const pokemon = game.scene.getPlayerPokemon(); + const pokemon = game.scene.getPlayerPokemon()!; mockI18next(); const text = getTerrainBlockMessage(pokemon, terrainType); expect(text).toBe("terrain:defaultBlockMessage"); @@ -176,7 +176,7 @@ describe("terrain", () => { it("should return the block text", async () => { await game.startBattle([Species.MAGIKARP]); - const pokemon = game.scene.getPlayerPokemon(); + const pokemon = game.scene.getPlayerPokemon()!; mockI18next(); const text = getTerrainBlockMessage(pokemon, terrainType); expect(text).toBe("terrain:defaultBlockMessage"); diff --git a/src/test/moves/astonish.test.ts b/src/test/moves/astonish.test.ts index c5d59f82102..358e4a9bec3 100644 --- a/src/test/moves/astonish.test.ts +++ b/src/test/moves/astonish.test.ts @@ -43,9 +43,9 @@ describe("Moves - Astonish", () => { async () => { await game.startBattle([Species.MEOWSCARADA]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; - const enemyPokemon = game.scene.getEnemyPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon()!; game.doAttack(getMovePosition(game.scene, 0, Moves.ASTONISH)); diff --git a/src/test/moves/aurora_veil.test.ts b/src/test/moves/aurora_veil.test.ts index f98e9e9cc0c..a10c9b6b60a 100644 --- a/src/test/moves/aurora_veil.test.ts +++ b/src/test/moves/aurora_veil.test.ts @@ -49,7 +49,7 @@ describe("Moves - Aurora Veil", () => { game.doAttack(getMovePosition(game.scene, 0, moveToUse)); await game.phaseInterceptor.to(TurnEndPhase); - const mockedDmg = getMockedMoveDamage(game.scene.getEnemyPokemon(), game.scene.getPlayerPokemon(), allMoves[moveToUse]); + const mockedDmg = getMockedMoveDamage(game.scene.getEnemyPokemon()!, game.scene.getPlayerPokemon()!, allMoves[moveToUse]); expect(mockedDmg).toBe(allMoves[moveToUse].power * singleBattleMultiplier); }); @@ -64,7 +64,7 @@ describe("Moves - Aurora Veil", () => { game.doAttack(getMovePosition(game.scene, 1, moveToUse)); await game.phaseInterceptor.to(TurnEndPhase); - const mockedDmg = getMockedMoveDamage(game.scene.getEnemyPokemon(), game.scene.getPlayerPokemon(), allMoves[moveToUse]); + const mockedDmg = getMockedMoveDamage(game.scene.getEnemyPokemon()!, game.scene.getPlayerPokemon()!, allMoves[moveToUse]); expect(mockedDmg).toBe(allMoves[moveToUse].power * doubleBattleMultiplier); }); @@ -77,7 +77,7 @@ describe("Moves - Aurora Veil", () => { await game.phaseInterceptor.to(TurnEndPhase); - const mockedDmg = getMockedMoveDamage(game.scene.getEnemyPokemon(), game.scene.getPlayerPokemon(), allMoves[moveToUse]); + const mockedDmg = getMockedMoveDamage(game.scene.getEnemyPokemon()!, game.scene.getPlayerPokemon()!, allMoves[moveToUse]); expect(mockedDmg).toBe(allMoves[moveToUse].power * singleBattleMultiplier); }); @@ -92,7 +92,7 @@ describe("Moves - Aurora Veil", () => { game.doAttack(getMovePosition(game.scene, 1, moveToUse)); await game.phaseInterceptor.to(TurnEndPhase); - const mockedDmg = getMockedMoveDamage(game.scene.getEnemyPokemon(), game.scene.getPlayerPokemon(), allMoves[moveToUse]); + const mockedDmg = getMockedMoveDamage(game.scene.getEnemyPokemon()!, game.scene.getPlayerPokemon()!, allMoves[moveToUse]); expect(mockedDmg).toBe(allMoves[moveToUse].power * doubleBattleMultiplier); }); diff --git a/src/test/moves/baton_pass.test.ts b/src/test/moves/baton_pass.test.ts index ba961613998..9f0cb3619b2 100644 --- a/src/test/moves/baton_pass.test.ts +++ b/src/test/moves/baton_pass.test.ts @@ -45,7 +45,7 @@ describe("Moves - Baton Pass", () => { // round 1 - buff game.doAttack(getMovePosition(game.scene, 0, Moves.NASTY_PLOT)); await game.toNextTurn(); - expect(game.scene.getPlayerPokemon().summonData.battleStats[BattleStat.SPATK]).toEqual(2); + expect(game.scene.getPlayerPokemon()!.summonData.battleStats[BattleStat.SPATK]).toEqual(2); // round 2 - baton pass game.doAttack(getMovePosition(game.scene, 0, Moves.BATON_PASS)); @@ -53,8 +53,9 @@ describe("Moves - Baton Pass", () => { await game.phaseInterceptor.to(TurnEndPhase); // assert - expect(game.scene.getPlayerPokemon().species.speciesId).toEqual(Species.SHUCKLE); - expect(game.scene.getPlayerPokemon().summonData.battleStats[BattleStat.SPATK]).toEqual(2); + const playerPkm = game.scene.getPlayerPokemon()!; + expect(playerPkm.species.speciesId).toEqual(Species.SHUCKLE); + expect(playerPkm.summonData.battleStats[BattleStat.SPATK]).toEqual(2); }, 20000); it("passes stat stage buffs when AI uses it", async() => { @@ -72,17 +73,17 @@ describe("Moves - Baton Pass", () => { await game.toNextTurn(); // round 2 - baton pass - game.scene.getEnemyPokemon().hp = 100; + game.scene.getEnemyPokemon()!.hp = 100; game.override.enemyMoveset(new Array(4).fill(Moves.BATON_PASS)); game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); await game.phaseInterceptor.to(PostSummonPhase, false); // assert // check buffs are still there - expect(game.scene.getEnemyPokemon().summonData.battleStats[BattleStat.SPATK]).toEqual(2); + expect(game.scene.getEnemyPokemon()!.summonData.battleStats[BattleStat.SPATK]).toEqual(2); // confirm that a switch actually happened. can't use species because I // can't find a way to override trainer parties with more than 1 pokemon species - expect(game.scene.getEnemyPokemon().hp).not.toEqual(100); + expect(game.scene.getEnemyPokemon()!.hp).not.toEqual(100); expect(game.phaseInterceptor.log.slice(-4)).toEqual([ "MoveEffectPhase", "SwitchSummonPhase", diff --git a/src/test/moves/beat_up.test.ts b/src/test/moves/beat_up.test.ts index e720c625956..a5e4b3cbd34 100644 --- a/src/test/moves/beat_up.test.ts +++ b/src/test/moves/beat_up.test.ts @@ -42,8 +42,8 @@ describe("Moves - Beat Up", () => { async () => { await game.startBattle([Species.MAGIKARP, Species.BULBASAUR, Species.CHARMANDER, Species.SQUIRTLE, Species.PIKACHU, Species.EEVEE]); - const playerPokemon = game.scene.getPlayerPokemon(); - const enemyPokemon = game.scene.getEnemyPokemon(); + const playerPokemon = game.scene.getPlayerPokemon()!; + const enemyPokemon = game.scene.getEnemyPokemon()!; let enemyStartingHp = enemyPokemon.hp; game.doAttack(getMovePosition(game.scene, 0, Moves.BEAT_UP)); @@ -66,7 +66,7 @@ describe("Moves - Beat Up", () => { async () => { await game.startBattle([Species.MAGIKARP, Species.BULBASAUR, Species.CHARMANDER, Species.SQUIRTLE, Species.PIKACHU, Species.EEVEE]); - const playerPokemon = game.scene.getPlayerPokemon(); + const playerPokemon = game.scene.getPlayerPokemon()!; game.scene.getParty()[1].trySetStatus(StatusEffect.BURN); @@ -84,8 +84,8 @@ describe("Moves - Beat Up", () => { game.override.startingHeldItems([{name: "MULTI_LENS", count: 1}]); await game.startBattle([Species.MAGIKARP, Species.BULBASAUR, Species.CHARMANDER, Species.SQUIRTLE, Species.PIKACHU, Species.EEVEE]); - const playerPokemon = game.scene.getPlayerPokemon(); - const enemyPokemon = game.scene.getEnemyPokemon(); + const playerPokemon = game.scene.getPlayerPokemon()!; + const enemyPokemon = game.scene.getEnemyPokemon()!; let enemyStartingHp = enemyPokemon.hp; game.doAttack(getMovePosition(game.scene, 0, Moves.BEAT_UP)); diff --git a/src/test/moves/belly_drum.test.ts b/src/test/moves/belly_drum.test.ts index 5bb27394805..74afc910faf 100644 --- a/src/test/moves/belly_drum.test.ts +++ b/src/test/moves/belly_drum.test.ts @@ -43,7 +43,7 @@ describe("Moves - BELLY DRUM", () => { async() => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; const hpLost = Math.floor(leadPokemon.getMaxHp() / RATIO); game.doAttack(getMovePosition(game.scene, 0, Moves.BELLY_DRUM)); @@ -58,7 +58,7 @@ describe("Moves - BELLY DRUM", () => { async() => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; const hpLost = Math.floor(leadPokemon.getMaxHp() / RATIO); // Here - BattleStat.ATK -> -3 and BattleStat.SPATK -> 6 @@ -78,7 +78,7 @@ describe("Moves - BELLY DRUM", () => { async() => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; leadPokemon.summonData.battleStats[BattleStat.ATK] = 6; @@ -94,7 +94,7 @@ describe("Moves - BELLY DRUM", () => { async() => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; const hpLost = Math.floor(leadPokemon.getMaxHp() / RATIO); leadPokemon.hp = hpLost - PREDAMAGE; diff --git a/src/test/moves/ceaseless_edge.test.ts b/src/test/moves/ceaseless_edge.test.ts index 288ea6ac277..c5ce8375102 100644 --- a/src/test/moves/ceaseless_edge.test.ts +++ b/src/test/moves/ceaseless_edge.test.ts @@ -45,7 +45,7 @@ describe("Moves - Ceaseless Edge", () => { async () => { await game.startBattle([ Species.ILLUMISE ]); - const enemyPokemon = game.scene.getEnemyPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyStartingHp = enemyPokemon.hp; @@ -70,7 +70,7 @@ describe("Moves - Ceaseless Edge", () => { game.override.startingHeldItems([{name: "MULTI_LENS"}]); await game.startBattle([ Species.ILLUMISE ]); - const enemyPokemon = game.scene.getEnemyPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyStartingHp = enemyPokemon.hp; diff --git a/src/test/moves/clangorous_soul.test.ts b/src/test/moves/clangorous_soul.test.ts index 251225e7068..5493466ba56 100644 --- a/src/test/moves/clangorous_soul.test.ts +++ b/src/test/moves/clangorous_soul.test.ts @@ -44,7 +44,7 @@ describe("Moves - CLANGOROUS_SOUL", () => { async() => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; const hpLost = Math.floor(leadPokemon.getMaxHp() / RATIO); game.doAttack(getMovePosition(game.scene, 0, Moves.CLANGOROUS_SOUL)); @@ -63,7 +63,7 @@ describe("Moves - CLANGOROUS_SOUL", () => { async() => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; const hpLost = Math.floor(leadPokemon.getMaxHp() / RATIO); //Here - BattleStat.SPD -> 0 and BattleStat.SPDEF -> 4 @@ -88,7 +88,7 @@ describe("Moves - CLANGOROUS_SOUL", () => { async() => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; leadPokemon.summonData.battleStats[BattleStat.ATK] = 6; leadPokemon.summonData.battleStats[BattleStat.DEF] = 6; @@ -112,7 +112,7 @@ describe("Moves - CLANGOROUS_SOUL", () => { async() => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; const hpLost = Math.floor(leadPokemon.getMaxHp() / RATIO); leadPokemon.hp = hpLost - PREDAMAGE; diff --git a/src/test/moves/double_team.test.ts b/src/test/moves/double_team.test.ts index 48b322f5f11..2153b856517 100644 --- a/src/test/moves/double_team.test.ts +++ b/src/test/moves/double_team.test.ts @@ -36,8 +36,8 @@ describe("Moves - Double Team", () => { it("increases the user's evasion by one stage.", async () => { await game.startBattle([Species.MAGIKARP]); - const ally = game.scene.getPlayerPokemon(); - const enemy = game.scene.getEnemyPokemon(); + const ally = game.scene.getPlayerPokemon()!; + const enemy = game.scene.getEnemyPokemon()!; vi.spyOn(enemy, "getAccuracyMultiplier"); expect(ally.summonData.battleStats[BattleStat.EVA]).toBe(0); diff --git a/src/test/moves/dragon_rage.test.ts b/src/test/moves/dragon_rage.test.ts index 3c6e2b83baa..6ec7521f678 100644 --- a/src/test/moves/dragon_rage.test.ts +++ b/src/test/moves/dragon_rage.test.ts @@ -51,7 +51,7 @@ describe("Moves - Dragon Rage", () => { await game.startBattle(); partyPokemon = game.scene.getParty()[0]; - enemyPokemon = game.scene.getEnemyPokemon(); + enemyPokemon = game.scene.getEnemyPokemon()!; // remove berries game.scene.removePartyMemberModifiers(0); diff --git a/src/test/moves/dynamax_cannon.test.ts b/src/test/moves/dynamax_cannon.test.ts index 8af6a624797..57846c1aef7 100644 --- a/src/test/moves/dynamax_cannon.test.ts +++ b/src/test/moves/dynamax_cannon.test.ts @@ -81,7 +81,7 @@ describe("Moves - Dynamax Cannon", () => { const phase = game.scene.getCurrentPhase() as MoveEffectPhase; expect(phase.move.moveId).toBe(dynamaxCannon.id); // Force level cap to be 100 - vi.spyOn(phase.getTarget().scene, "getMaxExpLevel").mockReturnValue(100); + vi.spyOn(phase.getTarget()!.scene, "getMaxExpLevel").mockReturnValue(100); await game.phaseInterceptor.to(DamagePhase, false); expect(dynamaxCannon.calculateBattlePower).toHaveLastReturnedWith(120); }, 20000); @@ -98,7 +98,7 @@ describe("Moves - Dynamax Cannon", () => { const phase = game.scene.getCurrentPhase() as MoveEffectPhase; expect(phase.move.moveId).toBe(dynamaxCannon.id); // Force level cap to be 100 - vi.spyOn(phase.getTarget().scene, "getMaxExpLevel").mockReturnValue(100); + vi.spyOn(phase.getTarget()!.scene, "getMaxExpLevel").mockReturnValue(100); await game.phaseInterceptor.to(DamagePhase, false); expect(dynamaxCannon.calculateBattlePower).toHaveLastReturnedWith(140); }, 20000); @@ -115,7 +115,7 @@ describe("Moves - Dynamax Cannon", () => { const phase = game.scene.getCurrentPhase() as MoveEffectPhase; expect(phase.move.moveId).toBe(dynamaxCannon.id); // Force level cap to be 100 - vi.spyOn(phase.getTarget().scene, "getMaxExpLevel").mockReturnValue(100); + vi.spyOn(phase.getTarget()!.scene, "getMaxExpLevel").mockReturnValue(100); await game.phaseInterceptor.to(DamagePhase, false); expect(dynamaxCannon.calculateBattlePower).toHaveLastReturnedWith(160); }, 20000); @@ -132,7 +132,7 @@ describe("Moves - Dynamax Cannon", () => { const phase = game.scene.getCurrentPhase() as MoveEffectPhase; expect(phase.move.moveId).toBe(dynamaxCannon.id); // Force level cap to be 100 - vi.spyOn(phase.getTarget().scene, "getMaxExpLevel").mockReturnValue(100); + vi.spyOn(phase.getTarget()!.scene, "getMaxExpLevel").mockReturnValue(100); await game.phaseInterceptor.to(DamagePhase, false); expect(dynamaxCannon.calculateBattlePower).toHaveLastReturnedWith(180); }, 20000); @@ -149,7 +149,7 @@ describe("Moves - Dynamax Cannon", () => { const phase = game.scene.getCurrentPhase() as MoveEffectPhase; expect(phase.move.moveId).toBe(dynamaxCannon.id); // Force level cap to be 100 - vi.spyOn(phase.getTarget().scene, "getMaxExpLevel").mockReturnValue(100); + vi.spyOn(phase.getTarget()!.scene, "getMaxExpLevel").mockReturnValue(100); await game.phaseInterceptor.to(DamagePhase, false); expect(dynamaxCannon.calculateBattlePower).toHaveLastReturnedWith(200); }, 20000); diff --git a/src/test/moves/fillet_away.test.ts b/src/test/moves/fillet_away.test.ts index a3922b18468..6965ced46d9 100644 --- a/src/test/moves/fillet_away.test.ts +++ b/src/test/moves/fillet_away.test.ts @@ -44,7 +44,7 @@ describe("Moves - FILLET AWAY", () => { async() => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; const hpLost = Math.floor(leadPokemon.getMaxHp() / RATIO); game.doAttack(getMovePosition(game.scene, 0, Moves.FILLET_AWAY)); @@ -61,7 +61,7 @@ describe("Moves - FILLET AWAY", () => { async() => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; const hpLost = Math.floor(leadPokemon.getMaxHp() / RATIO); //Here - BattleStat.SPD -> 0 and BattleStat.SPATK -> 3 @@ -82,7 +82,7 @@ describe("Moves - FILLET AWAY", () => { async() => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; leadPokemon.summonData.battleStats[BattleStat.ATK] = 6; leadPokemon.summonData.battleStats[BattleStat.SPATK] = 6; @@ -102,7 +102,7 @@ describe("Moves - FILLET AWAY", () => { async() => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; const hpLost = Math.floor(leadPokemon.getMaxHp() / RATIO); leadPokemon.hp = hpLost - PREDAMAGE; diff --git a/src/test/moves/fissure.test.ts b/src/test/moves/fissure.test.ts index f2f58212209..979bc40646c 100644 --- a/src/test/moves/fissure.test.ts +++ b/src/test/moves/fissure.test.ts @@ -45,7 +45,7 @@ describe("Moves - Fissure", () => { await game.startBattle(); partyPokemon = game.scene.getParty()[0]; - enemyPokemon = game.scene.getEnemyPokemon(); + enemyPokemon = game.scene.getEnemyPokemon()!; // remove berries game.scene.removePartyMemberModifiers(0); diff --git a/src/test/moves/flower_shield.test.ts b/src/test/moves/flower_shield.test.ts index a00c84f8714..7ca5fb8bc62 100644 --- a/src/test/moves/flower_shield.test.ts +++ b/src/test/moves/flower_shield.test.ts @@ -39,8 +39,8 @@ describe("Moves - Flower Shield", () => { game.override.enemySpecies(Species.CHERRIM); await game.startBattle([Species.MAGIKARP]); - const cherrim = game.scene.getEnemyPokemon(); - const magikarp = game.scene.getPlayerPokemon(); + const cherrim = game.scene.getEnemyPokemon()!; + const magikarp = game.scene.getPlayerPokemon()!; expect(magikarp.summonData.battleStats[BattleStat.DEF]).toBe(0); expect(cherrim.summonData.battleStats[BattleStat.DEF]).toBe(0); @@ -81,8 +81,8 @@ describe("Moves - Flower Shield", () => { game.override.enemyLevel(50); await game.startBattle([Species.CHERRIM]); - const paras = game.scene.getEnemyPokemon(); - const cherrim = game.scene.getPlayerPokemon(); + const paras = game.scene.getEnemyPokemon()!; + const cherrim = game.scene.getPlayerPokemon()!; expect(paras.summonData.battleStats[BattleStat.DEF]).toBe(0); expect(cherrim.summonData.battleStats[BattleStat.DEF]).toBe(0); @@ -100,8 +100,8 @@ describe("Moves - Flower Shield", () => { game.override.enemySpecies(Species.MAGIKARP); await game.startBattle([Species.MAGIKARP]); - const enemy = game.scene.getEnemyPokemon(); - const ally = game.scene.getPlayerPokemon(); + const enemy = game.scene.getEnemyPokemon()!; + const ally = game.scene.getPlayerPokemon()!; expect(enemy.summonData.battleStats[BattleStat.DEF]).toBe(0); expect(ally.summonData.battleStats[BattleStat.DEF]).toBe(0); diff --git a/src/test/moves/foresight.test.ts b/src/test/moves/foresight.test.ts index 4a2b4f8af03..5d847ca1bc4 100644 --- a/src/test/moves/foresight.test.ts +++ b/src/test/moves/foresight.test.ts @@ -35,7 +35,7 @@ describe("Internals", () => { it("should allow Normal and Fighting moves to hit Ghost types", async () => { await game.startBattle(); - const enemy = game.scene.getEnemyPokemon(); + const enemy = game.scene.getEnemyPokemon()!; game.doAttack(getMovePosition(game.scene, 0, Moves.QUICK_ATTACK)); await game.toNextTurn(); @@ -59,7 +59,7 @@ describe("Internals", () => { game.override.enemyMoveset(Array(4).fill(Moves.MINIMIZE)); await game.startBattle(); - const pokemon = game.scene.getPlayerPokemon(); + const pokemon = game.scene.getPlayerPokemon()!; vi.spyOn(pokemon, "getAccuracyMultiplier"); game.doAttack(getMovePosition(game.scene, 0, Moves.FORESIGHT)); diff --git a/src/test/moves/fusion_bolt.test.ts b/src/test/moves/fusion_bolt.test.ts index 3ba4148db9f..c7a21e2c736 100644 --- a/src/test/moves/fusion_bolt.test.ts +++ b/src/test/moves/fusion_bolt.test.ts @@ -41,7 +41,7 @@ describe("Moves - Fusion Bolt", () => { Species.ZEKROM, ]); - const partyMember = game.scene.getPlayerPokemon(); + const partyMember = game.scene.getPlayerPokemon()!; const initialHp = partyMember.hp; game.doAttack(getMovePosition(game.scene, 0, fusionBolt)); diff --git a/src/test/moves/fusion_flare.test.ts b/src/test/moves/fusion_flare.test.ts index 9862995be32..9ae42e7977f 100644 --- a/src/test/moves/fusion_flare.test.ts +++ b/src/test/moves/fusion_flare.test.ts @@ -41,7 +41,7 @@ describe("Moves - Fusion Flare", () => { Species.RESHIRAM, ]); - const partyMember = game.scene.getPlayerPokemon(); + const partyMember = game.scene.getPlayerPokemon()!; game.doAttack(getMovePosition(game.scene, 0, fusionFlare)); @@ -49,7 +49,7 @@ describe("Moves - Fusion Flare", () => { // Inflict freeze quietly and check if it was properly inflicted partyMember.trySetStatus(StatusEffect.FREEZE, false); - expect(partyMember.status.effect).toBe(StatusEffect.FREEZE); + expect(partyMember.status!.effect).toBe(StatusEffect.FREEZE); await game.toNextTurn(); diff --git a/src/test/moves/gastro_acid.test.ts b/src/test/moves/gastro_acid.test.ts index c6692d3442c..77cf35f39e2 100644 --- a/src/test/moves/gastro_acid.test.ts +++ b/src/test/moves/gastro_acid.test.ts @@ -83,6 +83,6 @@ describe("Moves - Gastro Acid", () => { await game.phaseInterceptor.to("TurnInitPhase"); - expect(game.scene.getPlayerPokemon().getLastXMoves()[0].result).toBe(MoveResult.FAIL); + expect(game.scene.getPlayerPokemon()!.getLastXMoves()[0].result).toBe(MoveResult.FAIL); }, TIMEOUT); }); diff --git a/src/test/moves/glaive_rush.test.ts b/src/test/moves/glaive_rush.test.ts index fc9f6ee1c7f..ce63da6b565 100644 --- a/src/test/moves/glaive_rush.test.ts +++ b/src/test/moves/glaive_rush.test.ts @@ -38,7 +38,7 @@ describe("Moves - Glaive Rush", () => { it("takes double damage from attacks", async() => { await game.startBattle(); - const enemy = game.scene.getEnemyPokemon(); + const enemy = game.scene.getEnemyPokemon()!; enemy.hp = 1000; vi.spyOn(game.scene, "randBattleSeedInt").mockReturnValue(0); @@ -50,11 +50,11 @@ describe("Moves - Glaive Rush", () => { await game.phaseInterceptor.to(DamagePhase); expect(enemy.hp).toBeLessThanOrEqual(1001 - (damageDealt * 3)); - }, 20000); + }, 5000); // TODO: revert back to 20s it("always gets hit by attacks", async() => { await game.startBattle(); - const enemy = game.scene.getEnemyPokemon(); + const enemy = game.scene.getEnemyPokemon()!; enemy.hp = 1000; allMoves[Moves.AVALANCHE].accuracy = 0; @@ -68,8 +68,8 @@ describe("Moves - Glaive Rush", () => { game.override.startingHeldItems([{name: "MULTI_LENS", count: 2}]); game.override.enemyMoveset(Array(4).fill(Moves.AVALANCHE)); await game.startBattle(); - const player = game.scene.getPlayerPokemon(); - const enemy = game.scene.getEnemyPokemon(); + const player = game.scene.getPlayerPokemon()!; + const enemy = game.scene.getEnemyPokemon()!; enemy.hp = 1000; player.hp = 1000; @@ -87,8 +87,8 @@ describe("Moves - Glaive Rush", () => { it("secondary effects only last until next move", async() => { game.override.enemyMoveset(Array(4).fill(Moves.SHADOW_SNEAK)); await game.startBattle(); - const player = game.scene.getPlayerPokemon(); - const enemy = game.scene.getEnemyPokemon(); + const player = game.scene.getPlayerPokemon()!; + const enemy = game.scene.getEnemyPokemon()!; enemy.hp = 1000; player.hp = 1000; allMoves[Moves.SHADOW_SNEAK].accuracy = 0; @@ -112,8 +112,8 @@ describe("Moves - Glaive Rush", () => { game.override.enemyMoveset(Array(4).fill(Moves.SHADOW_SNEAK)); game.override.starterSpecies(0); await game.startBattle([Species.KLINK, Species.FEEBAS]); - const player = game.scene.getPlayerPokemon(); - const enemy = game.scene.getEnemyPokemon(); + const player = game.scene.getPlayerPokemon()!; + const enemy = game.scene.getEnemyPokemon()!; enemy.hp = 1000; allMoves[Moves.SHADOW_SNEAK].accuracy = 0; diff --git a/src/test/moves/hard_press.test.ts b/src/test/moves/hard_press.test.ts index 6a45e49137b..baf63a1ad23 100644 --- a/src/test/moves/hard_press.test.ts +++ b/src/test/moves/hard_press.test.ts @@ -48,7 +48,7 @@ describe("Moves - Hard Press", () => { it("should return 50 power if target HP ratio is at 50%", async () => { await game.startBattle([Species.PIKACHU]); const targetHpRatio = .5; - const enemy = game.scene.getEnemyPokemon(); + const enemy = game.scene.getEnemyPokemon()!; vi.spyOn(enemy, "getHpRatio").mockReturnValue(targetHpRatio); @@ -61,7 +61,7 @@ describe("Moves - Hard Press", () => { it("should return 1 power if target HP ratio is at 1%", async () => { await game.startBattle([Species.PIKACHU]); const targetHpRatio = .01; - const enemy = game.scene.getEnemyPokemon(); + const enemy = game.scene.getEnemyPokemon()!; vi.spyOn(enemy, "getHpRatio").mockReturnValue(targetHpRatio); @@ -74,7 +74,7 @@ describe("Moves - Hard Press", () => { it("should return 1 power if target HP ratio is less than 1%", async () => { await game.startBattle([Species.PIKACHU]); const targetHpRatio = .005; - const enemy = game.scene.getEnemyPokemon(); + const enemy = game.scene.getEnemyPokemon()!; vi.spyOn(enemy, "getHpRatio").mockReturnValue(targetHpRatio); diff --git a/src/test/moves/hyper_beam.test.ts b/src/test/moves/hyper_beam.test.ts index e7d3454ba32..369d4cac853 100644 --- a/src/test/moves/hyper_beam.test.ts +++ b/src/test/moves/hyper_beam.test.ts @@ -43,8 +43,8 @@ describe("Moves - Hyper Beam", () => { async () => { await game.startBattle([Species.MAGIKARP]); - const leadPokemon = game.scene.getPlayerPokemon(); - const enemyPokemon = game.scene.getEnemyPokemon(); + const leadPokemon = game.scene.getPlayerPokemon()!; + const enemyPokemon = game.scene.getEnemyPokemon()!; game.doAttack(getMovePosition(game.scene, 0, Moves.HYPER_BEAM)); diff --git a/src/test/moves/light_screen.test.ts b/src/test/moves/light_screen.test.ts index e47b6fe93ea..9de1f8c492b 100644 --- a/src/test/moves/light_screen.test.ts +++ b/src/test/moves/light_screen.test.ts @@ -48,7 +48,7 @@ describe("Moves - Light Screen", () => { await game.phaseInterceptor.to(TurnEndPhase); - const mockedDmg = getMockedMoveDamage(game.scene.getEnemyPokemon(), game.scene.getPlayerPokemon(), allMoves[moveToUse]); + const mockedDmg = getMockedMoveDamage(game.scene.getEnemyPokemon()!, game.scene.getPlayerPokemon()!, allMoves[moveToUse]); expect(mockedDmg).toBe(allMoves[moveToUse].power * singleBattleMultiplier); }); @@ -63,7 +63,7 @@ describe("Moves - Light Screen", () => { game.doAttack(getMovePosition(game.scene, 1, moveToUse)); await game.phaseInterceptor.to(TurnEndPhase); - const mockedDmg = getMockedMoveDamage(game.scene.getEnemyPokemon(), game.scene.getPlayerPokemon(), allMoves[moveToUse]); + const mockedDmg = getMockedMoveDamage(game.scene.getEnemyPokemon()!, game.scene.getPlayerPokemon()!, allMoves[moveToUse]); expect(mockedDmg).toBe(allMoves[moveToUse].power * doubleBattleMultiplier); }); @@ -75,7 +75,7 @@ describe("Moves - Light Screen", () => { game.doAttack(getMovePosition(game.scene, 0, moveToUse)); await game.phaseInterceptor.to(TurnEndPhase); - const mockedDmg = getMockedMoveDamage(game.scene.getEnemyPokemon(), game.scene.getPlayerPokemon(), allMoves[moveToUse]); + const mockedDmg = getMockedMoveDamage(game.scene.getEnemyPokemon()!, game.scene.getPlayerPokemon()!, allMoves[moveToUse]); expect(mockedDmg).toBe(allMoves[moveToUse].power); }); diff --git a/src/test/moves/lucky_chant.test.ts b/src/test/moves/lucky_chant.test.ts index 1a29edb8052..1232ce9ffc3 100644 --- a/src/test/moves/lucky_chant.test.ts +++ b/src/test/moves/lucky_chant.test.ts @@ -41,7 +41,7 @@ describe("Moves - Lucky Chant", () => { async () => { await game.startBattle([Species.CHARIZARD]); - const playerPokemon = game.scene.getPlayerPokemon(); + const playerPokemon = game.scene.getPlayerPokemon()!; game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); @@ -91,8 +91,8 @@ describe("Moves - Lucky Chant", () => { await game.startBattle([Species.CHARIZARD]); - const playerPokemon = game.scene.getPlayerPokemon(); - const enemyPokemon = game.scene.getEnemyPokemon(); + const playerPokemon = game.scene.getPlayerPokemon()!; + const enemyPokemon = game.scene.getEnemyPokemon()!; enemyPokemon.addTag(BattlerTagType.ALWAYS_CRIT, 2, Moves.NONE, 0); diff --git a/src/test/moves/make_it_rain.test.ts b/src/test/moves/make_it_rain.test.ts index 850f8f644b8..72386930873 100644 --- a/src/test/moves/make_it_rain.test.ts +++ b/src/test/moves/make_it_rain.test.ts @@ -55,8 +55,8 @@ describe("Moves - Make It Rain", () => { await game.startBattle([Species.CHARIZARD]); - const playerPokemon = game.scene.getPlayerPokemon(); - const enemyPokemon = game.scene.getEnemyPokemon(); + const playerPokemon = game.scene.getPlayerPokemon()!; + const enemyPokemon = game.scene.getEnemyPokemon()!; game.doAttack(getMovePosition(game.scene, 0, Moves.MAKE_IT_RAIN)); diff --git a/src/test/moves/miracle_eye.test.ts b/src/test/moves/miracle_eye.test.ts index 188c5736fc4..53d575ea96d 100644 --- a/src/test/moves/miracle_eye.test.ts +++ b/src/test/moves/miracle_eye.test.ts @@ -35,7 +35,7 @@ describe("Internals", () => { it("should allow Psychic moves to hit Dark types", async () => { await game.startBattle(); - const enemy = game.scene.getEnemyPokemon(); + const enemy = game.scene.getEnemyPokemon()!; game.doAttack(getMovePosition(game.scene, 0, Moves.CONFUSION)); await game.toNextTurn(); diff --git a/src/test/moves/purify.test.ts b/src/test/moves/purify.test.ts index 4d108c43d4b..0367cc5a9b2 100644 --- a/src/test/moves/purify.test.ts +++ b/src/test/moves/purify.test.ts @@ -42,8 +42,8 @@ describe("Moves - Purify", () => { async () => { await game.startBattle(); - const enemyPokemon: EnemyPokemon = game.scene.getEnemyPokemon(); - const playerPokemon: PlayerPokemon = game.scene.getPlayerPokemon(); + const enemyPokemon: EnemyPokemon = game.scene.getEnemyPokemon()!; + const playerPokemon: PlayerPokemon = game.scene.getPlayerPokemon()!; playerPokemon.hp = playerPokemon.getMaxHp() - 1; enemyPokemon.status = new Status(StatusEffect.BURN); @@ -51,7 +51,7 @@ describe("Moves - Purify", () => { game.doAttack(getMovePosition(game.scene, 0, Moves.PURIFY)); await game.phaseInterceptor.to(MoveEndPhase); - expect(enemyPokemon.status).toBe(undefined); + expect(enemyPokemon.status).toBeNull(); expect(playerPokemon.isFullHp()).toBe(true); }, TIMEOUT @@ -62,7 +62,7 @@ describe("Moves - Purify", () => { async () => { await game.startBattle(); - const playerPokemon: PlayerPokemon = game.scene.getPlayerPokemon(); + const playerPokemon: PlayerPokemon = game.scene.getPlayerPokemon()!; playerPokemon.hp = playerPokemon.getMaxHp() - 1; const playerInitialHp = playerPokemon.hp; diff --git a/src/test/moves/reflect.test.ts b/src/test/moves/reflect.test.ts index 821d9df437a..f5ea489a75e 100644 --- a/src/test/moves/reflect.test.ts +++ b/src/test/moves/reflect.test.ts @@ -47,7 +47,7 @@ describe("Moves - Reflect", () => { game.doAttack(getMovePosition(game.scene, 0, moveToUse)); await game.phaseInterceptor.to(TurnEndPhase); - const mockedDmg = getMockedMoveDamage(game.scene.getEnemyPokemon(), game.scene.getPlayerPokemon(), allMoves[moveToUse]); + const mockedDmg = getMockedMoveDamage(game.scene.getEnemyPokemon()!, game.scene.getPlayerPokemon()!, allMoves[moveToUse]); expect(mockedDmg).toBe(allMoves[moveToUse].power * singleBattleMultiplier); }); @@ -62,7 +62,7 @@ describe("Moves - Reflect", () => { game.doAttack(getMovePosition(game.scene, 1, moveToUse)); await game.phaseInterceptor.to(TurnEndPhase); - const mockedDmg = getMockedMoveDamage(game.scene.getEnemyPokemon(), game.scene.getPlayerPokemon(), allMoves[moveToUse]); + const mockedDmg = getMockedMoveDamage(game.scene.getEnemyPokemon()!, game.scene.getPlayerPokemon()!, allMoves[moveToUse]); expect(mockedDmg).toBe(allMoves[moveToUse].power * doubleBattleMultiplier); }); @@ -75,7 +75,7 @@ describe("Moves - Reflect", () => { await game.phaseInterceptor.to(TurnEndPhase); - const mockedDmg = getMockedMoveDamage(game.scene.getEnemyPokemon(), game.scene.getPlayerPokemon(), allMoves[moveToUse]); + const mockedDmg = getMockedMoveDamage(game.scene.getEnemyPokemon()!, game.scene.getPlayerPokemon()!, allMoves[moveToUse]); expect(mockedDmg).toBe(allMoves[moveToUse].power); }); diff --git a/src/test/moves/roost.test.ts b/src/test/moves/roost.test.ts index 9ebd52e457d..a9036dcb478 100644 --- a/src/test/moves/roost.test.ts +++ b/src/test/moves/roost.test.ts @@ -40,7 +40,7 @@ describe("Moves - Roost", () => { async () => { await game.startBattle([Species.MAGIKARP]); - const enemyPokemon = game.scene.getEnemyPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon()!; const enemyStartingHp = enemyPokemon.hp; diff --git a/src/test/moves/spit_up.test.ts b/src/test/moves/spit_up.test.ts index 298c96d6d66..ec0a53028ff 100644 --- a/src/test/moves/spit_up.test.ts +++ b/src/test/moves/spit_up.test.ts @@ -45,10 +45,10 @@ describe("Moves - Spit Up", () => { await game.startBattle([Species.ABOMASNOW]); - const pokemon = game.scene.getPlayerPokemon(); + const pokemon = game.scene.getPlayerPokemon()!; pokemon.addTag(BattlerTagType.STOCKPILING); - const stockpilingTag = pokemon.getTag(StockpilingTag); + const stockpilingTag = pokemon.getTag(StockpilingTag)!; expect(stockpilingTag).toBeDefined(); expect(stockpilingTag.stockpiledCount).toBe(stacksToSetup); @@ -69,11 +69,11 @@ describe("Moves - Spit Up", () => { await game.startBattle([Species.ABOMASNOW]); - const pokemon = game.scene.getPlayerPokemon(); + const pokemon = game.scene.getPlayerPokemon()!; pokemon.addTag(BattlerTagType.STOCKPILING); pokemon.addTag(BattlerTagType.STOCKPILING); - const stockpilingTag = pokemon.getTag(StockpilingTag); + const stockpilingTag = pokemon.getTag(StockpilingTag)!; expect(stockpilingTag).toBeDefined(); expect(stockpilingTag.stockpiledCount).toBe(stacksToSetup); @@ -94,12 +94,12 @@ describe("Moves - Spit Up", () => { await game.startBattle([Species.ABOMASNOW]); - const pokemon = game.scene.getPlayerPokemon(); + const pokemon = game.scene.getPlayerPokemon()!; pokemon.addTag(BattlerTagType.STOCKPILING); pokemon.addTag(BattlerTagType.STOCKPILING); pokemon.addTag(BattlerTagType.STOCKPILING); - const stockpilingTag = pokemon.getTag(StockpilingTag); + const stockpilingTag = pokemon.getTag(StockpilingTag)!; expect(stockpilingTag).toBeDefined(); expect(stockpilingTag.stockpiledCount).toBe(stacksToSetup); @@ -118,9 +118,9 @@ describe("Moves - Spit Up", () => { it("fails without stacks", { timeout: 10000 }, async () => { await game.startBattle([Species.ABOMASNOW]); - const pokemon = game.scene.getPlayerPokemon(); + const pokemon = game.scene.getPlayerPokemon()!; - const stockpilingTag = pokemon.getTag(StockpilingTag); + const stockpilingTag = pokemon.getTag(StockpilingTag)!; expect(stockpilingTag).toBeUndefined(); vi.spyOn(allMoves[Moves.SPIT_UP], "calculateBattlePower"); @@ -137,10 +137,10 @@ describe("Moves - Spit Up", () => { it("decreases stats based on stored values (both boosts equal)", { timeout: 10000 }, async () => { await game.startBattle([Species.ABOMASNOW]); - const pokemon = game.scene.getPlayerPokemon(); + const pokemon = game.scene.getPlayerPokemon()!; pokemon.addTag(BattlerTagType.STOCKPILING); - const stockpilingTag = pokemon.getTag(StockpilingTag); + const stockpilingTag = pokemon.getTag(StockpilingTag)!; expect(stockpilingTag).toBeDefined(); vi.spyOn(allMoves[Moves.SPIT_UP], "calculateBattlePower"); @@ -166,10 +166,10 @@ describe("Moves - Spit Up", () => { it("decreases stats based on stored values (different boosts)", { timeout: 10000 }, async () => { await game.startBattle([Species.ABOMASNOW]); - const pokemon = game.scene.getPlayerPokemon(); + const pokemon = game.scene.getPlayerPokemon()!; pokemon.addTag(BattlerTagType.STOCKPILING); - const stockpilingTag = pokemon.getTag(StockpilingTag); + const stockpilingTag = pokemon.getTag(StockpilingTag)!; expect(stockpilingTag).toBeDefined(); // for the sake of simplicity (and because other tests cover the setup), set boost amounts directly diff --git a/src/test/moves/stockpile.test.ts b/src/test/moves/stockpile.test.ts index 604b08745eb..375eeab3c95 100644 --- a/src/test/moves/stockpile.test.ts +++ b/src/test/moves/stockpile.test.ts @@ -41,7 +41,7 @@ describe("Moves - Stockpile", () => { it("Gains a stockpile stack and increases DEF and SPDEF by 1 on each use, fails at max stacks (3)", { timeout: 10000 }, async () => { await game.startBattle([Species.ABOMASNOW]); - const user = game.scene.getPlayerPokemon(); + const user = game.scene.getPlayerPokemon()!; // Unfortunately, Stockpile stacks are not directly queryable (i.e. there is no pokemon.getStockpileStacks()), // we just have to know that they're implemented as a BattlerTag. @@ -59,7 +59,7 @@ describe("Moves - Stockpile", () => { game.doAttack(getMovePosition(game.scene, 0, Moves.STOCKPILE)); await game.phaseInterceptor.to(TurnInitPhase); - const stockpilingTag = user.getTag(StockpilingTag); + const stockpilingTag = user.getTag(StockpilingTag)!; const def = user.summonData.battleStats[BattleStat.DEF]; const spdef = user.summonData.battleStats[BattleStat.SPDEF]; @@ -82,7 +82,7 @@ describe("Moves - Stockpile", () => { it("Gains a stockpile stack even if DEF and SPDEF are at +6", { timeout: 10000 }, async () => { await game.startBattle([Species.ABOMASNOW]); - const user = game.scene.getPlayerPokemon(); + const user = game.scene.getPlayerPokemon()!; user.summonData.battleStats[BattleStat.DEF] = 6; user.summonData.battleStats[BattleStat.SPDEF] = 6; @@ -94,7 +94,7 @@ describe("Moves - Stockpile", () => { game.doAttack(getMovePosition(game.scene, 0, Moves.STOCKPILE)); await game.phaseInterceptor.to(TurnInitPhase); - const stockpilingTag = user.getTag(StockpilingTag); + const stockpilingTag = user.getTag(StockpilingTag)!; expect(stockpilingTag).toBeDefined(); expect(stockpilingTag.stockpiledCount).toBe(1); expect(user.summonData.battleStats[BattleStat.DEF]).toBe(6); @@ -106,7 +106,7 @@ describe("Moves - Stockpile", () => { game.doAttack(getMovePosition(game.scene, 0, Moves.STOCKPILE)); await game.phaseInterceptor.to(TurnInitPhase); - const stockpilingTagAgain = user.getTag(StockpilingTag); + const stockpilingTagAgain = user.getTag(StockpilingTag)!; expect(stockpilingTagAgain).toBeDefined(); expect(stockpilingTagAgain.stockpiledCount).toBe(2); expect(user.summonData.battleStats[BattleStat.DEF]).toBe(6); diff --git a/src/test/moves/swallow.test.ts b/src/test/moves/swallow.test.ts index 9a0a19dce2b..aed30445fd2 100644 --- a/src/test/moves/swallow.test.ts +++ b/src/test/moves/swallow.test.ts @@ -44,13 +44,13 @@ describe("Moves - Swallow", () => { await game.startBattle([Species.ABOMASNOW]); - const pokemon = game.scene.getPlayerPokemon(); + const pokemon = game.scene.getPlayerPokemon()!; vi.spyOn(pokemon, "getMaxHp").mockReturnValue(100); pokemon["hp"] = 1; pokemon.addTag(BattlerTagType.STOCKPILING); - const stockpilingTag = pokemon.getTag(StockpilingTag); + const stockpilingTag = pokemon.getTag(StockpilingTag)!; expect(stockpilingTag).toBeDefined(); expect(stockpilingTag.stockpiledCount).toBe(stacksToSetup); @@ -71,14 +71,14 @@ describe("Moves - Swallow", () => { await game.startBattle([Species.ABOMASNOW]); - const pokemon = game.scene.getPlayerPokemon(); + const pokemon = game.scene.getPlayerPokemon()!; vi.spyOn(pokemon, "getMaxHp").mockReturnValue(100); pokemon["hp"] = 1; pokemon.addTag(BattlerTagType.STOCKPILING); pokemon.addTag(BattlerTagType.STOCKPILING); - const stockpilingTag = pokemon.getTag(StockpilingTag); + const stockpilingTag = pokemon.getTag(StockpilingTag)!; expect(stockpilingTag).toBeDefined(); expect(stockpilingTag.stockpiledCount).toBe(stacksToSetup); @@ -99,7 +99,7 @@ describe("Moves - Swallow", () => { await game.startBattle([Species.ABOMASNOW]); - const pokemon = game.scene.getPlayerPokemon(); + const pokemon = game.scene.getPlayerPokemon()!; vi.spyOn(pokemon, "getMaxHp").mockReturnValue(100); pokemon["hp"] = 0.0001; @@ -107,7 +107,7 @@ describe("Moves - Swallow", () => { pokemon.addTag(BattlerTagType.STOCKPILING); pokemon.addTag(BattlerTagType.STOCKPILING); - const stockpilingTag = pokemon.getTag(StockpilingTag); + const stockpilingTag = pokemon.getTag(StockpilingTag)!; expect(stockpilingTag).toBeDefined(); expect(stockpilingTag.stockpiledCount).toBe(stacksToSetup); @@ -126,9 +126,9 @@ describe("Moves - Swallow", () => { it("fails without stacks", { timeout: 10000 }, async () => { await game.startBattle([Species.ABOMASNOW]); - const pokemon = game.scene.getPlayerPokemon(); + const pokemon = game.scene.getPlayerPokemon()!; - const stockpilingTag = pokemon.getTag(StockpilingTag); + const stockpilingTag = pokemon.getTag(StockpilingTag)!; expect(stockpilingTag).toBeUndefined(); game.doAttack(0); @@ -141,10 +141,10 @@ describe("Moves - Swallow", () => { it("decreases stats based on stored values (both boosts equal)", { timeout: 10000 }, async () => { await game.startBattle([Species.ABOMASNOW]); - const pokemon = game.scene.getPlayerPokemon(); + const pokemon = game.scene.getPlayerPokemon()!; pokemon.addTag(BattlerTagType.STOCKPILING); - const stockpilingTag = pokemon.getTag(StockpilingTag); + const stockpilingTag = pokemon.getTag(StockpilingTag)!; expect(stockpilingTag).toBeDefined(); game.doAttack(0); @@ -166,10 +166,10 @@ describe("Moves - Swallow", () => { it("decreases stats based on stored values (different boosts)", { timeout: 10000 }, async () => { await game.startBattle([Species.ABOMASNOW]); - const pokemon = game.scene.getPlayerPokemon(); + const pokemon = game.scene.getPlayerPokemon()!; pokemon.addTag(BattlerTagType.STOCKPILING); - const stockpilingTag = pokemon.getTag(StockpilingTag); + const stockpilingTag = pokemon.getTag(StockpilingTag)!; expect(stockpilingTag).toBeDefined(); // for the sake of simplicity (and because other tests cover the setup), set boost amounts directly diff --git a/src/test/moves/tailwind.test.ts b/src/test/moves/tailwind.test.ts index d88de680d8a..b2643dc68f3 100644 --- a/src/test/moves/tailwind.test.ts +++ b/src/test/moves/tailwind.test.ts @@ -80,8 +80,8 @@ describe("Abilities - Wind Rider", () => { await game.startBattle([Species.MAGIKARP]); - const ally = game.scene.getPlayerPokemon(); - const enemy = game.scene.getEnemyPokemon(); + const ally = game.scene.getPlayerPokemon()!; + const enemy = game.scene.getEnemyPokemon()!; const allySpd = ally.getStat(Stat.SPD); const enemySpd = enemy.getStat(Stat.SPD); diff --git a/src/test/moves/thousand_arrows.test.ts b/src/test/moves/thousand_arrows.test.ts index 3b15610f896..84a71ee5256 100644 --- a/src/test/moves/thousand_arrows.test.ts +++ b/src/test/moves/thousand_arrows.test.ts @@ -39,7 +39,7 @@ describe("Moves - Thousand Arrows", () => { async () => { await game.startBattle([ Species.ILLUMISE ]); - const enemyPokemon = game.scene.getEnemyPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon()!; game.doAttack(getMovePosition(game.scene, 0, Moves.THOUSAND_ARROWS)); @@ -62,7 +62,7 @@ describe("Moves - Thousand Arrows", () => { await game.startBattle([ Species.ILLUMISE ]); - const enemyPokemon = game.scene.getEnemyPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon()!; game.doAttack(getMovePosition(game.scene, 0, Moves.THOUSAND_ARROWS)); @@ -84,9 +84,9 @@ describe("Moves - Thousand Arrows", () => { await game.startBattle([ Species.ILLUMISE ]); - const enemyPokemon = game.scene.getEnemyPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon()!; - enemyPokemon.addTag(BattlerTagType.MAGNET_RISEN, null, Moves.MAGNET_RISE); + enemyPokemon.addTag(BattlerTagType.MAGNET_RISEN, undefined, Moves.MAGNET_RISE); game.doAttack(getMovePosition(game.scene, 0, Moves.THOUSAND_ARROWS)); diff --git a/src/test/moves/tidy_up.test.ts b/src/test/moves/tidy_up.test.ts index 83e1dda07cb..e35a438c562 100644 --- a/src/test/moves/tidy_up.test.ts +++ b/src/test/moves/tidy_up.test.ts @@ -106,7 +106,7 @@ describe("Moves - Tidy Up", () => { it("user's stats are raised with no traps set", async() => { await game.startBattle(); - const player = game.scene.getPlayerPokemon().summonData.battleStats; + const player = game.scene.getPlayerPokemon()!.summonData.battleStats; expect(player[BattleStat.ATK]).toBe(0); expect(player[BattleStat.SPD]).toBe(0); diff --git a/src/test/moves/u_turn.test.ts b/src/test/moves/u_turn.test.ts index c54a94dde2b..2c12a4da43b 100644 --- a/src/test/moves/u_turn.test.ts +++ b/src/test/moves/u_turn.test.ts @@ -43,7 +43,7 @@ describe("Moves - U-turn", () => { Species.RAICHU, Species.SHUCKLE ]); - game.scene.getPlayerPokemon().hp = playerHp; + game.scene.getPlayerPokemon()!.hp = playerHp; // act game.doAttack(getMovePosition(game.scene, 0, Moves.U_TURN)); @@ -53,7 +53,7 @@ describe("Moves - U-turn", () => { // assert expect(game.scene.getParty()[1].hp).toEqual(Math.floor(game.scene.getParty()[1].getMaxHp() * 0.33 + playerHp)); expect(game.phaseInterceptor.log).toContain("SwitchSummonPhase"); - expect(game.scene.getPlayerPokemon().species.speciesId).toBe(Species.SHUCKLE); + expect(game.scene.getPlayerPokemon()!.species.speciesId).toBe(Species.SHUCKLE); }, 20000); it("triggers rough skin on the u-turn user before a new pokemon is switched in", async() => { @@ -70,9 +70,10 @@ describe("Moves - U-turn", () => { await game.phaseInterceptor.to(SwitchPhase, false); // assert - expect(game.scene.getPlayerPokemon().hp).not.toEqual(game.scene.getPlayerPokemon().getMaxHp()); - expect(game.scene.getEnemyPokemon().battleData.abilityRevealed).toBe(true); // proxy for asserting ability activated - expect(game.scene.getPlayerPokemon().species.speciesId).toEqual(Species.RAICHU); + const playerPkm = game.scene.getPlayerPokemon()!; + expect(playerPkm.hp).not.toEqual(playerPkm.getMaxHp()); + expect(game.scene.getEnemyPokemon()!.battleData.abilityRevealed).toBe(true); // proxy for asserting ability activated + expect(playerPkm.species.speciesId).toEqual(Species.RAICHU); expect(game.phaseInterceptor.log).not.toContain("SwitchSummonPhase"); }, 20000); @@ -83,16 +84,17 @@ describe("Moves - U-turn", () => { Species.RAICHU, Species.SHUCKLE ]); - vi.spyOn(game.scene.getEnemyPokemon(), "randSeedInt").mockReturnValue(0); + vi.spyOn(game.scene.getEnemyPokemon()!, "randSeedInt").mockReturnValue(0); // act game.doAttack(getMovePosition(game.scene, 0, Moves.U_TURN)); await game.phaseInterceptor.to(SwitchPhase, false); // assert - expect(game.scene.getPlayerPokemon().status?.effect).toEqual(StatusEffect.POISON); - expect(game.scene.getPlayerPokemon().species.speciesId).toEqual(Species.RAICHU); - expect(game.scene.getEnemyPokemon().battleData.abilityRevealed).toBe(true); // proxy for asserting ability activated + const playerPkm = game.scene.getPlayerPokemon()!; + expect(playerPkm.status?.effect).toEqual(StatusEffect.POISON); + expect(playerPkm.species.speciesId).toEqual(Species.RAICHU); + expect(game.scene.getEnemyPokemon()!.battleData.abilityRevealed).toBe(true); // proxy for asserting ability activated expect(game.phaseInterceptor.log).not.toContain("SwitchSummonPhase"); }, 20000); }); diff --git a/src/test/settingMenu/helpers/menuManip.ts b/src/test/settingMenu/helpers/menuManip.ts index f33867476cf..4fd5f526897 100644 --- a/src/test/settingMenu/helpers/menuManip.ts +++ b/src/test/settingMenu/helpers/menuManip.ts @@ -70,7 +70,7 @@ export class MenuManip { weWantThisBindInstead(keycode) { this.keycode = Phaser.Input.Keyboard.KeyCodes[keycode]; const icon = getIconWithKeycode(this.config, this.keycode); - const key = getKeyWithKeycode(this.config, this.keycode); + const key = getKeyWithKeycode(this.config, this.keycode)!; // TODO: is this bang correct? const _keys = key.toLowerCase().split("_"); const iconIdentifier = _keys[_keys.length-1]; expect(icon.toLowerCase().includes(iconIdentifier)).toEqual(true); @@ -78,7 +78,7 @@ export class MenuManip { } whenWeDelete(settingName?: string) { - this.settingName = SettingKeyboard[settingName] || this.settingName; + this.settingName = settingName ? SettingKeyboard[settingName] : this.settingName; // const key = getKeyWithSettingName(this.config, this.settingName); deleteBind(this.config, this.settingName); // expect(this.config.custom[key]).toEqual(-1); @@ -86,7 +86,7 @@ export class MenuManip { } whenWeTryToDelete(settingName?: string) { - this.settingName = SettingKeyboard[settingName] || this.settingName; + this.settingName = settingName ? SettingKeyboard[settingName] : this.settingName; deleteBind(this.config, this.settingName); return this; } diff --git a/src/test/settingMenu/rebinding_setting.test.ts b/src/test/settingMenu/rebinding_setting.test.ts index 3bc17109c95..eead23972c2 100644 --- a/src/test/settingMenu/rebinding_setting.test.ts +++ b/src/test/settingMenu/rebinding_setting.test.ts @@ -37,13 +37,13 @@ describe("Test Rebinding", () => { expect(button).toEqual(Button.LEFT); }); it("Check key for Keyboard KeyCode", () => { - const key = getKeyWithKeycode(config, Phaser.Input.Keyboard.KeyCodes.LEFT); + const key = getKeyWithKeycode(config, Phaser.Input.Keyboard.KeyCodes.LEFT) ?? ""; const settingName = config.custom[key]; const button = config.settings[settingName]; expect(button).toEqual(Button.LEFT); }); it("Check key for currenly Assigned to action not alt", () => { - const key = getKeyWithKeycode(config, Phaser.Input.Keyboard.KeyCodes.A); + const key = getKeyWithKeycode(config, Phaser.Input.Keyboard.KeyCodes.A) ?? ""; const settingName = config.custom[key]; const button = config.settings[settingName]; expect(button).toEqual(Button.LEFT); @@ -66,25 +66,25 @@ describe("Test Rebinding", () => { }); it("Check icon for currenly Assigned to key code", () => { const keycode = Phaser.Input.Keyboard.KeyCodes.LEFT; - const key = getKeyWithKeycode(config, keycode); + const key = getKeyWithKeycode(config, keycode) ?? ""; const icon = config.icons[key]; expect(icon).toEqual("KEY_ARROW_LEFT.png"); }); it("Check icon for currenly Assigned to key code", () => { const keycode = Phaser.Input.Keyboard.KeyCodes.A; - const key = getKeyWithKeycode(config, keycode); + const key = getKeyWithKeycode(config, keycode) ?? ""; const icon = config.icons[key]; expect(icon).toEqual("A.png"); }); it("Check icon for currenly Assigned to setting name", () => { const settingName = SettingKeyboard.Button_Left; - const key = getKeyWithSettingName(config, settingName); + const key = getKeyWithSettingName(config, settingName) ?? ""; const icon = config.icons[key]; expect(icon).toEqual("KEY_ARROW_LEFT.png"); }); it("Check icon for currenly Assigned to setting name alt", () => { const settingName = SettingKeyboard.Alt_Button_Left; - const key = getKeyWithSettingName(config, settingName); + const key = getKeyWithSettingName(config, settingName) ?? ""; const icon = config.icons[key]; expect(icon).toEqual("A.png"); }); @@ -369,7 +369,7 @@ describe("Test Rebinding", () => { it("test keyboard listener", () => { const keyDown = Phaser.Input.Keyboard.KeyCodes.S; - const key = getKeyWithKeycode(config, keyDown); + const key = getKeyWithKeycode(config, keyDown) ?? ""; const settingName = config.custom[key]; const buttonDown = config.settings[settingName]; expect(buttonDown).toEqual(Button.DOWN); diff --git a/src/test/sprites/pokemonSprite.test.ts b/src/test/sprites/pokemonSprite.test.ts index ce847751b6b..deb5844d677 100644 --- a/src/test/sprites/pokemonSprite.test.ts +++ b/src/test/sprites/pokemonSprite.test.ts @@ -23,9 +23,12 @@ describe("check if every variant's sprite are correctly set", () => { expVariant = masterlist.exp; femaleVariant = masterlist.female; backVariant = masterlist.back; - delete masterlist.exp; - delete masterlist.female; - delete masterlist.back; + //@ts-ignore + delete masterlist.exp; //TODO: resolve ts-ignore + //@ts-ignore + delete masterlist.female; //TODO: resolve ts-ignore + //@ts-ignore + delete masterlist.back; //TODO: resolve ts-ignore }); it("data should not be undefined", () => { @@ -103,7 +106,7 @@ describe("check if every variant's sprite are correctly set", () => { } function getMissingFiles(keys: Record, dirPath: string): string[] { - const errors = []; + const errors: string[] = []; for (const key of Object.keys(keys)) { const row = keys[key]; for (const [index, elm] of row.entries()) { diff --git a/src/test/ui/starter-select.test.ts b/src/test/ui/starter-select.test.ts index eae5b3fe3a5..b61338bfcad 100644 --- a/src/test/ui/starter-select.test.ts +++ b/src/test/ui/starter-select.test.ts @@ -55,8 +55,8 @@ describe("UI - Starter select", () => { game.phaseInterceptor.unlock(); }); await game.phaseInterceptor.run(SelectStarterPhase); - let options: OptionSelectItem[]; - let optionSelectUiHandler: OptionSelectUiHandler; + let options: OptionSelectItem[] = []; + let optionSelectUiHandler: OptionSelectUiHandler | undefined; await new Promise((resolve) => { game.onNextPrompt("SelectStarterPhase", Mode.OPTION_SELECT, () => { optionSelectUiHandler = game.scene.ui.getHandler() as OptionSelectUiHandler; @@ -69,7 +69,7 @@ describe("UI - Starter select", () => { expect(options.some(option => option.label === "Manage Moves")).toBe(true); expect(options.some(option => option.label === "Use Candies")).toBe(true); expect(options.some(option => option.label === "Cancel")).toBe(true); - optionSelectUiHandler.processInput(Button.ACTION); + optionSelectUiHandler?.processInput(Button.ACTION); await new Promise((resolve) => { game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { @@ -116,8 +116,8 @@ describe("UI - Starter select", () => { game.phaseInterceptor.unlock(); }); await game.phaseInterceptor.run(SelectStarterPhase); - let options: OptionSelectItem[]; - let optionSelectUiHandler: OptionSelectUiHandler; + let options: OptionSelectItem[] = []; + let optionSelectUiHandler: OptionSelectUiHandler | undefined; await new Promise((resolve) => { game.onNextPrompt("SelectStarterPhase", Mode.OPTION_SELECT, () => { optionSelectUiHandler = game.scene.ui.getHandler() as OptionSelectUiHandler; @@ -130,7 +130,7 @@ describe("UI - Starter select", () => { expect(options.some(option => option.label === "Manage Moves")).toBe(true); expect(options.some(option => option.label === "Use Candies")).toBe(true); expect(options.some(option => option.label === "Cancel")).toBe(true); - optionSelectUiHandler.processInput(Button.ACTION); + optionSelectUiHandler?.processInput(Button.ACTION); await new Promise((resolve) => { game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { @@ -180,8 +180,8 @@ describe("UI - Starter select", () => { game.phaseInterceptor.unlock(); }); await game.phaseInterceptor.run(SelectStarterPhase); - let options: OptionSelectItem[]; - let optionSelectUiHandler: OptionSelectUiHandler; + let options: OptionSelectItem[] = []; + let optionSelectUiHandler: OptionSelectUiHandler | undefined; await new Promise((resolve) => { game.onNextPrompt("SelectStarterPhase", Mode.OPTION_SELECT, () => { optionSelectUiHandler = game.scene.ui.getHandler() as OptionSelectUiHandler; @@ -194,7 +194,7 @@ describe("UI - Starter select", () => { expect(options.some(option => option.label === "Manage Moves")).toBe(true); expect(options.some(option => option.label === "Use Candies")).toBe(true); expect(options.some(option => option.label === "Cancel")).toBe(true); - optionSelectUiHandler.processInput(Button.ACTION); + optionSelectUiHandler?.processInput(Button.ACTION); await new Promise((resolve) => { game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { @@ -242,8 +242,8 @@ describe("UI - Starter select", () => { game.phaseInterceptor.unlock(); }); await game.phaseInterceptor.run(SelectStarterPhase); - let options: OptionSelectItem[]; - let optionSelectUiHandler: OptionSelectUiHandler; + let options: OptionSelectItem[] = []; + let optionSelectUiHandler: OptionSelectUiHandler | undefined; await new Promise((resolve) => { game.onNextPrompt("SelectStarterPhase", Mode.OPTION_SELECT, () => { optionSelectUiHandler = game.scene.ui.getHandler() as OptionSelectUiHandler; @@ -256,7 +256,7 @@ describe("UI - Starter select", () => { expect(options.some(option => option.label === "Manage Moves")).toBe(true); expect(options.some(option => option.label === "Use Candies")).toBe(true); expect(options.some(option => option.label === "Cancel")).toBe(true); - optionSelectUiHandler.processInput(Button.ACTION); + optionSelectUiHandler?.processInput(Button.ACTION); await new Promise((resolve) => { game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { @@ -303,8 +303,8 @@ describe("UI - Starter select", () => { game.phaseInterceptor.unlock(); }); await game.phaseInterceptor.run(SelectStarterPhase); - let options: OptionSelectItem[]; - let optionSelectUiHandler: OptionSelectUiHandler; + let options: OptionSelectItem[] = []; + let optionSelectUiHandler: OptionSelectUiHandler | undefined; await new Promise((resolve) => { game.onNextPrompt("SelectStarterPhase", Mode.OPTION_SELECT, () => { optionSelectUiHandler = game.scene.ui.getHandler() as OptionSelectUiHandler; @@ -317,7 +317,7 @@ describe("UI - Starter select", () => { expect(options.some(option => option.label === "Manage Moves")).toBe(true); expect(options.some(option => option.label === "Use Candies")).toBe(true); expect(options.some(option => option.label === "Cancel")).toBe(true); - optionSelectUiHandler.processInput(Button.ACTION); + optionSelectUiHandler?.processInput(Button.ACTION); await new Promise((resolve) => { game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { @@ -364,8 +364,8 @@ describe("UI - Starter select", () => { game.phaseInterceptor.unlock(); }); await game.phaseInterceptor.run(SelectStarterPhase); - let options: OptionSelectItem[]; - let optionSelectUiHandler: OptionSelectUiHandler; + let options: OptionSelectItem[] = []; + let optionSelectUiHandler: OptionSelectUiHandler | undefined; await new Promise((resolve) => { game.onNextPrompt("SelectStarterPhase", Mode.OPTION_SELECT, () => { optionSelectUiHandler = game.scene.ui.getHandler() as OptionSelectUiHandler; @@ -378,7 +378,7 @@ describe("UI - Starter select", () => { expect(options.some(option => option.label === "Manage Moves")).toBe(true); expect(options.some(option => option.label === "Use Candies")).toBe(true); expect(options.some(option => option.label === "Cancel")).toBe(true); - optionSelectUiHandler.processInput(Button.ACTION); + optionSelectUiHandler?.processInput(Button.ACTION); await new Promise((resolve) => { game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { @@ -426,8 +426,8 @@ describe("UI - Starter select", () => { game.phaseInterceptor.unlock(); }); await game.phaseInterceptor.run(SelectStarterPhase); - let options: OptionSelectItem[]; - let optionSelectUiHandler: OptionSelectUiHandler; + let options: OptionSelectItem[] = []; + let optionSelectUiHandler: OptionSelectUiHandler | undefined; await new Promise((resolve) => { game.onNextPrompt("SelectStarterPhase", Mode.OPTION_SELECT, () => { optionSelectUiHandler = game.scene.ui.getHandler() as OptionSelectUiHandler; @@ -440,7 +440,7 @@ describe("UI - Starter select", () => { expect(options.some(option => option.label === "Manage Moves")).toBe(true); expect(options.some(option => option.label === "Use Candies")).toBe(true); expect(options.some(option => option.label === "Cancel")).toBe(true); - optionSelectUiHandler.processInput(Button.ACTION); + optionSelectUiHandler?.processInput(Button.ACTION); await new Promise((resolve) => { game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { @@ -486,8 +486,8 @@ describe("UI - Starter select", () => { game.phaseInterceptor.unlock(); }); await game.phaseInterceptor.run(SelectStarterPhase); - let options: OptionSelectItem[]; - let optionSelectUiHandler: OptionSelectUiHandler; + let options: OptionSelectItem[] = []; + let optionSelectUiHandler: OptionSelectUiHandler | undefined; await new Promise((resolve) => { game.onNextPrompt("SelectStarterPhase", Mode.OPTION_SELECT, () => { optionSelectUiHandler = game.scene.ui.getHandler() as OptionSelectUiHandler; @@ -500,7 +500,7 @@ describe("UI - Starter select", () => { expect(options.some(option => option.label === "Manage Moves")).toBe(true); expect(options.some(option => option.label === "Use Candies")).toBe(true); expect(options.some(option => option.label === "Cancel")).toBe(true); - optionSelectUiHandler.processInput(Button.ACTION); + optionSelectUiHandler?.processInput(Button.ACTION); let starterSelectUiHandler: StarterSelectUiHandler; await new Promise((resolve) => { @@ -551,8 +551,8 @@ describe("UI - Starter select", () => { game.phaseInterceptor.unlock(); }); await game.phaseInterceptor.run(SelectStarterPhase); - let options: OptionSelectItem[]; - let optionSelectUiHandler: OptionSelectUiHandler; + let options: OptionSelectItem[] = []; + let optionSelectUiHandler: OptionSelectUiHandler | undefined; await new Promise((resolve) => { game.onNextPrompt("SelectStarterPhase", Mode.OPTION_SELECT, () => { optionSelectUiHandler = game.scene.ui.getHandler() as OptionSelectUiHandler; @@ -565,9 +565,9 @@ describe("UI - Starter select", () => { expect(options.some(option => option.label === "Manage Moves")).toBe(true); expect(options.some(option => option.label === "Use Candies")).toBe(true); expect(options.some(option => option.label === "Cancel")).toBe(true); - optionSelectUiHandler.processInput(Button.ACTION); + optionSelectUiHandler?.processInput(Button.ACTION); - let starterSelectUiHandler: StarterSelectUiHandler; + let starterSelectUiHandler: StarterSelectUiHandler | undefined; await new Promise((resolve) => { game.onNextPrompt("SelectStarterPhase", Mode.STARTER_SELECT, () => { starterSelectUiHandler = game.scene.ui.getHandler() as StarterSelectUiHandler; @@ -576,11 +576,11 @@ describe("UI - Starter select", () => { }); }); - expect(starterSelectUiHandler.starterSpecies.length).toBe(1); - expect(starterSelectUiHandler.starterSpecies[0].generation).toBe(1); - expect(starterSelectUiHandler.starterSpecies[0].speciesId).toBe(32); - expect(starterSelectUiHandler.cursorObj.x).toBe(53); - expect(starterSelectUiHandler.cursorObj.y).toBe(31); + expect(starterSelectUiHandler?.starterSpecies.length).toBe(1); + expect(starterSelectUiHandler?.starterSpecies[0].generation).toBe(1); + expect(starterSelectUiHandler?.starterSpecies[0].speciesId).toBe(32); + expect(starterSelectUiHandler?.cursorObj.x).toBe(53); + expect(starterSelectUiHandler?.cursorObj.y).toBe(31); game.onNextPrompt("SelectStarterPhase", Mode.CONFIRM, () => { const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; diff --git a/src/test/utils/TextInterceptor.ts b/src/test/utils/TextInterceptor.ts index a49f41f6be0..507161eb6d0 100644 --- a/src/test/utils/TextInterceptor.ts +++ b/src/test/utils/TextInterceptor.ts @@ -1,6 +1,6 @@ export default class TextInterceptor { private scene; - public logs = []; + public logs: string[] = []; constructor(scene) { this.scene = scene; scene.messageWrapper = this; @@ -17,6 +17,6 @@ export default class TextInterceptor { } getLatestMessage(): string { - return this.logs.pop(); + return this.logs.pop() ?? ""; } } diff --git a/src/test/utils/gameManager.ts b/src/test/utils/gameManager.ts index 842c6086058..771ab1e7081 100644 --- a/src/test/utils/gameManager.ts +++ b/src/test/utils/gameManager.ts @@ -81,7 +81,7 @@ export default class GameManager { * Ends the current phase. */ endPhase() { - this.scene.getCurrentPhase().end(); + this.scene.getCurrentPhase()?.end(); } /** @@ -174,7 +174,7 @@ export default class GameManager { // Confirm target selection if move is multi-target this.onNextPrompt("SelectTargetPhase", Mode.TARGET_SELECT, () => { const handler = this.scene.ui.getHandler() as TargetSelectUiHandler; - const move = (this.scene.getCurrentPhase() as SelectTargetPhase).getPokemon().getMoveset()[movePosition].getMove(); + const move = (this.scene.getCurrentPhase() as SelectTargetPhase).getPokemon().getMoveset()[movePosition]!.getMove(); // TODO: is the bang correct? if (move.isMultiTarget()) { handler.processInput(Button.ACTION); } @@ -255,7 +255,7 @@ export default class GameManager { */ isCurrentPhase(phaseTarget) { const targetName = typeof phaseTarget === "string" ? phaseTarget : phaseTarget.name; - return this.scene.getCurrentPhase().constructor.name === targetName; + return this.scene.getCurrentPhase()?.constructor.name === targetName; } /** @@ -278,7 +278,7 @@ export default class GameManager { await waitUntil(() => this.scene.ui?.getMode() === Mode.TITLE); await this.scene.gameData.tryExportData(GameDataType.SESSION, 0); await waitUntil(() => localStorage.hasOwnProperty("toExport")); - return resolve(localStorage.getItem("toExport")); + return resolve(localStorage.getItem("toExport")!); // TODO: is this bang correct?; }); } @@ -332,7 +332,7 @@ export default class GameManager { doRevivePokemon(pokemonIndex: number) { const party = this.scene.getParty(); const candidate = new ModifierTypeOption(modifierTypes.MAX_REVIVE(), 0); - const modifier = candidate.type.newModifier(party[pokemonIndex]); + const modifier = candidate.type!.newModifier(party[pokemonIndex]); this.scene.addModifier(modifier, false); } diff --git a/src/test/utils/gameManagerUtils.ts b/src/test/utils/gameManagerUtils.ts index 74a73bb7875..dfba55fc75c 100644 --- a/src/test/utils/gameManagerUtils.ts +++ b/src/test/utils/gameManagerUtils.ts @@ -85,6 +85,7 @@ export function waitUntil(truth) { export function getMovePosition(scene: BattleScene, pokemonIndex: 0 | 1, move: Moves) { const playerPokemon = scene.getPlayerField()[pokemonIndex]; const moveSet = playerPokemon.getMoveset(); - const index = moveSet.findIndex((m) => m.moveId === move); + const index = moveSet.findIndex((m) => m?.moveId === move); + console.log(`Move position for ${Moves[move]} (=${move}):`, index); return index; } diff --git a/src/test/utils/inputsHandler.ts b/src/test/utils/inputsHandler.ts index e41667dc873..148329ada32 100644 --- a/src/test/utils/inputsHandler.ts +++ b/src/test/utils/inputsHandler.ts @@ -7,13 +7,17 @@ import TouchControl from "#app/touch-controls"; import { JSDOM } from "jsdom"; import fs from "fs"; +interface LogEntry { + type: string; + button: any; +} export default class InputsHandler { private scene: BattleScene; private events: Phaser.Events.EventEmitter; private inputController: InputsController; - public log = []; - public logUp = []; + public log: LogEntry[] = []; + public logUp: LogEntry[] = []; private fakePad: Fakepad; private fakeMobile: FakeMobile; @@ -22,7 +26,7 @@ export default class InputsHandler { this.inputController = this.scene.inputController; this.fakePad = new Fakepad(pad_xbox360); this.fakeMobile = new FakeMobile(); - this.scene.input.gamepad.gamepads.push(this.fakePad); + this.scene.input.gamepad?.gamepads.push(this.fakePad); this.init(); } @@ -37,18 +41,18 @@ export default class InputsHandler { pressGamepadButton(button: integer, duration: integer): Promise { return new Promise(async (resolve) => { - this.scene.input.gamepad.emit("down", this.fakePad, {index: button}); + this.scene.input.gamepad?.emit("down", this.fakePad, {index: button}); await holdOn(duration); - this.scene.input.gamepad.emit("up", this.fakePad, {index: button}); + this.scene.input.gamepad?.emit("up", this.fakePad, {index: button}); resolve(); }); } pressKeyboardKey(key: integer, duration: integer): Promise { return new Promise(async (resolve) => { - this.scene.input.keyboard.emit("keydown", {keyCode: key}); + this.scene.input.keyboard?.emit("keydown", {keyCode: key}); await holdOn(duration); - this.scene.input.keyboard.emit("keyup", {keyCode: key}); + this.scene.input.keyboard?.emit("keyup", {keyCode: key}); resolve(); }); } @@ -57,7 +61,7 @@ export default class InputsHandler { const touchControl = new TouchControl(this.scene); touchControl.deactivatePressedKey(); //test purpose this.events = this.inputController.events; - this.scene.input.gamepad.emit("connected", this.fakePad); + this.scene.input.gamepad?.emit("connected", this.fakePad); this.listenInputs(); } @@ -77,7 +81,8 @@ class Fakepad extends Phaser.Input.Gamepad.Gamepad { public index: number; constructor(pad) { - super(undefined, {...pad, buttons: pad.deviceMapping, axes: []}); + //@ts-ignore + super(undefined, {...pad, buttons: pad.deviceMapping, axes: []}); //TODO: resolve ts-ignore this.id = "xbox_360_fakepad"; this.index = 0; } diff --git a/src/test/utils/mocks/mockClock.ts b/src/test/utils/mocks/mockClock.ts index ba12dc002cc..3664a831305 100644 --- a/src/test/utils/mocks/mockClock.ts +++ b/src/test/utils/mocks/mockClock.ts @@ -2,7 +2,7 @@ import Clock = Phaser.Time.Clock; export class MockClock extends Clock { - public overrideDelay: number; + public overrideDelay: number | undefined; constructor(scene) { super(scene); this.overrideDelay = undefined; diff --git a/src/test/utils/mocks/mockConsoleLog.ts b/src/test/utils/mocks/mockConsoleLog.ts index 61c6c14b989..f44a0c7d6cd 100644 --- a/src/test/utils/mocks/mockConsoleLog.ts +++ b/src/test/utils/mocks/mockConsoleLog.ts @@ -1,12 +1,12 @@ const MockConsoleLog = (_logDisabled= false, _phaseText=false) => { - let logs = []; + let logs: any[] = []; const logDisabled: boolean = _logDisabled; const phaseText: boolean = _phaseText; const originalLog = console.log; const originalError = console.error; const originalDebug = console.debug; const originalWarn = console.warn; - const notified = []; + const notified: any[] = []; const blacklist = ["Phaser", "variant icon does not exist", "Texture \"%s\" not found"]; const whitelist = ["Phase"]; diff --git a/src/test/utils/mocks/mockGameObject.ts b/src/test/utils/mocks/mockGameObject.ts new file mode 100644 index 00000000000..9138e0f687a --- /dev/null +++ b/src/test/utils/mocks/mockGameObject.ts @@ -0,0 +1,3 @@ +export interface MockGameObject { + +} diff --git a/src/test/utils/mocks/mockTextureManager.ts b/src/test/utils/mocks/mockTextureManager.ts index 36a09efcf5a..95e8996836f 100644 --- a/src/test/utils/mocks/mockTextureManager.ts +++ b/src/test/utils/mocks/mockTextureManager.ts @@ -5,6 +5,7 @@ import MockNineslice from "#test/utils/mocks/mocksContainer/mockNineslice"; import MockImage from "#test/utils/mocks/mocksContainer/mockImage"; import MockText from "#test/utils/mocks/mocksContainer/mockText"; import MockPolygon from "#test/utils/mocks/mocksContainer/mockPolygon"; +import { MockGameObject } from "./mockGameObject"; export default class MockTextureManager { @@ -12,7 +13,7 @@ export default class MockTextureManager { private scene; public add; public displayList; - public list = []; + public list: MockGameObject[] = []; constructor(scene) { this.scene = scene; diff --git a/src/test/utils/mocks/mocksContainer/mockContainer.ts b/src/test/utils/mocks/mocksContainer/mockContainer.ts index b74c46b4e86..d3672cb5235 100644 --- a/src/test/utils/mocks/mocksContainer/mockContainer.ts +++ b/src/test/utils/mocks/mocksContainer/mockContainer.ts @@ -1,6 +1,7 @@ import MockTextureManager from "#test/utils/mocks/mockTextureManager"; +import { MockGameObject } from "../mockGameObject"; -export default class MockContainer { +export default class MockContainer implements MockGameObject { protected x; protected y; protected scene; @@ -11,7 +12,7 @@ export default class MockContainer { private style; public frame; protected textureManager; - public list = []; + public list: MockGameObject[] = []; constructor(textureManager: MockTextureManager, x, y) { this.x = x; diff --git a/src/test/utils/mocks/mocksContainer/mockGraphics.ts b/src/test/utils/mocks/mocksContainer/mockGraphics.ts index a08f150fe61..e026b212e16 100644 --- a/src/test/utils/mocks/mocksContainer/mockGraphics.ts +++ b/src/test/utils/mocks/mocksContainer/mockGraphics.ts @@ -1,6 +1,8 @@ -export default class MockGraphics { +import { MockGameObject } from "../mockGameObject"; + +export default class MockGraphics implements MockGameObject { private scene; - public list = []; + public list: MockGameObject[] = []; constructor(textureManager, config) { this.scene = textureManager.scene; } diff --git a/src/test/utils/mocks/mocksContainer/mockRectangle.ts b/src/test/utils/mocks/mocksContainer/mockRectangle.ts index db323268037..26c2f74ea42 100644 --- a/src/test/utils/mocks/mocksContainer/mockRectangle.ts +++ b/src/test/utils/mocks/mocksContainer/mockRectangle.ts @@ -1,7 +1,9 @@ -export default class MockRectangle { +import { MockGameObject } from "../mockGameObject"; + +export default class MockRectangle implements MockGameObject { private fillColor; private scene; - public list = []; + public list: MockGameObject[] = []; constructor(textureManager, x, y, width, height, fillColor) { this.fillColor = fillColor; diff --git a/src/test/utils/mocks/mocksContainer/mockSprite.ts b/src/test/utils/mocks/mocksContainer/mockSprite.ts index fb7f84741e8..9c566fc4bcb 100644 --- a/src/test/utils/mocks/mocksContainer/mockSprite.ts +++ b/src/test/utils/mocks/mocksContainer/mockSprite.ts @@ -1,9 +1,10 @@ +import { MockGameObject } from "../mockGameObject"; import Sprite = Phaser.GameObjects.Sprite; import Frame = Phaser.Textures.Frame; import Phaser from "phaser"; -export default class MockSprite { +export default class MockSprite implements MockGameObject { private phaserSprite; public pipelineData; public texture; @@ -12,10 +13,11 @@ export default class MockSprite { public textureManager; public scene; public anims; - public list = []; + public list: MockGameObject[] = []; constructor(textureManager, x, y, texture) { this.textureManager = textureManager; this.scene = textureManager.scene; + // @ts-ignore Phaser.GameObjects.Sprite.prototype.setInteractive = this.setInteractive; // @ts-ignore Phaser.GameObjects.Sprite.prototype.setTexture = this.setTexture; diff --git a/src/test/utils/mocks/mocksContainer/mockText.ts b/src/test/utils/mocks/mocksContainer/mockText.ts index f4513e20926..5d405efadfd 100644 --- a/src/test/utils/mocks/mocksContainer/mockText.ts +++ b/src/test/utils/mocks/mocksContainer/mockText.ts @@ -1,12 +1,13 @@ import UI from "#app/ui/ui"; +import { MockGameObject } from "../mockGameObject"; -export default class MockText { +export default class MockText implements MockGameObject { private phaserText; private wordWrapWidth; private splitRegExp; private scene; private textureManager; - public list = []; + public list: MockGameObject[] = []; public style; public text = ""; diff --git a/src/test/utils/overridesHelper.ts b/src/test/utils/overridesHelper.ts index e51928cc784..e77cd49b742 100644 --- a/src/test/utils/overridesHelper.ts +++ b/src/test/utils/overridesHelper.ts @@ -192,7 +192,7 @@ export class OverridesHelper { * @param battleType battle type to set * @returns this */ - battleType(battleType: "single" | "double"): this { + battleType(battleType: "single" | "double" | null): this { vi.spyOn(Overrides, "BATTLE_TYPE_OVERRIDE", "get").mockReturnValue(battleType); this.log(`Battle type set to ${battleType} only!`); return this; diff --git a/src/test/utils/phaseInterceptor.ts b/src/test/utils/phaseInterceptor.ts index aabde643aa8..34f79f93b6e 100644 --- a/src/test/utils/phaseInterceptor.ts +++ b/src/test/utils/phaseInterceptor.ts @@ -289,7 +289,7 @@ export default class PhaseInterceptor { setMode(mode: Mode, ...args: any[]): Promise { const currentPhase = this.scene.getCurrentPhase(); const instance = this.scene.ui; - console.log("setMode", mode, args); + console.log("setMode", `${Mode[mode]} (=${mode})`, args); const ret = this.originalSetMode.apply(instance, [mode, ...args]); if (!this.phases[currentPhase.constructor.name]) { throw new Error(`missing ${currentPhase.constructor.name} in phaseInterceptior PHASES list`); @@ -328,7 +328,7 @@ export default class PhaseInterceptor { * @param callback - The callback function to execute. * @param expireFn - The function to determine if the prompt has expired. */ - addToNextPrompt(phaseTarget: string, mode: Mode, callback: () => void, expireFn: () => void, awaitingActionInput: boolean = false) { + addToNextPrompt(phaseTarget: string, mode: Mode, callback: () => void, expireFn?: () => void, awaitingActionInput: boolean = false) { this.prompts.push({ phaseTarget, mode, diff --git a/src/timed-event-manager.ts b/src/timed-event-manager.ts index dac67bd7b4e..0502080d3a5 100644 --- a/src/timed-event-manager.ts +++ b/src/timed-event-manager.ts @@ -52,32 +52,32 @@ export class TimedEventManager { let multiplier = 1; const shinyEvents = timedEvents.filter((te) => te.eventType === EventType.SHINY && this.isActive(te)); shinyEvents.forEach((se) => { - multiplier *= se.shinyMultiplier; + multiplier *= se.shinyMultiplier!; // TODO: is this bang correct? }); return multiplier; } getEventBannerFilename(): string { - return timedEvents.find((te: TimedEvent) => this.isActive(te)).bannerFilename ?? null; + return timedEvents.find((te: TimedEvent) => this.isActive(te))?.bannerFilename!; // TODO: is this bang correct? } } export class TimedEventDisplay extends Phaser.GameObjects.Container { - private event: TimedEvent; + private event: TimedEvent | null; private eventTimerText: Phaser.GameObjects.Text; private banner: Phaser.GameObjects.Image; private bannerShadow: Phaser.GameObjects.Rectangle; - private eventTimer: NodeJS.Timeout; + private eventTimer: NodeJS.Timeout | null; - constructor(scene: BattleScene, x: number, y: number, event: TimedEvent) { + constructor(scene: BattleScene, x: number, y: number, event?: TimedEvent) { super(scene, x, y); - this.event = event; + this.event = event!; // TODO: is this bang correct? this.setVisible(false); } setup() { - this.banner = new Phaser.GameObjects.Image(this.scene, 29, 64, this.event.bannerFilename); + this.banner = new Phaser.GameObjects.Image(this.scene, 29, 64, this.event!.bannerFilename!); // TODO: are the bangs correct here? this.banner.setName("img-event-banner"); this.banner.setOrigin(0, 0); this.banner.setScale(0.07); @@ -97,7 +97,7 @@ export class TimedEventDisplay extends Phaser.GameObjects.Container { this.scene, this.banner.x + 8, this.banner.y + 100, - this.timeToGo(this.event.endDate), + this.timeToGo(this.event!.endDate), // TODO: is the bang correct here? TextStyle.WINDOW ); this.eventTimerText.setName("text-event-timer"); @@ -118,7 +118,7 @@ export class TimedEventDisplay extends Phaser.GameObjects.Container { clear() { this.setVisible(false); - clearInterval(this.eventTimer); + this.eventTimer && clearInterval(this.eventTimer); this.eventTimer = null; } @@ -145,6 +145,6 @@ export class TimedEventDisplay extends Phaser.GameObjects.Container { } updateCountdown() { - this.eventTimerText.setText(this.timeToGo(this.event.endDate)); + this.eventTimerText.setText(this.timeToGo(this.event!.endDate)); // TODO: is the bang correct here? } } diff --git a/src/touch-controls.ts b/src/touch-controls.ts index 9953e99c81a..1726b47a4bd 100644 --- a/src/touch-controls.ts +++ b/src/touch-controls.ts @@ -48,7 +48,7 @@ export default class TouchControl { node.addEventListener("touchend", event => { event.preventDefault(); - this.touchButtonUp(node, key, event.target["id"]); + this.touchButtonUp(node, key, event.target?.["id"]); }); } @@ -120,7 +120,7 @@ export default class TouchControl { * Prevent zoom on specified element * @param {HTMLElement} element */ - preventElementZoom(element: HTMLElement): void { + preventElementZoom(element: HTMLElement | null): void { if (!element) { return; } diff --git a/src/ui/ability-bar.ts b/src/ui/ability-bar.ts index 7a4ae559975..b8259af9f3d 100644 --- a/src/ui/ability-bar.ts +++ b/src/ui/ability-bar.ts @@ -12,8 +12,8 @@ export default class AbilityBar extends Phaser.GameObjects.Container { private bg: Phaser.GameObjects.Image; private abilityBarText: Phaser.GameObjects.Text; - private tween: Phaser.Tweens.Tween; - private autoHideTimer: NodeJS.Timeout; + private tween: Phaser.Tweens.Tween | null; + private autoHideTimer: NodeJS.Timeout | null; public shown: boolean; diff --git a/src/ui/abstact-option-select-ui-handler.ts b/src/ui/abstact-option-select-ui-handler.ts index bf8a79ae194..f0148509220 100644 --- a/src/ui/abstact-option-select-ui-handler.ts +++ b/src/ui/abstact-option-select-ui-handler.ts @@ -36,7 +36,7 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler { protected optionSelectText: Phaser.GameObjects.Text; protected optionSelectIcons: Phaser.GameObjects.Sprite[]; - protected config: OptionSelectConfig; + protected config: OptionSelectConfig | null; protected blockInput: boolean; @@ -44,10 +44,10 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler { protected scale: number = 0.1666666667; - private cursorObj: Phaser.GameObjects.Image; + private cursorObj: Phaser.GameObjects.Image | null; constructor(scene: BattleScene, mode?: Mode) { - super(scene, mode); + super(scene, mode!); // TODO: is this bang correct? } abstract getWindowWidth(): integer; @@ -96,7 +96,7 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler { this.optionSelectBg.width = Math.max(this.optionSelectText.displayWidth + 24, this.getWindowWidth()); - if (this.config?.options.length > this.config?.maxOptions) { + if (this.config?.options && this.config?.options.length > (this.config?.maxOptions!)) { // TODO: is this bang correct? this.optionSelectText.setText(this.getOptionsWithScroll().map(o => o.label).join("\n")); } @@ -123,8 +123,10 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler { itemOverlayIcon.setPositionRelative(this.optionSelectText, 36 * this.scale, 7 + i * (114 * this.scale - 3)); - itemIcon.setTint(argbFromRgba(Utils.rgbHexToRgba(option.itemArgs[0]))); - itemOverlayIcon.setTint(argbFromRgba(Utils.rgbHexToRgba(option.itemArgs[1]))); + if (option.itemArgs) { + itemIcon.setTint(argbFromRgba(Utils.rgbHexToRgba(option.itemArgs[0]))); + itemOverlayIcon.setTint(argbFromRgba(Utils.rgbHexToRgba(option.itemArgs[1]))); + } } } }); diff --git a/src/ui/achv-bar.ts b/src/ui/achv-bar.ts index 05dde03aed7..0f3ab7c2e47 100644 --- a/src/ui/achv-bar.ts +++ b/src/ui/achv-bar.ts @@ -28,7 +28,7 @@ export default class AchvBar extends Phaser.GameObjects.Container { this.defaultWidth = 160; this.defaultHeight = 40; - this.bg = this.scene.add.nineslice(0, 0, "achv_bar", null, this.defaultWidth, this.defaultHeight, 41, 6, 16, 4); + this.bg = this.scene.add.nineslice(0, 0, "achv_bar", undefined, this.defaultWidth, this.defaultHeight, 41, 6, 16, 4); this.bg.setOrigin(0, 0); this.add(this.bg); @@ -119,7 +119,8 @@ export default class AchvBar extends Phaser.GameObjects.Container { this.shown = false; this.setVisible(false); if (this.queue.length) { - this.showAchv(this.queue.shift()); + const shifted = this.queue.shift(); + shifted && this.showAchv(shifted); } } }); diff --git a/src/ui/achvs-ui-handler.ts b/src/ui/achvs-ui-handler.ts index b5e17ce2b67..304b5df8340 100644 --- a/src/ui/achvs-ui-handler.ts +++ b/src/ui/achvs-ui-handler.ts @@ -19,10 +19,10 @@ export default class AchvsUiHandler extends MessageUiHandler { private scoreText: Phaser.GameObjects.Text; private unlockText: Phaser.GameObjects.Text; - private cursorObj: Phaser.GameObjects.NineSlice; + private cursorObj: Phaser.GameObjects.NineSlice | null; constructor(scene: BattleScene, mode?: Mode) { - super(scene, mode); + super(scene, mode!); // TODO: is this bang correct? } setup() { @@ -210,7 +210,7 @@ export default class AchvsUiHandler extends MessageUiHandler { let updateAchv = ret; if (!this.cursorObj) { - this.cursorObj = this.scene.add.nineslice(0, 0, "select_cursor_highlight", null, 16, 16, 1, 1, 1, 1); + this.cursorObj = this.scene.add.nineslice(0, 0, "select_cursor_highlight", undefined, 16, 16, 1, 1, 1, 1); this.cursorObj.setOrigin(0, 0); this.achvIconsContainer.add(this.cursorObj); updateAchv = true; diff --git a/src/ui/awaitable-ui-handler.ts b/src/ui/awaitable-ui-handler.ts index 18635b132f9..33be11ccc27 100644 --- a/src/ui/awaitable-ui-handler.ts +++ b/src/ui/awaitable-ui-handler.ts @@ -5,7 +5,7 @@ import {Button} from "#enums/buttons"; export default abstract class AwaitableUiHandler extends UiHandler { protected awaitingActionInput: boolean; - protected onActionInput: Function; + protected onActionInput: Function | null; public tutorialActive: boolean = false; constructor(scene: BattleScene, mode: Mode) { diff --git a/src/ui/ball-ui-handler.ts b/src/ui/ball-ui-handler.ts index 9fc591f209f..d8b3e5e3ee8 100644 --- a/src/ui/ball-ui-handler.ts +++ b/src/ui/ball-ui-handler.ts @@ -13,7 +13,7 @@ export default class BallUiHandler extends UiHandler { private pokeballSelectBg: Phaser.GameObjects.NineSlice; private countsText: Phaser.GameObjects.Text; - private cursorObj: Phaser.GameObjects.Image; + private cursorObj: Phaser.GameObjects.Image | null; private scale: number = 0.1666666667; diff --git a/src/ui/battle-info.ts b/src/ui/battle-info.ts index d78b05a569f..98ebdf21078 100644 --- a/src/ui/battle-info.ts +++ b/src/ui/battle-info.ts @@ -22,12 +22,12 @@ export default class BattleInfo extends Phaser.GameObjects.Container { private boss: boolean; private bossSegments: integer; private offset: boolean; - private lastName: string; + private lastName: string | null; private lastTeraType: Type; private lastStatus: StatusEffect; private lastHp: integer; private lastMaxHp: integer; - private lastHpFrame: string; + private lastHpFrame: string | null; private lastExp: integer; private lastLevelExp: integer; private lastLevel: integer; @@ -267,7 +267,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container { this.add(this.effectivenessContainer); this.effectivenessText = addTextObject(this.scene, 5, 4.5, "", TextStyle.BATTLE_INFO); - this.effectivenessWindow = addWindow((this.scene as BattleScene), 0, 0, 0, 20, false, false, null, null, WindowVariant.XTHIN); + this.effectivenessWindow = addWindow((this.scene as BattleScene), 0, 0, 0, 20, undefined, false, undefined, undefined, WindowVariant.XTHIN); this.effectivenessContainer.add(this.effectivenessWindow); this.effectivenessContainer.add(this.effectivenessText); @@ -293,7 +293,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container { this.teraIcon.setVisible(this.lastTeraType !== Type.UNKNOWN); this.teraIcon.on("pointerover", () => { if (this.lastTeraType !== Type.UNKNOWN) { - (this.scene as BattleScene).ui.showTooltip(null, `${Utils.toReadableString(Type[this.lastTeraType])} Terastallized`); + (this.scene as BattleScene).ui.showTooltip("", `${Utils.toReadableString(Type[this.lastTeraType])} Terastallized`); } }); this.teraIcon.on("pointerout", () => (this.scene as BattleScene).ui.hideTooltip()); @@ -303,7 +303,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container { this.splicedIcon.setPositionRelative(this.nameText, nameTextWidth + this.genderText.displayWidth + 1 + (this.teraIcon.visible ? this.teraIcon.displayWidth + 1 : 0), 2.5); this.splicedIcon.setVisible(isFusion); if (this.splicedIcon.visible) { - this.splicedIcon.on("pointerover", () => (this.scene as BattleScene).ui.showTooltip(null, `${pokemon.species.getName(pokemon.formIndex)}/${pokemon.fusionSpecies.getName(pokemon.fusionFormIndex)}`)); + this.splicedIcon.on("pointerover", () => (this.scene as BattleScene).ui.showTooltip("", `${pokemon.species.getName(pokemon.formIndex)}/${pokemon.fusionSpecies?.getName(pokemon.fusionFormIndex)}`)); this.splicedIcon.on("pointerout", () => (this.scene as BattleScene).ui.hideTooltip()); } @@ -318,7 +318,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container { const shinyDescriptor = doubleShiny || baseVariant ? `${baseVariant === 2 ? i18next.t("common:epicShiny") : baseVariant === 1 ? i18next.t("common:rareShiny") : i18next.t("common:commonShiny")}${doubleShiny ? `/${pokemon.fusionVariant === 2 ? i18next.t("common:epicShiny") : pokemon.fusionVariant === 1 ? i18next.t("common:rareShiny") : i18next.t("common:commonShiny")}` : ""}` : ""; - this.shinyIcon.on("pointerover", () => (this.scene as BattleScene).ui.showTooltip(null, `${i18next.t("common:shinyOnHover")}${shinyDescriptor ? ` (${shinyDescriptor})` : ""}`)); + this.shinyIcon.on("pointerover", () => (this.scene as BattleScene).ui.showTooltip("", `${i18next.t("common:shinyOnHover")}${shinyDescriptor ? ` (${shinyDescriptor})` : ""}`)); this.shinyIcon.on("pointerout", () => (this.scene as BattleScene).ui.hideTooltip()); } @@ -330,7 +330,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container { if (!this.player) { if (this.nameText.visible) { - this.nameText.on("pointerover", () => (this.scene as BattleScene).ui.showTooltip(null, i18next.t("battleInfo:generation", { generation: i18next.t(`starterSelectUiHandler:gen${pokemon.species.generation}`) }))); + this.nameText.on("pointerover", () => (this.scene as BattleScene).ui.showTooltip("", i18next.t("battleInfo:generation", { generation: i18next.t(`starterSelectUiHandler:gen${pokemon.species.generation}`) }))); this.nameText.on("pointerout", () => (this.scene as BattleScene).ui.hideTooltip()); } @@ -472,7 +472,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container { updateBossSegmentDividers(pokemon: EnemyPokemon): void { while (this.hpBarSegmentDividers.length) { - this.hpBarSegmentDividers.pop().destroy(); + this.hpBarSegmentDividers.pop()?.destroy(); } if (this.boss && this.bossSegments > 1) { @@ -768,7 +768,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container { } this.currentEffectiveness = effectiveness; - if (!(this.scene as BattleScene).typeHints || effectiveness === undefined || this.flyoutMenu.flyoutVisible) { + if (!(this.scene as BattleScene).typeHints || effectiveness === undefined || this.flyoutMenu?.flyoutVisible) { this.effectivenessContainer.setVisible(false); return; } diff --git a/src/ui/battle-message-ui-handler.ts b/src/ui/battle-message-ui-handler.ts index f2da553c6da..6c5049394a7 100644 --- a/src/ui/battle-message-ui-handler.ts +++ b/src/ui/battle-message-ui-handler.ts @@ -147,19 +147,21 @@ export default class BattleMessageUiHandler extends MessageUiHandler { } } } + + return false; } clear() { super.clear(); } - showText(text: string, delay?: integer, callback?: Function, callbackDelay?: integer, prompt?: boolean, promptDelay?: integer) { + showText(text: string, delay?: integer | null, callback?: Function | null, callbackDelay?: integer | null, prompt?: boolean | null, promptDelay?: integer | null) { this.hideNameText(); super.showText(text, delay, callback, callbackDelay, prompt, promptDelay); } - showDialogue(text: string, name: string, delay?: integer, callback?: Function, callbackDelay?: integer, prompt?: boolean, promptDelay?: integer) { - this.showNameText(name); + showDialogue(text: string, name?: string, delay?: integer | null, callback?: Function, callbackDelay?: integer, prompt?: boolean, promptDelay?: integer) { + name && this.showNameText(name); super.showDialogue(text, name, delay, callback, callbackDelay, prompt, promptDelay); } @@ -180,7 +182,7 @@ export default class BattleMessageUiHandler extends MessageUiHandler { this.awaitingActionInput = true; this.onActionInput = () => { if (!showTotals) { - return this.promptLevelUpStats(partyMemberIndex, null, true).then(() => resolve()); + return this.promptLevelUpStats(partyMemberIndex, [], true).then(() => resolve()); } else { this.levelUpStatsContainer.setVisible(false); resolve(); @@ -206,8 +208,8 @@ export default class BattleMessageUiHandler extends MessageUiHandler { highestIv = ivs[s]; } }); - shownStats.push(shownStat); - statsPool.splice(statsPool.indexOf(shownStat), 1); + shownStats.push(shownStat!); // TODO: is the bang correct? + statsPool.splice(statsPool.indexOf(shownStat!), 1); // TODO: is the bang correct? } } else { shownStats = stats; @@ -228,7 +230,7 @@ export default class BattleMessageUiHandler extends MessageUiHandler { } getIvDescriptor(value: integer, typeIv: integer, pokemonId: integer): string { - const starterSpecies = this.scene.getPokemonById(pokemonId).species.getRootSpeciesId(true); + const starterSpecies = this.scene.getPokemonById(pokemonId)!.species.getRootSpeciesId(true); // TODO: is this bang correct? const starterIvs: number[] = this.scene.gameData.dexData[starterSpecies].ivs; const uiTheme = (this.scene as BattleScene).uiTheme; // Assuming uiTheme is accessible diff --git a/src/ui/bgm-bar.ts b/src/ui/bgm-bar.ts index 076eec26a8e..936ab91d8fa 100644 --- a/src/ui/bgm-bar.ts +++ b/src/ui/bgm-bar.ts @@ -24,7 +24,7 @@ export default class BgmBar extends Phaser.GameObjects.Container { this.defaultWidth = 230; this.defaultHeight = 100; - this.bg = this.scene.add.nineslice(-5, -5, "bgm_bar", null, this.defaultWidth, this.defaultHeight, 0, 0, 10, 10); + this.bg = this.scene.add.nineslice(-5, -5, "bgm_bar", undefined, this.defaultWidth, this.defaultHeight, 0, 0, 10, 10); this.bg.setOrigin(0, 0); this.add(this.bg); diff --git a/src/ui/candy-bar.ts b/src/ui/candy-bar.ts index 3a9f180dd59..5496ce9afce 100644 --- a/src/ui/candy-bar.ts +++ b/src/ui/candy-bar.ts @@ -11,8 +11,8 @@ export default class CandyBar extends Phaser.GameObjects.Container { private countText: Phaser.GameObjects.Text; private speciesId: Species; - private tween: Phaser.Tweens.Tween; - private autoHideTimer: NodeJS.Timeout; + private tween: Phaser.Tweens.Tween | null; + private autoHideTimer: NodeJS.Timeout | null; public shown: boolean; @@ -21,7 +21,7 @@ export default class CandyBar extends Phaser.GameObjects.Container { } setup(): void { - this.bg = this.scene.add.nineslice(0, 0, "party_exp_bar", null, 8, 18, 21, 5, 6, 4); + this.bg = this.scene.add.nineslice(0, 0, "party_exp_bar", undefined, 8, 18, 21, 5, 6, 4); this.bg.setOrigin(0, 0); this.add(this.bg); diff --git a/src/ui/challenges-select-ui-handler.ts b/src/ui/challenges-select-ui-handler.ts index 6dcc359ef31..1200b3f3b40 100644 --- a/src/ui/challenges-select-ui-handler.ts +++ b/src/ui/challenges-select-ui-handler.ts @@ -30,12 +30,12 @@ export default class GameChallengesUiHandler extends UiHandler { private challengeLabels: Array<{ label: Phaser.GameObjects.Text, value: Phaser.GameObjects.Text }>; private monoTypeValue: Phaser.GameObjects.Sprite; - private cursorObj: Phaser.GameObjects.NineSlice; + private cursorObj: Phaser.GameObjects.NineSlice | null; private startCursor: Phaser.GameObjects.NineSlice; constructor(scene: BattleScene, mode?: Mode) { - super(scene, mode); + super(scene, mode!); // TODO: is this bang correct? } setup() { @@ -110,7 +110,7 @@ export default class GameChallengesUiHandler extends UiHandler { startText.setOrigin(0, 0); startText.setPositionRelative(startBg, 8, 4); - this.startCursor = this.scene.add.nineslice(0, 0, "summary_moves_cursor", null, (this.scene.game.canvas.width / 18) - 10, 16, 1, 1, 1, 1); + this.startCursor = this.scene.add.nineslice(0, 0, "summary_moves_cursor", undefined, (this.scene.game.canvas.width / 18) - 10, 16, 1, 1, 1, 1); this.startCursor.setName("9s-start-cursor"); this.startCursor.setOrigin(0, 0); this.startCursor.setPositionRelative(startBg, 4, 4); @@ -258,7 +258,7 @@ export default class GameChallengesUiHandler extends UiHandler { } else { this.scene.clearPhaseQueue(); this.scene.pushPhase(new TitlePhase(this.scene)); - this.scene.getCurrentPhase().end(); + this.scene.getCurrentPhase()?.end(); } success = true; } else if (button === Button.SUBMIT || button === Button.ACTION) { @@ -267,7 +267,7 @@ export default class GameChallengesUiHandler extends UiHandler { const totalMinDifficulty = this.scene.gameMode.challenges.reduce((v, c) => v + c.getMinDifficulty(), 0); if (totalDifficulty >= totalMinDifficulty) { this.scene.unshiftPhase(new SelectStarterPhase(this.scene)); - this.scene.getCurrentPhase().end(); + this.scene.getCurrentPhase()?.end(); success = true; } else { success = false; @@ -354,7 +354,7 @@ export default class GameChallengesUiHandler extends UiHandler { let ret = super.setCursor(cursor); if (!this.cursorObj) { - this.cursorObj = this.scene.add.nineslice(0, 0, "summary_moves_cursor", null, (this.scene.game.canvas.width / 9) - 10, 16, 1, 1, 1, 1); + this.cursorObj = this.scene.add.nineslice(0, 0, "summary_moves_cursor", undefined, (this.scene.game.canvas.width / 9) - 10, 16, 1, 1, 1, 1); this.cursorObj.setOrigin(0, 0); this.valuesContainer.add(this.cursorObj); } diff --git a/src/ui/command-ui-handler.ts b/src/ui/command-ui-handler.ts index f083acd2f5b..11814a25240 100644 --- a/src/ui/command-ui-handler.ts +++ b/src/ui/command-ui-handler.ts @@ -17,7 +17,7 @@ export enum Command { export default class CommandUiHandler extends UiHandler { private commandsContainer: Phaser.GameObjects.Container; - private cursorObj: Phaser.GameObjects.Image; + private cursorObj: Phaser.GameObjects.Image | null; protected fieldIndex: integer = 0; protected cursor2: integer = 0; diff --git a/src/ui/daily-run-scoreboard.ts b/src/ui/daily-run-scoreboard.ts index 212d7b2a66c..b535a94d35c 100644 --- a/src/ui/daily-run-scoreboard.ts +++ b/src/ui/daily-run-scoreboard.ts @@ -59,14 +59,14 @@ export class DailyRunScoreboard extends Phaser.GameObjects.Container { } setup() { - const titleWindow = addWindow(this.scene, 0, 0, 114, 18, false, false, null, null, WindowVariant.THIN); + const titleWindow = addWindow(this.scene, 0, 0, 114, 18, false, false, undefined, undefined, WindowVariant.THIN); this.add(titleWindow); this.titleLabel = addTextObject(this.scene, titleWindow.displayWidth / 2, titleWindow.displayHeight / 2, i18next.t("menu:loading"), TextStyle.WINDOW, { fontSize: "64px" }); this.titleLabel.setOrigin(0.5, 0.5); this.add(this.titleLabel); - const window = addWindow(this.scene, 0, 17, 114, 118, false, false, null, null, WindowVariant.THIN); + const window = addWindow(this.scene, 0, 17, 114, 118, false, false, undefined, undefined, WindowVariant.THIN); this.add(window); this.rankingsContainer = this.scene.add.container(6, 21); diff --git a/src/ui/dropdown.ts b/src/ui/dropdown.ts index 80935d16a71..f1723559b57 100644 --- a/src/ui/dropdown.ts +++ b/src/ui/dropdown.ts @@ -233,9 +233,9 @@ export class DropDownOption extends Phaser.GameObjects.Container { /** * @returns the x position to use for the current label depending on if it has a sprite or not */ - getCurrentLabelX(): number { + getCurrentLabelX(): number | undefined { if (this.labels[this.currentLabelIndex].sprite) { - return this.labels[this.currentLabelIndex].sprite.x; + return this.labels[this.currentLabelIndex].sprite?.x; } return this.text.x; } @@ -313,7 +313,7 @@ export class DropDown extends Phaser.GameObjects.Container { } }); - this.window = addWindow(scene, 0, 0, optionWidth, options[options.length - 1].y + optionHeight + optionPaddingY, false, false, null, null, WindowVariant.XTHIN); + this.window = addWindow(scene, 0, 0, optionWidth, options[options.length - 1].y + optionHeight + optionPaddingY, false, false, undefined, undefined, WindowVariant.XTHIN); this.add(this.window); this.add(options); this.add(this.cursorObj); @@ -465,7 +465,7 @@ export class DropDown extends Phaser.GameObjects.Container { * - the settings dictionary is like this { val: any, state: DropDownState, cursor: boolean, dir: SortDirection } */ private getSettings(): any[] { - const settings = []; + const settings : any[] = []; for (let i = 0; i < this.options.length; i++) { settings.push({ val: this.options[i].val, state: this.options[i].state , cursor: (this.cursor === i), dir: this.options[i].dir }); } @@ -570,7 +570,7 @@ export class DropDown extends Phaser.GameObjects.Container { const optionWidth = this.options[i].getWidth(); if (optionWidth > maxWidth) { maxWidth = optionWidth; - x = this.options[i].getCurrentLabelX(); + x = this.options[i].getCurrentLabelX() ?? 0; } } this.window.width = maxWidth + x - this.window.x + 6; diff --git a/src/ui/egg-gacha-ui-handler.ts b/src/ui/egg-gacha-ui-handler.ts index 61031ba1c5c..92f3aaea1a4 100644 --- a/src/ui/egg-gacha-ui-handler.ts +++ b/src/ui/egg-gacha-ui-handler.ts @@ -60,7 +60,7 @@ export default class EggGachaUiHandler extends MessageUiHandler { this.eggGachaContainer.setVisible(false); ui.add(this.eggGachaContainer); - const bg = this.scene.add.nineslice(0, 0, "default_bg", null, 320, 180, 0, 0, 16, 0); + const bg = this.scene.add.nineslice(0, 0, "default_bg", undefined, 320, 180, 0, 0, 16, 0); bg.setOrigin(0, 0); this.eggGachaContainer.add(bg); @@ -99,7 +99,7 @@ export default class EggGachaUiHandler extends MessageUiHandler { const gachaInfoContainer = this.scene.add.container(160, 46); - const currentLanguage = i18next.resolvedLanguage; + const currentLanguage = i18next.resolvedLanguage!; // TODO: is this bang correct? let gachaTextStyle = TextStyle.WINDOW_ALT; let gachaX = 4; let gachaY = 0; @@ -217,7 +217,7 @@ export default class EggGachaUiHandler extends MessageUiHandler { { multiplier: multiplierOne, description: `25 ${i18next.t("egg:pulls")}`, icon: getVoucherTypeIcon(VoucherType.GOLDEN) } ]; - const { resolvedLanguage } = i18next; + const resolvedLanguage = i18next.resolvedLanguage!; // TODO: is this bang correct? const pullOptionsText = pullOptions.map(option =>{ const desc = option.description.split(" "); if (desc[0].length < 2) { @@ -335,7 +335,7 @@ export default class EggGachaUiHandler extends MessageUiHandler { return Utils.fixedInt(delay); } - pull(pullCount?: integer, count?: integer, eggs?: Egg[]): void { + pull(pullCount: integer = 0, count: integer = 0, eggs?: Egg[]): void { if (Overrides.EGG_GACHA_PULL_COUNT_OVERRIDE && !count) { pullCount = Overrides.EGG_GACHA_PULL_COUNT_OVERRIDE; } @@ -345,10 +345,10 @@ export default class EggGachaUiHandler extends MessageUiHandler { const doPull = () => { if (this.transitionCancelled) { - return this.showSummary(eggs); + return this.showSummary(eggs!); } - const egg = this.scene.add.sprite(127, 75, "egg", `egg_${eggs[count].getKey()}`); + const egg = this.scene.add.sprite(127, 75, "egg", `egg_${eggs![count].getKey()}`); egg.setScale(0.5); this.gachaContainers[this.gachaCursor].add(egg); @@ -391,7 +391,7 @@ export default class EggGachaUiHandler extends MessageUiHandler { if (++count < pullCount) { this.pull(pullCount, count, eggs); } else { - this.showSummary(eggs); + this.showSummary(eggs!); } } }); @@ -584,7 +584,7 @@ export default class EggGachaUiHandler extends MessageUiHandler { } showError(text: string): void { - this.showText(text, null, () => this.showText(this.defaultText), Utils.fixedInt(1500)); + this.showText(text, undefined, () => this.showText(this.defaultText), Utils.fixedInt(1500)); } setTransitioning(transitioning: boolean): void { diff --git a/src/ui/egg-hatch-scene-handler.ts b/src/ui/egg-hatch-scene-handler.ts index 0e247da60ab..f567861e0b7 100644 --- a/src/ui/egg-hatch-scene-handler.ts +++ b/src/ui/egg-hatch-scene-handler.ts @@ -36,7 +36,7 @@ export default class EggHatchSceneHandler extends UiHandler { show(_args: any[]): boolean { super.show(_args); - this.getUi().showText(null, 0); + this.getUi().showText("", 0); this.scene.setModifiersVisible(false); diff --git a/src/ui/evolution-scene-handler.ts b/src/ui/evolution-scene-handler.ts index 64d190c4d3f..ffbd06afde3 100644 --- a/src/ui/evolution-scene-handler.ts +++ b/src/ui/evolution-scene-handler.ts @@ -83,6 +83,8 @@ export default class EvolutionSceneHandler extends MessageUiHandler { } } } + + return false; } setCursor(_cursor: integer): boolean { diff --git a/src/ui/fight-ui-handler.ts b/src/ui/fight-ui-handler.ts index ed520512443..8279ab72a70 100644 --- a/src/ui/fight-ui-handler.ts +++ b/src/ui/fight-ui-handler.ts @@ -21,7 +21,7 @@ export default class FightUiHandler extends UiHandler { private powerText: Phaser.GameObjects.Text; private accuracyLabel: Phaser.GameObjects.Text; private accuracyText: Phaser.GameObjects.Text; - private cursorObj: Phaser.GameObjects.Image; + private cursorObj: Phaser.GameObjects.Image | null; private moveCategoryIcon: Phaser.GameObjects.Sprite; protected fieldIndex: integer = 0; @@ -176,7 +176,7 @@ export default class FightUiHandler extends UiHandler { const hasMove = cursor < moveset.length; if (hasMove) { - const pokemonMove = moveset[cursor]; + const pokemonMove = moveset[cursor]!; // TODO: is the bang correct? this.typeIcon.setTexture(`types${Utils.verifyLang(i18next.resolvedLanguage) ? `_${i18next.resolvedLanguage}` : ""}`, Type[pokemonMove.getMove().type].toLowerCase()).setScale(0.8); this.moveCategoryIcon.setTexture("categories", MoveCategory[pokemonMove.getMove().category].toLowerCase()).setScale(1.0); @@ -246,7 +246,7 @@ export default class FightUiHandler extends UiHandler { moveText.setName("text-empty-move"); if (moveIndex < moveset.length) { - const pokemonMove = moveset[moveIndex]; + const pokemonMove = moveset[moveIndex]!; // TODO is the bang correct? moveText.setText(pokemonMove.getName()); moveText.setName(pokemonMove.getName()); moveText.setColor(this.getMoveColor(pokemon, pokemonMove) ?? moveText.style.color); @@ -273,7 +273,7 @@ export default class FightUiHandler extends UiHandler { const moveColors = opponents.map((opponent) => { return opponent.getMoveEffectiveness(pokemon, pokemonMove); - }).sort((a, b) => b - a).map((effectiveness) => { + }).filter((eff) => !!eff).sort((a, b) => b - a).map((effectiveness) => { return getTypeDamageMultiplierColor(effectiveness, "offense"); }); diff --git a/src/ui/filter-bar.ts b/src/ui/filter-bar.ts index 52266a3a06b..31d7c562da2 100644 --- a/src/ui/filter-bar.ts +++ b/src/ui/filter-bar.ts @@ -31,7 +31,7 @@ export class FilterBar extends Phaser.GameObjects.Container { this.width = width; this.height = height; - this.window = addWindow(scene, 0, 0, width, height, false, false, null, null, WindowVariant.THIN); + this.window = addWindow(scene, 0, 0, width, height, false, false, undefined, undefined, WindowVariant.THIN); this.add(this.window); this.cursorObj = this.scene.add.image(1, 1, "cursor"); diff --git a/src/ui/form-modal-ui-handler.ts b/src/ui/form-modal-ui-handler.ts index 2c576a0fbaa..a4539c2369f 100644 --- a/src/ui/form-modal-ui-handler.ts +++ b/src/ui/form-modal-ui-handler.ts @@ -17,7 +17,7 @@ export abstract class FormModalUiHandler extends ModalUiHandler { protected inputContainers: Phaser.GameObjects.Container[]; protected inputs: InputText[]; protected errorMessage: Phaser.GameObjects.Text; - protected submitAction: Function; + protected submitAction: Function | null; protected tween: Phaser.Tweens.Tween; constructor(scene: BattleScene, mode?: Mode) { diff --git a/src/ui/game-stats-ui-handler.ts b/src/ui/game-stats-ui-handler.ts index 8f1e8890a76..3d6d8081d4e 100644 --- a/src/ui/game-stats-ui-handler.ts +++ b/src/ui/game-stats-ui-handler.ts @@ -219,7 +219,7 @@ export default class GameStatsUiHandler extends UiHandler { private statValues: Phaser.GameObjects.Text[]; constructor(scene: BattleScene, mode?: Mode) { - super(scene, mode); + super(scene, mode!); // TODO: is this bang correct? this.statLabels = []; this.statValues = []; @@ -299,7 +299,7 @@ export default class GameStatsUiHandler extends UiHandler { const statKeys = Object.keys(displayStats).slice(this.cursor * 2, this.cursor * 2 + 18); statKeys.forEach((key, s) => { const stat = displayStats[key] as DisplayStat; - const value = stat.sourceFunc(this.scene.gameData); + const value = stat.sourceFunc!(this.scene.gameData); // TODO: is this bang correct? this.statLabels[s].setText(!stat.hidden || isNaN(parseInt(value)) || parseInt(value) ? i18next.t(`gameStatsUiHandler:${stat.label_key}`) : "???"); this.statValues[s].setText(value); }); diff --git a/src/ui/login-form-ui-handler.ts b/src/ui/login-form-ui-handler.ts index 971bef6ea6b..450c583a26c 100644 --- a/src/ui/login-form-ui-handler.ts +++ b/src/ui/login-form-ui-handler.ts @@ -130,7 +130,7 @@ export default class LoginFormUiHandler extends FormModalUiHandler { .then(response => { if (response.hasOwnProperty("token")) { Utils.setCookie(Utils.sessionIdKey, response.token); - originalLoginAction(); + originalLoginAction && originalLoginAction(); } else { onFail(response); } diff --git a/src/ui/menu-ui-handler.ts b/src/ui/menu-ui-handler.ts index c0c5e69b893..27db60aa5da 100644 --- a/src/ui/menu-ui-handler.ts +++ b/src/ui/menu-ui-handler.ts @@ -38,7 +38,7 @@ export default class MenuUiHandler extends MessageUiHandler { private menuBg: Phaser.GameObjects.NineSlice; protected optionSelectText: Phaser.GameObjects.Text; - private cursorObj: Phaser.GameObjects.Image; + private cursorObj: Phaser.GameObjects.Image | null; private excludedMenus: () => ConditionalMenu[]; private menuOptions: MenuOptions[]; @@ -52,7 +52,7 @@ export default class MenuUiHandler extends MessageUiHandler { constructor(scene: BattleScene, mode?: Mode) { - super(scene, mode); + super(scene, mode!); // TODO: is this bang correct? this.excludedMenus = () => [ { condition: [Mode.COMMAND, Mode.TITLE].includes(mode ?? Mode.TITLE), options: [ MenuOptions.EGG_GACHA, MenuOptions.EGG_LIST] }, @@ -69,7 +69,7 @@ export default class MenuUiHandler extends MessageUiHandler { setup(): void { const ui = this.getUi(); // wiki url directs based on languges available on wiki - const lang = i18next.resolvedLanguage.substring(0,2); + const lang = i18next.resolvedLanguage?.substring(0,2)!; // TODO: is this bang correct? if (["de", "fr", "ko", "zh"].includes(lang)) { wikiUrl = `https://wiki.pokerogue.net/${lang}:start`; } @@ -147,7 +147,7 @@ export default class MenuUiHandler extends MessageUiHandler { this.menuContainer.add(this.menuMessageBoxContainer); - const manageDataOptions = []; + const manageDataOptions: any[] = []; // TODO: proper type const confirmSlot = (message: string, slotFilter: (i: integer) => boolean, callback: (i: integer) => void) => { ui.revertMode(); @@ -159,7 +159,7 @@ export default class MenuUiHandler extends MessageUiHandler { handler: () => { callback(i); ui.revertMode(); - ui.showText(null, 0); + ui.showText("", 0); return true; } }; @@ -167,7 +167,7 @@ export default class MenuUiHandler extends MessageUiHandler { label: i18next.t("menuUiHandler:cancel"), handler: () => { ui.revertMode(); - ui.showText(null, 0); + ui.showText("", 0); return true; } }]), @@ -259,7 +259,7 @@ export default class MenuUiHandler extends MessageUiHandler { { label: "Wiki", handler: () => { - window.open(wikiUrl, "_blank").focus(); + window.open(wikiUrl, "_blank")?.focus(); return true; }, keepOpen: true @@ -267,7 +267,7 @@ export default class MenuUiHandler extends MessageUiHandler { { label: "Discord", handler: () => { - window.open(discordUrl, "_blank").focus(); + window.open(discordUrl, "_blank")?.focus(); return true; }, keepOpen: true @@ -275,7 +275,7 @@ export default class MenuUiHandler extends MessageUiHandler { { label: "GitHub", handler: () => { - window.open(githubUrl, "_blank").focus(); + window.open(githubUrl, "_blank")?.focus(); return true; }, keepOpen: true @@ -283,7 +283,7 @@ export default class MenuUiHandler extends MessageUiHandler { { label: "Reddit", handler: () => { - window.open(redditUrl, "_blank").focus(); + window.open(redditUrl, "_blank")?.focus(); return true; }, keepOpen: true @@ -386,7 +386,7 @@ export default class MenuUiHandler extends MessageUiHandler { if (!bypassLogin && !this.manageDataConfig.options.some(o => o.label === i18next.t("menuUiHandler:linkDiscord") || o.label === i18next.t("menuUiHandler:unlinkDiscord"))) { this.manageDataConfig.options.splice(this.manageDataConfig.options.length-1,0, { - label: loggedInUser.discordId === "" ? i18next.t("menuUiHandler:linkDiscord") : i18next.t("menuUiHandler:unlinkDiscord"), + label: loggedInUser?.discordId === "" ? i18next.t("menuUiHandler:linkDiscord") : i18next.t("menuUiHandler:unlinkDiscord"), handler: () => { if (loggedInUser?.discordId === "") { const token = Utils.getCookie(Utils.sessionIdKey); @@ -442,7 +442,7 @@ export default class MenuUiHandler extends MessageUiHandler { ui.showText(i18next.t("menuUiHandler:losingProgressionWarning"), null, () => { ui.setOverlayMode(Mode.CONFIRM, () => this.scene.gameData.saveAll(this.scene, true, true, true, true).then(() => this.scene.reset(true)), () => { ui.revertMode(); - ui.showText(null, 0); + ui.showText("", 0); }, false, -98); }); } else { @@ -467,7 +467,7 @@ export default class MenuUiHandler extends MessageUiHandler { ui.showText(i18next.t("menuUiHandler:losingProgressionWarning"), null, () => { ui.setOverlayMode(Mode.CONFIRM, doLogout, () => { ui.revertMode(); - ui.showText(null, 0); + ui.showText("", 0); }, false, -98); }); } else { diff --git a/src/ui/message-ui-handler.ts b/src/ui/message-ui-handler.ts index 05c91ca1643..c870ef13a27 100644 --- a/src/ui/message-ui-handler.ts +++ b/src/ui/message-ui-handler.ts @@ -4,8 +4,8 @@ import { Mode } from "./ui"; import * as Utils from "../utils"; export default abstract class MessageUiHandler extends AwaitableUiHandler { - protected textTimer: Phaser.Time.TimerEvent; - protected textCallbackTimer: Phaser.Time.TimerEvent; + protected textTimer: Phaser.Time.TimerEvent | null; + protected textCallbackTimer: Phaser.Time.TimerEvent | null; public pendingPrompt: boolean; public message: Phaser.GameObjects.Text; @@ -17,15 +17,15 @@ export default abstract class MessageUiHandler extends AwaitableUiHandler { this.pendingPrompt = false; } - showText(text: string, delay?: integer, callback?: Function, callbackDelay?: integer, prompt?: boolean, promptDelay?: integer) { + showText(text: string, delay?: integer | null, callback?: Function | null, callbackDelay?: integer | null, prompt?: boolean | null, promptDelay?: integer | null) { this.showTextInternal(text, delay, callback, callbackDelay, prompt, promptDelay); } - showDialogue(text: string, name: string, delay?: integer, callback?: Function, callbackDelay?: integer, prompt?: boolean, promptDelay?: integer) { + showDialogue(text: string, name?: string, delay?: integer | null, callback?: Function | null, callbackDelay?: integer | null, prompt?: boolean | null, promptDelay?: integer | null) { this.showTextInternal(text, delay, callback, callbackDelay, prompt, promptDelay); } - private showTextInternal(text: string, delay: integer, callback: Function, callbackDelay: integer, prompt: boolean, promptDelay: integer) { + private showTextInternal(text: string, delay?: integer | null, callback?: Function | null, callbackDelay?: integer | null, prompt?: boolean | null, promptDelay?: integer | null) { if (delay === null || delay === undefined) { delay = 20; } @@ -33,7 +33,7 @@ export default abstract class MessageUiHandler extends AwaitableUiHandler { const delayMap = new Map(); const soundMap = new Map(); const actionPattern = /@(c|d|s)\{(.*?)\}/; - let actionMatch: RegExpExecArray; + let actionMatch: RegExpExecArray | null; while ((actionMatch = actionPattern.exec(text))) { switch (actionMatch[1]) { case "c": @@ -99,7 +99,7 @@ export default abstract class MessageUiHandler extends AwaitableUiHandler { this.textTimer = this.scene.time.addEvent({ delay: delay, callback: () => { - const charIndex = text.length - this.textTimer.repeatCount; + const charIndex = text.length - (this.textTimer?.repeatCount!); // TODO: is this bang correct? const charVar = charVarMap.get(charIndex); const charSound = soundMap.get(charIndex); const charDelay = delayMap.get(charIndex); @@ -111,7 +111,7 @@ export default abstract class MessageUiHandler extends AwaitableUiHandler { if (charSound) { this.scene.playSound(charSound); } - if (callback && !this.textTimer.repeatCount) { + if (callback && !this.textTimer?.repeatCount) { if (callbackDelay && !prompt) { this.textCallbackTimer = this.scene.time.delayedCall(callbackDelay, () => { if (this.textCallbackTimer) { @@ -126,11 +126,11 @@ export default abstract class MessageUiHandler extends AwaitableUiHandler { } }; if (charDelay) { - this.textTimer.paused = true; + this.textTimer!.paused = true; // TODO: is the bang correct? this.scene.tweens.addCounter({ duration: Utils.getFrameMs(charDelay), onComplete: () => { - this.textTimer.paused = false; + this.textTimer!.paused = false; // TODO: is the bang correct? advance(); } }); @@ -151,7 +151,7 @@ export default abstract class MessageUiHandler extends AwaitableUiHandler { } } - showPrompt(callback: Function, callbackDelay: integer) { + showPrompt(callback?: Function | null, callbackDelay?: integer | null) { const wrappedTextLines = this.message.runWordWrap(this.message.text).split(/\n/g); const textLinesCount = wrappedTextLines.length; const lastTextLine = wrappedTextLines[wrappedTextLines.length - 1]; diff --git a/src/ui/modal-ui-handler.ts b/src/ui/modal-ui-handler.ts index 85b20e423c3..5aac6ac194e 100644 --- a/src/ui/modal-ui-handler.ts +++ b/src/ui/modal-ui-handler.ts @@ -17,7 +17,7 @@ export abstract class ModalUiHandler extends UiHandler { protected buttonBgs: Phaser.GameObjects.NineSlice[]; constructor(scene: BattleScene, mode?: Mode) { - super(scene, mode); + super(scene, mode!); // TODO: is this bang correct? this.buttonContainers = []; this.buttonBgs = []; diff --git a/src/ui/modifier-select-ui-handler.ts b/src/ui/modifier-select-ui-handler.ts index 76cda280720..016708027ca 100644 --- a/src/ui/modifier-select-ui-handler.ts +++ b/src/ui/modifier-select-ui-handler.ts @@ -35,7 +35,7 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler { public options: ModifierOption[]; public shopOptionsRows: ModifierOption[][]; - private cursorObj: Phaser.GameObjects.Image; + private cursorObj: Phaser.GameObjects.Image | null; constructor(scene: BattleScene) { super(scene, Mode.CONFIRM); @@ -53,9 +53,12 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler { const canvas = document.createElement("canvas"); const context = canvas.getContext("2d"); const styleOptions = getTextStyleOptions(TextStyle.PARTY, (this.scene as BattleScene).uiTheme).styleOptions; - context.font = styleOptions.fontSize + "px " + styleOptions.fontFamily; - this.transferButtonWidth = context.measureText(i18next.t("modifierSelectUiHandler:transfer")).width; - this.checkButtonWidth = context.measureText(i18next.t("modifierSelectUiHandler:checkTeam")).width; + + if (context) { + context.font = styleOptions.fontSize + "px " + styleOptions.fontFamily; + this.transferButtonWidth = context.measureText(i18next.t("modifierSelectUiHandler:transfer")).width; + this.checkButtonWidth = context.measureText(i18next.t("modifierSelectUiHandler:checkTeam")).width; + } this.transferButtonContainer = this.scene.add.container((this.scene.game.canvas.width - this.checkButtonWidth) / 6 - 21, -64); this.transferButtonContainer.setName("transfer-btn"); @@ -394,7 +397,7 @@ export default class ModifierSelectUiHandler extends AwaitableUiHandler { } const type = options[this.cursor].modifierTypeOption.type; - ui.showText(type.getDescription(this.scene)); + type && ui.showText(type.getDescription(this.scene)); if (type instanceof TmModifierType) { // prepare the move overlay to be shown with the toggle this.moveInfoOverlay.show(allMoves[type.moveId]); @@ -574,7 +577,7 @@ class ModifierOption extends Phaser.GameObjects.Container { this.add(this.itemContainer); const getItem = () => { - const item = this.scene.add.sprite(0, 0, "items", this.modifierTypeOption.type.iconImage); + const item = this.scene.add.sprite(0, 0, "items", this.modifierTypeOption.type?.iconImage); return item; }; @@ -587,10 +590,10 @@ class ModifierOption extends Phaser.GameObjects.Container { this.itemContainer.add(this.itemTint); } - this.itemText = addTextObject(this.scene, 0, 35, this.modifierTypeOption.type.name, TextStyle.PARTY, { align: "center" }); + this.itemText = addTextObject(this.scene, 0, 35, this.modifierTypeOption.type?.name!, TextStyle.PARTY, { align: "center" }); // TODO: is this bang correct? this.itemText.setOrigin(0.5, 0); this.itemText.setAlpha(0); - this.itemText.setTint(getModifierTierTextTint(this.modifierTypeOption.type.tier)); + this.itemText.setTint(this.modifierTypeOption.type?.tier ? getModifierTierTextTint(this.modifierTypeOption.type?.tier) : undefined); this.add(this.itemText); if (this.modifierTypeOption.cost) { @@ -722,7 +725,7 @@ class ModifierOption extends Phaser.GameObjects.Container { } getPbAtlasKey(tierOffset: integer = 0) { - return getPokeballAtlasKey((this.modifierTypeOption.type.tier + tierOffset) as integer as PokeballType); + return getPokeballAtlasKey((this.modifierTypeOption.type?.tier! + tierOffset) as integer as PokeballType); // TODO: is this bang correct? } updateCostText(): void { diff --git a/src/ui/move-info-overlay.ts b/src/ui/move-info-overlay.ts index 3b947cb842d..ded19b01a12 100644 --- a/src/ui/move-info-overlay.ts +++ b/src/ui/move-info-overlay.ts @@ -30,7 +30,7 @@ export default class MoveInfoOverlay extends Phaser.GameObjects.Container implem private move: Move; private desc: Phaser.GameObjects.Text; - private descScroll : Phaser.Tweens.Tween = null; + private descScroll : Phaser.Tweens.Tween | null = null; private val: Phaser.GameObjects.Container; private pp: Phaser.GameObjects.Text; @@ -131,7 +131,7 @@ export default class MoveInfoOverlay extends Phaser.GameObjects.Container implem // show this component with infos for the specific move show(move : Move):boolean { if (!(this.scene as BattleScene).enableMoveInfo) { - return; // move infos have been disabled + return false; // move infos have been disabled // TODO:: is `false` correct? i used to be `undeefined` } this.move = move; this.pow.setText(move.power >= 0 ? move.power.toString() : "---"); diff --git a/src/ui/party-exp-bar.ts b/src/ui/party-exp-bar.ts index 506b8b5c825..d2521225375 100644 --- a/src/ui/party-exp-bar.ts +++ b/src/ui/party-exp-bar.ts @@ -7,7 +7,7 @@ export default class PartyExpBar extends Phaser.GameObjects.Container { private pokemonIcon: Phaser.GameObjects.Container; private expText: Phaser.GameObjects.Text; - private tween: Phaser.Tweens.Tween; + private tween: Phaser.Tweens.Tween | null; public shown: boolean; @@ -16,7 +16,7 @@ export default class PartyExpBar extends Phaser.GameObjects.Container { } setup(): void { - this.bg = this.scene.add.nineslice(0, 0, "party_exp_bar", null, 8, 18, 21, 5, 6, 4); + this.bg = this.scene.add.nineslice(0, 0, "party_exp_bar", undefined, 8, 18, 21, 5, 6, 4); this.bg.setOrigin(0, 0); this.add(this.bg); diff --git a/src/ui/party-ui-handler.ts b/src/ui/party-ui-handler.ts index 7b77b71f4ec..3a9b3463ef1 100644 --- a/src/ui/party-ui-handler.ts +++ b/src/ui/party-ui-handler.ts @@ -118,9 +118,9 @@ export enum PartyOption { export type PartySelectCallback = (cursor: integer, option: PartyOption) => void; export type PartyModifierTransferSelectCallback = (fromCursor: integer, index: integer, itemQuantity?: integer, toCursor?: integer) => void; export type PartyModifierSpliceSelectCallback = (fromCursor: integer, toCursor?: integer) => void; -export type PokemonSelectFilter = (pokemon: PlayerPokemon) => string; -export type PokemonModifierTransferSelectFilter = (pokemon: PlayerPokemon, modifier: PokemonHeldItemModifier) => string; -export type PokemonMoveSelectFilter = (pokemonMove: PokemonMove) => string; +export type PokemonSelectFilter = (pokemon: PlayerPokemon) => string | null; +export type PokemonModifierTransferSelectFilter = (pokemon: PlayerPokemon, modifier: PokemonHeldItemModifier) => string | null; +export type PokemonMoveSelectFilter = (pokemonMove: PokemonMove) => string | null; export default class PartyUiHandler extends MessageUiHandler { private partyUiMode: PartyUiMode; @@ -142,7 +142,7 @@ export default class PartyUiHandler extends MessageUiHandler { /** This is only public for test/ui/transfer-item.test.ts */ public optionsContainer: Phaser.GameObjects.Container; private optionsBg: Phaser.GameObjects.NineSlice; - private optionsCursorObj: Phaser.GameObjects.Image; + private optionsCursorObj: Phaser.GameObjects.Image | null; private options: integer[]; private transferMode: boolean; @@ -156,7 +156,7 @@ export default class PartyUiHandler extends MessageUiHandler { private transferAll: boolean; private lastCursor: integer = 0; - private selectCallback: PartySelectCallback | PartyModifierTransferSelectCallback; + private selectCallback: PartySelectCallback | PartyModifierTransferSelectCallback | null; private selectFilter: PokemonSelectFilter | PokemonModifierTransferSelectFilter; private moveSelectFilter: PokemonMoveSelectFilter; private tmMoveId: Moves; @@ -377,17 +377,17 @@ export default class PartyUiHandler extends MessageUiHandler { this.moveInfoOverlay.clear(); const filterResult = (this.selectFilter as PokemonSelectFilter)(pokemon); if (filterResult === null) { - this.selectCallback(this.cursor, option); + this.selectCallback?.(this.cursor, option); this.clearOptions(); } else { this.clearOptions(); - this.showText(filterResult as string, null, () => this.showText(null, 0), null, true); + this.showText(filterResult as string, undefined, () => this.showText(null, 0), undefined, true); } ui.playSelect(); return true; } else if ((option !== PartyOption.SUMMARY && option !== PartyOption.UNPAUSE_EVOLUTION && option !== PartyOption.UNSPLICE && option !== PartyOption.RELEASE && option !== PartyOption.CANCEL && option !== PartyOption.RENAME) || (option === PartyOption.RELEASE && this.partyUiMode === PartyUiMode.RELEASE)) { - let filterResult: string; + let filterResult: string | null; const getTransferrableItemsFromPokemon = (pokemon: PlayerPokemon) => this.scene.findModifiers(m => m instanceof PokemonHeldItemModifier && m.isTransferrable && m.pokemonId === pokemon.id) as PokemonHeldItemModifier[]; if (option !== PartyOption.TRANSFER && option !== PartyOption.SPLICE) { @@ -396,7 +396,7 @@ export default class PartyUiHandler extends MessageUiHandler { filterResult = this.FilterChallengeLegal(pokemon); } if (filterResult === null && this.partyUiMode === PartyUiMode.MOVE_MODIFIER) { - filterResult = this.moveSelectFilter(pokemon.moveset[this.optionsCursor]); + filterResult = this.moveSelectFilter(pokemon.moveset[this.optionsCursor]!); // TODO: is this bang correct? } } else { filterResult = (this.selectFilter as PokemonModifierTransferSelectFilter)(pokemon, getTransferrableItemsFromPokemon(this.scene.getParty()[this.transferCursor])[this.transferOptionCursor]); @@ -451,7 +451,7 @@ export default class PartyUiHandler extends MessageUiHandler { return true; } else { this.clearOptions(); - this.showText(filterResult as string, null, () => this.showText(null, 0), null, true); + this.showText(filterResult as string, undefined, () => this.showText(null, 0), undefined, true); } } else if (option === PartyOption.SUMMARY) { ui.playSelect(); @@ -461,18 +461,18 @@ export default class PartyUiHandler extends MessageUiHandler { this.clearOptions(); ui.playSelect(); pokemon.pauseEvolutions = false; - this.showText(i18next.t("partyUiHandler:unpausedEvolutions", { pokemonName: getPokemonNameWithAffix(pokemon) }), null, () => this.showText(null, 0), null, true); + this.showText(i18next.t("partyUiHandler:unpausedEvolutions", { pokemonName: getPokemonNameWithAffix(pokemon) }), undefined, () => this.showText(null, 0), null, true); } else if (option === PartyOption.UNSPLICE) { this.clearOptions(); ui.playSelect(); - this.showText(i18next.t("partyUiHandler:unspliceConfirmation", { fusionName: pokemon.fusionSpecies.name, pokemonName: pokemon.name }), null, () => { + this.showText(i18next.t("partyUiHandler:unspliceConfirmation", { fusionName: pokemon.fusionSpecies?.name, pokemonName: pokemon.name }), null, () => { ui.setModeWithoutClear(Mode.CONFIRM, () => { const fusionName = pokemon.name; pokemon.unfuse().then(() => { this.clearPartySlots(); this.populatePartySlots(); ui.setMode(Mode.PARTY); - this.showText(i18next.t("partyUiHandler:wasReverted", { fusionName: fusionName, pokemonName: pokemon.name }), null, () => { + this.showText(i18next.t("partyUiHandler:wasReverted", { fusionName: fusionName, pokemonName: pokemon.name }), undefined, () => { ui.setMode(Mode.PARTY); this.showText(null, 0); }, null, true); @@ -732,7 +732,7 @@ export default class PartyUiHandler extends MessageUiHandler { return changed; } - showText(text: string, delay?: integer, callback?: Function, callbackDelay?: integer, prompt?: boolean, promptDelay?: integer) { + showText(text: string | null, delay?: integer | null, callback?: Function | null, callbackDelay?: integer | null, prompt?: boolean, promptDelay?: integer) { if (text === null) { text = defaultMessage; } @@ -792,7 +792,7 @@ export default class PartyUiHandler extends MessageUiHandler { const learnableLevelMoves = this.partyUiMode === PartyUiMode.REMEMBER_MOVE_MODIFIER ? pokemon.getLearnableLevelMoves() - : null; + : []; if (this.partyUiMode === PartyUiMode.REMEMBER_MOVE_MODIFIER && learnableLevelMoves?.length) { // show the move overlay with info for the first move @@ -802,7 +802,7 @@ export default class PartyUiHandler extends MessageUiHandler { const itemModifiers = this.partyUiMode === PartyUiMode.MODIFIER_TRANSFER ? this.scene.findModifiers(m => m instanceof PokemonHeldItemModifier && m.isTransferrable && m.pokemonId === pokemon.id) as PokemonHeldItemModifier[] - : null; + : []; if (this.options.length) { this.options.splice(0, this.options.length); @@ -810,7 +810,7 @@ export default class PartyUiHandler extends MessageUiHandler { this.eraseOptionsCursor(); } - let formChangeItemModifiers: PokemonFormChangeItemModifier[]; + let formChangeItemModifiers: PokemonFormChangeItemModifier[] | undefined; if (this.partyUiMode !== PartyUiMode.MOVE_MODIFIER && this.partyUiMode !== PartyUiMode.REMEMBER_MOVE_MODIFIER && (this.transferMode || this.partyUiMode !== PartyUiMode.MODIFIER_TRANSFER)) { switch (this.partyUiMode) { @@ -951,7 +951,7 @@ export default class PartyUiHandler extends MessageUiHandler { case PartyOption.MOVE_2: case PartyOption.MOVE_3: case PartyOption.MOVE_4: - const move = pokemon.moveset[option - PartyOption.MOVE_1]; + const move = pokemon.moveset[option - PartyOption.MOVE_1]!; // TODO: is the bang correct? if (this.showMovePp) { const maxPP = move.getMovePp(); const currPP = maxPP - move.ppUsed; @@ -1060,7 +1060,7 @@ export default class PartyUiHandler extends MessageUiHandler { if (this.partyUiMode === PartyUiMode.RELEASE) { const selectCallback = this.selectCallback; this.selectCallback = null; - selectCallback(this.cursor, PartyOption.RELEASE); + selectCallback && selectCallback(this.cursor, PartyOption.RELEASE); } this.showText(null, 0); }, null, true); diff --git a/src/ui/pokeball-tray.ts b/src/ui/pokeball-tray.ts index 00a8cdadc97..cf3b24c4d11 100644 --- a/src/ui/pokeball-tray.ts +++ b/src/ui/pokeball-tray.ts @@ -15,7 +15,7 @@ export default class PokeballTray extends Phaser.GameObjects.Container { } setup(): void { - this.bg = this.scene.add.nineslice(0, 0, `pb_tray_overlay_${this.player ? "player" : "enemy"}`, null, 104, 4, 48, 8, 0, 0); + this.bg = this.scene.add.nineslice(0, 0, `pb_tray_overlay_${this.player ? "player" : "enemy"}`, undefined, 104, 4, 48, 8, 0, 0); this.bg.setOrigin(this.player ? 1 : 0, 0); this.add(this.bg); diff --git a/src/ui/pokemon-icon-anim-handler.ts b/src/ui/pokemon-icon-anim-handler.ts index 99fe39c4184..d6796d5cb5d 100644 --- a/src/ui/pokemon-icon-anim-handler.ts +++ b/src/ui/pokemon-icon-anim-handler.ts @@ -21,7 +21,9 @@ export default class PokemonIconAnimHandler { const value = tween.getValue(); this.toggled = !!value; for (const i of this.icons.keys()) { - i.y += this.getModeYDelta(this.icons.get(i)) * (this.toggled ? 1 : -1); + const icon = this.icons.get(i); + const delta = icon ? this.getModeYDelta(icon) : 0; + i.y += delta * (this.toggled ? 1 : -1); } }; scene.tweens.addCounter({ @@ -56,7 +58,7 @@ export default class PokemonIconAnimHandler { } if (this.toggled) { const lastYDelta = this.icons.has(i) - ? this.icons.get(i) + ? this.icons.get(i)! : 0; const yDelta = this.getModeYDelta(mode); i.y += yDelta + lastYDelta; @@ -71,7 +73,9 @@ export default class PokemonIconAnimHandler { } for (const i of icons) { if (this.toggled) { - i.y -= this.getModeYDelta(this.icons.get(i)); + const icon = this.icons.get(i); + const delta = icon ? this.getModeYDelta(icon) : 0; + i.y -= delta; } this.icons.delete(i); } @@ -80,7 +84,9 @@ export default class PokemonIconAnimHandler { removeAll(): void { for (const i of this.icons.keys()) { if (this.toggled) { - i.y -= this.getModeYDelta(this.icons.get(i)); + const icon = this.icons.get(i); + const delta = icon ? this.getModeYDelta(icon) : 0; + i.y -= delta; } this.icons.delete(i); } diff --git a/src/ui/pokemon-info-container.ts b/src/ui/pokemon-info-container.ts index b2ee5a9164a..edb85ecff7a 100644 --- a/src/ui/pokemon-info-container.ts +++ b/src/ui/pokemon-info-container.ts @@ -80,8 +80,8 @@ export default class PokemonInfoContainer extends Phaser.GameObjects.Container { setup(): void { this.setName("pkmn-info"); - const currentLanguage = i18next.resolvedLanguage; - const langSettingKey = Object.keys(languageSettings).find(lang => currentLanguage.includes(lang)); + const currentLanguage = i18next.resolvedLanguage!; // TODO: is this bang correct? + const langSettingKey = Object.keys(languageSettings).find(lang => currentLanguage?.includes(lang))!; // TODO: is this bang correct? const textSettings = languageSettings[langSettingKey]; const infoBg = addWindow(this.scene, 0, 0, this.infoWindowWidth, 132); infoBg.setOrigin(0.5, 0.5); @@ -243,7 +243,7 @@ export default class PokemonInfoContainer extends Phaser.GameObjects.Container { this.pokemonFormText.setText(formName.length > this.numCharsBeforeCutoff ? formName.substring(0, this.numCharsBeforeCutoff - 3) + "..." : formName); if (formName.length > this.numCharsBeforeCutoff) { this.pokemonFormText.setInteractive(new Phaser.Geom.Rectangle(0, 0, this.pokemonFormText.width, this.pokemonFormText.height), Phaser.Geom.Rectangle.Contains); - this.pokemonFormText.on("pointerover", () => (this.scene as BattleScene).ui.showTooltip(null, pokemon.species.forms?.[pokemon.formIndex]?.formName, true)); + this.pokemonFormText.on("pointerover", () => (this.scene as BattleScene).ui.showTooltip("", pokemon.species.forms?.[pokemon.formIndex]?.formName, true)); this.pokemonFormText.on("pointerout", () => (this.scene as BattleScene).ui.hideTooltip()); } else { this.pokemonFormText.disableInteractive(); @@ -302,7 +302,7 @@ export default class PokemonInfoContainer extends Phaser.GameObjects.Container { const shinyDescriptor = doubleShiny || baseVariant ? `${baseVariant === 2 ? i18next.t("common:epicShiny") : baseVariant === 1 ? i18next.t("common:rareShiny") : i18next.t("common:commonShiny")}${doubleShiny ? `/${pokemon.fusionVariant === 2 ? i18next.t("common:epicShiny") : pokemon.fusionVariant === 1 ? i18next.t("common:rareShiny") : i18next.t("common:commonShiny")}` : ""}` : ""; - this.pokemonShinyIcon.on("pointerover", () => (this.scene as BattleScene).ui.showTooltip(null, `${i18next.t("common:shinyOnHover")}${shinyDescriptor ? ` (${shinyDescriptor})` : ""}`, true)); + this.pokemonShinyIcon.on("pointerover", () => (this.scene as BattleScene).ui.showTooltip("", `${i18next.t("common:shinyOnHover")}${shinyDescriptor ? ` (${shinyDescriptor})` : ""}`, true)); this.pokemonShinyIcon.on("pointerout", () => (this.scene as BattleScene).ui.hideTooltip()); const newShiny = BigInt(1 << (pokemon.shiny ? 1 : 0)); @@ -324,11 +324,11 @@ export default class PokemonInfoContainer extends Phaser.GameObjects.Container { } const starterSpeciesId = pokemon.species.getRootSpeciesId(); - const originalIvs: integer[] = this.scene.gameData.dexData[starterSpeciesId].caughtAttr + const originalIvs: integer[] | null = this.scene.gameData.dexData[starterSpeciesId].caughtAttr ? this.scene.gameData.dexData[starterSpeciesId].ivs : null; - this.statsContainer.updateIvs(pokemon.ivs, originalIvs); + this.statsContainer.updateIvs(pokemon.ivs, originalIvs!); // TODO: is this bang correct? this.scene.tweens.add({ targets: this, @@ -352,7 +352,7 @@ export default class PokemonInfoContainer extends Phaser.GameObjects.Container { } for (let m = 0; m < 4; m++) { - const move = m < pokemon.moveset.length ? pokemon.moveset[m].getMove() : null; + const move = m < pokemon.moveset.length && pokemon.moveset[m] ? pokemon.moveset[m]!.getMove() : null; this.pokemonMoveBgs[m].setFrame(Type[move ? move.type : Type.UNKNOWN].toString().toLowerCase()); this.pokemonMoveLabels[m].setText(move ? move.name : "-"); this.pokemonMovesContainers[m].setVisible(!!move); diff --git a/src/ui/registration-form-ui-handler.ts b/src/ui/registration-form-ui-handler.ts index d5e7f239378..733aab79b05 100644 --- a/src/ui/registration-form-ui-handler.ts +++ b/src/ui/registration-form-ui-handler.ts @@ -92,7 +92,7 @@ export default class RegistrationFormUiHandler extends FormModalUiHandler { .then(response => { if (response.hasOwnProperty("token")) { Utils.setCookie(Utils.sessionIdKey, response.token); - originalRegistrationAction(); + originalRegistrationAction && originalRegistrationAction(); } else { onFail(response); } diff --git a/src/ui/save-slot-select-ui-handler.ts b/src/ui/save-slot-select-ui-handler.ts index 8a81ac4858d..e6ab0d3b3c3 100644 --- a/src/ui/save-slot-select-ui-handler.ts +++ b/src/ui/save-slot-select-ui-handler.ts @@ -29,11 +29,11 @@ export default class SaveSlotSelectUiHandler extends MessageUiHandler { private sessionSlots: SessionSlot[]; private uiMode: SaveSlotUiMode; - private saveSlotSelectCallback: SaveSlotSelectCallback; + private saveSlotSelectCallback: SaveSlotSelectCallback | null; private scrollCursor: integer = 0; - private cursorObj: Phaser.GameObjects.NineSlice; + private cursorObj: Phaser.GameObjects.NineSlice | null; private sessionSlotsContainerInitialY: number; @@ -106,16 +106,16 @@ export default class SaveSlotSelectUiHandler extends MessageUiHandler { switch (this.uiMode) { case SaveSlotUiMode.LOAD: this.saveSlotSelectCallback = null; - originalCallback(cursor); + originalCallback && originalCallback(cursor); break; case SaveSlotUiMode.SAVE: const saveAndCallback = () => { const originalCallback = this.saveSlotSelectCallback; this.saveSlotSelectCallback = null; ui.revertMode(); - ui.showText(null, 0); + ui.showText("", 0); ui.setMode(Mode.MESSAGE); - originalCallback(cursor); + originalCallback && originalCallback(cursor); }; if (this.sessionSlots[cursor].hasData) { ui.showText(i18next.t("saveSlotSelectUiHandler:overwriteData"), null, () => { @@ -129,7 +129,7 @@ export default class SaveSlotSelectUiHandler extends MessageUiHandler { }); }, () => { ui.revertMode(); - ui.showText(null, 0); + ui.showText("", 0); }, false, 0, 19, 2000); }); } else if (this.sessionSlots[cursor].hasData === false) { @@ -143,7 +143,7 @@ export default class SaveSlotSelectUiHandler extends MessageUiHandler { } } else { this.saveSlotSelectCallback = null; - originalCallback(-1); + originalCallback && originalCallback(-1); success = true; } } else { @@ -202,7 +202,7 @@ export default class SaveSlotSelectUiHandler extends MessageUiHandler { const changed = super.setCursor(cursor); if (!this.cursorObj) { - this.cursorObj = this.scene.add.nineslice(0, 0, "select_cursor_highlight_thick", null, 296, 44, 6, 6, 6, 6); + this.cursorObj = this.scene.add.nineslice(0, 0, "select_cursor_highlight_thick", undefined, 296, 44, 6, 6, 6, 6); this.cursorObj.setOrigin(0, 0); this.sessionSlotsContainer.add(this.cursorObj); } @@ -292,7 +292,7 @@ class SessionSlot extends Phaser.GameObjects.Container { const icon = this.scene.addPokemonIcon(pokemon, 0, 0, 0, 0); const text = addTextObject(this.scene, 32, 20, `${i18next.t("saveSlotSelectUiHandler:lv")}${Utils.formatLargeNumber(pokemon.level, 1000)}`, TextStyle.PARTY, { fontSize: "54px", color: "#f8f8f8" }); - text.setShadow(0, 0, null); + text.setShadow(0, 0, undefined); text.setStroke("#424242", 14); text.setOrigin(1, 0); @@ -316,9 +316,11 @@ class SessionSlot extends Phaser.GameObjects.Container { if (modifier instanceof PokemonHeldItemModifier) { continue; } - const icon = modifier.getIcon(this.scene, false); - icon.setPosition(24 * visibleModifierIndex, 0); - modifierIconsContainer.add(icon); + const icon = modifier?.getIcon(this.scene, false); + if (icon) { + icon.setPosition(24 * visibleModifierIndex, 0); + modifierIconsContainer.add(icon); + } if (++visibleModifierIndex === 12) { break; } diff --git a/src/ui/settings/abstract-binding-ui-handler.ts b/src/ui/settings/abstract-binding-ui-handler.ts index 809c4ffa2f8..3da555e2c96 100644 --- a/src/ui/settings/abstract-binding-ui-handler.ts +++ b/src/ui/settings/abstract-binding-ui-handler.ts @@ -7,6 +7,8 @@ import {Button} from "#enums/buttons"; import {NavigationManager} from "#app/ui/settings/navigationMenu"; import i18next from "i18next"; +type CancelFn = (succes?: boolean) => boolean; + /** * Abstract class for handling UI elements related to button bindings. */ @@ -35,7 +37,7 @@ export default abstract class AbstractBindingUiHandler extends UiHandler { protected targetButtonIcon: Phaser.GameObjects.Sprite; // Function to call on cancel or completion of binding. - protected cancelFn: (boolean?) => boolean; + protected cancelFn: CancelFn | null; abstract swapAction(): boolean; protected timeLeftAutoClose: number = 5; @@ -51,7 +53,7 @@ export default abstract class AbstractBindingUiHandler extends UiHandler { * @param mode - The UI mode. */ constructor(scene: BattleScene, mode?: Mode) { - super(scene, mode); + super(scene, mode!); // TODO: is this bang correct? } /** @@ -107,7 +109,7 @@ export default abstract class AbstractBindingUiHandler extends UiHandler { if (this.timeLeftAutoClose >= 0) { this.manageAutoCloseTimer(); } else { - this.cancelFn(); + this.cancelFn && this.cancelFn(); } }, 1000); } @@ -163,7 +165,7 @@ export default abstract class AbstractBindingUiHandler extends UiHandler { */ processInput(button: Button): boolean { if (this.buttonPressed === null) { - return; + return false; // TODO: is false correct as default? (previously was `undefined`) } const ui = this.getUi(); let success = false; @@ -177,11 +179,11 @@ export default abstract class AbstractBindingUiHandler extends UiHandler { case Button.ACTION: // Process actions based on current cursor position. if (this.cursor === 0) { - this.cancelFn(); + this.cancelFn && this.cancelFn(); } else { success = this.swapAction(); NavigationManager.getInstance().updateIcons(); - this.cancelFn(success); + this.cancelFn && this.cancelFn(success); } break; } @@ -242,7 +244,7 @@ export default abstract class AbstractBindingUiHandler extends UiHandler { * @param assignedButtonIcon - The icon of the button that is assigned. * @param type - The type of button press. */ - onInputDown(buttonIcon: string, assignedButtonIcon: string, type: string): void { + onInputDown(buttonIcon: string, assignedButtonIcon: string | null, type: string): void { clearTimeout(this.countdownTimer); this.timerText.setText(""); this.newButtonIcon.setTexture(type); diff --git a/src/ui/settings/abstract-control-settings-ui-handler.ts b/src/ui/settings/abstract-control-settings-ui-handler.ts index 9bf0cb40975..1f0c2b98fbd 100644 --- a/src/ui/settings/abstract-control-settings-ui-handler.ts +++ b/src/ui/settings/abstract-control-settings-ui-handler.ts @@ -33,7 +33,7 @@ export default abstract class AbstractControlSettingsUiHandler extends UiHandler protected scrollCursor: integer; protected optionCursors: integer[]; - protected cursorObj: Phaser.GameObjects.NineSlice; + protected cursorObj: Phaser.GameObjects.NineSlice | null; protected optionsBg: Phaser.GameObjects.NineSlice; protected actionsBg: Phaser.GameObjects.NineSlice; @@ -74,13 +74,13 @@ export default abstract class AbstractControlSettingsUiHandler extends UiHandler * @param mode - The UI mode. */ constructor(scene: BattleScene, mode?: Mode) { - super(scene, mode); + super(scene, mode!); // TODO: is this bang correct? this.rowsToDisplay = 8; } getLocalStorageSetting(): object { // Retrieve the settings from local storage or use an empty object if none exist. - const settings: object = localStorage.hasOwnProperty(this.localStoragePropertyName) ? JSON.parse(localStorage.getItem(this.localStoragePropertyName)) : {}; + const settings: object = localStorage.hasOwnProperty(this.localStoragePropertyName) ? JSON.parse(localStorage.getItem(this.localStoragePropertyName)!) : {}; // TODO: is this bang correct? return settings; } @@ -442,7 +442,7 @@ export default abstract class AbstractControlSettingsUiHandler extends UiHandler switch (button) { case Button.ACTION: if (!this.optionCursors || !this.optionValueLabels) { - return; + return false; // TODO: is false correct as default? (previously was `undefined`) } if (this.settingBlacklisted.includes(setting) || !setting.includes("BUTTON_")) { success = false; @@ -490,7 +490,7 @@ export default abstract class AbstractControlSettingsUiHandler extends UiHandler break; case Button.LEFT: // Move selection left within the current option set. if (!this.optionCursors || !this.optionValueLabels) { - return; + return false; // TODO: is false correct as default? (previously was `undefined`) } if (this.settingBlacklisted.includes(setting) || setting.includes("BUTTON_")) { success = false; @@ -500,7 +500,7 @@ export default abstract class AbstractControlSettingsUiHandler extends UiHandler break; case Button.RIGHT: // Move selection right within the current option set. if (!this.optionCursors || !this.optionValueLabels) { - return; + return false; // TODO: is false correct as default? (previously was `undefined`) } if (this.settingBlacklisted.includes(setting) || setting.includes("BUTTON_")) { success = false; @@ -526,7 +526,7 @@ export default abstract class AbstractControlSettingsUiHandler extends UiHandler resetScroll() { this.cursorObj?.destroy(); this.cursorObj = null; - this.cursor = null; + this.cursor = 0; this.setCursor(0); this.setScrollCursor(0); this.updateSettingsScroll(); @@ -547,7 +547,7 @@ export default abstract class AbstractControlSettingsUiHandler extends UiHandler // Check if the cursor object exists, if not, create it. if (!this.cursorObj) { - this.cursorObj = this.scene.add.nineslice(0, 0, "summary_moves_cursor", null, (this.scene.game.canvas.width / 6) - 10, 16, 1, 1, 1, 1); + this.cursorObj = this.scene.add.nineslice(0, 0, "summary_moves_cursor", undefined, (this.scene.game.canvas.width / 6) - 10, 16, 1, 1, 1, 1); this.cursorObj.setOrigin(0, 0); // Set the origin to the top-left corner. this.optionsContainer.add(this.cursorObj); // Add the cursor to the options container. } diff --git a/src/ui/settings/abstract-settings-ui-handler.ts b/src/ui/settings/abstract-settings-ui-handler.ts index 4747a17be32..96d8e790c8a 100644 --- a/src/ui/settings/abstract-settings-ui-handler.ts +++ b/src/ui/settings/abstract-settings-ui-handler.ts @@ -30,7 +30,7 @@ export default class AbstractSettingsUiHandler extends UiHandler { protected navigationIcons: InputsIcons; - private cursorObj: Phaser.GameObjects.NineSlice; + private cursorObj: Phaser.GameObjects.NineSlice | null; private reloadSettings: Array; private reloadRequired: boolean; @@ -41,7 +41,7 @@ export default class AbstractSettingsUiHandler extends UiHandler { protected localStorageKey: string; constructor(scene: BattleScene, mode?: Mode) { - super(scene, mode); + super(scene, mode!); // TODO: is this bang correct? this.reloadRequired = false; this.rowsToDisplay = 8; @@ -180,7 +180,7 @@ export default class AbstractSettingsUiHandler extends UiHandler { super.show(args); this.updateBindings(); - const settings: object = localStorage.hasOwnProperty(this.localStorageKey) ? JSON.parse(localStorage.getItem(this.localStorageKey)) : {}; + const settings: object = localStorage.hasOwnProperty(this.localStorageKey) ? JSON.parse(localStorage.getItem(this.localStorageKey)!) : {}; // TODO: is this bang correct? this.settings.forEach((setting, s) => this.setOptionCursor(s, settings.hasOwnProperty(setting.key) ? settings[setting.key] : this.settings[s].default)); @@ -285,7 +285,7 @@ export default class AbstractSettingsUiHandler extends UiHandler { const ret = super.setCursor(cursor); if (!this.cursorObj) { - this.cursorObj = this.scene.add.nineslice(0, 0, "summary_moves_cursor", null, (this.scene.game.canvas.width / 6) - 10, 16, 1, 1, 1, 1); + this.cursorObj = this.scene.add.nineslice(0, 0, "summary_moves_cursor", undefined, (this.scene.game.canvas.width / 6) - 10, 16, 1, 1, 1, 1); this.cursorObj.setOrigin(0, 0); this.optionsContainer.add(this.cursorObj); } diff --git a/src/ui/settings/gamepad-binding-ui-handler.ts b/src/ui/settings/gamepad-binding-ui-handler.ts index 70291da15a2..16a8b9d2c30 100644 --- a/src/ui/settings/gamepad-binding-ui-handler.ts +++ b/src/ui/settings/gamepad-binding-ui-handler.ts @@ -10,7 +10,7 @@ export default class GamepadBindingUiHandler extends AbstractBindingUiHandler { constructor(scene: BattleScene, mode?: Mode) { super(scene, mode); - this.scene.input.gamepad.on("down", this.gamepadButtonDown, this); + this.scene.input.gamepad?.on("down", this.gamepadButtonDown, this); } setup() { super.setup(); diff --git a/src/ui/settings/keyboard-binding-ui-handler.ts b/src/ui/settings/keyboard-binding-ui-handler.ts index 2a92bb0fa6c..0bc74da86ce 100644 --- a/src/ui/settings/keyboard-binding-ui-handler.ts +++ b/src/ui/settings/keyboard-binding-ui-handler.ts @@ -11,7 +11,7 @@ export default class KeyboardBindingUiHandler extends AbstractBindingUiHandler { constructor(scene: BattleScene, mode?: Mode) { super(scene, mode); // Listen to gamepad button down events to initiate binding. - scene.input.keyboard.on("keydown", this.onKeyDown, this); + scene.input.keyboard?.on("keydown", this.onKeyDown, this); } setup() { super.setup(); diff --git a/src/ui/settings/settings-keyboard-ui-handler.ts b/src/ui/settings/settings-keyboard-ui-handler.ts index 5c4444991ad..3408359f33b 100644 --- a/src/ui/settings/settings-keyboard-ui-handler.ts +++ b/src/ui/settings/settings-keyboard-ui-handler.ts @@ -42,10 +42,10 @@ export default class SettingsKeyboardUiHandler extends AbstractControlSettingsUi this.settingBlacklisted = settingKeyboardBlackList; this.device = Device.KEYBOARD; - const deleteEvent = scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.DELETE); - const restoreDefaultEvent = scene.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.HOME); - deleteEvent.on("up", this.onDeleteDown, this); - restoreDefaultEvent.on("up", this.onHomeDown, this); + const deleteEvent = scene.input.keyboard?.addKey(Phaser.Input.Keyboard.KeyCodes.DELETE); + const restoreDefaultEvent = scene.input.keyboard?.addKey(Phaser.Input.Keyboard.KeyCodes.HOME); + deleteEvent && deleteEvent.on("up", this.onDeleteDown, this); + restoreDefaultEvent && restoreDefaultEvent.on("up", this.onHomeDown, this); } setSetting = setSettingKeyboard; diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index 028786c85f0..447f5c95e46 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -286,7 +286,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { private abilityCursor: number = -1; private natureCursor: number = -1; private filterBarCursor: integer = 0; - private starterMoveset: StarterMoveset; + private starterMoveset: StarterMoveset | null; private scrollCursor: number; private allSpecies: PokemonSpecies[] = []; @@ -298,7 +298,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { private starterAbilityIndexes: integer[] = []; private starterNatures: Nature[] = []; private starterMovesets: StarterMoveset[] = []; - private speciesStarterDexEntry: DexEntry; + private speciesStarterDexEntry: DexEntry | null; private speciesStarterMoves: Moves[]; private canCycleShiny: boolean; private canCycleForm: boolean; @@ -309,7 +309,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { private value: integer = 0; private canAddParty: boolean; - private assetLoadCancelled: Utils.BooleanHolder; + private assetLoadCancelled: Utils.BooleanHolder | null; public cursorObj: Phaser.GameObjects.Image; private starterCursorObjs: Phaser.GameObjects.Image[]; private pokerusCursorObjs: Phaser.GameObjects.Image[]; @@ -331,7 +331,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { private instructionRowY = 0; private instructionRowTextOffset = 12; - private starterSelectCallback: StarterSelectCallback; + private starterSelectCallback: StarterSelectCallback | null; private starterPreferences: StarterPreferences; @@ -343,8 +343,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler { setup() { const ui = this.getUi(); - const currentLanguage = i18next.resolvedLanguage; - const langSettingKey = Object.keys(languageSettings).find(lang => currentLanguage.includes(lang)); + const currentLanguage = i18next.resolvedLanguage!; // TODO: is this bang correct? + const langSettingKey = Object.keys(languageSettings).find(lang => currentLanguage.includes(lang))!; // TODO: is this bang correct? const textSettings = languageSettings[langSettingKey]; this.starterSelectContainer = this.scene.add.container(0, -this.scene.game.canvas.height / 6); @@ -574,7 +574,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { startLabel.setOrigin(0.5, 0); this.starterSelectContainer.add(startLabel); - this.startCursorObj = this.scene.add.nineslice(teamWindowX+4, 160, "select_cursor", null, 26, 15, 6, 6, 6, 6); + this.startCursorObj = this.scene.add.nineslice(teamWindowX+4, 160, "select_cursor", undefined, 26, 15, 6, 6, 6, 6); this.startCursorObj.setVisible(false); this.startCursorObj.setOrigin(0, 0); this.starterSelectContainer.add(this.startCursorObj); @@ -845,7 +845,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.scene.executeWithSeedOffset(() => { for (let c = 0; c < 3; c++) { let randomSpeciesId: Species; - let species: PokemonSpecies; + let species: PokemonSpecies | undefined; const generateSpecies = () => { randomSpeciesId = Utils.randSeedItem(starterSpecies); @@ -867,7 +867,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { } } while (dupe); - this.pokerusSpecies.push(species); + this.pokerusSpecies.push(species!); // TODO: is the bang correct? } }, 0, date.getTime().toString()); @@ -1296,7 +1296,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { species = this.starterSpecies[this.starterIconsCursorIndex]; } const ui = this.getUi(); - let options = []; + let options: any[] = []; // TODO: add proper type const [isDupe, removeIndex]: [boolean, number] = this.isInParty(species); // checks to see if the pokemon is a duplicate; if it is, returns the index that will be removed @@ -1322,7 +1322,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { const cursorObj = this.starterCursorObjs[this.starterSpecies.length]; cursorObj.setVisible(true); cursorObj.setPosition(this.cursorObj.x, this.cursorObj.y); - this.addToParty(species, this.dexAttrCursor, this.abilityCursor, this.natureCursor as unknown as Nature, this.starterMoveset.slice(0) as StarterMoveset); + this.addToParty(species, this.dexAttrCursor, this.abilityCursor, this.natureCursor as unknown as Nature, this.starterMoveset?.slice(0) as StarterMoveset); ui.playSelect(); } else { ui.playError(); // this should be redundant as there is now a trigger for when a pokemon can't be added to party @@ -1378,7 +1378,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { label: allMoves[sm].name, handler: () => { this.switchMoveHandler(i, sm, m); - showSwapOptions(this.starterMoveset); + showSwapOptions(this.starterMoveset!); // TODO: is this bang correct? return true; }, onHover: () => { @@ -1389,7 +1389,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { }).concat({ label: i18next.t("menu:cancel"), handler: () => { - showSwapOptions(this.starterMoveset); + showSwapOptions(this.starterMoveset!); // TODO: is this bang correct? return true; }, onHover: () => { @@ -1433,7 +1433,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { options.push({ label: i18next.t("starterSelectUiHandler:manageMoves"), handler: () => { - showSwapOptions(this.starterMoveset); + showSwapOptions(this.starterMoveset!); // TODO: is this bang correct? return true; } }); @@ -1449,7 +1449,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { ui.setMode(Mode.STARTER_SELECT).then(() => { ui.showText(i18next.t("starterSelectUiHandler:selectNature"), null, () => { - const natures = this.scene.gameData.getNaturesForAttr(this.speciesStarterDexEntry.natureAttr); + const natures = this.scene.gameData.getNaturesForAttr(this.speciesStarterDexEntry?.natureAttr); ui.setModeWithoutClear(Mode.OPTION_SELECT, { options: natures.map((n: Nature, i: number) => { const option: OptionSelectItem = { @@ -1518,7 +1518,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { } } const showUseCandies = () => { // this lets you use your candies - const options = []; + const options: any[] = []; // TODO: add proper type if (!(passiveAttr & PassiveAttr.UNLOCKED)) { const passiveCost = getPassiveCandyCount(speciesStarters[this.lastSpecies.speciesId]); options.push({ @@ -1691,7 +1691,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { let newFormIndex = props.formIndex; do { newFormIndex = (newFormIndex + 1) % formCount; - if (this.lastSpecies.forms[newFormIndex].isStarterSelectable && this.speciesStarterDexEntry.caughtAttr & this.scene.gameData.getFormAttr(newFormIndex)) { + if (this.lastSpecies.forms[newFormIndex].isStarterSelectable && this.speciesStarterDexEntry!.caughtAttr! & this.scene.gameData.getFormAttr(newFormIndex)) { // TODO: are those bangs correct? break; } } while (newFormIndex !== props.formIndex); @@ -1736,7 +1736,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { break; case Button.CYCLE_NATURE: if (this.canCycleNature) { - const natures = this.scene.gameData.getNaturesForAttr(this.speciesStarterDexEntry.natureAttr); + const natures = this.scene.gameData.getNaturesForAttr(this.speciesStarterDexEntry?.natureAttr); const natureIndex = natures.indexOf(this.natureCursor); const newNature = natures[natureIndex < natures.length - 1 ? natureIndex + 1 : 0]; // store cycled nature as default @@ -1751,24 +1751,24 @@ export default class StarterSelectUiHandler extends MessageUiHandler { do { newVariant = (newVariant + 1) % 3; if (!newVariant) { - if (this.speciesStarterDexEntry.caughtAttr & DexAttr.DEFAULT_VARIANT) { + if (this.speciesStarterDexEntry!.caughtAttr & DexAttr.DEFAULT_VARIANT) { // TODO: is this bang correct? break; } } else if (newVariant === 1) { - if (this.speciesStarterDexEntry.caughtAttr & DexAttr.VARIANT_2) { + if (this.speciesStarterDexEntry!.caughtAttr & DexAttr.VARIANT_2) { // TODO: is this bang correct? break; } } else { - if (this.speciesStarterDexEntry.caughtAttr & DexAttr.VARIANT_3) { + if (this.speciesStarterDexEntry!.caughtAttr & DexAttr.VARIANT_3) { // TODO: is this bang correct? break; } } } while (newVariant !== props.variant); starterAttributes.variant = newVariant; // store the selected variant - this.setSpeciesDetails(this.lastSpecies, undefined, undefined, undefined, newVariant, undefined, undefined); + this.setSpeciesDetails(this.lastSpecies, undefined, undefined, undefined, newVariant as Variant, undefined, undefined); // Cycle tint based on current sprite tint - const tint = getVariantTint(newVariant); - this.pokemonShinyIcon.setFrame(getVariantIcon(newVariant)); + const tint = getVariantTint(newVariant as Variant); + this.pokemonShinyIcon.setFrame(getVariantIcon(newVariant as Variant)); this.pokemonShinyIcon.setTint(tint); success = true; } @@ -1950,34 +1950,34 @@ export default class StarterSelectUiHandler extends MessageUiHandler { switchMoveHandler(i: number, newMove: Moves, move: Moves) { const speciesId = this.lastSpecies.speciesId; - const existingMoveIndex = this.starterMoveset.indexOf(newMove); - this.starterMoveset[i] = newMove; + const existingMoveIndex = this.starterMoveset?.indexOf(newMove)!; // TODO: is this bang correct? + this.starterMoveset![i] = newMove; // TODO: is this bang correct? if (existingMoveIndex > -1) { - this.starterMoveset[existingMoveIndex] = move; + this.starterMoveset![existingMoveIndex] = move; // TODO: is this bang correct? } const props: DexAttrProps = this.scene.gameData.getSpeciesDexAttrProps(this.lastSpecies, this.dexAttrCursor); // species has different forms if (pokemonFormLevelMoves.hasOwnProperty(speciesId)) { // starterMoveData doesn't have base form moves or is using the single form format if (!this.scene.gameData.starterData[speciesId].moveset || Array.isArray(this.scene.gameData.starterData[speciesId].moveset)) { - this.scene.gameData.starterData[speciesId].moveset = { [props.formIndex]: this.starterMoveset.slice(0) as StarterMoveset }; + this.scene.gameData.starterData[speciesId].moveset = { [props.formIndex]: this.starterMoveset?.slice(0) as StarterMoveset }; } const starterMoveData = this.scene.gameData.starterData[speciesId].moveset; // starterMoveData doesn't have active form moves if (!starterMoveData.hasOwnProperty(props.formIndex)) { - this.scene.gameData.starterData[speciesId].moveset[props.formIndex] = this.starterMoveset.slice(0) as StarterMoveset; + this.scene.gameData.starterData[speciesId].moveset[props.formIndex] = this.starterMoveset?.slice(0) as StarterMoveset; } // does the species' starter move data have its form's starter moves and has it been updated if (starterMoveData.hasOwnProperty(props.formIndex)) { // active form move hasn't been updated if (starterMoveData[props.formIndex][existingMoveIndex] !== newMove) { - this.scene.gameData.starterData[speciesId].moveset[props.formIndex] = this.starterMoveset.slice(0) as StarterMoveset; + this.scene.gameData.starterData[speciesId].moveset[props.formIndex] = this.starterMoveset?.slice(0) as StarterMoveset; } } } else { - this.scene.gameData.starterData[speciesId].moveset = this.starterMoveset.slice(0) as StarterMoveset; + this.scene.gameData.starterData[speciesId].moveset = this.starterMoveset?.slice(0) as StarterMoveset; } this.setSpeciesDetails(this.lastSpecies, undefined, undefined, undefined, undefined, undefined, undefined, false); @@ -1986,7 +1986,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { Array.from({ length: this.starterSpecies.length }, (_, i) => { const starterSpecies = this.starterSpecies[i]; if (starterSpecies.speciesId === speciesId) { - this.starterMovesets[i] = this.starterMoveset; + this.starterMovesets[i] = this.starterMoveset!; // TODO: is this bang correct? } }); } @@ -2382,22 +2382,22 @@ export default class StarterSelectUiHandler extends MessageUiHandler { } } - setSpecies(species: PokemonSpecies) { + setSpecies(species: PokemonSpecies | null) { this.speciesStarterDexEntry = species ? this.scene.gameData.dexData[species.speciesId] : null; this.dexAttrCursor = species ? this.scene.gameData.getSpeciesDefaultDexAttr(species, false, true) : 0n; this.abilityCursor = species ? this.scene.gameData.getStarterSpeciesDefaultAbilityIndex(species) : 0; this.natureCursor = species ? this.scene.gameData.getSpeciesDefaultNature(species) : 0; - const starterAttributes : StarterAttributes = species ? {...this.starterPreferences[species.speciesId]} : null; + const starterAttributes : StarterAttributes | null = species ? {...this.starterPreferences[species.speciesId]} : null; // validate starterAttributes if (starterAttributes) { // this may cause changes so we created a copy of the attributes before - if (!isNaN(starterAttributes.variant)) { + if (starterAttributes.variant && !isNaN(starterAttributes.variant)) { if (![ - this.speciesStarterDexEntry.caughtAttr & DexAttr.NON_SHINY, - this.speciesStarterDexEntry.caughtAttr & DexAttr.DEFAULT_VARIANT, - this.speciesStarterDexEntry.caughtAttr & DexAttr.VARIANT_2, - this.speciesStarterDexEntry.caughtAttr & DexAttr.VARIANT_3 + this.speciesStarterDexEntry!.caughtAttr & DexAttr.NON_SHINY, // TODO: is that bang correct? + this.speciesStarterDexEntry!.caughtAttr & DexAttr.DEFAULT_VARIANT, // TODO: is that bang correct? + this.speciesStarterDexEntry!.caughtAttr & DexAttr.VARIANT_2, // TODO: is that bang correct? + this.speciesStarterDexEntry!.caughtAttr & DexAttr.VARIANT_3 // TODO: is that bang correct? ][starterAttributes.variant+1]) { // add 1 as -1 = non-shiny // requested variant wasn't unlocked, purging setting delete starterAttributes.variant; @@ -2405,29 +2405,29 @@ export default class StarterSelectUiHandler extends MessageUiHandler { } if (typeof starterAttributes.female !== "boolean" || !(starterAttributes.female ? - this.speciesStarterDexEntry.caughtAttr & DexAttr.FEMALE : - this.speciesStarterDexEntry.caughtAttr & DexAttr.MALE + this.speciesStarterDexEntry!.caughtAttr & DexAttr.FEMALE : // TODO: is this bang correct? + this.speciesStarterDexEntry!.caughtAttr & DexAttr.MALE // TODO: is this bang correct? )) { // requested gender wasn't unlocked, purging setting delete starterAttributes.female; } - const abilityAttr = this.scene.gameData.starterData[species.speciesId].abilityAttr; + const abilityAttr = this.scene.gameData.starterData[species!.speciesId].abilityAttr; // TODO: is this bang correct? if (![ abilityAttr & AbilityAttr.ABILITY_1, - species.ability2 ? (abilityAttr & AbilityAttr.ABILITY_2) : abilityAttr & AbilityAttr.ABILITY_HIDDEN, - species.ability2 && abilityAttr & AbilityAttr.ABILITY_HIDDEN - ][starterAttributes.ability]) { + species!.ability2 ? (abilityAttr & AbilityAttr.ABILITY_2) : abilityAttr & AbilityAttr.ABILITY_HIDDEN, // TODO: is this bang correct? + species!.ability2 && abilityAttr & AbilityAttr.ABILITY_HIDDEN // TODO: is this bang correct? + ][starterAttributes.ability!]) { // TODO: is this bang correct? // requested ability wasn't unlocked, purging setting delete starterAttributes.ability; } - if (!(species.forms[starterAttributes.form]?.isStarterSelectable && this.speciesStarterDexEntry.caughtAttr & this.scene.gameData.getFormAttr(starterAttributes.form))) { + if (!(species?.forms[starterAttributes.form!]?.isStarterSelectable && this.speciesStarterDexEntry!.caughtAttr & this.scene.gameData.getFormAttr(starterAttributes.form!))) { // TODO: are those bangs correct? // requested form wasn't unlocked/isn't a starter form, purging setting delete starterAttributes.form; } - if (this.scene.gameData.getNaturesForAttr(this.speciesStarterDexEntry.natureAttr).indexOf(starterAttributes.nature as unknown as Nature) < 0) { + if (this.scene.gameData.getNaturesForAttr(this.speciesStarterDexEntry?.natureAttr).indexOf(starterAttributes.nature as unknown as Nature) < 0) { // requested nature wasn't unlocked, purging setting delete starterAttributes.nature; } @@ -2437,7 +2437,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { // load default nature from stater save data, if set this.natureCursor = starterAttributes.nature; } - if (!isNaN(starterAttributes?.ability)) { + if (starterAttributes?.ability && !isNaN(starterAttributes.ability)) { // load default nature from stater save data, if set this.abilityCursor = starterAttributes.ability; } @@ -2448,7 +2448,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.showStats(); } else { this.statsContainer.setVisible(false); - this.statsContainer.updateIvs(null); + //@ts-ignore + this.statsContainer.updateIvs(null); // TODO: resolve ts-ignore. what. how? huh? } } @@ -2465,7 +2466,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.scene.tweens.getTweensOf(icon).forEach(tween => tween.resume()); } - this.lastSpecies = species; + this.lastSpecies = species!; // TODO: is this bang correct? if (species && (this.speciesStarterDexEntry?.seenAttr || this.speciesStarterDexEntry?.caughtAttr)) { this.pokemonNumberText.setText(Utils.padInt(species.speciesId, 4)); @@ -2547,7 +2548,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { const candyCropY = 16 - (16 * (currentFriendship / friendshipCap)); if (this.pokemonCandyDarknessOverlay.visible) { - this.pokemonCandyDarknessOverlay.on("pointerover", () => (this.scene as BattleScene).ui.showTooltip(null, `${currentFriendship}/${friendshipCap}`, true)); + this.pokemonCandyDarknessOverlay.on("pointerover", () => (this.scene as BattleScene).ui.showTooltip("", `${currentFriendship}/${friendshipCap}`, true)); this.pokemonCandyDarknessOverlay.on("pointerout", () => (this.scene as BattleScene).ui.hideTooltip()); } @@ -2582,7 +2583,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { // load default nature from stater save data, if set const defaultNature = starterAttributes?.nature || this.scene.gameData.getSpeciesDefaultNature(species); props = this.scene.gameData.getSpeciesDexAttrProps(species, defaultDexAttr); - if (!isNaN(starterAttributes?.variant)) { + if (starterAttributes?.variant && !isNaN(starterAttributes.variant)) { if (props.shiny = (starterAttributes.variant >= 0)) { props.variant = starterAttributes.variant as Variant; } @@ -2594,7 +2595,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { } const speciesForm = getPokemonSpeciesForm(species.speciesId, props.formIndex); - this.setTypeIcons(speciesForm.type1, speciesForm.type2); + this.setTypeIcons(speciesForm.type1, speciesForm!.type2!); // TODO: are those bangs correct? this.pokemonSprite.clearTint(); if (this.pokerusSpecies.includes(species)) { @@ -2648,14 +2649,14 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.pokemonCandyCountText.setVisible(false); this.pokemonFormText.setVisible(false); - this.setSpeciesDetails(species, false, 0, false, 0, 0, 0); + this.setSpeciesDetails(species!, false, 0, false, 0, 0, 0); // TODO: is this bang correct? this.pokemonSprite.clearTint(); } } - setSpeciesDetails(species: PokemonSpecies, shiny: boolean, formIndex: integer, female: boolean, variant: Variant, abilityIndex: integer, natureIndex: integer, forSeen: boolean = false): void { + setSpeciesDetails(species: PokemonSpecies, shiny?: boolean, formIndex?: integer, female?: boolean, variant?: Variant, abilityIndex?: integer, natureIndex?: integer, forSeen: boolean = false): void { const oldProps = species ? this.scene.gameData.getSpeciesDexAttrProps(species, this.dexAttrCursor) : null; const oldAbilityIndex = this.abilityCursor > -1 ? this.abilityCursor : this.scene.gameData.getStarterSpeciesDefaultAbilityIndex(species); const oldNatureIndex = this.natureCursor > -1 ? this.natureCursor : this.scene.gameData.getSpeciesDefaultNature(species); @@ -2672,10 +2673,10 @@ export default class StarterSelectUiHandler extends MessageUiHandler { } if (species) { - this.dexAttrCursor |= (shiny !== undefined ? !shiny : !(shiny = oldProps.shiny)) ? DexAttr.NON_SHINY : DexAttr.SHINY; - this.dexAttrCursor |= (female !== undefined ? !female : !(female = oldProps.female)) ? DexAttr.MALE : DexAttr.FEMALE; - this.dexAttrCursor |= (variant !== undefined ? !variant : !(variant = oldProps.variant)) ? DexAttr.DEFAULT_VARIANT : variant === 1 ? DexAttr.VARIANT_2 : DexAttr.VARIANT_3; - this.dexAttrCursor |= this.scene.gameData.getFormAttr(formIndex !== undefined ? formIndex : (formIndex = oldProps.formIndex)); + this.dexAttrCursor |= (shiny !== undefined ? !shiny : !(shiny = oldProps?.shiny)) ? DexAttr.NON_SHINY : DexAttr.SHINY; + this.dexAttrCursor |= (female !== undefined ? !female : !(female = oldProps?.female)) ? DexAttr.MALE : DexAttr.FEMALE; + this.dexAttrCursor |= (variant !== undefined ? !variant : !(variant = oldProps?.variant)) ? DexAttr.DEFAULT_VARIANT : variant === 1 ? DexAttr.VARIANT_2 : DexAttr.VARIANT_3; + this.dexAttrCursor |= this.scene.gameData.getFormAttr(formIndex !== undefined ? formIndex : (formIndex = oldProps!.formIndex)); // TODO: is this bang correct? this.abilityCursor = abilityIndex !== undefined ? abilityIndex : (abilityIndex = oldAbilityIndex); this.natureCursor = natureIndex !== undefined ? natureIndex : (natureIndex = oldNatureIndex); } @@ -2717,7 +2718,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { } } - this.shinyOverlay.setVisible(shiny); + this.shinyOverlay.setVisible(shiny ?? false); // TODO: is false the correct default? this.pokemonNumberText.setColor(this.getTextColor(shiny ? TextStyle.SUMMARY_GOLD : TextStyle.SUMMARY, false)); this.pokemonNumberText.setShadowColor(this.getTextColor(shiny ? TextStyle.SUMMARY_GOLD : TextStyle.SUMMARY, true)); @@ -2733,16 +2734,16 @@ export default class StarterSelectUiHandler extends MessageUiHandler { const assetLoadCancelled = new Utils.BooleanHolder(false); this.assetLoadCancelled = assetLoadCancelled; - species.loadAssets(this.scene, female, formIndex, shiny, variant, true).then(() => { + species.loadAssets(this.scene, female!, formIndex, shiny, variant, true).then(() => { // TODO: is this bang correct? if (assetLoadCancelled.value) { return; } this.assetLoadCancelled = null; this.speciesLoaded.set(species.speciesId, true); - this.pokemonSprite.play(species.getSpriteKey(female, formIndex, shiny, variant)); + this.pokemonSprite.play(species.getSpriteKey(female!, formIndex, shiny, variant)); // TODO: is this bang correct? this.pokemonSprite.setPipelineData("shiny", shiny); this.pokemonSprite.setPipelineData("variant", variant); - this.pokemonSprite.setPipelineData("spriteKey", species.getSpriteKey(female, formIndex, shiny, variant)); + this.pokemonSprite.setPipelineData("spriteKey", species.getSpriteKey(female!, formIndex, shiny, variant)); // TODO: is this bang correct? this.pokemonSprite.setVisible(!this.statsMode); }); @@ -2750,7 +2751,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { const isValidForChallenge = new Utils.BooleanHolder(true); Challenge.applyChallenges(this.scene.gameMode, Challenge.ChallengeType.STARTER_CHOICE, species, isValidForChallenge, this.scene.gameData.getSpeciesDexAttrProps(species, this.dexAttrCursor), !!this.starterSpecies.length); const starterSprite = this.filteredStarterContainers[this.cursor].icon as Phaser.GameObjects.Sprite; - starterSprite.setTexture(species.getIconAtlasKey(formIndex, shiny, variant), species.getIconId(female, formIndex, shiny, variant)); + starterSprite.setTexture(species.getIconAtlasKey(formIndex, shiny, variant), species.getIconId(female!, formIndex, shiny, variant)); // TODO: is this bang correct? this.filteredStarterContainers[this.cursor].checkIconId(female, formIndex, shiny, variant); this.canCycleShiny = !!(dexEntry.caughtAttr & DexAttr.NON_SHINY && dexEntry.caughtAttr & DexAttr.SHINY); this.canCycleGender = !!(dexEntry.caughtAttr & DexAttr.MALE && dexEntry.caughtAttr & DexAttr.FEMALE); @@ -2758,7 +2759,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.canCycleForm = species.forms.filter(f => f.isStarterSelectable || !pokemonFormChanges[species.speciesId]?.find(fc => fc.formKey)) .map((_, f) => dexEntry.caughtAttr & this.scene.gameData.getFormAttr(f)).filter(f => f).length > 1; this.canCycleNature = this.scene.gameData.getNaturesForAttr(dexEntry.natureAttr).length > 1; - this.canCycleVariant = shiny && [ dexEntry.caughtAttr & DexAttr.DEFAULT_VARIANT, dexEntry.caughtAttr & DexAttr.VARIANT_2, dexEntry.caughtAttr & DexAttr.VARIANT_3].filter(v => v).length > 1; + this.canCycleVariant = !!shiny && [ dexEntry.caughtAttr & DexAttr.DEFAULT_VARIANT, dexEntry.caughtAttr & DexAttr.VARIANT_2, dexEntry.caughtAttr & DexAttr.VARIANT_3].filter(v => v).length > 1; } if (dexEntry.caughtAttr && species.malePercent !== null) { @@ -2771,7 +2772,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { } if (dexEntry.caughtAttr) { - const ability = this.lastSpecies.getAbility(abilityIndex); + const ability = this.lastSpecies.getAbility(abilityIndex!); // TODO: is this bang correct? this.pokemonAbilityText.setText(allAbilities[ability].name); const isHidden = abilityIndex === (this.lastSpecies.ability2 ? 2 : 1); @@ -2786,7 +2787,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.pokemonNatureText.setText(getNatureName(natureIndex as unknown as Nature, true, true, false, this.scene.uiTheme)); let levelMoves: LevelMoves; - if (pokemonFormLevelMoves.hasOwnProperty(species.speciesId) && pokemonFormLevelMoves[species.speciesId].hasOwnProperty(formIndex)) { + if (pokemonFormLevelMoves.hasOwnProperty(species.speciesId) && formIndex && pokemonFormLevelMoves[species.speciesId].hasOwnProperty(formIndex)) { levelMoves = pokemonFormLevelMoves[species.speciesId][formIndex]; } else { levelMoves = pokemonSpeciesLevelMoves[species.speciesId]; @@ -2801,41 +2802,42 @@ export default class StarterSelectUiHandler extends MessageUiHandler { } const speciesMoveData = this.scene.gameData.starterData[species.speciesId].moveset; - const moveData: StarterMoveset = speciesMoveData + const moveData: StarterMoveset | null = speciesMoveData ? Array.isArray(speciesMoveData) ? speciesMoveData as StarterMoveset - : (speciesMoveData as StarterFormMoveData)[formIndex] + : (speciesMoveData as StarterFormMoveData)[formIndex!] // TODO: is this bang correct? : null; const availableStarterMoves = this.speciesStarterMoves.concat(speciesEggMoves.hasOwnProperty(species.speciesId) ? speciesEggMoves[species.speciesId].filter((_, em: integer) => this.scene.gameData.starterData[species.speciesId].eggMoves & (1 << em)) : []); this.starterMoveset = (moveData || (this.speciesStarterMoves.slice(0, 4) as StarterMoveset)).filter(m => availableStarterMoves.find(sm => sm === m)) as StarterMoveset; // Consolidate move data if it contains an incompatible move if (this.starterMoveset.length < 4 && this.starterMoveset.length < availableStarterMoves.length) { - this.starterMoveset.push(...availableStarterMoves.filter(sm => this.starterMoveset.indexOf(sm) === -1).slice(0, 4 - this.starterMoveset.length)); + this.starterMoveset.push(...availableStarterMoves.filter(sm => this.starterMoveset?.indexOf(sm) === -1).slice(0, 4 - this.starterMoveset.length)); } // Remove duplicate moves this.starterMoveset = this.starterMoveset.filter( (move, i) => { - return this.starterMoveset.indexOf(move) === i; + return this.starterMoveset?.indexOf(move) === i; }) as StarterMoveset; - const speciesForm = getPokemonSpeciesForm(species.speciesId, formIndex); - const formText = Utils.capitalizeString(species?.forms[formIndex]?.formKey, "-", false, false); + const speciesForm = getPokemonSpeciesForm(species.speciesId, formIndex!); // TODO: is the bang correct? + const formText = Utils.capitalizeString(species?.forms[formIndex!]?.formKey, "-", false, false); // TODO: is the bang correct? const speciesName = Utils.capitalizeString(Species[species.speciesId], "_", true, false); if (species.speciesId === Species.ARCEUS) { - this.pokemonFormText.setText(i18next.t(`pokemonInfo:Type.${formText.toUpperCase()}`)); + this.pokemonFormText.setText(i18next.t(`pokemonInfo:Type.${formText?.toUpperCase()}`)); } else { this.pokemonFormText.setText(formText ? i18next.t(`pokemonForm:${speciesName}${formText}`) : ""); } - this.setTypeIcons(speciesForm.type1, speciesForm.type2); + this.setTypeIcons(speciesForm.type1, speciesForm.type2!); // TODO: is this bang correct? } else { this.pokemonAbilityText.setText(""); this.pokemonPassiveText.setText(""); this.pokemonNatureText.setText(""); - this.setTypeIcons(null, null); + // @ts-ignore + this.setTypeIcons(null, null); // TODO: resolve ts-ignore.. huh!? } } else { this.shinyOverlay.setVisible(false); @@ -2845,7 +2847,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.pokemonAbilityText.setText(""); this.pokemonPassiveText.setText(""); this.pokemonNatureText.setText(""); - this.setTypeIcons(null, null); + // @ts-ignore + this.setTypeIcons(null, null); // TODO: resolve ts-ignore.. huh!? } if (!this.starterMoveset) { @@ -2868,7 +2871,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.pokemonEggMoveLabels[em].setText(eggMove && eggMoveUnlocked ? eggMove.name : "???"); } - this.pokemonEggMovesContainer.setVisible(this.speciesStarterDexEntry?.caughtAttr && hasEggMoves); + this.pokemonEggMovesContainer.setVisible(!!this.speciesStarterDexEntry?.caughtAttr && hasEggMoves); this.pokemonAdditionalMoveCountLabel.setText(`(+${Math.max(this.speciesStarterMoves.length - 4, 0)})`); this.pokemonAdditionalMoveCountLabel.setVisible(this.speciesStarterMoves.length > 4); @@ -3064,7 +3067,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.scene.pushPhase(new TitlePhase(this.scene)); } this.clearText(); - this.scene.getCurrentPhase().end(); + this.scene.getCurrentPhase()?.end(); }, cancel, null, null, 19); }); @@ -3097,7 +3100,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { const thisObj = this; const originalStarterSelectCallback = this.starterSelectCallback; this.starterSelectCallback = null; - originalStarterSelectCallback(new Array(this.starterSpecies.length).fill(0).map(function (_, i) { + originalStarterSelectCallback && originalStarterSelectCallback(new Array(this.starterSpecies.length).fill(0).map(function (_, i) { const starterSpecies = thisObj.starterSpecies[i]; return { species: starterSpecies, @@ -3116,7 +3119,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { } else { const handler = this.scene.ui.getHandler() as AwaitableUiHandler; handler.tutorialActive = true; - this.scene.ui.showText(i18next.t("starterSelectUiHandler:invalidParty"), null, () => this.scene.ui.showText(null, 0, () => handler.tutorialActive = false), null, true); + this.scene.ui.showText(i18next.t("starterSelectUiHandler:invalidParty"), null, () => this.scene.ui.showText("", 0, () => handler.tutorialActive = false), null, true); } return true; } @@ -3147,7 +3150,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.statsMode = false; this.statsContainer.setVisible(false); this.pokemonSprite.setVisible(!!this.speciesStarterDexEntry?.caughtAttr); - this.statsContainer.updateIvs(null); + //@ts-ignore + this.statsContainer.updateIvs(null); // TODO: resolve ts-ignore. !?!? } } diff --git a/src/ui/summary-ui-handler.ts b/src/ui/summary-ui-handler.ts index 405429fcd3f..030e67fcc30 100644 --- a/src/ui/summary-ui-handler.ts +++ b/src/ui/summary-ui-handler.ts @@ -2,7 +2,7 @@ import BattleScene, { starterColors } from "../battle-scene"; import { Mode } from "./ui"; import UiHandler from "./ui-handler"; import * as Utils from "../utils"; -import { PlayerPokemon } from "../field/pokemon"; +import { PlayerPokemon, PokemonMove } from "../field/pokemon"; import { getStarterValueFriendshipCap, speciesStarters } from "../data/pokemon-species"; import { argbFromRgba } from "@material/material-color-utilities"; import { Type, getTypeRgb } from "../data/type"; @@ -24,7 +24,6 @@ import i18next from "i18next"; import {modifierSortFunc} from "../modifier/modifier"; import { PlayerGender } from "#enums/player-gender"; - enum Page { PROFILE, STATS, @@ -41,11 +40,11 @@ interface abilityContainer { /** An image displaying the summary label */ labelImage: Phaser.GameObjects.Image, /** The ability object */ - ability: Ability, + ability: Ability | null, /** The text object displaying the name of the ability */ - nameText: Phaser.GameObjects.Text, + nameText: Phaser.GameObjects.Text | null, /** The text object displaying the description of the ability */ - descriptionText: Phaser.GameObjects.Text, + descriptionText: Phaser.GameObjects.Text | null, } export default class SummaryUiHandler extends UiHandler { @@ -79,8 +78,8 @@ export default class SummaryUiHandler extends UiHandler { private summaryPageContainer: Phaser.GameObjects.Container; private movesContainer: Phaser.GameObjects.Container; private moveDescriptionText: Phaser.GameObjects.Text; - private moveCursorObj: Phaser.GameObjects.Sprite; - private selectedMoveCursorObj: Phaser.GameObjects.Sprite; + private moveCursorObj: Phaser.GameObjects.Sprite | null; + private selectedMoveCursorObj: Phaser.GameObjects.Sprite | null; private moveRowsContainer: Phaser.GameObjects.Container; private extraMoveRowContainer: Phaser.GameObjects.Container; private moveEffectContainer: Phaser.GameObjects.Container; @@ -89,14 +88,14 @@ export default class SummaryUiHandler extends UiHandler { private moveCategoryIcon: Phaser.GameObjects.Sprite; private summaryPageTransitionContainer: Phaser.GameObjects.Container; - private descriptionScrollTween: Phaser.Tweens.Tween; - private moveCursorBlinkTimer: Phaser.Time.TimerEvent; + private descriptionScrollTween: Phaser.Tweens.Tween | null; + private moveCursorBlinkTimer: Phaser.Time.TimerEvent | null; - private pokemon: PlayerPokemon; + private pokemon: PlayerPokemon | null; private playerParty: boolean; /**This is set to false when checking the summary of a freshly caught Pokemon as it is not part of a player's party yet but still needs to display its items**/ - private newMove: Move; - private moveSelectFunction: Function; + private newMove: Move | null; + private moveSelectFunction: Function | null; private transitioning: boolean; private statusVisible: boolean; private moveEffectsVisible: boolean; @@ -104,7 +103,7 @@ export default class SummaryUiHandler extends UiHandler { private moveSelect: boolean; private moveCursor: integer; private selectedMoveIndex: integer; - private selectCallback: Function; + private selectCallback: Function | null; constructor(scene: BattleScene) { super(scene, Mode.SUMMARY); @@ -138,7 +137,7 @@ export default class SummaryUiHandler extends UiHandler { this.numberText.setOrigin(0, 1); this.summaryContainer.add(this.numberText); - this.pokemonSprite = this.scene.initPokemonSprite(this.scene.add.sprite(56, -106, "pkmn__sub"), null, false, true); + this.pokemonSprite = this.scene.initPokemonSprite(this.scene.add.sprite(56, -106, "pkmn__sub"), undefined, false, true); this.summaryContainer.add(this.pokemonSprite); this.nameText = addTextObject(this.scene, 6, -54, "", TextStyle.SUMMARY); @@ -305,10 +304,10 @@ export default class SummaryUiHandler extends UiHandler { this.pokemonSprite.setPipelineData("variant", this.pokemon.variant); [ "spriteColors", "fusionSpriteColors" ].map(k => { delete this.pokemonSprite.pipelineData[`${k}Base`]; - if (this.pokemon.summonData?.speciesForm) { + if (this.pokemon?.summonData?.speciesForm) { k += "Base"; } - this.pokemonSprite.pipelineData[k] = this.pokemon.getSprite().pipelineData[k]; + this.pokemonSprite.pipelineData[k] = this.pokemon?.getSprite().pipelineData[k]; }); this.pokemon.cry(); @@ -319,7 +318,7 @@ export default class SummaryUiHandler extends UiHandler { this.splicedIcon.setPositionRelative(this.nameText, this.nameText.displayWidth + 2, 3); this.splicedIcon.setVisible(isFusion); if (this.splicedIcon.visible) { - this.splicedIcon.on("pointerover", () => (this.scene as BattleScene).ui.showTooltip(null, `${this.pokemon.species.getName(this.pokemon.formIndex)}/${this.pokemon.fusionSpecies.getName(this.pokemon.fusionFormIndex)}`, true)); + this.splicedIcon.on("pointerover", () => (this.scene as BattleScene).ui.showTooltip("", `${this.pokemon?.species.getName(this.pokemon.formIndex)}/${this.pokemon?.fusionSpecies?.getName(this.pokemon?.fusionFormIndex)}`, true)); this.splicedIcon.on("pointerout", () => (this.scene as BattleScene).ui.hideTooltip()); } @@ -338,7 +337,7 @@ export default class SummaryUiHandler extends UiHandler { const candyCropY = 16 - (16 * (currentFriendship / friendshipCap)); if (this.candyShadow.visible) { - this.candyShadow.on("pointerover", () => (this.scene as BattleScene).ui.showTooltip(null, `${currentFriendship}/${friendshipCap}`, true)); + this.candyShadow.on("pointerover", () => (this.scene as BattleScene).ui.showTooltip("", `${currentFriendship}/${friendshipCap}`, true)); this.candyShadow.on("pointerout", () => (this.scene as BattleScene).ui.hideTooltip()); } @@ -357,7 +356,7 @@ export default class SummaryUiHandler extends UiHandler { const shinyDescriptor = doubleShiny || baseVariant ? `${baseVariant === 2 ? i18next.t("common:epicShiny") : baseVariant === 1 ? i18next.t("common:rareShiny") : i18next.t("common:commonShiny")}${doubleShiny ? `/${this.pokemon.fusionVariant === 2 ? i18next.t("common:epicShiny") : this.pokemon.fusionVariant === 1 ? i18next.t("common:rareShiny") : i18next.t("common:commonShiny")}` : ""}` : ""; - this.shinyIcon.on("pointerover", () => (this.scene as BattleScene).ui.showTooltip(null, `${i18next.t("common:shinyOnHover")}${shinyDescriptor ? ` (${shinyDescriptor})` : ""}`, true)); + this.shinyIcon.on("pointerover", () => (this.scene as BattleScene).ui.showTooltip("", `${i18next.t("common:shinyOnHover")}${shinyDescriptor ? ` (${shinyDescriptor})` : ""}`, true)); this.shinyIcon.on("pointerout", () => (this.scene as BattleScene).ui.hideTooltip()); } @@ -416,16 +415,16 @@ export default class SummaryUiHandler extends UiHandler { if (this.moveSelect) { if (button === Button.ACTION) { - if (this.moveCursor < this.pokemon.moveset.length) { + if (this.pokemon && this.moveCursor < this.pokemon.moveset.length) { if (this.summaryUiMode === SummaryUiMode.LEARN_MOVE) { - this.moveSelectFunction(this.moveCursor); + this.moveSelectFunction && this.moveSelectFunction(this.moveCursor); } else { if (this.selectedMoveIndex === -1) { this.selectedMoveIndex = this.moveCursor; this.setCursor(this.moveCursor); } else { if (this.selectedMoveIndex !== this.moveCursor) { - const tempMove = this.pokemon.moveset[this.selectedMoveIndex]; + const tempMove = this.pokemon?.moveset[this.selectedMoveIndex]; this.pokemon.moveset[this.selectedMoveIndex] = this.pokemon.moveset[this.moveCursor]; this.pokemon.moveset[this.moveCursor] = tempMove; @@ -483,15 +482,15 @@ export default class SummaryUiHandler extends UiHandler { if (this.cursor === Page.MOVES) { this.showMoveSelect(); success = true; - } else if (this.cursor === Page.PROFILE && this.pokemon.hasPassive()) { + } else if (this.cursor === Page.PROFILE && this.pokemon?.hasPassive()) { // if we're on the PROFILE page and this pokemon has a passive unlocked.. // Since abilities are displayed by default, all we need to do is toggle visibility on all elements to show passives - this.abilityContainer.nameText.setVisible(!this.abilityContainer.descriptionText.visible); - this.abilityContainer.descriptionText.setVisible(!this.abilityContainer.descriptionText.visible); + this.abilityContainer.nameText?.setVisible(!this.abilityContainer.descriptionText?.visible); + this.abilityContainer.descriptionText?.setVisible(!this.abilityContainer.descriptionText.visible); this.abilityContainer.labelImage.setVisible(!this.abilityContainer.labelImage.visible); - this.passiveContainer.nameText.setVisible(!this.passiveContainer.descriptionText.visible); - this.passiveContainer.descriptionText.setVisible(!this.passiveContainer.descriptionText.visible); + this.passiveContainer.nameText?.setVisible(!this.passiveContainer.descriptionText?.visible); + this.passiveContainer.descriptionText?.setVisible(!this.passiveContainer.descriptionText.visible); this.passiveContainer.labelImage.setVisible(!this.passiveContainer.labelImage.visible); } } else if (button === Button.CANCEL) { @@ -523,7 +522,7 @@ export default class SummaryUiHandler extends UiHandler { } const isDown = button === Button.DOWN; const party = this.scene.getParty(); - const partyMemberIndex = party.indexOf(this.pokemon); + const partyMemberIndex = this.pokemon ? party.indexOf(this.pokemon) : -1; if ((isDown && partyMemberIndex < party.length - 1) || (!isDown && partyMemberIndex)) { const page = this.cursor; this.clear(); @@ -609,7 +608,7 @@ export default class SummaryUiHandler extends UiHandler { loop: true, delay: Utils.fixedInt(600), callback: () => { - this.moveCursorObj.setVisible(false); + this.moveCursorObj?.setVisible(false); this.scene.time.delayedCall(Utils.fixedInt(100), () => { if (!this.moveCursorObj) { return; @@ -727,16 +726,16 @@ export default class SummaryUiHandler extends UiHandler { return typeIcon; }; - const types = this.pokemon.getTypes(false, false, true); + const types = this.pokemon?.getTypes(false, false, true)!; // TODO: is this bang correct? profileContainer.add(getTypeIcon(0, types[0])); if (types.length > 1) { profileContainer.add(getTypeIcon(1, types[1])); } - if (this.pokemon.isTerastallized()) { + if (this.pokemon?.isTerastallized()) { profileContainer.add(getTypeIcon(types.length, this.pokemon.getTeraType(), true)); } - if (this.pokemon.getLuck()) { + if (this.pokemon?.getLuck()) { const luckLabelText = addTextObject(this.scene, 141, 28, i18next.t("common:luckIndicator"), TextStyle.SUMMARY_ALT); luckLabelText.setOrigin(0, 0); profileContainer.add(luckLabelText); @@ -749,13 +748,13 @@ export default class SummaryUiHandler extends UiHandler { this.abilityContainer = { labelImage: this.scene.add.image(0, 0, "summary_profile_ability"), - ability: this.pokemon.getAbility(true), + ability: this.pokemon?.getAbility(true)!, // TODO: is this bang correct? nameText: null, descriptionText: null}; const allAbilityInfo = [this.abilityContainer]; // Creates an array to iterate through // Only add to the array and set up displaying a passive if it's unlocked - if (this.pokemon.hasPassive()) { + if (this.pokemon?.hasPassive()) { this.passiveContainer = { labelImage: this.scene.add.image(0, 0, "summary_profile_passive"), ability: this.pokemon.getPassiveAbility(), @@ -777,11 +776,11 @@ export default class SummaryUiHandler extends UiHandler { abilityInfo.labelImage.setOrigin(0, 0); profileContainer.add(abilityInfo.labelImage); - abilityInfo.nameText = addTextObject(this.scene, 7, 66, abilityInfo.ability.name, TextStyle.SUMMARY_ALT); + abilityInfo.nameText = addTextObject(this.scene, 7, 66, abilityInfo.ability?.name!, TextStyle.SUMMARY_ALT); // TODO: is this bang correct? abilityInfo.nameText.setOrigin(0, 1); profileContainer.add(abilityInfo.nameText); - abilityInfo.descriptionText = addTextObject(this.scene, 7, 69, abilityInfo.ability.description, TextStyle.WINDOW_ALT, { wordWrap: { width: 1224 } }); + abilityInfo.descriptionText = addTextObject(this.scene, 7, 69, abilityInfo.ability?.description!, TextStyle.WINDOW_ALT, { wordWrap: { width: 1224 } }); // TODO: is this bang correct? abilityInfo.descriptionText.setOrigin(0, 0); profileContainer.add(abilityInfo.descriptionText); @@ -813,17 +812,17 @@ export default class SummaryUiHandler extends UiHandler { }); // Turn off visibility of passive info by default this.passiveContainer?.labelImage.setVisible(false); - this.passiveContainer?.nameText.setVisible(false); - this.passiveContainer?.descriptionText.setVisible(false); + this.passiveContainer?.nameText?.setVisible(false); + this.passiveContainer?.descriptionText?.setVisible(false); const closeFragment = getBBCodeFrag("", TextStyle.WINDOW_ALT); - const rawNature = Utils.toReadableString(Nature[this.pokemon.getNature()]); - const nature = `${getBBCodeFrag(Utils.toReadableString(getNatureName(this.pokemon.getNature())), TextStyle.SUMMARY_RED)}${closeFragment}`; + const rawNature = Utils.toReadableString(Nature[this.pokemon?.getNature()!]); // TODO: is this bang correct? + const nature = `${getBBCodeFrag(Utils.toReadableString(getNatureName(this.pokemon?.getNature()!)), TextStyle.SUMMARY_RED)}${closeFragment}`; // TODO: is this bang correct? const memoString = i18next.t("pokemonSummary:memoString", { - metFragment: i18next.t(`pokemonSummary:metFragment.${this.pokemon.metBiome === -1? "apparently": "normal"}`, { - biome: `${getBBCodeFrag(getBiomeName(this.pokemon.metBiome), TextStyle.SUMMARY_RED)}${closeFragment}`, - level: `${getBBCodeFrag(this.pokemon.metLevel.toString(), TextStyle.SUMMARY_RED)}${closeFragment}`, + metFragment: i18next.t(`pokemonSummary:metFragment.${this.pokemon?.metBiome === -1? "apparently": "normal"}`, { + biome: `${getBBCodeFrag(getBiomeName(this.pokemon?.metBiome!), TextStyle.SUMMARY_RED)}${closeFragment}`, // TODO: is this bang correct? + level: `${getBBCodeFrag(this.pokemon?.metLevel.toString()!, TextStyle.SUMMARY_RED)}${closeFragment}`, // TODO: is this bang correct? }), natureFragment: i18next.exists(`pokemonSummary:natureFragment.${rawNature}`) ? @@ -831,7 +830,7 @@ export default class SummaryUiHandler extends UiHandler { nature, }); - const memoText = addBBCodeTextObject(this.scene, 7, 113, memoString, TextStyle.WINDOW_ALT); + const memoText = addBBCodeTextObject(this.scene, 7, 113, String(memoString), TextStyle.WINDOW_ALT); memoText.setOrigin(0, 0); profileContainer.add(memoText); break; @@ -846,15 +845,15 @@ export default class SummaryUiHandler extends UiHandler { const rowIndex = s % 3; const colIndex = Math.floor(s / 3); - const natureStatMultiplier = getNatureStatMultiplier(this.pokemon.getNature(), s); + const natureStatMultiplier = getNatureStatMultiplier(this.pokemon?.getNature()!, s); // TODO: is this bang correct? const statLabel = addTextObject(this.scene, 27 + 115 * colIndex + (colIndex === 1 ? 5 : 0), 56 + 16 * rowIndex, statName, natureStatMultiplier === 1 ? TextStyle.SUMMARY : natureStatMultiplier > 1 ? TextStyle.SUMMARY_PINK : TextStyle.SUMMARY_BLUE); statLabel.setOrigin(0.5, 0); statsContainer.add(statLabel); const statValueText = stat !== Stat.HP - ? Utils.formatStat(this.pokemon.stats[s]) - : `${Utils.formatStat(this.pokemon.hp, true)}/${Utils.formatStat(this.pokemon.getMaxHp(), true)}`; + ? Utils.formatStat(this.pokemon?.stats[s]!) // TODO: is this bang correct? + : `${Utils.formatStat(this.pokemon?.hp!, true)}/${Utils.formatStat(this.pokemon?.getMaxHp()!, true)}`; // TODO: are those bangs correct? const statValue = addTextObject(this.scene, 120 + 88 * colIndex, 56 + 16 * rowIndex, statValueText, TextStyle.WINDOW_ALT); statValue.setOrigin(1, 0); @@ -862,7 +861,7 @@ export default class SummaryUiHandler extends UiHandler { }); const itemModifiers = (this.scene.findModifiers(m => m instanceof PokemonHeldItemModifier - && m.pokemonId === this.pokemon.id, this.playerParty) as PokemonHeldItemModifier[]) + && m.pokemonId === this.pokemon?.id, this.playerParty) as PokemonHeldItemModifier[]) .sort(modifierSortFunc); itemModifiers.forEach((item, i) => { @@ -876,8 +875,12 @@ export default class SummaryUiHandler extends UiHandler { icon.on("pointerout", () => (this.scene as BattleScene).ui.hideTooltip()); }); - const relLvExp = getLevelRelExp(this.pokemon.level + 1, this.pokemon.species.growthRate); - const expRatio = this.pokemon.level < this.scene.getMaxExpLevel() ? this.pokemon.levelExp / relLvExp : 0; + const pkmLvl = this.pokemon?.level!; // TODO: is this bang correct? + const pkmLvlExp = this.pokemon?.levelExp!; // TODO: is this bang correct? + const pkmExp = this.pokemon?.exp!; // TODO: is this bang correct? + const pkmSpeciesGrowthRate = this.pokemon?.species.growthRate!; // TODO: is this bang correct? + const relLvExp = getLevelRelExp(pkmLvl + 1, pkmSpeciesGrowthRate); + const expRatio = pkmLvl < this.scene.getMaxExpLevel() ? pkmLvlExp / relLvExp : 0; const expLabel = addTextObject(this.scene, 6, 112, i18next.t("pokemonSummary:expPoints"), TextStyle.SUMMARY); expLabel.setOrigin(0, 0); @@ -887,12 +890,12 @@ export default class SummaryUiHandler extends UiHandler { nextLvExpLabel.setOrigin(0, 0); statsContainer.add(nextLvExpLabel); - const expText = addTextObject(this.scene, 208, 112, this.pokemon.exp.toString(), TextStyle.WINDOW_ALT); + const expText = addTextObject(this.scene, 208, 112, pkmExp.toString(), TextStyle.WINDOW_ALT); expText.setOrigin(1, 0); statsContainer.add(expText); - const nextLvExp = this.pokemon.level < this.scene.getMaxExpLevel() - ? getLevelTotalExp(this.pokemon.level + 1, this.pokemon.species.growthRate) - this.pokemon.exp + const nextLvExp = pkmLvl < this.scene.getMaxExpLevel() + ? getLevelTotalExp(pkmLvl + 1, pkmSpeciesGrowthRate) - pkmExp : 0; const nextLvExpText = addTextObject(this.scene, 208, 128, nextLvExp.toString(), TextStyle.WINDOW_ALT); nextLvExpText.setOrigin(1, 0); @@ -924,14 +927,14 @@ export default class SummaryUiHandler extends UiHandler { extraRowOverlay.setOrigin(0, 1); this.extraMoveRowContainer.add(extraRowOverlay); - const extraRowText = addTextObject(this.scene, 35, 0, this.summaryUiMode === SummaryUiMode.LEARN_MOVE ? this.newMove.name : i18next.t("pokemonSummary:cancel"), + const extraRowText = addTextObject(this.scene, 35, 0, this.summaryUiMode === SummaryUiMode.LEARN_MOVE && this.newMove ? this.newMove.name : i18next.t("pokemonSummary:cancel"), this.summaryUiMode === SummaryUiMode.LEARN_MOVE ? TextStyle.SUMMARY_PINK : TextStyle.SUMMARY); extraRowText.setOrigin(0, 1); this.extraMoveRowContainer.add(extraRowText); if (this.summaryUiMode === SummaryUiMode.LEARN_MOVE) { this.extraMoveRowContainer.setVisible(true); - const newMoveTypeIcon = this.scene.add.sprite(0, 0, `types${Utils.verifyLang(i18next.resolvedLanguage) ? `_${i18next.resolvedLanguage}` : ""}`, Type[this.newMove.type].toLowerCase()); + const newMoveTypeIcon = this.scene.add.sprite(0, 0, `types${Utils.verifyLang(i18next.resolvedLanguage) ? `_${i18next.resolvedLanguage}` : ""}`, Type[this.newMove?.type!].toLowerCase()); // TODO: is this bang correct? newMoveTypeIcon.setOrigin(0, 1); this.extraMoveRowContainer.add(newMoveTypeIcon); @@ -939,7 +942,7 @@ export default class SummaryUiHandler extends UiHandler { ppOverlay.setOrigin(0, 1); this.extraMoveRowContainer.add(ppOverlay); - const pp = Utils.padInt(this.newMove.pp, 2, " "); + const pp = Utils.padInt(this.newMove?.pp!, 2, " "); // TODO: is this bang correct? const ppText = addTextObject(this.scene, 173, 1, `${pp}/${pp}`, TextStyle.WINDOW); ppText.setOrigin(0, 1); this.extraMoveRowContainer.add(ppText); @@ -949,7 +952,7 @@ export default class SummaryUiHandler extends UiHandler { this.movesContainer.add(this.moveRowsContainer); for (let m = 0; m < 4; m++) { - const move = m < this.pokemon.moveset.length ? this.pokemon.moveset[m] : null; + const move: PokemonMove | null = this.pokemon && this.pokemon.moveset.length > m ? this.pokemon?.moveset[m] : null; const moveRowContainer = this.scene.add.container(0, 16 * m); this.moveRowsContainer.add(moveRowContainer); @@ -1020,13 +1023,13 @@ export default class SummaryUiHandler extends UiHandler { }); } - getSelectedMove(): Move { + getSelectedMove(): Move | null { if (this.cursor !== Page.MOVES) { return null; } - if (this.moveCursor < 4 && this.moveCursor < this.pokemon.moveset.length) { - return this.pokemon.moveset[this.moveCursor].getMove(); + if (this.moveCursor < 4 && this.pokemon && this.moveCursor < this.pokemon.moveset.length) { + return this.pokemon.moveset[this.moveCursor]!.getMove(); // TODO: is this bang correct? } else if (this.summaryUiMode === SummaryUiMode.LEARN_MOVE && this.moveCursor === 4) { return this.newMove; } @@ -1043,7 +1046,7 @@ export default class SummaryUiHandler extends UiHandler { hideMoveSelect() { if (this.summaryUiMode === SummaryUiMode.LEARN_MOVE) { - this.moveSelectFunction(4); + this.moveSelectFunction && this.moveSelectFunction(4); return; } diff --git a/src/ui/target-select-ui-handler.ts b/src/ui/target-select-ui-handler.ts index 48799473343..9a0922715e8 100644 --- a/src/ui/target-select-ui-handler.ts +++ b/src/ui/target-select-ui-handler.ts @@ -18,7 +18,7 @@ export default class TargetSelectUiHandler extends UiHandler { private isMultipleTargets: boolean = false; private targets: BattlerIndex[]; private targetsHighlighted: Pokemon[]; - private targetFlashTween: Phaser.Tweens.Tween; + private targetFlashTween: Phaser.Tweens.Tween | null; private targetBattleInfoMoveTween: Phaser.Tweens.Tween[] = []; constructor(scene: BattleScene) { @@ -68,12 +68,12 @@ export default class TargetSelectUiHandler extends UiHandler { switch (button) { case Button.UP: if (this.cursor < BattlerIndex.ENEMY && this.targets.findIndex(t => t >= BattlerIndex.ENEMY) > -1) { - success = this.setCursor(this.targets.find(t => t >= BattlerIndex.ENEMY)); + success = this.setCursor(this.targets.find(t => t >= BattlerIndex.ENEMY)!); // TODO: is the bang correct here? } break; case Button.DOWN: if (this.cursor >= BattlerIndex.ENEMY && this.targets.findIndex(t => t < BattlerIndex.ENEMY) > -1) { - success = this.setCursor(this.targets.find(t => t < BattlerIndex.ENEMY)); + success = this.setCursor(this.targets.find(t => t < BattlerIndex.ENEMY)!); // TODO: is the bang correct here? } break; case Button.LEFT: diff --git a/src/ui/text.ts b/src/ui/text.ts index ab4a26b6e98..8b76c2f5c62 100644 --- a/src/ui/text.ts +++ b/src/ui/text.ts @@ -185,7 +185,7 @@ export function getTextStyleOptions(style: TextStyle, uiTheme: UiTheme, extraSty if (extraStyleOptions) { if (extraStyleOptions.fontSize) { - const sizeRatio = parseInt(extraStyleOptions.fontSize.toString().slice(0, -2)) / parseInt(styleOptions.fontSize.toString().slice(0, -2)); + const sizeRatio = parseInt(extraStyleOptions.fontSize.toString().slice(0, -2)) / parseInt(styleOptions.fontSize?.toString().slice(0, -2) ?? "1"); shadowXpos *= sizeRatio; } styleOptions = Object.assign(styleOptions, extraStyleOptions); diff --git a/src/ui/time-of-day-widget.ts b/src/ui/time-of-day-widget.ts index e71839a84c5..5d2f184e679 100644 --- a/src/ui/time-of-day-widget.ts +++ b/src/ui/time-of-day-widget.ts @@ -147,7 +147,10 @@ export default class TimeOfDayWidget extends Phaser.GameObjects.Container { // Swaps all elements of the icon arrays by shifting the first element onto the end of the array // This ensures index[0] is always the new time of day icon and index[1] is always the current one this.timeOfDayIconPairs.forEach( - icons => icons.push(icons.shift())); + icons => { + const shifted = icons.shift(); + shifted && icons.push(shifted); + }); } /** diff --git a/src/ui/title-ui-handler.ts b/src/ui/title-ui-handler.ts index e2a704f7541..3c25ed34d61 100644 --- a/src/ui/title-ui-handler.ts +++ b/src/ui/title-ui-handler.ts @@ -14,7 +14,7 @@ export default class TitleUiHandler extends OptionSelectUiHandler { private splashMessageText: Phaser.GameObjects.Text; private eventDisplay: TimedEventDisplay; - private titleStatsTimer: NodeJS.Timeout; + private titleStatsTimer: NodeJS.Timeout | null; constructor(scene: BattleScene, mode: Mode = Mode.TITLE) { super(scene, mode); @@ -118,7 +118,7 @@ export default class TitleUiHandler extends OptionSelectUiHandler { this.eventDisplay?.clear(); - clearInterval(this.titleStatsTimer); + this.titleStatsTimer && clearInterval(this.titleStatsTimer); this.titleStatsTimer = null; this.scene.tweens.add({ diff --git a/src/ui/ui-theme.ts b/src/ui/ui-theme.ts index 58490e1c618..75725910b82 100644 --- a/src/ui/ui-theme.ts +++ b/src/ui/ui-theme.ts @@ -43,7 +43,7 @@ export function addWindow(scene: BattleScene, x: number, y: number, width: numbe const borderSize = scene.uiTheme ? 6 : 8; - const window = scene.add.nineslice(x, y, `window_${scene.windowType}${getWindowVariantSuffix(windowVariant)}`, null, width, height, borderSize, borderSize, borderSize, borderSize); + const window = scene.add.nineslice(x, y, `window_${scene.windowType}${getWindowVariantSuffix(windowVariant)}`, undefined, width, height, borderSize, borderSize, borderSize, borderSize); window.setOrigin(0, 0); if (mergeMaskLeft || mergeMaskTop || maskOffsetX || maskOffsetY) { diff --git a/src/ui/ui.ts b/src/ui/ui.ts index ec6e91fa526..8ea4270deb3 100644 --- a/src/ui/ui.ts +++ b/src/ui/ui.ts @@ -271,10 +271,10 @@ export default class UI extends Phaser.GameObjects.Container { return handler.processInput(button); } - showText(text: string, delay?: integer, callback?: Function, callbackDelay?: integer, prompt?: boolean, promptDelay?: integer): void { + showText(text: string, delay?: integer | null, callback?: Function | null, callbackDelay?: integer | null, prompt?: boolean | null, promptDelay?: integer | null): void { if (prompt && text.indexOf("$") > -1) { const messagePages = text.split(/\$/g).map(m => m.trim()); - let showMessageAndCallback = () => callback(); + let showMessageAndCallback = () => callback && callback(); for (let p = messagePages.length - 1; p >= 0; p--) { const originalFunc = showMessageAndCallback; showMessageAndCallback = () => this.showText(messagePages[p], null, originalFunc, null, true); @@ -290,18 +290,18 @@ export default class UI extends Phaser.GameObjects.Container { } } - showDialogue(text: string, name: string, delay: integer = 0, callback: Function, callbackDelay?: integer, promptDelay?: integer): void { + showDialogue(text: string, name: string | undefined, delay: integer | null = 0, callback: Function, callbackDelay?: integer, promptDelay?: integer): void { // First get the gender of the player (default male) (also used if UNSET) let playerGenderPrefix = "PGM"; if ((this.scene as BattleScene).gameData.gender === PlayerGender.FEMALE) { playerGenderPrefix = "PGF"; } // Add the prefix to the text - const localizationKey = playerGenderPrefix + text; + const localizationKey: string = playerGenderPrefix + text; // Get localized dialogue (if available) let hasi18n = false; - if (i18next.exists(localizationKey as ParseKeys) ) { + if (i18next.exists(localizationKey) ) { text = i18next.t(localizationKey as ParseKeys); hasi18n = true; @@ -341,7 +341,7 @@ export default class UI extends Phaser.GameObjects.Container { const key = playerGenderPrefix + text; - if (i18next.exists(key as ParseKeys) ) { + if (i18next.exists(key) ) { if ((this.scene as BattleScene).skipSeenDialogues && (this.scene as BattleScene).gameData.getSeenDialogues()[key] === true) { return true; } @@ -371,8 +371,8 @@ export default class UI extends Phaser.GameObjects.Container { update(): void { if (this.tooltipContainer.visible) { - const reverse = this.scene.game.input.mousePointer.x >= this.scene.game.canvas.width - this.tooltipBg.width * 6 - 12; - this.tooltipContainer.setPosition(!reverse ? this.scene.game.input.mousePointer.x / 6 + 2 : this.scene.game.input.mousePointer.x / 6 - this.tooltipBg.width - 2, this.scene.game.input.mousePointer.y / 6 + 2); + const reverse = this.scene.game.input.mousePointer && this.scene.game.input.mousePointer.x >= this.scene.game.canvas.width - this.tooltipBg.width * 6 - 12; + this.tooltipContainer.setPosition(!reverse ? this.scene.game.input.mousePointer!.x / 6 + 2 : this.scene.game.input.mousePointer!.x / 6 - this.tooltipBg.width - 2, this.scene.game.input.mousePointer!.y / 6 + 2); // TODO: are these bangs correct? } } @@ -507,7 +507,7 @@ export default class UI extends Phaser.GameObjects.Container { const doRevertMode = () => { this.getHandler().clear(); - this.mode = this.modeChain.pop(); + this.mode = this.modeChain.pop()!; // TODO: is this bang correct? const touchControls = document.getElementById("touchControls"); if (touchControls) { touchControls.dataset.uiMode = Mode[this.mode]; diff --git a/src/ui/unavailable-modal-ui-handler.ts b/src/ui/unavailable-modal-ui-handler.ts index c864801d9b4..873bef4ba79 100644 --- a/src/ui/unavailable-modal-ui-handler.ts +++ b/src/ui/unavailable-modal-ui-handler.ts @@ -7,7 +7,7 @@ import * as Utils from "#app/utils"; import i18next from "i18next"; export default class UnavailableModalUiHandler extends ModalUiHandler { - private reconnectTimer: NodeJS.Timeout; + private reconnectTimer: NodeJS.Timeout | null; private reconnectDuration: number; private reconnectCallback: () => void; diff --git a/src/ui/vouchers-ui-handler.ts b/src/ui/vouchers-ui-handler.ts index 370859bed54..169d851599b 100644 --- a/src/ui/vouchers-ui-handler.ts +++ b/src/ui/vouchers-ui-handler.ts @@ -22,10 +22,10 @@ export default class VouchersUiHandler extends MessageUiHandler { private itemsTotal: integer; private scrollCursor: integer; - private cursorObj: Phaser.GameObjects.NineSlice; + private cursorObj: Phaser.GameObjects.NineSlice | null; constructor(scene: BattleScene, mode?: Mode) { - super(scene, mode); + super(scene, mode!); // TODO: is this bang correct? this.itemsTotal = Object.keys(vouchers).length; this.scrollCursor = 0; @@ -192,7 +192,7 @@ export default class VouchersUiHandler extends MessageUiHandler { let updateVoucher = ret; if (!this.cursorObj) { - this.cursorObj = this.scene.add.nineslice(0, 0, "select_cursor_highlight", null, 16, 16, 1, 1, 1, 1); + this.cursorObj = this.scene.add.nineslice(0, 0, "select_cursor_highlight", undefined, 16, 16, 1, 1, 1, 1); this.cursorObj.setOrigin(0, 0); this.voucherIconsContainer.add(this.cursorObj); updateVoucher = true; diff --git a/src/utils.ts b/src/utils.ts index 6a816d5b84d..01a0b8faa42 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -116,7 +116,7 @@ export function randSeedWeightedItem(items: T[]): T { : Phaser.Math.RND.weightedPick(items); } -export function randSeedEasedWeightedItem(items: T[], easingFunction: string = "Sine.easeIn"): T { +export function randSeedEasedWeightedItem(items: T[], easingFunction: string = "Sine.easeIn"): T | null { if (!items.length) { return null; } @@ -246,16 +246,16 @@ export function formatStat(stat: integer, forHp: boolean = false): string { return formatLargeNumber(stat, forHp ? 100000 : 1000000); } -export function getEnumKeys(enumType): string[] { - return Object.values(enumType).filter(v => isNaN(parseInt(v.toString()))).map(v => v.toString()); +export function getEnumKeys(enumType: any): string[] { + return Object.values(enumType).filter(v => isNaN(parseInt(v!.toString()))).map(v => v!.toString()); } -export function getEnumValues(enumType): integer[] { - return Object.values(enumType).filter(v => !isNaN(parseInt(v.toString()))).map(v => parseInt(v.toString())); +export function getEnumValues(enumType: any): integer[] { + return Object.values(enumType).filter(v => !isNaN(parseInt(v!.toString()))).map(v => parseInt(v!.toString())); } -export function executeIf(condition: boolean, promiseFunc: () => Promise): Promise { - return condition ? promiseFunc() : new Promise(resolve => resolve(null)); +export function executeIf(condition: boolean, promiseFunc: () => Promise): Promise { + return condition ? promiseFunc() : new Promise(resolve => resolve(null)); } export const sessionIdKey = "pokerogue_sessionId"; @@ -432,7 +432,7 @@ export function deltaRgb(rgb1: integer[], rgb2: integer[]): integer { } export function rgbHexToRgba(hex: string) { - const color = hex.match(/^([\da-f]{2})([\da-f]{2})([\da-f]{2})$/i); + const color = hex.match(/^([\da-f]{2})([\da-f]{2})([\da-f]{2})$/i)!; // TODO: is this bang correct? return { r: parseInt(color[1], 16), g: parseInt(color[2], 16), diff --git a/tsconfig.json b/tsconfig.json index 546ea2a9d12..f8e019a1b8b 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -5,7 +5,7 @@ "moduleResolution": "bundler", "resolveJsonModule": true, "esModuleInterop": true, - "strictNullChecks": false, + "strictNullChecks": true, "sourceMap": false, "strict": false, "rootDir": "./src", From b0ab207f84e8d614c5314aa200e79b5307fe7fcd Mon Sep 17 00:00:00 2001 From: Chapybara-jp Date: Wed, 7 Aug 2024 18:58:28 +0200 Subject: [PATCH 013/282] [Localization(ja)] Translate egg.ts (#3405) * Translate egg.ts * Update egg.ts --- src/locales/ja/egg.ts | 46 +++++++++++++++++++++---------------------- 1 file changed, 23 insertions(+), 23 deletions(-) diff --git a/src/locales/ja/egg.ts b/src/locales/ja/egg.ts index 9f699ce0fdc..962abfb133a 100644 --- a/src/locales/ja/egg.ts +++ b/src/locales/ja/egg.ts @@ -1,28 +1,28 @@ import { SimpleTranslationEntries } from "#app/interfaces/locales"; export const egg: SimpleTranslationEntries = { - "egg": "Egg", - "greatTier": "Rare", - "ultraTier": "Epic", - "masterTier": "Legendary", - "defaultTier": "Common", - "hatchWavesMessageSoon": "Sounds can be heard coming from inside! It will hatch soon!", - "hatchWavesMessageClose": "It appears to move occasionally. It may be close to hatching.", - "hatchWavesMessageNotClose": "What will hatch from this? It doesn't seem close to hatching.", - "hatchWavesMessageLongTime": "It looks like this Egg will take a long time to hatch.", - "gachaTypeLegendary": "Legendary Rate Up", - "gachaTypeMove": "Rare Egg Move Rate Up", - "gachaTypeShiny": "Shiny Rate Up", - "selectMachine": "Select a machine.", - "notEnoughVouchers": "You don't have enough vouchers!", - "tooManyEggs": "You have too many eggs!", - "pull": "Pull", - "pulls": "Pulls", - "sameSpeciesEgg": "{{species}} will hatch from this egg!", - "hatchFromTheEgg": "{{pokemonName}} hatched from the egg!", - "eggMoveUnlock": "Egg Move unlocked: {{moveName}}", - "rareEggMoveUnlock": "Rare Egg Move unlocked: {{moveName}}", - "moveUPGacha": "Move UP!", - "shinyUPGacha": "Shiny UP!", + "egg": "タマゴ", + "greatTier": "レア", + "ultraTier": "超レア", + "masterTier": "伝説", + "defaultTier": "ふつう", + "hatchWavesMessageSoon": "なかから おとが きこえてくる! もうすぐ うまれそう!", + "hatchWavesMessageClose": "ときどき うごいている みたい。 うまれるまで もう ちょっとかな?", + "hatchWavesMessageNotClose": "なにが うまれてくるのかな? うまれるまで まだまだ じかんが かかりそう。", + "hatchWavesMessageLongTime": "この タマゴは うまれるまで かなり じかんが かかりそう。", + "gachaTypeLegendary": "伝説確率アップ", + "gachaTypeMove": "レアなタマゴわざ確率アップ", + "gachaTypeShiny": "色違い確率アップ", + "selectMachine": "ガチャマシンを選択", + "notEnoughVouchers": "タマゴクーポンが足りません!", + "tooManyEggs": "タマゴが一杯です!", + "pull": "回引く", + "pulls": "回引く", + "sameSpeciesEgg": "{{species}}は このタマゴから うまれる!", + "hatchFromTheEgg": "{{pokemonName}}は タマゴから うまれた!", + "eggMoveUnlock": "タマゴわざ {{moveName}}を おぼえた!", + "rareEggMoveUnlock": "レアなタマゴわざ {{moveName}}を おぼえた!!", + "moveUPGacha": "わざ UP!", + "shinyUPGacha": "色違い UP!", "legendaryUPGacha": "UP!", } as const; From 3698f13f49d2dc94c3e496c5cc1b2ae2b750b62e Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Wed, 7 Aug 2024 11:14:02 -0700 Subject: [PATCH 014/282] [Bug] Fix healing modifying the HP stat instead of the Pokemon's HP (#3406) --- src/data/move.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/move.ts b/src/data/move.ts index b5ca217a73e..1fe4af0db06 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -1650,7 +1650,7 @@ export class HitHealAttr extends MoveEffectAttr { super(true, MoveEffectTrigger.HIT); this.healRatio = healRatio!; // TODO: is this bang correct? - this.healStat = healStat!; // TODO: is this bang correct? + this.healStat = healStat ?? null; } /** * Heals the user the determined amount and possibly displays a message about regaining health. From f9d7b71fd683c4efaba965003489bd7fbf7e530b Mon Sep 17 00:00:00 2001 From: flx-sta <50131232+flx-sta@users.noreply.github.com> Date: Wed, 7 Aug 2024 11:31:57 -0700 Subject: [PATCH 015/282] [Refactor] allow `null` for ui mode constructor argument (#3407) --- src/ui/abstact-option-select-ui-handler.ts | 6 +++--- src/ui/achvs-ui-handler.ts | 4 ++-- src/ui/awaitable-ui-handler.ts | 2 +- src/ui/challenges-select-ui-handler.ts | 4 ++-- src/ui/form-modal-ui-handler.ts | 2 +- src/ui/game-stats-ui-handler.ts | 4 ++-- src/ui/loading-modal-ui-handler.ts | 2 +- src/ui/login-form-ui-handler.ts | 2 +- src/ui/menu-ui-handler.ts | 4 ++-- src/ui/message-ui-handler.ts | 2 +- src/ui/modal-ui-handler.ts | 4 ++-- src/ui/outdated-modal-ui-handler.ts | 2 +- src/ui/session-reload-modal-ui-handler.ts | 2 +- src/ui/settings/abstract-binding-ui-handler.ts | 4 ++-- src/ui/settings/abstract-control-settings-ui-handler.ts | 4 ++-- src/ui/settings/abstract-settings-ui-handler.ts | 4 ++-- src/ui/settings/gamepad-binding-ui-handler.ts | 2 +- src/ui/settings/keyboard-binding-ui-handler.ts | 3 ++- src/ui/settings/settings-audio-ui-handler.ts | 2 +- src/ui/settings/settings-display-ui-handler.ts | 2 +- src/ui/settings/settings-gamepad-ui-handler.ts | 2 +- src/ui/settings/settings-keyboard-ui-handler.ts | 2 +- src/ui/settings/settings-ui-handler.ts | 2 +- src/ui/ui-handler.ts | 4 ++-- src/ui/unavailable-modal-ui-handler.ts | 2 +- src/ui/vouchers-ui-handler.ts | 4 ++-- 26 files changed, 39 insertions(+), 38 deletions(-) diff --git a/src/ui/abstact-option-select-ui-handler.ts b/src/ui/abstact-option-select-ui-handler.ts index f0148509220..ae7f107efc0 100644 --- a/src/ui/abstact-option-select-ui-handler.ts +++ b/src/ui/abstact-option-select-ui-handler.ts @@ -46,8 +46,8 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler { private cursorObj: Phaser.GameObjects.Image | null; - constructor(scene: BattleScene, mode?: Mode) { - super(scene, mode!); // TODO: is this bang correct? + constructor(scene: BattleScene, mode: Mode | null) { + super(scene, mode); } abstract getWindowWidth(): integer; @@ -60,7 +60,7 @@ export default abstract class AbstractOptionSelectUiHandler extends UiHandler { const ui = this.getUi(); this.optionSelectContainer = this.scene.add.container((this.scene.game.canvas.width / 6) - 1, -48); - this.optionSelectContainer.setName(`option-select-${Mode[this.mode]}`); + this.optionSelectContainer.setName(`option-select-${this.mode ? Mode[this.mode] : "UNKNOWN"}`); this.optionSelectContainer.setVisible(false); ui.add(this.optionSelectContainer); diff --git a/src/ui/achvs-ui-handler.ts b/src/ui/achvs-ui-handler.ts index 304b5df8340..46259e52d0d 100644 --- a/src/ui/achvs-ui-handler.ts +++ b/src/ui/achvs-ui-handler.ts @@ -21,8 +21,8 @@ export default class AchvsUiHandler extends MessageUiHandler { private cursorObj: Phaser.GameObjects.NineSlice | null; - constructor(scene: BattleScene, mode?: Mode) { - super(scene, mode!); // TODO: is this bang correct? + constructor(scene: BattleScene, mode: Mode | null = null) { + super(scene, mode); } setup() { diff --git a/src/ui/awaitable-ui-handler.ts b/src/ui/awaitable-ui-handler.ts index 33be11ccc27..2052c6e2ade 100644 --- a/src/ui/awaitable-ui-handler.ts +++ b/src/ui/awaitable-ui-handler.ts @@ -8,7 +8,7 @@ export default abstract class AwaitableUiHandler extends UiHandler { protected onActionInput: Function | null; public tutorialActive: boolean = false; - constructor(scene: BattleScene, mode: Mode) { + constructor(scene: BattleScene, mode: Mode | null = null) { super(scene, mode); } diff --git a/src/ui/challenges-select-ui-handler.ts b/src/ui/challenges-select-ui-handler.ts index 1200b3f3b40..12211fa71cc 100644 --- a/src/ui/challenges-select-ui-handler.ts +++ b/src/ui/challenges-select-ui-handler.ts @@ -34,8 +34,8 @@ export default class GameChallengesUiHandler extends UiHandler { private startCursor: Phaser.GameObjects.NineSlice; - constructor(scene: BattleScene, mode?: Mode) { - super(scene, mode!); // TODO: is this bang correct? + constructor(scene: BattleScene, mode: Mode | null = null) { + super(scene, mode); } setup() { diff --git a/src/ui/form-modal-ui-handler.ts b/src/ui/form-modal-ui-handler.ts index a4539c2369f..4516e39675c 100644 --- a/src/ui/form-modal-ui-handler.ts +++ b/src/ui/form-modal-ui-handler.ts @@ -20,7 +20,7 @@ export abstract class FormModalUiHandler extends ModalUiHandler { protected submitAction: Function | null; protected tween: Phaser.Tweens.Tween; - constructor(scene: BattleScene, mode?: Mode) { + constructor(scene: BattleScene, mode: Mode | null = null) { super(scene, mode); this.editing = false; diff --git a/src/ui/game-stats-ui-handler.ts b/src/ui/game-stats-ui-handler.ts index 3d6d8081d4e..c28e5d851a2 100644 --- a/src/ui/game-stats-ui-handler.ts +++ b/src/ui/game-stats-ui-handler.ts @@ -218,8 +218,8 @@ export default class GameStatsUiHandler extends UiHandler { private statLabels: Phaser.GameObjects.Text[]; private statValues: Phaser.GameObjects.Text[]; - constructor(scene: BattleScene, mode?: Mode) { - super(scene, mode!); // TODO: is this bang correct? + constructor(scene: BattleScene, mode: Mode | null = null) { + super(scene, mode); this.statLabels = []; this.statValues = []; diff --git a/src/ui/loading-modal-ui-handler.ts b/src/ui/loading-modal-ui-handler.ts index c335b59de9f..d86f7afd3b6 100644 --- a/src/ui/loading-modal-ui-handler.ts +++ b/src/ui/loading-modal-ui-handler.ts @@ -5,7 +5,7 @@ import { addTextObject, TextStyle } from "./text"; import { Mode } from "./ui"; export default class LoadingModalUiHandler extends ModalUiHandler { - constructor(scene: BattleScene, mode?: Mode) { + constructor(scene: BattleScene, mode: Mode | null = null) { super(scene, mode); } diff --git a/src/ui/login-form-ui-handler.ts b/src/ui/login-form-ui-handler.ts index 450c583a26c..9a787b40b1b 100644 --- a/src/ui/login-form-ui-handler.ts +++ b/src/ui/login-form-ui-handler.ts @@ -13,7 +13,7 @@ export default class LoginFormUiHandler extends FormModalUiHandler { private externalPartyContainer: Phaser.GameObjects.Container; private externalPartyBg: Phaser.GameObjects.NineSlice; private externalPartyTitle: Phaser.GameObjects.Text; - constructor(scene: BattleScene, mode?: Mode) { + constructor(scene: BattleScene, mode: Mode | null = null) { super(scene, mode); } diff --git a/src/ui/menu-ui-handler.ts b/src/ui/menu-ui-handler.ts index 27db60aa5da..0c99953c62d 100644 --- a/src/ui/menu-ui-handler.ts +++ b/src/ui/menu-ui-handler.ts @@ -51,8 +51,8 @@ export default class MenuUiHandler extends MessageUiHandler { public bgmBar: BgmBar; - constructor(scene: BattleScene, mode?: Mode) { - super(scene, mode!); // TODO: is this bang correct? + constructor(scene: BattleScene, mode: Mode | null = null) { + super(scene, mode); this.excludedMenus = () => [ { condition: [Mode.COMMAND, Mode.TITLE].includes(mode ?? Mode.TITLE), options: [ MenuOptions.EGG_GACHA, MenuOptions.EGG_LIST] }, diff --git a/src/ui/message-ui-handler.ts b/src/ui/message-ui-handler.ts index c870ef13a27..a78887e1581 100644 --- a/src/ui/message-ui-handler.ts +++ b/src/ui/message-ui-handler.ts @@ -11,7 +11,7 @@ export default abstract class MessageUiHandler extends AwaitableUiHandler { public message: Phaser.GameObjects.Text; public prompt: Phaser.GameObjects.Sprite; - constructor(scene: BattleScene, mode: Mode) { + constructor(scene: BattleScene, mode: Mode | null = null) { super(scene, mode); this.pendingPrompt = false; diff --git a/src/ui/modal-ui-handler.ts b/src/ui/modal-ui-handler.ts index 5aac6ac194e..cecdacc1eb9 100644 --- a/src/ui/modal-ui-handler.ts +++ b/src/ui/modal-ui-handler.ts @@ -16,8 +16,8 @@ export abstract class ModalUiHandler extends UiHandler { protected buttonContainers: Phaser.GameObjects.Container[]; protected buttonBgs: Phaser.GameObjects.NineSlice[]; - constructor(scene: BattleScene, mode?: Mode) { - super(scene, mode!); // TODO: is this bang correct? + constructor(scene: BattleScene, mode: Mode | null = null) { + super(scene, mode); this.buttonContainers = []; this.buttonBgs = []; diff --git a/src/ui/outdated-modal-ui-handler.ts b/src/ui/outdated-modal-ui-handler.ts index 1e737cf638b..fc4b93f9b8a 100644 --- a/src/ui/outdated-modal-ui-handler.ts +++ b/src/ui/outdated-modal-ui-handler.ts @@ -4,7 +4,7 @@ import { addTextObject, TextStyle } from "./text"; import { Mode } from "./ui"; export default class OutdatedModalUiHandler extends ModalUiHandler { - constructor(scene: BattleScene, mode?: Mode) { + constructor(scene: BattleScene, mode: Mode | null = null) { super(scene, mode); } diff --git a/src/ui/session-reload-modal-ui-handler.ts b/src/ui/session-reload-modal-ui-handler.ts index 5313de58580..147634b19d2 100644 --- a/src/ui/session-reload-modal-ui-handler.ts +++ b/src/ui/session-reload-modal-ui-handler.ts @@ -4,7 +4,7 @@ import { addTextObject, TextStyle } from "./text"; import { Mode } from "./ui"; export default class SessionReloadModalUiHandler extends ModalUiHandler { - constructor(scene: BattleScene, mode?: Mode) { + constructor(scene: BattleScene, mode: Mode | null = null) { super(scene, mode); } diff --git a/src/ui/settings/abstract-binding-ui-handler.ts b/src/ui/settings/abstract-binding-ui-handler.ts index 3da555e2c96..5e6dd80c6d6 100644 --- a/src/ui/settings/abstract-binding-ui-handler.ts +++ b/src/ui/settings/abstract-binding-ui-handler.ts @@ -52,8 +52,8 @@ export default abstract class AbstractBindingUiHandler extends UiHandler { * @param scene - The BattleScene instance. * @param mode - The UI mode. */ - constructor(scene: BattleScene, mode?: Mode) { - super(scene, mode!); // TODO: is this bang correct? + constructor(scene: BattleScene, mode: Mode | null = null) { + super(scene, mode); } /** diff --git a/src/ui/settings/abstract-control-settings-ui-handler.ts b/src/ui/settings/abstract-control-settings-ui-handler.ts index 1f0c2b98fbd..f8dab1bf7cc 100644 --- a/src/ui/settings/abstract-control-settings-ui-handler.ts +++ b/src/ui/settings/abstract-control-settings-ui-handler.ts @@ -73,8 +73,8 @@ export default abstract class AbstractControlSettingsUiHandler extends UiHandler * @param scene - The BattleScene instance. * @param mode - The UI mode. */ - constructor(scene: BattleScene, mode?: Mode) { - super(scene, mode!); // TODO: is this bang correct? + constructor(scene: BattleScene, mode: Mode | null = null) { + super(scene, mode); this.rowsToDisplay = 8; } diff --git a/src/ui/settings/abstract-settings-ui-handler.ts b/src/ui/settings/abstract-settings-ui-handler.ts index 96d8e790c8a..6a074c83e90 100644 --- a/src/ui/settings/abstract-settings-ui-handler.ts +++ b/src/ui/settings/abstract-settings-ui-handler.ts @@ -40,8 +40,8 @@ export default class AbstractSettingsUiHandler extends UiHandler { protected settings: Array; protected localStorageKey: string; - constructor(scene: BattleScene, mode?: Mode) { - super(scene, mode!); // TODO: is this bang correct? + constructor(scene: BattleScene, mode: Mode | null = null) { + super(scene, mode); this.reloadRequired = false; this.rowsToDisplay = 8; diff --git a/src/ui/settings/gamepad-binding-ui-handler.ts b/src/ui/settings/gamepad-binding-ui-handler.ts index 16a8b9d2c30..4e5b4576b85 100644 --- a/src/ui/settings/gamepad-binding-ui-handler.ts +++ b/src/ui/settings/gamepad-binding-ui-handler.ts @@ -8,7 +8,7 @@ import {addTextObject, TextStyle} from "#app/ui/text"; export default class GamepadBindingUiHandler extends AbstractBindingUiHandler { - constructor(scene: BattleScene, mode?: Mode) { + constructor(scene: BattleScene, mode: Mode | null = null) { super(scene, mode); this.scene.input.gamepad?.on("down", this.gamepadButtonDown, this); } diff --git a/src/ui/settings/keyboard-binding-ui-handler.ts b/src/ui/settings/keyboard-binding-ui-handler.ts index 0bc74da86ce..043c5fba6a5 100644 --- a/src/ui/settings/keyboard-binding-ui-handler.ts +++ b/src/ui/settings/keyboard-binding-ui-handler.ts @@ -8,11 +8,12 @@ import {addTextObject, TextStyle} from "#app/ui/text"; export default class KeyboardBindingUiHandler extends AbstractBindingUiHandler { - constructor(scene: BattleScene, mode?: Mode) { + constructor(scene: BattleScene, mode: Mode | null = null) { super(scene, mode); // Listen to gamepad button down events to initiate binding. scene.input.keyboard?.on("keydown", this.onKeyDown, this); } + setup() { super.setup(); diff --git a/src/ui/settings/settings-audio-ui-handler.ts b/src/ui/settings/settings-audio-ui-handler.ts index 10313ed388c..e86c0d26546 100644 --- a/src/ui/settings/settings-audio-ui-handler.ts +++ b/src/ui/settings/settings-audio-ui-handler.ts @@ -11,7 +11,7 @@ export default class SettingsAudioUiHandler extends AbstractSettingsUiHandler { * @param scene - The BattleScene instance. * @param mode - The UI mode, optional. */ - constructor(scene: BattleScene, mode?: Mode) { + constructor(scene: BattleScene, mode: Mode | null = null) { super(scene, mode); this.title = "Audio"; this.settings = Setting.filter(s => s.type === SettingType.AUDIO); diff --git a/src/ui/settings/settings-display-ui-handler.ts b/src/ui/settings/settings-display-ui-handler.ts index 5193f76a5e0..3f0c9edd26f 100644 --- a/src/ui/settings/settings-display-ui-handler.ts +++ b/src/ui/settings/settings-display-ui-handler.ts @@ -11,7 +11,7 @@ export default class SettingsDisplayUiHandler extends AbstractSettingsUiHandler * @param scene - The BattleScene instance. * @param mode - The UI mode, optional. */ - constructor(scene: BattleScene, mode?: Mode) { + constructor(scene: BattleScene, mode: Mode | null = null) { super(scene, mode); this.title = "Display"; this.settings = Setting.filter(s => s.type === SettingType.DISPLAY); diff --git a/src/ui/settings/settings-gamepad-ui-handler.ts b/src/ui/settings/settings-gamepad-ui-handler.ts index f86e8088ec6..902d7eff34e 100644 --- a/src/ui/settings/settings-gamepad-ui-handler.ts +++ b/src/ui/settings/settings-gamepad-ui-handler.ts @@ -31,7 +31,7 @@ export default class SettingsGamepadUiHandler extends AbstractControlSettingsUiH * @param scene - The BattleScene instance. * @param mode - The UI mode, optional. */ - constructor(scene: BattleScene, mode?: Mode) { + constructor(scene: BattleScene, mode: Mode | null = null) { super(scene, mode); this.titleSelected = "Gamepad"; this.setting = SettingGamepad; diff --git a/src/ui/settings/settings-keyboard-ui-handler.ts b/src/ui/settings/settings-keyboard-ui-handler.ts index 3408359f33b..dc6de8c90dc 100644 --- a/src/ui/settings/settings-keyboard-ui-handler.ts +++ b/src/ui/settings/settings-keyboard-ui-handler.ts @@ -29,7 +29,7 @@ export default class SettingsKeyboardUiHandler extends AbstractControlSettingsUi * @param scene - The BattleScene instance. * @param mode - The UI mode, optional. */ - constructor(scene: BattleScene, mode?: Mode) { + constructor(scene: BattleScene, mode: Mode | null = null) { super(scene, mode); this.titleSelected = "Keyboard"; this.setting = SettingKeyboard; diff --git a/src/ui/settings/settings-ui-handler.ts b/src/ui/settings/settings-ui-handler.ts index a6332be1343..b4a40eae1a5 100644 --- a/src/ui/settings/settings-ui-handler.ts +++ b/src/ui/settings/settings-ui-handler.ts @@ -10,7 +10,7 @@ export default class SettingsUiHandler extends AbstractSettingsUiHandler { * @param scene - The BattleScene instance. * @param mode - The UI mode, optional. */ - constructor(scene: BattleScene, mode?: Mode) { + constructor(scene: BattleScene, mode: Mode | null = null) { super(scene, mode); this.title = "General"; this.settings = Setting.filter(s => s.type === SettingType.GENERAL); diff --git a/src/ui/ui-handler.ts b/src/ui/ui-handler.ts index 8336109847e..94625efaa75 100644 --- a/src/ui/ui-handler.ts +++ b/src/ui/ui-handler.ts @@ -8,7 +8,7 @@ import {Button} from "#enums/buttons"; */ export default abstract class UiHandler { protected scene: BattleScene; - protected mode: integer; + protected mode: integer | null; protected cursor: integer = 0; public active: boolean = false; @@ -16,7 +16,7 @@ export default abstract class UiHandler { * @param {BattleScene} scene The same scene as everything else. * @param {Mode} mode The mode of the UI element. These should be unique. */ - constructor(scene: BattleScene, mode: Mode) { + constructor(scene: BattleScene, mode: Mode | null = null) { this.scene = scene; this.mode = mode; } diff --git a/src/ui/unavailable-modal-ui-handler.ts b/src/ui/unavailable-modal-ui-handler.ts index 873bef4ba79..dab1a8c3be8 100644 --- a/src/ui/unavailable-modal-ui-handler.ts +++ b/src/ui/unavailable-modal-ui-handler.ts @@ -16,7 +16,7 @@ export default class UnavailableModalUiHandler extends ModalUiHandler { private readonly randVarianceTime = 1000 * 10; - constructor(scene: BattleScene, mode?: Mode) { + constructor(scene: BattleScene, mode: Mode | null = null) { super(scene, mode); this.reconnectDuration = this.minTime; } diff --git a/src/ui/vouchers-ui-handler.ts b/src/ui/vouchers-ui-handler.ts index 169d851599b..bb2dc2cd0be 100644 --- a/src/ui/vouchers-ui-handler.ts +++ b/src/ui/vouchers-ui-handler.ts @@ -24,8 +24,8 @@ export default class VouchersUiHandler extends MessageUiHandler { private cursorObj: Phaser.GameObjects.NineSlice | null; - constructor(scene: BattleScene, mode?: Mode) { - super(scene, mode!); // TODO: is this bang correct? + constructor(scene: BattleScene, mode: Mode | null = null) { + super(scene, mode); this.itemsTotal = Object.keys(vouchers).length; this.scrollCursor = 0; From 2b99f005dc9f711943312db87679ccaed2228486 Mon Sep 17 00:00:00 2001 From: innerthunder <168692175+innerthunder@users.noreply.github.com> Date: Wed, 7 Aug 2024 11:32:56 -0700 Subject: [PATCH 016/282] [Enhancement] Add Move Header phase and attributes (#2716) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Create Move Header phase and attributes * Fix move header persisting after run/ball * Add mid-turn sleep test * Fix status effect text in move header phase * Remove preemptive non-volatile status check * Process move headers in main loop of TurnStartPhase instead * Fix merge issues in Focus Punch test * Fix Focus Punch test + ESLint * Add i18n key for Focus Punch header message * Fix missing arg in i18n message * Add Focus Punch message translations (DE, FR, KO, PT-BR, ZH) Co-authored-by: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> Co-authored-by: Lugiad' Co-authored-by: Enoch Co-authored-by: José Ricardo Fleury Oliveira Co-authored-by: Sonny Ding <93831983+sonnyding1@users.noreply.github.com> * Update src/locales/it/move-trigger.ts Co-authored-by: Enoch * Use new test helper functions + snooz's cleanup suggestions * Add check for MoveHeaderPhase in switch test * Add key to JA locale * Add CA-ES locale key * Fix strict-null checks in focus punch test --------- Co-authored-by: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> Co-authored-by: Lugiad' Co-authored-by: Enoch Co-authored-by: José Ricardo Fleury Oliveira Co-authored-by: Sonny Ding <93831983+sonnyding1@users.noreply.github.com> --- src/data/move.ts | 38 +++++++++ src/locales/ca-ES/move-trigger.ts | 1 + src/locales/de/move-trigger.ts | 1 + src/locales/en/move-trigger.ts | 1 + src/locales/es/move-trigger.ts | 1 + src/locales/fr/move-trigger.ts | 1 + src/locales/it/move-trigger.ts | 1 + src/locales/ja/move-trigger.ts | 1 + src/locales/ko/move-trigger.ts | 1 + src/locales/pt_BR/move-trigger.ts | 1 + src/locales/zh_CN/move-trigger.ts | 1 + src/locales/zh_TW/move-trigger.ts | 1 + src/phases.ts | 31 ++++++- src/test/moves/focus_punch.test.ts | 132 +++++++++++++++++++++++++++++ 14 files changed, 211 insertions(+), 1 deletion(-) create mode 100644 src/test/moves/focus_punch.test.ts diff --git a/src/data/move.ts b/src/data/move.ts index 1fe4af0db06..2117d832d74 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -984,6 +984,43 @@ export class MoveEffectAttr extends MoveAttr { } } +/** + * Base class defining all Move Header attributes. + * Move Header effects apply at the beginning of a turn before any moves are resolved. + * They can be used to apply effects to the field (e.g. queueing a message) or to the user + * (e.g. adding a battler tag). + */ +export class MoveHeaderAttr extends MoveAttr { + constructor() { + super(true); + } +} + +/** + * Header attribute to queue a message at the beginning of a turn. + * @see {@link MoveHeaderAttr} + */ +export class MessageHeaderAttr extends MoveHeaderAttr { + private message: string | ((user: Pokemon, move: Move) => string); + + constructor(message: string | ((user: Pokemon, move: Move) => string)) { + super(); + this.message = message; + } + + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { + const message = typeof this.message === "string" + ? this.message + : this.message(user, move); + + if (message) { + user.scene.queueMessage(message); + return true; + } + return false; + } +} + export class PreMoveMessageAttr extends MoveAttr { private message: string | ((user: Pokemon, target: Pokemon, move: Move) => string); @@ -6837,6 +6874,7 @@ export function initMoves() { && (user.status.effect === StatusEffect.BURN || user.status.effect === StatusEffect.POISON || user.status.effect === StatusEffect.TOXIC || user.status.effect === StatusEffect.PARALYSIS) ? 2 : 1) .attr(BypassBurnDamageReductionAttr), new AttackMove(Moves.FOCUS_PUNCH, Type.FIGHTING, MoveCategory.PHYSICAL, 150, 100, 20, -1, -3, 3) + .attr(MessageHeaderAttr, (user, move) => i18next.t("moveTriggers:isTighteningFocus", {pokemonName: getPokemonNameWithAffix(user)})) .punchingMove() .ignoresVirtual() .condition((user, target, move) => !user.turnData.attacksReceived.find(r => r.damage)), diff --git a/src/locales/ca-ES/move-trigger.ts b/src/locales/ca-ES/move-trigger.ts index 7977cca29d4..b85f27228be 100644 --- a/src/locales/ca-ES/move-trigger.ts +++ b/src/locales/ca-ES/move-trigger.ts @@ -21,6 +21,7 @@ export const moveTriggers: SimpleTranslationEntries = { "isGlowing": "{{pokemonName}} became cloaked in a harsh light!", "bellChimed": "A bell chimed!", "foresawAnAttack": "{{pokemonName}} foresaw\nan attack!", + "isTighteningFocus": "{{pokemonName}} is\ntightening its focus!", "hidUnderwater": "{{pokemonName}} hid\nunderwater!", "soothingAromaWaftedThroughArea": "A soothing aroma wafted through the area!", "sprangUp": "{{pokemonName}} sprang up!", diff --git a/src/locales/de/move-trigger.ts b/src/locales/de/move-trigger.ts index e8f3298308a..53c9c847b38 100644 --- a/src/locales/de/move-trigger.ts +++ b/src/locales/de/move-trigger.ts @@ -21,6 +21,7 @@ export const moveTriggers: SimpleTranslationEntries = { "isGlowing": "{{pokemonName}} leuchtet grell!", "bellChimed": "Eine Glocke läutet!", "foresawAnAttack": "{{pokemonName}} sieht einen Angriff voraus!", + "isTighteningFocus": "{{pokemonName}} konzentriert sich!", "hidUnderwater": "{{pokemonName}} taucht unter!", "soothingAromaWaftedThroughArea": "Ein wohltuendes Aroma breitet sich aus!", "sprangUp": "{{pokemonName}} springt hoch in die Luft!", diff --git a/src/locales/en/move-trigger.ts b/src/locales/en/move-trigger.ts index 7977cca29d4..b85f27228be 100644 --- a/src/locales/en/move-trigger.ts +++ b/src/locales/en/move-trigger.ts @@ -21,6 +21,7 @@ export const moveTriggers: SimpleTranslationEntries = { "isGlowing": "{{pokemonName}} became cloaked in a harsh light!", "bellChimed": "A bell chimed!", "foresawAnAttack": "{{pokemonName}} foresaw\nan attack!", + "isTighteningFocus": "{{pokemonName}} is\ntightening its focus!", "hidUnderwater": "{{pokemonName}} hid\nunderwater!", "soothingAromaWaftedThroughArea": "A soothing aroma wafted through the area!", "sprangUp": "{{pokemonName}} sprang up!", diff --git a/src/locales/es/move-trigger.ts b/src/locales/es/move-trigger.ts index 9fef0194b87..a1d9f2e3185 100644 --- a/src/locales/es/move-trigger.ts +++ b/src/locales/es/move-trigger.ts @@ -21,6 +21,7 @@ export const moveTriggers: SimpleTranslationEntries = { "isGlowing": "{{pokemonName}} became cloaked in a harsh light!", "bellChimed": "A bell chimed!", "foresawAnAttack": "{{pokemonName}} foresaw\nan attack!", + "isTighteningFocus": "{{pokemonName}} is\ntightening its focus!", "hidUnderwater": "{{pokemonName}} hid\nunderwater!", "soothingAromaWaftedThroughArea": "A soothing aroma wafted through the area!", "sprangUp": "{{pokemonName}} sprang up!", diff --git a/src/locales/fr/move-trigger.ts b/src/locales/fr/move-trigger.ts index d611e19d61a..7f9f3a471c6 100644 --- a/src/locales/fr/move-trigger.ts +++ b/src/locales/fr/move-trigger.ts @@ -21,6 +21,7 @@ export const moveTriggers: SimpleTranslationEntries = { "isGlowing": "{{pokemonName}} est entouré\nd’une lumière intense !", "bellChimed": "Un grelot sonne !", "foresawAnAttack": "{{pokemonName}}\nprévoit une attaque !", + "isTighteningFocus": "{{pokemonName}} se concentre\nau maximum !", "hidUnderwater": "{{pokemonName}}\nse cache sous l’eau !", "soothingAromaWaftedThroughArea": "Une odeur apaisante flotte dans l’air !", "sprangUp": "{{pokemonName}}\nse propulse dans les airs !", diff --git a/src/locales/it/move-trigger.ts b/src/locales/it/move-trigger.ts index 98fd37defc4..badf2777d6f 100644 --- a/src/locales/it/move-trigger.ts +++ b/src/locales/it/move-trigger.ts @@ -21,6 +21,7 @@ export const moveTriggers: SimpleTranslationEntries = { "isGlowing": "{{pokemonName}} è avvolto da una luce intensa!", "bellChimed": " Si sente suonare una campanella!", "foresawAnAttack": "{{pokemonName}} presagisce\nl’attacco imminente!", + "isTighteningFocus": "{{pokemonName}} si concentra al massimo!", "hidUnderwater": "{{pokemonName}} sparisce\nsott’acqua!", "soothingAromaWaftedThroughArea": "Un gradevole profumo si diffonde nell’aria!", "sprangUp": "{{pokemonName}} spicca un gran balzo!", diff --git a/src/locales/ja/move-trigger.ts b/src/locales/ja/move-trigger.ts index c0d06b78bf9..7c794379f55 100644 --- a/src/locales/ja/move-trigger.ts +++ b/src/locales/ja/move-trigger.ts @@ -21,6 +21,7 @@ export const moveTriggers: SimpleTranslationEntries = { "isGlowing": "{{pokemonName}}を\nはげしいひかりが つつむ!", "bellChimed": "すずのおとが ひびきわたった!", "foresawAnAttack": "{{pokemonName}}は\nみらいに こうげきを よちした!", + "isTighteningFocus": "{{pokemonName}} is\ntightening its focus!", "hidUnderwater": "{{pokemonName}}は\nすいちゅうに みをひそめた!", "soothingAromaWaftedThroughArea": "ここちよい かおりが ひろがった!", "sprangUp": "{{pokemonName}}は\nたかく とびはねた!", diff --git a/src/locales/ko/move-trigger.ts b/src/locales/ko/move-trigger.ts index 364cb730889..4c32e5b5b9f 100644 --- a/src/locales/ko/move-trigger.ts +++ b/src/locales/ko/move-trigger.ts @@ -21,6 +21,7 @@ export const moveTriggers: SimpleTranslationEntries = { "isGlowing": "{{pokemonName}}를(을)\n강렬한 빛이 감쌌다!", "bellChimed": "방울소리가 울려 퍼졌다!", "foresawAnAttack": "{{pokemonName}}는(은)\n미래의 공격을 예지했다!", + "isTighteningFocus": "{{pokemonName}}[[는]]\n집중력을 높이고 있다!", "hidUnderwater": "{{pokemonName}}는(은)\n물속에 몸을 숨겼다!", "soothingAromaWaftedThroughArea": "기분 좋은 향기가 퍼졌다!", "sprangUp": "{{pokemonName}}는(은)\n높이 뛰어올랐다!", diff --git a/src/locales/pt_BR/move-trigger.ts b/src/locales/pt_BR/move-trigger.ts index 579638b00c3..a96cdb27953 100644 --- a/src/locales/pt_BR/move-trigger.ts +++ b/src/locales/pt_BR/move-trigger.ts @@ -21,6 +21,7 @@ export const moveTriggers: SimpleTranslationEntries = { "isGlowing": "{{pokemonName}} ficou envolto em uma luz forte!", "bellChimed": "Um sino tocou!", "foresawAnAttack": "{{pokemonName}} previu/num ataque!", + "isTighteningFocus": "{{pokemonName}} está\naumentando seu foco!", "hidUnderwater": "{{pokemonName}} se escondeu/nembaixo d'água!", "soothingAromaWaftedThroughArea": "Um aroma suave se espalhou pelo ambiente!", "sprangUp": "{{pokemonName}} se levantou!", diff --git a/src/locales/zh_CN/move-trigger.ts b/src/locales/zh_CN/move-trigger.ts index 23ded8cfb25..d46ef1e313e 100644 --- a/src/locales/zh_CN/move-trigger.ts +++ b/src/locales/zh_CN/move-trigger.ts @@ -21,6 +21,7 @@ export const moveTriggers: SimpleTranslationEntries = { "isGlowing": "强光包围了{{pokemonName}}\n!", "bellChimed": "铃声响彻四周!", "foresawAnAttack": "{{pokemonName}}\n预知了未来的攻击!", + "isTighteningFocus": "{{pokemonName}}正在集中注意力!", "hidUnderwater": "{{pokemonName}}\n潜入了水中!", "soothingAromaWaftedThroughArea": "怡人的香气扩散了开来!", "sprangUp": "{{pokemonName}}\n高高地跳了起来!", diff --git a/src/locales/zh_TW/move-trigger.ts b/src/locales/zh_TW/move-trigger.ts index ea355515f71..0831ef82637 100644 --- a/src/locales/zh_TW/move-trigger.ts +++ b/src/locales/zh_TW/move-trigger.ts @@ -21,6 +21,7 @@ export const moveTriggers: SimpleTranslationEntries = { "isGlowing": "強光包圍了\n{{pokemonName}}!", "bellChimed": "鈴聲響徹四周!", "foresawAnAttack": "{{pokemonName}}\n預知了未來的攻擊!", + "isTighteningFocus": "{{pokemonName}}正在集中注意力!", "hidUnderwater": "{{pokemonName}}\n潛入了水中!", "soothingAromaWaftedThroughArea": "怡人的香氣擴散了開來!", "sprangUp": "{{pokemonName}}\n高高地跳了起來!", diff --git a/src/phases.ts b/src/phases.ts index 7397974846f..ac6da0db148 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -1,7 +1,7 @@ import BattleScene, { bypassLogin } from "./battle-scene"; import { default as Pokemon, PlayerPokemon, EnemyPokemon, PokemonMove, MoveResult, DamageResult, FieldPosition, HitResult, TurnMove } from "./field/pokemon"; import * as Utils from "./utils"; -import { allMoves, applyMoveAttrs, BypassSleepAttr, ChargeAttr, applyFilteredMoveAttrs, HitsTagAttr, MissEffectAttr, MoveAttr, MoveEffectAttr, MoveFlags, MultiHitAttr, OverrideMoveEffectAttr, MoveTarget, getMoveTargets, MoveTargetSet, MoveEffectTrigger, CopyMoveAttr, AttackMove, SelfStatusMove, PreMoveMessageAttr, HealStatusEffectAttr, NoEffectAttr, BypassRedirectAttr, FixedDamageAttr, PostVictoryStatChangeAttr, ForceSwitchOutAttr, VariableTargetAttr, IncrementMovePriorityAttr } from "./data/move"; +import { allMoves, applyMoveAttrs, BypassSleepAttr, ChargeAttr, applyFilteredMoveAttrs, HitsTagAttr, MissEffectAttr, MoveAttr, MoveEffectAttr, MoveFlags, MultiHitAttr, OverrideMoveEffectAttr, MoveTarget, getMoveTargets, MoveTargetSet, MoveEffectTrigger, CopyMoveAttr, AttackMove, SelfStatusMove, PreMoveMessageAttr, HealStatusEffectAttr, NoEffectAttr, BypassRedirectAttr, FixedDamageAttr, PostVictoryStatChangeAttr, ForceSwitchOutAttr, VariableTargetAttr, IncrementMovePriorityAttr, MoveHeaderAttr } from "./data/move"; import { Mode } from "./ui/ui"; import { Command } from "./ui/command-ui-handler"; import { Stat } from "./data/pokemon-stat"; @@ -2353,6 +2353,9 @@ export class TurnStartPhase extends FieldPhase { continue; } const move = pokemon.getMoveset().find(m => m?.moveId === queuedMove.move) || new PokemonMove(queuedMove.move); + if (move.getMove().hasAttr(MoveHeaderAttr)) { + this.scene.unshiftPhase(new MoveHeaderPhase(this.scene, pokemon, move)); + } if (pokemon.isPlayer()) { if (turnCommand.cursor === -1) { this.scene.pushPhase(new MovePhase(this.scene, pokemon, turnCommand.targets || turnCommand.move!.targets, move));//TODO: is the bang correct here? @@ -2597,6 +2600,32 @@ export class CommonAnimPhase extends PokemonPhase { } } +export class MoveHeaderPhase extends BattlePhase { + public pokemon: Pokemon; + public move: PokemonMove; + + constructor(scene: BattleScene, pokemon: Pokemon, move: PokemonMove) { + super(scene); + + this.pokemon = pokemon; + this.move = move; + } + + canMove(): boolean { + return this.pokemon.isActive(true) && this.move.isUsable(this.pokemon); + } + + start() { + super.start(); + + if (this.canMove()) { + applyMoveAttrs(MoveHeaderAttr, this.pokemon, null, this.move.getMove()).then(() => this.end()); + } else { + this.end(); + } + } +} + export class MovePhase extends BattlePhase { public pokemon: Pokemon; public move: PokemonMove; diff --git a/src/test/moves/focus_punch.test.ts b/src/test/moves/focus_punch.test.ts new file mode 100644 index 00000000000..f5cf85ffae0 --- /dev/null +++ b/src/test/moves/focus_punch.test.ts @@ -0,0 +1,132 @@ +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import GameManager from "#test/utils/gameManager"; +import { Species } from "#enums/species"; +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { BerryPhase, MessagePhase, MoveHeaderPhase, SwitchSummonPhase, TurnStartPhase } from "#app/phases"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; + +const TIMEOUT = 20 * 1000; + +describe("Moves - Focus Punch", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .battleType("single") + .ability(Abilities.UNNERVE) + .moveset([Moves.FOCUS_PUNCH]) + .enemySpecies(Species.GROUDON) + .enemyAbility(Abilities.INSOMNIA) + .enemyMoveset(SPLASH_ONLY) + .startingLevel(100) + .enemyLevel(100); + }); + + it( + "should deal damage at the end of turn if uninterrupted", + async () => { + await game.startBattle([Species.CHARIZARD]); + + const leadPokemon = game.scene.getPlayerPokemon()!; + const enemyPokemon = game.scene.getEnemyPokemon()!; + + const enemyStartingHp = enemyPokemon.hp; + + game.doAttack(getMovePosition(game.scene, 0, Moves.FOCUS_PUNCH)); + + await game.phaseInterceptor.to(MessagePhase); + + expect(enemyPokemon.hp).toBe(enemyStartingHp); + expect(leadPokemon.getMoveHistory().length).toBe(0); + + await game.phaseInterceptor.to(BerryPhase, false); + + expect(enemyPokemon.hp).toBeLessThan(enemyStartingHp); + expect(leadPokemon.getMoveHistory().length).toBe(1); + expect(leadPokemon.turnData.damageDealt).toBe(enemyStartingHp - enemyPokemon.hp); + }, TIMEOUT + ); + + it( + "should fail if the user is hit", + async () => { + game.override.enemyMoveset(Array(4).fill(Moves.TACKLE)); + + await game.startBattle([Species.CHARIZARD]); + + const leadPokemon = game.scene.getPlayerPokemon()!; + const enemyPokemon = game.scene.getEnemyPokemon()!; + + const enemyStartingHp = enemyPokemon.hp; + + game.doAttack(getMovePosition(game.scene, 0, Moves.FOCUS_PUNCH)); + + await game.phaseInterceptor.to(MessagePhase); + + expect(enemyPokemon.hp).toBe(enemyStartingHp); + expect(leadPokemon.getMoveHistory().length).toBe(0); + + await game.phaseInterceptor.to(BerryPhase, false); + + expect(enemyPokemon.hp).toBe(enemyStartingHp); + expect(leadPokemon.getMoveHistory().length).toBe(1); + expect(leadPokemon.turnData.damageDealt).toBe(0); + }, TIMEOUT + ); + + it( + "should be cancelled if the user falls asleep mid-turn", + async () => { + game.override.enemyMoveset(Array(4).fill(Moves.SPORE)); + + await game.startBattle([Species.CHARIZARD]); + + const leadPokemon = game.scene.getPlayerPokemon()!; + const enemyPokemon = game.scene.getEnemyPokemon()!; + + game.doAttack(getMovePosition(game.scene, 0, Moves.FOCUS_PUNCH)); + + await game.phaseInterceptor.to(MessagePhase); // Header message + + expect(leadPokemon.getMoveHistory().length).toBe(0); + + await game.phaseInterceptor.to(BerryPhase, false); + + expect(leadPokemon.getMoveHistory().length).toBe(1); + expect(enemyPokemon.hp).toBe(enemyPokemon.getMaxHp()); + }, TIMEOUT + ); + + it( + "should not queue its pre-move message before an enemy switches", + async () => { + /** Guarantee a Trainer battle with multiple enemy Pokemon */ + game.override.startingWave(25); + + await game.startBattle([Species.CHARIZARD]); + + game.forceOpponentToSwitch(); + game.doAttack(getMovePosition(game.scene, 0, Moves.FOCUS_PUNCH)); + + await game.phaseInterceptor.to(TurnStartPhase); + + expect(game.scene.getCurrentPhase() instanceof SwitchSummonPhase).toBeTruthy(); + expect(game.scene.phaseQueue.find(phase => phase instanceof MoveHeaderPhase)).toBeDefined(); + }, TIMEOUT + ); +}); From 78a829579f1c4b0e3236f70e4e5d9d6636b0b3ab Mon Sep 17 00:00:00 2001 From: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> Date: Wed, 7 Aug 2024 20:53:51 +0200 Subject: [PATCH 017/282] [Localization] Fixing the German stats page (#3410) * Readding the german stats changes * Shadow --- src/ui/text.ts | 29 ++++++++++++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/src/ui/text.ts b/src/ui/text.ts index 8b76c2f5c62..43dca9efc45 100644 --- a/src/ui/text.ts +++ b/src/ui/text.ts @@ -107,6 +107,7 @@ export function addTextInputObject(scene: Phaser.Scene, x: number, y: number, wi } export function getTextStyleOptions(style: TextStyle, uiTheme: UiTheme, extraStyleOptions?: Phaser.Types.GameObjects.Text.TextStyle): TextStyleOptions { + const lang = i18next.resolvedLanguage; let shadowXpos = 4; let shadowYpos = 5; let scale = 0.1666666667; @@ -137,11 +138,37 @@ export function getTextStyleOptions(style: TextStyle, uiTheme: UiTheme, extraSty case TextStyle.SUMMARY_GREEN: case TextStyle.WINDOW: case TextStyle.WINDOW_ALT: - case TextStyle.STATS_VALUE: shadowXpos = 3; shadowYpos = 3; break; case TextStyle.STATS_LABEL: + let fontSizeLabel = "96px"; + switch (lang) { + case "de": + shadowXpos = 3; + shadowYpos = 3; + fontSizeLabel = "80px"; + break; + default: + fontSizeLabel = "96px"; + break; + } + styleOptions.fontSize = fontSizeLabel; + break; + case TextStyle.STATS_VALUE: + shadowXpos = 3; + shadowYpos = 3; + let fontSizeValue = "96px"; + switch (lang) { + case "de": + fontSizeValue = "80px"; + break; + default: + fontSizeValue = "96px"; + break; + } + styleOptions.fontSize = fontSizeValue; + break; case TextStyle.MESSAGE: case TextStyle.SETTINGS_LABEL: case TextStyle.SETTINGS_LOCKED: From 597d8f566ad866f183471e5de26855d2a5937b56 Mon Sep 17 00:00:00 2001 From: Chapybara-jp Date: Wed, 7 Aug 2024 21:33:36 +0200 Subject: [PATCH 018/282] [Localization(ja)] Update biome.ts (#3413) --- src/locales/ja/biome.ts | 70 ++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/src/locales/ja/biome.ts b/src/locales/ja/biome.ts index d3f34c021d4..4551e779c74 100644 --- a/src/locales/ja/biome.ts +++ b/src/locales/ja/biome.ts @@ -1,40 +1,40 @@ import { SimpleTranslationEntries } from "#app/interfaces/locales"; export const biome: SimpleTranslationEntries = { - "unknownLocation": "Somewhere you can\'t remember", - "TOWN": "Town", - "PLAINS": "Plains", - "GRASS": "Grassy Field", - "TALL_GRASS": "Tall Grass", - "METROPOLIS": "Metropolis", - "FOREST": "Forest", - "SEA": "Sea", - "SWAMP": "Swamp", - "BEACH": "Beach", - "LAKE": "Lake", - "SEABED": "Seabed", - "MOUNTAIN": "Mountain", - "BADLANDS": "Badlands", - "CAVE": "Cave", - "DESERT": "Desert", - "ICE_CAVE": "Ice Cave", - "MEADOW": "Meadow", - "POWER_PLANT": "Power Plant", - "VOLCANO": "Volcano", - "GRAVEYARD": "Graveyard", - "DOJO": "Dojo", - "FACTORY": "Factory", - "RUINS": "Ancient Ruins", - "WASTELAND": "Wasteland", - "ABYSS": "Abyss", - "SPACE": "Space", - "CONSTRUCTION_SITE": "Construction Site", - "JUNGLE": "Jungle", - "FAIRY_CAVE": "Fairy Cave", - "TEMPLE": "Temple", - "SLUM": "Slum", - "SNOWY_FOREST": "Snowy Forest", - "ISLAND": "Island", - "LABORATORY": "Laboratory", + "unknownLocation": "覚えていない場所", + "TOWN": "タウン", + "PLAINS": "平原", + "GRASS": "草原", + "TALL_GRASS": "長い草むら", + "METROPOLIS": "シティ", + "FOREST": "森", + "SEA": "海", + "SWAMP": "沼", + "BEACH": "海辺", + "LAKE": "湖", + "SEABED": "海底", + "MOUNTAIN": "山", + "BADLANDS": "悪地", + "CAVE": "洞窟", + "DESERT": "砂漠", + "ICE_CAVE": "氷の洞窟", + "MEADOW": "花畑", + "POWER_PLANT": "発電所", + "VOLCANO": "火山", + "GRAVEYARD": "墓場", + "DOJO": "道場", + "FACTORY": "工場", + "RUINS": "古の遺跡", + "WASTELAND": "荒地", + "ABYSS": "深淵", + "SPACE": "宇宙", + "CONSTRUCTION_SITE": "工事現場", + "JUNGLE": "ジャングル", + "FAIRY_CAVE": "フェアリーの洞窟", + "TEMPLE": "神殿", + "SLUM": "スラム", + "SNOWY_FOREST": "雪の森", + "ISLAND": "島", + "LABORATORY": "ラボ", "END": "???", } as const; From 94c1c923e48108b8a3fb1505d28f0cf2ad137c89 Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Wed, 7 Aug 2024 12:55:14 -0700 Subject: [PATCH 019/282] [Bug] Default 0.5 heal ratio in `HitHealAttr` (#3414) --- src/data/move.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/move.ts b/src/data/move.ts index 2117d832d74..827c3716d9b 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -1686,7 +1686,7 @@ export class HitHealAttr extends MoveEffectAttr { constructor(healRatio?: number | null, healStat?: Stat) { super(true, MoveEffectTrigger.HIT); - this.healRatio = healRatio!; // TODO: is this bang correct? + this.healRatio = healRatio ?? 0.5; this.healStat = healStat ?? null; } /** From 8783fd81c72e86982a38153ffe08a5a4a5e99b6c Mon Sep 17 00:00:00 2001 From: Frederico Santos Date: Wed, 7 Aug 2024 21:29:41 +0100 Subject: [PATCH 020/282] Revert egg additive/multiplicative change and change endless biome rotation for every 5 waves. (#3415) Co-authored-by: snoozbuster --- src/battle-scene.ts | 26 +++++--------------------- src/modifier/modifier.ts | 2 +- src/phases.ts | 4 +--- src/test/items/exp_booster.test.ts | 11 ++++++----- vite.config.ts | 3 ++- 5 files changed, 15 insertions(+), 31 deletions(-) diff --git a/src/battle-scene.ts b/src/battle-scene.ts index 4269edecfaf..c0b6e2ba91e 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -1115,27 +1115,11 @@ export default class BattleScene extends SceneBase { //this.pushPhase(new TrainerMessageTestPhase(this, TrainerType.RIVAL, TrainerType.RIVAL_2, TrainerType.RIVAL_3, TrainerType.RIVAL_4, TrainerType.RIVAL_5, TrainerType.RIVAL_6)); if (!waveIndex && lastBattle) { - let isNewBiome = !(lastBattle.waveIndex % 10) || ((this.gameMode.hasShortBiomes || this.gameMode.isDaily) && (lastBattle.waveIndex % 50) === 49); - if (!isNewBiome && this.gameMode.hasShortBiomes && (lastBattle.waveIndex % 10) < 9) { - let w = lastBattle.waveIndex - ((lastBattle.waveIndex % 10) - 1); - let biomeWaves = 1; - while (w < lastBattle.waveIndex) { - let wasNewBiome = false; - this.executeWithSeedOffset(() => { - wasNewBiome = !Utils.randSeedInt(6 - biomeWaves); - }, w << 4); - if (wasNewBiome) { - biomeWaves = 1; - } else { - biomeWaves++; - } - w++; - } - - this.executeWithSeedOffset(() => { - isNewBiome = !Utils.randSeedInt(6 - biomeWaves); - }, lastBattle.waveIndex << 4); - } + const isWaveIndexMultipleOfTen = !(lastBattle.waveIndex % 10); + const isEndlessOrDaily = this.gameMode.hasShortBiomes || this.gameMode.isDaily; + const isEndlessFifthWave = this.gameMode.hasShortBiomes && (lastBattle.waveIndex % 5) === 0; + const isWaveIndexMultipleOfFiftyMinusOne = (lastBattle.waveIndex % 50) === 49; + const isNewBiome = isWaveIndexMultipleOfTen || isEndlessFifthWave || (isEndlessOrDaily && isWaveIndexMultipleOfFiftyMinusOne); const resetArenaState = isNewBiome || this.currentBattle.battleType === BattleType.TRAINER || this.currentBattle.battleSpec === BattleSpec.FINAL_BOSS; this.getEnemyParty().forEach(enemyPokemon => enemyPokemon.destroy()); this.trySpreadPokerus(); diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index 6ff2d3c9718..c6871353a7d 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -1818,7 +1818,7 @@ export class PokemonExpBoosterModifier extends PokemonHeldItemModifier { } apply(args: any[]): boolean { - (args[1] as Utils.NumberHolder).value += (this.getStackCount() * this.boostMultiplier); + (args[1] as Utils.NumberHolder).value = Math.floor((args[1] as Utils.NumberHolder).value * (1 + (this.getStackCount() * this.boostMultiplier))); return true; } diff --git a/src/phases.ts b/src/phases.ts index ac6da0db148..39cbbd5ff8b 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -3988,9 +3988,7 @@ export class VictoryPhase extends PokemonPhase { expMultiplier = Overrides.XP_MULTIPLIER_OVERRIDE; } const pokemonExp = new Utils.NumberHolder(expValue * expMultiplier); - const modifierBonusExp = new Utils.NumberHolder(1); - this.scene.applyModifiers(PokemonExpBoosterModifier, true, partyMember, modifierBonusExp); - pokemonExp.value *= modifierBonusExp.value; + this.scene.applyModifiers(PokemonExpBoosterModifier, true, partyMember, pokemonExp); partyMemberExp.push(Math.floor(pokemonExp.value)); } diff --git a/src/test/items/exp_booster.test.ts b/src/test/items/exp_booster.test.ts index 3348304b2e7..2b700c92086 100644 --- a/src/test/items/exp_booster.test.ts +++ b/src/test/items/exp_booster.test.ts @@ -27,13 +27,14 @@ describe("EXP Modifier Items", () => { game.override.battleType("single"); }); - it("EXP booster items stack additively", async() => { - game.override.startingHeldItems([{name: "LUCKY_EGG"}, {name: "GOLDEN_EGG"}]); + it("EXP booster items stack multiplicatively", async() => { + game.override.startingHeldItems([{name: "LUCKY_EGG", count: 3}, {name: "GOLDEN_EGG"}]); await game.startBattle(); const partyMember = game.scene.getPlayerPokemon()!; - const modifierBonusExp = new Utils.NumberHolder(1); - partyMember.scene.applyModifiers(PokemonExpBoosterModifier, true, partyMember, modifierBonusExp); - expect(modifierBonusExp.value).toBe(2.4); + partyMember.exp = 100; + const expHolder = new Utils.NumberHolder(partyMember.exp); + partyMember.scene.applyModifiers(PokemonExpBoosterModifier, true, partyMember, expHolder); + expect(expHolder.value).toBe(440); }, 20000); }); diff --git a/vite.config.ts b/vite.config.ts index f5c95aa56bd..4bd013bff2e 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -20,7 +20,8 @@ export const defaultConfig = { } warn(warning); }, - } + }, + appType: "mpa", }; From 00d039c65b7380876170287ac7864353e338deae Mon Sep 17 00:00:00 2001 From: Mumble Date: Wed, 7 Aug 2024 16:56:05 -0700 Subject: [PATCH 021/282] [Enhancement] Achievements Page is now Scrollable (#3395) * Scrollable Achivements * Update src/ui/achvs-ui-handler.ts Co-authored-by: Adrian T. <68144167+torranx@users.noreply.github.com> * Removed debugging message * Removed redundant object.keys() * Changed constants to be within the class * No more need for mode! See PR #3407 * tRaIlINg SpAcEs NoT aLlOwEd * Added comments as requested. --------- Co-authored-by: Frutescens Co-authored-by: Adrian T. <68144167+torranx@users.noreply.github.com> --- src/ui/achvs-ui-handler.ts | 114 +++++++++++++++++++++++++++++-------- 1 file changed, 89 insertions(+), 25 deletions(-) diff --git a/src/ui/achvs-ui-handler.ts b/src/ui/achvs-ui-handler.ts index 46259e52d0d..ad707fb52e1 100644 --- a/src/ui/achvs-ui-handler.ts +++ b/src/ui/achvs-ui-handler.ts @@ -10,6 +10,9 @@ import { ParseKeys } from "i18next"; import { PlayerGender } from "#enums/player-gender"; export default class AchvsUiHandler extends MessageUiHandler { + private readonly ACHV_ROWS = 4; + private readonly ACHV_COLS = 17; + private achvsContainer: Phaser.GameObjects.Container; private achvIconsContainer: Phaser.GameObjects.Container; @@ -19,10 +22,16 @@ export default class AchvsUiHandler extends MessageUiHandler { private scoreText: Phaser.GameObjects.Text; private unlockText: Phaser.GameObjects.Text; + private achvsTotal: number; + private scrollCursor: number; + private cursorObj: Phaser.GameObjects.NineSlice | null; constructor(scene: BattleScene, mode: Mode | null = null) { super(scene, mode); + + this.achvsTotal = Object.keys(achvs).length; + this.scrollCursor = 0; } setup() { @@ -53,9 +62,9 @@ export default class AchvsUiHandler extends MessageUiHandler { this.achvIcons = []; - for (let a = 0; a < Object.keys(achvs).length; a++) { - const x = (a % 17) * 18; - const y = Math.floor(a / 17) * 18; + for (let a = 0; a < this.ACHV_ROWS * this.ACHV_COLS; a++) { + const x = (a % this.ACHV_COLS) * 18; + const y = Math.floor(a / this.ACHV_COLS) * 18; const icon = this.scene.add.sprite(x, y, "items", "unknown"); icon.setOrigin(0, 0); @@ -119,24 +128,11 @@ export default class AchvsUiHandler extends MessageUiHandler { show(args: any[]): boolean { super.show(args); - const achvUnlocks = this.scene.gameData.achvUnlocks; - - Object.values(achvs).forEach((achv: Achv, i: integer) => { - const icon = this.achvIcons[i]; - const unlocked = achvUnlocks.hasOwnProperty(achv.id); - const hidden = !unlocked && achv.secret && (!achv.parentId || !achvUnlocks.hasOwnProperty(achv.parentId)); - const tinted = !hidden && !unlocked; - - icon.setFrame(!hidden ? achv.iconImage : "unknown"); - if (tinted) { - icon.setTintFill(0); - } else { - icon.clearTint(); - } - }); + this.updateAchvIcons(); this.achvsContainer.setVisible(true); this.setCursor(0); + this.setScrollCursor(0); this.getUi().moveTo(this.achvsContainer, this.getUi().length - 1); @@ -173,24 +169,39 @@ export default class AchvsUiHandler extends MessageUiHandler { success = true; this.scene.ui.revertMode(); } else { + const rowIndex = Math.floor(this.cursor / this.ACHV_COLS); + const itemOffset = (this.scrollCursor * this.ACHV_COLS); switch (button) { case Button.UP: - if (this.cursor >= 17) { - success = this.setCursor(this.cursor - 17); + if (this.cursor < this.ACHV_COLS) { + if (this.scrollCursor) { + success = this.setScrollCursor(this.scrollCursor - 1); + } + } else { + success = this.setCursor(this.cursor - this.ACHV_COLS); } break; case Button.DOWN: - if (this.cursor + 17 < Object.keys(achvs).length) { - success = this.setCursor(this.cursor + 17); + const canMoveDown = (this.cursor + itemOffset) + this.ACHV_COLS < this.achvsTotal; + if (rowIndex >= this.ACHV_ROWS - 1) { + if (this.scrollCursor < Math.ceil(this.achvsTotal / this.ACHV_COLS) - this.ACHV_ROWS && canMoveDown) { + success = this.setScrollCursor(this.scrollCursor + 1); + } + } else if (canMoveDown) { + success = this.setCursor(this.cursor + this.ACHV_COLS); } break; case Button.LEFT: - if (this.cursor) { + if (!this.cursor && this.scrollCursor) { + success = this.setScrollCursor(this.scrollCursor - 1) && this.setCursor(this.cursor + (this.ACHV_COLS - 1)); + } else if (this.cursor) { success = this.setCursor(this.cursor - 1); } break; case Button.RIGHT: - if (this.cursor < Object.keys(achvs).length - 1) { + if (this.cursor + 1 === this.ACHV_ROWS * this.ACHV_COLS && this.scrollCursor < Math.ceil(this.achvsTotal / this.ACHV_COLS) - this.ACHV_ROWS) { + success = this.setScrollCursor(this.scrollCursor + 1) && this.setCursor(this.cursor - (this.ACHV_COLS - 1)); + } else if (this.cursor + itemOffset < this.achvsTotal - 1) { success = this.setCursor(this.cursor + 1); } break; @@ -219,12 +230,65 @@ export default class AchvsUiHandler extends MessageUiHandler { this.cursorObj.setPositionRelative(this.achvIcons[this.cursor], 0, 0); if (updateAchv) { - this.showAchv(achvs[Object.keys(achvs)[cursor]]); + this.showAchv(achvs[Object.keys(achvs)[cursor + this.scrollCursor * this.ACHV_COLS]]); } return ret; } + /** + * setScrollCursor(scrollCursor: integer) : boolean + * scrollCursor refers to the page's position within the entire sum of the data, unlike cursor, which refers to a user's position within displayed data + * @param takes a scrollCursor that has been updated based on user behavior + * @returns returns a boolean that indicates whether the updated scrollCursor led to an update in the data displayed. + */ + setScrollCursor(scrollCursor: integer): boolean { + if (scrollCursor === this.scrollCursor) { + return false; + } + + this.scrollCursor = scrollCursor; + + this.updateAchvIcons(); + + this.showAchv(achvs[Object.keys(achvs)[Math.min(this.cursor + this.scrollCursor * this.ACHV_COLS, Object.values(achvs).length - 1)]]); + + return true; + } + + + /** + * updateAchvIcons(): void + * Determines what data is to be displayed on the UI and updates it accordingly based on the current value of this.scrollCursor + */ + updateAchvIcons(): void { + const achvUnlocks = this.scene.gameData.achvUnlocks; + + const itemOffset = this.scrollCursor * this.ACHV_COLS; + const itemLimit = this.ACHV_ROWS * this.ACHV_COLS; + + const achvRange = Object.values(achvs).slice(itemOffset, itemLimit + itemOffset); + + achvRange.forEach((achv: Achv, i: integer) => { + const icon = this.achvIcons[i]; + const unlocked = achvUnlocks.hasOwnProperty(achv.id); + const hidden = !unlocked && achv.secret && (!achv.parentId || !achvUnlocks.hasOwnProperty(achv.parentId)); + const tinted = !hidden && !unlocked; + + icon.setFrame(!hidden ? achv.iconImage : "unknown"); + icon.setVisible(true); + if (tinted) { + icon.setTintFill(0); + } else { + icon.clearTint(); + } + }); + + if (achvRange.length < this.achvIcons.length) { + this.achvIcons.slice(achvRange.length).map(i => i.setVisible(false)); + } + } + clear() { super.clear(); this.achvsContainer.setVisible(false); From 723040208d69fb94c7cb05b77eae36403a3af300 Mon Sep 17 00:00:00 2001 From: "Amani H." <109637146+xsn34kzx@users.noreply.github.com> Date: Wed, 7 Aug 2024 20:07:28 -0400 Subject: [PATCH 022/282] [Enhancement/Item] Add Achievement to Unlock Eviolite (#3390) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add Achievement & Adjust Weight Function * Create `EVIOLITE` Unlockable * Add Placeholder Localization Entries * Add `de` Localization Co-authored-by: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> * Add `ko` Localization Co-authored-by: returntoice * Add Placeholder `ja` Entry * Add `pt-BR` Localization Co-authored-by: José Ricardo Fleury Oliveira * Add `fr` Localization Co-authored-by: Lugiad' * Add Missing Placeholders for Localization * Add `fr` Localization (female) Co-authored-by: Lugiad' --------- Co-authored-by: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> Co-authored-by: returntoice Co-authored-by: José Ricardo Fleury Oliveira Co-authored-by: Lugiad' --- src/locales/ca-ES/achv.ts | 4 ++++ src/locales/de/achv.ts | 6 ++++++ src/locales/en/achv.ts | 4 ++++ src/locales/es/achv.ts | 4 ++++ src/locales/fr/achv.ts | 8 ++++++++ src/locales/it/achv.ts | 4 ++++ src/locales/ja/achv.ts | 4 ++++ src/locales/ko/achv.ts | 4 ++++ src/locales/pt_BR/achv.ts | 8 ++++++++ src/locales/zh_CN/achv.ts | 4 ++++ src/locales/zh_TW/achv.ts | 4 ++++ src/modifier/modifier-type.ts | 7 ++++++- src/phases.ts | 5 +++++ src/system/achv.ts | 4 ++++ src/system/game-data.ts | 3 ++- src/system/unlockables.ts | 8 ++++++-- 16 files changed, 77 insertions(+), 4 deletions(-) diff --git a/src/locales/ca-ES/achv.ts b/src/locales/ca-ES/achv.ts index 6123b735c4e..a05c8b814ab 100644 --- a/src/locales/ca-ES/achv.ts +++ b/src/locales/ca-ES/achv.ts @@ -169,6 +169,10 @@ export const PGMachv: AchievementTranslationEntries = { name: "Undefeated", description: "Beat the game in classic mode", }, + "UNEVOLVED_CLASSIC_VICTORY": { + name: "Bring Your Child To Work Day", + description: "Beat the game in Classic Mode with at least one unevolved party member." + }, "MONO_GEN_ONE": { name: "The Original Rival", diff --git a/src/locales/de/achv.ts b/src/locales/de/achv.ts index 6c84988883d..3d498d048a7 100644 --- a/src/locales/de/achv.ts +++ b/src/locales/de/achv.ts @@ -170,6 +170,11 @@ export const PGMachv: AchievementTranslationEntries = { name: "Ungeschlagen", description: "Beende den klassischen Modus erfolgreich.", }, + "UNEVOLVED_CLASSIC_VICTORY": { + name: "'Bringe dein Kind mit zur Arbeit'-Tag" , + description: "Beende den klassischen Modus erfolgreich mit mindestens einem nicht entwickeltem Pokémon in deinem Team" + }, + "MONO_GEN_ONE": { name: "Der originale Rivale", description: "Schließe die 'Nur 1. Generation' Herausforderung ab.", @@ -348,6 +353,7 @@ export const PGFachv: AchievementTranslationEntries = { "HIDDEN_ABILITY": PGMachv.HIDDEN_ABILITY, "PERFECT_IVS": PGMachv.PERFECT_IVS, "CLASSIC_VICTORY": PGMachv.CLASSIC_VICTORY, + "UNEVOLVED_CLASSIC_VICTORY": PGMachv.UNEVOLVED_CLASSIC_VICTORY, "MONO_GEN_ONE": PGMachv.MONO_GEN_ONE, "MONO_GEN_TWO": PGMachv.MONO_GEN_TWO, "MONO_GEN_THREE": PGMachv.MONO_GEN_THREE, diff --git a/src/locales/en/achv.ts b/src/locales/en/achv.ts index 6123b735c4e..a05c8b814ab 100644 --- a/src/locales/en/achv.ts +++ b/src/locales/en/achv.ts @@ -169,6 +169,10 @@ export const PGMachv: AchievementTranslationEntries = { name: "Undefeated", description: "Beat the game in classic mode", }, + "UNEVOLVED_CLASSIC_VICTORY": { + name: "Bring Your Child To Work Day", + description: "Beat the game in Classic Mode with at least one unevolved party member." + }, "MONO_GEN_ONE": { name: "The Original Rival", diff --git a/src/locales/es/achv.ts b/src/locales/es/achv.ts index ed734f21d0a..e291d93add2 100644 --- a/src/locales/es/achv.ts +++ b/src/locales/es/achv.ts @@ -169,6 +169,10 @@ export const PGMachv: AchievementTranslationEntries = { name: "Imbatible", description: "Completa el juego en modo clásico.", }, + "UNEVOLVED_CLASSIC_VICTORY": { + name: "Bring Your Child To Work Day", + description: "Beat the game in Classic Mode with at least one unevolved party member." + }, "MONO_GEN_ONE": { name: "The Original Rival", diff --git a/src/locales/fr/achv.ts b/src/locales/fr/achv.ts index d5b80700493..a2d7d2378a1 100644 --- a/src/locales/fr/achv.ts +++ b/src/locales/fr/achv.ts @@ -169,6 +169,10 @@ export const PGMachv: AchievementTranslationEntries = { name: "Invaincu", description: "Terminer le jeu en mode classique", }, + "UNEVOLVED_CLASSIC_VICTORY": { + name: "Le stagiaire de 3e", + description: "Terminer le mode Classique avec au moins un Pokémon non-évolué dans l’équipe." + }, "MONO_GEN_ONE": { name: "Le rival originel", @@ -439,6 +443,10 @@ export const PGFachv: AchievementTranslationEntries = { name: "Invaincue", description: "Terminer le jeu en mode classique", }, + "UNEVOLVED_CLASSIC_VICTORY": { + name: "Le stagiaire de 3e", + description: "Terminer le mode Classique avec au moins un Pokémon non-évolué dans l’équipe." + }, "MONO_GEN_ONE": { name: "Le rival originel", diff --git a/src/locales/it/achv.ts b/src/locales/it/achv.ts index e7e35a1a47b..91222b81579 100644 --- a/src/locales/it/achv.ts +++ b/src/locales/it/achv.ts @@ -169,6 +169,10 @@ export const PGMachv: AchievementTranslationEntries = { name: "Imbattuto", description: "Vinci in modalità classica", }, + "UNEVOLVED_CLASSIC_VICTORY": { + name: "Bring Your Child To Work Day", + description: "Beat the game in Classic Mode with at least one unevolved party member." + }, "MONO_GEN_ONE": { name: "Rivale Originale", diff --git a/src/locales/ja/achv.ts b/src/locales/ja/achv.ts index 3063488c659..7e8d41c9808 100644 --- a/src/locales/ja/achv.ts +++ b/src/locales/ja/achv.ts @@ -169,6 +169,10 @@ export const PGMachv: AchievementTranslationEntries = { name: "Undefeated", description: "Beat the game in classic mode", }, + "UNEVOLVED_CLASSIC_VICTORY": { + name: "Bring Your Child To Work Day", + description: "Beat the game in Classic Mode with at least one unevolved party member." + }, "MONO_GEN_ONE": { name: "The Original Rival", diff --git a/src/locales/ko/achv.ts b/src/locales/ko/achv.ts index abc0f186fd4..431cb7d3296 100644 --- a/src/locales/ko/achv.ts +++ b/src/locales/ko/achv.ts @@ -169,6 +169,10 @@ export const PGMachv: AchievementTranslationEntries = { name: "무패", description: "클래식 모드 클리어", }, + "UNEVOLVED_CLASSIC_VICTORY": { + name: "우리집 꿈나무", + description: "최종 진화형이 아닌 포켓몬을 데리고 클래식 모드 클리어." + }, "MONO_GEN_ONE": { name: "근본 라이벌", diff --git a/src/locales/pt_BR/achv.ts b/src/locales/pt_BR/achv.ts index 78c4da6ae2e..5874616bcdc 100644 --- a/src/locales/pt_BR/achv.ts +++ b/src/locales/pt_BR/achv.ts @@ -169,6 +169,10 @@ export const PGMachv: AchievementTranslationEntries = { name: "Invencível", description: "Vença o jogo no modo clássico", }, + "UNEVOLVED_CLASSIC_VICTORY": { + name: "Tire as Crianças da Sala", + description: "Vença o jogo no Modo Clássico com pelo menos um membro da equipe não evoluído.." + }, "MONO_GEN_ONE": { @@ -440,6 +444,10 @@ export const PGFachv: AchievementTranslationEntries = { name: "Invencível", description: "Vença o jogo no modo clássico", }, + "UNEVOLVED_CLASSIC_VICTORY": { + name: "Bring Your Child To Work Day", + description: "Beat the game in Classic Mode with at least one unevolved party member." + }, "MONO_GEN_ONE": { diff --git a/src/locales/zh_CN/achv.ts b/src/locales/zh_CN/achv.ts index a32f244400d..e2355342ab6 100644 --- a/src/locales/zh_CN/achv.ts +++ b/src/locales/zh_CN/achv.ts @@ -169,6 +169,10 @@ export const PGMachv: AchievementTranslationEntries = { name: "战无不胜", description: "在经典模式中通关游戏", }, + "UNEVOLVED_CLASSIC_VICTORY": { + name: "Bring Your Child To Work Day", + description: "Beat the game in Classic Mode with at least one unevolved party member." + }, "MONO_GEN_ONE": { name: "最初的劲敌", diff --git a/src/locales/zh_TW/achv.ts b/src/locales/zh_TW/achv.ts index 7c945e794a2..dbd1d44d220 100644 --- a/src/locales/zh_TW/achv.ts +++ b/src/locales/zh_TW/achv.ts @@ -169,6 +169,10 @@ export const PGMachv: AchievementTranslationEntries = { name: "戰無不勝", description: "在經典模式中通關遊戲", }, + "UNEVOLVED_CLASSIC_VICTORY": { + name: "Bring Your Child To Work Day", + description: "Beat the game in Classic Mode with at least one unevolved party member." + }, "MONO_GEN_ONE": { name: "最初的勁敵", diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index a6117d09ffe..07a9b74b9ff 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -1544,7 +1544,12 @@ const modifierPool: ModifierPool = { new WeightedModifierType(modifierTypes.MINT, 4), new WeightedModifierType(modifierTypes.RARE_EVOLUTION_ITEM, (party: Pokemon[]) => Math.min(Math.ceil(party[0].scene.currentBattle.waveIndex / 15) * 4, 32), 32), new WeightedModifierType(modifierTypes.AMULET_COIN, skipInLastClassicWaveOrDefault(3)), - //new WeightedModifierType(modifierTypes.EVIOLITE, (party: Pokemon[]) => party.some(p => ((p.getSpeciesForm(true).speciesId in pokemonEvolutions) || (p.isFusion() && (p.getFusionSpeciesForm(true).speciesId in pokemonEvolutions))) && !p.getHeldItems().some(i => i instanceof Modifiers.EvolutionStatBoosterModifier)) ? 10 : 0), + new WeightedModifierType(modifierTypes.EVIOLITE, (party: Pokemon[]) => { + if (party[0].scene.gameData.unlocks[Unlockables.EVIOLITE]) { + return party.some(p => ((p.getSpeciesForm(true).speciesId in pokemonEvolutions) || (p.isFusion() && (p.getFusionSpeciesForm(true).speciesId in pokemonEvolutions))) && !p.getHeldItems().some(i => i instanceof Modifiers.EvolutionStatBoosterModifier)) ? 10 : 0; + } + return 0; + }), new WeightedModifierType(modifierTypes.SPECIES_STAT_BOOSTER, 12), new WeightedModifierType(modifierTypes.LEEK, (party: Pokemon[]) => { const checkedSpecies = [ Species.FARFETCHD, Species.GALAR_FARFETCHD, Species.SIRFETCHD ]; diff --git a/src/phases.ts b/src/phases.ts index 39cbbd5ff8b..52537740695 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -65,6 +65,7 @@ import { PlayerGender } from "#enums/player-gender"; import { Species } from "#enums/species"; import { TrainerType } from "#enums/trainer-type"; import { applyChallenges, ChallengeType } from "./data/challenge"; +import { pokemonEvolutions } from "./data/pokemon-evolutions"; const { t } = i18next; @@ -4287,6 +4288,7 @@ export class GameOverPhase extends BattlePhase { if (this.victory && newClear) { if (this.scene.gameMode.isClassic) { firstClear = this.scene.validateAchv(achvs.CLASSIC_VICTORY); + this.scene.validateAchv(achvs.UNEVOLVED_CLASSIC_VICTORY); this.scene.gameData.gameStats.sessionsWon++; for (const pokemon of this.scene.getParty()) { this.awardRibbon(pokemon); @@ -4387,6 +4389,9 @@ export class GameOverPhase extends BattlePhase { if (!this.scene.gameData.unlocks[Unlockables.MINI_BLACK_HOLE]) { this.scene.unshiftPhase(new UnlockPhase(this.scene, Unlockables.MINI_BLACK_HOLE)); } + if (!this.scene.gameData.unlocks[Unlockables.EVIOLITE] && this.scene.getParty().some(p => p.getSpeciesForm(true).speciesId in pokemonEvolutions)) { + this.scene.unshiftPhase(new UnlockPhase(this.scene, Unlockables.EVIOLITE)); + } } } diff --git a/src/system/achv.ts b/src/system/achv.ts index b1f575fb31c..040a48d9a7e 100644 --- a/src/system/achv.ts +++ b/src/system/achv.ts @@ -1,6 +1,7 @@ import { Modifier } from "typescript"; import BattleScene from "../battle-scene"; import { TurnHeldItemTransferModifier } from "../modifier/modifier"; +import { pokemonEvolutions } from "#app/data/pokemon-evolutions"; import i18next from "i18next"; import * as Utils from "../utils"; import { PlayerGender } from "#enums/player-gender"; @@ -240,6 +241,8 @@ export function getAchievementDescription(localizationKey: string): string { return i18next.t(`${genderPrefix}achv:PERFECT_IVS.description` as ParseKeys); case "CLASSIC_VICTORY": return i18next.t(`${genderPrefix}achv:CLASSIC_VICTORY.description` as ParseKeys); + case "UNEVOLVED_CLASSIC_VICTORY": + return i18next.t(`${genderPrefix}achv:UNEVOLVED_CLASSIC_VICTORY.description` as ParseKeys); case "MONO_GEN_ONE": return i18next.t(`${genderPrefix}achv:MONO_GEN_ONE.description` as ParseKeys); case "MONO_GEN_TWO": @@ -326,6 +329,7 @@ export const achvs = { HIDDEN_ABILITY: new Achv("HIDDEN_ABILITY","", "HIDDEN_ABILITY.description","ability_charm", 75), PERFECT_IVS: new Achv("PERFECT_IVS","", "PERFECT_IVS.description","blunder_policy", 100), CLASSIC_VICTORY: new Achv("CLASSIC_VICTORY","", "CLASSIC_VICTORY.description","relic_crown", 150), + UNEVOLVED_CLASSIC_VICTORY: new Achv("UNEVOLVED_CLASSIC_VICTORY", "", "UNEVOLVED_CLASSIC_VICTORY.description", "eviolite", 175, c => c.getParty().some(p => p.getSpeciesForm(true).speciesId in pokemonEvolutions)), MONO_GEN_ONE_VICTORY: new ChallengeAchv("MONO_GEN_ONE","", "MONO_GEN_ONE.description", "ribbon_gen1", 100, c => c instanceof SingleGenerationChallenge && c.value === 1), MONO_GEN_TWO_VICTORY: new ChallengeAchv("MONO_GEN_TWO","", "MONO_GEN_TWO.description", "ribbon_gen2", 100, c => c instanceof SingleGenerationChallenge && c.value === 2), MONO_GEN_THREE_VICTORY: new ChallengeAchv("MONO_GEN_THREE","", "MONO_GEN_THREE.description", "ribbon_gen3", 100, c => c instanceof SingleGenerationChallenge && c.value === 3), diff --git a/src/system/game-data.ts b/src/system/game-data.ts index 2cc6ab93c61..8b756735ee6 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -309,7 +309,8 @@ export class GameData { this.unlocks = { [Unlockables.ENDLESS_MODE]: false, [Unlockables.MINI_BLACK_HOLE]: false, - [Unlockables.SPLICED_ENDLESS_MODE]: false + [Unlockables.SPLICED_ENDLESS_MODE]: false, + [Unlockables.EVIOLITE]: false }; this.achvUnlocks = {}; this.voucherUnlocks = {}; diff --git a/src/system/unlockables.ts b/src/system/unlockables.ts index d8e7d97edf6..983909373fd 100644 --- a/src/system/unlockables.ts +++ b/src/system/unlockables.ts @@ -1,9 +1,11 @@ +import i18next from "i18next"; import { GameMode, GameModes } from "../game-mode"; export enum Unlockables { ENDLESS_MODE, MINI_BLACK_HOLE, - SPLICED_ENDLESS_MODE + SPLICED_ENDLESS_MODE, + EVIOLITE } export function getUnlockableName(unlockable: Unlockables) { @@ -11,8 +13,10 @@ export function getUnlockableName(unlockable: Unlockables) { case Unlockables.ENDLESS_MODE: return `${GameMode.getModeName(GameModes.ENDLESS)} Mode`; case Unlockables.MINI_BLACK_HOLE: - return "Mini Black Hole"; + return i18next.t("modifierType:ModifierType.MINI_BLACK_HOLE.name"); case Unlockables.SPLICED_ENDLESS_MODE: return `${GameMode.getModeName(GameModes.SPLICED_ENDLESS)} Mode`; + case Unlockables.EVIOLITE: + return i18next.t("modifierType:ModifierType.EVIOLITE.name"); } } From a272d28cdfd51fb73cc1dc2d7165adc1a96eb9eb Mon Sep 17 00:00:00 2001 From: Mumble Date: Wed, 7 Aug 2024 17:44:05 -0700 Subject: [PATCH 023/282] [Misc] Eternatus Dialogue reflects # of Classic Sessions Played (#3387) * Eternatus Dialogue now includes # of Classic sessions played * Updated gendered messages * Update src/locales/fr/dialogue.ts Co-authored-by: Lugiad' * Update src/locales/fr/dialogue.ts Co-authored-by: Lugiad' * Update src/phases.ts Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * Added comments * Update src/phases.ts Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * Update src/phases.ts Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * strict-null changes * Update phases.ts for null-ish results * Fixed repeated 'for' in English boss dialogue * Correcting Boss Dialogue --------- Co-authored-by: Frutescens Co-authored-by: Lugiad' Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> --- src/locales/de/dialogue.ts | 2 +- src/locales/en/dialogue.ts | 4 ++-- src/locales/es/dialogue.ts | 4 ++-- src/locales/fr/dialogue.ts | 8 ++++---- src/locales/it/dialogue.ts | 4 ++-- src/locales/ko/dialogue.ts | 2 +- src/locales/pt_BR/dialogue.ts | 4 ++-- src/locales/zh_CN/dialogue.ts | 2 +- src/locales/zh_TW/dialogue.ts | 2 +- src/phases.ts | 11 ++++++++++- 10 files changed, 26 insertions(+), 17 deletions(-) diff --git a/src/locales/de/dialogue.ts b/src/locales/de/dialogue.ts index 09a887ef875..3687a538200 100644 --- a/src/locales/de/dialogue.ts +++ b/src/locales/de/dialogue.ts @@ -2792,7 +2792,7 @@ export const PGFdialogue: DialogueTranslationEntries = PGMdialogue; export const PGMbattleSpecDialogue: SimpleTranslationEntries = { "encounter": `Es scheint, als wäre es wieder mal an der Zeit.\nDu weißt, warum du hierher kommen musst, oder? $Dich hat es hierher gezogen, du warst bereits hier.\nUnzählige Male. - $Obwohl, vielleicht doch nicht unzählig.\nUm genau zu sein, dies ist der 5.643.853te Zyklus. + $Obwohl, vielleicht doch nicht unzählig.\nUm genau zu sein, dies ist der {{cycleCount}}te Zyklus. $Du verlierst jeden Zyklus dein Gedächtnis. Trotzdem \nbleibt etwas, ein Teil deines ehemaligen Ichs, erhalten. $Bis jetzt hast du es noch nicht vollbracht zu siegen, aber dieses Mal spüre ich eine andere Präsenz in dir.\n $Du bist der Einzige hier, aber es kommt mir so vor als wäre da...jemand anderes. diff --git a/src/locales/en/dialogue.ts b/src/locales/en/dialogue.ts index 95382eeb4e0..bc06e935874 100644 --- a/src/locales/en/dialogue.ts +++ b/src/locales/en/dialogue.ts @@ -2715,11 +2715,11 @@ export const PGFdialogue: DialogueTranslationEntries = PGMdialogue; export const PGMbattleSpecDialogue: SimpleTranslationEntries = { "encounter": `It appears the time has finally come once again.\nYou know why you have come here, do you not? $You were drawn here, because you have been here before.\nCountless times. - $Though, perhaps it can be counted.\nTo be precise, this is in fact your 5,643,853rd cycle. + $Though, perhaps it can be counted.\nTo be precise, this is in fact your {{cycleCount}} cycle. $Each cycle your mind reverts to its former state.\nEven so, somehow, remnants of your former selves remain. $Until now you have yet to succeed, but I sense a different presence in you this time.\n $You are the only one here, though it is as if there is… another. - $Will you finally prove a formidable challenge to me?\nThe challenge I have longed for for millennia? + $Will you finally prove a formidable challenge to me?\nThe challenge I have longed after for millennia? $We begin.`, "firstStageWin": `I see. The presence I felt was indeed real.\nIt appears I no longer need to hold back. $Do not disappoint me.`, diff --git a/src/locales/es/dialogue.ts b/src/locales/es/dialogue.ts index 6908984b171..3620275f799 100644 --- a/src/locales/es/dialogue.ts +++ b/src/locales/es/dialogue.ts @@ -2710,11 +2710,11 @@ export const PGFdialogue: DialogueTranslationEntries = PGMdialogue; export const PGMbattleSpecDialogue: SimpleTranslationEntries = { "encounter": `It appears the time has finally come once again.\nYou know why you have come here, do you not? $You were drawn here, because you have been here before.\nCountless times. - $Though, perhaps it can be counted.\nTo be precise, this is in fact your 5,643,853rd cycle. + $Though, perhaps it can be counted.\nTo be precise, this is in fact your {{cycleCount}} cycle. $Each cycle your mind reverts to its former state.\nEven so, somehow, remnants of your former selves remain. $Until now you have yet to succeed, but I sense a different presence in you this time.\n $You are the only one here, though it is as if there is… another. - $Will you finally prove a formidable challenge to me?\nThe challenge I have longed for for millennia? + $Will you finally prove a formidable challenge to me?\nThe challenge I have longed after for millennia? $We begin.`, "firstStageWin": `I see. The presence I felt was indeed real.\nIt appears I no longer need to hold back. $Do not disappoint me.`, diff --git a/src/locales/fr/dialogue.ts b/src/locales/fr/dialogue.ts index ad70a01f210..ecc80d2abaf 100644 --- a/src/locales/fr/dialogue.ts +++ b/src/locales/fr/dialogue.ts @@ -5188,8 +5188,8 @@ export const PGFdialogue: DialogueTranslationEntries = { // Dialogue of the endboss of the game when the player character is male (Or unset) export const PGMbattleSpecDialogue: SimpleTranslationEntries = { "encounter": `Une fois de plus, te revoilà.\nSais-tu que ce n’est point là ta première venue ? - $Tu a été appelé ici parce que t’y est déjà venu.\nUn nombre inimaginable de fois. - $Mais allons-y, faisons le décompte.\nTu en es très précisément à ton 5 643 853e cycle. + $Tu as été appelé ici parce que t’y es déjà venu.\nUn nombre inimaginable de fois. + $Mais allons-y, faisons le décompte.\nTu en es très précisément à ton {{cycleCount}}e cycle. $Chaque cycle réinitialise ton souvenir du précédent.\nMais étrangement, des bribes subsistent en toi. $Jusqu’à maintenant, tu as toujours échoué. Mais je ressens quelque chose de différent cette fois-ci.\n $Tu es la seule présence ici, bien que j’ai le sentiment d’en ressentir… une autre. @@ -5203,8 +5203,8 @@ export const PGMbattleSpecDialogue: SimpleTranslationEntries = { // Dialogue of the endboss of the game when the player character is female. For languages that do not have gendered pronouns, this can be set to PGMbattleSpecDialogue. export const PGFbattleSpecDialogue: SimpleTranslationEntries = { "encounter": `Une fois de plus, te revoilà.\nSais-tu que ce n’est point là ta première venue ? - $Tu a été appelée ici parce que t’y est déjà venue.\nUn nombre inimaginable de fois. - $Mais allons-y, faisons le décompte.\nTu en es très précisément à ton 5 643 853e cycle. + $Tu as été appelée ici parce que t’y es déjà venue.\nUn nombre inimaginable de fois. + $Mais allons-y, faisons le décompte.\nTu en es très précisément à ton {{cycleCount}}e cycle. $Chaque cycle réinitialise ton souvenir du précédent.\nMais étrangement, des bribes subsistent en toi. $Jusqu’à maintenant, tu as toujours échoué. Mais je ressens quelque chose de différent cette fois-ci.\n $Tu es la seule présence ici, bien que j’ai le sentiment d’en ressentir… une autre. diff --git a/src/locales/it/dialogue.ts b/src/locales/it/dialogue.ts index d0c14dee824..570bd089ff8 100644 --- a/src/locales/it/dialogue.ts +++ b/src/locales/it/dialogue.ts @@ -2710,11 +2710,11 @@ export const PGFdialogue: DialogueTranslationEntries = PGMdialogue; export const PGMbattleSpecDialogue: SimpleTranslationEntries = { "encounter": `It appears the time has finally come once again.\nYou know why you have come here, do you not? $You were drawn here, because you have been here before.\nCountless times. - $Though, perhaps it can be counted.\nTo be precise, this is in fact your 5,643,853rd cycle. + $Though, perhaps it can be counted.\nTo be precise, this is in fact your {{cycleCount}} cycle. $Each cycle your mind reverts to its former state.\nEven so, somehow, remnants of your former selves remain. $Until now you have yet to succeed, but I sense a different presence in you this time.\n $You are the only one here, though it is as if there is… another. - $Will you finally prove a formidable challenge to me?\nThe challenge I have longed for for millennia? + $Will you finally prove a formidable challenge to me?\nThe challenge I have longed after for millennia? $We begin.`, "firstStageWin": `I see. The presence I felt was indeed real.\nIt appears I no longer need to hold back. $Do not disappoint me.`, diff --git a/src/locales/ko/dialogue.ts b/src/locales/ko/dialogue.ts index e032ec14844..81eee94e2dc 100644 --- a/src/locales/ko/dialogue.ts +++ b/src/locales/ko/dialogue.ts @@ -2707,7 +2707,7 @@ export const PGFdialogue: DialogueTranslationEntries = PGMdialogue; export const PGMbattleSpecDialogue: SimpleTranslationEntries = { "encounter": `드디어 때가 다시 도래했다.\n당도한 연유를 아는가? $이미 도달한 적이 있기에 이 자리에 있다.\n셀 수도 없이 많이. - $아니, 사실 셀 수는 있지.\n정확히 너의 5,643,853번째다. + $아니, 사실 셀 수는 있지.\n정확히 너의 {{cycleCount}}번째다. $매 번 태초의 정신으로 되돌아갔을 뿐.\n하지만 어떻게든, 흔적은 남는다. $실패만을 반복했을 뿐이지만,\n지금은 네 안에 무언가가 있구나.\n $홀로 선 것처럼 보이나, 무언가 이질적인… diff --git a/src/locales/pt_BR/dialogue.ts b/src/locales/pt_BR/dialogue.ts index cbd781009e5..9e2fecd386a 100644 --- a/src/locales/pt_BR/dialogue.ts +++ b/src/locales/pt_BR/dialogue.ts @@ -5002,7 +5002,7 @@ export const PGFdialogue: DialogueTranslationEntries = { export const PGMbattleSpecDialogue: SimpleTranslationEntries = { "encounter": `Parece que a hora finalmente chegou novamente.\nVocê sabe por que veio aqui, não sabe? $Você foi atraído para cá, porque já esteve aqui antes.\nInúmeras vezes. - $Embora talvez isso possa ser contado.\nPara ser preciso, este é de fato o seu 5.643.853º ciclo. + $Embora talvez isso possa ser contado.\nPara ser preciso, este é de fato o seu {{cycleCount}}º ciclo. $A cada ciclo, sua mente retorna ao seu estado anterior.\nMesmo assim, de alguma forma, vestígios de seus antigos "eus" permanecem. $Até agora, você ainda não conseguiu, mas sinto uma presença diferente em você desta vez.\n $Você é o único aqui, embora pareça haver... outro. @@ -5017,7 +5017,7 @@ export const PGMbattleSpecDialogue: SimpleTranslationEntries = { export const PGFbattleSpecDialogue: SimpleTranslationEntries = { "encounter": `Parece que a hora finalmente chegou novamente.\nVocê sabe por que veio aqui, não sabe? $Você foi atraída para cá, porque já esteve aqui antes.\nInúmeras vezes. - $Embora talvez isso possa ser contado.\nPara ser preciso, este é de fato o seu 5.643.853º ciclo. + $Embora talvez isso possa ser contado.\nPara ser preciso, este é de fato o seu {{cycleCount}}º ciclo. $A cada ciclo, sua mente retorna ao seu estado anterior.\nMesmo assim, de alguma forma, vestígios de seus antigos "eus" permanecem. $Até agora, você ainda não conseguiu, mas sinto uma presença diferente em você desta vez.\n $Você é a única aqui, embora pareça haver... outro. diff --git a/src/locales/zh_CN/dialogue.ts b/src/locales/zh_CN/dialogue.ts index 597b26dd639..ebce2caada4 100644 --- a/src/locales/zh_CN/dialogue.ts +++ b/src/locales/zh_CN/dialogue.ts @@ -2530,7 +2530,7 @@ export const PGFdialogue: DialogueTranslationEntries = PGMdialogue; export const PGMbattleSpecDialogue: SimpleTranslationEntries = { "encounter": `看来终于又到了那个时候。\n你知道自己为何会来到这里,不是吗? $你被吸引到这里,因为你以前就来过这里。\n无数次。 - $尽管,或许可以数一数。\n准确地说,这实际上是你的第5,643,853次循环。 + $尽管,或许可以数一数。\n准确地说,这实际上是你的第{{cycleCount}}次循环。 $每一次循环,你的思想都会恢复到之前的状态。\n即便如此,不知何故,你之前自我的残留仍然存在。 $直到现在,你仍未成功,\n但我感觉这次你身上有一种异样的气息。 $你是这里唯一的人,尽管感觉上还有……另一个人。 diff --git a/src/locales/zh_TW/dialogue.ts b/src/locales/zh_TW/dialogue.ts index 16dad83599e..295d37509d4 100644 --- a/src/locales/zh_TW/dialogue.ts +++ b/src/locales/zh_TW/dialogue.ts @@ -2529,7 +2529,7 @@ export const PGFdialogue: DialogueTranslationEntries = PGMdialogue; export const PGMbattleSpecDialogue: SimpleTranslationEntries = { "encounter": `看來終於又到了那個時候。\n你知道自己為何會來到這裡,不是嗎? $你被吸引到這裡,因為你以前就來過這裡。\n無數次。 - $儘管,或許可以數一數。\n準確地說,這實際上是你的第5,643,853次循環。 + $儘管,或許可以數一數。\n準確地說,這實際上是你的第{{cycleCount}}次循環。 $每一次循環,你的思想都會恢復到之前的狀態。\n即便如此,不知何故,你之前自我的殘留仍然存在。 $直到現在,你仍未成功,但我感覺這次你身上有一種異樣的氣息。 $你是這裡唯一的人,儘管感覺上還有……另一個人。 diff --git a/src/phases.ts b/src/phases.ts index 52537740695..7bc3ceeb55d 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -1131,7 +1131,16 @@ export class EncounterPhase extends BattlePhase { case BattleSpec.FINAL_BOSS: const enemy = this.scene.getEnemyPokemon(); this.scene.ui.showText(this.getEncounterMessage(), null, () => { - this.scene.ui.showDialogue(battleSpecDialogue[BattleSpec.FINAL_BOSS].encounter, enemy?.species.name, null, () => { + const count = 5643853 + this.scene.gameData.gameStats.classicSessionsPlayed; + //The two lines below check if English ordinals (1st, 2nd, 3rd, Xth) are used and determine which one to use. + //Otherwise, it defaults to an empty string. + //As of 08-07-24: Spanish and Italian default to the English translations + const ordinalUse = ["en", "es", "it"]; + const currentLanguage = i18next.resolvedLanguage ?? "en"; + const ordinalIndex = (ordinalUse.includes(currentLanguage)) ? ["st", "nd", "rd"][((count + 90) % 100 - 10) % 10 - 1] ?? "th" : ""; + const cycleCount = count.toLocaleString() + ordinalIndex; + const encounterDialogue = i18next.t(`${(this.scene.gameData.gender === PlayerGender.FEMALE) ? "PGF" : "PGM"}battleSpecDialogue:encounter`, {cycleCount: cycleCount}); + this.scene.ui.showDialogue(encounterDialogue, enemy?.species.name, null, () => { this.doEncounterCommon(false); }); }, 1500, true); From 8faf27efc928641a01352935df91ae85ee26569d Mon Sep 17 00:00:00 2001 From: DustinLin <39450497+DustinLin@users.noreply.github.com> Date: Wed, 7 Aug 2024 17:44:34 -0700 Subject: [PATCH 024/282] [BUG] - dragon tail switchout ability in wild battles proc crashes game (#3346) * fixing switchout ability doubles bug, refactor move redirect code * added unit test for dragon tail * updating test * addressing errors from pages deployment * pages deployment still failing * typedoc * please let this be the one * formatting and test fixing * await starting battle should go after overrides --- src/battle-scene.ts | 21 ++++ src/data/move.ts | 16 ++- src/field/pokemon.ts | 15 ++- src/phases.ts | 21 ++-- src/test/moves/dragon_tail.test.ts | 166 +++++++++++++++++++++++++++++ 5 files changed, 223 insertions(+), 16 deletions(-) create mode 100644 src/test/moves/dragon_tail.test.ts diff --git a/src/battle-scene.ts b/src/battle-scene.ts index c0b6e2ba91e..d8c34fefdd6 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -768,6 +768,27 @@ export default class BattleScene extends SceneBase { : ret; } + /** + * Used in doubles battles to redirect moves from one pokemon to another when one faints or is removed from the field + * @param removedPokemon {@linkcode Pokemon} the pokemon that is being removed from the field (flee, faint), moves to be redirected FROM + * @param allyPokemon {@linkcode Pokemon} the pokemon that will have the moves be redirected TO + */ + redirectPokemonMoves(removedPokemon: Pokemon, allyPokemon: Pokemon): void { + // failsafe: if not a double battle just return + if (this.currentBattle.double === false) { + return; + } + if (allyPokemon?.isActive(true)) { + let targetingMovePhase: MovePhase; + do { + targetingMovePhase = this.findPhase(mp => mp instanceof MovePhase && mp.targets.length === 1 && mp.targets[0] === removedPokemon.getBattlerIndex() && mp.pokemon.isPlayer() !== allyPokemon.isPlayer()) as MovePhase; + if (targetingMovePhase && targetingMovePhase.targets[0] !== allyPokemon.getBattlerIndex()) { + targetingMovePhase.targets[0] = allyPokemon.getBattlerIndex(); + } + } while (targetingMovePhase); + } + } + /** * Returns the ModifierBar of this scene, which is declared private and therefore not accessible elsewhere * @returns {ModifierBar} diff --git a/src/data/move.ts b/src/data/move.ts index 827c3716d9b..14e7738b948 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -4883,13 +4883,18 @@ export class ForceSwitchOutAttr extends MoveEffectAttr { user.scene.prependToPhase(new SwitchSummonPhase(user.scene, switchOutTarget.getFieldIndex(), (user.scene.currentBattle.trainer ? user.scene.currentBattle.trainer.getNextSummonIndex((switchOutTarget as EnemyPokemon).trainerSlot) : 0), false, this.batonPass, false), MoveEndPhase); } } else { - // Switch out logic for everything else - switchOutTarget.setVisible(false); + // Switch out logic for everything else (eg: WILD battles) + switchOutTarget.leaveField(false); if (switchOutTarget.hp) { - switchOutTarget.hideInfo().then(() => switchOutTarget.destroy()); - switchOutTarget.scene.field.remove(switchOutTarget); + switchOutTarget.setWildFlee(true); user.scene.queueMessage(i18next.t("moveTriggers:fled", {pokemonName: getPokemonNameWithAffix(switchOutTarget)}), null, true, 500); + + // in double battles redirect potential moves off fled pokemon + if (switchOutTarget.scene.currentBattle.double) { + const allyPokemon = switchOutTarget.getAlly(); + switchOutTarget.scene.redirectPokemonMoves(switchOutTarget, allyPokemon); + } } if (!switchOutTarget.getAlly()?.isActive(true)) { @@ -7585,7 +7590,8 @@ export function initMoves() { new AttackMove(Moves.FROST_BREATH, Type.ICE, MoveCategory.SPECIAL, 60, 90, 10, 100, 0, 5) .attr(CritOnlyAttr), new AttackMove(Moves.DRAGON_TAIL, Type.DRAGON, MoveCategory.PHYSICAL, 60, 90, 10, -1, -6, 5) - .attr(ForceSwitchOutAttr), + .attr(ForceSwitchOutAttr) + .hidesTarget(), new SelfStatusMove(Moves.WORK_UP, Type.NORMAL, -1, 30, -1, 0, 5) .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK ], 1, true), new AttackMove(Moves.ELECTROWEB, Type.ELECTRIC, MoveCategory.SPECIAL, 55, 95, 15, 100, 0, 5) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 84058cc656f..283f90f891c 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -88,6 +88,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { public luck: integer; public pauseEvolutions: boolean; public pokerus: boolean; + public wildFlee: boolean; public fusionSpecies: PokemonSpecies | null; public fusionFormIndex: integer; @@ -129,6 +130,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { this.species = species; this.pokeball = dataSource?.pokeball || PokeballType.POKEBALL; this.level = level; + this.wildFlee = false; + // Determine the ability index if (abilityIndex !== undefined) { this.abilityIndex = abilityIndex; // Use the provided ability index if it is defined @@ -298,14 +301,14 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } /** - * Check if this pokemon is both not fainted and allowed to be in battle. + * Check if this pokemon is both not fainted (or a fled wild pokemon) and allowed to be in battle. * This is frequently a better alternative to {@link isFainted} * @returns {boolean} True if pokemon is allowed in battle */ isAllowedInBattle(): boolean { const challengeAllowed = new Utils.BooleanHolder(true); applyChallenges(this.scene.gameMode, ChallengeType.POKEMON_IN_BATTLE, this, challengeAllowed); - return !this.isFainted() && challengeAllowed.value; + return !this.isFainted() && !this.wildFlee && challengeAllowed.value; } isActive(onField?: boolean): boolean { @@ -1779,6 +1782,14 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { }); } + /** + * sets if the pokemon has fled (implies it's a wild pokemon) + * @param status - boolean + */ + setWildFlee(status: boolean): void { + this.wildFlee = status; + } + updateInfo(instant?: boolean): Promise { return this.battleInfo.updateInfo(this, instant); } diff --git a/src/phases.ts b/src/phases.ts index 7bc3ceeb55d..c4662df199d 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -2576,6 +2576,15 @@ export class BattleEndPhase extends BattlePhase { this.scene.updateModifiers().then(() => this.end()); } + + end() { + // removing pokemon at the end of a battle + for (const p of this.scene.getEnemyParty()) { + p.destroy(); + } + + super.end(); + } } export class NewBattlePhase extends BattlePhase { @@ -3830,6 +3839,7 @@ export class FaintPhase extends PokemonPhase { doFaint(): void { const pokemon = this.getPokemon(); + // Track total times pokemon have been KO'd for supreme overlord/last respects if (pokemon.isPlayer()) { this.scene.currentBattle.playerFaints += 1; @@ -3880,17 +3890,10 @@ export class FaintPhase extends PokemonPhase { } } + // in double battles redirect potential moves off fainted pokemon if (this.scene.currentBattle.double) { const allyPokemon = pokemon.getAlly(); - if (allyPokemon?.isActive(true)) { - let targetingMovePhase: MovePhase; - do { - targetingMovePhase = this.scene.findPhase(mp => mp instanceof MovePhase && mp.targets.length === 1 && mp.targets[0] === pokemon.getBattlerIndex() && mp.pokemon.isPlayer() !== allyPokemon.isPlayer()) as MovePhase; - if (targetingMovePhase && targetingMovePhase.targets[0] !== allyPokemon.getBattlerIndex()) { - targetingMovePhase.targets[0] = allyPokemon.getBattlerIndex(); - } - } while (targetingMovePhase); - } + this.scene.redirectPokemonMoves(pokemon, allyPokemon); } pokemon.lapseTags(BattlerTagLapseType.FAINT); diff --git a/src/test/moves/dragon_tail.test.ts b/src/test/moves/dragon_tail.test.ts new file mode 100644 index 00000000000..7374451e643 --- /dev/null +++ b/src/test/moves/dragon_tail.test.ts @@ -0,0 +1,166 @@ +import { allMoves } from "#app/data/move.js"; +import { SPLASH_ONLY } from "../utils/testUtils"; +import { BattleEndPhase, BerryPhase, TurnEndPhase} from "#app/phases.js"; +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest"; +import GameManager from "../utils/gameManager"; +import { getMovePosition } from "../utils/gameManagerUtils"; +import { BattlerIndex } from "#app/battle.js"; + +const TIMEOUT = 20 * 1000; + +describe("Moves - Dragon Tail", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override.battleType("single") + .moveset([Moves.DRAGON_TAIL, Moves.SPLASH]) + .enemySpecies(Species.WAILORD) + .enemyMoveset(SPLASH_ONLY) + .startingLevel(5) + .enemyLevel(5); + + vi.spyOn(allMoves[Moves.DRAGON_TAIL], "accuracy", "get").mockReturnValue(100); + }); + + test( + "Single battle should cause opponent to flee, and not crash", + async () => { + await game.startBattle([Species.DRATINI]); + + const enemyPokemon = game.scene.getEnemyPokemon()!; + expect(enemyPokemon).toBeDefined(); + + game.doAttack(getMovePosition(game.scene, 0, Moves.DRAGON_TAIL)); + + await game.phaseInterceptor.to(BerryPhase); + + const isVisible = enemyPokemon.visible; + const hasFled = enemyPokemon.wildFlee; + expect(!isVisible && hasFled).toBe(true); + + // simply want to test that the game makes it this far without crashing + await game.phaseInterceptor.to(BattleEndPhase); + }, TIMEOUT + ); + + test( + "Single battle should cause opponent to flee, display ability, and not crash", + async () => { + game.override.enemyAbility(Abilities.ROUGH_SKIN); + await game.startBattle([Species.DRATINI]); + + const leadPokemon = game.scene.getPlayerPokemon()!; + expect(leadPokemon).toBeDefined(); + + const enemyPokemon = game.scene.getEnemyPokemon()!; + expect(enemyPokemon).toBeDefined(); + + game.doAttack(getMovePosition(game.scene, 0, Moves.DRAGON_TAIL)); + + await game.phaseInterceptor.to(BerryPhase); + + const isVisible = enemyPokemon.visible; + const hasFled = enemyPokemon.wildFlee; + expect(!isVisible && hasFled).toBe(true); + expect(leadPokemon.hp).toBeLessThan(leadPokemon.getMaxHp()); + }, TIMEOUT + ); + + test( + "Double battles should proceed without crashing" , + async () => { + game.override.battleType("double").enemyMoveset(SPLASH_ONLY); + game.override.moveset([Moves.DRAGON_TAIL, Moves.SPLASH, Moves.FLAMETHROWER]) + .enemyAbility(Abilities.ROUGH_SKIN); + await game.startBattle([Species.DRATINI, Species.DRATINI, Species.WAILORD, Species.WAILORD]); + + const leadPokemon = game.scene.getParty()[0]!; + const secPokemon = game.scene.getParty()[1]!; + expect(leadPokemon).toBeDefined(); + expect(secPokemon).toBeDefined(); + + const enemyLeadPokemon = game.scene.currentBattle.enemyParty[0]!; + const enemySecPokemon = game.scene.currentBattle.enemyParty[1]!; + expect(enemyLeadPokemon).toBeDefined(); + expect(enemySecPokemon).toBeDefined(); + + game.doAttack(getMovePosition(game.scene, 0, Moves.DRAGON_TAIL)); + game.doSelectTarget(BattlerIndex.ENEMY); + + game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + + await game.phaseInterceptor.to(TurnEndPhase); + + const isVisibleLead = enemyLeadPokemon.visible; + const hasFledLead = enemyLeadPokemon.wildFlee; + const isVisibleSec = enemySecPokemon.visible; + const hasFledSec = enemySecPokemon.wildFlee; + expect(!isVisibleLead && hasFledLead && isVisibleSec && !hasFledSec).toBe(true); + expect(leadPokemon.hp).toBeLessThan(leadPokemon.getMaxHp()); + + // second turn + + game.doAttack(getMovePosition(game.scene, 0, Moves.FLAMETHROWER)); + game.doSelectTarget(BattlerIndex.ENEMY_2); + game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + + await game.phaseInterceptor.to(BerryPhase); + expect(enemySecPokemon.hp).toBeLessThan(enemySecPokemon.getMaxHp()); + }, TIMEOUT + ); + + test( + "Flee move redirection works" , + async () => { + game.override.battleType("double").enemyMoveset(SPLASH_ONLY); + game.override.moveset([Moves.DRAGON_TAIL, Moves.SPLASH, Moves.FLAMETHROWER]); + game.override.enemyAbility(Abilities.ROUGH_SKIN); + await game.startBattle([Species.DRATINI, Species.DRATINI, Species.WAILORD, Species.WAILORD]); + + const leadPokemon = game.scene.getParty()[0]!; + const secPokemon = game.scene.getParty()[1]!; + expect(leadPokemon).toBeDefined(); + expect(secPokemon).toBeDefined(); + + const enemyLeadPokemon = game.scene.currentBattle.enemyParty[0]!; + const enemySecPokemon = game.scene.currentBattle.enemyParty[1]!; + expect(enemyLeadPokemon).toBeDefined(); + expect(enemySecPokemon).toBeDefined(); + + game.doAttack(getMovePosition(game.scene, 0, Moves.DRAGON_TAIL)); + game.doSelectTarget(BattlerIndex.ENEMY); + + // target the same pokemon, second move should be redirected after first flees + game.doAttack(getMovePosition(game.scene, 0, Moves.DRAGON_TAIL)); + game.doSelectTarget(BattlerIndex.ENEMY); + + await game.phaseInterceptor.to(BerryPhase); + + const isVisibleLead = enemyLeadPokemon.visible; + const hasFledLead = enemyLeadPokemon.wildFlee; + const isVisibleSec = enemySecPokemon.visible; + const hasFledSec = enemySecPokemon.wildFlee; + expect(!isVisibleLead && hasFledLead && !isVisibleSec && hasFledSec).toBe(true); + expect(leadPokemon.hp).toBeLessThan(leadPokemon.getMaxHp()); + expect(secPokemon.hp).toBeLessThan(secPokemon.getMaxHp()); + expect(enemyLeadPokemon.hp).toBeLessThan(enemyLeadPokemon.getMaxHp()); + expect(enemySecPokemon.hp).toBeLessThan(enemySecPokemon.getMaxHp()); + }, TIMEOUT + ); +}); From 17517d467b3af44f8c93e8371022a2dd5e69b971 Mon Sep 17 00:00:00 2001 From: Blitzy <118096277+Blitz425@users.noreply.github.com> Date: Wed, 7 Aug 2024 19:46:33 -0500 Subject: [PATCH 025/282] [Feature] Implement Additional Grunt Dialogue (#3331) * Update dialogue.ts * Update dialogue.ts * Add Placeholder text in Locale files * Update dialogue.ts * Update dialogue.ts * Fix Punctuation, Change Plasma Grunt Line 3 * Update dialogue.ts * Apply suggestions from code review Co-authored-by: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> Co-authored-by: sodam <66295123+sodaMelon@users.noreply.github.com> Co-authored-by: Yonmaru40 <47717431+40chyan@users.noreply.github.com> * Update dialogue.ts * Update dialogue.ts * Apply suggestions from code review Co-authored-by: returntoice * Update dialogue.ts * Update new locale files --------- Co-authored-by: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> Co-authored-by: sodam <66295123+sodaMelon@users.noreply.github.com> Co-authored-by: Yonmaru40 <47717431+40chyan@users.noreply.github.com> Co-authored-by: returntoice --- src/data/dialogue.ts | 72 ++++++++++++++++++++++++++++------ src/locales/ca-ES/dialogue.ts | 73 ++++++++++++++++++++++++++++------- src/locales/de/dialogue.ts | 69 +++++++++++++++++++++++++++------ src/locales/en/dialogue.ts | 72 ++++++++++++++++++++++++++++------ src/locales/es/dialogue.ts | 72 ++++++++++++++++++++++++++++------ src/locales/fr/dialogue.ts | 72 ++++++++++++++++++++++++++++------ src/locales/it/dialogue.ts | 72 ++++++++++++++++++++++++++++------ src/locales/ja/dialogue.ts | 73 ++++++++++++++++++++++++++++------- src/locales/ko/dialogue.ts | 72 ++++++++++++++++++++++++++++------ src/locales/pt_BR/dialogue.ts | 72 ++++++++++++++++++++++++++++------ src/locales/zh_CN/dialogue.ts | 72 ++++++++++++++++++++++++++++------ src/locales/zh_TW/dialogue.ts | 72 ++++++++++++++++++++++++++++------ 12 files changed, 718 insertions(+), 145 deletions(-) diff --git a/src/data/dialogue.ts b/src/data/dialogue.ts index 8a595855a30..3e48d81ed12 100644 --- a/src/data/dialogue.ts +++ b/src/data/dialogue.ts @@ -452,10 +452,18 @@ export const trainerTypeDialogue: TrainerTypeDialogue = { [TrainerType.ROCKET_GRUNT]: [ { encounter: [ - "dialogue:rocket_grunt.encounter.1" + "dialogue:rocket_grunt.encounter.1", + "dialogue:rocket_grunt.encounter.2", + "dialogue:rocket_grunt.encounter.3", + "dialogue:rocket_grunt.encounter.4", + "dialogue:rocket_grunt.encounter.5", ], victory: [ - "dialogue:rocket_grunt.victory.1" + "dialogue:rocket_grunt.victory.1", + "dialogue:rocket_grunt.victory.2", + "dialogue:rocket_grunt.victory.3", + "dialogue:rocket_grunt.victory.4", + "dialogue:rocket_grunt.victory.5", ] } ], @@ -518,10 +526,18 @@ export const trainerTypeDialogue: TrainerTypeDialogue = { [TrainerType.MAGMA_GRUNT]: [ { encounter: [ - "dialogue:magma_grunt.encounter.1" + "dialogue:magma_grunt.encounter.1", + "dialogue:magma_grunt.encounter.2", + "dialogue:magma_grunt.encounter.3", + "dialogue:magma_grunt.encounter.4", + "dialogue:magma_grunt.encounter.5", ], victory: [ - "dialogue:magma_grunt.victory.1" + "dialogue:magma_grunt.victory.1", + "dialogue:magma_grunt.victory.2", + "dialogue:magma_grunt.victory.3", + "dialogue:magma_grunt.victory.4", + "dialogue:magma_grunt.victory.5", ] } ], @@ -556,10 +572,18 @@ export const trainerTypeDialogue: TrainerTypeDialogue = { [TrainerType.AQUA_GRUNT]: [ { encounter: [ - "dialogue:aqua_grunt.encounter.1" + "dialogue:aqua_grunt.encounter.1", + "dialogue:aqua_grunt.encounter.2", + "dialogue:aqua_grunt.encounter.3", + "dialogue:aqua_grunt.encounter.4", + "dialogue:aqua_grunt.encounter.5", ], victory: [ - "dialogue:aqua_grunt.victory.1" + "dialogue:aqua_grunt.victory.1", + "dialogue:aqua_grunt.victory.2", + "dialogue:aqua_grunt.victory.3", + "dialogue:aqua_grunt.victory.4", + "dialogue:aqua_grunt.victory.5", ] } ], @@ -594,10 +618,18 @@ export const trainerTypeDialogue: TrainerTypeDialogue = { [TrainerType.GALACTIC_GRUNT]: [ { encounter: [ - "dialogue:galactic_grunt.encounter.1" + "dialogue:galactic_grunt.encounter.1", + "dialogue:galactic_grunt.encounter.2", + "dialogue:galactic_grunt.encounter.3", + "dialogue:galactic_grunt.encounter.4", + "dialogue:galactic_grunt.encounter.5", ], victory: [ - "dialogue:galactic_grunt.victory.1" + "dialogue:galactic_grunt.victory.1", + "dialogue:galactic_grunt.victory.2", + "dialogue:galactic_grunt.victory.3", + "dialogue:galactic_grunt.victory.4", + "dialogue:galactic_grunt.victory.5", ] } ], @@ -646,10 +678,18 @@ export const trainerTypeDialogue: TrainerTypeDialogue = { [TrainerType.PLASMA_GRUNT]: [ { encounter: [ - "dialogue:plasma_grunt.encounter.1" + "dialogue:plasma_grunt.encounter.1", + "dialogue:plasma_grunt.encounter.2", + "dialogue:plasma_grunt.encounter.3", + "dialogue:plasma_grunt.encounter.4", + "dialogue:plasma_grunt.encounter.5", ], victory: [ - "dialogue:plasma_grunt.victory.1" + "dialogue:plasma_grunt.victory.1", + "dialogue:plasma_grunt.victory.2", + "dialogue:plasma_grunt.victory.3", + "dialogue:plasma_grunt.victory.4", + "dialogue:plasma_grunt.victory.5", ] } ], @@ -670,10 +710,18 @@ export const trainerTypeDialogue: TrainerTypeDialogue = { [TrainerType.FLARE_GRUNT]: [ { encounter: [ - "dialogue:flare_grunt.encounter.1" + "dialogue:flare_grunt.encounter.1", + "dialogue:flare_grunt.encounter.2", + "dialogue:flare_grunt.encounter.3", + "dialogue:flare_grunt.encounter.4", + "dialogue:flare_grunt.encounter.5", ], victory: [ - "dialogue:flare_grunt.victory.1" + "dialogue:flare_grunt.victory.1", + "dialogue:flare_grunt.victory.2", + "dialogue:flare_grunt.victory.3", + "dialogue:flare_grunt.victory.4", + "dialogue:flare_grunt.victory.5", ] } ], diff --git a/src/locales/ca-ES/dialogue.ts b/src/locales/ca-ES/dialogue.ts index 64e4028a912..e783ea14006 100644 --- a/src/locales/ca-ES/dialogue.ts +++ b/src/locales/ca-ES/dialogue.ts @@ -583,51 +583,98 @@ export const PGMdialogue: DialogueTranslationEntries = { }, "rocket_grunt": { "encounter": { - 1: "Prepare for trouble!" + 1: "Se prepara pra encrenca!", + 2: "We're pulling a big job here! Get lost, kid!", + 3: "Hand over your Pokémon, or face the wrath of Team Rocket!", + 4: "You're about to experience the true terror of Team Rocket!", + 5: "Hey, kid! Me am a Team Rocket member kind of guy!" //Use of wrong grammar is deliberate }, "victory": { - 1: "Team Rocket blasting off again!" + 1: "Equipe Rocket decolando de novo!", + 2: "Oh no! I dropped the Lift Key!", + 3: "I blew it!", + 4: "My associates won't stand for this!", + 5: "You say what? Team Rocket bye-bye a go-go? Broken it is says you?" //Use of wrong grammar is deliberate. }, }, "magma_grunt": { "encounter": { - 1: " If you get in the way of Team Magma, don’t expect any mercy!" + 1: "Se você se meter com a Equipe Magma, não teremos piedade!", + 2: "You'd better not interfere with our plans! We're making the world a better place!", + 3: "You're in the way! Team Magma has no time for kids like you!", + 4: "I hope you brought marshmallows because things are about to heat up!", + 5: "We're going to use the power of a volcano! It's gonna be... explosive! Get it? Heh heh!" }, "victory": { - 1: "Huh? I lost?!" + 1: "Ahn? Eu perdi?!", + 2: "I can't believe I lost! I even skipped lunch for this", + 3: "No way! You're just a kid!", + 4: "Urrrgh... I should've ducked into our hideout right away...", + 5: "You beat me... Do you think the boss will dock my pay for this?" }, }, - "aqua_grunt": { "encounter": { - 1: "No one who crosses Team Aqua gets any mercy, not even kids!" + 1: "Não pegamos leve com quem se mete com a Equipe Aqua, nem mesmo crianças!", + 2: "Grrr... You've got some nerve meddling with Team Aqua!", + 3: "You're about to get soaked! And not just from my water Pokémon!", + 4: "We, Team Aqua, exist for the good of all!", + 5: "Prepare to be washed away by the tides of my... uh, Pokémon! Yeah, my Pokémon!" }, "victory": { - 1: "You're kidding me!" + 1: "Tá de brincadeira!", + 2: "Arrgh, I didn't count on being meddled with by some meddling kid!", + 3: "I lost?! Guess I'll have to swim back to the hideout now...", + 4: "Oh, man, what a disaster... The boss is going to be furious...", + 5: "You beat me... Do you think the boss will make me walk the plank for this?" }, }, "galactic_grunt": { "encounter": { - 1: "Don't mess with Team Galactic!" + 1: "Não mexe com a Equipe Galáctica!", + 2: "Witness the power of our technology and the future we envision!", + 3: "In the name of Team Galactic, I'll eliminate anyone who stands in our way!", + 4: "Get ready to lose!", + 5: "Hope you're ready for a cosmic beatdown!" }, "victory": { - 1: "Shut down..." + 1: "Fui amassado...", + 2: "This setback means nothing in the grand scheme.", + 3: "Our plans are bigger than this defeat.", + 4: "How?!", + 5: "Note to self: practice Pokémon battling, ASAP." }, }, "plasma_grunt": { "encounter": { - 1: "We won't tolerate people who have different ideas!" + 1: "Não toleramos pessoas que pensam diferente de nós!", + 2: "If I win against you, release your Pokémon!", + 3: "If you get in the way of Team Plasma, I'll take care of you!", + 4: "Team Plasma will liberate Pokémon from selfish humans like you!", + 5: "Our hairstyles are out of this world... but our battling skills? You'll find out soon enough." }, "victory": { - 1: "Plasmaaaaaaaaa!" + 1: "Plasmaaaaaaaaa!", + 2: "How could I lose...", + 3: "...What a weak Pokémon, I'll just have to go steal some better ones!", + 4: "Great plans are always interrupted.", + 5: "This is bad... Badbadbadbadbadbadbad! Bad for Team Plasma! Or Plasbad, for short!" }, }, "flare_grunt": { "encounter": { - 1: "Fashion is most important to us!" + 1: "Your Pokémon are no match for the elegance of Team Flare.", + 2: "Hope you brought your sunglasses, because things are about to get bright!", + 3: "Team Flare will cleanse the world of imperfection!", + 4: "Prepare to face the brilliance of Team Flare!", + 5: "Fashion is most important to us!" }, "victory": { - 1: "The future doesn't look bright for me." + 1: "The future doesn't look bright for me.", + 2: "Perhaps there's more to battling than I thought. Back to the drawing board.", + 3: "Gahh?! I lost?!", + 4: "Even in defeat, Team Flare's elegance shines through.", + 5: "You may have beaten me, but when I lose, I go out in style!" }, }, "rocket_boss_giovanni_1": { diff --git a/src/locales/de/dialogue.ts b/src/locales/de/dialogue.ts index 3687a538200..a84060143fc 100644 --- a/src/locales/de/dialogue.ts +++ b/src/locales/de/dialogue.ts @@ -602,51 +602,98 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: `Jetzt gibt es Ärger!… $und es kommt noch härter! $Wir wollen über die Erde regieren… - $und naja du kennst den Rest…!` + $und naja du kennst den Rest…!`, + 2: "Wir führen gerade eine große Operation durch. Hast du vor uns zu stören?", + 3: "Gib uns deine Pokémon, oder stelle dich dem Zorn von Team Rocket!", + 4: "Team Rocket wird seinen Plan zur Vollendung bringen, Aus dem Weg!", + 5: "Los, gib uns deine Pokémon. Wir brauchen sie für unseren Plan!" }, "victory": { - 1: "Das war mal wieder ein Schuss in den Ofen!" + 1: "Das war mal wieder ein Schuss in den Ofen!", + 2: "Dem Boss wird das aber nicht gefallen!", + 3: "Ich habe es vermasselt!", + 4: "Meine Kollegen werden das nicht tolerieren!", + 5: "Team Rocket wird wiederkehren! Das sage ich Jessie und James!" }, }, "magma_grunt": { "encounter": { - 1: "Keiner, der sich Team Magma in den Weg stellt, bekommt Gnade, nicht einmal Kinder!" + 1: "Keiner, der sich Team Magma in den Weg stellt, bekommt Gnade, nicht einmal Kinder!", + 2: "Störe besser nicht unsere Pläne! Wir formen die Welt nach unseren Vorstellungen!", + 3: "Du stehst uns im Weg! Team Magma hat keine Zeit für Störenfriede wie dich!", + 4: "Bereite dich auf die Hölle vor, denn es wird bald sehr heiß!", + 5: "Wir werden die Macht des Vulkans entfesseln! Es wird gewaltig sein! Mach dich bereit!" }, "victory": { - 1: "Wie kann das sein? Ich bin Teil vom mächtigen Team Magma! Wir wollen doch nur die Welt verbessern…" + 1: "Wie kann das sein? Ich bin Teil des mächtigen Team Magma! Wir streben nach der Verbesserung der Welt...", + 2: "Unglaublich, dass ich verloren habe! Mit meinen mächtigen Pokémon.", + 3: "Das kann nicht sein! Ich hab doch viel mehr Erfahrung als du!", + 4: "Verdammt... Ich hätte sofort in unser Versteck fliehen sollen...", + 5: "Du hast mich besiegt... Der Boss wird mich dafür zur Rechenschaft ziehen." }, }, "aqua_grunt": { "encounter": { 1: "Du willst dich also mit Team Aqua anlegen? Du traust dich ja was… Dich werfe ich über Bord!", + 2: "Du hast ganz schön Mut, dich mit Team Aqua anzulegen!", + 3: "Ich hoffe du hast einen Regenschirm dabei. Hier wird es jetzt nass!", + 4: "Wir, Team Aqua, existieren zum Wohle aller!", + 5: "Bereite dich darauf vor, von den Fluten meiner Pokémon weggespült zu werden!" }, "victory": { 1: "Vielleicht sollte ich wohl lieber selber über die Planke gehen…", + 2: "Arrgh, ich habe nicht damit gerechnet, von einer Landratte gestört zu werden!", + 3: "Ich habe verloren?! Ich schätze, ich muss jetzt zurück zum Versteck schwimmen...", + 4: "Oh Mann, was für eine Katastrophe... Der Boss wird wütend sein...", + 5: "Du hast mich besiegt... Meinst du, der Boss wird mich dafür kielholen lassen?" }, }, "galactic_grunt": { "encounter": { - 1: "Team Galaktik wird die Welt in eine bessere Welt verwandeln! Und du wirst uns nicht aufhalten!" + 1: "Team Galaktik wird die Welt in eine bessere verwandeln! Und du wirst uns nicht aufhalten!", + 2: "Erlebe die Macht unserer Technologie und die Zukunft, die wir uns vorstellen!", + 3: "Im Namen von Team Galaktik werde ich jeden beseitigen, der uns im Weg steht!", + 4: "Mach dich bereit zu verlieren!", + 5: "Hoffentlich bist du bereit für eine kosmische Niederlage!" }, "victory": { - 1: "Zyrus wird uns für diese Niederlage bestrafen…" + 1: "Zyrus wird uns für diese Niederlage bestrafen…", + 2: "Dieser Rückschlag bedeutet nichts in Hinsicht unseres großen Plans.", + 3: "Unsere Pläne sind größer als diese Niederlage.", + 4: "Wie ist das möglich?!", + 5: "Notiz an mich selbst: Pokémon-Kämpfe üben, so bald wie möglich." }, }, "plasma_grunt": { "encounter": { - 1: "Pokémon sollten frei sein! Team Plasma wird sie befreien!" + 1: "Pokémon sollten frei sein! Team Plasma wird sie befreien!", + 2: "Wenn ich gegen dich gewinne, lass deine Pokémon frei!", + 3: "Wenn du Team Plasma im Weg stehst, werde ich mich um dich kümmern!", + 4: "Team Plasma wird Pokémon von egoistischen Menschen wie dir befreien!", + 5: "Lass dich von unserem Aussehen nicht täuschen. Unsere Kampffähigkeiten sind überragend!" }, "victory": { - 1: "Wie konnte ich verlieren? Ich dachte, ich würde die Welt retten…" + 1: "Wie konnte ich verlieren? Ich dachte, ich würde die Welt retten...", + 2: "Wie konnte ich nur verlieren...", + 3: "...Dieses Pokémon ist zu schwach, ich werde stärkere beschaffen müssen!", + 4: "Große Pläne stoßen immer auf Hindernisse.", + 5: "Das ist ein schwerer Rückschlag für Team Plasma..." }, }, "flare_grunt": { "encounter": { - 1: `Ich bin ein Mitglied von Team Flare! Das sieht man mir doch an. Mein Stil ist unverkennbar! - $Du kannst definitiv ein Umstyling gebrauchen!` + 1: "Deine Pokémon haben keine Chance gegen die Überlegenheit von Team Flare.", + 2: "Mach dich bereit, denn gleich wird es hier lichterloh brennen!", + 3: "Team Flare wird die Welt von allen Makeln befreien!", + 4: "Bereite dich auf die unvergleichliche Macht von Team Flare vor!", + 5: "Unsere Mission steht über allem, sogar über der Mode!" }, "victory": { - 1: "Stil ist wohl doch nicht alles…" + 1: "Diese Niederlage wirft einen Schatten auf meine Zukunft.", + 2: "Es scheint, dass ich meine Strategien überdenken muss. Zurück ans Reißbrett.", + 3: "Unglaublich?! Ich habe verloren?!", + 4: "Selbst in der Niederlage bleibt Team Flare unübertroffen in seiner Eleganz.", + 5: "Du hast mich besiegt, aber Team Flare wird immer in Glanz und Stil erstrahlen." }, }, "rocket_boss_giovanni_1": { diff --git a/src/locales/en/dialogue.ts b/src/locales/en/dialogue.ts index bc06e935874..715f245e518 100644 --- a/src/locales/en/dialogue.ts +++ b/src/locales/en/dialogue.ts @@ -583,51 +583,99 @@ export const PGMdialogue: DialogueTranslationEntries = { }, "rocket_grunt": { "encounter": { - 1: "Prepare for trouble!" + 1: "Prepare for trouble!", + 2: "We're pulling a big job here! Get lost, kid!", + 3: "Hand over your Pokémon, or face the wrath of Team Rocket!", + 4: "You're about to experience the true terror of Team Rocket!", + 5: "Hey, kid! Me am a Team Rocket member kind of guy!" //Use of wrong grammar is deliberate }, "victory": { - 1: "Team Rocket blasting off again!" + 1: "Team Rocket blasting off again!", + 2: "Oh no! I dropped the Lift Key!", + 3: "I blew it!", + 4: "My associates won't stand for this!", + 5: "You say what? Team Rocket bye-bye a go-go? Broken it is says you?" //Use of wrong grammar is deliberate. }, }, "magma_grunt": { "encounter": { - 1: " If you get in the way of Team Magma, don’t expect any mercy!" + 1: "If you get in the way of Team Magma, don’t expect any mercy!", + 2: "You'd better not interfere with our plans! We're making the world a better place!", + 3: "You're in the way! Team Magma has no time for kids like you!", + 4: "I hope you brought marshmallows because things are about to heat up!", + 5: "We're going to use the power of a volcano! It's gonna be... explosive! Get it? Heh heh!" }, "victory": { - 1: "Huh? I lost?!" + 1: "Huh? I lost?!", + 2: "I can't believe I lost! I even skipped lunch for this", + 3: "No way! You're just a kid!", + 4: "Urrrgh... I should've ducked into our hideout right away...", + 5: "You beat me... Do you think the boss will dock my pay for this?" }, }, "aqua_grunt": { "encounter": { - 1: "No one who crosses Team Aqua gets any mercy, not even kids!" + 1: "No one who crosses Team Aqua gets any mercy, not even kids!", + 2: "Grrr... You've got some nerve meddling with Team Aqua!", + 3: "You're about to get soaked! And not just from my water Pokémon!", + 4: "We, Team Aqua, exist for the good of all!", + 5: "Prepare to be washed away by the tides of my... uh, Pokémon! Yeah, my Pokémon!" }, "victory": { - 1: "You're kidding me!" + 1: "You're kidding me!", + 2: "Arrgh, I didn't count on being meddled with by some meddling kid!", + 3: "I lost?! Guess I'll have to swim back to the hideout now...", + 4: "Oh, man, what a disaster... The boss is going to be furious...", + 5: "You beat me... Do you think the boss will make me walk the plank for this?" }, }, "galactic_grunt": { "encounter": { - 1: "Don't mess with Team Galactic!" + 1: "Don't mess with Team Galactic!", + 2: "Witness the power of our technology and the future we envision!", + 3: "In the name of Team Galactic, I'll eliminate anyone who stands in our way!", + 4: "Get ready to lose!", + 5: "Hope you're ready for a cosmic beatdown!" }, "victory": { - 1: "Shut down..." + 1: "Shut down...", + 2: "This setback means nothing in the grand scheme.", + 3: "Our plans are bigger than this defeat.", + 4: "How?!", + 5: "Note to self: practice Pokémon battling, ASAP." }, }, "plasma_grunt": { "encounter": { - 1: "We won't tolerate people who have different ideas!" + 1: "We won't tolerate people who have different ideas!", + 2: "If I win against you, release your Pokémon!", + 3: "If you get in the way of Team Plasma, I'll take care of you!", + 4: "Team Plasma will liberate Pokémon from selfish humans like you!", + 5: "Our hairstyles are out of this world... but our battling skills? You'll find out soon enough." }, "victory": { - 1: "Plasmaaaaaaaaa!" + 1: "Plasmaaaaaaaaa!", + 2: "How could I lose...", + 3: "...What a weak Pokémon, I'll just have to go steal some better ones!", + 4: "Great plans are always interrupted.", + 5: "This is bad... Badbadbadbadbadbadbad! Bad for Team Plasma! Or Plasbad, for short!" }, }, "flare_grunt": { "encounter": { - 1: "Fashion is most important to us!" + 1: "Your Pokémon are no match for the elegance of Team Flare.", + 2: "Hope you brought your sunglasses, because things are about to get bright!", + 3: "Team Flare will cleanse the world of imperfection!", + 4: "Prepare to face the brilliance of Team Flare!", + 5: "Fashion is most important to us!" }, "victory": { - 1: "The future doesn't look bright for me." + 1: "The future doesn't look bright for me.", + 2: "Perhaps there's more to battling than I thought. Back to the drawing board.", + 3: "Gahh?! I lost?!", + 4: "Even in defeat, Team Flare's elegance shines through.", + 5: "You may have beaten me, but when I lose, I go out in style!" }, }, "rocket_boss_giovanni_1": { diff --git a/src/locales/es/dialogue.ts b/src/locales/es/dialogue.ts index 3620275f799..187127d1d39 100644 --- a/src/locales/es/dialogue.ts +++ b/src/locales/es/dialogue.ts @@ -582,50 +582,98 @@ export const PGMdialogue: DialogueTranslationEntries = { }, "rocket_grunt": { "encounter": { - 1: "¡Ríndete ahora, o prepárate para luchar!" + 1: "¡Ríndete ahora, o prepárate para luchar!", + 2: "We're pulling a big job here! Get lost, kid!", + 3: "Hand over your Pokémon, or face the wrath of Team Rocket!", + 4: "You're about to experience the true terror of Team Rocket!", + 5: "Hey, kid! Me am a Team Rocket member kind of guy!" //Use of wrong grammar is deliberate }, "victory": { - 1: "¡El Team Rocket despega de nuevo!" + 1: "¡El Team Rocket despega de nuevo!", + 2: "Oh no! I dropped the Lift Key!", + 3: "I blew it!", + 4: "My associates won't stand for this!", + 5: "You say what? Team Rocket bye-bye a go-go? Broken it is says you?" //Use of wrong grammar is deliberate. }, }, "magma_grunt": { "encounter": { - 1: "¡No esperes piedad si te interpones al Team Magma!" + 1: "¡No esperes piedad si te interpones al Team Magma!", + 2: "You'd better not interfere with our plans! We're making the world a better place!", + 3: "You're in the way! Team Magma has no time for kids like you!", + 4: "I hope you brought marshmallows because things are about to heat up!", + 5: "We're going to use the power of a volcano! It's gonna be... explosive! Get it? Heh heh!" }, "victory": { - 1: "¿Eh? ¿He perdido?" + 1: "¿Eh? ¿He perdido?", + 2: "I can't believe I lost! I even skipped lunch for this", + 3: "No way! You're just a kid!", + 4: "Urrrgh... I should've ducked into our hideout right away...", + 5: "You beat me... Do you think the boss will dock my pay for this?" }, }, "aqua_grunt": { "encounter": { - 1: "El Team Aqua no muestra piedad, ¡ni siquiera a los niños!" + 1: "El Team Aqua no muestra piedad, ¡ni siquiera a los niños!", + 2: "Grrr... You've got some nerve meddling with Team Aqua!", + 3: "You're about to get soaked! And not just from my water Pokémon!", + 4: "We, Team Aqua, exist for the good of all!", + 5: "Prepare to be washed away by the tides of my... uh, Pokémon! Yeah, my Pokémon!" }, "victory": { - 1: "¡Bromeas! ¡No me lo creo!" + 1: "¡Bromeas! ¡No me lo creo!", + 2: "Arrgh, I didn't count on being meddled with by some meddling kid!", + 3: "I lost?! Guess I'll have to swim back to the hideout now...", + 4: "Oh, man, what a disaster... The boss is going to be furious...", + 5: "You beat me... Do you think the boss will make me walk the plank for this?" }, }, "galactic_grunt": { "encounter": { - 1: "¡No desafíes al Equipo Galaxia, te arrepentirás!" + 1: "¡No desafíes al Equipo Galaxia, te arrepentirás!", + 2: "Witness the power of our technology and the future we envision!", + 3: "In the name of Team Galactic, I'll eliminate anyone who stands in our way!", + 4: "Get ready to lose!", + 5: "Hope you're ready for a cosmic beatdown!" }, "victory": { - 1: "Me callaste la boca..." + 1: "Me callaste la boca...", + 2: "This setback means nothing in the grand scheme.", + 3: "Our plans are bigger than this defeat.", + 4: "How?!", + 5: "Note to self: practice Pokémon battling, ASAP." }, }, "plasma_grunt": { "encounter": { - 1: "¡El Equipo Plasma no tolerará otros ideales!" + 1: "¡El Equipo Plasma no tolerará otros ideales!", + 2: "If I win against you, release your Pokémon!", + 3: "If you get in the way of Team Plasma, I'll take care of you!", + 4: "Team Plasma will liberate Pokémon from selfish humans like you!", + 5: "Our hairstyles are out of this world... but our battling skills? You'll find out soon enough." }, "victory": { - 1: "Plasmaaaaaaaaa!" + 1: "Plasmaaaaaaaaa!", + 2: "How could I lose...", + 3: "...What a weak Pokémon, I'll just have to go steal some better ones!", + 4: "Great plans are always interrupted.", + 5: "This is bad... Badbadbadbadbadbadbad! Bad for Team Plasma! Or Plasbad, for short!" }, }, "flare_grunt": { "encounter": { - 1: "¡La moda es lo más importante para nosotros!" + 1: "Your Pokémon are no match for the elegance of Team Flare.", + 2: "Hope you brought your sunglasses, because things are about to get bright!", + 3: "Team Flare will cleanse the world of imperfection!", + 4: "Prepare to face the brilliance of Team Flare!", + 5: "Fashion is most important to us!" }, "victory": { - 1: "Me temo que se me avecina un futuro oscuro..." + 1: "The future doesn't look bright for me.", + 2: "Perhaps there's more to battling than I thought. Back to the drawing board.", + 3: "Gahh?! I lost?!", + 4: "Even in defeat, Team Flare's elegance shines through.", + 5: "You may have beaten me, but when I lose, I go out in style!" }, }, "rocket_boss_giovanni_1": { diff --git a/src/locales/fr/dialogue.ts b/src/locales/fr/dialogue.ts index ecc80d2abaf..8a8707dc4e5 100644 --- a/src/locales/fr/dialogue.ts +++ b/src/locales/fr/dialogue.ts @@ -385,50 +385,98 @@ export const PGMdialogue: DialogueTranslationEntries = { }, "rocket_grunt": { "encounter": { - 1: "Nous sommes de retour !" + 1: "Nous sommes de retour !", + 2: "We're pulling a big job here! Get lost, kid!", + 3: "Hand over your Pokémon, or face the wrath of Team Rocket!", + 4: "You're about to experience the true terror of Team Rocket!", + 5: "Hey, kid! Me am a Team Rocket member kind of guy!" //Use of wrong grammar is deliberate }, "victory": { - 1: "Une fois de plus la Team Rocket s’envole vers d’autres cieux !" + 1: "Une fois de plus la Team Rocket s’envole vers d’autres cieux !", + 2: "Oh no! I dropped the Lift Key!", + 3: "I blew it!", + 4: "My associates won't stand for this!", + 5: "You say what? Team Rocket bye-bye a go-go? Broken it is says you?" //Use of wrong grammar is deliberate. }, }, "magma_grunt": { "encounter": { - 1: "N’espère pas recevoir de la pitié si tu te mets sur le chemin de la Team Magma !" + 1: "N’espère pas recevoir de la pitié si tu te mets sur le chemin de la Team Magma !", + 2: "You'd better not interfere with our plans! We're making the world a better place!", + 3: "You're in the way! Team Magma has no time for kids like you!", + 4: "I hope you brought marshmallows because things are about to heat up!", + 5: "We're going to use the power of a volcano! It's gonna be... explosive! Get it? Heh heh!" }, "victory": { - 1: "Je…?\nJ’ai perdu ?!" + 1: "Je…?\nJ’ai perdu ?!", + 2: "I can't believe I lost! I even skipped lunch for this", + 3: "No way! You're just a kid!", + 4: "Urrrgh... I should've ducked into our hideout right away...", + 5: "You beat me... Do you think the boss will dock my pay for this?" }, }, "aqua_grunt": { "encounter": { - 1: "Aucune pitié si tu te mets sur le chemin de la Team Aqua, même pour un gamin !" + 1: "Aucune pitié si tu te mets sur le chemin de la Team Aqua, même pour un gamin !", + 2: "Grrr... You've got some nerve meddling with Team Aqua!", + 3: "You're about to get soaked! And not just from my water Pokémon!", + 4: "We, Team Aqua, exist for the good of all!", + 5: "Prepare to be washed away by the tides of my... uh, Pokémon! Yeah, my Pokémon!" }, "victory": { - 1: "Comment ça ?" + 1: "Comment ça ?", + 2: "Arrgh, I didn't count on being meddled with by some meddling kid!", + 3: "I lost?! Guess I'll have to swim back to the hideout now...", + 4: "Oh, man, what a disaster... The boss is going to be furious...", + 5: "You beat me... Do you think the boss will make me walk the plank for this?" }, }, "galactic_grunt": { "encounter": { - 1: "Ne te mets pas en travers de la Team Galaxie !" + 1: "Ne te mets pas en travers de la Team Galaxie !", + 2: "Witness the power of our technology and the future we envision!", + 3: "In the name of Team Galactic, I'll eliminate anyone who stands in our way!", + 4: "Get ready to lose!", + 5: "Hope you're ready for a cosmic beatdown!" }, "victory": { - 1: "Désactivation…" + 1: "Désactivation…", + 2: "This setback means nothing in the grand scheme.", + 3: "Our plans are bigger than this defeat.", + 4: "How?!", + 5: "Note to self: practice Pokémon battling, ASAP." }, }, "plasma_grunt": { "encounter": { - 1: "Pas de quatiers à ceux qui ne suivent pas notre idéal !" + 1: "Pas de quatiers à ceux qui ne suivent pas notre idéal !", + 2: "If I win against you, release your Pokémon!", + 3: "If you get in the way of Team Plasma, I'll take care of you!", + 4: "Team Plasma will liberate Pokémon from selfish humans like you!", + 5: "Our hairstyles are out of this world... but our battling skills? You'll find out soon enough." }, "victory": { - 1: "Plasmaaaaaaaaa !" + 1: "Plasmaaaaaaaaa !", + 2: "How could I lose...", + 3: "...What a weak Pokémon, I'll just have to go steal some better ones!", + 4: "Great plans are always interrupted.", + 5: "This is bad... Badbadbadbadbadbadbad! Bad for Team Plasma! Or Plasbad, for short!" }, }, "flare_grunt": { "encounter": { - 1: "Le style et le bon gout, il n’y a que ça qui compte !" + 1: "Your Pokémon are no match for the elegance of Team Flare.", + 2: "Hope you brought your sunglasses, because things are about to get bright!", + 3: "Team Flare will cleanse the world of imperfection!", + 4: "Prepare to face the brilliance of Team Flare!", + 5: "Fashion is most important to us!" }, "victory": { - 1: "Mon futur me semble guère radieux." + 1: "The future doesn't look bright for me.", + 2: "Perhaps there's more to battling than I thought. Back to the drawing board.", + 3: "Gahh?! I lost?!", + 4: "Even in defeat, Team Flare's elegance shines through.", + 5: "You may have beaten me, but when I lose, I go out in style!" }, }, "rocket_boss_giovanni_1": { diff --git a/src/locales/it/dialogue.ts b/src/locales/it/dialogue.ts index 570bd089ff8..1089db4e6f8 100644 --- a/src/locales/it/dialogue.ts +++ b/src/locales/it/dialogue.ts @@ -582,50 +582,98 @@ export const PGMdialogue: DialogueTranslationEntries = { }, "rocket_grunt": { "encounter": { - 1: "Prepare for trouble!" + 1: "Prepare for trouble!", + 2: "We're pulling a big job here! Get lost, kid!", + 3: "Hand over your Pokémon, or face the wrath of Team Rocket!", + 4: "You're about to experience the true terror of Team Rocket!", + 5: "Hey, kid! Me am a Team Rocket member kind of guy!" //Use of wrong grammar is deliberate }, "victory": { - 1: "Team Rocket blasting off again!" + 1: "Team Rocket blasting off again!", + 2: "Oh no! I dropped the Lift Key!", + 3: "I blew it!", + 4: "My associates won't stand for this!", + 5: "You say what? Team Rocket bye-bye a go-go? Broken it is says you?" //Use of wrong grammar is deliberate. }, }, "magma_grunt": { "encounter": { - 1: " If you get in the way of Team Magma, don’t expect any mercy!" + 1: "If you get in the way of Team Magma, don’t expect any mercy!", + 2: "You'd better not interfere with our plans! We're making the world a better place!", + 3: "You're in the way! Team Magma has no time for kids like you!", + 4: "I hope you brought marshmallows because things are about to heat up!", + 5: "We're going to use the power of a volcano! It's gonna be... explosive! Get it? Heh heh!" }, "victory": { - 1: "Huh? I lost?!" + 1: "Huh? I lost?!", + 2: "I can't believe I lost! I even skipped lunch for this", + 3: "No way! You're just a kid!", + 4: "Urrrgh... I should've ducked into our hideout right away...", + 5: "You beat me... Do you think the boss will dock my pay for this?" }, }, "aqua_grunt": { "encounter": { - 1: "No one who crosses Team Aqua gets any mercy, not even kids!" + 1: "No one who crosses Team Aqua gets any mercy, not even kids!", + 2: "Grrr... You've got some nerve meddling with Team Aqua!", + 3: "You're about to get soaked! And not just from my water Pokémon!", + 4: "We, Team Aqua, exist for the good of all!", + 5: "Prepare to be washed away by the tides of my... uh, Pokémon! Yeah, my Pokémon!" }, "victory": { - 1: "You're kidding me!" + 1: "You're kidding me!", + 2: "Arrgh, I didn't count on being meddled with by some meddling kid!", + 3: "I lost?! Guess I'll have to swim back to the hideout now...", + 4: "Oh, man, what a disaster... The boss is going to be furious...", + 5: "You beat me... Do you think the boss will make me walk the plank for this?" }, }, "galactic_grunt": { "encounter": { - 1: "Don't mess with Team Galactic!" + 1: "Don't mess with Team Galactic!", + 2: "Witness the power of our technology and the future we envision!", + 3: "In the name of Team Galactic, I'll eliminate anyone who stands in our way!", + 4: "Get ready to lose!", + 5: "Hope you're ready for a cosmic beatdown!" }, "victory": { - 1: "Shut down..." + 1: "Shut down...", + 2: "This setback means nothing in the grand scheme.", + 3: "Our plans are bigger than this defeat.", + 4: "How?!", + 5: "Note to self: practice Pokémon battling, ASAP." }, }, "plasma_grunt": { "encounter": { - 1: "We won't tolerate people who have different ideas!" + 1: "We won't tolerate people who have different ideas!", + 2: "If I win against you, release your Pokémon!", + 3: "If you get in the way of Team Plasma, I'll take care of you!", + 4: "Team Plasma will liberate Pokémon from selfish humans like you!", + 5: "Our hairstyles are out of this world... but our battling skills? You'll find out soon enough." }, "victory": { - 1: "Plasmaaaaaaaaa!" + 1: "Plasmaaaaaaaaa!", + 2: "How could I lose...", + 3: "...What a weak Pokémon, I'll just have to go steal some better ones!", + 4: "Great plans are always interrupted.", + 5: "This is bad... Badbadbadbadbadbadbad! Bad for Team Plasma! Or Plasbad, for short!" }, }, "flare_grunt": { "encounter": { - 1: "Fashion is most important to us!" + 1: "Your Pokémon are no match for the elegance of Team Flare.", + 2: "Hope you brought your sunglasses, because things are about to get bright!", + 3: "Team Flare will cleanse the world of imperfection!", + 4: "Prepare to face the brilliance of Team Flare!", + 5: "Fashion is most important to us!" }, "victory": { - 1: "The future doesn't look bright for me." + 1: "The future doesn't look bright for me.", + 2: "Perhaps there's more to battling than I thought. Back to the drawing board.", + 3: "Gahh?! I lost?!", + 4: "Even in defeat, Team Flare's elegance shines through.", + 5: "You may have beaten me, but when I lose, I go out in style!" }, }, "rocket_boss_giovanni_1": { diff --git a/src/locales/ja/dialogue.ts b/src/locales/ja/dialogue.ts index 64e4028a912..e783ea14006 100644 --- a/src/locales/ja/dialogue.ts +++ b/src/locales/ja/dialogue.ts @@ -583,51 +583,98 @@ export const PGMdialogue: DialogueTranslationEntries = { }, "rocket_grunt": { "encounter": { - 1: "Prepare for trouble!" + 1: "Se prepara pra encrenca!", + 2: "We're pulling a big job here! Get lost, kid!", + 3: "Hand over your Pokémon, or face the wrath of Team Rocket!", + 4: "You're about to experience the true terror of Team Rocket!", + 5: "Hey, kid! Me am a Team Rocket member kind of guy!" //Use of wrong grammar is deliberate }, "victory": { - 1: "Team Rocket blasting off again!" + 1: "Equipe Rocket decolando de novo!", + 2: "Oh no! I dropped the Lift Key!", + 3: "I blew it!", + 4: "My associates won't stand for this!", + 5: "You say what? Team Rocket bye-bye a go-go? Broken it is says you?" //Use of wrong grammar is deliberate. }, }, "magma_grunt": { "encounter": { - 1: " If you get in the way of Team Magma, don’t expect any mercy!" + 1: "Se você se meter com a Equipe Magma, não teremos piedade!", + 2: "You'd better not interfere with our plans! We're making the world a better place!", + 3: "You're in the way! Team Magma has no time for kids like you!", + 4: "I hope you brought marshmallows because things are about to heat up!", + 5: "We're going to use the power of a volcano! It's gonna be... explosive! Get it? Heh heh!" }, "victory": { - 1: "Huh? I lost?!" + 1: "Ahn? Eu perdi?!", + 2: "I can't believe I lost! I even skipped lunch for this", + 3: "No way! You're just a kid!", + 4: "Urrrgh... I should've ducked into our hideout right away...", + 5: "You beat me... Do you think the boss will dock my pay for this?" }, }, - "aqua_grunt": { "encounter": { - 1: "No one who crosses Team Aqua gets any mercy, not even kids!" + 1: "Não pegamos leve com quem se mete com a Equipe Aqua, nem mesmo crianças!", + 2: "Grrr... You've got some nerve meddling with Team Aqua!", + 3: "You're about to get soaked! And not just from my water Pokémon!", + 4: "We, Team Aqua, exist for the good of all!", + 5: "Prepare to be washed away by the tides of my... uh, Pokémon! Yeah, my Pokémon!" }, "victory": { - 1: "You're kidding me!" + 1: "Tá de brincadeira!", + 2: "Arrgh, I didn't count on being meddled with by some meddling kid!", + 3: "I lost?! Guess I'll have to swim back to the hideout now...", + 4: "Oh, man, what a disaster... The boss is going to be furious...", + 5: "You beat me... Do you think the boss will make me walk the plank for this?" }, }, "galactic_grunt": { "encounter": { - 1: "Don't mess with Team Galactic!" + 1: "Não mexe com a Equipe Galáctica!", + 2: "Witness the power of our technology and the future we envision!", + 3: "In the name of Team Galactic, I'll eliminate anyone who stands in our way!", + 4: "Get ready to lose!", + 5: "Hope you're ready for a cosmic beatdown!" }, "victory": { - 1: "Shut down..." + 1: "Fui amassado...", + 2: "This setback means nothing in the grand scheme.", + 3: "Our plans are bigger than this defeat.", + 4: "How?!", + 5: "Note to self: practice Pokémon battling, ASAP." }, }, "plasma_grunt": { "encounter": { - 1: "We won't tolerate people who have different ideas!" + 1: "Não toleramos pessoas que pensam diferente de nós!", + 2: "If I win against you, release your Pokémon!", + 3: "If you get in the way of Team Plasma, I'll take care of you!", + 4: "Team Plasma will liberate Pokémon from selfish humans like you!", + 5: "Our hairstyles are out of this world... but our battling skills? You'll find out soon enough." }, "victory": { - 1: "Plasmaaaaaaaaa!" + 1: "Plasmaaaaaaaaa!", + 2: "How could I lose...", + 3: "...What a weak Pokémon, I'll just have to go steal some better ones!", + 4: "Great plans are always interrupted.", + 5: "This is bad... Badbadbadbadbadbadbad! Bad for Team Plasma! Or Plasbad, for short!" }, }, "flare_grunt": { "encounter": { - 1: "Fashion is most important to us!" + 1: "Your Pokémon are no match for the elegance of Team Flare.", + 2: "Hope you brought your sunglasses, because things are about to get bright!", + 3: "Team Flare will cleanse the world of imperfection!", + 4: "Prepare to face the brilliance of Team Flare!", + 5: "Fashion is most important to us!" }, "victory": { - 1: "The future doesn't look bright for me." + 1: "The future doesn't look bright for me.", + 2: "Perhaps there's more to battling than I thought. Back to the drawing board.", + 3: "Gahh?! I lost?!", + 4: "Even in defeat, Team Flare's elegance shines through.", + 5: "You may have beaten me, but when I lose, I go out in style!" }, }, "rocket_boss_giovanni_1": { diff --git a/src/locales/ko/dialogue.ts b/src/locales/ko/dialogue.ts index 81eee94e2dc..ed0b498abbc 100644 --- a/src/locales/ko/dialogue.ts +++ b/src/locales/ko/dialogue.ts @@ -582,50 +582,98 @@ export const PGMdialogue: DialogueTranslationEntries = { }, "rocket_grunt": { "encounter": { - 1: "트러블에 대비하도록!" + 1: "트러블에 대비하도록!", + 2: "우리는 위업을 이루는 중이라고! 저리 비켜, 꼬마 녀석!", + 3: "포켓몬을 넘기지 않겠다면, 로켓단이 징벌하겠다!", + 4: "로켓단의 진정한 공포를 보여주마!", + 5: "헤이, 키드! 미는 로켓단의 멤버라구요!" //Use of wrong grammar is deliberate }, "victory": { - 1: "로켓단은 다시 떠오를 거니까!" + 1: "로켓단은 다시 떠오를 거니까!", + 2: "이런! 엘리베이터 키를 떨어뜨렸어!", + 3: "실패했군!", + 4: "내 동료들이 가만히 있지 않을 거다!", + 5: "유 쎄이 왓? 로켓단이 바이바이? 유한테 브레이킹?" //Use of wrong grammar is deliberate }, }, "magma_grunt": { "encounter": { - 1: " 마그마단을 방해한다면, 자비는 없닷!" + 1: " 마그마단을 방해한다면, 자비는 없닷!", + 2: "계획을 방해하지 않는 게 좋을 거다! 우리는 세상을 더 나은 곳으로 만들고 있거든!", + 3: "방해꾼 녀석! 마그단은 너 같은 꼬마들을 상대할 시간이 없어!", + 4: "마시멜로를 갖고 있었으면 좋겠네. 왜냐하면… 곧 뜨거워질 테니까!", + 5: "화산의 힘을 사용할 거야! 그건 정말로… 폭발적일 테니까! 알아들었지? 헤헷!" }, "victory": { - 1: "하? 내가 졌어?!" + 1: "하? 내가 졌어?!", + 2: "내가 지다니! 이것 때문에 점심도 거르고 왔는데.", + 3: "말도 안돼! 넌 아직 어린애잖아!", + 4: "으윽… 당장 은신처로 숨을 걸 그랬나…", + 5: "네가 이겼어… 이것 때문에 보스가, 내 월급 깎으려나?" }, }, "aqua_grunt": { "encounter": { - 1: "아쿠아단을 넘본 사람에게는 자비는 없다, 꼬마도 마찬가지야!" + 1: "아쿠아단을 넘본 사람에게는 자비는 없다, 꼬마도 마찬가지야!", + 2: "쯧… 아쿠아단에 참견하다니 오지랖이 넓군!", + 3: "흠뻑 물을 뒤집어쓰게 될 거다! 내 물 포켓몬의 공격 뿐만이 아니야!", + 4: "우리, 아쿠아단은, 모두를 위해 존재한다!", + 5: "내가 떠밀… 아니, 파도에 떠내려갈 준비나 하라고! 내 포켓몬이 그렇게 만들 테니까 " }, "victory": { - 1: "말도 안돼!" + 1: "말도 안 돼!", + 2: "크윽, 참견쟁이 꼬마에게 당하다니!", + 3: "내가 졌다고?! 헤엄쳐서 은신처로 돌아가야겠군…", + 4: "이런, 완전 망했군… 보스가 화를 내실텐데…", + 5: "네가 이겼어… 이것 때문에 보스가, 나를 판자 위로 보내는 거 아냐?" }, }, "galactic_grunt": { "encounter": { - 1: "갤럭시단을 방해하지 마!" + 1: "갤럭시단을 방해하지 마!", + 2: "기술의 힘과 우리가 꿈꾸는 미래를 목격하라!", + 3: "갤럭시단으로서, 우리를 방해하는 자는 누구든 제거하겠다!", + 4: "질 준비나 하라고!", + 5: "우주에서 싸울 준비는 됐겠지!" }, "victory": { - 1: "사격 중지…… " + 1: "사격 중지…… ", + 2: "이런 좌절이라도, 우리의 큰 계획 앞엔 아무 의미도 못 돼.", + 3: "우리의 계획은 이번 패배보다 크거든.", + 4: "어떻게 한 거지?!", + 5: "메모해야겠군. 최대한 포켓몬 배틀을 ASAP으로 연습할 것." }, }, "plasma_grunt": { "encounter": { - 1: "다른 생각을 가진사람들은 용납하지 않겠다!" + 1: "다른 생각을 가진사람들은 용납하지 않겠다!", + 2: "내가 이기면, 네 포켓몬들을 놓아주도록 해!", + 3: "플라즈마단을 방해한다면, 내가 처리해주지!", + 4: "플라즈마단은 너 같은 이기적인 인간에게서 포켓몬을 해방할 것이다!", + 5: "우리 스타일링은 정말 대단하지… 배틀 실력은 어떻냐고? 곧 알게 될거야." }, "victory": { - 1: "플라-스마-!" + 1: "플라-스마-!", + 2: "내가 지다니…", + 3: "…포켓몬이 너무 약해, 더 좋은 포켓몬을 훔치러 가야겠군!", + 4: "훌륭한 계획은 항상 방해를 받는다니깐.", + 5: "이건 나빠… 나빠나빠나빠나빠나빠! 플라스마단에 나빠! 줄여서, 플라나빠!" }, }, "flare_grunt": { "encounter": { - 1: "패션이 우리한텐 가장 중요하다고!" + 1: "네 포켓몬, 플레어단의 우아함에 상대가 되지 않는다고.", + 2: "선글라스를 가져왔길 바랄게. 곧 밝게 빛날 테니까!", + 3: "플레어단이 세상의 불완전함을 정화할 거야!", + 4: "플레어단의 광채를 마주칠 준비는 됐겠지!", + 5: "패션이 우리한텐 가장 중요하다고!" }, "victory": { - 1: "미래가 밝아 보이질 않네." + 1: "미래가 밝아 보이질 않네.", + 2: "생각했던 것보다 전투에는 많은 요소가 있는 것 같군. 다시 계획을 짜야겠어.", + 3: "아앗?! 내가 졌어?!", + 4: "패배 속에서도, 플레어단의 우아함은 빛나고 있다고.", + 5: "네가 이긴 것 같네. 그렇지만 졌어도, 난 우아하게 퇴장할 거니까!" }, }, "rocket_boss_giovanni_1": { diff --git a/src/locales/pt_BR/dialogue.ts b/src/locales/pt_BR/dialogue.ts index 9e2fecd386a..88018c7fcda 100644 --- a/src/locales/pt_BR/dialogue.ts +++ b/src/locales/pt_BR/dialogue.ts @@ -582,50 +582,98 @@ export const PGMdialogue: DialogueTranslationEntries = { }, "rocket_grunt": { "encounter": { - 1: "Se prepara pra encrenca!" + 1: "Se prepara pra encrenca!", + 2: "We're pulling a big job here! Get lost, kid!", + 3: "Hand over your Pokémon, or face the wrath of Team Rocket!", + 4: "You're about to experience the true terror of Team Rocket!", + 5: "Hey, kid! Me am a Team Rocket member kind of guy!" //Use of wrong grammar is deliberate }, "victory": { - 1: "Equipe Rocket decolando de novo!" + 1: "Equipe Rocket decolando de novo!", + 2: "Oh no! I dropped the Lift Key!", + 3: "I blew it!", + 4: "My associates won't stand for this!", + 5: "You say what? Team Rocket bye-bye a go-go? Broken it is says you?" //Use of wrong grammar is deliberate. }, }, "magma_grunt": { "encounter": { - 1: "Se você se meter com a Equipe Magma, não teremos piedade!" + 1: "Se você se meter com a Equipe Magma, não teremos piedade!", + 2: "You'd better not interfere with our plans! We're making the world a better place!", + 3: "You're in the way! Team Magma has no time for kids like you!", + 4: "I hope you brought marshmallows because things are about to heat up!", + 5: "We're going to use the power of a volcano! It's gonna be... explosive! Get it? Heh heh!" }, "victory": { - 1: "Ahn? Eu perdi?!" + 1: "Ahn? Eu perdi?!", + 2: "I can't believe I lost! I even skipped lunch for this", + 3: "No way! You're just a kid!", + 4: "Urrrgh... I should've ducked into our hideout right away...", + 5: "You beat me... Do you think the boss will dock my pay for this?" }, }, "aqua_grunt": { "encounter": { - 1: "Não pegamos leve com quem se mete com a Equipe Aqua, nem mesmo crianças!" + 1: "Não pegamos leve com quem se mete com a Equipe Aqua, nem mesmo crianças!", + 2: "Grrr... You've got some nerve meddling with Team Aqua!", + 3: "You're about to get soaked! And not just from my water Pokémon!", + 4: "We, Team Aqua, exist for the good of all!", + 5: "Prepare to be washed away by the tides of my... uh, Pokémon! Yeah, my Pokémon!" }, "victory": { - 1: "Tá de brincadeira!" + 1: "Tá de brincadeira!", + 2: "Arrgh, I didn't count on being meddled with by some meddling kid!", + 3: "I lost?! Guess I'll have to swim back to the hideout now...", + 4: "Oh, man, what a disaster... The boss is going to be furious...", + 5: "You beat me... Do you think the boss will make me walk the plank for this?" }, }, "galactic_grunt": { "encounter": { - 1: "Não mexe com a Equipe Galáctica!" + 1: "Não mexe com a Equipe Galáctica!", + 2: "Witness the power of our technology and the future we envision!", + 3: "In the name of Team Galactic, I'll eliminate anyone who stands in our way!", + 4: "Get ready to lose!", + 5: "Hope you're ready for a cosmic beatdown!" }, "victory": { - 1: "Fui amassado..." + 1: "Fui amassado...", + 2: "This setback means nothing in the grand scheme.", + 3: "Our plans are bigger than this defeat.", + 4: "How?!", + 5: "Note to self: practice Pokémon battling, ASAP." }, }, "plasma_grunt": { "encounter": { - 1: "Não toleramos pessoas que pensam diferente de nós!" + 1: "Não toleramos pessoas que pensam diferente de nós!", + 2: "If I win against you, release your Pokémon!", + 3: "If you get in the way of Team Plasma, I'll take care of you!", + 4: "Team Plasma will liberate Pokémon from selfish humans like you!", + 5: "Our hairstyles are out of this world... but our battling skills? You'll find out soon enough." }, "victory": { - 1: "Plasmaaaaaaaaa!" + 1: "Plasmaaaaaaaaa!", + 2: "How could I lose...", + 3: "...What a weak Pokémon, I'll just have to go steal some better ones!", + 4: "Great plans are always interrupted.", + 5: "This is bad... Badbadbadbadbadbadbad! Bad for Team Plasma! Or Plasbad, for short!" }, }, "flare_grunt": { "encounter": { - 1: "A moda é a coisa mais importante pra gente!" + 1: "Your Pokémon are no match for the elegance of Team Flare.", + 2: "Hope you brought your sunglasses, because things are about to get bright!", + 3: "Team Flare will cleanse the world of imperfection!", + 4: "Prepare to face the brilliance of Team Flare!", + 5: "Fashion is most important to us!" }, "victory": { - 1: "O futuro não parece brilhante pra mim." + 1: "The future doesn't look bright for me.", + 2: "Perhaps there's more to battling than I thought. Back to the drawing board.", + 3: "Gahh?! I lost?!", + 4: "Even in defeat, Team Flare's elegance shines through.", + 5: "You may have beaten me, but when I lose, I go out in style!" }, }, "rocket_boss_giovanni_1": { diff --git a/src/locales/zh_CN/dialogue.ts b/src/locales/zh_CN/dialogue.ts index ebce2caada4..07d725a2aa8 100644 --- a/src/locales/zh_CN/dialogue.ts +++ b/src/locales/zh_CN/dialogue.ts @@ -581,50 +581,98 @@ export const PGMdialogue: DialogueTranslationEntries = { }, "rocket_grunt": { "encounter": { - 1: "你要有麻烦了!" + 1: "你要有麻烦了!", + 2: "我们要干大事了!\n闪一边去,小子!", + 3: "把你的宝可梦交过来,\n不然就尝尝火箭队的厉害!", + 4: "你准备好感受火箭队真正的恐怖了吗!", + 5: "喂,小子!俺可是火箭队滴!" //Use of wrong grammar is deliberate }, "victory": { - 1: "好讨厌的感觉啊!" + 1: "好讨厌的感觉啊!", + 2: "哎呀!不小心丢掉电梯钥匙啦!", + 3: "我搞砸了。", + 4: "我的伙计们不会放过你……!", + 5: "你说啥?俺们火箭队要玩完了?" //Use of wrong grammar is deliberate. }, }, "magma_grunt": { "encounter": { - 1: "如果你挡在熔岩队路上,那就别指望我们手下留情!" + 1: "如果你挡在熔岩队路上,那就别指望我们手下留情!", + 2: "你最好别妨碍我们的计划!\n我们会让世界变得更美好!", + 3: "少碍事!熔岩队没时间理你这样的小孩!", + 4: "你有棉花糖没?我来给你好好烤烤!", + 5: "我们会利用火山的力量!\n它马上要…爆发了!懂吗?嘿嘿嘿……" }, "victory": { - 1: "哈?我输了?!" + 1: "哈?我输了?!", + 2: "我怎么会输!我为了训练饭都不吃了!", + 3: "不会吧,不就是一个小孩!", + 4: "呃啊…我得赶快逃回基地…", + 5: "你打败我了…你觉得老大会扣我工资吗?" }, }, "aqua_grunt": { "encounter": { - 1: "即使是小孩,如果要和海洋队作对,也别指望我们手下留情!" + 1: "即使是小孩,如果要和海洋队作对,也别指望我们手下留情!", + 2: "嚯…你好大的胆子,敢惹我们海洋队!", + 3: "不仅是我的水系宝可梦,整片大海即将淹没你!", + 4: "我们海洋队,是为了大义!", + 5: "准备好被我的…呃…我宝可梦的海流冲走吧!" }, "victory": { - 1: "你在开玩笑吧?" + 1: "你在开玩笑吧?", + 2: "害,没想到这种小屁孩也要管我的闲事!", + 3: "我输了?看来我得自己游回基地了。", + 4: "不是吧,怎么会,老大要生气了……", + 5: "你打败了我…老大不会要让我上跳板吧……" }, }, "galactic_grunt": { "encounter": { - 1: "别惹银河队!" + 1: "别惹银河队!", + 2: "见识下我们的科技,和我们所设想的未来!", + 3: "以银河队之名,我会扫清一切挡路的人!", + 4: "准备输的一败涂地吧!", + 5: "希望你做好被宇宙力量碾压的准备。" }, "victory": { - 1: "停机了…" + 1: "停机了…", + 2: "从长远来看,这次的挫折不用在意。", + 3: "小失败不会影响我们的宏图伟业!", + 4: "咋回事!?", + 5: "个人记录:提升对战水平,优先级,高……" }, }, "plasma_grunt": { "encounter": { - 1: "异端不共戴天!" + 1: "异端不共戴天!", + 2: "要是我赢了你!就把你的宝可梦放生!", + 3: "要是敢和等离子队作对,我来好好关照你!", + 4: "等离子队会从你们这种自私的人手里解放宝可梦!", + 5: "我们的发型帅的一批,而我们的战斗水平呢,\n马上让你见识一下。" }, "victory": { - 1: "等离子子子子子子!" + 1: "等离子子子子子子!", + 2: "我怎么会输……", + 3: "…没用的家伙!我得去偷个厉害点的宝可梦!", + 4: "伟大的事业总会被人阻挠…", + 5: "烂完了…烂烂烂烂烂!等离子队烂了!\n说短点就是,等烂子队!" }, }, "flare_grunt": { "encounter": { - 1: "时尚最重要!" + 1: "你的宝可梦无法与闪焰队的优雅相提并论", + 2: "带个墨镜吧,别被我闪瞎狗眼了!", + 3: "闪焰队将净化这个不完美的世界!", + 4: "准备面对闪焰队的美!", + 5: "时尚对我们来说最重要!" }, "victory": { - 1: "未来一片黑暗啊…" + 1: "我的未来看起来并不明亮…", + 2: "这战斗比我想的更难搞,我得重头训练了。", + 3: "啊啊?我输了?!", + 4: "就算是在失败当中,闪焰队依旧优雅动人!", + 5: "你虽然打败了我,但是我输的也这么潇洒!" }, }, "rocket_boss_giovanni_1": { diff --git a/src/locales/zh_TW/dialogue.ts b/src/locales/zh_TW/dialogue.ts index 295d37509d4..cfe43317bb7 100644 --- a/src/locales/zh_TW/dialogue.ts +++ b/src/locales/zh_TW/dialogue.ts @@ -581,50 +581,98 @@ export const PGMdialogue: DialogueTranslationEntries = { }, "rocket_grunt": { "encounter": { - 1: "Prepare for trouble!" + 1: "Prepare for trouble!", + 2: "We're pulling a big job here! Get lost, kid!", + 3: "Hand over your Pokémon, or face the wrath of Team Rocket!", + 4: "You're about to experience the true terror of Team Rocket!", + 5: "Hey, kid! Me am a Team Rocket member kind of guy!" //Use of wrong grammar is deliberate }, "victory": { - 1: "Team Rocket blasting off again!" + 1: "Team Rocket blasting off again!", + 2: "Oh no! I dropped the Lift Key!", + 3: "I blew it!", + 4: "My associates won't stand for this!", + 5: "You say what? Team Rocket bye-bye a go-go? Broken it is says you?" //Use of wrong grammar is deliberate. }, }, "magma_grunt": { "encounter": { - 1: " If you get in the way of Team Magma, don’t expect any mercy!" + 1: "If you get in the way of Team Magma, don’t expect any mercy!", + 2: "You'd better not interfere with our plans! We're making the world a better place!", + 3: "You're in the way! Team Magma has no time for kids like you!", + 4: "I hope you brought marshmallows because things are about to heat up!", + 5: "We're going to use the power of a volcano! It's gonna be... explosive! Get it? Heh heh!" }, "victory": { - 1: "Huh? I lost?!" + 1: "Huh? I lost?!", + 2: "I can't believe I lost! I even skipped lunch for this", + 3: "No way! You're just a kid!", + 4: "Urrrgh... I should've ducked into our hideout right away...", + 5: "You beat me... Do you think the boss will dock my pay for this?" }, }, "aqua_grunt": { "encounter": { - 1: "No one who crosses Team Aqua gets any mercy, not even kids!" + 1: "No one who crosses Team Aqua gets any mercy, not even kids!", + 2: "Grrr... You've got some nerve meddling with Team Aqua!", + 3: "You're about to get soaked! And not just from my water Pokémon!", + 4: "We, Team Aqua, exist for the good of all!", + 5: "Prepare to be washed away by the tides of my... uh, Pokémon! Yeah, my Pokémon!" }, "victory": { - 1: "You're kidding me!" + 1: "You're kidding me!", + 2: "Arrgh, I didn't count on being meddled with by some meddling kid!", + 3: "I lost?! Guess I'll have to swim back to the hideout now...", + 4: "Oh, man, what a disaster... The boss is going to be furious...", + 5: "You beat me... Do you think the boss will make me walk the plank for this?" }, }, "galactic_grunt": { "encounter": { - 1: "Don't mess with Team Galactic!" + 1: "Don't mess with Team Galactic!", + 2: "Witness the power of our technology and the future we envision!", + 3: "In the name of Team Galactic, I'll eliminate anyone who stands in our way!", + 4: "Get ready to lose!", + 5: "Hope you're ready for a cosmic beatdown!" }, "victory": { - 1: "Shut down..." + 1: "Shut down...", + 2: "This setback means nothing in the grand scheme.", + 3: "Our plans are bigger than this defeat.", + 4: "How?!", + 5: "Note to self: practice Pokémon battling, ASAP." }, }, "plasma_grunt": { "encounter": { - 1: "We won't tolerate people who have different ideas!" + 1: "We won't tolerate people who have different ideas!", + 2: "If I win against you, release your Pokémon!", + 3: "If you get in the way of Team Plasma, I'll take care of you!", + 4: "Team Plasma will liberate Pokémon from selfish humans like you!", + 5: "Our hairstyles are out of this world... but our battling skills? You'll find out soon enough." }, "victory": { - 1: "Plasmaaaaaaaaa!" + 1: "Plasmaaaaaaaaa!", + 2: "How could I lose...", + 3: "...What a weak Pokémon, I'll just have to go steal some better ones!", + 4: "Great plans are always interrupted.", + 5: "This is bad... Badbadbadbadbadbadbad! Bad for Team Plasma! Or Plasbad, for short!" }, }, "flare_grunt": { "encounter": { - 1: "Fashion is most important to us!" + 1: "Your Pokémon are no match for the elegance of Team Flare.", + 2: "Hope you brought your sunglasses, because things are about to get bright!", + 3: "Team Flare will cleanse the world of imperfection!", + 4: "Prepare to face the brilliance of Team Flare!", + 5: "Fashion is most important to us!" }, "victory": { - 1: "The future doesn't look bright for me." + 1: "The future doesn't look bright for me.", + 2: "Perhaps there's more to battling than I thought. Back to the drawing board.", + 3: "Gahh?! I lost?!", + 4: "Even in defeat, Team Flare's elegance shines through.", + 5: "You may have beaten me, but when I lose, I go out in style!" }, }, "rocket_boss_giovanni_1": { From c70cf871999ce000f7e2e7fb4d31a1989ab2b7e7 Mon Sep 17 00:00:00 2001 From: Yonmaru40 <47717431+40chyan@users.noreply.github.com> Date: Thu, 8 Aug 2024 11:06:57 +0800 Subject: [PATCH 026/282] [Localization] Zh_cn adding translation 8/8 (#3425) * Update achv.ts * Update dialogue.ts * Update filter-bar.ts * Update trainers.ts * Update starter-select-ui-handler.ts --- src/locales/zh_CN/achv.ts | 4 +- src/locales/zh_CN/dialogue.ts | 214 +++++++++--------- src/locales/zh_CN/filter-bar.ts | 18 +- .../zh_CN/starter-select-ui-handler.ts | 2 +- src/locales/zh_CN/trainers.ts | 54 ++--- 5 files changed, 146 insertions(+), 146 deletions(-) diff --git a/src/locales/zh_CN/achv.ts b/src/locales/zh_CN/achv.ts index e2355342ab6..303beeffea3 100644 --- a/src/locales/zh_CN/achv.ts +++ b/src/locales/zh_CN/achv.ts @@ -170,8 +170,8 @@ export const PGMachv: AchievementTranslationEntries = { description: "在经典模式中通关游戏", }, "UNEVOLVED_CLASSIC_VICTORY": { - name: "Bring Your Child To Work Day", - description: "Beat the game in Classic Mode with at least one unevolved party member." + name: "带孩子来上班", + description: "通关经典模式时队伍中至少有一名未进化的宝可梦" }, "MONO_GEN_ONE": { diff --git a/src/locales/zh_CN/dialogue.ts b/src/locales/zh_CN/dialogue.ts index 07d725a2aa8..20d1d0d6040 100644 --- a/src/locales/zh_CN/dialogue.ts +++ b/src/locales/zh_CN/dialogue.ts @@ -384,199 +384,199 @@ export const PGMdialogue: DialogueTranslationEntries = { }, "archer": { "encounter": { - 1: "Before you go any further, let's see how you far against us, Team Rocket!", - 2: "I have received reports that your skills are not insignificant. Let's see if they are true.", - 3: "I am Archer, an Admin of Team Rocket. And I do not go easy on enemies of our organization." + 1: "在你继续前进之前,\n让我看看你要如何和对付火箭队。", + 2: "我收到报告说你的实力与众不同,\n就让我来看看这是否属实吧。", + 3: "我是阿波罗,火箭对的干部。\n我不会对组织的敌人手软。" }, "victory": { - 1: "What a blunder!", - 2: "With my current skills, I was not up to the task after all.", - 3: "F-forgive me, Giovanni... For me to be defeated by a mere trainer..." + 1: "大失误……", + 2: "以我现在的实力,无法胜任我的任务……", + 3: "原……谅我,坂木。\n我竟被一名训练师打败了。." }, }, "ariana": { "encounter": { - 1: `Hold it right there! We can't someone on the loose." - $It's harmful to Team Rocket's pride, you see.`, - 2: `I don't know or care if what I'm doing is right or wrong... - $I just put my faith in Giovanni and do as I am told`, - 3: "Your trip ends here. I'm going to take you down!" + 1: `站住!我们可不能放过你!" + $这会损伤火箭对的名誉,明白吗?`, + 2: `我不知道也不想知道我的所作所为正确与否… + $我只要遵从坂木老大的指令就可以了!`, + 3: "你的旅途到此为止了,我会把你狠狠扳倒!" }, "victory": { - 1: `Tch, you really are strong. It's too bad. - $If you were to join Team Rocket, you could become an Executive.`, - 2: "I... I'm shattered...", - 3: "Aaaieeeee! This can't be happening! I fought hard, but I still lost…" + 1: `切,你好强,可恶。 + $如果你加入火箭队,肯定能成为干部。`, + 2: "好……好崩溃……", + 3: "嗯啊啊!这不可能!我使出全力还是输了!" }, }, "proton": { "encounter": { - 1: "What do you want? If you interrupt our work, don't expect any mercy!", - 2: `What do we have here? I am often labeled as the scariest and cruelest guy in Team Rocket… - $I strongly urge you not to interfere with our business!`, - 3: "I am Proton, an Admin of Team Rocket. I am here to put an end to your meddling!" + 1: "你想干什么?如果你要妨碍我们的事业,我可不会手下留情。", + 2: `你在这干什么?别人总说我是火箭队里最残忍和恐怖的人… + $我强烈推荐你别来碍我们的事!`, + 3: "我是兰斯,火箭队的干部。就让来扫除你对我们的阻挠。" }, "victory": { - 1: "The fortress came down!", - 2: "You may have won this time… But all you did was make Team Rocket's wrath grow…", - 3: "I am defeated… But I will not forget this!" + 1: "我的防线崩溃了……", + 2: "你虽然这次赢了,但是这只是让火箭队的怒火继续燃烧!", + 3: "我输了…但是我不会忘记的。" }, }, "petrel": { "encounter": { - 1: `Muhahaha, we've been waiting for you. Me? You don't know who I am? It is me, Giovanni. - $The majestic Giovanni himself! Wahahaha! …Huh? I don't sound anything like Giovanni? - $I don't even look like Giovanni? How come? I've worked so hard to mimic him!`, - 2: "I am Petrel, an Admin of Team Rocket. I will not allow you to interfere with our plans!", - 3: "Rocket Executive Petrel will deal with this intruder!" + 1: `哇哈哈哈,我们一直在等你。我?你不知道我是谁?是我,坂木啊。 + $伟大的坂木大人本人!哇哈哈哈!…啊?我听起来不像坂木吗? + $我连看起来都不像?怎么会呢,我可认真的变装了!`, + 2: "我是拉姆达,火箭队的干部。我不会允许你干涉我们的计划!", + 3: "火箭队干部拉姆达来会会这个入侵者!" }, "victory": { - 1: "OK, OK. I'll tell you where he is.", - 2: "I… I couldn't do a thing… Giovanni, please forgive me…", - 3: "No, I can't let this affect me. I have to inform the others…" + 1: "好好好,我会说他在哪的", + 2: "我……我什么也做不了……坂木,请原谅我……", + 3: "不,我不能慌了神,必须通知其他人…" }, }, "tabitha": { "encounter": { - 1: "Hehehe! So you've come all the way here! But you're too late!", - 2: `Hehehe... Got here already, did you? We underestimated you! But this is it! - $I'm a cut above the Grunts you've seen so far. I'm not stalling for time. - $I'm going to pulverize you!`, - 3: "I'm going to give you a little taste of pain! Resign yourself to it!" + 1: "呵呵呵!原来你都一路来到这里了!但你来晚了!", + 2: `呵呵呵……你终于来了?我们小瞧你了,没不过事! + $我比你见过的所有队员都要厉害,我可不会拖延时间。 + $我会把你碾碎!`, + 3: "我要让你尝尝痛苦的滋味!认命吧!" }, "victory": { - 1: `Hehehe! You might have beaten me, but you don't stand a chance against the Boss! - $If you get lost now, you won't have to face a sound whipping!`, - 2: "Hehehe... So, I lost, too...", - 3: "Ahya! How could this be? For an Admin like me to lose to some random trainer..." + 1: `呵呵呵!虽然你打败了我,但你根本没机会打败老大! + $如果你现在输了,你就不用面对那样严厉的鞭笞了!`, + 2: "呵呵呵……所以,我也输了……", + 3: "啊哈!怎么会这样?像我这样的干部\n竟然输给了一个随处可见的训练师……" }, }, "courtney": { "encounter": { - 1: "The thing...The thing that you hold...That is what... That's what we of Team Magma seek...", - 2: "... Well then...Deleting...", - 3: "...Ha. ...Analyzing... ...Hah♪" + 1: "那个东西……你所拥有的那个东西……\n那就是……那就是我们熔岩队所寻找的东西……", + 2: "……那么……删除记忆……", + 3: "……哈……分析中……啊哈♪" }, "victory": { - 1: "... ...Change...the world.", - 2: `As anticipated. Unanticipated. You. Target lock...completed. - $Commencing...experiment. You. Forever. Aha... ♪`, - 3: "...Again? That's unanticipated. ...I knew it. You...are interesting! ...Haha. ♪" + 1: "……改变……世界。", + 2: `如预期。出乎意料。目标锁定…锁定你……完成。 + $开始……实验。材料是你…永远…啊哈……♪`, + 3: "……又来了?出乎意料……我就知道。你……很有趣!……啊哈哈!♪" }, }, "shelly": { "encounter": { - 1: `Ahahahaha! You're going to meddle in Team Aqua's affairs? - $You're either absolutely fearless, simply ignorant, or both! - $You're so cute, you're disgusting! I'll put you down`, - 2: "What's this? Who's this spoiled brat?", - 3: "Cool your jets. Be patient. I'll crush you shortly." + 1: `啊哈哈哈哈!你要插手海洋队的事? + $你要么是绝对无畏,要么就是无知,或者两者兼有! + $你太可爱了,太恶心了!我要把你打倒!`, + 2: "怎么回事?这个小鬼头是谁?", + 3: "冷静点,耐心点。我很快就会把你击溃。" }, "victory": { - 1: `Ahahahaha! We got meddled with unexpectedly! We're out of options. - $We'll have to pull out. But this isn't the last you'll see of Team Aqua! - $We have other plans! Don't you forget it!`, - 2: "Ahhh?! Did I go too easy on you?!", - 3: `Uh. Are you telling me you've upped your game even more during the fight? - $You're a brat with a bright future… My Pokémon and I don't have any strength left to fight… - $Go on… Go and be destroyed by Archie.` + 1: `啊哈哈哈哈!我们意外地被人干扰了!我们别无选择。 + $不得不撤退了,但这会不是你最后一次面对海洋队! + $我们还有其他计划!别忘了!`, + 2: "啊?!我是不是对你太温柔了?!", + 3: `呃…难道在对战中你也一刻不停地在变强吗? + $你真是个前途光明的小鬼……\n我和我的宝可梦已经没有任何力量去战斗了…… + $继续吧……准备去被水梧桐摧毁吧。` }, }, "matt": { "encounter": { - 1: "Hoohahaha! What, you got a screw loose or something? Look at you, little Makuhita person!", - 2: "Oho! You! You're that funny kid!", - 3: "What are you doing here? Did you follow us?" + 1: "嚯!哈哈哈!怎么,你是不是脑子不正常了?\n看看你,像个幕下力士!", + 2: "“哦吼!你!你真是个有趣的孩子!", + 3: "你在这里干什么?你跟踪我们了吗?" }, "victory": { - 1: "All right then, until the Boss has time for you, I'll be your opponent!", - 2: `I can feel it! I can feel it, all right! The strength coming offa you! - $More! I still want more! But looks like we're outta time...`, - 3: "That was fun! I knew you'd show me a good time! I look forward to facing you again someday!" + 1: "好吧,在老大有时间对付你之前,我来成为你的对手!", + 2: `我能感觉到!我感觉到了,没错!你身上散发出的力量! + $更多!还想要更多!但看起来我们没时间了……`, + 3: "真有趣!我就知道你会让我尽兴的!\n我期待有一天再次面对你!" }, }, "mars": { "encounter": { - 1: "I'm Mars, one of Team Galactic's top Commanders.", - 2: "Team Galactic's vision for the future is unwavering. Opposition will be crushed without mercy!", - 3: "Feeling nervous? You should be!" + 1: "我是伙星,银河队的顶级干部之一。", + 2: "银河队对未来的愿景坚定不移。\n反对者将被无情地粉碎!", + 3: "“紧张吗?你是该感到紧张了!" }, "victory": { - 1: "This can't be happening! How did I lose?!", - 2: "You have some skill, I'll give you that.", - 3: "Defeated... This was a costly mistake." + 1: "这不可能!我怎么会输?!", + 2: "你很有本事,我承认。", + 3: "输了……犯了一个代价高昂的大错。" } }, "jupiter": { "encounter": { - 1: "Jupiter, Commander of Team Galactic, at your service.", - 2: "Resistance is futile. Team Galactic will prevail!", - 3: "You're trembling... scared already?" + 1: "岁星,银河队干部,为您效劳。", + 2: "抵抗是徒劳的。银河队必将获胜!", + 3: "你在发抖啊……已经害怕了吗?" }, "victory": { - 1: "No way... I lost?!", - 2: "Impressive, you've got guts!", - 3: "Losing like this... How embarrassing." + 1: "不会吧……我输了?!", + 2: "厉害,你胆子真大!", + 3: "输成这样……真丢人。" } }, "saturn": { "encounter": { - 1: "I am Saturn, Commander of Team Galactic.", - 2: "Our mission is absolute. Any hindrance will be obliterated!", - 3: "Is that fear I see in your eyes?" + 1: "我是镇星,银河队的干部。", + 2: "我们的使命是绝对的,任何阻碍都将被消灭!", + 3: "我从你的眼中看到的是恐惧吗?" }, "victory": { - 1: "Impossible... Defeated by you?!", - 2: "You have proven yourself a worthy adversary.", - 3: "Bestowed in defeat... This is unacceptable." + 1: "不可能……被你打败了?!", + 2: "你证明了自己是一个值得尊敬的对手。", + 3: "失败的苦涩……难以接受……。" }}, "zinzolin": { "encounter": { - 1: "You could become a threat to Team Plasma, so we will eliminate you here and now!", - 2: "Oh, for crying out loud... I didn't expect to have to battle in this freezing cold!", - 3: "You're an impressive Trainer to have made it this far. But it ends here." + 1: "你可能会对等离子队构成威胁,所以我们现在就消灭你!", + 2: "哦,天哪……我没想到要在这么冷的天气里战斗!", + 3: "能走到今天这一步,你真是个了不起的训练师。\n但一切到此结束。" }, "victory": { - 1: "Ghetsis... I have failed you...", - 2: "It's bitter cold. I'm shivering. I'm suffering. Yet, I still stand victorious.", - 3: "Hmph. You're a smarter Trainer than I expected, but not smart enough." + 1: "魁奇思大人……我让你失望了……", + 2: "好冷,我不仅发抖,还要遭罪。", + 3: "哼。你比我想象的要聪明,但还不够。" } }, "rood": { "encounter": { - 1: "You are a threat to Team Plasma. We cannot let you walk away from here and now!", - 2: "Oh, this icy wind... I never thought I'd have to fight here!", - 3: "You are a remarkable Trainer to have made it this far. But this is where it ends." + 1: "你对等离子队是个威胁。我们现在不能让你离开这里!", + 2: "哦,这寒风……我从没想过我必须在这里战斗!", + 3: "能走到今天这一步,你是一位了不起的训练师,但这就是你的结局了。" }, "victory": { - 1: "Ghetsis... I have failed my mission...", - 2: "The cold is piercing. I'm shivering. I'm suffering. Yet, I have triumphed.", - 3: "Hm. You are a talented Trainer, but unfortunately not talented enough." + 1: "魁奇思大人……我的任务失败了", + 2: "寒风刺骨。我瑟瑟发抖。我痛苦不堪。", + 3: "嗯,你是很有才。但是要打败等离子队还不够……!" } }, "xerosic": { "encounter": { - 1: "Ah ha ha! It would be my pleasure. Come on, little Trainer! Let's see what you've got!", - 2: "Hmm... You're more powerful than you look. I wonder how much energy there is inside you.", - 3: "I've been waiting for you! I need to do a little research on you! Come, let us begin!" + 1: "啊哈哈!我很乐意。\n来吧,小训练师!让我们看看你有什么本事!", + 2: "嗯……你比看上去更强大。\n我想知道你体内有多少能量。", + 3: "我一直在等你!我需要对你做一点研究!\n来吧,我们开始吧!" }, "victory": { - 1: "Ah, you're quite strong. Oh yes—very strong, indeed.", - 2: "Ding-ding-ding! You did it! To the victor go the spoils!", - 3: "Wonderful! Amazing! You have tremendous skill and bravery!" + 1: "啊,你好强大啊……嗯……确实非常强大。", + 2: "叮叮叮!你成功了!\n战利品归胜利者!", + 3: "太棒了!太神奇了!\n你的技巧和勇气都无与伦比!" } }, "bryony": { "encounter": { - 1: "I am Bryony, and it would be my pleasure to battle you. Show me what you've got.", - 2: "Impressive... You're more powerful than you appear. Let's see the true extent of your energy.", - 3: "I've anticipated your arrival. It's time for a little test. Shall we begin?" + 1: "我是芭菈,能与你一战是我的荣幸。\n让我看看你的实力。", + 2: "令人印象深刻……你比你看上去的还要强大。\n让我们看看你真正的实力。", + 3: "我预料到了你的到来。\n是时候进行一个小实验了,我们开始吧?" }, "victory": { - 1: "You're quite strong. Oh yes—very strong, indeed.", - 2: "Ding-ding-ding! You've done well. Victory is yours.", - 3: "Wonderful! Remarkable! Your skill and bravery are commendable." + 1: "你很强大。哦,嗯嗯!确实非常强大", + 2: "叮叮叮!你做得很好。胜利属于你。", + 3: "太棒了!了不起!你的技巧和勇气值得称赞。" } }, "rocket_grunt": { diff --git a/src/locales/zh_CN/filter-bar.ts b/src/locales/zh_CN/filter-bar.ts index 4ee38521a0a..6f484fc8635 100644 --- a/src/locales/zh_CN/filter-bar.ts +++ b/src/locales/zh_CN/filter-bar.ts @@ -13,18 +13,18 @@ export const filterBar: SimpleTranslationEntries = { "passive": "被动", "passiveUnlocked": "被动解锁", "passiveLocked": "被动未解锁", - "costReduction": "Cost Reduction", - "costReductionUnlocked": "Cost Reduction Unlocked", - "costReductionLocked": "Cost Reduction Locked", + "costReduction": "费用降低", + "costReductionUnlocked": "已降费", + "costReductionLocked": "未降费", "ribbon": "缎带", "hasWon": "有缎带", "hasNotWon": "无缎带", - "hiddenAbility": "Hidden Ability", - "hasHiddenAbility": "Hidden Ability - Yes", - "noHiddenAbility": "Hidden Ability - No", - "pokerus": "Pokerus", - "hasPokerus": "Pokerus - Yes", - "noPokerus": "Pokerus - No", + "hiddenAbility": "梦特", + "hasHiddenAbility": "有梦特", + "noHiddenAbility": "无梦特", + "pokerus": "病毒", + "hasPokerus": "有病毒", + "noPokerus": "无病毒", "sortByNumber": "编号", "sortByCost": "费用", "sortByCandies": "糖果", diff --git a/src/locales/zh_CN/starter-select-ui-handler.ts b/src/locales/zh_CN/starter-select-ui-handler.ts index b8c491288e1..c9c1cf501ef 100644 --- a/src/locales/zh_CN/starter-select-ui-handler.ts +++ b/src/locales/zh_CN/starter-select-ui-handler.ts @@ -7,7 +7,7 @@ import { SimpleTranslationEntries } from "#app/interfaces/locales"; */ export const starterSelectUiHandler: SimpleTranslationEntries = { "confirmStartTeam": "使用这些宝可梦开始游戏吗?", - "confirmExit": "Do you want to exit?", + "confirmExit": "确定要退出吗?", "invalidParty": "初始队伍不可用!", "gen1": "I", "gen2": "II", diff --git a/src/locales/zh_CN/trainers.ts b/src/locales/zh_CN/trainers.ts index eb27d2c0c0a..ab7b3fce6ac 100644 --- a/src/locales/zh_CN/trainers.ts +++ b/src/locales/zh_CN/trainers.ts @@ -20,18 +20,18 @@ export const titles: SimpleTranslationEntries = { "plasma_boss": "等离子队老大", "flare_boss": "闪焰队老大", - "rocket_admin": "Team Rocket Admin", - "rocket_admin_female": "Team Rocket Admin", - "magma_admin": "Team Magma Admin", - "magma_admin_female": "Team Magma Admin", - "aqua_admin": "Team Aqua Admin", - "aqua_admin_female": "Team Aqua Admin", - "galactic_commander": "Team Galactic Commander", - "galactic_commander_female": "Team Galactic Commander", - "plasma_sage": "Team Plasma Sage", - "plasma_admin": "Team Plasma Admin", - "flare_admin": "Team Flare Admin", - "flare_admin_female": "Team Flare Admin", + "rocket_admin": "火箭队干部", + "rocket_admin_female": "火箭队干部", + "magma_admin": "熔岩队干部", + "magma_admin_female": "熔岩队干部", + "aqua_admin": "海洋队干部", + "aqua_admin_female": "海洋队干部", + "galactic_commander": "银河队干部", + "galactic_commander_female": "银河队干部", + "plasma_sage": "等离子队贤人", + "plasma_admin": "等离子队干部", + "flare_admin": "闪焰队干部", + "flare_admin_female": "闪焰队干部", // Maybe if we add the evil teams we can add "Team Rocket" and "Team Aqua" etc. here as well as "Team Rocket Boss" and "Team Aqua Admin" etc. } as const; @@ -342,21 +342,21 @@ export const trainerNames: SimpleTranslationEntries = { "rival_female": "艾薇", // Evil Team Admins - "archer": "Archer", - "ariana": "Ariana", - "proton": "Proton", - "petrel": "Petrel", - "tabitha": "Tabitha", - "courtney": "Courtney", - "shelly": "Shelly", - "matt": "Matt", - "mars": "Mars", - "jupiter": "Jupiter", - "saturn": "Saturn", - "zinzolin": "Zinzolin", - "rood": "Rood", - "xerosic": "Xerosic", - "bryony": "Bryony", + "archer": "阿波罗", + "ariana": "雅典娜", + "proton": "兰斯", + "petrel": "拉姆达", + "tabitha": "火村", + "courtney": "火雁", + "shelly": "阿泉", + "matt": "阿潮", + "mars": "伙星", + "jupiter": "碎星", + "saturn": "镇星", + "zinzolin": "维奥", + "rood": "罗德", + "xerosic": "库瑟洛斯奇", + "bryony": "芭菈", // ---- 组织老大 Bosses ---- "maxie": "赤焰松", From 0bd32b7a7683490567096ddedf13b6a67d7c0249 Mon Sep 17 00:00:00 2001 From: Lugiad Date: Thu, 8 Aug 2024 05:14:00 +0200 Subject: [PATCH 027/282] [Localization] French - Some missing translations, typos and rephrasing. (#3423) * Update modifier-type.ts * Update tutorial.ts * Update modifier-type.ts * Update modifier-type.ts --- src/locales/fr/modifier-type.ts | 44 ++++++++++++++++----------------- src/locales/fr/tutorial.ts | 4 +-- 2 files changed, 24 insertions(+), 24 deletions(-) diff --git a/src/locales/fr/modifier-type.ts b/src/locales/fr/modifier-type.ts index 671a122f992..3635b318336 100644 --- a/src/locales/fr/modifier-type.ts +++ b/src/locales/fr/modifier-type.ts @@ -24,7 +24,7 @@ export const modifierType: ModifierTypeTranslationEntries = { } }, "PokemonReviveModifierType": { - description: "Réanime un Pokémon et restaure {{restorePercent}}% de ses PV.", + description: "Ranime un Pokémon et restaure {{restorePercent}}% de ses PV.", }, "PokemonStatusHealModifierType": { description: "Soigne tous les problèmes de statut d’un Pokémon.", @@ -64,13 +64,13 @@ export const modifierType: ModifierTypeTranslationEntries = { description: "Fait monter toute l’équipe de {{levels}} niveau·x.", }, "PokemonBaseStatBoosterModifierType": { - description: "Augmente de 10% {{statName}} de base de son porteur. Plus les IV sont hauts, plus il peut en porter.", + description: "Augmente de 10% {{statName}} de base de son porteur. Plus les IV sont hauts, plus il peut en porter.", }, "AllPokemonFullHpRestoreModifierType": { - description: "Restaure tous les PV de toute l'équipe.", + description: "Restaure tous les PV de toute l’équipe.", }, "AllPokemonFullReviveModifierType": { - description: "Réanime et restaure tous les PV de tous les Pokémon K.O.", + description: "Ranime et restaure tous les PV de tous les Pokémon K.O. .", }, "MoneyRewardModifierType": { description: "Octroie une {{moneyMultiplier}} somme d’argent.\n({{moneyAmount}} ₽)", @@ -151,9 +151,9 @@ export const modifierType: ModifierTypeTranslationEntries = { "SACRED_ASH": { name: "Cendre Sacrée" }, - "REVIVER_SEED": { name: "Résugraine", description: "Réanime et restaure la moitié des PV de son porteur s’il est mis K.O. par une capacité directe." }, + "REVIVER_SEED": { name: "Résugraine", description: "Ranime et restaure la moitié des PV de son porteur s’il est mis K.O. par une capacité directe." }, - "WHITE_HERB": { name: "White Herb", description: "An item to be held by a Pokémon. It will restore any lowered stat in battle." }, + "WHITE_HERB": { name: "Herbe Blanche", description: "Restaure toute stat ayant subi une baisse en combat." }, "ETHER": { name: "Huile" }, "MAX_ETHER": { name: "Huile Max" }, @@ -184,12 +184,12 @@ export const modifierType: ModifierTypeTranslationEntries = { "SOOTHE_BELL": { name: "Grelot Zen" }, - "SCOPE_LENS": { name: "Lentilscope", description: "Une lentille qui augmente le taux de critiques du porteur." }, - "LEEK": { name: "Poireau", description: "Objet à faire tenir à Canarticho. Un poireau très long et solide qui augmente son taux de critiques." }, + "SCOPE_LENS": { name: "Lentilscope", description: "Une lentille qui augmente d’un cran le taux de critiques du porteur." }, + "LEEK": { name: "Poireau", description: "À faire tenir à Canarticho ou Palarticho. Un poireau très long et solide qui augmente de 2 crans le taux de critiques." }, - "EVIOLITE": { name: "Évoluroc", description: "Un étrange concentré d’évolution qui augmente la Défense et la Défense Spéciale d’un Pokémon pouvant évoluer." }, + "EVIOLITE": { name: "Évoluroc", description: "Augmente de 50% la Défense et Déf. Spé. si le porteur peut évoluer, 25% aux fusions dont une moitié le peut encore." }, - "SOUL_DEW": { name: "Rosée Âme", description: "Augmente de 10% l’influence de la nature d’un Pokémon sur ses statistiques (cumulatif)." }, + "SOUL_DEW": { name: "Rosée Âme", description: "Augmente de 10% l’influence de la nature d’un Pokémon sur ses statistiques. Effet cumulatif." }, "NUGGET": { name: "Pépite" }, "BIG_NUGGET": { name: "Maxi Pépite" }, @@ -199,7 +199,7 @@ export const modifierType: ModifierTypeTranslationEntries = { "GOLDEN_PUNCH": { name: "Poing Doré", description: "50% des dégâts infligés sont convertis en argent." }, "COIN_CASE": { name: "Boite Jetons", description: "Tous les 10 combats, recevez 10% de votre argent en intérêts." }, - "LOCK_CAPSULE": { name: "Poké Écrin", description: "Permet de verrouiller des objets rares si vous relancez les objets proposés." }, + "LOCK_CAPSULE": { name: "Poké Écrin", description: "Permet de conserver la rareté des objets si vous relancez les objets proposés." }, "GRIP_CLAW": { name: "Accro Griffe" }, "WIDE_LENS": { name: "Loupe" }, @@ -220,8 +220,8 @@ export const modifierType: ModifierTypeTranslationEntries = { "LEFTOVERS": { name: "Restes", description: "Soigne à chaque tour 1/16 des PV max d’un Pokémon." }, "SHELL_BELL": { name: "Grelot Coque", description: "Soigne son porteur avec 1/8 des dégâts qu’il inflige à un Pokémon." }, - "TOXIC_ORB": { name: "Orbe Toxique", description: "Un orbe bizarre qui empoisonne gravement son porteur durant le combat." }, - "FLAME_ORB": { name: "Orbe Flamme", description: "Un orbe bizarre qui brule son porteur durant le combat." }, + "TOXIC_ORB": { name: "Orbe Toxique", description: "Empoisonne gravement son porteur à la fin du tour s’il n’a pas déjà de problème de statut." }, + "FLAME_ORB": { name: "Orbe Flamme", description: "Brule son porteur à la fin du tour s’il n’a pas déjà de problème de statut." }, "BATON": { name: "Bâton", description: "Permet de transmettre les effets en cas de changement de Pokémon. Ignore les pièges." }, @@ -242,21 +242,21 @@ export const modifierType: ModifierTypeTranslationEntries = { "ENEMY_ATTACK_POISON_CHANCE": { name: "Jeton Poison" }, "ENEMY_ATTACK_PARALYZE_CHANCE": { name: "Jeton Paralysie" }, "ENEMY_ATTACK_BURN_CHANCE": { name: "Jeton Brulure" }, - "ENEMY_STATUS_EFFECT_HEAL_CHANCE": { name: "Jeton Total Soin", description: "Ajoute 2.5% de chances à chaque tour de se soigner d’un problème de statut." }, + "ENEMY_STATUS_EFFECT_HEAL_CHANCE": { name: "Jeton Total Soin", description: "Ajoute 2,5% de chances à chaque tour de se soigner d’un problème de statut." }, "ENEMY_ENDURE_CHANCE": { name: "Jeton Ténacité" }, "ENEMY_FUSED_CHANCE": { name: "Jeton Fusion", description: "Ajoute 1% de chances qu’un Pokémon sauvage soit une fusion." }, }, SpeciesBoosterItem: { - "LIGHT_BALL": { name: "Balle Lumière", description: "Objet à faire tenir à Pikachu. Un orbe énigmatique qui augmente son Attaque et son Attaque Spéciale." }, - "THICK_CLUB": { name: "Masse Os", description: "Objet à faire tenir à Osselait ou Ossatueur. Un os dur qui augmente leur Attaque." }, - "METAL_POWDER": { name: "Poudre Métal", description: "Objet à faire tenir à Métamorph. Cette poudre étrange, très fine mais résistante, augmente sa Défense." }, - "QUICK_POWDER": { name: "Poudre Vite", description: "Objet à faire tenir à Métamorph. Cette poudre étrange, très fine mais résistante, augmente sa Vitesse." } + "LIGHT_BALL": { name: "Balle Lumière", description: "À faire tenir à Pikachu. Un orbe énigmatique qui double son Attaque et son Atq. Spé. ." }, + "THICK_CLUB": { name: "Masse Os", description: "À faire tenir à Osselait ou Ossatueur. Un os dur qui double leur Attaque." }, + "METAL_POWDER": { name: "Poudre Métal", description: "À faire tenir à Métamorph. Cette poudre étrange, très fine mais résistante, double sa Défense." }, + "QUICK_POWDER": { name: "Poudre Vite", description: "À faire tenir à Métamorph. Cette poudre étrange, très fine mais résistante, double sa Vitesse." } }, TempBattleStatBoosterItem: { "x_attack": "Attaque +", "x_defense": "Défense +", - "x_sp_atk": "Atq. Spé. +", - "x_sp_def": "Déf. Spé. +", + "x_sp_atk": "Atq. Spé. +", + "x_sp_def": "Déf. Spé. +", "x_speed": "Vitesse +", "x_accuracy": "Précision +", "dire_hit": "Muscle +", @@ -265,8 +265,8 @@ export const modifierType: ModifierTypeTranslationEntries = { TempBattleStatBoosterStatName: { "ATK": "Attaque", "DEF": "Défense", - "SPATK": "Atq. Spé.", - "SPDEF": "Déf. Spé.", + "SPATK": "Atq. Spé.", + "SPDEF": "Déf. Spé.", "SPD": "Vitesse", "ACC": "Précision", "CRIT": "Taux de critique", diff --git a/src/locales/fr/tutorial.ts b/src/locales/fr/tutorial.ts index d8940dadd56..f44c05f7d5c 100644 --- a/src/locales/fr/tutorial.ts +++ b/src/locales/fr/tutorial.ts @@ -34,9 +34,9 @@ export const tutorial: SimpleTranslationEntries = { "selectItem": `Après chaque combat, vous avez le choix entre 3 objets\ntirés au sort. Vous ne pouvez en prendre qu’un. $Cela peut être des objets consommables, des objets à\nfaire tenir, ou des objets passifs aux effets permanents. $La plupart des effets des objets non-consommables se cumuleront de diverses manières. - $Certains objets apparaîtront s’ils peuvent être utilisés, comme les objets d’évolution. + $Certains objets apparaitront s’ils peuvent être utilisés, comme les objets d’évolution. $Vous pouvez aussi transférer des objets tenus entre Pokémon en utilisant l’option de transfert. - $L’option de transfert apparaît en bas à droite dès que vous avez obtenu un objet à faire tenir. + $L’option de transfert apparait en bas à droite dès que vous avez obtenu un objet à faire tenir. $Vous pouvez acheter des consommables avec de l’argent.\nPlus vous progressez, plus le choix sera varié. $Choisir un des objets gratuits déclenchera le prochain combat, donc faites bien tous vos achats avant.`, From 9ff86857526c431d264973c7f3af8afe327af63f Mon Sep 17 00:00:00 2001 From: "Adrian T." <68144167+torranx@users.noreply.github.com> Date: Thu, 8 Aug 2024 11:15:45 +0800 Subject: [PATCH 028/282] [Dev] Update changeTurnOrder name to mockTurnOrder (naming convention) (#3422) * change changeTurnOrder to mockTurnOrder * update docs --- src/test/abilities/serene_grace.test.ts | 6 +++--- src/test/abilities/sheer_force.test.ts | 10 +++++----- src/test/abilities/shield_dust.test.ts | 4 ++-- src/test/abilities/zen_mode.test.ts | 8 ++++---- src/test/items/leek.test.ts | 4 ++-- src/test/items/scope_lens.test.ts | 4 ++-- src/test/moves/fusion_flare_bolt.test.ts | 16 ++++++++-------- src/test/moves/gastro_acid.test.ts | 4 ++-- src/test/utils/testUtils.ts | 11 ++++++----- 9 files changed, 34 insertions(+), 33 deletions(-) diff --git a/src/test/abilities/serene_grace.test.ts b/src/test/abilities/serene_grace.test.ts index c486604e4f9..59e9ff723da 100644 --- a/src/test/abilities/serene_grace.test.ts +++ b/src/test/abilities/serene_grace.test.ts @@ -11,7 +11,7 @@ import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { changeTurnOrder } from "../utils/testUtils"; +import { mockTurnOrder } from "../utils/testUtils"; import { BattlerIndex } from "#app/battle.js"; @@ -57,7 +57,7 @@ describe("Abilities - Serene Grace", () => { (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); }); - await changeTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]); + await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEffectPhase, false); // Check chance of Air Slash without Serene Grace @@ -90,7 +90,7 @@ describe("Abilities - Serene Grace", () => { (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); }); - await changeTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]); + await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEffectPhase, false); // Check chance of Air Slash with Serene Grace diff --git a/src/test/abilities/sheer_force.test.ts b/src/test/abilities/sheer_force.test.ts index 3f1bcadd43f..35353bc7000 100644 --- a/src/test/abilities/sheer_force.test.ts +++ b/src/test/abilities/sheer_force.test.ts @@ -11,7 +11,7 @@ import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { changeTurnOrder } from "../utils/testUtils"; +import { mockTurnOrder } from "../utils/testUtils"; import { BattlerIndex } from "#app/battle.js"; @@ -58,7 +58,7 @@ describe("Abilities - Sheer Force", () => { (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); }); - await changeTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]); + await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEffectPhase, false); const phase = game.scene.getCurrentPhase() as MoveEffectPhase; @@ -97,7 +97,7 @@ describe("Abilities - Sheer Force", () => { (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); }); - await changeTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]); + await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEffectPhase, false); const phase = game.scene.getCurrentPhase() as MoveEffectPhase; @@ -136,7 +136,7 @@ describe("Abilities - Sheer Force", () => { (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); }); - await changeTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]); + await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEffectPhase, false); const phase = game.scene.getCurrentPhase() as MoveEffectPhase; @@ -177,7 +177,7 @@ describe("Abilities - Sheer Force", () => { (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); }); - await changeTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]); + await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEffectPhase, false); const phase = game.scene.getCurrentPhase() as MoveEffectPhase; diff --git a/src/test/abilities/shield_dust.test.ts b/src/test/abilities/shield_dust.test.ts index c7e62b333d7..ded70eccb36 100644 --- a/src/test/abilities/shield_dust.test.ts +++ b/src/test/abilities/shield_dust.test.ts @@ -12,7 +12,7 @@ import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { BattlerIndex } from "#app/battle.js"; -import { changeTurnOrder } from "../utils/testUtils"; +import { mockTurnOrder } from "../utils/testUtils"; describe("Abilities - Shield Dust", () => { @@ -58,7 +58,7 @@ describe("Abilities - Shield Dust", () => { (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); }); - await changeTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]); + await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEffectPhase, false); // Shield Dust negates secondary effect diff --git a/src/test/abilities/zen_mode.test.ts b/src/test/abilities/zen_mode.test.ts index 63c6a3d4acf..fc0bf282078 100644 --- a/src/test/abilities/zen_mode.test.ts +++ b/src/test/abilities/zen_mode.test.ts @@ -12,7 +12,7 @@ import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; import { BattlerIndex } from "#app/battle.js"; -import { changeTurnOrder } from "../utils/testUtils"; +import { mockTurnOrder } from "../utils/testUtils"; const TIMEOUT = 20 * 1000; @@ -58,7 +58,7 @@ describe("Abilities - ZEN MODE", () => { const movePosition = getMovePosition(game.scene, 0, moveToUse); (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); }); - await changeTurnOrder(game, [BattlerIndex.ENEMY, BattlerIndex.PLAYER]); + await mockTurnOrder(game, [BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.phaseInterceptor.to(DamagePhase, false); // await game.phaseInterceptor.runFrom(DamagePhase).to(DamagePhase, false); const damagePhase = game.scene.getCurrentPhase() as DamagePhase; @@ -86,7 +86,7 @@ describe("Abilities - ZEN MODE", () => { const movePosition = getMovePosition(game.scene, 0, moveToUse); (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); }); - await changeTurnOrder(game, [BattlerIndex.ENEMY, BattlerIndex.PLAYER]); + await mockTurnOrder(game, [BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.phaseInterceptor.to(QuietFormChangePhase); await game.phaseInterceptor.to(TurnInitPhase, false); expect(game.scene.getParty()[0].hp).not.toBe(100); @@ -111,7 +111,7 @@ describe("Abilities - ZEN MODE", () => { const movePosition = getMovePosition(game.scene, 0, moveToUse); (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); }); - await changeTurnOrder(game, [BattlerIndex.ENEMY, BattlerIndex.PLAYER]); + await mockTurnOrder(game, [BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.phaseInterceptor.to(DamagePhase, false); // await game.phaseInterceptor.runFrom(DamagePhase).to(DamagePhase, false); const damagePhase = game.scene.getCurrentPhase() as DamagePhase; diff --git a/src/test/items/leek.test.ts b/src/test/items/leek.test.ts index 2cfd4d8dc64..7ac453f797a 100644 --- a/src/test/items/leek.test.ts +++ b/src/test/items/leek.test.ts @@ -8,7 +8,7 @@ import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phase from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import { changeTurnOrder } from "#test/utils/testUtils"; +import { mockTurnOrder } from "#test/utils/testUtils"; describe("Items - Leek", () => { let phaserGame: Phaser.Game; @@ -44,7 +44,7 @@ describe("Items - Leek", () => { game.doAttack(0); - await changeTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]); + await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEffectPhase); diff --git a/src/test/items/scope_lens.test.ts b/src/test/items/scope_lens.test.ts index 60f7aec171b..7e5c57c1364 100644 --- a/src/test/items/scope_lens.test.ts +++ b/src/test/items/scope_lens.test.ts @@ -8,7 +8,7 @@ import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phase from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import { changeTurnOrder } from "#test/utils/testUtils"; +import { mockTurnOrder } from "#test/utils/testUtils"; describe("Items - Scope Lens", () => { let phaserGame: Phaser.Game; @@ -43,7 +43,7 @@ describe("Items - Scope Lens", () => { ]); game.doAttack(0); - await changeTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]); + await mockTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]); await game.phaseInterceptor.to(MoveEffectPhase); diff --git a/src/test/moves/fusion_flare_bolt.test.ts b/src/test/moves/fusion_flare_bolt.test.ts index b0c374c1cd3..95090214962 100644 --- a/src/test/moves/fusion_flare_bolt.test.ts +++ b/src/test/moves/fusion_flare_bolt.test.ts @@ -8,7 +8,7 @@ import { allMoves } from "#app/data/move"; import { BattlerIndex } from "#app/battle"; import { Species } from "#enums/species"; import { Moves } from "#enums/moves"; -import { changeTurnOrder } from "#test/utils/testUtils"; +import { mockTurnOrder } from "#test/utils/testUtils"; describe("Moves - Fusion Flare and Fusion Bolt", () => { let phaserGame: Phaser.Game; @@ -56,7 +56,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { game.doSelectTarget(BattlerIndex.ENEMY); // Force user party to act before enemy party - await changeTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]); + await mockTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]); await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id); @@ -82,7 +82,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { game.doSelectTarget(BattlerIndex.ENEMY); // Force user party to act before enemy party - await changeTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]); + await mockTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]); await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id); @@ -108,7 +108,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { game.doSelectTarget(0); // Force first enemy to act (and fail) in between party - await changeTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY ]); + await mockTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY ]); await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id); @@ -140,7 +140,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { game.doSelectTarget(BattlerIndex.ENEMY); // Force first enemy to act in between party - await changeTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY ]); + await mockTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY ]); await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id); @@ -170,7 +170,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { game.doSelectTarget(BattlerIndex.PLAYER); // Force user party to act before enemy party - await changeTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]); + await mockTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]); await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id); @@ -222,7 +222,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { game.doSelectTarget(BattlerIndex.ENEMY); // Force first enemy to act in between party - await changeTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY ]); + await mockTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY ]); await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id); @@ -284,7 +284,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { game.doSelectTarget(BattlerIndex.PLAYER); // Force first enemy to act in between party - await changeTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY ]); + await mockTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY ]); await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id); diff --git a/src/test/moves/gastro_acid.test.ts b/src/test/moves/gastro_acid.test.ts index 77cf35f39e2..8c5f5f14eac 100644 --- a/src/test/moves/gastro_acid.test.ts +++ b/src/test/moves/gastro_acid.test.ts @@ -6,7 +6,7 @@ import { MoveResult } from "#app/field/pokemon.js"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { changeTurnOrder, SPLASH_ONLY } from "#test/utils/testUtils"; +import { mockTurnOrder, SPLASH_ONLY } from "#test/utils/testUtils"; const TIMEOUT = 20 * 1000; @@ -75,7 +75,7 @@ describe("Moves - Gastro Acid", () => { game.doAttack(getMovePosition(game.scene, 0, Moves.CORE_ENFORCER)); // Force player to be slower to enable Core Enforcer to proc its suppression effect - await changeTurnOrder(game, [BattlerIndex.ENEMY, BattlerIndex.PLAYER]); + await mockTurnOrder(game, [BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.phaseInterceptor.to("TurnInitPhase"); diff --git a/src/test/utils/testUtils.ts b/src/test/utils/testUtils.ts index 6ba46e6fc16..f1ed2bcdd07 100644 --- a/src/test/utils/testUtils.ts +++ b/src/test/utils/testUtils.ts @@ -40,15 +40,16 @@ export function removeEnemyHeldItems(game: GameManager): void { } /** - * Used to modify the turn order. Will advance the turn to {@link TurnStartPhase} - * @param game The {@link GameManager} instance - * @param order The turn order to set + * Intercepts `TurnStartPhase` and mocks the getOrder's return value {@linkcode TurnStartPhase.getOrder} + * Used to modify the turn order. + * @param {GameManager} game The GameManager instance + * @param {BattlerIndex[]} order The turn order to set * @example * ```ts - * await changeTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2]); + * await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2]); * ``` */ -export async function changeTurnOrder(game: GameManager, order: BattlerIndex[]): Promise { +export async function mockTurnOrder(game: GameManager, order: BattlerIndex[]): Promise { await game.phaseInterceptor.to(TurnStartPhase, false); vi.spyOn(game.scene.getCurrentPhase() as TurnStartPhase, "getOrder").mockReturnValue(order); From d0629830a806c88f127e41fad0b83a2841fc6f48 Mon Sep 17 00:00:00 2001 From: "Adrian T." <68144167+torranx@users.noreply.github.com> Date: Thu, 8 Aug 2024 11:18:37 +0800 Subject: [PATCH 029/282] [Dev] Add mockHitCheck util (#3421) * add mockHitCheck helper * update docs --- src/test/abilities/hustle.test.ts | 5 ++- src/test/abilities/libero.test.ts | 7 ++-- src/test/abilities/magic_guard.test.ts | 9 +++--- src/test/abilities/parental_bond.test.ts | 41 +++++++----------------- src/test/abilities/protean.test.ts | 7 ++-- src/test/abilities/sweet_veil.test.ts | 12 +++---- src/test/utils/testUtils.ts | 18 ++++++++++- 7 files changed, 45 insertions(+), 54 deletions(-) diff --git a/src/test/abilities/hustle.test.ts b/src/test/abilities/hustle.test.ts index 4434dc62a6b..80a71e54d0b 100644 --- a/src/test/abilities/hustle.test.ts +++ b/src/test/abilities/hustle.test.ts @@ -8,7 +8,7 @@ import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import { SPLASH_ONLY } from "#test/utils/testUtils"; +import { mockHitCheck, SPLASH_ONLY } from "#test/utils/testUtils"; describe("Abilities - Hustle", () => { let phaserGame: Phaser.Game; @@ -44,8 +44,7 @@ describe("Abilities - Hustle", () => { vi.spyOn(pikachu, "getBattleStat"); game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); - await game.phaseInterceptor.to(MoveEffectPhase, false); - vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValue(true); + await mockHitCheck(game, true); await game.phaseInterceptor.to(DamagePhase); expect(pikachu.getBattleStat).toHaveReturnedWith(atk * 1.5); diff --git a/src/test/abilities/libero.test.ts b/src/test/abilities/libero.test.ts index e4d99d5b56c..6046df98243 100644 --- a/src/test/abilities/libero.test.ts +++ b/src/test/abilities/libero.test.ts @@ -2,7 +2,7 @@ import { allMoves } from "#app/data/move.js"; import { Type } from "#app/data/type.js"; import { Weather, WeatherType } from "#app/data/weather.js"; import { PlayerPokemon } from "#app/field/pokemon.js"; -import { MoveEffectPhase, TurnEndPhase } from "#app/phases.js"; +import { TurnEndPhase } from "#app/phases.js"; import { Abilities } from "#enums/abilities"; import { BattlerTagType } from "#enums/battler-tag-type"; import { Biome } from "#enums/biome"; @@ -12,7 +12,7 @@ import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { SPLASH_ONLY } from "#test/utils/testUtils"; +import { mockHitCheck, SPLASH_ONLY } from "#test/utils/testUtils"; const TIMEOUT = 20 * 1000; @@ -192,8 +192,7 @@ describe("Abilities - Protean", () => { expect(leadPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); - await game.phaseInterceptor.to(MoveEffectPhase, false); - vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValueOnce(false); + await mockHitCheck(game, false); await game.phaseInterceptor.to(TurnEndPhase); const enemyPokemon = game.scene.getEnemyPokemon()!; diff --git a/src/test/abilities/magic_guard.test.ts b/src/test/abilities/magic_guard.test.ts index 23b3bad828f..f138ef77219 100644 --- a/src/test/abilities/magic_guard.test.ts +++ b/src/test/abilities/magic_guard.test.ts @@ -1,8 +1,8 @@ -import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import Phaser from "phaser"; import GameManager from "#test/utils/gameManager"; import { Species } from "#enums/species"; -import { TurnEndPhase, MoveEffectPhase } from "#app/phases"; +import { TurnEndPhase } from "#app/phases"; import { Moves } from "#enums/moves"; import { ArenaTagType } from "#enums/arena-tag-type"; import { ArenaTagSide, getArenaTag } from "#app/data/arena-tag"; @@ -11,7 +11,7 @@ import { Abilities } from "#enums/abilities"; import { WeatherType } from "#app/data/weather.js"; import { StatusEffect, getStatusEffectCatchRateMultiplier } from "#app/data/status-effect"; import { BattlerTagType } from "#enums/battler-tag-type"; -import { SPLASH_ONLY } from "#test/utils/testUtils"; +import { mockHitCheck, SPLASH_ONLY } from "#test/utils/testUtils"; const TIMEOUT = 20 * 1000; // 20 sec timeout @@ -258,8 +258,7 @@ describe("Abilities - Magic Guard", () => { const leadPokemon = game.scene.getPlayerPokemon()!; game.doAttack(getMovePosition(game.scene, 0, Moves.HIGH_JUMP_KICK)); - await game.phaseInterceptor.to(MoveEffectPhase, false); - vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValueOnce(false); + await mockHitCheck(game, false); await game.phaseInterceptor.to(TurnEndPhase); diff --git a/src/test/abilities/parental_bond.test.ts b/src/test/abilities/parental_bond.test.ts index 1fb27ad7e1f..e5f0f969d10 100644 --- a/src/test/abilities/parental_bond.test.ts +++ b/src/test/abilities/parental_bond.test.ts @@ -7,10 +7,10 @@ import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phaser from "phaser"; -import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest"; +import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { SPLASH_ONLY } from "#test/utils/testUtils"; +import { mockHitCheck, SPLASH_ONLY } from "#test/utils/testUtils"; const TIMEOUT = 20 * 1000; @@ -129,10 +129,7 @@ describe("Abilities - Parental Bond", () => { expect(enemyPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.DOUBLE_HIT)); - - await game.phaseInterceptor.to(MoveEffectPhase, false); - - vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValue(true); + await mockHitCheck(game, true); await game.phaseInterceptor.to(BerryPhase, false); @@ -175,9 +172,7 @@ describe("Abilities - Parental Bond", () => { expect(enemyPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.ROLLOUT)); - - await game.phaseInterceptor.to(MoveEffectPhase, false); - vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValue(true); + await mockHitCheck(game, true); await game.phaseInterceptor.to(DamagePhase, false); @@ -373,9 +368,7 @@ describe("Abilities - Parental Bond", () => { const enemyStartingHp = enemyPokemon.hp; game.doAttack(getMovePosition(game.scene, 0, Moves.SUPER_FANG)); - - await game.phaseInterceptor.to(MoveEffectPhase, false); - vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValue(true); + await mockHitCheck(game, true); await game.phaseInterceptor.to(DamagePhase); @@ -404,9 +397,7 @@ describe("Abilities - Parental Bond", () => { const enemyStartingHp = enemyPokemon.hp; game.doAttack(getMovePosition(game.scene, 0, Moves.SEISMIC_TOSS)); - - await game.phaseInterceptor.to(MoveEffectPhase, false); - vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValue(true); + await mockHitCheck(game, true); await game.phaseInterceptor.to(DamagePhase); @@ -432,9 +423,7 @@ describe("Abilities - Parental Bond", () => { expect(enemyPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.HYPER_BEAM)); - - await game.phaseInterceptor.to(MoveEffectPhase, false); - vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValue(true); + await mockHitCheck(game, true); await game.phaseInterceptor.to(DamagePhase); @@ -462,9 +451,7 @@ describe("Abilities - Parental Bond", () => { expect(enemyPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.ANCHOR_SHOT)); - - await game.phaseInterceptor.to(MoveEffectPhase, false); - vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValue(true); + await mockHitCheck(game, true); await game.phaseInterceptor.to(DamagePhase); @@ -494,9 +481,7 @@ describe("Abilities - Parental Bond", () => { expect(enemyPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.SMACK_DOWN)); - - await game.phaseInterceptor.to(MoveEffectPhase, false); - vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValue(true); + await mockHitCheck(game, true); await game.phaseInterceptor.to(DamagePhase); @@ -523,9 +508,7 @@ describe("Abilities - Parental Bond", () => { expect(enemyPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.U_TURN)); - - await game.phaseInterceptor.to(MoveEffectPhase, false); - vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValue(true); + await mockHitCheck(game, true); await game.phaseInterceptor.to(MoveEffectPhase); expect(leadPokemon.turnData.hitCount).toBe(2); @@ -549,9 +532,7 @@ describe("Abilities - Parental Bond", () => { expect(enemyPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.WAKE_UP_SLAP)); - - await game.phaseInterceptor.to(MoveEffectPhase, false); - vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValue(true); + await mockHitCheck(game, true); await game.phaseInterceptor.to(DamagePhase); diff --git a/src/test/abilities/protean.test.ts b/src/test/abilities/protean.test.ts index 63d1a0ea719..8022f73255f 100644 --- a/src/test/abilities/protean.test.ts +++ b/src/test/abilities/protean.test.ts @@ -2,7 +2,7 @@ import { allMoves } from "#app/data/move.js"; import { Type } from "#app/data/type.js"; import { Weather, WeatherType } from "#app/data/weather.js"; import { PlayerPokemon } from "#app/field/pokemon.js"; -import { MoveEffectPhase, TurnEndPhase } from "#app/phases.js"; +import { TurnEndPhase } from "#app/phases.js"; import { Abilities } from "#enums/abilities"; import { BattlerTagType } from "#enums/battler-tag-type"; import { Biome } from "#enums/biome"; @@ -12,7 +12,7 @@ import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { SPLASH_ONLY } from "#test/utils/testUtils"; +import { mockHitCheck, SPLASH_ONLY } from "#test/utils/testUtils"; const TIMEOUT = 20 * 1000; @@ -192,8 +192,7 @@ describe("Abilities - Protean", () => { expect(leadPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); - await game.phaseInterceptor.to(MoveEffectPhase, false); - vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValueOnce(false); + await mockHitCheck(game, false); await game.phaseInterceptor.to(TurnEndPhase); const enemyPokemon = game.scene.getEnemyPokemon()!; diff --git a/src/test/abilities/sweet_veil.test.ts b/src/test/abilities/sweet_veil.test.ts index 03e9452a358..5af822da061 100644 --- a/src/test/abilities/sweet_veil.test.ts +++ b/src/test/abilities/sweet_veil.test.ts @@ -1,14 +1,14 @@ -import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import Phaser from "phaser"; import GameManager from "#test/utils/gameManager"; import { Species } from "#enums/species"; -import { CommandPhase, MoveEffectPhase, MovePhase, TurnEndPhase } from "#app/phases"; +import { CommandPhase, MovePhase, TurnEndPhase } from "#app/phases"; import { Moves } from "#enums/moves"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { BattlerTagType } from "#app/enums/battler-tag-type.js"; import { Abilities } from "#app/enums/abilities.js"; import { BattlerIndex } from "#app/battle.js"; -import { SPLASH_ONLY } from "#test/utils/testUtils"; +import { mockHitCheck, SPLASH_ONLY } from "#test/utils/testUtils"; describe("Abilities - Sweet Veil", () => { let phaserGame: Phaser.Game; @@ -80,13 +80,11 @@ describe("Abilities - Sweet Veil", () => { game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); // First pokemon move - await game.phaseInterceptor.to(MoveEffectPhase, false); - vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValueOnce(true); + await mockHitCheck(game, true); // Second pokemon move await game.phaseInterceptor.to(MovePhase, false); - await game.phaseInterceptor.to(MoveEffectPhase, false); - vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValueOnce(true); + await mockHitCheck(game, true); expect(game.scene.getPlayerField().some(p => !!p.getTag(BattlerTagType.DROWSY))).toBe(true); diff --git a/src/test/utils/testUtils.ts b/src/test/utils/testUtils.ts index f1ed2bcdd07..d5f266cd4ae 100644 --- a/src/test/utils/testUtils.ts +++ b/src/test/utils/testUtils.ts @@ -3,7 +3,7 @@ import i18next, { type ParseKeys } from "i18next"; import { vi } from "vitest"; import GameManager from "./gameManager"; import { BattlerIndex } from "#app/battle.js"; -import { TurnStartPhase } from "#app/phases.js"; +import { MoveEffectPhase, TurnStartPhase } from "#app/phases.js"; /** Ready to use array of Moves.SPLASH x4 */ export const SPLASH_ONLY = [Moves.SPLASH, Moves.SPLASH, Moves.SPLASH, Moves.SPLASH]; @@ -54,3 +54,19 @@ export async function mockTurnOrder(game: GameManager, order: BattlerIndex[]): P vi.spyOn(game.scene.getCurrentPhase() as TurnStartPhase, "getOrder").mockReturnValue(order); } + +/** + * Intercepts `MoveEffectPhase` and mocks the hitCheck's return value {@linkcode MoveEffectPhase.hitCheck}. + * Used to force a move to either hit or miss. + * Note that this uses `mockReturnValue()`, meaning it will also apply to a + * succeeding `MoveEffectPhase` immediately following the first one + * (in the case of a multi-target move) + * + * @param {GameManager} game The GameManager instance + * @param shouldHit Whether the move should hit + */ +export async function mockHitCheck(game: GameManager, shouldHit: boolean): Promise { + await game.phaseInterceptor.to(MoveEffectPhase, false); + + vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValue(shouldHit); +} From 7b4e91eb02fee31f17c34241665052a47ee5bf57 Mon Sep 17 00:00:00 2001 From: flx-sta <50131232+flx-sta@users.noreply.github.com> Date: Wed, 7 Aug 2024 21:46:53 -0700 Subject: [PATCH 030/282] [Bug] Fix no wild evolutions (#3426) * fix wild pokemon not evolving anymore * add test to cover defaults for wildDelay --- src/data/pokemon-evolutions.ts | 24 ++++++++++++------------ src/test/evolution.test.ts | 8 +++++++- 2 files changed, 19 insertions(+), 13 deletions(-) diff --git a/src/data/pokemon-evolutions.ts b/src/data/pokemon-evolutions.ts index e7baf608b97..e29a4c16c29 100644 --- a/src/data/pokemon-evolutions.ts +++ b/src/data/pokemon-evolutions.ts @@ -64,21 +64,21 @@ export class SpeciesFormEvolution { public level: integer; public item: EvolutionItem | null; public condition: SpeciesEvolutionCondition | null; - public wildDelay: SpeciesWildEvolutionDelay | null; + public wildDelay: SpeciesWildEvolutionDelay; - constructor(speciesId: Species, preFormKey: string | null, evoFormKey: string | null, level: integer, item: EvolutionItem | null, condition: SpeciesEvolutionCondition | null, wildDelay?: SpeciesWildEvolutionDelay | null) { + constructor(speciesId: Species, preFormKey: string | null, evoFormKey: string | null, level: integer, item: EvolutionItem | null, condition: SpeciesEvolutionCondition | null, wildDelay?: SpeciesWildEvolutionDelay) { this.speciesId = speciesId; this.preFormKey = preFormKey; this.evoFormKey = evoFormKey; this.level = level; this.item = item || EvolutionItem.NONE; this.condition = condition; - this.wildDelay = wildDelay!; // TODO: is this bang correct? + this.wildDelay = wildDelay ?? SpeciesWildEvolutionDelay.NONE; } } export class SpeciesEvolution extends SpeciesFormEvolution { - constructor(speciesId: Species, level: integer, item: EvolutionItem | null, condition: SpeciesEvolutionCondition | null, wildDelay?: SpeciesWildEvolutionDelay | null) { + constructor(speciesId: Species, level: integer, item: EvolutionItem | null, condition: SpeciesEvolutionCondition | null, wildDelay?: SpeciesWildEvolutionDelay) { super(speciesId, null, null, level, item, condition, wildDelay); } } @@ -400,8 +400,8 @@ export const pokemonEvolutions: PokemonEvolutions = { new SpeciesEvolution(Species.LINOONE, 20, null, null) ], [Species.WURMPLE]: [ - new SpeciesEvolution(Species.SILCOON, 7, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAWN || p.scene.arena.getTimeOfDay() === TimeOfDay.DAY), null), - new SpeciesEvolution(Species.CASCOON, 7, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DUSK || p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT), null) + new SpeciesEvolution(Species.SILCOON, 7, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAWN || p.scene.arena.getTimeOfDay() === TimeOfDay.DAY)), + new SpeciesEvolution(Species.CASCOON, 7, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DUSK || p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT)) ], [Species.SILCOON]: [ new SpeciesEvolution(Species.BEAUTIFLY, 10, null, null) @@ -945,7 +945,7 @@ export const pokemonEvolutions: PokemonEvolutions = { new SpeciesEvolution(Species.SHIINOTIC, 24, null, null) ], [Species.SALANDIT]: [ - new SpeciesEvolution(Species.SALAZZLE, 33, null, new SpeciesEvolutionCondition(p => p.gender === Gender.FEMALE, p => p.gender = Gender.FEMALE), null) + new SpeciesEvolution(Species.SALAZZLE, 33, null, new SpeciesEvolutionCondition(p => p.gender === Gender.FEMALE, p => p.gender = Gender.FEMALE)) ], [Species.STUFFUL]: [ new SpeciesEvolution(Species.BEWEAR, 27, null, null) @@ -969,8 +969,8 @@ export const pokemonEvolutions: PokemonEvolutions = { new SpeciesEvolution(Species.COSMOEM, 43, null, null) ], [Species.COSMOEM]: [ - new SpeciesEvolution(Species.SOLGALEO, 53, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAY), null), - new SpeciesEvolution(Species.LUNALA, 53, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT), null) + new SpeciesEvolution(Species.SOLGALEO, 53, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.DAY)), + new SpeciesEvolution(Species.LUNALA, 53, null, new SpeciesEvolutionCondition(p => p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT)) ], [Species.MELTAN]: [ new SpeciesEvolution(Species.MELMETAL, 48, null, null) @@ -1406,9 +1406,9 @@ export const pokemonEvolutions: PokemonEvolutions = { new SpeciesEvolution(Species.CRABOMINABLE, 1, EvolutionItem.ICE_STONE, null, SpeciesWildEvolutionDelay.LONG) ], [Species.ROCKRUFF]: [ - new SpeciesFormEvolution(Species.LYCANROC, "", "midday", 25, null, new SpeciesEvolutionCondition(p => (p.scene.arena.getTimeOfDay() === TimeOfDay.DAWN || p.scene.arena.getTimeOfDay() === TimeOfDay.DAY) && (p.formIndex === 0)), null), - new SpeciesFormEvolution(Species.LYCANROC, "", "dusk", 25, null, new SpeciesEvolutionCondition(p => p.formIndex === 1), null), - new SpeciesFormEvolution(Species.LYCANROC, "", "midnight", 25, null, new SpeciesEvolutionCondition(p => (p.scene.arena.getTimeOfDay() === TimeOfDay.DUSK || p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT) && (p.formIndex === 0)), null) + new SpeciesFormEvolution(Species.LYCANROC, "", "midday", 25, null, new SpeciesEvolutionCondition(p => (p.scene.arena.getTimeOfDay() === TimeOfDay.DAWN || p.scene.arena.getTimeOfDay() === TimeOfDay.DAY) && (p.formIndex === 0))), + new SpeciesFormEvolution(Species.LYCANROC, "", "dusk", 25, null, new SpeciesEvolutionCondition(p => p.formIndex === 1)), + new SpeciesFormEvolution(Species.LYCANROC, "", "midnight", 25, null, new SpeciesEvolutionCondition(p => (p.scene.arena.getTimeOfDay() === TimeOfDay.DUSK || p.scene.arena.getTimeOfDay() === TimeOfDay.NIGHT) && (p.formIndex === 0))) ], [Species.STEENEE]: [ new SpeciesEvolution(Species.TSAREENA, 28, null, new SpeciesEvolutionCondition(p => p.moveset.filter(m => m?.moveId === Moves.STOMP).length > 0), SpeciesWildEvolutionDelay.LONG) diff --git a/src/test/evolution.test.ts b/src/test/evolution.test.ts index c8ebffa6119..b1764a67ad7 100644 --- a/src/test/evolution.test.ts +++ b/src/test/evolution.test.ts @@ -1,4 +1,4 @@ -import { pokemonEvolutions } from "#app/data/pokemon-evolutions.js"; +import { pokemonEvolutions, SpeciesFormEvolution, SpeciesWildEvolutionDelay } from "#app/data/pokemon-evolutions.js"; import { Abilities } from "#app/enums/abilities.js"; import { Species } from "#app/enums/species.js"; import GameManager from "#test/utils/gameManager"; @@ -83,4 +83,10 @@ describe("Evolution", () => { expect(ninjask.abilityIndex).toBe(2); expect(shedinja.abilityIndex).toBe(1); }, TIMEOUT); + + it("should set wild delay to NONE by default", () => { + const speciesFormEvo = new SpeciesFormEvolution(Species.ABRA, null, null, 1000, null, null); + + expect(speciesFormEvo.wildDelay).toBe(SpeciesWildEvolutionDelay.NONE); + }); }); From 9eb57c0c661cde84064ae5a5319bd27e6d01be5f Mon Sep 17 00:00:00 2001 From: Opaque02 <66582645+Opaque02@users.noreply.github.com> Date: Thu, 8 Aug 2024 15:04:12 +1000 Subject: [PATCH 031/282] [QoL] IV scanner update to hide the prompt and let you see the stats mid battle on the stats screen (#3285) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * IV scanner PR fix Updated locales to have updated keys for IV scanner in menu Updated legacy UI to work with IV scanner changes Updated code to have player and enemy battle stats for ease of use Updated logic to make the player side work exactly the same as previously since there should be no HP stat shown for players. Also updated the colours so there's no more grey option for unknown stats Added HP, updated logic and colours. Need to undo changes to player pokemon to not be as squished because of no HP, and need to see what happens for trainers Fixing up some git errors Fixed a bug with double battles not updating the pokemon properly Updated settings to allow for the ability to skip the IV scanning prompts Adding functionality to IV scanner to skip prompt and see IVs mid battle * Merged with latest + fixed bug with IV scanner vs pokemon info container getRootSpeciesId being different * Updated as per merge comment * Updating to fix comments * Updated comments * Update src/locales/fr/settings.ts Co-authored-by: Lugiad' * Update src/locales/de/settings.ts Co-authored-by: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> * Update src/locales/pt_BR/settings.ts Co-authored-by: José Ricardo Fleury Oliveira * Update src/locales/ko/settings.ts Co-authored-by: Enoch * Update src/locales/zh_CN/settings.ts Co-authored-by: mercurius-00 <80205689+mercurius-00@users.noreply.github.com> * Update src/locales/zh_TW/settings.ts Co-authored-by: mercurius-00 <80205689+mercurius-00@users.noreply.github.com> * Updating text of IV scanner to be gold * Updated text colour to use one of the existing golds instead of a custom gold * Japanese locale * Updating docs --------- Co-authored-by: Lugiad' Co-authored-by: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> Co-authored-by: José Ricardo Fleury Oliveira Co-authored-by: Enoch Co-authored-by: mercurius-00 <80205689+mercurius-00@users.noreply.github.com> --- public/images/ui/legacy/pbinfo_stat.json | 21 +++++ public/images/ui/legacy/pbinfo_stat.png | Bin 263 -> 451 bytes .../images/ui/legacy/pbinfo_stat_numbers.json | 21 +++++ .../images/ui/legacy/pbinfo_stat_numbers.png | Bin 392 -> 435 bytes public/images/ui/pbinfo_stat.json | 21 +++++ public/images/ui/pbinfo_stat.png | Bin 278 -> 496 bytes public/images/ui/pbinfo_stat_numbers.json | 21 +++++ public/images/ui/pbinfo_stat_numbers.png | Bin 430 -> 499 bytes src/battle-scene.ts | 1 + src/data/battle-stat.ts | 5 +- src/locales/de/settings.ts | 1 + src/locales/en/pokemon-info.ts | 3 +- src/locales/en/settings.ts | 1 + src/locales/es/settings.ts | 1 + src/locales/fr/settings.ts | 1 + src/locales/it/settings.ts | 1 + src/locales/ja/settings.ts | 1 + src/locales/ko/settings.ts | 1 + src/locales/pt_BR/settings.ts | 1 + src/locales/zh_CN/settings.ts | 1 + src/locales/zh_TW/settings.ts | 1 + src/phases.ts | 50 +++++++++--- src/system/settings/settings.ts | 11 +++ src/ui/battle-info.ts | 52 ++++++++++--- src/ui/battle-message-ui-handler.ts | 72 +++++++++++------- src/ui/text.ts | 4 +- 26 files changed, 240 insertions(+), 52 deletions(-) diff --git a/public/images/ui/legacy/pbinfo_stat.json b/public/images/ui/legacy/pbinfo_stat.json index b7da47fc192..a956f81150d 100644 --- a/public/images/ui/legacy/pbinfo_stat.json +++ b/public/images/ui/legacy/pbinfo_stat.json @@ -176,6 +176,27 @@ "w": 12, "h": 6 } + }, + { + "filename": "HP", + "rotated": false, + "trimmed": true, + "sourceSize": { + "w": 9, + "h": 8 + }, + "spriteSourceSize": { + "x": 1, + "y": 2, + "w": 8, + "h": 6 + }, + "frame": { + "x": 112, + "y": 0, + "w": 8, + "h": 6 + } } ] } diff --git a/public/images/ui/legacy/pbinfo_stat.png b/public/images/ui/legacy/pbinfo_stat.png index 62ec3758772daea6013a4de5532575a66caf8116..18b0ca314dec0bc30e3527d9828421a5417256e0 100644 GIT binary patch literal 451 zcmV;!0X+VRP)Px#1ZP1_K>z@;j|==^1poj6Q%OWYR7gvul)G&MK@dY%SBgVbak;v1=-gE}SLiO> zibA&{n`aRq2+q#het@v^;c(}qg9h05{f^J)?c;tFzG02^lp68vzae?Qz7BjGtuanI(D^*SybWIJI?a<0V$QQ( zot&rM{i?k3PpF=`>bqR&_66EcxugA!33xhRPDk*7b)Y@Q=yQ>okK?*DhdA9+X@KgT zq)mF);MDsQzJHfHdVl&Jk+0lORKLN5rv66EOo1;``8e+Tn|oI1{G9*Z@AF;mXg__A z>{l;HbszM{Uo^~EMBe>CiJ6bq0djo+z~!Msui683oIYRSex3gcm|uM!pncx2^9uG# zefO*83H2vms(NVc&2*sZcm9uX>4ziTUS6B+06ITq)<+Mg_y6jj{ATk%`Z2x$!H8}^ txZ~DE0000EWmrjOO-%qQ00008000000002eQEc4QuN(io6fN32b;e=)XJ@8wjxa57 z6;5`pyz#?~2;;a-r4XYn{3?!Y<6HKbItN$2xk}gw>0y zUzy)p<5e-!w)Vy<(87aih3;8-LtI=7KLTHk<}Jk-^i|&t;uc GLK6T7%VuW) diff --git a/public/images/ui/legacy/pbinfo_stat_numbers.json b/public/images/ui/legacy/pbinfo_stat_numbers.json index fa7d757990f..c106d1cf41e 100644 --- a/public/images/ui/legacy/pbinfo_stat_numbers.json +++ b/public/images/ui/legacy/pbinfo_stat_numbers.json @@ -281,6 +281,27 @@ "w": 9, "h": 8 } + }, + { + "filename": "empty", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 1, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 1, + "h": 8 + }, + "frame": { + "x": 117, + "y": 0, + "w": 1, + "h": 8 + } } ] } diff --git a/public/images/ui/legacy/pbinfo_stat_numbers.png b/public/images/ui/legacy/pbinfo_stat_numbers.png index ee1453b21070f8de40a299a2d0c82c49093799cc..b02dfbec72f63c34f12dd1232d071eefc305c9c1 100644 GIT binary patch literal 435 zcmV;k0ZjghP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!TOkOSlj+ytcz%1M?yuOEzFY<6PpQlR}L@;nacBaX)b^VgrweYTS4aX=q&JWh^D>SJQ~MU3O3 zV4cI~Ha6wI4#r&$$i?zF79=MPi)>f>*e>C5a8{QC`Z`a!#|ILG{$a5WNYo*XE$Zk# zsBwbRVJsHT=} dYn*i^gd@0!^jmMfva0|9002ovPDHLkV1kzcyjlPN literal 392 zcmV;30eAk1P)NeVolC?^B79yfh4NP^lrY9U!*DY-V@3rV{hYdQ>YK;=1YJaz3T;`<^$DGJL<5 z0VRW87@CHmA>NuYKzH1TLC5xSzn%dVgI*Y#hCzM2e@<+(--30)Oref_gmu$R&9E*Q zKCPUg&65~>rQzm$c=)wGxON}pkE{!ZPit-h_?q;dhMV)@;n(^|U!-Qgl_%A@VDM** z28vT)T`)O@Pln{f8%r6yr(x9i(DP6xH!0n5bN5`F;gccxJgbFgqhZwe(DRg7RCba7 mA?H5)Du%PaS?j+(7uOe-FYwO$9P0Z30000Px#1ZP1_K>z@;j|==^1poj6fJsC_R7gwhmd#BAF%X3vI@zs>1~^bcBIUpZB#>x< zLmHr_-BJS2@X*WCc)S~O$RVF(jb}VR9@`sbGYrGA81p=b_H(#ot{dxEa`x~kaC+Xp z9tndWm6om&qn8Wos)I260oL-C*`S)TJ?>k~if4w@s9-S}r z=u8yPqcQan96mp4Lud@(b=1i>y+*kylI3zdcdM4~hq;wCb%6Ur_c|Hgcf^wZ+~yyT zulxA|=&)ya9>(B7)<=M5^kwv#Q@nVVOYMNZihd(^b m4rN$LW=%~1DgXcg2mk;800000(o>TF0000>3p^r=85p>QL70(Y)*K0-;9^e~#}JM4YbQkt9Z}$Lk>2rt zuKR?x9W_gW7GHdEIZRA3PQiWWf_gEBD>-+P7WbQFDeB5(FiQnkYJT0+d!^ilFVNop z&g@AaU;a`5G;zDk43V2*;$L0AUpUvbfi-hpw1(4@QY8*&1zW>D^RKHGtIA58?GDdB z^z5+u8@b1GkFN|~6tyyB+m=mNc0TgfI9*xz^hZc=_{JB-6D{k$v)J#gjM>h5gnvUW Wt8RFN+!3I289ZJ6T-G@yGywokWokPB diff --git a/public/images/ui/pbinfo_stat_numbers.json b/public/images/ui/pbinfo_stat_numbers.json index ec4f7117bb7..ccd49bbbb79 100644 --- a/public/images/ui/pbinfo_stat_numbers.json +++ b/public/images/ui/pbinfo_stat_numbers.json @@ -281,6 +281,27 @@ "w": 9, "h": 8 } + }, + { + "filename": "empty", + "rotated": false, + "trimmed": false, + "sourceSize": { + "w": 1, + "h": 8 + }, + "spriteSourceSize": { + "x": 0, + "y": 0, + "w": 1, + "h": 8 + }, + "frame": { + "x": 117, + "y": 0, + "w": 1, + "h": 8 + } } ] } diff --git a/public/images/ui/pbinfo_stat_numbers.png b/public/images/ui/pbinfo_stat_numbers.png index c778ba992734421a718b2c49db1db0ae77a28e09..1465f8b7a6497fa417bb2b7d2d8e80de93e8dd48 100644 GIT binary patch literal 499 zcmVPx#1ZP1_K>z@;j|==^1poj532;bRa{vGi!T8~Esx)bWzSVxwcsx71 zHVPoblQ#P^&l6{yarMvNWEAHXbzSe`vTB;9;nN3_GZ=U90p^v*7x!#)M#7$>J!@uW+MgBZOOjC)Q=9*dDI z-fX=Nhb#{E_=i{y(Pw=fu1g$Ei6dcgUY^cdzsmwHJP*%dtikX zquv8~X2n77I-v8AltXfPu(qy~ph#YqhT4aR`cJy|(%| z=-B0U>%RW@K!)Z)r(RDcEhmNo@O81j>Y!uaUmr{-E|U+WG!HuUcz&65QgkGFQ^dP* pGQ=U$J=Ax7r$eNB= literal 430 zcmV;f0a5;mP)X}UpFSFJe%YMSjb zvz=}Te=dw_+OM;>zwNiTz<(WGW!%j?&)@0VTARh5OWbc`j(J{Tok%Zt#$YoH;sBj7 z0D#IlJRc6p%*|?r>-8D{#_^;+F^22I1yqy`_PebZNKrNbfWEEq_WF{{oLyYu^!yS4 z#PO(4jM4P@WGYS8UqlLVGYqiSvW&F&OBuS>FtHC$Vz?0ZyX|CN5<3@SjG<>5X2}?8 zQ)v+?7z&xQg%~oUa!zD?QzeEgj_Hh<7_VVM6DZ`EEo4UD)*|DZy2Lt;DavMIyoRBA zxP2Ty%KN9gENZI8IE_78Q^T$GD~(@jhsGYQsdI~*V!X;!+J?fg{Gd2S+NQZaWGcsm zi<{b~a&9zLI&@IbQb7LyuD?x7eaKXf@hzMCJ+VH0TaTtDpMHPh { - this.scene.ui.setMode(Mode.CONFIRM, () => { - this.scene.ui.setMode(Mode.MESSAGE); - this.scene.ui.clearText(); - new CommonBattleAnim(CommonAnim.LOCK_ON, pokemon, pokemon).play(this.scene, () => { - this.scene.ui.getMessageHandler().promptIvs(pokemon.id, pokemon.ivs, this.shownIvs).then(() => this.end()); + let enemyIvs: number[] = []; + let statsContainer: Phaser.GameObjects.Sprite[] = []; + let statsContainerLabels: Phaser.GameObjects.Sprite[] = []; + const enemyField = this.scene.getEnemyField(); + const uiTheme = (this.scene as BattleScene).uiTheme; // Assuming uiTheme is accessible + for (let e = 0; e < enemyField.length; e++) { + enemyIvs = enemyField[e].ivs; + const currentIvs = this.scene.gameData.dexData[enemyField[e].species.getRootSpeciesId()].ivs; // we are using getRootSpeciesId() here because we want to check against the baby form, not the mid form if it exists + const ivsToShow = this.scene.ui.getMessageHandler().getTopIvs(enemyIvs, this.shownIvs); + statsContainer = enemyField[e].getBattleInfo().getStatsValueContainer().list as Phaser.GameObjects.Sprite[]; + statsContainerLabels = statsContainer.filter(m => m.name.indexOf("icon_stat_label") >= 0); + for (let s = 0; s < statsContainerLabels.length; s++) { + const ivStat = Stat[statsContainerLabels[s].frame.name]; + if (enemyIvs[ivStat] > currentIvs[ivStat] && ivsToShow.indexOf(Number(ivStat)) >= 0) { + const hexColour = enemyIvs[ivStat] === 31 ? getTextColor(TextStyle.PERFECT_IV, false, uiTheme) : getTextColor(TextStyle.SUMMARY_GREEN, false, uiTheme); + const hexTextColour = Phaser.Display.Color.HexStringToColor(hexColour).color; + statsContainerLabels[s].setTint(hexTextColour); + } + statsContainerLabels[s].setVisible(true); + } + } + + if (!this.scene.hideIvs) { + this.scene.ui.showText(i18next.t("battle:ivScannerUseQuestion", { pokemonName: getPokemonNameWithAffix(pokemon) }), null, () => { + this.scene.ui.setMode(Mode.CONFIRM, () => { + this.scene.ui.setMode(Mode.MESSAGE); + this.scene.ui.clearText(); + new CommonBattleAnim(CommonAnim.LOCK_ON, pokemon, pokemon).play(this.scene, () => { + this.scene.ui.getMessageHandler().promptIvs(pokemon.id, pokemon.ivs, this.shownIvs).then(() => this.end()); + }); + }, () => { + this.scene.ui.setMode(Mode.MESSAGE); + this.scene.ui.clearText(); + this.end(); }); - }, () => { - this.scene.ui.setMode(Mode.MESSAGE); - this.scene.ui.clearText(); - this.end(); }); - }); + } else { + this.end(); + } } } diff --git a/src/system/settings/settings.ts b/src/system/settings/settings.ts index 96acffd6bfb..3f9b906d1cf 100644 --- a/src/system/settings/settings.ts +++ b/src/system/settings/settings.ts @@ -79,6 +79,7 @@ export const SettingKeys = { Skip_Seen_Dialogues: "SKIP_SEEN_DIALOGUES", Battle_Style: "BATTLE_STYLE", Enable_Retries: "ENABLE_RETRIES", + Hide_IVs: "HIDE_IVS", Tutorials: "TUTORIALS", Touch_Controls: "TOUCH_CONTROLS", Vibration: "VIBRATION", @@ -250,6 +251,13 @@ export const Setting: Array = [ default: 0, type: SettingType.GENERAL }, + { + key: SettingKeys.Hide_IVs, + label: i18next.t("settings:hideIvs"), + options: OFF_ON, + default: 0, + type: SettingType.GENERAL + }, { key: SettingKeys.Tutorials, label: i18next.t("settings:tutorials"), @@ -618,6 +626,9 @@ export function setSetting(scene: BattleScene, setting: string, value: integer): case SettingKeys.Enable_Retries: scene.enableRetries = Setting[index].options[value].value === "On"; break; + case SettingKeys.Hide_IVs: + scene.hideIvs = Setting[index].options[value].value === "On"; + break; case SettingKeys.Skip_Seen_Dialogues: scene.skipSeenDialogues = Setting[index].options[value].value === "On"; break; diff --git a/src/ui/battle-info.ts b/src/ui/battle-info.ts index 98ebdf21078..dbf0d5911c8 100644 --- a/src/ui/battle-info.ts +++ b/src/ui/battle-info.ts @@ -12,8 +12,6 @@ import BattleFlyout from "./battle-flyout"; import { WindowVariant, addWindow } from "./ui-theme"; import i18next from "i18next"; -const battleStatOrder = [ BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.ACC, BattleStat.EVA, BattleStat.SPD ]; - export default class BattleInfo extends Phaser.GameObjects.Container { private baseY: number; @@ -70,6 +68,10 @@ export default class BattleInfo extends Phaser.GameObjects.Container { public flyoutMenu?: BattleFlyout; + private battleStatOrder: BattleStat[]; + private battleStatOrderPlayer = [BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.ACC, BattleStat.EVA, BattleStat.SPD]; + private battleStatOrderEnemy = [BattleStat.HP, BattleStat.ATK, BattleStat.DEF, BattleStat.SPATK, BattleStat.SPDEF, BattleStat.ACC, BattleStat.EVA, BattleStat.SPD]; + constructor(scene: Phaser.Scene, x: number, y: number, player: boolean) { super(scene, x, y); this.baseY = y; @@ -222,20 +224,44 @@ export default class BattleInfo extends Phaser.GameObjects.Container { this.statValuesContainer = this.scene.add.container(0, 0); this.statsContainer.add(this.statValuesContainer); - battleStatOrder.map((s, i) => { - const statX = i > 1 ? this.statNumbers[i - 2].x + this.statNumbers[i - 2].width + 4 : -this.statsBox.width + 8; - const statY = -this.statsBox.height / 2 + 4 + (i < battleStatOrder.length - 1 ? (i % 2 ? 10 : 0) : 5); + // this gives us a different starting location from the left of the label and padding between stats for a player vs enemy + // since the player won't have HP to show, it doesn't need to change from the current version + const startingX = this.player ? -this.statsBox.width + 8 : -this.statsBox.width + 5; + const paddingX = this.player ? 4 : 2; + const statOverflow = this.player ? 1 : 0; + this.battleStatOrder = this.player ? this.battleStatOrderPlayer : this.battleStatOrderEnemy; // this tells us whether or not to use the player or enemy battle stat order + + this.battleStatOrder.map((s, i) => { + // we do a check for i > statOverflow to see when the stat labels go onto the next column + // For enemies, we have HP (i=0) by itself then a new column, so we check for i > 0 + // For players, we don't have HP, so we start with i = 0 and i = 1 for our first column, and so need to check for i > 1 + const statX = i > statOverflow ? this.statNumbers[Math.max(i - 2, 0)].x + this.statNumbers[Math.max(i - 2, 0)].width + paddingX : startingX; // we have the Math.max(i - 2, 0) in there so for i===1 to not return a negative number; since this is now based on anything >0 instead of >1, we need to allow for i-2 < 0 + + const baseY = -this.statsBox.height / 2 + 4; // this is the baseline for the y-axis + let statY: number; // this will be the y-axis placement for the labels + if (this.battleStatOrder[i] === BattleStat.SPD || this.battleStatOrder[i] === BattleStat.HP) { + statY = baseY + 5; + } else { + statY = baseY + (!!(i % 2) === this.player ? 10 : 0); // we compare i % 2 against this.player to tell us where to place the label; because this.battleStatOrder for enemies has HP, this.battleStatOrder[1]=ATK, but for players this.battleStatOrder[0]=ATK, so this comparing i % 2 to this.player fixes this issue for us + } + const statLabel = this.scene.add.sprite(statX, statY, "pbinfo_stat", BattleStat[s]); statLabel.setName("icon_stat_label_" + i.toString()); statLabel.setOrigin(0, 0); statLabels.push(statLabel); this.statValuesContainer.add(statLabel); - const statNumber = this.scene.add.sprite(statX + statLabel.width, statY, "pbinfo_stat_numbers", "3"); + const statNumber = this.scene.add.sprite(statX + statLabel.width, statY, "pbinfo_stat_numbers", this.battleStatOrder[i] !== BattleStat.HP ? "3" : "empty"); statNumber.setName("icon_stat_number_" + i.toString()); statNumber.setOrigin(0, 0); this.statNumbers.push(statNumber); this.statValuesContainer.add(statNumber); + + if (this.battleStatOrder[i] === BattleStat.HP) { + statLabel.setVisible(false); + statNumber.setVisible(false); + } + }); if (!this.player) { @@ -274,6 +300,10 @@ export default class BattleInfo extends Phaser.GameObjects.Container { } } + getStatsValueContainer(): Phaser.GameObjects.Container { + return this.statValuesContainer; + } + initInfo(pokemon: Pokemon) { this.updateNameText(pokemon); const nameTextWidth = this.nameText.displayWidth; @@ -403,7 +433,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container { this.statValuesContainer.setPosition(8, 7); } - const battleStats = battleStatOrder.map(() => 0); + const battleStats = this.battleStatOrder.map(() => 0); this.lastBattleStats = battleStats.join(""); this.updateBattleStats(battleStats); @@ -622,7 +652,7 @@ export default class BattleInfo extends Phaser.GameObjects.Container { const battleStats = pokemon.summonData ? pokemon.summonData.battleStats - : battleStatOrder.map(() => 0); + : this.battleStatOrder.map(() => 0); const battleStatsStr = battleStats.join(""); if (this.lastBattleStats !== battleStatsStr) { @@ -740,8 +770,10 @@ export default class BattleInfo extends Phaser.GameObjects.Container { } updateBattleStats(battleStats: integer[]): void { - battleStatOrder.map((s, i) => { - this.statNumbers[i].setFrame(battleStats[s].toString()); + this.battleStatOrder.map((s, i) => { + if (s !== BattleStat.HP) { + this.statNumbers[i].setFrame(battleStats[s].toString()); + } }); } diff --git a/src/ui/battle-message-ui-handler.ts b/src/ui/battle-message-ui-handler.ts index 6c5049394a7..1c7dfb27630 100644 --- a/src/ui/battle-message-ui-handler.ts +++ b/src/ui/battle-message-ui-handler.ts @@ -196,24 +196,7 @@ export default class BattleMessageUiHandler extends MessageUiHandler { this.scene.executeWithSeedOffset(() => { let levelUpStatsValuesText = ""; const stats = Utils.getEnumValues(Stat); - let shownStats: Stat[] = []; - if (shownIvsCount < 6) { - const statsPool = stats.slice(0); - for (let i = 0; i < shownIvsCount; i++) { - let shownStat: Stat; - let highestIv = -1; - statsPool.map(s => { - if (ivs[s] > highestIv) { - shownStat = s as Stat; - highestIv = ivs[s]; - } - }); - shownStats.push(shownStat!); // TODO: is the bang correct? - statsPool.splice(statsPool.indexOf(shownStat!), 1); // TODO: is the bang correct? - } - } else { - shownStats = stats; - } + const shownStats = this.getTopIvs(ivs, shownIvsCount); for (const s of stats) { levelUpStatsValuesText += `${shownStats.indexOf(s) > -1 ? this.getIvDescriptor(ivs[s], s, pokemonId) : "???"}\n`; } @@ -229,35 +212,70 @@ export default class BattleMessageUiHandler extends MessageUiHandler { }); } + getTopIvs(ivs: integer[], shownIvsCount: integer): Stat[] { + const stats = Utils.getEnumValues(Stat); + let shownStats: Stat[] = []; + if (shownIvsCount < 6) { + const statsPool = stats.slice(0); + for (let i = 0; i < shownIvsCount; i++) { + let shownStat: Stat | null = null; + let highestIv = -1; + statsPool.map(s => { + if (ivs[s] > highestIv) { + shownStat = s as Stat; + highestIv = ivs[s]; + } + }); + if (shownStat) { + shownStats.push(shownStat); + statsPool.splice(statsPool.indexOf(shownStat), 1); + } + } + } else { + shownStats = stats; + } + return shownStats; + } + getIvDescriptor(value: integer, typeIv: integer, pokemonId: integer): string { - const starterSpecies = this.scene.getPokemonById(pokemonId)!.species.getRootSpeciesId(true); // TODO: is this bang correct? + const starterSpecies = this.scene.getPokemonById(pokemonId)!.species.getRootSpeciesId(); // we are using getRootSpeciesId() here because we want to check against the baby form, not the mid form if it exists const starterIvs: number[] = this.scene.gameData.dexData[starterSpecies].ivs; const uiTheme = (this.scene as BattleScene).uiTheme; // Assuming uiTheme is accessible // Function to wrap text in color based on comparison - const coloredText = (text: string, isBetter: boolean) => { - const textStyle: TextStyle = isBetter ? TextStyle.SUMMARY_GREEN : TextStyle.SUMMARY; + const coloredText = (text: string, isBetter: boolean, ivValue) => { + let textStyle: TextStyle; + if (isBetter) { + if (ivValue === 31) { + textStyle = TextStyle.PERFECT_IV; + } else { + textStyle = TextStyle.SUMMARY_GREEN; + } + } else { + textStyle = TextStyle.SUMMARY; + } + //const textStyle: TextStyle = isBetter ? TextStyle.SUMMARY_GREEN : TextStyle.SUMMARY; const color = getTextColor(textStyle, false, uiTheme); return `[color=${color}][shadow=${getTextColor(textStyle, true, uiTheme)}]${text}[/shadow][/color]`; }; if (value > 30) { - return coloredText(i18next.t("battleMessageUiHandler:ivBest"), value > starterIvs[typeIv]); + return coloredText(i18next.t("battleMessageUiHandler:ivBest"), value > starterIvs[typeIv], value); } if (value === 30) { - return coloredText(i18next.t("battleMessageUiHandler:ivFantastic"), value > starterIvs[typeIv]); + return coloredText(i18next.t("battleMessageUiHandler:ivFantastic"), value > starterIvs[typeIv], value); } if (value > 20) { - return coloredText(i18next.t("battleMessageUiHandler:ivVeryGood"), value > starterIvs[typeIv]); + return coloredText(i18next.t("battleMessageUiHandler:ivVeryGood"), value > starterIvs[typeIv], value); } if (value > 10) { - return coloredText(i18next.t("battleMessageUiHandler:ivPrettyGood"), value > starterIvs[typeIv]); + return coloredText(i18next.t("battleMessageUiHandler:ivPrettyGood"), value > starterIvs[typeIv], value); } if (value > 0) { - return coloredText(i18next.t("battleMessageUiHandler:ivDecent"), value > starterIvs[typeIv]); + return coloredText(i18next.t("battleMessageUiHandler:ivDecent"), value > starterIvs[typeIv], value); } - return coloredText(i18next.t("battleMessageUiHandler:ivNoGood"), value > starterIvs[typeIv]); + return coloredText(i18next.t("battleMessageUiHandler:ivNoGood"), value > starterIvs[typeIv], value); } showNameText(name: string): void { diff --git a/src/ui/text.ts b/src/ui/text.ts index 43dca9efc45..c1d7fe091c0 100644 --- a/src/ui/text.ts +++ b/src/ui/text.ts @@ -37,7 +37,8 @@ export enum TextStyle { MOVE_PP_NEAR_EMPTY, MOVE_PP_EMPTY, SMALLER_WINDOW_ALT, - BGM_BAR + BGM_BAR, + PERFECT_IV } export interface TextStyleOptions { @@ -291,6 +292,7 @@ export function getTextColor(textStyle: TextStyle, shadow?: boolean, uiTheme: Ui case TextStyle.SUMMARY_GREEN: return !shadow ? "#78c850" : "#306850"; case TextStyle.SETTINGS_LABEL: + case TextStyle.PERFECT_IV: return !shadow ? "#f8b050" : "#c07800"; case TextStyle.SETTINGS_SELECTED: return !shadow ? "#f88880" : "#f83018"; From cff3adf2e6fbc9cf87b10fd07109e9193178d231 Mon Sep 17 00:00:00 2001 From: Opaque02 <66582645+Opaque02@users.noreply.github.com> Date: Thu, 8 Aug 2024 22:55:56 +1000 Subject: [PATCH 032/282] Updating locale folder from ca-ES to ca_ES (#3429) * Updating locale folder from ca-ES to ca_ES * Updated the i18n config file to include ca_ES instead of ca-ES --- src/locales/{ca-ES => ca_ES}/ability-trigger.ts | 0 src/locales/{ca-ES => ca_ES}/ability.ts | 0 src/locales/{ca-ES => ca_ES}/achv.ts | 0 src/locales/{ca-ES => ca_ES}/arena-flyout.ts | 0 src/locales/{ca-ES => ca_ES}/arena-tag.ts | 0 src/locales/{ca-ES => ca_ES}/battle-info.ts | 0 src/locales/{ca-ES => ca_ES}/battle-message-ui-handler.ts | 0 src/locales/{ca-ES => ca_ES}/battle.ts | 0 src/locales/{ca-ES => ca_ES}/battler-tags.ts | 0 src/locales/{ca-ES => ca_ES}/berry.ts | 0 src/locales/{ca-ES => ca_ES}/bgm-name.ts | 0 src/locales/{ca-ES => ca_ES}/biome.ts | 0 src/locales/{ca-ES => ca_ES}/challenges.ts | 0 src/locales/{ca-ES => ca_ES}/command-ui-handler.ts | 0 src/locales/{ca-ES => ca_ES}/common.ts | 0 src/locales/{ca-ES => ca_ES}/config.ts | 0 src/locales/{ca-ES => ca_ES}/dialogue.ts | 0 src/locales/{ca-ES => ca_ES}/egg.ts | 0 src/locales/{ca-ES => ca_ES}/fight-ui-handler.ts | 0 src/locales/{ca-ES => ca_ES}/filter-bar.ts | 0 src/locales/{ca-ES => ca_ES}/game-mode.ts | 0 src/locales/{ca-ES => ca_ES}/game-stats-ui-handler.ts | 0 src/locales/{ca-ES => ca_ES}/growth.ts | 0 src/locales/{ca-ES => ca_ES}/menu-ui-handler.ts | 0 src/locales/{ca-ES => ca_ES}/menu.ts | 0 src/locales/{ca-ES => ca_ES}/modifier-select-ui-handler.ts | 0 src/locales/{ca-ES => ca_ES}/modifier-type.ts | 0 src/locales/{ca-ES => ca_ES}/modifier.ts | 0 src/locales/{ca-ES => ca_ES}/move-trigger.ts | 0 src/locales/{ca-ES => ca_ES}/move.ts | 0 src/locales/{ca-ES => ca_ES}/nature.ts | 0 src/locales/{ca-ES => ca_ES}/party-ui-handler.ts | 0 src/locales/{ca-ES => ca_ES}/pokeball.ts | 0 src/locales/{ca-ES => ca_ES}/pokemon-form.ts | 0 src/locales/{ca-ES => ca_ES}/pokemon-info-container.ts | 0 src/locales/{ca-ES => ca_ES}/pokemon-info.ts | 0 src/locales/{ca-ES => ca_ES}/pokemon-summary.ts | 0 src/locales/{ca-ES => ca_ES}/pokemon.ts | 0 src/locales/{ca-ES => ca_ES}/save-slot-select-ui-handler.ts | 0 src/locales/{ca-ES => ca_ES}/settings.ts | 0 src/locales/{ca-ES => ca_ES}/splash-messages.ts | 0 src/locales/{ca-ES => ca_ES}/starter-select-ui-handler.ts | 0 src/locales/{ca-ES => ca_ES}/status-effect.ts | 0 src/locales/{ca-ES => ca_ES}/trainers.ts | 0 src/locales/{ca-ES => ca_ES}/tutorial.ts | 0 src/locales/{ca-ES => ca_ES}/voucher.ts | 0 src/locales/{ca-ES => ca_ES}/weather.ts | 0 src/plugins/i18n.ts | 2 +- 48 files changed, 1 insertion(+), 1 deletion(-) rename src/locales/{ca-ES => ca_ES}/ability-trigger.ts (100%) rename src/locales/{ca-ES => ca_ES}/ability.ts (100%) rename src/locales/{ca-ES => ca_ES}/achv.ts (100%) rename src/locales/{ca-ES => ca_ES}/arena-flyout.ts (100%) rename src/locales/{ca-ES => ca_ES}/arena-tag.ts (100%) rename src/locales/{ca-ES => ca_ES}/battle-info.ts (100%) rename src/locales/{ca-ES => ca_ES}/battle-message-ui-handler.ts (100%) rename src/locales/{ca-ES => ca_ES}/battle.ts (100%) rename src/locales/{ca-ES => ca_ES}/battler-tags.ts (100%) rename src/locales/{ca-ES => ca_ES}/berry.ts (100%) rename src/locales/{ca-ES => ca_ES}/bgm-name.ts (100%) rename src/locales/{ca-ES => ca_ES}/biome.ts (100%) rename src/locales/{ca-ES => ca_ES}/challenges.ts (100%) rename src/locales/{ca-ES => ca_ES}/command-ui-handler.ts (100%) rename src/locales/{ca-ES => ca_ES}/common.ts (100%) rename src/locales/{ca-ES => ca_ES}/config.ts (100%) rename src/locales/{ca-ES => ca_ES}/dialogue.ts (100%) rename src/locales/{ca-ES => ca_ES}/egg.ts (100%) rename src/locales/{ca-ES => ca_ES}/fight-ui-handler.ts (100%) rename src/locales/{ca-ES => ca_ES}/filter-bar.ts (100%) rename src/locales/{ca-ES => ca_ES}/game-mode.ts (100%) rename src/locales/{ca-ES => ca_ES}/game-stats-ui-handler.ts (100%) rename src/locales/{ca-ES => ca_ES}/growth.ts (100%) rename src/locales/{ca-ES => ca_ES}/menu-ui-handler.ts (100%) rename src/locales/{ca-ES => ca_ES}/menu.ts (100%) rename src/locales/{ca-ES => ca_ES}/modifier-select-ui-handler.ts (100%) rename src/locales/{ca-ES => ca_ES}/modifier-type.ts (100%) rename src/locales/{ca-ES => ca_ES}/modifier.ts (100%) rename src/locales/{ca-ES => ca_ES}/move-trigger.ts (100%) rename src/locales/{ca-ES => ca_ES}/move.ts (100%) rename src/locales/{ca-ES => ca_ES}/nature.ts (100%) rename src/locales/{ca-ES => ca_ES}/party-ui-handler.ts (100%) rename src/locales/{ca-ES => ca_ES}/pokeball.ts (100%) rename src/locales/{ca-ES => ca_ES}/pokemon-form.ts (100%) rename src/locales/{ca-ES => ca_ES}/pokemon-info-container.ts (100%) rename src/locales/{ca-ES => ca_ES}/pokemon-info.ts (100%) rename src/locales/{ca-ES => ca_ES}/pokemon-summary.ts (100%) rename src/locales/{ca-ES => ca_ES}/pokemon.ts (100%) rename src/locales/{ca-ES => ca_ES}/save-slot-select-ui-handler.ts (100%) rename src/locales/{ca-ES => ca_ES}/settings.ts (100%) rename src/locales/{ca-ES => ca_ES}/splash-messages.ts (100%) rename src/locales/{ca-ES => ca_ES}/starter-select-ui-handler.ts (100%) rename src/locales/{ca-ES => ca_ES}/status-effect.ts (100%) rename src/locales/{ca-ES => ca_ES}/trainers.ts (100%) rename src/locales/{ca-ES => ca_ES}/tutorial.ts (100%) rename src/locales/{ca-ES => ca_ES}/voucher.ts (100%) rename src/locales/{ca-ES => ca_ES}/weather.ts (100%) diff --git a/src/locales/ca-ES/ability-trigger.ts b/src/locales/ca_ES/ability-trigger.ts similarity index 100% rename from src/locales/ca-ES/ability-trigger.ts rename to src/locales/ca_ES/ability-trigger.ts diff --git a/src/locales/ca-ES/ability.ts b/src/locales/ca_ES/ability.ts similarity index 100% rename from src/locales/ca-ES/ability.ts rename to src/locales/ca_ES/ability.ts diff --git a/src/locales/ca-ES/achv.ts b/src/locales/ca_ES/achv.ts similarity index 100% rename from src/locales/ca-ES/achv.ts rename to src/locales/ca_ES/achv.ts diff --git a/src/locales/ca-ES/arena-flyout.ts b/src/locales/ca_ES/arena-flyout.ts similarity index 100% rename from src/locales/ca-ES/arena-flyout.ts rename to src/locales/ca_ES/arena-flyout.ts diff --git a/src/locales/ca-ES/arena-tag.ts b/src/locales/ca_ES/arena-tag.ts similarity index 100% rename from src/locales/ca-ES/arena-tag.ts rename to src/locales/ca_ES/arena-tag.ts diff --git a/src/locales/ca-ES/battle-info.ts b/src/locales/ca_ES/battle-info.ts similarity index 100% rename from src/locales/ca-ES/battle-info.ts rename to src/locales/ca_ES/battle-info.ts diff --git a/src/locales/ca-ES/battle-message-ui-handler.ts b/src/locales/ca_ES/battle-message-ui-handler.ts similarity index 100% rename from src/locales/ca-ES/battle-message-ui-handler.ts rename to src/locales/ca_ES/battle-message-ui-handler.ts diff --git a/src/locales/ca-ES/battle.ts b/src/locales/ca_ES/battle.ts similarity index 100% rename from src/locales/ca-ES/battle.ts rename to src/locales/ca_ES/battle.ts diff --git a/src/locales/ca-ES/battler-tags.ts b/src/locales/ca_ES/battler-tags.ts similarity index 100% rename from src/locales/ca-ES/battler-tags.ts rename to src/locales/ca_ES/battler-tags.ts diff --git a/src/locales/ca-ES/berry.ts b/src/locales/ca_ES/berry.ts similarity index 100% rename from src/locales/ca-ES/berry.ts rename to src/locales/ca_ES/berry.ts diff --git a/src/locales/ca-ES/bgm-name.ts b/src/locales/ca_ES/bgm-name.ts similarity index 100% rename from src/locales/ca-ES/bgm-name.ts rename to src/locales/ca_ES/bgm-name.ts diff --git a/src/locales/ca-ES/biome.ts b/src/locales/ca_ES/biome.ts similarity index 100% rename from src/locales/ca-ES/biome.ts rename to src/locales/ca_ES/biome.ts diff --git a/src/locales/ca-ES/challenges.ts b/src/locales/ca_ES/challenges.ts similarity index 100% rename from src/locales/ca-ES/challenges.ts rename to src/locales/ca_ES/challenges.ts diff --git a/src/locales/ca-ES/command-ui-handler.ts b/src/locales/ca_ES/command-ui-handler.ts similarity index 100% rename from src/locales/ca-ES/command-ui-handler.ts rename to src/locales/ca_ES/command-ui-handler.ts diff --git a/src/locales/ca-ES/common.ts b/src/locales/ca_ES/common.ts similarity index 100% rename from src/locales/ca-ES/common.ts rename to src/locales/ca_ES/common.ts diff --git a/src/locales/ca-ES/config.ts b/src/locales/ca_ES/config.ts similarity index 100% rename from src/locales/ca-ES/config.ts rename to src/locales/ca_ES/config.ts diff --git a/src/locales/ca-ES/dialogue.ts b/src/locales/ca_ES/dialogue.ts similarity index 100% rename from src/locales/ca-ES/dialogue.ts rename to src/locales/ca_ES/dialogue.ts diff --git a/src/locales/ca-ES/egg.ts b/src/locales/ca_ES/egg.ts similarity index 100% rename from src/locales/ca-ES/egg.ts rename to src/locales/ca_ES/egg.ts diff --git a/src/locales/ca-ES/fight-ui-handler.ts b/src/locales/ca_ES/fight-ui-handler.ts similarity index 100% rename from src/locales/ca-ES/fight-ui-handler.ts rename to src/locales/ca_ES/fight-ui-handler.ts diff --git a/src/locales/ca-ES/filter-bar.ts b/src/locales/ca_ES/filter-bar.ts similarity index 100% rename from src/locales/ca-ES/filter-bar.ts rename to src/locales/ca_ES/filter-bar.ts diff --git a/src/locales/ca-ES/game-mode.ts b/src/locales/ca_ES/game-mode.ts similarity index 100% rename from src/locales/ca-ES/game-mode.ts rename to src/locales/ca_ES/game-mode.ts diff --git a/src/locales/ca-ES/game-stats-ui-handler.ts b/src/locales/ca_ES/game-stats-ui-handler.ts similarity index 100% rename from src/locales/ca-ES/game-stats-ui-handler.ts rename to src/locales/ca_ES/game-stats-ui-handler.ts diff --git a/src/locales/ca-ES/growth.ts b/src/locales/ca_ES/growth.ts similarity index 100% rename from src/locales/ca-ES/growth.ts rename to src/locales/ca_ES/growth.ts diff --git a/src/locales/ca-ES/menu-ui-handler.ts b/src/locales/ca_ES/menu-ui-handler.ts similarity index 100% rename from src/locales/ca-ES/menu-ui-handler.ts rename to src/locales/ca_ES/menu-ui-handler.ts diff --git a/src/locales/ca-ES/menu.ts b/src/locales/ca_ES/menu.ts similarity index 100% rename from src/locales/ca-ES/menu.ts rename to src/locales/ca_ES/menu.ts diff --git a/src/locales/ca-ES/modifier-select-ui-handler.ts b/src/locales/ca_ES/modifier-select-ui-handler.ts similarity index 100% rename from src/locales/ca-ES/modifier-select-ui-handler.ts rename to src/locales/ca_ES/modifier-select-ui-handler.ts diff --git a/src/locales/ca-ES/modifier-type.ts b/src/locales/ca_ES/modifier-type.ts similarity index 100% rename from src/locales/ca-ES/modifier-type.ts rename to src/locales/ca_ES/modifier-type.ts diff --git a/src/locales/ca-ES/modifier.ts b/src/locales/ca_ES/modifier.ts similarity index 100% rename from src/locales/ca-ES/modifier.ts rename to src/locales/ca_ES/modifier.ts diff --git a/src/locales/ca-ES/move-trigger.ts b/src/locales/ca_ES/move-trigger.ts similarity index 100% rename from src/locales/ca-ES/move-trigger.ts rename to src/locales/ca_ES/move-trigger.ts diff --git a/src/locales/ca-ES/move.ts b/src/locales/ca_ES/move.ts similarity index 100% rename from src/locales/ca-ES/move.ts rename to src/locales/ca_ES/move.ts diff --git a/src/locales/ca-ES/nature.ts b/src/locales/ca_ES/nature.ts similarity index 100% rename from src/locales/ca-ES/nature.ts rename to src/locales/ca_ES/nature.ts diff --git a/src/locales/ca-ES/party-ui-handler.ts b/src/locales/ca_ES/party-ui-handler.ts similarity index 100% rename from src/locales/ca-ES/party-ui-handler.ts rename to src/locales/ca_ES/party-ui-handler.ts diff --git a/src/locales/ca-ES/pokeball.ts b/src/locales/ca_ES/pokeball.ts similarity index 100% rename from src/locales/ca-ES/pokeball.ts rename to src/locales/ca_ES/pokeball.ts diff --git a/src/locales/ca-ES/pokemon-form.ts b/src/locales/ca_ES/pokemon-form.ts similarity index 100% rename from src/locales/ca-ES/pokemon-form.ts rename to src/locales/ca_ES/pokemon-form.ts diff --git a/src/locales/ca-ES/pokemon-info-container.ts b/src/locales/ca_ES/pokemon-info-container.ts similarity index 100% rename from src/locales/ca-ES/pokemon-info-container.ts rename to src/locales/ca_ES/pokemon-info-container.ts diff --git a/src/locales/ca-ES/pokemon-info.ts b/src/locales/ca_ES/pokemon-info.ts similarity index 100% rename from src/locales/ca-ES/pokemon-info.ts rename to src/locales/ca_ES/pokemon-info.ts diff --git a/src/locales/ca-ES/pokemon-summary.ts b/src/locales/ca_ES/pokemon-summary.ts similarity index 100% rename from src/locales/ca-ES/pokemon-summary.ts rename to src/locales/ca_ES/pokemon-summary.ts diff --git a/src/locales/ca-ES/pokemon.ts b/src/locales/ca_ES/pokemon.ts similarity index 100% rename from src/locales/ca-ES/pokemon.ts rename to src/locales/ca_ES/pokemon.ts diff --git a/src/locales/ca-ES/save-slot-select-ui-handler.ts b/src/locales/ca_ES/save-slot-select-ui-handler.ts similarity index 100% rename from src/locales/ca-ES/save-slot-select-ui-handler.ts rename to src/locales/ca_ES/save-slot-select-ui-handler.ts diff --git a/src/locales/ca-ES/settings.ts b/src/locales/ca_ES/settings.ts similarity index 100% rename from src/locales/ca-ES/settings.ts rename to src/locales/ca_ES/settings.ts diff --git a/src/locales/ca-ES/splash-messages.ts b/src/locales/ca_ES/splash-messages.ts similarity index 100% rename from src/locales/ca-ES/splash-messages.ts rename to src/locales/ca_ES/splash-messages.ts diff --git a/src/locales/ca-ES/starter-select-ui-handler.ts b/src/locales/ca_ES/starter-select-ui-handler.ts similarity index 100% rename from src/locales/ca-ES/starter-select-ui-handler.ts rename to src/locales/ca_ES/starter-select-ui-handler.ts diff --git a/src/locales/ca-ES/status-effect.ts b/src/locales/ca_ES/status-effect.ts similarity index 100% rename from src/locales/ca-ES/status-effect.ts rename to src/locales/ca_ES/status-effect.ts diff --git a/src/locales/ca-ES/trainers.ts b/src/locales/ca_ES/trainers.ts similarity index 100% rename from src/locales/ca-ES/trainers.ts rename to src/locales/ca_ES/trainers.ts diff --git a/src/locales/ca-ES/tutorial.ts b/src/locales/ca_ES/tutorial.ts similarity index 100% rename from src/locales/ca-ES/tutorial.ts rename to src/locales/ca_ES/tutorial.ts diff --git a/src/locales/ca-ES/voucher.ts b/src/locales/ca_ES/voucher.ts similarity index 100% rename from src/locales/ca-ES/voucher.ts rename to src/locales/ca_ES/voucher.ts diff --git a/src/locales/ca-ES/weather.ts b/src/locales/ca_ES/weather.ts similarity index 100% rename from src/locales/ca-ES/weather.ts rename to src/locales/ca_ES/weather.ts diff --git a/src/plugins/i18n.ts b/src/plugins/i18n.ts index 82cde7cd2ad..33f00d22555 100644 --- a/src/plugins/i18n.ts +++ b/src/plugins/i18n.ts @@ -2,7 +2,7 @@ import i18next from "i18next"; import LanguageDetector from "i18next-browser-languagedetector"; import processor, { KoreanPostpositionProcessor } from "i18next-korean-postposition-processor"; -import { caESConfig} from "#app/locales/ca-ES/config.js"; +import { caESConfig} from "#app/locales/ca_ES/config.js"; import { deConfig } from "#app/locales/de/config.js"; import { enConfig } from "#app/locales/en/config.js"; import { esConfig } from "#app/locales/es/config.js"; From aaad2241aebdd7b814dba37af1f67716671d127e Mon Sep 17 00:00:00 2001 From: Alex Van Liew Date: Thu, 8 Aug 2024 05:58:07 -0700 Subject: [PATCH 033/282] [Dev] Add typecheck command (#3409) * add test command for typechecking * change command name --- package.json | 1 + 1 file changed, 1 insertion(+) diff --git a/package.json b/package.json index dc851e05c92..b85ac639a1b 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "test:cov": "vitest run --project pre && vitest run --project main --coverage", "test:watch": "vitest run --project pre && vitest watch --project main --coverage", "test:silent": "vitest run --project pre && vitest run --project main --silent", + "typecheck": "tsc --noEmit", "eslint": "eslint --fix .", "eslint-ci": "eslint .", "docs": "typedoc", From 49bb681554970096d80ee9519ce327285339e770 Mon Sep 17 00:00:00 2001 From: Opaque02 <66582645+Opaque02@users.noreply.github.com> Date: Thu, 8 Aug 2024 23:16:27 +1000 Subject: [PATCH 034/282] [Bug] Starter UI challenge form fix (#3373) * First issue with soft attribute on challenges as well as incorrect sprites appearing on the starter select ui * Updated logic to fix starter party icons, forms and shinies in starter selection area * Fixed issue where some pokemon were being shown in challenges originally if the default form didn't meet the criteria * Updated docs and tests to account for new behaviour * Removed some debugging comments * Fixed rotom form not counting as valid party * Fixed a bug where the cursor's last known position would be used when pokemon forms were being changed when other forms were available when updated from your party directly * Fixed issue with starter party icons' forms updating incorrectly when removing pokemon from party * Fixed docs * Updated code to allow for starter icons to remember their previous state after a reload --- src/data/challenge.ts | 21 ++--- src/system/game-data.ts | 1 + src/test/ui/starter-select.test.ts | 17 +++- src/ui/starter-select-ui-handler.ts | 137 ++++++++++++++++++++++------ 4 files changed, 130 insertions(+), 46 deletions(-) diff --git a/src/data/challenge.ts b/src/data/challenge.ts index 5f17fdedb78..18cc58ddaf1 100644 --- a/src/data/challenge.ts +++ b/src/data/challenge.ts @@ -273,11 +273,9 @@ export abstract class Challenge { * @param valid {@link Utils.BooleanHolder} A BooleanHolder, the value gets set to false if the pokemon isn't allowed. * @param dexAttr {@link DexAttrProps} The dex attributes of the pokemon. * @param soft {@link boolean} If true, allow it if it could become a valid pokemon. - * @param checkEvolutions {@link boolean} If true, check the pokemon's future evolutions - * @param checkForms {@link boolean} If true, check the pokemon's alternative forms * @returns {@link boolean} Whether this function did anything. */ - applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder, dexAttr: DexAttrProps, soft: boolean = false, checkEvolutions?: boolean, checkForms?: boolean): boolean { + applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder, dexAttr: DexAttrProps, soft: boolean = false): boolean { return false; } @@ -405,14 +403,13 @@ export class SingleGenerationChallenge extends Challenge { super(Challenges.SINGLE_GENERATION, 9); } - applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder, dexAttr: DexAttrProps, soft: boolean = false, checkEvolutions?: boolean): boolean { + applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder, dexAttr: DexAttrProps, soft: boolean = false): boolean { const generations = [pokemon.generation]; - const checkPokemonEvolutions = checkEvolutions ?? true as boolean; if (soft) { const speciesToCheck = [pokemon.speciesId]; while (speciesToCheck.length) { const checking = speciesToCheck.pop(); - if (checking && pokemonEvolutions.hasOwnProperty(checking) && checkPokemonEvolutions) { + if (checking && pokemonEvolutions.hasOwnProperty(checking)) { pokemonEvolutions[checking].forEach(e => { speciesToCheck.push(e.speciesId); generations.push(getPokemonSpecies(e.speciesId).generation); @@ -533,22 +530,20 @@ export class SingleTypeChallenge extends Challenge { super(Challenges.SINGLE_TYPE, 18); } - applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder, dexAttr: DexAttrProps, soft: boolean = false, checkEvolutions?: boolean, checkForms?: boolean): boolean { + applyStarterChoice(pokemon: PokemonSpecies, valid: Utils.BooleanHolder, dexAttr: DexAttrProps, soft: boolean = false): boolean { const speciesForm = getPokemonSpeciesForm(pokemon.speciesId, dexAttr.formIndex); const types = [speciesForm.type1, speciesForm.type2]; - const checkPokemonEvolutions = checkEvolutions ?? true as boolean; - const checkPokemonForms = checkForms ?? true as boolean; if (soft) { const speciesToCheck = [pokemon.speciesId]; while (speciesToCheck.length) { const checking = speciesToCheck.pop(); - if (checking && pokemonEvolutions.hasOwnProperty(checking) && checkPokemonEvolutions) { + if (checking && pokemonEvolutions.hasOwnProperty(checking)) { pokemonEvolutions[checking].forEach(e => { speciesToCheck.push(e.speciesId); types.push(getPokemonSpecies(e.speciesId).type1, getPokemonSpecies(e.speciesId).type2); }); } - if (checking && pokemonFormChanges.hasOwnProperty(checking) && checkPokemonForms) { + if (checking && pokemonFormChanges.hasOwnProperty(checking)) { pokemonFormChanges[checking].forEach(f1 => { getPokemonSpecies(checking).forms.forEach(f2 => { if (f1.formKey === f2.formKey) { @@ -746,7 +741,7 @@ export class LowerStarterPointsChallenge extends Challenge { * @param soft {@link boolean} If true, allow it if it could become a valid pokemon. * @returns True if any challenge was successfully applied. */ -export function applyChallenges(gameMode: GameMode, challengeType: ChallengeType.STARTER_CHOICE, pokemon: PokemonSpecies, valid: Utils.BooleanHolder, dexAttr: DexAttrProps, soft: boolean, checkEvolutions?: boolean, checkForms?: boolean): boolean; +export function applyChallenges(gameMode: GameMode, challengeType: ChallengeType.STARTER_CHOICE, pokemon: PokemonSpecies, valid: Utils.BooleanHolder, dexAttr: DexAttrProps, soft: boolean): boolean; /** * Apply all challenges that modify available total starter points. * @param gameMode {@link GameMode} The current gameMode @@ -854,7 +849,7 @@ export function applyChallenges(gameMode: GameMode, challengeType: ChallengeType if (c.value !== 0) { switch (challengeType) { case ChallengeType.STARTER_CHOICE: - ret ||= c.applyStarterChoice(args[0], args[1], args[2], args[3], args[4], args[5]); + ret ||= c.applyStarterChoice(args[0], args[1], args[2], args[3]); break; case ChallengeType.STARTER_POINTS: ret ||= c.applyStarterPoints(args[0]); diff --git a/src/system/game-data.ts b/src/system/game-data.ts index 8b756735ee6..b483ada2829 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -197,6 +197,7 @@ export interface StarterAttributes { variant?: integer; form?: integer; female?: boolean; + shiny?: boolean; } export interface StarterPreferences { diff --git a/src/test/ui/starter-select.test.ts b/src/test/ui/starter-select.test.ts index b61338bfcad..020b26b7f66 100644 --- a/src/test/ui/starter-select.test.ts +++ b/src/test/ui/starter-select.test.ts @@ -51,6 +51,9 @@ describe("UI - Starter select", () => { const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; handler.processInput(Button.RIGHT); handler.processInput(Button.LEFT); + handler.processInput(Button.CYCLE_SHINY); + handler.processInput(Button.V); + handler.processInput(Button.V); handler.processInput(Button.ACTION); game.phaseInterceptor.unlock(); }); @@ -112,6 +115,9 @@ describe("UI - Starter select", () => { handler.processInput(Button.RIGHT); handler.processInput(Button.LEFT); handler.processInput(Button.CYCLE_GENDER); + handler.processInput(Button.CYCLE_SHINY); + handler.processInput(Button.V); + handler.processInput(Button.V); handler.processInput(Button.ACTION); game.phaseInterceptor.unlock(); }); @@ -176,6 +182,9 @@ describe("UI - Starter select", () => { handler.processInput(Button.CYCLE_GENDER); handler.processInput(Button.CYCLE_NATURE); handler.processInput(Button.CYCLE_ABILITY); + handler.processInput(Button.CYCLE_SHINY); + handler.processInput(Button.V); + handler.processInput(Button.V); handler.processInput(Button.ACTION); game.phaseInterceptor.unlock(); }); @@ -238,6 +247,9 @@ describe("UI - Starter select", () => { handler.processInput(Button.RIGHT); handler.processInput(Button.LEFT); handler.processInput(Button.CYCLE_GENDER); + handler.processInput(Button.CYCLE_SHINY); + handler.processInput(Button.V); + handler.processInput(Button.V); handler.processInput(Button.ACTION); game.phaseInterceptor.unlock(); }); @@ -298,7 +310,6 @@ describe("UI - Starter select", () => { const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; handler.processInput(Button.RIGHT); handler.processInput(Button.LEFT); - handler.processInput(Button.CYCLE_SHINY); handler.processInput(Button.ACTION); game.phaseInterceptor.unlock(); }); @@ -358,7 +369,7 @@ describe("UI - Starter select", () => { const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; handler.processInput(Button.RIGHT); handler.processInput(Button.LEFT); - handler.processInput(Button.V); + handler.processInput(Button.CYCLE_SHINY); handler.processInput(Button.V); handler.processInput(Button.ACTION); game.phaseInterceptor.unlock(); @@ -419,7 +430,7 @@ describe("UI - Starter select", () => { const handler = game.scene.ui.getHandler() as StarterSelectUiHandler; handler.processInput(Button.RIGHT); handler.processInput(Button.LEFT); - handler.processInput(Button.V); + handler.processInput(Button.CYCLE_SHINY); handler.processInput(Button.V); handler.processInput(Button.V); handler.processInput(Button.ACTION); diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index 447f5c95e46..5a6271cbc4b 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -1303,11 +1303,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler { const isPartyValid = this.isPartyValid(); const isValidForChallenge = new Utils.BooleanHolder(true); - if (isPartyValid) { - Challenge.applyChallenges(this.scene.gameMode, Challenge.ChallengeType.STARTER_CHOICE, species, isValidForChallenge, this.scene.gameData.getSpeciesDexAttrProps(species, this.scene.gameData.getSpeciesDefaultDexAttr(species, false, true)), this.starterSpecies.length !== 0); - } else { - Challenge.applyChallenges(this.scene.gameMode, Challenge.ChallengeType.STARTER_CHOICE, species, isValidForChallenge, this.scene.gameData.getSpeciesDexAttrProps(species, this.scene.gameData.getSpeciesDefaultDexAttr(species, false, true)), this.starterSpecies.length !== 0, false, false); - } + + Challenge.applyChallenges(this.scene.gameMode, Challenge.ChallengeType.STARTER_CHOICE, species, isValidForChallenge, this.scene.gameData.getSpeciesDexAttrProps(species, this.getCurrentDexProps(species.speciesId)), isPartyValid); const currentPartyValue = this.starterSpecies.map(s => s.generation).reduce((total: number, gen: number, i: number) => total += this.scene.gameData.getSpeciesStarterValue(this.starterSpecies[i].speciesId), 0); const newCost = this.scene.gameData.getSpeciesStarterValue(species.speciesId); @@ -1661,7 +1658,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { success = true; } } else { - const props = this.scene.gameData.getSpeciesDexAttrProps(this.lastSpecies, this.dexAttrCursor); + const props = this.scene.gameData.getSpeciesDexAttrProps(this.lastSpecies, this.getCurrentDexProps(this.lastSpecies.speciesId)); // prepare persistent starter data to store changes let starterAttributes = this.starterPreferences[this.lastSpecies.speciesId]; if (!starterAttributes) { @@ -1671,8 +1668,9 @@ export default class StarterSelectUiHandler extends MessageUiHandler { case Button.CYCLE_SHINY: if (this.canCycleShiny) { const newVariant = props.variant; + starterAttributes.shiny = starterAttributes.shiny ? !starterAttributes.shiny : true; this.setSpeciesDetails(this.lastSpecies, !props.shiny, undefined, undefined, props.shiny ? 0 : undefined, undefined, undefined); - if (this.dexAttrCursor & DexAttr.SHINY) { + if (starterAttributes.shiny) { this.scene.playSound("sparkle"); // Set the variant label to the shiny tint const tint = getVariantTint(newVariant); @@ -1680,6 +1678,10 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.pokemonShinyIcon.setTint(tint); this.pokemonShinyIcon.setVisible(true); } else { + // starterAttributes.variant = 0; + if (starterAttributes?.variant) { + delete starterAttributes.variant; + } this.pokemonShinyIcon.setVisible(false); success = true; } @@ -1948,6 +1950,13 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.updateInstructions(); } + updatePartyIcon(species: PokemonSpecies, index: number) { + const props = this.scene.gameData.getSpeciesDexAttrProps(species, this.getCurrentDexProps(species.speciesId)); + this.starterIcons[index].setTexture(species.getIconAtlasKey(props.formIndex, props.shiny, props.variant)); + this.starterIcons[index].setFrame(species.getIconId(props.female, props.formIndex, props.shiny, props.variant)); + this.checkIconId(this.starterIcons[index], species, props.female, props.formIndex, props.shiny, props.variant); + } + switchMoveHandler(i: number, newMove: Moves, move: Moves) { const speciesId = this.lastSpecies.speciesId; const existingMoveIndex = this.starterMoveset?.indexOf(newMove)!; // TODO: is this bang correct? @@ -2099,9 +2108,24 @@ export default class StarterSelectUiHandler extends MessageUiHandler { // pre filter for challenges if (this.scene.gameMode.modeId === GameModes.CHALLENGE) { this.starterContainers.forEach(container => { - const isValidForChallenge = new Utils.BooleanHolder(true); - Challenge.applyChallenges(this.scene.gameMode, Challenge.ChallengeType.STARTER_CHOICE, container.species, isValidForChallenge, this.scene.gameData.getSpeciesDexAttrProps(container.species, this.scene.gameData.getSpeciesDefaultDexAttr(container.species, false, true)), true); - if (isValidForChallenge.value) { + const species = container.species; + let allFormsValid = false; + if (species.forms?.length > 0) { + for (let i = 0; i < species.forms.length; i++) { + /* Here we are making a fake form index dex props for challenges + * Since some pokemon rely on forms to be valid (i.e. blaze tauros for fire challenges), we make a fake form and dex props to use in the challenge + */ + const tempFormProps = BigInt(Math.pow(2, i)) * DexAttr.DEFAULT_FORM; + const isValidForChallenge = new Utils.BooleanHolder(true); + Challenge.applyChallenges(this.scene.gameMode, Challenge.ChallengeType.STARTER_CHOICE, container.species, isValidForChallenge, this.scene.gameData.getSpeciesDexAttrProps(species, tempFormProps), true); + allFormsValid = allFormsValid || isValidForChallenge.value; + } + } else { + const isValidForChallenge = new Utils.BooleanHolder(true); + Challenge.applyChallenges(this.scene.gameMode, Challenge.ChallengeType.STARTER_CHOICE, container.species, isValidForChallenge, this.scene.gameData.getSpeciesDexAttrProps(species, this.scene.gameData.getSpeciesDefaultDexAttr(container.species, false, true)), true); + allFormsValid = isValidForChallenge.value; + } + if (allFormsValid) { this.validStarterContainers.push(container); } else { container.setVisible(false); @@ -2111,6 +2135,18 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.validStarterContainers = this.starterContainers; } + // this updates icons for previously saved pokemon + for (let i = 0; i < this.validStarterContainers.length; i++) { + const currentFilteredContainer = this.validStarterContainers[i]; + const starterSprite = currentFilteredContainer.icon as Phaser.GameObjects.Sprite; + + const currentDexAttr = this.getCurrentDexProps(currentFilteredContainer.species.speciesId); + const props = this.scene.gameData.getSpeciesDexAttrProps(currentFilteredContainer.species, currentDexAttr); + + starterSprite.setTexture(currentFilteredContainer.species.getIconAtlasKey(props.formIndex, props.shiny, props.variant), currentFilteredContainer.species.getIconId(props.female!, props.formIndex, props.shiny, props.variant)); + currentFilteredContainer.checkIconId(props.female, props.formIndex, props.shiny, props.variant); + } + // filter this.validStarterContainers.forEach(container => { container.setVisible(false); @@ -2336,9 +2372,9 @@ export default class StarterSelectUiHandler extends MessageUiHandler { const species = this.filteredStarterContainers[cursor]?.species; if (species) { - const defaultDexAttr = this.scene.gameData.getSpeciesDefaultDexAttr(species, false, true); + const defaultDexAttr = this.getCurrentDexProps(species.speciesId); const defaultProps = this.scene.gameData.getSpeciesDexAttrProps(species, defaultDexAttr); - const variant = defaultProps.variant; + const variant = this.starterPreferences[species.speciesId]?.variant ? this.starterPreferences[species.speciesId].variant as Variant : defaultProps.variant; const tint = getVariantTint(variant); this.pokemonShinyIcon.setFrame(getVariantIcon(variant)); this.pokemonShinyIcon.setTint(tint); @@ -2384,7 +2420,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { setSpecies(species: PokemonSpecies | null) { this.speciesStarterDexEntry = species ? this.scene.gameData.dexData[species.speciesId] : null; - this.dexAttrCursor = species ? this.scene.gameData.getSpeciesDefaultDexAttr(species, false, true) : 0n; + this.dexAttrCursor = species ? this.getCurrentDexProps(species.speciesId) : 0n; this.abilityCursor = species ? this.scene.gameData.getStarterSpeciesDefaultAbilityIndex(species) : 0; this.natureCursor = species ? this.scene.gameData.getSpeciesDefaultNature(species) : 0; @@ -2454,7 +2490,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { } if (this.lastSpecies) { - const dexAttr = this.scene.gameData.getSpeciesDefaultDexAttr(this.lastSpecies, false, true); + const dexAttr = this.getCurrentDexProps(this.lastSpecies.speciesId); const props = this.scene.gameData.getSpeciesDexAttrProps(this.lastSpecies, dexAttr); const speciesIndex = this.allSpecies.indexOf(this.lastSpecies); const lastSpeciesIcon = this.starterContainers[speciesIndex].icon; @@ -2480,7 +2516,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.pokemonLuckText.setText(luck.toString()); this.pokemonLuckText.setTint(getVariantTint(Math.min(luck - 1, 2) as Variant)); this.pokemonLuckLabelText.setVisible(this.pokemonLuckText.visible); - this.pokemonShinyIcon.setVisible(this.pokemonLuckText.visible); + this.pokemonShinyIcon.setVisible(this.starterPreferences[species.speciesId]?.shiny ?? false); //Growth translate let growthReadable = Utils.toReadableString(GrowthRate[species.growthRate]); @@ -2504,7 +2540,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.pokemonHatchedIcon.setFrame(getEggTierForSpecies(species)); } this.pokemonHatchedCountText.setText(`${this.speciesStarterDexEntry.hatchedCount}`); - const defaultDexAttr = this.scene.gameData.getSpeciesDefaultDexAttr(species, false, true); + const defaultDexAttr = this.getCurrentDexProps(species.speciesId); const defaultProps = this.scene.gameData.getSpeciesDexAttrProps(species, defaultDexAttr); const variant = defaultProps.variant; const tint = getVariantTint(variant); @@ -2578,13 +2614,13 @@ export default class StarterSelectUiHandler extends MessageUiHandler { props = this.scene.gameData.getSpeciesDexAttrProps(species, this.starterAttr[starterIndex]); this.setSpeciesDetails(species, props.shiny, props.formIndex, props.female, props.variant, this.starterAbilityIndexes[starterIndex], this.starterNatures[starterIndex]); } else { - const defaultDexAttr = this.scene.gameData.getSpeciesDefaultDexAttr(species, false, true); + const defaultDexAttr = this.getCurrentDexProps(species.speciesId); const defaultAbilityIndex = starterAttributes?.ability ?? this.scene.gameData.getStarterSpeciesDefaultAbilityIndex(species); // load default nature from stater save data, if set const defaultNature = starterAttributes?.nature || this.scene.gameData.getSpeciesDefaultNature(species); props = this.scene.gameData.getSpeciesDexAttrProps(species, defaultDexAttr); if (starterAttributes?.variant && !isNaN(starterAttributes.variant)) { - if (props.shiny = (starterAttributes.variant >= 0)) { + if (props.shiny) { props.variant = starterAttributes.variant as Variant; } } @@ -2679,6 +2715,10 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.dexAttrCursor |= this.scene.gameData.getFormAttr(formIndex !== undefined ? formIndex : (formIndex = oldProps!.formIndex)); // TODO: is this bang correct? this.abilityCursor = abilityIndex !== undefined ? abilityIndex : (abilityIndex = oldAbilityIndex); this.natureCursor = natureIndex !== undefined ? natureIndex : (natureIndex = oldNatureIndex); + const [isInParty, partyIndex]: [boolean, number] = this.isInParty(species); // we use this to firstly check if the pokemon is in the party, and if so, to get the party index in order to update the icon image + if (isInParty) { + this.updatePartyIcon(species, partyIndex); + } } this.pokemonSprite.setVisible(false); @@ -2695,7 +2735,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { const dexEntry = this.scene.gameData.dexData[species.speciesId]; const abilityAttr = this.scene.gameData.starterData[species.speciesId].abilityAttr; if (!dexEntry.caughtAttr) { - const props = this.scene.gameData.getSpeciesDexAttrProps(species, this.scene.gameData.getSpeciesDefaultDexAttr(species, forSeen, !forSeen)); + const props = this.scene.gameData.getSpeciesDexAttrProps(species, this.getCurrentDexProps(species.speciesId)); const defaultAbilityIndex = this.scene.gameData.getStarterSpeciesDefaultAbilityIndex(species); const defaultNature = this.scene.gameData.getSpeciesDefaultNature(species); if (shiny === undefined || shiny !== props.shiny) { @@ -2750,9 +2790,10 @@ export default class StarterSelectUiHandler extends MessageUiHandler { const isValidForChallenge = new Utils.BooleanHolder(true); Challenge.applyChallenges(this.scene.gameMode, Challenge.ChallengeType.STARTER_CHOICE, species, isValidForChallenge, this.scene.gameData.getSpeciesDexAttrProps(species, this.dexAttrCursor), !!this.starterSpecies.length); - const starterSprite = this.filteredStarterContainers[this.cursor].icon as Phaser.GameObjects.Sprite; - starterSprite.setTexture(species.getIconAtlasKey(formIndex, shiny, variant), species.getIconId(female!, formIndex, shiny, variant)); // TODO: is this bang correct? - this.filteredStarterContainers[this.cursor].checkIconId(female, formIndex, shiny, variant); + const currentFilteredContainer = this.filteredStarterContainers.find(p => p.species.speciesId === species.speciesId)!; + const starterSprite = currentFilteredContainer.icon as Phaser.GameObjects.Sprite; + starterSprite.setTexture(species.getIconAtlasKey(formIndex, shiny, variant), species.getIconId(female!, formIndex, shiny, variant)); + currentFilteredContainer.checkIconId(female, formIndex, shiny, variant); this.canCycleShiny = !!(dexEntry.caughtAttr & DexAttr.NON_SHINY && dexEntry.caughtAttr & DexAttr.SHINY); this.canCycleGender = !!(dexEntry.caughtAttr & DexAttr.MALE && dexEntry.caughtAttr & DexAttr.FEMALE); this.canCycleAbility = [ abilityAttr & AbilityAttr.ABILITY_1, (abilityAttr & AbilityAttr.ABILITY_2) && species.ability2, abilityAttr & AbilityAttr.ABILITY_HIDDEN ].filter(a => a).length > 1; @@ -2876,6 +2917,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.pokemonAdditionalMoveCountLabel.setText(`(+${Math.max(this.speciesStarterMoves.length - 4, 0)})`); this.pokemonAdditionalMoveCountLabel.setVisible(this.speciesStarterMoves.length > 4); + this.tryUpdateValue(); + this.updateInstructions(); } @@ -2903,7 +2946,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { for (let s = 0; s < this.starterSpecies.length; s++) { const species = this.starterSpecies[s]; - const currentDexAttr = this.scene.gameData.getSpeciesDefaultDexAttr(species, false, true); + const currentDexAttr = this.getCurrentDexProps(species.speciesId); const props = this.scene.gameData.getSpeciesDexAttrProps(species, currentDexAttr); this.starterIcons[s].setTexture(species.getIconAtlasKey(props.formIndex, props.shiny, props.variant)); this.starterIcons[s].setFrame(species.getIconId(props.female, props.formIndex, props.shiny, props.variant)); @@ -2984,7 +3027,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { if (addingToParty) { // this does a check to see if the pokemon being added is valid; if so, it will update the isPartyValid boolean const isNewPokemonValid = new Utils.BooleanHolder(true); const species = this.filteredStarterContainers[this.cursor].species; - Challenge.applyChallenges(this.scene.gameMode, Challenge.ChallengeType.STARTER_CHOICE, species, isNewPokemonValid, this.scene.gameData.getSpeciesDexAttrProps(species, this.scene.gameData.getSpeciesDefaultDexAttr(species, false, true)), !!(this.starterSpecies.length), false, false); + Challenge.applyChallenges(this.scene.gameMode, Challenge.ChallengeType.STARTER_CHOICE, species, isNewPokemonValid, this.scene.gameData.getSpeciesDexAttrProps(species, this.getCurrentDexProps(species.speciesId)), false); isPartyValid = isPartyValid || isNewPokemonValid.value; } @@ -3013,11 +3056,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { * we change to can AddParty value to true since the user has enough cost to choose this pokemon and this pokemon registered too. */ const isValidForChallenge = new Utils.BooleanHolder(true); - if (isPartyValid) { // we have two checks here - one for the party being valid and one for not. This comes from mono type challenges - if the party is valid it will check pokemon's evolutions and forms, and if it's not valid it won't check their evolutions and forms - Challenge.applyChallenges(this.scene.gameMode, Challenge.ChallengeType.STARTER_CHOICE, this.allSpecies[s], isValidForChallenge, this.scene.gameData.getSpeciesDexAttrProps(this.allSpecies[s], this.scene.gameData.getSpeciesDefaultDexAttr(this.allSpecies[s], false, true)), !!(this.starterSpecies.length + (add ? 1 : 0))); - } else { - Challenge.applyChallenges(this.scene.gameMode, Challenge.ChallengeType.STARTER_CHOICE, this.allSpecies[s], isValidForChallenge, this.scene.gameData.getSpeciesDexAttrProps(this.allSpecies[s], this.scene.gameData.getSpeciesDefaultDexAttr(this.allSpecies[s], false, true)), !!(this.starterSpecies.length + (add ? 1 : 0)), false, false); - } + Challenge.applyChallenges(this.scene.gameMode, Challenge.ChallengeType.STARTER_CHOICE, this.allSpecies[s], isValidForChallenge, this.scene.gameData.getSpeciesDexAttrProps(this.allSpecies[s], this.getCurrentDexProps(this.allSpecies[s].speciesId)), isPartyValid); const canBeChosen = remainValue >= speciesStarterValue && isValidForChallenge.value; @@ -3132,12 +3171,50 @@ export default class StarterSelectUiHandler extends MessageUiHandler { for (let s = 0; s < this.starterSpecies.length; s++) { const isValidForChallenge = new Utils.BooleanHolder(true); const species = this.starterSpecies[s]; - Challenge.applyChallenges(this.scene.gameMode, Challenge.ChallengeType.STARTER_CHOICE, species, isValidForChallenge, this.scene.gameData.getSpeciesDexAttrProps(species, this.dexAttrCursor), this.starterSpecies.length !== 0, false, false); + Challenge.applyChallenges(this.scene.gameMode, Challenge.ChallengeType.STARTER_CHOICE, species, isValidForChallenge, this.scene.gameData.getSpeciesDexAttrProps(species, this.getCurrentDexProps(species.speciesId)), false); canStart = canStart || isValidForChallenge.value; } return canStart; } + /* this creates a temporary dex attr props that we use to check whether a pokemon is valid for a challenge. + * when checking for certain challenges (i.e. mono type), we need to check for form changes AND evolutions + * However, since some pokemon can evolve based on their intial gender/form, we need a way to look for that + * This temporary dex attr will therefore ONLY look at gender and form, since there's no cases of shinies/variants + * having different evolutions to their non shiny/variant part, and so those can be ignored + * Since the current form and gender is stored in the starter preferences, this is where we get the values from + */ + getCurrentDexProps(speciesId: number): bigint { + let props = 0n; + + if (this.starterPreferences[speciesId]?.female) { // this checks the gender of the pokemon + props += DexAttr.FEMALE; + } else { + props += DexAttr.MALE; + } + if (this.starterPreferences[speciesId]?.shiny) { + props += DexAttr.SHINY; + if (this.starterPreferences[speciesId]?.variant) { + props += BigInt(Math.pow(2, this.starterPreferences[speciesId]?.variant)) * DexAttr.DEFAULT_VARIANT; + } else { + props += DexAttr.DEFAULT_VARIANT; + } + } else { + props += DexAttr.NON_SHINY; + if (this.starterPreferences[speciesId]?.variant) { + delete this.starterPreferences[speciesId].variant; + } + props += DexAttr.DEFAULT_VARIANT; // we add the default variant here because non shiny versions are listed as default variant + } + if (this.starterPreferences[speciesId]?.form) { // this checks for the form of the pokemon + props += BigInt(Math.pow(2, this.starterPreferences[speciesId]?.form)) * DexAttr.DEFAULT_FORM; + } else { + props += DexAttr.DEFAULT_FORM; + } + + return props; + } + toggleStatsMode(on?: boolean): void { if (on === undefined) { on = !this.statsMode; From f0d4dfa09e45f4fd8a21bad89d036a78cc6d087e Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Thu, 8 Aug 2024 11:02:02 -0700 Subject: [PATCH 035/282] [Test] Mock turn order in Miracle Eye test (#3437) --- src/test/moves/miracle_eye.test.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/test/moves/miracle_eye.test.ts b/src/test/moves/miracle_eye.test.ts index 53d575ea96d..8bfa0f4bfc1 100644 --- a/src/test/moves/miracle_eye.test.ts +++ b/src/test/moves/miracle_eye.test.ts @@ -2,10 +2,11 @@ import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import Phaser from "phaser"; import GameManager from "#test/utils/gameManager"; import { Species } from "#app/enums/species.js"; -import { SPLASH_ONLY } from "../utils/testUtils"; +import { mockTurnOrder, SPLASH_ONLY } from "../utils/testUtils"; import { Moves } from "#app/enums/moves.js"; import { getMovePosition } from "../utils/gameManagerUtils"; import { MoveEffectPhase } from "#app/phases.js"; +import { BattlerIndex } from "#app/battle.js"; describe("Internals", () => { let phaserGame: Phaser.Game; @@ -38,6 +39,7 @@ describe("Internals", () => { const enemy = game.scene.getEnemyPokemon()!; game.doAttack(getMovePosition(game.scene, 0, Moves.CONFUSION)); + await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.toNextTurn(); expect(enemy.hp).toBe(enemy.getMaxHp()); From b5a40bfdfc5a173beee5c8c0b08d456e10e09e1a Mon Sep 17 00:00:00 2001 From: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> Date: Thu, 8 Aug 2024 20:02:26 +0200 Subject: [PATCH 036/282] [Localization] German missing keys (#3436) * Add all keys that are in english but missing in german * useless change * Revert "useless change" This reverts commit 15cff42d8d8b713ebc7a1dee84a6b465797e319d. --- src/locales/de/ability-trigger.ts | 2 +- src/locales/de/pokemon-info-container.ts | 1 + src/locales/de/pokemon-info.ts | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/locales/de/ability-trigger.ts b/src/locales/de/ability-trigger.ts index 3c9586fb6f2..30433ec9bdd 100644 --- a/src/locales/de/ability-trigger.ts +++ b/src/locales/de/ability-trigger.ts @@ -1,7 +1,7 @@ import { SimpleTranslationEntries } from "#app/interfaces/locales"; export const abilityTriggers: SimpleTranslationEntries = { - "blockRecoilDamage" : "{{pokemonName}} wurde durch {{abilityName}} vor Rückstoß geschützt!", + "blockRecoilDamage": "{{pokemonName}} wurde durch {{abilityName}} vor Rückstoß geschützt!", "badDreams": "{{pokemonName}} ist in einem Alptraum gefangen!", "costar": "{{pokemonName}} kopiert die Statusveränderungen von {{allyName}}!", "iceFaceAvoidedDamage": "{{pokemonName}} wehrt Schaden mit {{abilityName}} ab!", diff --git a/src/locales/de/pokemon-info-container.ts b/src/locales/de/pokemon-info-container.ts index 1f82cf2cd83..9540d858cd8 100644 --- a/src/locales/de/pokemon-info-container.ts +++ b/src/locales/de/pokemon-info-container.ts @@ -5,4 +5,5 @@ export const pokemonInfoContainer: SimpleTranslationEntries = { "gender": "Geschlecht:", "ability": "Fähigkeit:", "nature": "Wesen:", + "form": "Form:", } as const; diff --git a/src/locales/de/pokemon-info.ts b/src/locales/de/pokemon-info.ts index 08a23de2b3a..b926c0c5115 100644 --- a/src/locales/de/pokemon-info.ts +++ b/src/locales/de/pokemon-info.ts @@ -3,6 +3,7 @@ import { PokemonInfoTranslationEntries } from "#app/interfaces/locales"; export const pokemonInfo: PokemonInfoTranslationEntries = { Stat: { "HP": "KP", + "HPStat": "KP", "HPshortened": "KP", "ATK": "Angriff", "ATKshortened": "Ang", From b4a891cc713297d703fb4914e3faaddffab5e2af Mon Sep 17 00:00:00 2001 From: innerthunder <168692175+innerthunder@users.noreply.github.com> Date: Thu, 8 Aug 2024 11:03:28 -0700 Subject: [PATCH 037/282] [Move] Reimplement Beak Blast (#3427) * Re-Implement Beak Blast * Fix charge animation loading issues --- src/data/battle-anims.ts | 10 ++- src/data/battler-tags.ts | 42 +++++++++- src/data/move.ts | 37 ++++---- src/enums/battler-tag-type.ts | 3 +- src/phases.ts | 1 + src/test/moves/beak_blast.test.ts | 135 ++++++++++++++++++++++++++++++ 6 files changed, 207 insertions(+), 21 deletions(-) create mode 100644 src/test/moves/beak_blast.test.ts diff --git a/src/data/battle-anims.ts b/src/data/battle-anims.ts index d9fc87c67c7..bcf3bd7bb40 100644 --- a/src/data/battle-anims.ts +++ b/src/data/battle-anims.ts @@ -1,6 +1,6 @@ //import { battleAnimRawData } from "./battle-anim-raw-data"; import BattleScene from "../battle-scene"; -import { AttackMove, ChargeAttr, DelayedAttackAttr, MoveFlags, SelfStatusMove, allMoves } from "./move"; +import { AttackMove, BeakBlastHeaderAttr, ChargeAttr, DelayedAttackAttr, MoveFlags, SelfStatusMove, allMoves } from "./move"; import Pokemon from "../field/pokemon"; import * as Utils from "../utils"; import { BattlerIndex } from "../battle"; @@ -499,7 +499,9 @@ export function initMoveAnim(scene: BattleScene, move: Moves): Promise { } else { populateMoveAnim(move, ba); } - const chargeAttr = allMoves[move].getAttrs(ChargeAttr)[0] || allMoves[move].getAttrs(DelayedAttackAttr)[0]; + const chargeAttr = allMoves[move].getAttrs(ChargeAttr)[0] + || allMoves[move].getAttrs(DelayedAttackAttr)[0] + || allMoves[move].getAttrs(BeakBlastHeaderAttr)[0]; if (chargeAttr) { initMoveChargeAnim(scene, chargeAttr.chargeAnim).then(() => resolve()); } else { @@ -570,7 +572,9 @@ export function loadMoveAnimAssets(scene: BattleScene, moveIds: Moves[], startLo return new Promise(resolve => { const moveAnimations = moveIds.map(m => moveAnims.get(m) as AnimConfig).flat(); for (const moveId of moveIds) { - const chargeAttr = allMoves[moveId].getAttrs(ChargeAttr)[0] || allMoves[moveId].getAttrs(DelayedAttackAttr)[0]; + const chargeAttr = allMoves[moveId].getAttrs(ChargeAttr)[0] + || allMoves[moveId].getAttrs(DelayedAttackAttr)[0] + || allMoves[moveId].getAttrs(BeakBlastHeaderAttr)[0]; if (chargeAttr) { const moveChargeAnims = chargeAnims.get(chargeAttr.chargeAnim); moveAnimations.push(moveChargeAnims instanceof AnimConfig ? moveChargeAnims : moveChargeAnims![0]); // TODO: is the bang correct? diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index c25407d0599..16dd4914ed4 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -1,4 +1,4 @@ -import { CommonAnim, CommonBattleAnim } from "./battle-anims"; +import { ChargeAnim, CommonAnim, CommonBattleAnim, MoveChargeAnim } from "./battle-anims"; import { CommonAnimPhase, MoveEffectPhase, MovePhase, PokemonHealPhase, ShowAbilityPhase, StatChangeCallback, StatChangePhase } from "../phases"; import { getPokemonNameWithAffix } from "../messages"; import Pokemon, { MoveResult, HitResult } from "../field/pokemon"; @@ -118,6 +118,44 @@ export class RechargingTag extends BattlerTag { } } +/** + * BattlerTag representing the "charge phase" of Beak Blast + * Pokemon with this tag will inflict BURN status on any attacker that makes contact. + * @see {@link https://bulbapedia.bulbagarden.net/wiki/Beak_Blast_(move) | Beak Blast} + */ +export class BeakBlastChargingTag extends BattlerTag { + constructor() { + super(BattlerTagType.BEAK_BLAST_CHARGING, [ BattlerTagLapseType.PRE_MOVE, BattlerTagLapseType.TURN_END ], 1, Moves.BEAK_BLAST); + } + + onAdd(pokemon: Pokemon): void { + // Play Beak Blast's charging animation + new MoveChargeAnim(ChargeAnim.BEAK_BLAST_CHARGING, this.sourceMove, pokemon).play(pokemon.scene); + + // Queue Beak Blast's header message + pokemon.scene.queueMessage(i18next.t("moveTriggers:startedHeatingUpBeak", { pokemonName: getPokemonNameWithAffix(pokemon) })); + } + + /** + * Inflicts `BURN` status on attackers that make contact, and causes this tag + * to be removed after the source makes a move (or the turn ends, whichever comes first) + * @param pokemon {@linkcode Pokemon} the owner of this tag + * @param lapseType {@linkcode BattlerTagLapseType} the type of functionality invoked in battle + * @returns `true` if invoked with the CUSTOM lapse type; `false` otherwise + */ + lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { + if (lapseType === BattlerTagLapseType.CUSTOM) { + const effectPhase = pokemon.scene.getCurrentPhase(); + if (effectPhase instanceof MoveEffectPhase && effectPhase.move.getMove().hasFlag(MoveFlags.MAKES_CONTACT)) { + const attacker = effectPhase.getPokemon(); + attacker.trySetStatus(StatusEffect.BURN, true, pokemon); + } + return true; + } + return super.lapse(pokemon, lapseType); + } +} + export class TrappedTag extends BattlerTag { constructor(tagType: BattlerTagType, lapseType: BattlerTagLapseType, turnCount: number, sourceMove: Moves, sourceId: number) { super(tagType, lapseType, turnCount, sourceMove, sourceId); @@ -1738,6 +1776,8 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: number, source switch (tagType) { case BattlerTagType.RECHARGING: return new RechargingTag(sourceMove); + case BattlerTagType.BEAK_BLAST_CHARGING: + return new BeakBlastChargingTag(); case BattlerTagType.FLINCHED: return new FlinchedTag(sourceMove); case BattlerTagType.INTERRUPTED: diff --git a/src/data/move.ts b/src/data/move.ts index 14e7738b948..c43150992bc 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -1021,6 +1021,22 @@ export class MessageHeaderAttr extends MoveHeaderAttr { } } +/** + * Header attribute to implement the "charge phase" of Beak Blast at the + * beginning of a turn. + * @see {@link https://bulbapedia.bulbagarden.net/wiki/Beak_Blast_(move) | Beak Blast} + * @see {@linkcode BeakBlastChargingTag} + */ +export class BeakBlastHeaderAttr extends MoveHeaderAttr { + /** Required to initialize Beak Blast's charge animation correctly */ + public chargeAnim = ChargeAnim.BEAK_BLAST_CHARGING; + + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { + user.addTag(BattlerTagType.BEAK_BLAST_CHARGING); + return true; + } +} + export class PreMoveMessageAttr extends MoveAttr { private message: string | ((user: Pokemon, target: Pokemon, move: Move) => string); @@ -2391,24 +2407,21 @@ export class ChargeAttr extends OverrideMoveEffectAttr { private chargeText: string; private tagType: BattlerTagType | null; private chargeEffect: boolean; - public sameTurn: boolean; public followUpPriority: integer | null; - constructor(chargeAnim: ChargeAnim, chargeText: string, tagType?: BattlerTagType | null, chargeEffect: boolean = false, sameTurn: boolean = false, followUpPriority?: integer) { + constructor(chargeAnim: ChargeAnim, chargeText: string, tagType?: BattlerTagType | null, chargeEffect: boolean = false) { super(); this.chargeAnim = chargeAnim; this.chargeText = chargeText; this.tagType = tagType!; // TODO: is this bang correct? this.chargeEffect = chargeEffect; - this.sameTurn = sameTurn; - this.followUpPriority = followUpPriority!; // TODO: is this bang correct? } apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): Promise { return new Promise(resolve => { const lastMove = user.getLastXMoves().find(() => true); - if (!lastMove || lastMove.move !== move.id || (lastMove.result !== MoveResult.OTHER && (this.sameTurn || lastMove.turn !== user.scene.currentBattle.turn))) { + if (!lastMove || lastMove.move !== move.id || (lastMove.result !== MoveResult.OTHER && lastMove.turn !== user.scene.currentBattle.turn)) { (args[0] as Utils.BooleanHolder).value = true; new MoveChargeAnim(this.chargeAnim, move.id, user).play(user.scene, () => { user.scene.queueMessage(this.chargeText.replace("{TARGET}", getPokemonNameWithAffix(target)).replace("{USER}", getPokemonNameWithAffix(user))); @@ -2420,13 +2433,6 @@ export class ChargeAttr extends OverrideMoveEffectAttr { } user.pushMoveHistory({ move: move.id, targets: [ target.getBattlerIndex() ], result: MoveResult.OTHER }); user.getMoveQueue().push({ move: move.id, targets: [ target.getBattlerIndex() ], ignorePP: true }); - if (this.sameTurn) { - let movesetMove = user.moveset.find(m => m?.moveId === move.id); - if (!movesetMove) { // account for any move that calls a ChargeAttr move when the ChargeAttr move does not exist in moveset - movesetMove = new PokemonMove(move.id, 0, 0, true); - } - user.scene.pushMovePhase(new MovePhase(user.scene, user, [ target.getBattlerIndex() ], movesetMove, true), this.followUpPriority!); // TODO: is this bang correct? - } user.addTag(BattlerTagType.CHARGING, 1, move.id, user.id); resolve(true); }); @@ -8081,11 +8087,10 @@ export function initMoves() { .attr(StatChangeAttr, BattleStat.ATK, -1), new StatusMove(Moves.INSTRUCT, Type.PSYCHIC, -1, 15, -1, 0, 7) .unimplemented(), - new AttackMove(Moves.BEAK_BLAST, Type.FLYING, MoveCategory.PHYSICAL, 100, 100, 15, -1, 5, 7) - .attr(ChargeAttr, ChargeAnim.BEAK_BLAST_CHARGING, i18next.t("moveTriggers:startedHeatingUpBeak", {pokemonName: "{USER}"}), undefined, false, true, -3) + new AttackMove(Moves.BEAK_BLAST, Type.FLYING, MoveCategory.PHYSICAL, 100, 100, 15, -1, -3, 7) + .attr(BeakBlastHeaderAttr) .ballBombMove() - .makesContact(false) - .partial(), + .makesContact(false), new AttackMove(Moves.CLANGING_SCALES, Type.DRAGON, MoveCategory.SPECIAL, 110, 100, 5, -1, 0, 7) .attr(StatChangeAttr, BattleStat.DEF, -1, true, null, true, false, MoveEffectTrigger.HIT, true) .soundBased() diff --git a/src/enums/battler-tag-type.ts b/src/enums/battler-tag-type.ts index 405e8cc4822..fd1455eab6c 100644 --- a/src/enums/battler-tag-type.ts +++ b/src/enums/battler-tag-type.ts @@ -66,5 +66,6 @@ export enum BattlerTagType { IGNORE_GHOST = "IGNORE_GHOST", IGNORE_DARK = "IGNORE_DARK", GULP_MISSILE_ARROKUDA = "GULP_MISSILE_ARROKUDA", - GULP_MISSILE_PIKACHU = "GULP_MISSILE_PIKACHU" + GULP_MISSILE_PIKACHU = "GULP_MISSILE_PIKACHU", + BEAK_BLAST_CHARGING = "BEAK_BLAST_CHARGING" } diff --git a/src/phases.ts b/src/phases.ts index 5d72ffef42a..ad591a368d3 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -3087,6 +3087,7 @@ export class MoveEffectPhase extends PokemonPhase { Utils.executeIf(!isProtected && !chargeEffect, () => applyFilteredMoveAttrs((attr: MoveAttr) => attr instanceof MoveEffectAttr && (attr as MoveEffectAttr).trigger === MoveEffectTrigger.HIT && (!attr.firstHitOnly || firstHit) && (!attr.lastHitOnly || lastHit) && (!attr.firstTargetOnly || firstTarget), user, target, this.move.getMove()).then(() => { return Utils.executeIf(!target.isFainted() || target.canApplyAbility(), () => applyPostDefendAbAttrs(PostDefendAbAttr, target, user, this.move.getMove(), hitResult).then(() => { + target.lapseTag(BattlerTagType.BEAK_BLAST_CHARGING); if (!user.isPlayer() && this.move.getMove() instanceof AttackMove) { user.scene.applyShuffledModifiers(this.scene, EnemyAttackStatusEffectChanceModifier, false, target); } diff --git a/src/test/moves/beak_blast.test.ts b/src/test/moves/beak_blast.test.ts new file mode 100644 index 00000000000..61a022ac9eb --- /dev/null +++ b/src/test/moves/beak_blast.test.ts @@ -0,0 +1,135 @@ +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import GameManager from "#test/utils/gameManager"; +import { Species } from "#enums/species"; +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { BerryPhase, MovePhase, TurnEndPhase } from "#app/phases"; +import { BattlerTagType } from "#app/enums/battler-tag-type.js"; +import { StatusEffect } from "#app/enums/status-effect.js"; + +const TIMEOUT = 20 * 1000; + +describe("Moves - Beak Blast", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .battleType("single") + .ability(Abilities.UNNERVE) + .moveset([Moves.BEAK_BLAST]) + .enemySpecies(Species.SNORLAX) + .enemyAbility(Abilities.INSOMNIA) + .enemyMoveset(Array(4).fill(Moves.TACKLE)) + .startingLevel(100) + .enemyLevel(100); + }); + + it( + "should add a charge effect that burns attackers on contact", + async () => { + await game.startBattle([Species.BLASTOISE]); + + const leadPokemon = game.scene.getPlayerPokemon()!; + const enemyPokemon = game.scene.getEnemyPokemon()!; + + game.doAttack(getMovePosition(game.scene, 0, Moves.BEAK_BLAST)); + + await game.phaseInterceptor.to(MovePhase, false); + expect(leadPokemon.getTag(BattlerTagType.BEAK_BLAST_CHARGING)).toBeDefined(); + + await game.phaseInterceptor.to(BerryPhase, false); + expect(enemyPokemon.status?.effect).toBe(StatusEffect.BURN); + }, TIMEOUT + ); + + it( + "should still charge and burn opponents if the user is sleeping", + async () => { + game.override.statusEffect(StatusEffect.SLEEP); + + await game.startBattle([Species.BLASTOISE]); + + const leadPokemon = game.scene.getPlayerPokemon()!; + const enemyPokemon = game.scene.getEnemyPokemon()!; + + game.doAttack(getMovePosition(game.scene, 0, Moves.BEAK_BLAST)); + + await game.phaseInterceptor.to(MovePhase, false); + expect(leadPokemon.getTag(BattlerTagType.BEAK_BLAST_CHARGING)).toBeDefined(); + + await game.phaseInterceptor.to(BerryPhase, false); + expect(enemyPokemon.status?.effect).toBe(StatusEffect.BURN); + }, TIMEOUT + ); + + it( + "should not burn attackers that don't make contact", + async () => { + game.override.enemyMoveset(Array(4).fill(Moves.WATER_GUN)); + + await game.startBattle([Species.BLASTOISE]); + + const leadPokemon = game.scene.getPlayerPokemon()!; + const enemyPokemon = game.scene.getEnemyPokemon()!; + + game.doAttack(getMovePosition(game.scene, 0, Moves.BEAK_BLAST)); + + await game.phaseInterceptor.to(MovePhase, false); + expect(leadPokemon.getTag(BattlerTagType.BEAK_BLAST_CHARGING)).toBeDefined(); + + await game.phaseInterceptor.to(BerryPhase, false); + expect(enemyPokemon.status?.effect).not.toBe(StatusEffect.BURN); + }, TIMEOUT + ); + + it( + "should only hit twice with Multi-Lens", + async () => { + game.override.startingHeldItems([{name: "MULTI_LENS", count: 1}]); + + await game.startBattle([Species.BLASTOISE]); + + const leadPokemon = game.scene.getPlayerPokemon()!; + + game.doAttack(getMovePosition(game.scene, 0, Moves.BEAK_BLAST)); + + await game.phaseInterceptor.to(BerryPhase, false); + expect(leadPokemon.turnData.hitCount).toBe(2); + }, TIMEOUT + ); + + it( + "should be blocked by Protect", + async () => { + game.override.enemyMoveset(Array(4).fill(Moves.PROTECT)); + + await game.startBattle([Species.BLASTOISE]); + + const leadPokemon = game.scene.getPlayerPokemon()!; + const enemyPokemon = game.scene.getEnemyPokemon()!; + + game.doAttack(getMovePosition(game.scene, 0, Moves.BEAK_BLAST)); + + await game.phaseInterceptor.to(MovePhase, false); + expect(leadPokemon.getTag(BattlerTagType.BEAK_BLAST_CHARGING)).toBeDefined(); + + await game.phaseInterceptor.to(TurnEndPhase); + expect(enemyPokemon.hp).toBe(enemyPokemon.getMaxHp()); + expect(leadPokemon.getTag(BattlerTagType.BEAK_BLAST_CHARGING)).toBeUndefined(); + }, TIMEOUT + ); +}); From 15106b83fbaa9d780e2ac0cd66cce66d932f8f44 Mon Sep 17 00:00:00 2001 From: Enoch Date: Fri, 9 Aug 2024 03:04:04 +0900 Subject: [PATCH 038/282] [Localization(ja)] Translated ability-trigger.ts, status-effect.ts (#3428) * Translated ability-trigger.ts, status-effect.ts * Apply suggestions from code review Co-authored-by: Chapybara-jp * Apply suggestions from code review * Apply suggestions from code review * Apply suggestions from code review Co-authored-by: Chapybara-jp --------- Co-authored-by: Chapybara-jp --- src/locales/ja/ability-trigger.ts | 117 +++++++++++++++--------------- src/locales/ja/status-effect.ts | 86 +++++++++++----------- 2 files changed, 102 insertions(+), 101 deletions(-) diff --git a/src/locales/ja/ability-trigger.ts b/src/locales/ja/ability-trigger.ts index 445f09cbab7..a1ef05407be 100644 --- a/src/locales/ja/ability-trigger.ts +++ b/src/locales/ja/ability-trigger.ts @@ -1,62 +1,63 @@ import { SimpleTranslationEntries } from "#app/interfaces/locales"; export const abilityTriggers: SimpleTranslationEntries = { - "blockRecoilDamage" : "{{pokemonName}}は {{abilityName}}で\nはんどうダメージを うけない!", - "badDreams": "{{pokemonName}}は ナイトメアに うなされている!", - "costar": "{{pokemonName}} copied {{allyName}}'s stat changes!", - "iceFaceAvoidedDamage": "{{pokemonName}}は\n{{abilityName}}で ダメージを うけない!", - "perishBody": "{{pokemonName}}の {{abilityName}}で\nおたがいは 3ターンごに ほろびてしまう!", - "poisonHeal": "{{pokemonName}}は {{abilityName}}で\nかいふくした!", - "trace": "{{pokemonName}} copied {{targetName}}'s\n{{abilityName}}!", - "windPowerCharged": "{{pokemonName}}は\n{{moveName}}を うけて じゅうでんした!", - "quickDraw": "{{pokemonName}} can act faster than normal, thanks to its Quick Draw!", - "blockItemTheft": "{{pokemonNameWithAffix}}'s {{abilityName}}\nprevents item theft!", - "typeImmunityHeal": "{{pokemonNameWithAffix}}'s {{abilityName}}\nrestored its HP a little!", - "nonSuperEffectiveImmunity": "{{pokemonNameWithAffix}} avoided damage\nwith {{abilityName}}!", - "postDefendDisguise": "{{pokemonNameWithAffix}}'s disguise was busted!", - "moveImmunity": "It doesn't affect {{pokemonNameWithAffix}}!", - "reverseDrain": "{{pokemonNameWithAffix}} sucked up the liquid ooze!", - "postDefendTypeChange": "{{pokemonNameWithAffix}}'s {{abilityName}}\nmade it the {{typeName}} type!", - "postDefendContactDamage": "{{pokemonNameWithAffix}}'s {{abilityName}}\nhurt its attacker!", - "postDefendAbilitySwap": "{{pokemonNameWithAffix}} swapped\nabilities with its target!", - "postDefendAbilityGive": "{{pokemonNameWithAffix}} gave its target\n{{abilityName}}!", - "postDefendMoveDisable": "{{pokemonNameWithAffix}}'s {{moveName}}\nwas disabled!", - "pokemonTypeChange": "{{pokemonNameWithAffix}} transformed into the {{moveType}} type!", - "postAttackStealHeldItem": "{{pokemonNameWithAffix}} stole\n{{defenderName}}'s {{stolenItemType}}!", - "postDefendStealHeldItem": "{{pokemonNameWithAffix}} stole\n{{attackerName}}'s {{stolenItemType}}!", - "copyFaintedAllyAbility": "{{pokemonNameWithAffix}}'s {{abilityName}} was taken over!", - "intimidateImmunity": "{{pokemonNameWithAffix}}'s {{abilityName}} prevented it from being Intimidated!", - "postSummonAllyHeal": "{{pokemonNameWithAffix}} drank down all the\nmatcha that {{pokemonName}} made!", - "postSummonClearAllyStats": "{{pokemonNameWithAffix}}'s stat changes\nwere removed!", - "postSummonTransform": "{{pokemonNameWithAffix}} transformed\ninto {{targetName}}!", - "protectStat": "{{pokemonNameWithAffix}}'s {{abilityName}}\nprevents lowering its {{statName}}!", - "statusEffectImmunityWithName": "{{pokemonNameWithAffix}}'s {{abilityName}}\nprevents {{statusEffectName}}!", - "statusEffectImmunity": "{{pokemonNameWithAffix}}'s {{abilityName}}\nprevents status problems!", - "battlerTagImmunity": "{{pokemonNameWithAffix}}'s {{abilityName}}\nprevents {{battlerTagName}}!", - "forewarn": "{{pokemonNameWithAffix}} was forewarned about {{moveName}}!", - "frisk": "{{pokemonNameWithAffix}} frisked {{opponentName}}'s {{opponentAbilityName}}!", - "postWeatherLapseHeal": "{{pokemonNameWithAffix}}'s {{abilityName}}\nrestored its HP a little!", - "postWeatherLapseDamage": "{{pokemonNameWithAffix}} is hurt\nby its {{abilityName}}!", - "postTurnLootCreateEatenBerry": "{{pokemonNameWithAffix}} harvested one {{berryName}}!", - "postTurnHeal": "{{pokemonNameWithAffix}}'s {{abilityName}}\nrestored its HP a little!", - "fetchBall": "{{pokemonNameWithAffix}} found a\n{{pokeballName}}!", - "healFromBerryUse": "{{pokemonNameWithAffix}}'s {{abilityName}}\nrestored its HP!", - "arenaTrap": "{{pokemonNameWithAffix}}'s {{abilityName}}\nprevents switching!", - "postBattleLoot": "{{pokemonNameWithAffix}} picked up\n{{itemName}}!", - "postFaintContactDamage": "{{pokemonNameWithAffix}}'s {{abilityName}}\nhurt its attacker!", - "postFaintHpDamage": "{{pokemonNameWithAffix}}'s {{abilityName}}\nhurt its attacker!", - "postSummonPressure": "{{pokemonNameWithAffix}} is exerting its Pressure!", - "postSummonMoldBreaker": "{{pokemonNameWithAffix}} breaks the mold!", - "postSummonAnticipation": "{{pokemonNameWithAffix}} shuddered!", - "postSummonTurboblaze": "{{pokemonNameWithAffix}} is radiating a blazing aura!", - "postSummonTeravolt": "{{pokemonNameWithAffix}} is radiating a bursting aura!", - "postSummonDarkAura": "{{pokemonNameWithAffix}} is radiating a Dark Aura!", - "postSummonFairyAura": "{{pokemonNameWithAffix}} is radiating a Fairy Aura!", - "postSummonNeutralizingGas": "{{pokemonNameWithAffix}}'s Neutralizing Gas filled the area!", - "postSummonAsOneGlastrier": "{{pokemonNameWithAffix}} has two Abilities!", - "postSummonAsOneSpectrier": "{{pokemonNameWithAffix}} has two Abilities!", - "postSummonVesselOfRuin": "{{pokemonNameWithAffix}}'s Vessel of Ruin lowered the {{statName}}\nof all surrounding Pokémon!", - "postSummonSwordOfRuin": "{{pokemonNameWithAffix}}'s Sword of Ruin lowered the {{statName}}\nof all surrounding Pokémon!", - "postSummonTabletsOfRuin": "{{pokemonNameWithAffix}}'s Tablets of Ruin lowered the {{statName}}\nof all surrounding Pokémon!", - "postSummonBeadsOfRuin": "{{pokemonNameWithAffix}}'s Beads of Ruin lowered the {{statName}}\nof all surrounding Pokémon!", + "blockRecoilDamage" : "{{pokemonName}}は {{abilityName}}で 反動ダメージを 受けない!", + "badDreams": "{{pokemonName}}は ナイトメアに うなされている!", + "costar": "{{pokemonName}}は {{allyName}}の\n能力変化を コピーした!", + "iceFaceAvoidedDamage": "{{pokemonName}}は\n{{abilityName}}で ダメージを 受けない!", + "perishBody": "{{pokemonName}}の {{abilityName}}で\nおたがいは 3ターン後に ほろびいてしまう!", + "poisonHeal": "{{pokemonName}}は {{abilityName}}で 回復した!", + "trace": "{{pokemonName}}は 相手の {{targetName}}の\n{{abilityName}}を トレースした!", + "windPowerCharged": "{{pokemonName}}は\n{{moveName}}を 受けて じゅうでんした!", + "quickDraw": "{{pokemonName}}は クイックドロウで\n行動が はやくなった!", + "blockItemTheft": "{{pokemonNameWithAffix}}の {{abilityName}}で\n道具を うばわれない!", + "typeImmunityHeal": "{{pokemonNameWithAffix}}は {{abilityName}}で\n体力を 回復した!", + "nonSuperEffectiveImmunity": "{{pokemonNameWithAffix}}は {{abilityName}}で\nダメージを 受けない。", + "postDefendDisguise": "{{pokemonNameWithAffix}}の\nばけのかわが はがれた!", + "moveImmunity": "{{pokemonNameWithAffix}}には\n効果が ないようだ…", + "reverseDrain": "{{pokemonNameWithAffix}}は\nヘドロえきを 吸い取った!", + "postDefendTypeChange": "{{pokemonNameWithAffix}}は {{abilityName}}で\n{{typeName}}タイプに なった!", + "postDefendContactDamage": "{{pokemonNameWithAffix}}は {{abilityName}}で\n相手を キズつけた!", + "postDefendAbilitySwap": "{{pokemonNameWithAffix}}は\nおたがいの 特性を 入れ替えた!", + "postDefendAbilityGive": "{{pokemonNameWithAffix}}は\n特性が {{abilityName}}に なっちゃった!", + "postDefendMoveDisable": "{{pokemonNameWithAffix}}の\n{{moveName}}を 封じこめた!", + "pokemonTypeChange": "{{pokemonNameWithAffix}}は\n{{moveType}}タイプに なった!", + "postAttackStealHeldItem": "{{pokemonNameWithAffix}}は {{defenderName}}から\n{{stolenItemType}}を うばいとった!", + "postDefendStealHeldItem": "{{pokemonNameWithAffix}}は {{attackerName}}から\n{{stolenItemType}}を うばいとった!", + "copyFaintedAllyAbility": "{{pokemonNameWithAffix}}の\n{{abilityName}}を 引き継いだ!", + "intimidateImmunity": "{{pokemonNameWithAffix}}は\n{{abilityName}}の 効果で 能力が 下がらない!", + "postSummonAllyHeal": "{{pokemonNameWithAffix}}が たてた お茶を\n{{pokemonName}}は 飲みほした!", + "postSummonClearAllyStats": "{{pokemonNameWithAffix}}の\n能力変化が 元に戻った!", + "postSummonTransform": "{{pokemonNameWithAffix}}は\n{{targetName}}に 変身した!", + "protectStat": "{{pokemonNameWithAffix}}は {{abilityName}}の 効果で\n{{statName}}が 下がらない!", + "statusEffectImmunityWithName": "{{pokemonNameWithAffix}}は {{abilityName}}で\{{statusEffectName}}に ならない!", + "statusEffectImmunity": "{{pokemonNameWithAffix}}は {{abilityName}}で\n状態異常に ならない!", + "battlerTagImmunity": "{{pokemonNameWithAffix}}は {{abilityName}}で]\n{{battlerTagName}}を 無視した!", + "forewarn": "{{pokemonNameWithAffix}}の\n{{moveName}}を 読み取った!", + "frisk": "{{pokemonNameWithAffix}}は {{opponentName}}の\n{{opponentAbilityName}}を お見通しだ!", + "postWeatherLapseHeal": "{{pokemonNameWithAffix}}は {{abilityName}}で\n体力を 回復した!", + "postWeatherLapseDamage": "{{pokemonNameWithAffix}}は\n{{abilityName}}の ダメージを 受けた!", + "postTurnLootCreateEatenBerry": "{{pokemonNameWithAffix}}は\n{{berryName}}を 収穫した!", + "postTurnHeal": "{{pokemonNameWithAffix}}は {{abilityName}}で\n体力を 回復した!", + "fetchBall": "{{pokemonNameWithAffix}}は\n{{pokeballName}}を 拾ってきた!", + "healFromBerryUse": "{{pokemonNameWithAffix}}は {{abilityName}}で\n体力を 回復した!", + "arenaTrap": "{{pokemonNameWithAffix}}の {{abilityName}}で\n入れ替えることが できない!", + "postBattleLoot": "{{pokemonNameWithAffix}}は\n{{itemName}}を 拾った!", + "postFaintContactDamage": "{{pokemonNameWithAffix}}は {{abilityName}}で\n相手に ダメージを 与えた!", + "postFaintHpDamage": "{{pokemonNameWithAffix}}は {{abilityName}}で\n相手に ダメージを 与えた!", + "postSummonPressure": "{{pokemonNameWithAffix}}は\nプレッシャーを 放っている!", + "postSummonMoldBreaker": "{{pokemonNameWithAffix}}は\nかたやぶりだ!", + "postSummonAnticipation": "{{pokemonNameWithAffix}}は\nみぶるいした!", + "postSummonTurboblaze": "{{pokemonNameWithAffix}}は\n燃え盛(もえさか)る オーラを 放っている!", + "postSummonTeravolt": "{{pokemonNameWithAffix}}は\n弾(はじ)ける オーラを 放っている!", + "postSummonDarkAura": "{{pokemonNameWithAffix}}は\nダークオーラを 放っている!", + "postSummonFairyAura": "{{pokemonNameWithAffix}}は\nフェアリーオーラを 放っている!", + "postSummonNeutralizingGas": "あたりに かがくへんかガスが 充満した!", + "postSummonAsOneGlastrier": "{{pokemonNameWithAffix}}は\nふたつの 特性を あわせ持つ!", + "postSummonAsOneSpectrier": "{{pokemonNameWithAffix}}は\nふたつの 特性を あわせ持つ!", + "postSummonVesselOfRuin": "{{pokemonNameWithAffix}}の わざわいのうつわで\nまわりの {{statName}}が 弱まった!", + "postSummonSwordOfRuin": "{{pokemonNameWithAffix}}の わざわいのつるぎで\nまわりの {{statName}}が 弱まった!", + "postSummonTabletsOfRuin": "{{pokemonNameWithAffix}}の わざわいのおふだ\nまわりの {{statName}}が 弱まった!", + "postSummonBeadsOfRuin": "{{pokemonNameWithAffix}}の わざわいのたまで\nまわりの {{statName}}が 弱まった!", + "preventBerryUse": "{{pokemonNameWithAffix}}は 緊張して\nきのみが 食べられなくなった!", } as const; diff --git a/src/locales/ja/status-effect.ts b/src/locales/ja/status-effect.ts index 5914fc27298..b15907f3b33 100644 --- a/src/locales/ja/status-effect.ts +++ b/src/locales/ja/status-effect.ts @@ -2,7 +2,7 @@ import { StatusEffectTranslationEntries } from "#app/interfaces/locales.js"; export const statusEffect: StatusEffectTranslationEntries = { none: { - name: "None", + name: "なし", description: "", obtain: "", obtainSource: "", @@ -11,57 +11,57 @@ export const statusEffect: StatusEffectTranslationEntries = { heal: "" }, poison: { - name: "Poison", - description: "poisoning", - obtain: "{{pokemonNameWithAffix}}\nwas poisoned!", - obtainSource: "{{pokemonNameWithAffix}}\nwas poisoned by the {{sourceText}}!", - activation: "{{pokemonNameWithAffix}} is hurt\nby poison!", - overlap: "{{pokemonNameWithAffix}} is\nalready poisoned!", - heal: "{{pokemonNameWithAffix}} was\ncured of its poison!" + name: "どく", + description: "どく", + obtain: "{{pokemonNameWithAffix}}は\n毒を あびた!", + obtainSource: "{{pokemonNameWithAffix}}は\n{{sourceText}}で 毒を あびた!", + activation: "{{pokemonNameWithAffix}}は\n毒の ダメージを 受けた!", + overlap: "{{pokemonNameWithAffix}}は すでに\n毒を あびている", + heal: "{{pokemonNameWithAffix}}の 毒は\nきれいさっぱり なくなった!" }, toxic: { - name: "Toxic", - description: "poisoning", - obtain: "{{pokemonNameWithAffix}}\nwas badly poisoned!", - obtainSource: "{{pokemonNameWithAffix}}\nwas badly poisoned by the {{sourceText}}!", - activation: "{{pokemonNameWithAffix}} is hurt\nby poison!", - overlap: "{{pokemonNameWithAffix}} is\nalready poisoned!", - heal: "{{pokemonNameWithAffix}} was\ncured of its poison!" + name: "もうどく", + description: "もうどく", + obtain: "{{pokemonNameWithAffix}}は\n猛毒を あびた!", + obtainSource: "{{pokemonNameWithAffix}}は\n{{sourceText}}で 猛毒を あびた!", + activation: "{{pokemonNameWithAffix}}は\n毒の ダメージを受けた!", + overlap: "{{pokemonNameWithAffix}}は すでに\n毒を あびている", + heal: "{{pokemonNameWithAffix}}の 毒は\nきれいさっぱり なくなった!" }, paralysis: { - name: "Paralysis", - description: "paralysis", - obtain: "{{pokemonNameWithAffix}} was paralyzed,\nIt may be unable to move!", - obtainSource: "{{pokemonNameWithAffix}} was paralyzed by the {{sourceText}}!\nIt may be unable to move!", - activation: "{{pokemonNameWithAffix}} is paralyzed!\nIt can't move!", - overlap: "{{pokemonNameWithAffix}} is\nalready paralyzed!", - heal: "{{pokemonNameWithAffix}} was\nhealed of paralysis!" + name: "まひ", + description: "まひ", + obtain: "{{pokemonNameWithAffix}}は まひして\n技が でにくくなった!", + obtainSource: "{{pokemonNameWithAffix}}は {{sourceText}}で まひして\n技が でにくくなった!", + activation: "{{pokemonNameWithAffix}}は\n体が しびれて 動けない!", + overlap: "{{pokemonNameWithAffix}}は\nすでに まひしている", + heal: "{{pokemonNameWithAffix}}の\nしびれが とれた!" }, sleep: { - name: "Sleep", - description: "sleep", - obtain: "{{pokemonNameWithAffix}}\nfell asleep!", - obtainSource: "{{pokemonNameWithAffix}}\nfell asleep from the {{sourceText}}!", - activation: "{{pokemonNameWithAffix}} is fast asleep.", - overlap: "{{pokemonNameWithAffix}} is\nalready asleep!", - heal: "{{pokemonNameWithAffix}} woke up!" + name: "ねむり", + description: "ねむり", + obtain: "{{pokemonNameWithAffix}}は\n眠ってしまった!", + obtainSource: "{{pokemonNameWithAffix}}は\n{{sourceText}}で 眠ってしまった!", + activation: "{{pokemonNameWithAffix}}は\nぐうぐう 眠っている", + overlap: "{{pokemonNameWithAffix}}は\nすでに 眠っている", + heal: "{{pokemonNameWithAffix}}は\n目を 覚ました!" }, freeze: { - name: "Freeze", - description: "freezing", - obtain: "{{pokemonNameWithAffix}}\nwas frozen solid!", - obtainSource: "{{pokemonNameWithAffix}}\nwas frozen solid by the {{sourceText}}!", - activation: "{{pokemonNameWithAffix}} is\nfrozen solid!", - overlap: "{{pokemonNameWithAffix}} is\nalready frozen!", - heal: "{{pokemonNameWithAffix}} was\ndefrosted!" + name: "こおり", + description: "こおり", + obtain: "{{pokemonNameWithAffix}}は\n凍りついた!", + obtainSource: "{{pokemonNameWithAffix}}は\n{{sourceText}}で 凍りついた!", + activation: "{{pokemonNameWithAffix}}は\n凍ってしまって 動けない!", + overlap: "{{pokemonNameWithAffix}}は\nすでに 凍っている", + heal: "{{pokemonNameWithAffix}}は\nこおり状態が 治った!" }, burn: { - name: "Burn", - description: "burn", - obtain: "{{pokemonNameWithAffix}}\nwas burned!", - obtainSource: "{{pokemonNameWithAffix}}\nwas burned by the {{sourceText}}!", - activation: "{{pokemonNameWithAffix}} is hurt\nby its burn!", - overlap: "{{pokemonNameWithAffix}} is\nalready burned!", - heal: "{{pokemonNameWithAffix}} was\nhealed of its burn!" + name: "やけど", + description: "やけど", + obtain: "{{pokemonNameWithAffix}}は\nやけどを 負った!", + obtainSource: "{{pokemonNameWithAffix}}は\n{{sourceText}}で やけどを 負った!", + activation: "{{pokemonNameWithAffix}}は\nやけどの ダメージを 受けた!", + overlap: "{{pokemonNameWithAffix}}は すでに\nやけどを 負っている", + heal: "{{pokemonNameWithAffix}}の\nやけどが 治った!" }, } as const; From 7f5e873457f626cef4af112a010c6abea35f331a Mon Sep 17 00:00:00 2001 From: innerthunder <168692175+innerthunder@users.noreply.github.com> Date: Thu, 8 Aug 2024 11:23:11 -0700 Subject: [PATCH 039/282] [Move] Fully Implement Gulp Missile (#3438) * Fix Dive + Gulp Missile interaction * Fix animation + remove tests for inaccurate behavior * Fix strict-null issue in new test --- src/data/ability.ts | 8 +++--- src/data/move.ts | 4 +-- src/form-change-phase.ts | 3 ++- src/test/abilities/gulp_missile.test.ts | 34 ++++++++++++------------- 4 files changed, 23 insertions(+), 26 deletions(-) diff --git a/src/data/ability.ts b/src/data/ability.ts index f4701d3a4e1..950538af9f6 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -6,7 +6,7 @@ import { BattleStat, getBattleStatName } from "./battle-stat"; import { MovePhase, PokemonHealPhase, ShowAbilityPhase, StatChangePhase } from "../phases"; import { getPokemonNameWithAffix } from "../messages"; import { Weather, WeatherType } from "./weather"; -import { BattlerTag, GroundedTag, GulpMissileTag } from "./battler-tags"; +import { BattlerTag, GroundedTag, GulpMissileTag, SemiInvulnerableTag } from "./battler-tags"; import { StatusEffect, getNonVolatileStatusEffects, getStatusEffectDescriptor, getStatusEffectHealText } from "./status-effect"; import { Gender } from "./gender"; import Move, { AttackMove, MoveCategory, MoveFlags, MoveTarget, FlinchAttr, OneHitKOAttr, HitHealAttr, allMoves, StatusMove, SelfStatusMove, VariablePowerAttr, applyMoveAttrs, IncrementMovePriorityAttr, VariableMoveTypeAttr, RandomMovesetMoveAttr, RandomMoveAttr, NaturePowerAttr, CopyMoveAttr, MoveAttr, MultiHitAttr, ChargeAttr, SacrificialAttr, SacrificialAttrOnHit } from "./move"; @@ -517,7 +517,7 @@ export class PostDefendGulpMissileAbAttr extends PostDefendAbAttr { */ applyPostDefend(pokemon: Pokemon, passive: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean | Promise { const battlerTag = pokemon.getTag(GulpMissileTag); - if (!battlerTag || move.category === MoveCategory.STATUS) { + if (!battlerTag || move.category === MoveCategory.STATUS || pokemon.getTag(SemiInvulnerableTag)) { return false; } @@ -5138,9 +5138,7 @@ export function initAbilities() { .attr(NoFusionAbilityAbAttr) .attr(UncopiableAbilityAbAttr) .attr(UnswappableAbilityAbAttr) - .attr(PostDefendGulpMissileAbAttr) - // Does not transform when Surf/Dive misses/is protected - .partial(), + .attr(PostDefendGulpMissileAbAttr), new Ability(Abilities.STALWART, 8) .attr(BlockRedirectAbAttr), new Ability(Abilities.STEAM_ENGINE, 8) diff --git a/src/data/move.ts b/src/data/move.ts index c43150992bc..2d0ea11c3a0 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -4356,7 +4356,7 @@ export class AddBattlerTagAttr extends MoveEffectAttr { */ export class GulpMissileTagAttr extends MoveEffectAttr { constructor() { - super(true, MoveEffectTrigger.POST_APPLY); + super(true); } /** @@ -6954,7 +6954,7 @@ export function initMoves() { .makesContact(false) .partial(), new AttackMove(Moves.DIVE, Type.WATER, MoveCategory.PHYSICAL, 80, 100, 10, -1, 0, 3) - .attr(ChargeAttr, ChargeAnim.DIVE_CHARGING, i18next.t("moveTriggers:hidUnderwater", {pokemonName: "{USER}"}), BattlerTagType.UNDERWATER) + .attr(ChargeAttr, ChargeAnim.DIVE_CHARGING, i18next.t("moveTriggers:hidUnderwater", {pokemonName: "{USER}"}), BattlerTagType.UNDERWATER, true) .attr(GulpMissileTagAttr) .ignoresVirtual(), new AttackMove(Moves.ARM_THRUST, Type.FIGHTING, MoveCategory.PHYSICAL, 15, 100, 20, -1, 0, 3) diff --git a/src/form-change-phase.ts b/src/form-change-phase.ts index 55bf655081b..5acbc4fb77c 100644 --- a/src/form-change-phase.ts +++ b/src/form-change-phase.ts @@ -11,6 +11,7 @@ import { BattleSpec } from "#enums/battle-spec"; import { BattlePhase, MovePhase, PokemonHealPhase } from "./phases"; import { getTypeRgb } from "./data/type"; import { getPokemonNameWithAffix } from "./messages"; +import { SemiInvulnerableTag } from "./data/battler-tags"; export class FormChangePhase extends EvolutionPhase { private formChange: SpeciesFormChange; @@ -194,7 +195,7 @@ export class QuietFormChangePhase extends BattlePhase { const preName = getPokemonNameWithAffix(this.pokemon); - if (!this.pokemon.isOnField()) { + if (!this.pokemon.isOnField() || this.pokemon.getTag(SemiInvulnerableTag)) { this.pokemon.changeForm(this.formChange).then(() => { this.scene.ui.showText(getSpeciesFormChangeMessage(this.pokemon, this.formChange, preName), null, () => this.end(), 1500); }); diff --git a/src/test/abilities/gulp_missile.test.ts b/src/test/abilities/gulp_missile.test.ts index b64cbe2ef10..2647f765f6e 100644 --- a/src/test/abilities/gulp_missile.test.ts +++ b/src/test/abilities/gulp_missile.test.ts @@ -1,5 +1,6 @@ import { BattlerTagType } from "#app/enums/battler-tag-type.js"; import { + BerryPhase, MoveEndPhase, TurnEndPhase, TurnStartPhase, @@ -14,7 +15,6 @@ import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vite import { SPLASH_ONLY } from "../utils/testUtils"; import { BattleStat } from "#app/data/battle-stat.js"; import { StatusEffect } from "#app/enums/status-effect.js"; -import { GulpMissileTag } from "#app/data/battler-tags.js"; import Pokemon from "#app/field/pokemon.js"; describe("Abilities - Gulp Missile", () => { @@ -84,6 +84,17 @@ describe("Abilities - Gulp Missile", () => { expect(cramorant.formIndex).toBe(GORGING_FORM); }); + it("changes form during Dive's charge turn", async () => { + await game.startBattle([Species.CRAMORANT]); + const cramorant = game.scene.getPlayerPokemon()!; + + game.doAttack(getMovePosition(game.scene, 0, Moves.DIVE)); + await game.phaseInterceptor.to(MoveEndPhase); + + expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined(); + expect(cramorant.formIndex).toBe(GULPING_FORM); + }); + it("deals ¼ of the attacker's maximum HP when hit by a damaging attack", async () => { game.override.enemyMoveset(Array(4).fill(Moves.TACKLE)); await game.startBattle([Species.CRAMORANT]); @@ -165,29 +176,16 @@ describe("Abilities - Gulp Missile", () => { }); it("does not activate the ability when underwater", async () => { - game.override - .enemyMoveset(Array(4).fill(Moves.SURF)) - .enemySpecies(Species.REGIELEKI) - .enemyAbility(Abilities.BALL_FETCH) - .enemyLevel(5); + game.override.enemyMoveset(Array(4).fill(Moves.SURF)); await game.startBattle([Species.CRAMORANT]); const cramorant = game.scene.getPlayerPokemon()!; game.doAttack(getMovePosition(game.scene, 0, Moves.DIVE)); - await game.toNextTurn(); + await game.phaseInterceptor.to(BerryPhase, false); - // Turn 2 underwater, enemy moves first - game.doAttack(getMovePosition(game.scene, 0, Moves.DIVE)); - await game.phaseInterceptor.to(MoveEndPhase); - - expect(cramorant.formIndex).toBe(NORMAL_FORM); - expect(cramorant.getTag(GulpMissileTag)).toBeUndefined(); - - // Turn 2 Cramorant comes out and changes form - await game.phaseInterceptor.to(TurnEndPhase); - expect(cramorant.formIndex).not.toBe(NORMAL_FORM); - expect(cramorant.getTag(GulpMissileTag)).toBeDefined(); + expect(cramorant.getTag(BattlerTagType.GULP_MISSILE_ARROKUDA)).toBeDefined(); + expect(cramorant.formIndex).toBe(GULPING_FORM); }); it("prevents effect damage but inflicts secondary effect on attacker with Magic Guard", async () => { From 2e823b19148e246e3393bbf90e18b18d9bb75e6f Mon Sep 17 00:00:00 2001 From: innerthunder <168692175+innerthunder@users.noreply.github.com> Date: Thu, 8 Aug 2024 12:27:26 -0700 Subject: [PATCH 040/282] [Documentation] Add comments to `MoveEffectPhase` (+ some style changes) (#3392) * Document MoveEffectPhase * Edits based on Temp's suggestions --- src/phases.ts | 138 ++++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 128 insertions(+), 10 deletions(-) diff --git a/src/phases.ts b/src/phases.ts index ad591a368d3..db14dc022c4 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -2957,9 +2957,11 @@ export class MoveEffectPhase extends PokemonPhase { constructor(scene: BattleScene, battlerIndex: BattlerIndex, targets: BattlerIndex[], move: PokemonMove) { super(scene, battlerIndex); this.move = move; - // In double battles, if the right Pokemon selects a spread move and the left Pokemon dies - // with no party members available to switch in, then the right Pokemon takes the index - // of the left Pokemon and gets hit unless this is checked. + /** + * In double battles, if the right Pokemon selects a spread move and the left Pokemon dies + * with no party members available to switch in, then the right Pokemon takes the index + * of the left Pokemon and gets hit unless this is checked. + */ if (targets.includes(battlerIndex) && this.move.getMove().moveTarget === MoveTarget.ALL_NEAR_OTHERS) { const i = targets.indexOf(battlerIndex); targets.splice(i, i + 1); @@ -2970,40 +2972,72 @@ export class MoveEffectPhase extends PokemonPhase { start() { super.start(); + /** The Pokemon using this phase's invoked move */ const user = this.getUserPokemon(); + /** All Pokemon targeted by this phase's invoked move */ const targets = this.getTargets(); + /** If the user was somehow removed from the field, end this phase */ if (!user?.isOnField()) { return super.end(); } + /** + * Does an effect from this move override other effects on this turn? + * e.g. Charging moves (Fly, etc.) on their first turn of use. + */ const overridden = new Utils.BooleanHolder(false); + /** The {@linkcode Move} object from {@linkcode allMoves} invoked by this phase */ const move = this.move.getMove(); // Assume single target for override applyMoveAttrs(OverrideMoveEffectAttr, user, this.getTarget() ?? null, move, overridden, this.move.virtual).then(() => { - + // If other effects were overriden, stop this phase before they can be applied if (overridden.value) { return this.end(); } user.lapseTags(BattlerTagLapseType.MOVE_EFFECT); + /** + * If this phase is for the first hit of the invoked move, + * resolve the move's total hit count. This block combines the + * effects of the move itself, Parental Bond, and Multi-Lens to do so. + */ if (user.turnData.hitsLeft === undefined) { const hitCount = new Utils.IntegerHolder(1); // Assume single target for multi hit applyMoveAttrs(MultiHitAttr, user, this.getTarget() ?? null, move, hitCount); + // If Parental Bond is applicable, double the hit count applyPreAttackAbAttrs(AddSecondStrikeAbAttr, user, null, move, targets.length, hitCount, new Utils.IntegerHolder(0)); + // If Multi-Lens is applicable, multiply the hit count by 1 + the number of Multi-Lenses held by the user if (move instanceof AttackMove && !move.hasAttr(FixedDamageAttr)) { this.scene.applyModifiers(PokemonMultiHitModifier, user.isPlayer(), user, hitCount, new Utils.IntegerHolder(0)); } - user.turnData.hitsLeft = user.turnData.hitCount = hitCount.value; + // Set the user's relevant turnData fields to reflect the final hit count + user.turnData.hitCount = hitCount.value; + user.turnData.hitsLeft = hitCount.value; } + /** + * Log to be entered into the user's move history once the move result is resolved. + * Note that `result` (a {@linkcode MoveResult}) logs whether the move was successfully + * used in the sense of it not failing or missing; it does not account for the move's + * effectiveness (which is logged as a {@linkcode HitResult}). + */ const moveHistoryEntry = { move: this.move.moveId, targets: this.targets, result: MoveResult.PENDING, virtual: this.move.virtual }; + /** + * Stores results of hit checks of the invoked move against all targets, organized by battler index. + * @see {@linkcode hitCheck} + */ const targetHitChecks = Object.fromEntries(targets.map(p => [p.getBattlerIndex(), this.hitCheck(p)])); const hasActiveTargets = targets.some(t => t.isActive(true)); + /** + * If no targets are left for the move to hit (FAIL), or the invoked move is single-target + * (and not random target) and failed the hit check against its target (MISS), log the move + * as FAILed or MISSed (depending on the conditions above) and end this phase. + */ if (!hasActiveTargets || (!move.hasAttr(VariableTargetAttr) && !move.isMultiTarget() && !targetHitChecks[this.targets[0]])) { this.stopMultiHit(); if (hasActiveTargets) { @@ -3018,6 +3052,7 @@ export class MoveEffectPhase extends PokemonPhase { return this.end(); } + /** All move effect attributes are chained together in this array to be applied asynchronously. */ const applyAttrs: Promise[] = []; // Move animation only needs one target @@ -3025,6 +3060,10 @@ export class MoveEffectPhase extends PokemonPhase { /** Has the move successfully hit a target (for damage) yet? */ let hasHit: boolean = false; for (const target of targets) { + /** + * If the move missed a target, stop all future hits against that target + * and move on to the next target (if there is one). + */ if (!targetHitChecks[target.getBattlerIndex()]) { this.stopMultiHit(target); this.scene.queueMessage(i18next.t("battle:attackMissed", { pokemonNameWithAffix: getPokemonNameWithAffix(target) })); @@ -3036,18 +3075,38 @@ export class MoveEffectPhase extends PokemonPhase { continue; } + /** Is the invoked move blocked by a protection effect on the target? */ const isProtected = !this.move.getMove().checkFlag(MoveFlags.IGNORE_PROTECT, user, target) && target.findTags(t => t instanceof ProtectedTag).find(t => target.lapseTag(t.tagType)); + /** Does this phase represent the invoked move's first strike? */ const firstHit = (user.turnData.hitsLeft === user.turnData.hitCount); + // Only log the move's result on the first strike if (firstHit) { user.pushMoveHistory(moveHistoryEntry); } + /** + * Since all fail/miss checks have applied, the move is considered successfully applied. + * It's worth noting that if the move has no effect or is protected against, it's move + * result is still logged as a SUCCESS. + */ moveHistoryEntry.result = MoveResult.SUCCESS; + /** + * Stores the result of applying the invoked move to the target. + * If the target is protected, the result is always `NO_EFFECT`. + * Otherwise, the hit result is based on type effectiveness, immunities, + * and other factors that may negate the attack or status application. + * + * Internally, the call to {@linkcode Pokemon.apply} is where damage is calculated + * (for attack moves) and the target's HP is updated. However, this isn't + * made visible to the user until the resulting {@linkcode DamagePhase} + * is invoked. + */ const hitResult = !isProtected ? target.apply(user, move) : HitResult.NO_EFFECT; + /** Does {@linkcode hitResult} indicate that damage was dealt to the target? */ const dealsDamage = [ HitResult.EFFECTIVE, HitResult.SUPER_EFFECTIVE, @@ -3055,28 +3114,53 @@ export class MoveEffectPhase extends PokemonPhase { HitResult.ONE_HIT_KO ].includes(hitResult); + /** Is this target the first one hit by the move on its current strike? */ const firstTarget = dealsDamage && !hasHit; if (firstTarget) { hasHit = true; } + /** Does this phase represent the invoked move's last strike? */ const lastHit = (user.turnData.hitsLeft === 1 || !this.getTarget()?.isActive()); + /** + * If the user can change forms by using the invoked move, + * it only changes forms after the move's last hit + * (see Relic Song's interaction with Parental Bond when used by Meloetta). + */ if (lastHit) { this.scene.triggerPokemonFormChange(user, SpeciesFormChangePostMoveTrigger); } + /** + * Create a Promise that applys *all* effects from the invoked move's MoveEffectAttrs. + * These are ordered by trigger type (see {@linkcode MoveEffectTrigger}), and each trigger + * type requires different conditions to be met with respect to the move's hit result. + */ applyAttrs.push(new Promise(resolve => { + // Apply all effects with PRE_MOVE triggers (if the target isn't immune to the move) applyFilteredMoveAttrs((attr: MoveAttr) => attr instanceof MoveEffectAttr && attr.trigger === MoveEffectTrigger.PRE_APPLY && (!attr.firstHitOnly || firstHit) && (!attr.lastHitOnly || lastHit) && hitResult !== HitResult.NO_EFFECT, user, target, move).then(() => { + // All other effects require the move to not have failed or have been cancelled to trigger if (hitResult !== HitResult.FAIL) { + /** Are the move's effects tied to the first turn of a charge move? */ const chargeEffect = !!move.getAttrs(ChargeAttr).find(ca => ca.usedChargeEffect(user, this.getTarget() ?? null, move)); - // Charge attribute with charge effect takes all effect attributes and applies them to charge stage, so ignore them if this is present + /** + * If the invoked move's effects are meant to trigger during the move's "charge turn," + * ignore all effects after this point. + * Otherwise, apply all self-targeted POST_APPLY effects. + */ Utils.executeIf(!chargeEffect, () => applyFilteredMoveAttrs((attr: MoveAttr) => attr instanceof MoveEffectAttr && attr.trigger === MoveEffectTrigger.POST_APPLY && attr.selfTarget && (!attr.firstHitOnly || firstHit) && (!attr.lastHitOnly || lastHit), user, target, move)).then(() => { + // All effects past this point require the move to have hit the target if (hitResult !== HitResult.NO_EFFECT) { + // Apply all non-self-targeted POST_APPLY effects applyFilteredMoveAttrs((attr: MoveAttr) => attr instanceof MoveEffectAttr && (attr as MoveEffectAttr).trigger === MoveEffectTrigger.POST_APPLY && !(attr as MoveEffectAttr).selfTarget && (!attr.firstHitOnly || firstHit) && (!attr.lastHitOnly || lastHit), user, target, this.move.getMove()).then(() => { + /** + * If the move hit, and the target doesn't have Shield Dust, + * apply the chance to flinch the target gained from King's Rock + */ if (dealsDamage && !target.hasAbilityWithAttr(IgnoreMoveEffectsAbAttr)) { const flinched = new Utils.BooleanHolder(false); user.scene.applyModifiers(FlinchChanceModifier, user.isPlayer(), user, flinched); @@ -3084,15 +3168,23 @@ export class MoveEffectPhase extends PokemonPhase { target.addTag(BattlerTagType.FLINCHED, undefined, this.move.moveId, user.id); } } + // If the move was not protected against, apply all HIT effects Utils.executeIf(!isProtected && !chargeEffect, () => applyFilteredMoveAttrs((attr: MoveAttr) => attr instanceof MoveEffectAttr && (attr as MoveEffectAttr).trigger === MoveEffectTrigger.HIT && (!attr.firstHitOnly || firstHit) && (!attr.lastHitOnly || lastHit) && (!attr.firstTargetOnly || firstTarget), user, target, this.move.getMove()).then(() => { + // Apply the target's post-defend ability effects (as long as the target is active or can otherwise apply them) return Utils.executeIf(!target.isFainted() || target.canApplyAbility(), () => applyPostDefendAbAttrs(PostDefendAbAttr, target, user, this.move.getMove(), hitResult).then(() => { + // If the invoked move is an enemy attack, apply the enemy's status effect-inflicting tags and tokens target.lapseTag(BattlerTagType.BEAK_BLAST_CHARGING); if (!user.isPlayer() && this.move.getMove() instanceof AttackMove) { user.scene.applyShuffledModifiers(this.scene, EnemyAttackStatusEffectChanceModifier, false, target); } })).then(() => { + // Apply the user's post-attack ability effects applyPostAttackAbAttrs(PostAttackAbAttr, user, target, this.move.getMove(), hitResult).then(() => { + /** + * If the invoked move is an attack, apply the user's chance to + * steal an item from the target granted by Grip Claw + */ if (this.move.getMove() instanceof AttackMove) { this.scene.applyModifiers(ContactHeldItemTransferChanceModifier, this.player, user, target); } @@ -3112,7 +3204,7 @@ export class MoveEffectPhase extends PokemonPhase { }); })); } - // Trigger effect which should only apply one time on the last hit after all targeted effects have already applied + // Apply the move's POST_TARGET effects on the move's last hit, after all targeted effects have resolved const postTarget = (user.turnData.hitsLeft === 1 || !this.getTarget()?.isActive()) ? applyFilteredMoveAttrs((attr: MoveAttr) => attr instanceof MoveEffectAttr && attr.trigger === MoveEffectTrigger.POST_TARGET, user, null, move) : null; @@ -3125,6 +3217,7 @@ export class MoveEffectPhase extends PokemonPhase { } } + // Wait for all move effects to finish applying, then end this phase Promise.allSettled(applyAttrs).then(() => this.end()); }); }); @@ -3134,6 +3227,13 @@ export class MoveEffectPhase extends PokemonPhase { const move = this.move.getMove(); move.type = move.defaultType; const user = this.getUserPokemon(); + /** + * If this phase isn't for the invoked move's last strike, + * unshift another MoveEffectPhase for the next strike. + * Otherwise, queue a message indicating the number of times the move has struck + * (if the move has struck more than once), then apply the heal from Shell Bell + * to the user. + */ if (user) { if (user.turnData.hitsLeft && --user.turnData.hitsLeft >= 1 && this.getTarget()?.isActive()) { this.scene.unshiftPhase(this.getNewHitPhase()); @@ -3152,6 +3252,11 @@ export class MoveEffectPhase extends PokemonPhase { super.end(); } + /** + * Resolves whether this phase's invoked move hits or misses the given target + * @param target {@linkcode Pokemon} the Pokemon targeted by the invoked move + * @returns `true` if the move does not miss the target; `false` otherwise + */ hitCheck(target: Pokemon): boolean { // Moves targeting the user and entry hazards can't miss if ([MoveTarget.USER, MoveTarget.ENEMY_SIDE].includes(this.move.getMove().moveTarget)) { @@ -3182,8 +3287,8 @@ export class MoveEffectPhase extends PokemonPhase { return true; } - const hiddenTag = target.getTag(SemiInvulnerableTag); - if (hiddenTag && !this.move.getMove().getAttrs(HitsTagAttr).some(hta => hta.tagType === hiddenTag.tagType)) { + const semiInvulnerableTag = target.getTag(SemiInvulnerableTag); + if (semiInvulnerableTag && !this.move.getMove().getAttrs(HitsTagAttr).some(hta => hta.tagType === semiInvulnerableTag.tagType)) { return false; } @@ -3199,6 +3304,7 @@ export class MoveEffectPhase extends PokemonPhase { return rand <= moveAccuracy * (accuracyMultiplier!); // TODO: is this bang correct? } + /** Returns the {@linkcode Pokemon} using this phase's invoked move */ getUserPokemon(): Pokemon | undefined { if (this.battlerIndex > BattlerIndex.ENEMY_2) { return this.scene.getPokemonById(this.battlerIndex) ?? undefined; @@ -3206,14 +3312,20 @@ export class MoveEffectPhase extends PokemonPhase { return (this.player ? this.scene.getPlayerField() : this.scene.getEnemyField())[this.fieldIndex]; } + /** Returns an array of all {@linkcode Pokemon} targeted by this phase's invoked move */ getTargets(): Pokemon[] { return this.scene.getField(true).filter(p => this.targets.indexOf(p.getBattlerIndex()) > -1); } + /** Returns the first target of this phase's invoked move */ getTarget(): Pokemon | undefined { - return this.getTargets().find(() => true); + return this.getTargets()[0]; } + /** + * Removes the given {@linkcode Pokemon} from this phase's target list + * @param target {@linkcode Pokemon} the Pokemon to be removed + */ removeTarget(target: Pokemon): void { const targetIndex = this.targets.findIndex(ind => ind === target.getBattlerIndex()); if (targetIndex !== -1) { @@ -3221,6 +3333,11 @@ export class MoveEffectPhase extends PokemonPhase { } } + /** + * Prevents subsequent strikes of this phase's invoked move from occurring + * @param target {@linkcode Pokemon} if defined, only stop subsequent + * strikes against this Pokemon + */ stopMultiHit(target?: Pokemon): void { /** If given a specific target, remove the target from subsequent strikes */ if (target) { @@ -3236,6 +3353,7 @@ export class MoveEffectPhase extends PokemonPhase { } } + /** Returns a new MoveEffectPhase with the same properties as this phase */ getNewHitPhase() { return new MoveEffectPhase(this.scene, this.battlerIndex, this.targets, this.move); } From 6ad32f3c40cd1bcd08d67c03d8208b5524bc6908 Mon Sep 17 00:00:00 2001 From: Chapybara-jp Date: Thu, 8 Aug 2024 21:28:26 +0200 Subject: [PATCH 041/282] [Localisation(ja)] Translate challenges.ts (#3439) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Discordでこの質問を聞きましたが、ここでも聞いて置きます: "Starters" をどう翻訳しましょうか?一番合ってる公式の用語は「最初のパートナー」だと思いますが、ちょっと長いです。 --- src/locales/ja/challenges.ts | 42 ++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/src/locales/ja/challenges.ts b/src/locales/ja/challenges.ts index 1383ea021b1..71925baf7b8 100644 --- a/src/locales/ja/challenges.ts +++ b/src/locales/ja/challenges.ts @@ -1,32 +1,32 @@ import { TranslationEntries } from "#app/interfaces/locales"; export const challenges: TranslationEntries = { - "title": "チャレンジ じょうけん せってい", - "illegalEvolution": "{{pokemon}} changed into an ineligble pokémon\nfor this challenge!", + "title": "チャレンジを 設定", + "illegalEvolution": "{{pokemon}}は このチャレンジで\n対象外の ポケモンに なってしまった!", "singleGeneration": { - "name": "Mono Gen", - "desc": "You can only use Pokémon from Generation {{gen}}.", - "desc_default": "You can only use Pokémon from the chosen generation.", - "gen_1": "one", - "gen_2": "two", - "gen_3": "three", - "gen_4": "four", - "gen_5": "five", - "gen_6": "six", - "gen_7": "seven", - "gen_8": "eight", - "gen_9": "nine", + "name": "単一世代", + "desc": "{{gen}}世代からの ポケモンしか 使えません", + "desc_default": "選んだ 世代からの ポケモンしか 使えません", + "gen_1": "1", + "gen_2": "2", + "gen_3": "3", + "gen_4": "4", + "gen_5": "5", + "gen_6": "6", + "gen_7": "7", + "gen_8": "8", + "gen_9": "9", }, "singleType": { - "name": "Mono Type", - "desc": "You can only use Pokémon with the {{type}} type.", - "desc_default": "You can only use Pokémon of the chosen type." + "name": "単一タイプ", + "desc": "{{type}}タイプの ポケモンしか 使えません", + "desc_default": "選んだ タイプの ポケモンしか 使えません" //types in pokemon-info }, "freshStart": { - "name": "Fresh Start", - "desc": "You can only use the original starters, and only as if you had just started pokerogue.", - "value.0": "Off", - "value.1": "On", + "name": "出直し", + "desc": "ポケローグを 始めた ばかりの ような ままで ゲーム開始の 最初のパートナーしか 使えません", + "value.0": "オフ", + "value.1": "オン", }, } as const; From cff5a670b178376021663df7d0ea1d2100dd605b Mon Sep 17 00:00:00 2001 From: Chapybara-jp Date: Thu, 8 Aug 2024 21:30:42 +0200 Subject: [PATCH 042/282] [Localization(ja)] First draft translated achv.ts (#3408) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * First draft translated achv.ts * Update achv.ts Added Earth Monotype challenge translation じめんタイプチャレンジのギャグを加えました Changed spacing size 空白を全角スペースに変えた * Update src/locales/ja/achv.ts Co-authored-by: Yonmaru40 <47717431+40chyan@users.noreply.github.com> * Update achv.ts * Update achv.ts --------- Co-authored-by: Yonmaru40 <47717431+40chyan@users.noreply.github.com> --- src/locales/ja/achv.ts | 212 ++++++++++++++++++++--------------------- 1 file changed, 106 insertions(+), 106 deletions(-) diff --git a/src/locales/ja/achv.ts b/src/locales/ja/achv.ts index 7e8d41c9808..9693a16cdc0 100644 --- a/src/locales/ja/achv.ts +++ b/src/locales/ja/achv.ts @@ -3,171 +3,171 @@ import { AchievementTranslationEntries } from "#app/interfaces/locales.js"; // Achievement translations for the when the player character is male export const PGMachv: AchievementTranslationEntries = { "Achievements": { - name: "Achievements", + name: "実績", }, "Locked": { - name: "Locked", + name: "なし", }, "MoneyAchv": { - description: "Accumulate a total of ₽{{moneyAmount}}", + description: "一回の ランで ₽{{moneyAmount}}を 稼ぐ", }, "10K_MONEY": { - name: "Money Haver", + name: "お金を持つ人", }, "100K_MONEY": { - name: "Rich", + name: "富豪", }, "1M_MONEY": { - name: "Millionaire", + name: "百万長者", }, "10M_MONEY": { - name: "One Percenter", + name: "超富裕層", }, "DamageAchv": { - description: "Inflict {{damageAmount}} damage in one hit", + description: "一撃で {{damageAmount}}ダメージを 与える", }, "250_DMG": { - name: "Hard Hitter", + name: "力持ち", }, "1000_DMG": { - name: "Harder Hitter", + name: "強者", }, "2500_DMG": { - name: "That's a Lotta Damage!", + name: "カカロット", }, "10000_DMG": { - name: "One Punch Man", + name: "ワンパンマン", }, "HealAchv": { - description: "Heal {{healAmount}} {{HP}} at once with a move, ability, or held item", + description: "一つの 技や 特性や 持っているアイテムで {{healAmount}}{{HP}}を 一気に 回復する", }, "250_HEAL": { - name: "Novice Healer", + name: "回復発見者", }, "1000_HEAL": { - name: "Big Healer", + name: "大いなる治療者", }, "2500_HEAL": { - name: "Cleric", + name: "回復達人", }, "10000_HEAL": { - name: "Recovery Master", + name: "ジョーイさん", }, "LevelAchv": { - description: "Level up a Pokémon to Lv{{level}}", + description: "一つの ポケモンを Lv{{level}}まで レベルアップする", }, "LV_100": { - name: "But Wait, There's More!", + name: "まだまだだよ", }, "LV_250": { - name: "Elite", + name: "天王", }, "LV_1000": { - name: "To Go Even Further Beyond", + name: "向こうの向こうを超え", }, "RibbonAchv": { - description: "Accumulate a total of {{ribbonAmount}} Ribbons", + description: "{{ribbonAmount}}巻の リボンを 積もる", }, "10_RIBBONS": { - name: "Pokémon League Champion", + name: "ポケモンリーグチャンピオン", }, "25_RIBBONS": { - name: "Great League Champion", + name: "スーパーリーグチャンピオン", }, "50_RIBBONS": { - name: "Ultra League Champion", + name: "ハイパーリーグチャンピオン", }, "75_RIBBONS": { - name: "Rogue League Champion", + name: "ローグリーグチャンピオン", }, "100_RIBBONS": { - name: "Master League Champion", + name: "マスターリーグチャンピオン", }, "TRANSFER_MAX_BATTLE_STAT": { - name: "Teamwork", - description: "Baton pass to another party member with at least one stat maxed out", + name: "同力", + description: "少なくとも 一つの 能力を 最大まで あげて 他の 手持ちポケモンに バトンタッチする", }, "MAX_FRIENDSHIP": { - name: "Friendmaxxing", - description: "Reach max friendship on a Pokémon", + name: "マブ達", + description: "一つの 手持ちポケモンの 仲良し度を 最大に 上げる", }, "MEGA_EVOLVE": { - name: "Megamorph", - description: "Mega evolve a Pokémon", + name: "ザ・アブソリュート", + description: "一つの 手持ちポケモンを メガシンカさせる", }, "GIGANTAMAX": { - name: "Absolute Unit", - description: "Gigantamax a Pokémon", + name: "太―くて 堪らない", + description: "一つの 手持ちポケモンを キョダイマックスさせる", }, "TERASTALLIZE": { - name: "STAB Enthusiast", - description: "Terastallize a Pokémon", + name: "一致好き", + description: "一つの 手持ちポケモンを テラスタルさせる", }, "STELLAR_TERASTALLIZE": { - name: "The Hidden Type", - description: "Stellar Terastallize a Pokémon", + name: "隠れたタイプ", + description: "一つの 手持ちポケモンを ステラ・テラスタルさせる", }, "SPLICE": { - name: "Infinite Fusion", - description: "Splice two Pokémon together with DNA Splicers", + name: "インフィニット・フュジョン", + description: "いでんしのくさびで 二つの ポケモンを 吸収合体させる", }, "MINI_BLACK_HOLE": { - name: "A Hole Lot of Items", - description: "Acquire a Mini Black Hole", + name: "アイテムホーリック", + description: "ミニブラックホールを 手に入れる", }, "CATCH_MYTHICAL": { - name: "Mythical", - description: "Catch a mythical Pokémon", + name: "幻", + description: "幻の ポケモンを 捕まえる", }, "CATCH_SUB_LEGENDARY": { - name: "(Sub-)Legendary", - description: "Catch a sub-legendary Pokémon", + name: "準・伝説", + description: "準伝説の ポケモンを 捕まえる", }, "CATCH_LEGENDARY": { - name: "Legendary", - description: "Catch a legendary Pokémon", + name: "ザ・伝説", + description: "伝説の ポケモンを 捕まえる", }, "SEE_SHINY": { - name: "Shiny", - description: "Find a shiny Pokémon in the wild", + name: "色とりどりに光る", + description: "野生の 色違いポケモンを みつける", }, "SHINY_PARTY": { - name: "That's Dedication", - description: "Have a full party of shiny Pokémon", + name: "きらきら努力家", + description: "手持ちポケモンは 全員 色違いポケモンに する", }, "HATCH_MYTHICAL": { - name: "Mythical Egg", - description: "Hatch a mythical Pokémon from an egg", + name: "幻のタマゴ", + description: "幻の ポケモンを タマゴから 生まれる", }, "HATCH_SUB_LEGENDARY": { - name: "Sub-Legendary Egg", - description: "Hatch a sub-legendary Pokémon from an egg", + name: "準伝説のタマゴ", + description: "準伝説の ポケモンを タマゴから 生まれる", }, "HATCH_LEGENDARY": { - name: "Legendary Egg", - description: "Hatch a legendary Pokémon from an egg", + name: "伝説のタマゴ", + description: "伝説の ポケモンを タマゴから 生まれる", }, "HATCH_SHINY": { - name: "Shiny Egg", - description: "Hatch a shiny Pokémon from an egg", + name: "色違いタマゴ", + description: "色違いポケモンを タマゴから 生まれる", }, "HIDDEN_ABILITY": { - name: "Hidden Potential", - description: "Catch a Pokémon with a hidden ability", + name: "底力", + description: "隠れ特性がある ポケモンを 捕まえる", }, "PERFECT_IVS": { - name: "Certificate of Authenticity", - description: "Get perfect IVs on a Pokémon", + name: "個体値の賞状", + description: "一つの ポケモンの 個体値を すべて 最大に する", }, "CLASSIC_VICTORY": { - name: "Undefeated", - description: "Beat the game in classic mode", + name: "無双", + description: "クラシックモードを クリアする", }, "UNEVOLVED_CLASSIC_VICTORY": { name: "Bring Your Child To Work Day", @@ -175,102 +175,102 @@ export const PGMachv: AchievementTranslationEntries = { }, "MONO_GEN_ONE": { - name: "The Original Rival", - description: "Complete the generation one only challenge.", + name: "原始", + description: "1世代の 単一世代チャレンジを クリアする", }, "MONO_GEN_TWO": { - name: "Generation 1.5", - description: "Complete the generation two only challenge.", + name: "懐かしいカンジョウ", + description: "2世代の 単一世代チャレンジを クリアする", }, "MONO_GEN_THREE": { - name: "Too much water?", - description: "Complete the generation three only challenge.", + name: "水浸し", + description: "3世代の 単一世代チャレンジを クリアする", }, "MONO_GEN_FOUR": { - name: "Is she really the hardest?", - description: "Complete the generation four only challenge.", + name: "神々の地", + description: "4世代の 単一世代チャレンジを クリアする", }, "MONO_GEN_FIVE": { - name: "All Original", - description: "Complete the generation five only challenge.", + name: "ニューヨーカー", + description: "5世代の 単一世代チャレンジを クリアする", }, "MONO_GEN_SIX": { - name: "Almost Royalty", - description: "Complete the generation six only challenge.", + name: "サヴァ・サヴァ", + description: "6世代の 単一世代チャレンジを クリアする", }, "MONO_GEN_SEVEN": { - name: "Only Technically", - description: "Complete the generation seven only challenge.", + name: "アローラ・オエ", + description: "7世代の 単一世代チャレンジを クリアする", }, "MONO_GEN_EIGHT": { - name: "A Champion Time!", - description: "Complete the generation eight only challenge.", + name: "チャンピオン タイムを 楽しめ!", + description: "8世代の 単一世代チャレンジを クリアする", }, "MONO_GEN_NINE": { - name: "She was going easy on you", - description: "Complete the generation nine only challenge.", + name: "ネモに甘えたでしょう", + description: "9世代の 単一世代チャレンジを クリアする", }, "MonoType": { - description: "Complete the {{type}} monotype challenge.", + description: "{{type}}タイプの 単一タイプチャレンジを クリアする", }, "MONO_NORMAL": { - name: "Extra Ordinary", + name: "凡人", }, "MONO_FIGHTING": { - name: "I Know Kung Fu", + name: "八千以上だ!!", }, "MONO_FLYING": { - name: "Angry Birds", + name: "翼をください", }, "MONO_POISON": { - name: "Kanto's Favourite", + name: "カントーの名物", }, "MONO_GROUND": { - name: "Forecast: Earthquakes", + name: "自信でユラユラ", }, "MONO_ROCK": { - name: "Brock Hard", + name: "タケシの挑戦状", }, "MONO_BUG": { - name: "You Like Jazz?", + name: "チョウチョウせん者", }, "MONO_GHOST": { - name: "Who You Gonna Call?", + name: "貞子ちゃん", }, "MONO_STEEL": { - name: "Iron Giant", + name: "ハガネーター", }, "MONO_FIRE": { - name: "I Cast Fireball!", + name: "NIGHT OF FIRE", }, "MONO_WATER": { - name: "When It Rains, It Pours", + name: "土砂降リスト", }, "MONO_GRASS": { - name: "Can't Touch This", + name: "www", }, "MONO_ELECTRIC": { - name: "Aim For The Horn!", + name: "パチピカペコ", }, "MONO_PSYCHIC": { - name: "Big Brain Energy", + name: "陽キャ", }, "MONO_ICE": { - name: "Walking On Thin Ice", + name: "ありのまま", }, "MONO_DRAGON": { - name: "Pseudo-Legend Club", + name: "龍が如く", }, "MONO_DARK": { - name: "It's Just A Phase", + name: "陰キャ", }, "MONO_FAIRY": { - name: "Hey! Listen!", + name: "あらハート満タンになった", }, "FRESH_START": { - name: "First Try!", - description: "Complete the fresh start challenge." + name: "一発で!", + description: "出直しチャレンジを クリアする" } } as const; From b54a255c15bfdfad22188d451af1a974563040b9 Mon Sep 17 00:00:00 2001 From: Leo Kim <47556641+KimJeongSun@users.noreply.github.com> Date: Fri, 9 Aug 2024 04:34:20 +0900 Subject: [PATCH 043/282] [Enhancement] Add go filter shortcut (#3345) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * update goFilter shortcut * fix filter instruction position * remove unnecessary new lines * update requested changes. add other language entries too * remove unnecessary case code * open dropdown when pressing goFilter shortcut * add missing entry for `fr` * Update src/locales/fr/starter-select-ui-handler.ts Co-authored-by: Lugiad' * Update src/locales/de/starter-select-ui-handler.ts Co-authored-by: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> * update instruction container position and text offset for more longer instruction label. decrease size of fr instruction font * fixed de info font size * Update src/locales/pt_BR/starter-select-ui-handler.ts Co-authored-by: José Ricardo Fleury Oliveira * Update src/locales/ko/starter-select-ui-handler.ts Co-authored-by: Enoch * Update src/locales/zh_TW/starter-select-ui-handler.ts Co-authored-by: mercurius-00 <80205689+mercurius-00@users.noreply.github.com> * Update src/locales/zh_CN/starter-select-ui-handler.ts Co-authored-by: mercurius-00 <80205689+mercurius-00@users.noreply.github.com> * update font size, starterInfoXPos and starterInfoYOffset in zh. update starterInfoXPos in de * Update src/locales/es/starter-select-ui-handler.ts Co-authored-by: Asdar --------- Co-authored-by: Lugiad' Co-authored-by: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> Co-authored-by: José Ricardo Fleury Oliveira Co-authored-by: Enoch Co-authored-by: mercurius-00 <80205689+mercurius-00@users.noreply.github.com> Co-authored-by: Asdar --- src/locales/de/starter-select-ui-handler.ts | 1 + src/locales/en/starter-select-ui-handler.ts | 1 + src/locales/es/starter-select-ui-handler.ts | 1 + src/locales/fr/starter-select-ui-handler.ts | 1 + src/locales/it/starter-select-ui-handler.ts | 1 + src/locales/ko/starter-select-ui-handler.ts | 1 + .../pt_BR/starter-select-ui-handler.ts | 1 + .../zh_CN/starter-select-ui-handler.ts | 1 + .../zh_TW/starter-select-ui-handler.ts | 1 + src/ui-inputs.ts | 13 ++- src/ui/starter-select-ui-handler.ts | 81 +++++++++++++++++-- 11 files changed, 96 insertions(+), 7 deletions(-) diff --git a/src/locales/de/starter-select-ui-handler.ts b/src/locales/de/starter-select-ui-handler.ts index e8ae4ed201e..eb0d444cbd5 100644 --- a/src/locales/de/starter-select-ui-handler.ts +++ b/src/locales/de/starter-select-ui-handler.ts @@ -41,6 +41,7 @@ export const starterSelectUiHandler: SimpleTranslationEntries = { "cycleAbility": ": Fähigkeit", "cycleNature": ": Wesen", "cycleVariant": ": Seltenheit", + "goFilter": ": Zu den Filtern", "enablePassive": "Passiv-Skill aktivieren", "disablePassive": "Passiv-Skill deaktivieren", "locked": "Gesperrt", diff --git a/src/locales/en/starter-select-ui-handler.ts b/src/locales/en/starter-select-ui-handler.ts index deb4236c8ba..63641479585 100644 --- a/src/locales/en/starter-select-ui-handler.ts +++ b/src/locales/en/starter-select-ui-handler.ts @@ -41,6 +41,7 @@ export const starterSelectUiHandler: SimpleTranslationEntries = { "cycleAbility": ": Ability", "cycleNature": ": Nature", "cycleVariant": ": Variant", + "goFilter": ": Go to filters", "enablePassive": "Enable Passive", "disablePassive": "Disable Passive", "locked": "Locked", diff --git a/src/locales/es/starter-select-ui-handler.ts b/src/locales/es/starter-select-ui-handler.ts index d7c203f49c4..3bb655ddceb 100644 --- a/src/locales/es/starter-select-ui-handler.ts +++ b/src/locales/es/starter-select-ui-handler.ts @@ -41,6 +41,7 @@ export const starterSelectUiHandler: SimpleTranslationEntries = { "cycleAbility": ": Habilidad", "cycleNature": ": Naturaleza", "cycleVariant": ": Variante", + "goFilter": ": Ir a filtros", "enablePassive": "Activar Pasiva", "disablePassive": "Desactivar Pasiva", "locked": "Bloqueado", diff --git a/src/locales/fr/starter-select-ui-handler.ts b/src/locales/fr/starter-select-ui-handler.ts index dbd056cbf2a..fbd407a1450 100644 --- a/src/locales/fr/starter-select-ui-handler.ts +++ b/src/locales/fr/starter-select-ui-handler.ts @@ -41,6 +41,7 @@ export const starterSelectUiHandler: SimpleTranslationEntries = { "cycleAbility": ": Talent", "cycleNature": ": Nature", "cycleVariant": ": Variant", + "goFilter": ": Aller aux filtres", "enablePassive": "Activer Passif", "disablePassive": "Désactiver Passif", "locked": "Verrouillé", diff --git a/src/locales/it/starter-select-ui-handler.ts b/src/locales/it/starter-select-ui-handler.ts index 6f43b9415e0..9ef5ccbe3ee 100644 --- a/src/locales/it/starter-select-ui-handler.ts +++ b/src/locales/it/starter-select-ui-handler.ts @@ -41,6 +41,7 @@ export const starterSelectUiHandler: SimpleTranslationEntries = { "cycleAbility": ": Abilità", "cycleNature": ": Natura", "cycleVariant": ": Variante", + "goFilter": ": Go to filters", "enablePassive": "Attiva passiva", "disablePassive": "Disattiva passiva", "locked": "Bloccato", diff --git a/src/locales/ko/starter-select-ui-handler.ts b/src/locales/ko/starter-select-ui-handler.ts index 25bb006059e..722780807b6 100644 --- a/src/locales/ko/starter-select-ui-handler.ts +++ b/src/locales/ko/starter-select-ui-handler.ts @@ -41,6 +41,7 @@ export const starterSelectUiHandler: SimpleTranslationEntries = { "cycleAbility": ": 특성", "cycleNature": ": 성격", "cycleVariant": ": 색상", + "goFilter": ": 필터로 이동", "enablePassive": "패시브 활성화", "disablePassive": "패시브 비활성화", "locked": "잠김", diff --git a/src/locales/pt_BR/starter-select-ui-handler.ts b/src/locales/pt_BR/starter-select-ui-handler.ts index 660076da413..8bc045f76a9 100644 --- a/src/locales/pt_BR/starter-select-ui-handler.ts +++ b/src/locales/pt_BR/starter-select-ui-handler.ts @@ -41,6 +41,7 @@ export const starterSelectUiHandler: SimpleTranslationEntries = { "cycleAbility": ": » Habilidade", "cycleNature": ": » Natureza", "cycleVariant": ": » Variante", + "goFilter": ": Ir para filtros", "enablePassive": "Ativar Passiva", "disablePassive": "Desativar Passiva", "locked": "Bloqueada", diff --git a/src/locales/zh_CN/starter-select-ui-handler.ts b/src/locales/zh_CN/starter-select-ui-handler.ts index c9c1cf501ef..39bab560eac 100644 --- a/src/locales/zh_CN/starter-select-ui-handler.ts +++ b/src/locales/zh_CN/starter-select-ui-handler.ts @@ -41,6 +41,7 @@ export const starterSelectUiHandler: SimpleTranslationEntries = { "cycleAbility": ": 特性", "cycleNature": ": 性格", "cycleVariant": ": 变种", + "goFilter": ": 转到筛选", "enablePassive": "启用被动", "disablePassive": "禁用被动", "locked": "未解锁", diff --git a/src/locales/zh_TW/starter-select-ui-handler.ts b/src/locales/zh_TW/starter-select-ui-handler.ts index 1202bf45f0e..7aecd459178 100644 --- a/src/locales/zh_TW/starter-select-ui-handler.ts +++ b/src/locales/zh_TW/starter-select-ui-handler.ts @@ -42,6 +42,7 @@ export const starterSelectUiHandler: SimpleTranslationEntries = { "cycleAbility": ": 特性", "cycleNature": ": 性格", "cycleVariant": ": 變種", + "goFilter": ": 轉到篩選", "enablePassive": "啟用被動", "disablePassive": "禁用被動", "locked": "未解鎖", diff --git a/src/ui-inputs.ts b/src/ui-inputs.ts index 9288fd35892..d514ddb7823 100644 --- a/src/ui-inputs.ts +++ b/src/ui-inputs.ts @@ -79,7 +79,7 @@ export class UiInputs { [Button.ACTION]: () => this.buttonAb(Button.ACTION), [Button.CANCEL]: () => this.buttonAb(Button.CANCEL), [Button.MENU]: () => this.buttonMenu(), - [Button.STATS]: () => this.buttonStats(true), + [Button.STATS]: () => this.buttonGoToFilter(Button.STATS), [Button.CYCLE_SHINY]: () => this.buttonCycleOption(Button.CYCLE_SHINY), [Button.CYCLE_FORM]: () => this.buttonCycleOption(Button.CYCLE_FORM), [Button.CYCLE_GENDER]: () => this.buttonCycleOption(Button.CYCLE_GENDER), @@ -139,6 +139,17 @@ export class UiInputs { p.toggleStats(pressed); } } + + buttonGoToFilter(button: Button): void { + const whitelist = [StarterSelectUiHandler]; + const uiHandler = this.scene.ui?.getHandler(); + if (whitelist.some(handler => uiHandler instanceof handler)) { + this.scene.ui.processInput(button); + } else { + this.buttonStats(true); + } + } + buttonInfo(pressed: boolean = true): void { if (this.scene.showMovesetFlyout ) { for (const p of this.scene.getField().filter(p => p?.isActive(true))) { diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index 5a6271cbc4b..43af8d456c1 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -70,8 +70,9 @@ const languageSettings: { [key: string]: LanguageSetting } = { instructionTextSize: "38px", }, "de":{ - starterInfoTextSize: "56px", + starterInfoTextSize: "48px", instructionTextSize: "35px", + starterInfoXPos: 33, }, "es":{ starterInfoTextSize: "56px", @@ -79,7 +80,7 @@ const languageSettings: { [key: string]: LanguageSetting } = { }, "fr":{ starterInfoTextSize: "54px", - instructionTextSize: "42px", + instructionTextSize: "35px", }, "it":{ starterInfoTextSize: "56px", @@ -91,9 +92,10 @@ const languageSettings: { [key: string]: LanguageSetting } = { starterInfoXPos: 33, }, "zh":{ - starterInfoTextSize: "40px", - instructionTextSize: "42px", - starterInfoYOffset: 2 + starterInfoTextSize: "47px", + instructionTextSize: "38px", + starterInfoYOffset: 1, + starterInfoXPos: 24, }, "pt":{ starterInfoTextSize: "48px", @@ -258,18 +260,21 @@ export default class StarterSelectUiHandler extends MessageUiHandler { private pokemonShinyIcon: Phaser.GameObjects.Sprite; private instructionsContainer: Phaser.GameObjects.Container; + private filterInstructionsContainer: Phaser.GameObjects.Container; private shinyIconElement: Phaser.GameObjects.Sprite; private formIconElement: Phaser.GameObjects.Sprite; private abilityIconElement: Phaser.GameObjects.Sprite; private genderIconElement: Phaser.GameObjects.Sprite; private natureIconElement: Phaser.GameObjects.Sprite; private variantIconElement: Phaser.GameObjects.Sprite; + private goFilterIconElement: Phaser.GameObjects.Sprite; private shinyLabel: Phaser.GameObjects.Text; private formLabel: Phaser.GameObjects.Text; private genderLabel: Phaser.GameObjects.Text; private abilityLabel: Phaser.GameObjects.Text; private natureLabel: Phaser.GameObjects.Text; private variantLabel: Phaser.GameObjects.Text; + private goFilterLabel: Phaser.GameObjects.Text; private starterSelectMessageBox: Phaser.GameObjects.NineSlice; private starterSelectMessageBoxContainer: Phaser.GameObjects.Container; @@ -329,7 +334,9 @@ export default class StarterSelectUiHandler extends MessageUiHandler { //variables to keep track of the dynamically rendered list of instruction prompts for starter select private instructionRowX = 0; private instructionRowY = 0; - private instructionRowTextOffset = 12; + private instructionRowTextOffset = 9; + private filterInstructionRowX = 0; + private filterInstructionRowY = 0; private starterSelectCallback: StarterSelectCallback | null; @@ -825,8 +832,19 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.variantLabel = addTextObject(this.scene, this.instructionRowX + this.instructionRowTextOffset, this.instructionRowY, i18next.t("starterSelectUiHandler:cycleVariant"), TextStyle.PARTY, { fontSize: instructionTextSize }); this.variantLabel.setName("text-variant-label"); + this.goFilterIconElement = new Phaser.GameObjects.Sprite(this.scene, this.filterInstructionRowX, this.filterInstructionRowY, "keyboard", "C.png"); + this.goFilterIconElement.setName("sprite-goFilter-icon-element"); + this.goFilterIconElement.setScale(0.675); + this.goFilterIconElement.setOrigin(0.0, 0.0); + this.goFilterLabel = addTextObject(this.scene, this.filterInstructionRowX + this.instructionRowTextOffset, this.filterInstructionRowY, i18next.t("starterSelectUiHandler:goFilter"), TextStyle.PARTY, { fontSize: instructionTextSize }); + this.goFilterLabel.setName("text-goFilter-label"); + this.hideInstructions(); + this.filterInstructionsContainer = this.scene.add.container(50, 5); + this.filterInstructionsContainer.setVisible(true); + this.starterSelectContainer.add(this.filterInstructionsContainer); + this.starterSelectMessageBoxContainer = this.scene.add.container(0, this.scene.game.canvas.height / 6); this.starterSelectMessageBoxContainer.setVisible(false); this.starterSelectContainer.add(this.starterSelectMessageBoxContainer); @@ -1175,6 +1193,16 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.tryExit(); success = true; } + } else if (button === Button.STATS) { + // if stats button is pressed, go to filter directly + if (!this.filterMode) { + this.startCursorObj.setVisible(false); + this.starterIconsCursorObj.setVisible(false); + this.setSpecies(null); + this.filterBarCursor = 0; + this.setFilterMode(true); + this.filterBar.toggleDropDown(this.filterBarCursor); + } } else if (this.startCursorObj.visible) { // this checks to see if the start button is selected switch (button) { case Button.ACTION: @@ -2026,6 +2054,9 @@ export default class StarterSelectUiHandler extends MessageUiHandler { case SettingKeyboard.Button_Cycle_Variant: iconPath = "V.png"; break; + case SettingKeyboard.Button_Stats: + iconPath = "C.png"; + break; default: break; } @@ -2045,11 +2076,36 @@ export default class StarterSelectUiHandler extends MessageUiHandler { } } + updateFilterButtonIcon(iconSetting, gamepadType, iconElement, controlLabel): void { + let iconPath; + // touch controls cannot be rebound as is, and are just emulating a keyboard event. + // Additionally, since keyboard controls can be rebound (and will be displayed when they are), we need to have special handling for the touch controls + if (gamepadType === "touch") { + gamepadType = "keyboard"; + iconPath = "C.png"; + } else { + iconPath = this.scene.inputController?.getIconForLatestInputRecorded(iconSetting); + } + iconElement.setTexture(gamepadType, iconPath); + iconElement.setPosition(this.filterInstructionRowX, this.filterInstructionRowY); + controlLabel.setPosition(this.filterInstructionRowX + this.instructionRowTextOffset, this.filterInstructionRowY); + iconElement.setVisible(true); + controlLabel.setVisible(true); + this.filterInstructionsContainer.add([iconElement, controlLabel]); + this.filterInstructionRowY += 8; + if (this.filterInstructionRowY >= 24) { + this.filterInstructionRowY = 0; + this.filterInstructionRowX += 50; + } + } updateInstructions(): void { this.instructionRowX = 0; this.instructionRowY = 0; + this.filterInstructionRowX = 0; + this.filterInstructionRowY = 0; this.hideInstructions(); this.instructionsContainer.removeAll(); + this.filterInstructionsContainer.removeAll(); let gamepadType; if (this.scene.inputMethod === "gamepad") { gamepadType = this.scene.inputController.getConfig(this.scene.inputController.selectedDevice[Device.GAMEPAD]).padType; @@ -2057,6 +2113,10 @@ export default class StarterSelectUiHandler extends MessageUiHandler { gamepadType = this.scene.inputMethod; } + if (!gamepadType) { + return; + } + if (this.speciesStarterDexEntry?.caughtAttr) { if (this.canCycleShiny) { this.updateButtonIcon(SettingKeyboard.Button_Cycle_Shiny, gamepadType, this.shinyIconElement, this.shinyLabel); @@ -2077,6 +2137,12 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.updateButtonIcon(SettingKeyboard.Button_Cycle_Variant, gamepadType, this.variantIconElement, this.variantLabel); } } + + // if filter mode is inactivated and gamepadType is not undefined, update the button icons + if (!this.filterMode) { + this.updateFilterButtonIcon(SettingKeyboard.Button_Stats, gamepadType, this.goFilterIconElement, this.goFilterLabel); + } + } getValueLimit(): integer { @@ -2398,6 +2464,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.setCursor(filterMode ? this.filterBarCursor : this.cursor); if (filterMode) { this.setSpecies(null); + this.updateInstructions(); } return true; @@ -3260,6 +3327,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.natureLabel.setVisible(false); this.variantIconElement.setVisible(false); this.variantLabel.setVisible(false); + this.goFilterIconElement.setVisible(false); + this.goFilterLabel.setVisible(false); } clear(): void { From ba9378d1d89dfae693ba34fc1c9a524e37cb67cc Mon Sep 17 00:00:00 2001 From: ImperialSympathizer <110984302+ben-lear@users.noreply.github.com> Date: Thu, 8 Aug 2024 15:59:23 -0400 Subject: [PATCH 044/282] disables final boss passive (#3393) Co-authored-by: ImperialSympathizer --- src/field/pokemon.ts | 6 ++++++ src/test/final_boss.test.ts | 8 ++++++++ 2 files changed, 14 insertions(+) diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 283f90f891c..bf9cc6db42a 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -1081,6 +1081,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { (Overrides.OPP_PASSIVE_ABILITY_OVERRIDE !== Abilities.NONE && !this.isPlayer())) { return true; } + + // Final boss does not have passive + if (this.scene.currentBattle?.battleSpec === BattleSpec.FINAL_BOSS && this instanceof EnemyPokemon) { + return false; + } + return this.passive || this.isBoss(); } diff --git a/src/test/final_boss.test.ts b/src/test/final_boss.test.ts index c087bd5ba82..1636b66707b 100644 --- a/src/test/final_boss.test.ts +++ b/src/test/final_boss.test.ts @@ -56,6 +56,14 @@ describe("Final Boss", () => { expect(game.scene.getEnemyPokemon()!.species.speciesId).not.toBe(Species.ETERNATUS); }); + it("should not have passive enabled on Eternatus", async () => { + await runToFinalBossEncounter(game, [Species.BIDOOF]); + + const eternatus = game.scene.getEnemyPokemon(); + expect(eternatus.species.speciesId).toBe(Species.ETERNATUS); + expect(eternatus.hasPassive()).toBe(false); + }); + it.todo("should change form on direct hit down to last boss fragment", () => {}); }); From b794662776c4fb203ab4289abc6dd18342516cf1 Mon Sep 17 00:00:00 2001 From: ImperialSympathizer <110984302+ben-lear@users.noreply.github.com> Date: Thu, 8 Aug 2024 17:06:57 -0400 Subject: [PATCH 045/282] [Test] Fix final boss test (#3444) Co-authored-by: ImperialSympathizer --- src/test/final_boss.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/final_boss.test.ts b/src/test/final_boss.test.ts index 1636b66707b..3e1225295e0 100644 --- a/src/test/final_boss.test.ts +++ b/src/test/final_boss.test.ts @@ -60,8 +60,8 @@ describe("Final Boss", () => { await runToFinalBossEncounter(game, [Species.BIDOOF]); const eternatus = game.scene.getEnemyPokemon(); - expect(eternatus.species.speciesId).toBe(Species.ETERNATUS); - expect(eternatus.hasPassive()).toBe(false); + expect(eternatus?.species.speciesId).toBe(Species.ETERNATUS); + expect(eternatus?.hasPassive()).toBe(false); }); it.todo("should change form on direct hit down to last boss fragment", () => {}); From 30cc6aba8947aa6de2f2629e93f8d5365a13f940 Mon Sep 17 00:00:00 2001 From: flx-sta <50131232+flx-sta@users.noreply.github.com> Date: Fri, 9 Aug 2024 06:33:31 -0700 Subject: [PATCH 046/282] [Bug] Fix DNA splicers broken from the strictnull check (#3454) This makes DNA-splicer work again --- src/data/status-effect.ts | 6 +++--- src/field/pokemon.ts | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/data/status-effect.ts b/src/data/status-effect.ts index 828c52cae13..4381db5c2c6 100644 --- a/src/data/status-effect.ts +++ b/src/data/status-effect.ts @@ -115,11 +115,11 @@ export function getRandomStatusEffect(statusEffectA: StatusEffect, statusEffectB * @param statusA The first Status * @param statusB The second Status */ -export function getRandomStatus(statusA: Status, statusB: Status): Status { - if (statusA === undefined || statusA.effect === StatusEffect.NONE || statusA.effect === StatusEffect.FAINT) { +export function getRandomStatus(statusA: Status | null, statusB: Status | null): Status | null { + if (!statusA || statusA.effect === StatusEffect.NONE || statusA.effect === StatusEffect.FAINT) { return statusB; } - if (statusB === undefined || statusB.effect === StatusEffect.NONE || statusB.effect === StatusEffect.FAINT) { + if (!statusB || statusB.effect === StatusEffect.NONE || statusB.effect === StatusEffect.FAINT) { return statusA; } diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index bf9cc6db42a..b4461c21354 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -3614,7 +3614,7 @@ export class PlayerPokemon extends Pokemon { if (!this.isFainted()) { // If this Pokemon hasn't fainted, make sure the HP wasn't set over the new maximum this.hp = Math.min(this.hp, this.stats[Stat.HP]); - this.status = getRandomStatus(this.status!, pokemon.status!); // Get a random valid status between the two // TODO: are the bangs correct? + this.status = getRandomStatus(this.status, pokemon.status); // Get a random valid status between the two } else if (!pokemon.isFainted()) { // If this Pokemon fainted but the other hasn't, make sure the HP wasn't set to zero this.hp = Math.max(this.hp, 1); From 3dfe4570deb8be5e1a7330a7651a08bd3cd0ccc1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Ricardo=20Fleury=20Oliveira?= Date: Fri, 9 Aug 2024 10:33:46 -0300 Subject: [PATCH 047/282] [Localization] Update Portuguese translations for achievements, trainers and dialogues (#3452) --- src/locales/pt_BR/achv.ts | 6 +- src/locales/pt_BR/dialogue.ts | 1752 +++++++-------------------------- src/locales/pt_BR/trainers.ts | 60 +- 3 files changed, 384 insertions(+), 1434 deletions(-) diff --git a/src/locales/pt_BR/achv.ts b/src/locales/pt_BR/achv.ts index 5874616bcdc..59aae596f83 100644 --- a/src/locales/pt_BR/achv.ts +++ b/src/locales/pt_BR/achv.ts @@ -171,7 +171,7 @@ export const PGMachv: AchievementTranslationEntries = { }, "UNEVOLVED_CLASSIC_VICTORY": { name: "Tire as Crianças da Sala", - description: "Vença o jogo no Modo Clássico com pelo menos um membro da equipe não evoluído.." + description: "Vença o jogo no Modo Clássico com pelo menos um membro da equipe não evoluído." }, "MONO_GEN_ONE": { @@ -445,8 +445,8 @@ export const PGFachv: AchievementTranslationEntries = { description: "Vença o jogo no modo clássico", }, "UNEVOLVED_CLASSIC_VICTORY": { - name: "Bring Your Child To Work Day", - description: "Beat the game in Classic Mode with at least one unevolved party member." + name: "Tire as Crianças da Sala", + description: "Vença o jogo no Modo Clássico com pelo menos um membro da equipe não evoluído." }, "MONO_GEN_ONE": { diff --git a/src/locales/pt_BR/dialogue.ts b/src/locales/pt_BR/dialogue.ts index 88018c7fcda..d128dea29ea 100644 --- a/src/locales/pt_BR/dialogue.ts +++ b/src/locales/pt_BR/dialogue.ts @@ -1,6 +1,6 @@ import { DialogueTranslationEntries, SimpleTranslationEntries } from "#app/interfaces/locales"; -// Diálogo dos NPCs no jogo quando o personagem do jogador é masculino (ou não definido) +// Dialogue of the NPCs in the game when the player character is male (or unset) export const PGMdialogue: DialogueTranslationEntries = { "youngster": { "encounter": { @@ -385,295 +385,278 @@ export const PGMdialogue: DialogueTranslationEntries = { }, "archer": { "encounter": { - 1: "Before you go any further, let's see how you far against us, Team Rocket!", - 2: "I have received reports that your skills are not insignificant. Let's see if they are true.", - 3: "I am Archer, an Admin of Team Rocket. And I do not go easy on enemies of our organization." + 1: "Antes de você ir mais longe, vamos ver como você se sai contra nós, Equipe Rocket!", + 2: "Eu tenho recebido relatórios de que suas habilidades não são insignificantes. Vamos ver se são verdadeiros.", + 3: "Eu sou Archer, um Admin da Equipe Rocket. E não tenho piedade dos inimigos da nossa organização." }, "victory": { - 1: "What a blunder!", - 2: "With my current skills, I was not up to the task after all.", - 3: "F-forgive me, Giovanni... For me to be defeated by a mere trainer..." + 1: "Que vexame!", + 2: "Com minhas habilidades atuais, eu não estava à altura da tarefa, afinal.", + 3: "M-me perdoe, Giovanni... Por ser derrotado por um mero treinador..." }, }, "ariana": { "encounter": { - 1: `Hold it right there! We can't someone on the loose." - $It's harmful to Team Rocket's pride, you see.`, - 2: `I don't know or care if what I'm doing is right or wrong... - $I just put my faith in Giovanni and do as I am told`, - 3: "Your trip ends here. I'm going to take you down!" + 1: "Pera aí! Não podemos deixar alguém solto por aí. Isso é prejudicial para o orgulho da Equipe Rocket, entende?", + 2: "Eu não sei ou me importo se o que estou fazendo é certo ou errado... Eu apenas coloco minha fé em Giovanni e faço o que me é dito.", + 3: "Sua viagem termina aqui. Vou te derrubar!" }, "victory": { - 1: `Tch, you really are strong. It's too bad. - $If you were to join Team Rocket, you could become an Executive.`, - 2: "I... I'm shattered...", - 3: "Aaaieeeee! This can't be happening! I fought hard, but I still lost…" + 1: "Uau, você é forte. Que desperdício. Se você se juntasse à Equipe Rocket, poderia se tornar um Executivo.", + 2: "Eu... Eu estou arrasada...", + 3: "Aaaieeeee! Isso não pode estar acontecendo! Eu lutei muito, mas ainda perdi…" }, }, "proton": { "encounter": { - 1: "What do you want? If you interrupt our work, don't expect any mercy!", - 2: `What do we have here? I am often labeled as the scariest and cruelest guy in Team Rocket… - $I strongly urge you not to interfere with our business!`, - 3: "I am Proton, an Admin of Team Rocket. I am here to put an end to your meddling!" + 1: "O que você quer? Se você interromper nosso trabalho, não espere misericórdia!", + 2: "O que temos aqui? Costumam me chamar de o cara mais assustador e cruel da Equipe Rocket… Eu recomendo fortemente que você não interfira nos nossos negócios!", + 3: "Eu sou Proton, um Admin da Equipe Rocket. Estou aqui para acabar com a sua intromissão!" }, "victory": { - 1: "The fortress came down!", - 2: "You may have won this time… But all you did was make Team Rocket's wrath grow…", - 3: "I am defeated… But I will not forget this!" + 1: "A fortaleza caiu!", + 2: "Você pode ter vencido desta vez… Mas tudo o que fez foi aumentar a ira da Equipe Rocket…", + 3: "Fui derrotado… Mas não esquecerei disso!" }, }, - "petrel": { "encounter": { - 1: `Muhahaha, we've been waiting for you. Me? You don't know who I am? It is me, Giovanni. - $The majestic Giovanni himself! Wahahaha! …Huh? I don't sound anything like Giovanni? - $I don't even look like Giovanni? How come? I've worked so hard to mimic him!`, - 2: "I am Petrel, an Admin of Team Rocket. I will not allow you to interfere with our plans!", - 3: "Rocket Executive Petrel will deal with this intruder!" + 1: "Muhahaha, estávamos esperando por você. Eu? Você não sabe quem eu sou? Sou eu, Giovanni. O majestoso Giovanni em pessoa! Wahahaha! ...Huh? Eu não pareço nada com Giovanni? Eu nem mesmo pareço com Giovanni? Como assim? Trabalhei tanto para imitá-lo!", + 2: "Eu sou Petrel, um Admin da Equipe Rocket. Não permitirei que você interfira em nossos planos!", + 3: "O Executivo da Rocket, Petrel, vai lidar com este intruso!" }, "victory": { - 1: "OK, OK. I'll tell you where he is.", - 2: "I… I couldn't do a thing… Giovanni, please forgive me…", - 3: "No, I can't let this affect me. I have to inform the others…" + 1: "OK, OK. Vou te contar onde ele está.", + 2: "Eu... Eu não consegui fazer nada... Giovanni, por favor, me perdoe...", + 3: "Não, eu não posso deixar isso me afetar. Tenho que informar os outros…" }, }, "tabitha": { "encounter": { - 1: "Hehehe! So you've come all the way here! But you're too late!", - 2: `Hehehe... Got here already, did you? We underestimated you! But this is it! - $I'm a cut above the Grunts you've seen so far. I'm not stalling for time. - $I'm going to pulverize you!`, - 3: "I'm going to give you a little taste of pain! Resign yourself to it!" + 1: "Hehehe! Então você veio até aqui! Mas você chegou tarde demais!", + 2: "Hehehe... Já chegou aqui, não é? Nós subestimamos você! Mas é isso! Eu sou um passo acima dos Capangas que você viu até agora. Não estou ganhando tempo. Vou te pulverizar!", + 3: "Vou te dar um gostinho da dor! Resigne-se a isso!" }, "victory": { - 1: `Hehehe! You might have beaten me, but you don't stand a chance against the Boss! - $If you get lost now, you won't have to face a sound whipping!`, - 2: "Hehehe... So, I lost, too...", - 3: "Ahya! How could this be? For an Admin like me to lose to some random trainer..." + 1: "Hehehe! Você pode ter me derrotado, mas não tem chance contra o Chefe! Se você se perder agora, não terá que enfrentar uma surra sonora!", + 2: "Hehehe... Então, eu também perdi...", + 3: "Ahya! Como isso pode ser? Para um Admin como eu perder para um treinador qualquer..." }, }, "courtney": { "encounter": { - 1: "The thing...The thing that you hold...That is what... That's what we of Team Magma seek...", - 2: "... Well then...Deleting...", - 3: "...Ha. ...Analyzing... ...Hah♪" + 1: "A coisa... A coisa que você segura... É o que... É o que nós da Equipe Magma procuramos...", + 2: "... Bem então... Deletando...", + 3: "...Ha. ...Analisando... ...Hah♪" }, "victory": { - 1: "... ...Change...the world.", - 2: `As anticipated. Unanticipated. You. Target lock...completed. - $Commencing...experiment. You. Forever. Aha... ♪`, - 3: "...Again? That's unanticipated. ...I knew it. You...are interesting! ...Haha. ♪" + 1: "... ...Mudar...o mundo.", + 2: "Como antecipado. Não antecipado. Você. Bloqueio de alvo... concluído. Iniciando... experimento. Você. Para sempre. Aha... ♪", + 3: "... De novo? Isso não foi antecipado. ...Eu sabia. Você... é interessante! ...Haha. ♪" }, }, "shelly": { "encounter": { - 1: `Ahahahaha! You're going to meddle in Team Aqua's affairs? - $You're either absolutely fearless, simply ignorant, or both! - $You're so cute, you're disgusting! I'll put you down`, - 2: "What's this? Who's this spoiled brat?", - 3: "Cool your jets. Be patient. I'll crush you shortly." + 1: "Ahahahaha! Você vai se meter nos assuntos da Equipe Aqua? Você é absolutamente destemido, simplesmente ignorante ou ambos! Você é tão fofo que chega a ser nojento! Vou te derrubar", + 2: "O que é isso? Quem é essa criança mimada?", + 3: "Relaxe. Seja paciente. Vou te esmagar em breve." }, "victory": { - 1: `Ahahahaha! We got meddled with unexpectedly! We're out of options. - $We'll have to pull out. But this isn't the last you'll see of Team Aqua! - $We have other plans! Don't you forget it!`, - 2: "Ahhh?! Did I go too easy on you?!", - 3: `Uh. Are you telling me you've upped your game even more during the fight? - $You're a brat with a bright future… My Pokémon and I don't have any strength left to fight… - $Go on… Go and be destroyed by Archie.` + 1: "Ahahahaha! Fomos surpreendidos inesperadamente! Estamos sem opções. Teremos que recuar. Mas esta não é a última vez que você verá a Equipe Aqua! Temos outros planos! Não se esqueça disso!", + 2: "Ahhh?! Fui muito fácil com você?!", + 3: "Uh. Você está me dizendo que melhorou seu jogo ainda mais durante a luta? Você é um pirralho com um futuro brilhante… Meu Pokémon e eu não temos mais forças para lutar… Vá em frente… Vá e seja destruído por Archie." }, }, "matt": { "encounter": { - 1: "Hoohahaha! What, you got a screw loose or something? Look at you, little Makuhita person!", - 2: "Oho! You! You're that funny kid!", - 3: "What are you doing here? Did you follow us?" + 1: "Hoohahaha! O que, você tem um parafuso solto ou algo assim? Olhe para você, pequena pessoa Makuhita!", + 2: "Oho! Você! Você é aquela criança engraçada!", + 3: "O que você está fazendo aqui? Você nos seguiu?" }, "victory": { - 1: "All right then, until the Boss has time for you, I'll be your opponent!", - 2: `I can feel it! I can feel it, all right! The strength coming offa you! - $More! I still want more! But looks like we're outta time...`, - 3: "That was fun! I knew you'd show me a good time! I look forward to facing you again someday!" + 1: "Muito bem, até que o Chefe tenha tempo para você, serei seu oponente!", + 2: "Posso sentir! Posso sentir, tudo bem! A força saindo de você! Mais! Eu ainda quero mais! Mas parece que estamos sem tempo...", + 3: "Isso foi divertido! Eu sabia que você me mostraria um bom tempo! Estou ansioso para enfrentá-lo novamente algum dia!" }, }, "mars": { "encounter": { - 1: "I'm Mars, one of Team Galactic's top Commanders.", - 2: "Team Galactic's vision for the future is unwavering. Opposition will be crushed without mercy!", - 3: "Feeling nervous? You should be!" + 1: "Sou Mars, uma das principais Comandantes da Equipe Galáctica.", + 2: "A visão da Equipe Galáctica para o futuro é inabalável. A oposição será esmagada sem piedade!", + 3: "Sentindo-se nervoso? Você deveria estar!" }, "victory": { - 1: "This can't be happening! How did I lose?!", - 2: "You have some skill, I'll give you that.", - 3: "Defeated... This was a costly mistake." + 1: "Isso não pode estar acontecendo! Como eu perdi?!", + 2: "Você tem alguma habilidade, eu admito isso.", + 3: "Derrotada... Este foi um erro caro." } }, "jupiter": { "encounter": { - 1: "Jupiter, Commander of Team Galactic, at your service.", - 2: "Resistance is futile. Team Galactic will prevail!", - 3: "You're trembling... scared already?" + 1: "Júpiter, Comandante da Equipe Galáctica, ao seu serviço.", + 2: "A resistência é inútil. A Equipe Galáctica prevalecerá!", + 3: "Você está tremendo... já está com medo?" }, "victory": { - 1: "No way... I lost?!", - 2: "Impressive, you've got guts!", - 3: "Losing like this... How embarrassing." + 1: "De jeito nenhum... Eu perdi?!", + 2: "Impressionante, você tem coragem!", + 3: "Perder assim... Que embaraço." } }, "saturn": { "encounter": { - 1: "I am Saturn, Commander of Team Galactic.", - 2: "Our mission is absolute. Any hindrance will be obliterated!", - 3: "Is that fear I see in your eyes?" + 1: "Eu sou Saturno, Comandante da Equipe Galáctica.", + 2: "Nossa missão é absoluta. Qualquer obstáculo será obliterado!", + 3: "É medo o que vejo em seus olhos?" }, "victory": { - 1: "Impossible... Defeated by you?!", - 2: "You have proven yourself a worthy adversary.", - 3: "Bestowed in defeat... This is unacceptable." - }}, + 1: "Impossível... Derrotado por você?!", + 2: "Você provou ser um adversário digno.", + 3: "Derrotado... Isso é inaceitável." + } + }, "zinzolin": { "encounter": { - 1: "You could become a threat to Team Plasma, so we will eliminate you here and now!", - 2: "Oh, for crying out loud... I didn't expect to have to battle in this freezing cold!", - 3: "You're an impressive Trainer to have made it this far. But it ends here." + 1: "Você poderia se tornar uma ameaça para a Equipe Plasma, então vamos eliminá-lo aqui e agora!", + 2: "Oh, pelo amor de Deus... Eu não esperava ter que lutar neste frio congelante!", + 3: "Você é um treinador impressionante para ter chegado tão longe. Mas termina aqui." }, "victory": { - 1: "Ghetsis... I have failed you...", - 2: "It's bitter cold. I'm shivering. I'm suffering. Yet, I still stand victorious.", - 3: "Hmph. You're a smarter Trainer than I expected, but not smart enough." + 1: "Ghetsis... Eu falhei com você...", + 2: "Está amargamente frio. Estou tremendo. Estou sofrendo. Ainda assim, estou vitorioso.", + 3: "Hmph. Você é um treinador mais esperto do que eu esperava, mas não esperto o suficiente." } }, "rood": { "encounter": { - 1: "You are a threat to Team Plasma. We cannot let you walk away from here and now!", - 2: "Oh, this icy wind... I never thought I'd have to fight here!", - 3: "You are a remarkable Trainer to have made it this far. But this is where it ends." + 1: "Você é uma ameaça para a Equipe Plasma. Não podemos deixá-lo ir embora daqui e agora!", + 2: "Oh, este vento gelado... Eu nunca pensei que teria que lutar aqui!", + 3: "Você é um treinador notável para ter chegado tão longe. Mas é aqui que termina." }, "victory": { - 1: "Ghetsis... I have failed my mission...", - 2: "The cold is piercing. I'm shivering. I'm suffering. Yet, I have triumphed.", - 3: "Hm. You are a talented Trainer, but unfortunately not talented enough." + 1: "Ghetsis... Eu falhei em minha missão...", + 2: "O frio é penetrante. Estou tremendo. Estou sofrendo. Ainda assim, triunfei.", + 3: "Hm. Você é um treinador talentoso, mas infelizmente não talentoso o suficiente." } }, "xerosic": { "encounter": { - 1: "Ah ha ha! It would be my pleasure. Come on, little Trainer! Let's see what you've got!", - 2: "Hmm... You're more powerful than you look. I wonder how much energy there is inside you.", - 3: "I've been waiting for you! I need to do a little research on you! Come, let us begin!" + 1: "Ah ha ha! Será um prazer. Vamos lá, pequeno treinador! Vamos ver o que você tem!", + 2: "Hmm... Você é mais poderoso do que parece. Eu me pergunto quanta energia há dentro de você.", + 3: "Eu estava esperando por você! Preciso fazer uma pequena pesquisa sobre você! Vamos começar!" }, "victory": { - 1: "Ah, you're quite strong. Oh yes—very strong, indeed.", - 2: "Ding-ding-ding! You did it! To the victor go the spoils!", - 3: "Wonderful! Amazing! You have tremendous skill and bravery!" + 1: "Ah, você é bastante forte. Oh sim—muito forte, de fato.", + 2: "Ding-ding-ding! Você conseguiu! Ao vencedor, os despojos!", + 3: "Maravilhoso! Incrível! Você tem uma tremenda habilidade e coragem!" } }, "bryony": { "encounter": { - 1: "I am Bryony, and it would be my pleasure to battle you. Show me what you've got.", - 2: "Impressive... You're more powerful than you appear. Let's see the true extent of your energy.", - 3: "I've anticipated your arrival. It's time for a little test. Shall we begin?" + 1: "Eu sou Bryony, e será um prazer lutar com você. Mostre-me o que você tem.", + 2: "Impressionante... Você é mais poderoso do que parece. Vamos ver a verdadeira extensão de sua energia.", + 3: "Eu antecipei sua chegada. É hora de um pequeno teste. Vamos começar?" }, "victory": { - 1: "You're quite strong. Oh yes—very strong, indeed.", - 2: "Ding-ding-ding! You've done well. Victory is yours.", - 3: "Wonderful! Remarkable! Your skill and bravery are commendable." + 1: "Você é bastante forte. Oh sim—muito forte, de fato.", + 2: "Ding-ding-ding! Você se saiu bem. A vitória é sua.", + 3: "Maravilhoso! Notável! Sua habilidade e coragem são admiráveis." } }, "rocket_grunt": { "encounter": { 1: "Se prepara pra encrenca!", - 2: "We're pulling a big job here! Get lost, kid!", - 3: "Hand over your Pokémon, or face the wrath of Team Rocket!", - 4: "You're about to experience the true terror of Team Rocket!", - 5: "Hey, kid! Me am a Team Rocket member kind of guy!" //Use of wrong grammar is deliberate + 2: "Estamos realizando um grande trabalho aqui! Cai fora, moleque!", + 3: "Entregue seus Pokémon ou enfrente a ira da Equipe Rocket!", + 4: "Você está prestes a experimentar o verdadeiro terror da Equipe Rocket!", + 5: "Ei, moleque! Eu sou um tipo de cara da Equipe Rocket!" //Uso de gramática incorreta é proposital }, "victory": { 1: "Equipe Rocket decolando de novo!", - 2: "Oh no! I dropped the Lift Key!", - 3: "I blew it!", - 4: "My associates won't stand for this!", - 5: "You say what? Team Rocket bye-bye a go-go? Broken it is says you?" //Use of wrong grammar is deliberate. + 2: "Oh não! Eu deixei a Chave de Elevação cair!", + 3: "Eu estraguei tudo!", + 4: "Meus associados não vão tolerar isso!", + 5: "Você diz o que? Equipe Rocket tchau-tchau a vai-vai? Quebrado é diz você?" //Uso de gramática incorreta é proposital }, }, "magma_grunt": { "encounter": { 1: "Se você se meter com a Equipe Magma, não teremos piedade!", - 2: "You'd better not interfere with our plans! We're making the world a better place!", - 3: "You're in the way! Team Magma has no time for kids like you!", - 4: "I hope you brought marshmallows because things are about to heat up!", - 5: "We're going to use the power of a volcano! It's gonna be... explosive! Get it? Heh heh!" + 2: "É melhor você não interferir em nossos planos! Estamos tornando o mundo um lugar melhor!", + 3: "Você está no caminho! A Equipe Magma não tem tempo para crianças como você!", + 4: "Espero que você tenha trazido marshmallows porque as coisas estão prestes a esquentar!", + 5: "Vamos usar o poder de um vulcão! Vai ser... explosivo! Entendeu? Heh heh!" }, "victory": { 1: "Ahn? Eu perdi?!", - 2: "I can't believe I lost! I even skipped lunch for this", - 3: "No way! You're just a kid!", - 4: "Urrrgh... I should've ducked into our hideout right away...", - 5: "You beat me... Do you think the boss will dock my pay for this?" + 2: "Não posso acreditar que perdi! Até pulei o almoço por isso.", + 3: "De jeito nenhum! Você é apenas uma criança!", + 4: "Urrrgh... Eu deveria ter me escondido em nosso esconderijo imediatamente...", + 5: "Você me venceu... Você acha que o chefe vai cortar meu salário por isso?" }, }, "aqua_grunt": { "encounter": { 1: "Não pegamos leve com quem se mete com a Equipe Aqua, nem mesmo crianças!", - 2: "Grrr... You've got some nerve meddling with Team Aqua!", - 3: "You're about to get soaked! And not just from my water Pokémon!", - 4: "We, Team Aqua, exist for the good of all!", - 5: "Prepare to be washed away by the tides of my... uh, Pokémon! Yeah, my Pokémon!" + 2: "Grrr... Você tem coragem de se intrometer com a Equipe Aqua!", + 3: "Você está prestes a se molhar! E não apenas por causa dos meus Pokémon aquáticos!", + 4: "Nós, da Equipe Aqua, existimos para o bem de todos!", + 5: "Prepare-se para ser levado pelas ondas do meu... uh, Pokémon! Sim, meu Pokémon!" }, "victory": { 1: "Tá de brincadeira!", - 2: "Arrgh, I didn't count on being meddled with by some meddling kid!", - 3: "I lost?! Guess I'll have to swim back to the hideout now...", - 4: "Oh, man, what a disaster... The boss is going to be furious...", - 5: "You beat me... Do you think the boss will make me walk the plank for this?" + 2: "Arrgh, eu não contei que seria atrapalhado por uma criança intrometida!", + 3: "Eu perdi?! Acho que vou ter que nadar de volta para o esconderijo agora...", + 4: "Oh, cara, que desastre... O chefe vai ficar furioso...", + 5: "Você me venceu... Você acha que o chefe vai me fazer andar na prancha por isso?" }, }, "galactic_grunt": { "encounter": { - 1: "Não mexe com a Equipe Galáctica!", - 2: "Witness the power of our technology and the future we envision!", - 3: "In the name of Team Galactic, I'll eliminate anyone who stands in our way!", - 4: "Get ready to lose!", - 5: "Hope you're ready for a cosmic beatdown!" + 1: "Não mexa com a Equipe Galáctica!", + 2: "Presencie o poder da nossa tecnologia e o futuro que vislumbramos!", + 3: "Em nome da Equipe Galáctica, eliminarei qualquer um que ficar em nosso caminho!", + 4: "Prepare-se para perder!", + 5: "Espero que você esteja pronto para uma surra cósmica!" }, "victory": { 1: "Fui amassado...", - 2: "This setback means nothing in the grand scheme.", - 3: "Our plans are bigger than this defeat.", - 4: "How?!", - 5: "Note to self: practice Pokémon battling, ASAP." + 2: "Este contratempo não significa nada no grande esquema.", + 3: "Nossos planos são maiores que esta derrota.", + 4: "Como?!", + 5: "Nota para mim mesmo: praticar batalhas Pokémon, o mais rápido possível." }, }, "plasma_grunt": { "encounter": { 1: "Não toleramos pessoas que pensam diferente de nós!", - 2: "If I win against you, release your Pokémon!", - 3: "If you get in the way of Team Plasma, I'll take care of you!", - 4: "Team Plasma will liberate Pokémon from selfish humans like you!", - 5: "Our hairstyles are out of this world... but our battling skills? You'll find out soon enough." + 2: "Se eu ganhar de você, liberte seus Pokémon!", + 3: "Se você atrapalhar a Equipe Plasma, eu cuidarei de você!", + 4: "A Equipe Plasma vai libertar os Pokémon de humanos egoístas como você!", + 5: "Nossos penteados são de outro mundo... mas nossas habilidades de batalha? Você descobrirá em breve." }, "victory": { 1: "Plasmaaaaaaaaa!", - 2: "How could I lose...", - 3: "...What a weak Pokémon, I'll just have to go steal some better ones!", - 4: "Great plans are always interrupted.", - 5: "This is bad... Badbadbadbadbadbadbad! Bad for Team Plasma! Or Plasbad, for short!" + 2: "Como eu pude perder...", + 3: "...Que Pokémon fraco, vou ter que roubar alguns melhores!", + 4: "Grandes planos são sempre interrompidos.", + 5: "Isso é ruim... Ruim ruim ruim ruim ruim ruim ruim! Ruim para a Equipe Plasma! Ou Plasruim, para abreviar!" }, }, "flare_grunt": { "encounter": { - 1: "Your Pokémon are no match for the elegance of Team Flare.", - 2: "Hope you brought your sunglasses, because things are about to get bright!", - 3: "Team Flare will cleanse the world of imperfection!", - 4: "Prepare to face the brilliance of Team Flare!", - 5: "Fashion is most important to us!" + 1: "Seus Pokémon não são páreo para a elegância da Equipe Flare.", + 2: "Espero que você tenha trazido seus óculos de sol, porque as coisas vão ficar brilhantes!", + 3: "A Equipe Flare vai purificar o mundo da imperfeição!", + 4: "Prepare-se para enfrentar o brilho da Equipe Flare!", + 5: "A moda é o mais importante para nós!" }, "victory": { - 1: "The future doesn't look bright for me.", - 2: "Perhaps there's more to battling than I thought. Back to the drawing board.", - 3: "Gahh?! I lost?!", - 4: "Even in defeat, Team Flare's elegance shines through.", - 5: "You may have beaten me, but when I lose, I go out in style!" + 1: "O futuro não parece brilhante para mim.", + 2: "Talvez haja mais na batalha do que eu pensei. De volta à prancheta.", + 3: "Gahh?! Eu perdi?!", + 4: "Mesmo na derrota, a elegância da Equipe Flare brilha.", + 5: "Você pode ter me vencido, mas quando eu perco, eu saio com estilo!" }, }, "rocket_boss_giovanni_1": { @@ -1105,8 +1088,8 @@ export const PGMdialogue: DialogueTranslationEntries = { }, "crasher_wake": { "encounter": { - 1: "Crash! Crash! Cuidado!\nCrasher Wake… está… aqui!", - 2: "Crash! Crash! Crasher Wake!", + 1: "Crash! Crash! Cuidado!\nDemolidor Wake… está… aqui!", + 2: "Crash! Crash! Demolidor Wake!", 3: "Sou a onda de poder que vai te lavar!" }, "victory": { @@ -1448,7 +1431,7 @@ export const PGMdialogue: DialogueTranslationEntries = { }, "allister": { "encounter": { - 1: "'M Allister.\nA-aqui... vou eu..." + 1: "Sou Allister.\nA-aqui... vou eu..." }, "victory": { 1: `Quase perdi minha máscara de tanto choque... Isso foi… @@ -1579,7 +1562,7 @@ export const PGMdialogue: DialogueTranslationEntries = { 1: "Eu… Eu não… acredito…" }, "defeat": { - 1: "Isso foi por pouco. Me pergunto o que você está faltando." + 1: "Isso foi por pouco. Me pergunto o que está faltando em você." } }, "malva": { @@ -2004,7 +1987,7 @@ export const PGMdialogue: DialogueTranslationEntries = { "encounter": { 1: `Sabe de uma coisa? Estou realmente ansiosa para ter batalhas sérias com Treinadores fortes! $Quero dizer, vamos lá! Os Treinadores que chegam aqui são Treinadores que desejam a vitória com todas as fibras do seu ser! - #E eles estão batalhando ao lado de Pokémon que passaram por inúmeras batalhas difíceis! + $E eles estão batalhando ao lado de Pokémon que passaram por inúmeras batalhas difíceis! $Se eu batalhar com pessoas assim, não só eu ficarei mais forte, meus Pokémon também! $E nós vamos nos conhecer ainda melhor! OK! Prepare-se! $Sou Iris, a Campeã da Liga Pokémon, e vou te derrotar!`, @@ -2288,7 +2271,7 @@ export const PGMdialogue: DialogueTranslationEntries = { "encounter": { 1: `Oh, se não é um jovem Treinador… É adorável conhecê-lo assim. $Então, suponho que você ganhou o direito a uma batalha, como recompensa por seus esforços. - $O elusivo Fada pode parecer frágil como a brisa e delicado como uma flor, mas é forte.`, + $Uma elusiva Fada pode parecer frágil como a brisa e delicado como uma flor, mas é forte.`, }, "victory": { 1: "Espero que você encontre coisas para sorrir amanhã…" @@ -2458,7 +2441,7 @@ export const PGMdialogue: DialogueTranslationEntries = { }, "victory": { 1: "Não acredito que perdi... Mas você mereceu essa vitória. Bem feito!", - 2: "Parece que ainda tenho muito a aprender. Grande batalha, porém!" + 2: "Parece que ainda tenho muito a aprender. Porém, grande batalha!" }, "defeat": { 1: "Você lutou bem, mas eu tenho a vantagem! Melhor sorte na próxima vez!", @@ -2649,7 +2632,7 @@ export const PGMdialogue: DialogueTranslationEntries = { $@c{serious_mopen_fists}Prepare-se.` }, "victory": { - 1: "@c{neutral}O que…@d{64} O que você é?" + 1: "@c{neutral}O que…@d{64} O que é você?" }, }, "rival_4_female": { @@ -2664,7 +2647,7 @@ export const PGMdialogue: DialogueTranslationEntries = { $@c{angry_mopen}Prepare-se.` }, "victory": { - 1: "@c{neutral}O que…@d{64} O que você é?" + 1: "@c{neutral}O que…@d{64} O que é você?" }, "defeat": { 1: "$@c{smile}Você deveria se orgulhar de até onde chegou." @@ -2736,7 +2719,7 @@ export const PGMdialogue: DialogueTranslationEntries = { }; -// Diálogo dos NPCs no jogo quando o personagem do jogador é feminino. Para idiomas que não possuem pronomes de gênero, isso pode ser definido como PGMdialogue. +// Dialogue of the NPCs in the game when the player character is female. For languages that do not have gendered pronouns, this can be set to PGMdialogue. export const PGFdialogue: DialogueTranslationEntries = { "youngster": { "encounter": { @@ -2794,90 +2777,6 @@ export const PGFdialogue: DialogueTranslationEntries = { 9: "Estou realmente cansando de batalhar… Deve haver algo novo para fazer…" } }, - "breeder": { - "encounter": { - 1: "Pokémon obedientes, Pokémon egoístas… Pokémon têm características únicas.", - 2: "Embora minha criação e comportamento sejam ruins, criei meus Pokémon bem.", - 3: "Hmm, você disciplina seus Pokémon? Mimar demais não é bom." - }, - "victory": { - 1: "É importante nutrir e treinar as características de cada Pokémon.", - 2: "Ao contrário do meu lado diabólico, esses são bons Pokémon.", - 3: "Muito elogio pode estragar tanto Pokémon quanto pessoas." - }, - "defeat": { - 1: "Você não deve ficar com raiva dos seus Pokémon, mesmo se perder uma batalha.", - 2: "Certo? Pokémon bons, né? Eu sou adequado para criar coisas.", - 3: "Não importa o quanto você ame seus Pokémon, ainda precisa discipliná-los quando se comportam mal." - } - }, - "breeder_female": { - "encounter": { - 1: "Pokémon nunca te traem. Eles retribuem todo o amor que você dá a eles.", - 2: "Quer uma dica para treinar bons Pokémon?", - 3: "Eu criei esses Pokémon muito especiais usando um método especial." - }, - "victory": { - 1: "Ugh… Não era para ser assim. Será que administrei a mistura errada?", - 2: "Como isso aconteceu com meus Pokémon… O que você está dando de comer aos seus Pokémon?", - 3: "Se eu perder, isso significa que eu estava só matando o tempo. Não machuca meu ego nem um pouco." - }, - "defeat": { - 1: "Isso prova que meus Pokémon aceitaram meu amor.", - 2: "O verdadeiro truque para treinar bons Pokémon é capturar bons Pokémon.", - 3: "Pokémon serão fortes ou fracos dependendo de como você os cria." - } - }, - "fisherman": { - "encounter": { - 1: "Anem! Você me fez perder uma fisgada!\nO que vai fazer sobre isso?", - 2: "Sai daqui! Você está assustando os Pokémon!", - 3: "Vamos ver se você consegue fisgar uma vitória!", - }, - "victory": { - 1: "Esqueça isso.", - 2: "Da próxima vez, eu vou pescar a vitória!", - 3: "Acho que subestimei a força das correntes dessa vez.", - }, - }, - "fisherman_female": { - "encounter": { - 1: "Uau! Peguei um grande!", - 2: "Linha lançada, pronta para pescar o sucesso!", - 3: "Pronta para fazer ondas!" - }, - "victory": { - 1: "Vou voltar com um anzol mais forte.", - 2: "Vou pescar a vitória na próxima vez.", - 3: "Estou só afiando meus anzóis para a revanche!" - }, - }, - "swimmer": { - "encounter": { - 1: "Hora de mergulhar!", - 2: "Vamos surfar nas ondas da vitória!", - 3: "Pronto para fazer um splash!", - }, - "victory": { - 1: "Molhado na derrota!", - 2: "Uma onda de derrota!", - 3: "De volta à praia, eu acho.", - }, - }, - "backpacker": { - "encounter": { - 1: "Prepare-se, vamos começar!", - 2: "Vamos ver se você consegue acompanhar!", - 3: "Prepare-se, desafiante!", - 4: "Passei 20 anos tentando me encontrar… Mas onde estou?" - }, - "victory": { - 1: "Dessa vez tropecei!", - 2: "Ah, acho que estou perdido.", - 3: "Caminho sem saída!", - 4: "Espere um segundo! Ei! Você não sabe quem eu sou?" - }, - }, "ace_trainer": { "encounter": { 1: "Você parece bastante confiante.", @@ -2898,14 +2797,6 @@ export const PGFdialogue: DialogueTranslationEntries = { 4: "Claro que sou forte e não perco. É importante ganhar com graça." } }, - "parasol_lady": { - "encounter": { - 1: "Hora de embelezar o campo de batalha com elegância e postura!", - }, - "victory": { - 1: "Minha elegância permanece inabalável!", - } - }, "twins": { "encounter": { 1: "Prepare-se, porque quando nos unimos, é o dobro do problema!", @@ -2923,18 +2814,6 @@ export const PGFdialogue: DialogueTranslationEntries = { 3: "Dobro de sorrisos, dobro da dança da vitória!" } }, - "cyclist": { - "encounter": { - 1: "Prepare-se para comer poeira!", - 2: "Prepare-se, desafiante! Estou prestes a te deixar para trás!", - 3: "Pé no pedal, vamos ver se você consegue acompanhar!" - }, - "victory": { - 1: "As rodas podem estar paradas, mas a determinação continua a pedalar.", - 2: "Fui mais rápido!", - 3: "O caminho para a vitória tem muitas curvas e voltas para explorar." - }, - }, "black_belt": { "encounter": { 1: "Elogio sua coragem ao me desafiar! Pois eu sou o que tem o chute mais forte!", @@ -2945,100 +2824,6 @@ export const PGFdialogue: DialogueTranslationEntries = { 2: "Hmmm… Se eu ia perder de qualquer maneira, esperava ficar totalmente destruído no processo." }, }, - "battle_girl": { - "encounter": { - 1: "Você não precisa tentar me impressionar. Você pode perder contra mim.", - }, - "victory": { - 1: "É difícil dizer adeus, mas estamos ficando sem tempo…", - }, - }, - "hiker": { - "encounter": { - 1: "Minha barriga de meia-idade me deu tanta gravidade quanto as montanhas que eu escalo!", - 2: "Herdei esse corpo ossudo dos meus pais… Sou como uma cadeia de montanhas viva…", - }, - "victory": { - 1: "Pelo menos não posso perder quando se trata de IMC!", - 2: "Não é suficiente… Nunca é suficiente. Meu colesterol ruim não está alto o suficiente…" - }, - }, - "ranger": { - "encounter": { - 1: "Quando estou cercado pela natureza, a maioria das outras coisas deixa de importar.", - 2: "Quando estou vivendo sem natureza na minha vida, às vezes sinto uma crise de ansiedade se aproximando." - }, - "victory": { - 1: "Não importa para a vastidão da natureza se eu ganhar ou perder…", - 2: "Algo assim é bastante trivial comparado aos sentimentos sufocantes da vida na cidade." - }, - "defeat": { - 1: "Ganhei a batalha. Mas a vitória não é nada comparada à vastidão da natureza…", - 2: "Tenho certeza de que como você se sente não é tão ruim se comparar aos meus ataques de ansiedade…" - } - }, - "scientist": { - "encounter": { - 1: "Minha pesquisa levará este mundo à paz e alegria.", - }, - "victory": { - 1: "Sou um gênio… Não devo perder para alguém como você…", - }, - }, - "school_kid": { - "encounter": { - 1: "Heehee. Estou confiante nos meus cálculos e análises.", - 2: "Estou ganhando o máximo de experiência que posso porque quero ser um Líder de Ginásio um dia." - }, - "victory": { - 1: "Aff… Cálculo e análise talvez não sejam páreo para o acaso…", - 2: "Até experiências difíceis e desafiadoras têm seu propósito, eu acho." - } - }, - "artist": { - "encounter": { - 1: "Eu costumava ser popular, mas agora estou acabado.", - }, - "victory": { - 1: "À medida que os tempos mudam, os valores também mudam. Percebi isso tarde demais.", - }, - }, - "guitarist": { - "encounter": { - 1: "Prepare-se para sentir o ritmo da derrota enquanto eu toco minha vitória!", - }, - "victory": { - 1: "Silenciado por agora, mas minha melodia de resiliência continuará a tocar.", - }, - }, - "worker": { - "encounter": { - 1: "Me incomoda que as pessoas sempre me entendam mal. Sou muito mais puro do que todos pensam.", - }, - "victory": { - 1: "Eu realmente não quero que minha pele queime, então quero ficar na sombra enquanto trabalho.", - }, - }, - "worker_female": { - "encounter": { - 1: `Me incomoda que as pessoas sempre me entendam mal. - $Sou muito mais pura do que todos pensam.` - }, - "victory": { - 1: "Eu realmente não quero que minha pele queime, então quero ficar na sombra enquanto trabalho." - }, - "defeat": { - 1: "Meu corpo e mente nem sempre estão necessariamente em sincronia." - } - }, - "worker_double": { - "encounter": { - 1: "Vou te mostrar que podemos te quebrar. Estamos treinando no campo!", - }, - "victory": { - 1: "Que estranho… Como isso pode ser… Não deveria ter sido superado.", - }, - }, "hex_maniac": { "encounter": { 1: "Normalmente, só escuto música clássica, mas se eu perder, acho que vou tentar um pouco de new age!", @@ -3050,35 +2835,9 @@ export const PGFdialogue: DialogueTranslationEntries = { }, "defeat": { 1: "New age se refere simplesmente aos compositores clássicos do século XX, certo?", - 2: "Não fique preso na tristeza ou frustração. Você pode usar seus rancores para se motivar." + 2: "Não fique presa na tristeza ou frustração. Você pode usar seus rancores para se motivar." } }, - "psychic": { - "encounter": { - 1: "Oi! Concentre-se!", - }, - "victory": { - 1: "Perdi minha concentração!", - }, - }, - "officer": { - "encounter": { - 1: "Prepare-se, porque a justiça está prestes a ser servida!", - 2: "Pronto para defender a lei e servir a justiça no campo de batalha!" - }, - "victory": { - 1: "O peso da justiça parece mais pesado do que nunca…", - 2: "As sombras da derrota pairam no distrito." - } - }, - "beauty": { - "encounter": { - 1: "Minha última batalha… É assim que eu gostaria que víssemos esta partida…", - }, - "victory": { - 1: "Foi divertido… Vamos ter outra última batalha algum dia…", - }, - }, "baker": { "encounter": { 1: "Espero que esteja pronta para saborear a derrota!" @@ -3087,31 +2846,11 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Vou assar uma revanche." }, }, - "biker": { - "encounter": { - 1: "Hora de acelerar e te deixar na poeira!" - }, - "victory": { - 1: "Vou me ajustar para a próxima corrida." - }, - }, - "firebreather": { - "encounter": { - 1: "Minhas chamas irão te consumir!", - 2: "Minha alma está pegando fogo. Irei te mostrar como queima!", - 3: "Cola aqui e dá uma olhada!" - }, - "victory": { - 1: "Fui reduzido a cinzas…", - 2: "Uau! Isso foi quente!", - 3: "Ai! Queimei minha língua!" - }, - }, "sailor": { "encounter": { 1: "Mano, você vai andar na prancha se perder!", 2: "Vem com tudo! Sou um marinheiro com orgulho!", - 3: "Ahoy marujo! Tá enjoado, é?!" + 3: "Ahoy maruja! Tá enjoada, é?!" }, "victory": { 1: "Argh! Perdi pra uma criança!", @@ -3119,21 +2858,155 @@ export const PGFdialogue: DialogueTranslationEntries = { 3: "Estou achando que quem tá enjoado sou eu..." }, }, - "brock": { + "ariana": { "encounter": { - 1: "Minha especialidade em Pokémon do tipo Pedra vai te derrubar! Vamos lá!", - 2: "Minha vontade firme como pedra vai te sobrecarregar!", - 3: "Permita-me mostrar a verdadeira força dos meus Pokémon!" + 1: "Pera aí! Não podemos deixar alguém solto por aí. Isso é prejudicial para o orgulho da Equipe Rocket, entende?", + 2: "Eu não sei ou me importo se o que estou fazendo é certo ou errado... Eu apenas coloco minha fé em Giovanni e faço o que me é dito.", + 3: "Sua viagem termina aqui. Vou te derrubar!" }, "victory": { - 1: "A força dos seus Pokémon superou minhas defesas de pedra!", - 2: "O mundo é enorme! Estou feliz por ter tido a chance de batalhar com você.", - 3: "Talvez eu deva voltar a perseguir meu sonho de ser Criador de Pokémon…" + 1: "Uau, você é forte. Que desperdício. Se você se juntasse à Equipe Rocket, poderia se tornar uma Executiva.", + 2: "Eu... Eu estou arrasada...", + 3: "Aaaieeeee! Isso não pode estar acontecendo! Eu lutei muito, mas ainda perdi…" + }, + }, + "tabitha": { + "encounter": { + 1: "Hehehe! Então você veio até aqui! Mas você chegou tarde demais!", + 2: "Hehehe... Já chegou aqui, não é? Nós subestimamos você! Mas é isso! Eu sou um passo acima dos Capangas que você viu até agora. Não estou ganhando tempo. Vou te pulverizar!", + 3: "Vou te dar um gostinho da dor! Resigne-se a isso!" + }, + "victory": { + 1: "Hehehe! Você pode ter me derrotado, mas não tem chance contra o Chefe! Se você se perder agora, não terá que enfrentar uma surra sonora!", + 2: "Hehehe... Então, eu também perdi...", + 3: "Ahya! Como isso pode ser? Para um Admin como eu perder para uma treinadora qualquer..." + }, + }, + "shelly": { + "encounter": { + 1: "Ahahahaha! Você vai se meter nos assuntos da Equipe Aqua? Você é absolutamente destemida, simplesmente ignorante ou ambos! Você é tão fofa que chega a ser nojenta! Vou te derrubar", + 2: "O que é isso? Quem é essa criança mimada?", + 3: "Relaxe. Seja paciente. Vou te esmagar em breve." + }, + "victory": { + 1: "Ahahahaha! Fomos surpreendidos inesperadamente! Estamos sem opções. Teremos que recuar. Mas esta não é a última vez que você verá a Equipe Aqua! Temos outros planos! Não se esqueça disso!", + 2: "Ahhh?! Fui muito fácil com você?!", + 3: "Uh. Você está me dizendo que melhorou seu jogo ainda mais durante a luta? Você é uma pirralha com um futuro brilhante… Meu Pokémon e eu não temos mais forças para lutar… Vá em frente… Vá e seja destruída por Archie." + }, + }, + "matt": { + "encounter": { + 1: "Hoohahaha! O que, você tem um parafuso solto ou algo assim? Olhe para você, pequena pessoa Makuhita!", + 2: "Oho! Você! Você é aquela criança engraçada!", + 3: "O que você está fazendo aqui? Você nos seguiu?" + }, + "victory": { + 1: "Muito bem, até que o Chefe tenha tempo para você, serei seu oponente!", + 2: "Posso sentir! Posso sentir, tudo bem! A força saindo de você! Mais! Eu ainda quero mais! Mas parece que estamos sem tempo...", + 3: "Isso foi divertido! Eu sabia que você me mostraria um bom tempo! Estou ansioso para enfrentá-la novamente algum dia!" + }, + }, + "mars": { + "encounter": { + 1: "Sou Mars, uma das principais Comandantes da Equipe Galáctica.", + 2: "A visão da Equipe Galáctica para o futuro é inabalável. A oposição será esmagada sem piedade!", + 3: "Sentindo-se nervosa? Você deveria estar!" + }, + "victory": { + 1: "Isso não pode estar acontecendo! Como eu perdi?!", + 2: "Você tem alguma habilidade, eu admito isso.", + 3: "Derrotada... Este foi um erro caro." + } + }, + "zinzolin": { + "encounter": { + 1: "Você poderia se tornar uma ameaça para a Equipe Plasma, então vamos eliminá-la aqui e agora!", + 2: "Oh, pelo amor de Deus... Eu não esperava ter que lutar neste frio congelante!", + 3: "Você é uma treinadora impressionante para ter chegado tão longe. Mas termina aqui." + }, + "victory": { + 1: "Ghetsis... Eu falhei com você...", + 2: "Está amargamente frio. Estou tremendo. Estou sofrendo. Ainda assim, estou vitorioso.", + 3: "Hmph. Você é uma treinadora mais esperta do que eu esperava, mas não esperta o suficiente." + } + }, + "rood": { + "encounter": { + 1: "Você é uma ameaça para a Equipe Plasma. Não podemos deixá-la ir embora daqui e agora!", + 2: "Oh, este vento gelado... Eu nunca pensei que teria que lutar aqui!", + 3: "Você é uma treinadora notável para ter chegado tão longe. Mas é aqui que termina." + }, + "victory": { + 1: "Ghetsis... Eu falhei em minha missão...", + 2: "O frio é penetrante. Estou tremendo. Estou sofrendo. Ainda assim, triunfei.", + 3: "Hm. Você é uma treinadora talentosa, mas infelizmente não talentosa o suficiente." + } + }, + "xerosic": { + "encounter": { + 1: "Ah ha ha! Será um prazer. Vamos lá, pequena treinadora! Vamos ver o que você tem!", + 2: "Hmm... Você é mais poderosa do que parece. Eu me pergunto quanta energia há dentro de você.", + 3: "Eu estava esperando por você! Preciso fazer uma pequena pesquisa sobre você! Vamos começar!" + }, + "victory": { + 1: "Ah, você é bastante forte. Oh sim—muito forte, de fato.", + 2: "Ding-ding-ding! Você conseguiu! À vencedora, os despojos!", + 3: "Maravilhoso! Incrível! Você tem uma tremenda habilidade e coragem!" + } + }, + "bryony": { + "encounter": { + 1: "Eu sou Bryony, e será um prazer lutar com você. Mostre-me o que você tem.", + 2: "Impressionante... Você é mais poderosa do que parece. Vamos ver a verdadeira extensão de sua energia.", + 3: "Eu antecipei sua chegada. É hora de um pequeno teste. Vamos começar?" + }, + "victory": { + 1: "Você é bastante forte. Oh sim—muito forte, de fato.", + 2: "Ding-ding-ding! Você se saiu bem. A vitória é sua.", + 3: "Maravilhoso! Notável! Sua habilidade e coragem são admiráveis." + } + }, + "rocket_grunt": { + "encounter": { + 1: "Se prepara pra encrenca!", + 2: "Estamos realizando um grande trabalho aqui! Cai fora, garota!", + 3: "Entregue seus Pokémon ou enfrente a ira da Equipe Rocket!", + 4: "Você está prestes a experimentar o verdadeiro terror da Equipe Rocket!", + 5: "Ei, garota! Eu sou um tipo de cara da Equipe Rocket!" // Uso de gramática incorreta é proposital + }, + "victory": { + 1: "Equipe Rocket decolando de novo!", + 2: "Oh não! Eu deixei a Chave de Elevação cair!", + 3: "Eu estraguei tudo!", + 4: "Meus associados não vão tolerar isso!", + 5: "Você diz o que? Equipe Rocket tchau-tchau a vai-vai? Quebrado é diz você?" // Uso de gramática incorreta é proposital + }, + }, + "galactic_grunt": { + "encounter": { + 1: "Não mexa com a Equipe Galáctica!", + 2: "Presencie o poder da nossa tecnologia e o futuro que vislumbramos!", + 3: "Em nome da Equipe Galáctica, eliminarei qualquer um que ficar em nosso caminho!", + 4: "Prepare-se para perder!", + 5: "Espero que você esteja pronta para uma surra cósmica!" + }, + "victory": { + 1: "Fui amassado...", + 2: "Este contratempo não significa nada no grande esquema.", + 3: "Nossos planos são maiores que esta derrota.", + 4: "Como?!", + 5: "Nota para mim mesmo: praticar batalhas Pokémon, o mais rápido possível." + }, + }, + "galactic_boss_cyrus_1": { + "encounter": { + 1: "Você foi compelida a vir aqui por tal sentimentalismo vazio\nEu farei você se arrepender de ter ouvido seu coração!" + }, + "victory": { + 1: "Interessante. E bastante curioso." }, "defeat": { - 1: "A melhor defesa é um bom ataque!\nEssa é a minha maneira de fazer as coisas!", - 2: "Venha estudar rochas comigo da próxima vez para aprender melhor a combatê-las!", - 3: "Hah, todas as minhas viagens pelas regiões estão valendo a pena!" + 1: "Eu criarei meu novo mundo..." } }, "misty": { @@ -3170,77 +3043,6 @@ export const PGFdialogue: DialogueTranslationEntries = { 3: "Uma batalha de Pokémon é guerra, e eu te mostrei combate em primeira mão!" } }, - "erika": { - "encounter": { - 1: "Ah, o tempo está adorável aqui…\nOh, uma batalha? Muito bem então.", - 2: "Minhas habilidades de batalha Pokémon rivalizam com minhas habilidades de arranjo de flores.", - 3: "Oh, espero que o aroma agradável dos meus Pokémon não me faça dormir de novo…", - 4: "Ver flores em um jardim é tão calmante." - }, - "victory": { - 1: "Oh! Eu concedo a derrota.", - 2: "Aquela partida foi muito agradável.", - 3: "Ah, parece que perdi…", - 4: "Oh, meu Deus." - }, - "defeat": { - 1: "Tinha medo de adormecer…", - 2: "Oh, meu Deus, parece que meus Pokémon de Grama te dominaram.", - 3: "Essa batalha foi uma experiência tão calmante.", - 4: "Oh… É só isso?" - } - }, - "janine": { - "encounter": { - 1: "Estou dominando a arte dos ataques venenosos.\nVou lutar com você hoje!", - 2: "Meu pai confia que posso me defender.\nVou provar que ele está certo!", - 3: "Minhas técnicas de ninja só perdem para as do meu pai!\nVocê consegue acompanhar?" - }, - "victory": { - 1: "Ainda preciso de treinamento… Entendi.", - 2: "Sua técnica de batalha superou a minha.", - 3: "Vou me aplicar de verdade e melhorar minhas habilidades." - }, - "defeat": { - 1: "Hehe… o veneno drenou todas as suas forças para lutar.", - 2: "Ha! Você não teve chance contra minhas habilidades superiores de ninja!", - 3: "A fé do meu pai em mim não foi mal colocada." - } - }, - "sabrina": { - "encounter": { - 1: "Através da minha habilidade psíquica, tive uma visão da sua chegada!", - 2: "Não gosto de lutar, mas se você quiser, vou mostrar meus poderes!", - 3: "Posso sentir grande ambição em você. Vou ver se não é infundada." - }, - "victory": { - 1: "Seu poder… Ele supera o que eu previa…", - 2: "Não consegui prever seu poder com precisão.", - 3: "Mesmo com meus imensos poderes psíquicos, não consigo sentir outro tão forte quanto você." - }, - "defeat": { - 1: "Essa vitória… É exatamente como previ nas minhas visões!", - 2: "Talvez fosse outra pessoa que eu sentisse um grande desejo…", - 3: "Aprimore suas habilidades antes de entrar em batalha precipitadamente.\nVocê nunca sabe o que o futuro pode reservar se fizer isso…" - } - }, - "blaine": { - "encounter": { - 1: "Hah! Espero que tenha trazido uma Cura de Queimadura!", - 2: "Meus Pokémon de Fogo vão incinerar todos os desafiantes!", - 3: "Prepare-se para brincar com fogo!" - }, - "victory": { - 1: "Queimei até não restar nada! Nem cinzas sobraram!", - 2: "Não acendi as chamas alto o suficiente?", - 3: "Estou completamente exausto… Mas isso faz minha motivação para melhorar queimar ainda mais!" - }, - "defeat": { - 1: "Meu inferno ardente não pode ser apagado!", - 2: "Meus Pokémon foram fortalecidos com o calor desta vitória!", - 3: "Hah! Minha paixão queima mais do que a sua!" - } - }, "giovanni": { "encounter": { 1: "Eu, o líder da Equipe Rocket, vou te fazer sentir um mundo de dor!", @@ -3258,23 +3060,6 @@ export const PGFdialogue: DialogueTranslationEntries = { 3: "Espero que entenda o quão tolo foi me desafiar." } }, - "roxanne": { - "encounter": { - 1: "Você poderia gentilmente demonstrar como batalha?", - 2: "Você pode aprender muitas coisas batalhando com muitos treinadores.", - 3: "Oh, você me pegou estrategizando.\nGostaria de batalhar?" - }, - "victory": { - 1: "Oh, parece que perdi.\nEu entendo.", - 2: "Parece que ainda tenho muito mais a aprender quando se trata de batalhas.", - 3: "Vou levar o que aprendi aqui hoje a sério." - }, - "defeat": { - 1: "Aprendi muitas coisas com nossa batalha.\nEspero que você também tenha aprendido.", - 2: "Espero batalhar com você novamente.\nEspero que use o que aprendeu aqui.", - 3: "Venci devido a tudo o que aprendi." - } - }, "brawly": { "encounter": { 1: "Oh cara, uma desafiante!\nVamos ver o que você pode fazer!", @@ -3304,45 +3089,11 @@ export const PGFdialogue: DialogueTranslationEntries = { 3: "Obrigado pela emoção!\nWahahahaha!" }, "defeat": { - 1: "Você está totalmente carregado agora!\nWahahahaha!", + 1: "Você está totalmente carregada agora!\nWahahahaha!", 2: "Espero ver você faíscando em batalhas futuras!\nWahahahaha!", 3: "Wahahahaha! Que batalha eletrizante!" } }, - "flannery": { - "encounter": { - 1: "Meus Pokémon de fogo estão prontos para queimar a concorrência!\nVamos nessa!", - 2: "Prepare-se para sentir o calor da minha determinação!\nNão vou segurar nada!", - 3: "Minhas habilidades vão incinerar você!\nPrepare-se para a batalha mais quente da sua vida!" - }, - "victory": { - 1: "Essa derrota só faz minha determinação queimar mais!", - 2: "Essa perda não apagará minhas chamas!\nEstarei de volta mais forte!", - 3: "Vou usar essa experiência para reacender meu espírito competitivo!" - }, - "defeat": { - 1: "Minhas chamas nunca se apagarão!\nSou muito apaixonada por isso!", - 2: "Você foi incrível!\nVamos fazer isso de novo algum dia!", - 3: "Que batalha ardente!\nMal posso esperar pela próxima!" - } - }, - "norman": { - "encounter": { - 1: "Você está pronta para enfrentar a força pura do meu time?\nVou te mostrar o poder do equilíbrio!", - 2: "Minha experiência em batalha vai fazer você suar!\nPrepare-se!", - 3: "Treinei meu time rigorosamente.\nVamos ver se você consegue igualar!" - }, - "victory": { - 1: "Parece que subestimei você.\nFoi uma batalha dura.", - 2: "Você é forte, mas ainda há muito para aprender.", - 3: "Essa derrota não abalará minha determinação.\nEstarei de volta mais forte!" - }, - "defeat": { - 1: "Você lutou bravamente!\nEspero batalhar com você novamente.", - 2: "Sua força é incrível!\nNão posso esperar pela nossa próxima batalha.", - 3: "Foi uma honra batalhar com você!\nAté a próxima!" - } - }, "winona": { "encounter": { 1: "Tenho sobrevoado os céus em busca de presas...\nE você é meu alvo!", @@ -3362,7 +3113,7 @@ export const PGFdialogue: DialogueTranslationEntries = { }, "tate": { "encounter": { - 1: "Hehehe... Ficou surpreso de me ver sem minha irmã?", + 1: "Hehehe... Ficou surpresa de me ver sem minha irmã?", 2: "Posso ver o que você está pensando...\nVocê quer batalhar!", 3: "Como você pode derrotar alguém...\nQue sabe todos os seus movimentos?" }, @@ -3379,7 +3130,7 @@ export const PGFdialogue: DialogueTranslationEntries = { }, "liza": { "encounter": { - 1: "Fufufu... Ficou surpreso de me ver sem meu irmão?", + 1: "Fufufu... Ficou surpresa de me ver sem meu irmão?", 2: "Posso determinar o que você deseja...\nVocê quer batalhar, não quer?", 3: "Como você pode derrotar alguém...\nQue é um com seus Pokémon?" }, @@ -3394,60 +3145,6 @@ export const PGFdialogue: DialogueTranslationEntries = { 3: "Tudo graças ao meu treinamento rigoroso com Tate.\nPosso me sincronizar com meus Pokémon." } }, - "juan": { - "encounter": { - 1: "Agora não é hora de agir timidamente.\nVamos batalhar!", - 2: "Ahahaha, você será testemunha da minha arte com Pokémon de Água!", - 3: "Um tufão se aproxima!\nVocê será capaz de me testar?", - 4: "Por favor, você será testemunha da nossa arte.\nUma grande ilusão de água esculpida por meus Pokémon e por mim!" - }, - "victory": { - 1: "Você pode ser um gênio que pode enfrentar Wallace!", - 2: "Eu me concentrei na elegância enquanto você treinava.\nÉ natural que você me derrotasse.", - 3: "Ahahaha!\nMuito bem, você venceu desta vez.", - 4: "De você, sinto o brilho brilhante da habilidade que superará tudo." - }, - "defeat": { - 1: "Meus Pokémon e eu esculpimos uma ilusão de Água e saímos vitoriosos.", - 2: "Ahahaha, eu venci, e você perdeu.", - 3: "Posso emprestar meu traje? Pode te ajudar a batalhar!\nAhahaha, estou brincando!", - 4: "Eu sou o vencedor! O que quer dizer, você perdeu." - } - }, - "crasher_wake": { - "encounter": { - 1: "Crash! Crash! Cuidado!\nCrasher Wake… está… aqui!", - 2: "Crash! Crash! Crasher Wake!", - 3: "Sou a onda de poder que vai te lavar!" - }, - "victory": { - 1: "Isso coloca um sorriso no meu rosto!\nGuhahaha! Foi uma explosão!", - 2: "Hunwah! Acabou e terminou!\nComo vou dizer isso...\nQuero mais! Queria batalhar muito mais!", - 3: "O QUÊ?!" - }, - "defeat": { - 1: "Siiiiim! Isso mesmo!", - 2: "Eu venci, mas quero mais! Queria batalhar muito mais!", - 3: "Até logo!" - } - }, - "falkner": { - "encounter": { - 1: "Vou mostrar o verdadeiro poder dos magníficos Pokémon pássaros!", - 2: "Ventos, fiquem comigo!", - 3: "Pai! Espero que esteja vendo minha batalha de cima!" - }, - "victory": { - 1: "Eu entendo... Vou sair graciosamente.", - 2: "Uma derrota é uma derrota. Você é realmente forte.", - 3: "...Droga! Sim, eu perdi." - }, - "defeat": { - 1: "Pai! Venci com seus amados Pokémon pássaros...", - 2: "Pokémon pássaros são os melhores afinal!", - 3: "Sinto que estou alcançando meu pai!" - } - }, "nessa": { "encounter": { 1: "Não importa que tipo de plano sua mente refinada possa estar tramando, meu parceiro e eu vamos afundá-la.", @@ -3485,11 +3182,11 @@ export const PGFdialogue: DialogueTranslationEntries = { "marlon": { "encounter": { 1: "Você parece forte! Vamos começar!", - 2: "Sou forte como a amplitude do oceano. Você vai ser varrido, com certeza.", + 2: "Sou forte como a amplitude do oceano. Você vai ser varrida, com certeza.", 3: "Oh ho, então estou enfrentando você! Isso é fora do comum." }, "victory": { - 1: "Você foi incrível! Está criando alguns Pokémon incríveis. Você dominou a coisa de Treinador!", + 1: "Você foi incrível! Está criando alguns Pokémon incríveis. Você dominou a coisa de Treinadora!", 2: "Você não apenas parece forte, você é forte de verdade! Eh, eu também fui varrido!", 3: "Você é forte como uma onda impressionante!" }, @@ -3518,7 +3215,7 @@ export const PGFdialogue: DialogueTranslationEntries = { }, "marshal": { "encounter": { - 1: "Meu mentor, Alder, vê seu potencial como Treinadora e está interessado em você.\nMeu objetivo é testá-lo—levar você aos limites da sua força. Kiai!", + 1: "Meu mentor, Alder, vê seu potencial como Treinadora e está interessado em você.\nMeu objetivo é testá-la—levar você aos limites da sua força. Kiai!", 2: "Vitória, vitória decisiva, é meu objetivo! Desafiante, aqui vou eu!", 3: "Em mim mesmo, procuro desenvolver a força de um lutador e eliminar qualquer fraqueza em mim!\nPrevalecendo com a força de minhas convicções!" }, @@ -3550,40 +3247,6 @@ export const PGFdialogue: DialogueTranslationEntries = { 3: "Cheguei onde estou porque os Pokémon estavam ao meu lado.\nTalvez precisemos pensar por que os Pokémon nos ajudam, não em termos de Pokémon e Treinadores, mas como uma relação entre seres vivos." } }, - "chili": { - "encounter": { - 1: "Ihuuu! Hora de brincar com FOGO!! Sou o mais forte dos nossos irmãos!", - 2: "Ta-da! O incendiário do tipo Fogo Chili—sou eu—será seu oponente!", - 3: "Vou mostrar o que eu e meus tipos de Fogo podemos fazer!" - }, - "victory": { - 1: "Você me pegou. Estou... queimado...", - 2: "Uau! Você está pegando fogo!", - 3: "Ai! Você me pegou!" - }, - "defeat": { - 1: "Estou pegando fogo! Jogue comigo, e você se queimará!", - 2: "Quando você brinca com fogo, você se queima!", - 3: "Quero dizer, vamos lá, seu oponente era eu! Você não tinha chance!" - } - }, - "cilan": { - "encounter": { - 1: "Nada pessoal... Sem ressentimentos... Eu e meus Pokémon do tipo Grama vamos...\nUm... Vamos batalhar, aconteça o que acontecer.", - 2: "Então, hum, se você está bem comigo, vou, hum, colocar tudo o que tenho em ser, er, você sabe, seu oponente.", - 3: "OK… Então, hum, eu sou o Cilan, gosto de Pokémon do tipo Grama." - }, - "victory": { - 1: "Er... Acabou agora?", - 2: "…Que surpresa. Você é muito forte, não é?\nAcho que meus irmãos também não teriam sido capazes de te derrotar...", - 3: "…Huh. Parece que meu timing estava, hum, errado?" - }, - "defeat": { - 1: "Huh? Ganhei?", - 2: "Acho...\nSuponho que ganhei, porque competi com meus irmãos Chili e Cress, e todos conseguimos ficar mais fortes.", - 3: "Foi... uma experiência bastante emocionante..." - } - }, "roark": { "encounter": { 1: "Preciso ver seu potencial como Treinadora. E, vou precisar ver a dureza dos Pokémon que batalham com você!", @@ -3615,7 +3278,7 @@ export const PGFdialogue: DialogueTranslationEntries = { }, "victory": { 1: "Ainda não sou bom o suficiente...", - 2: "Eu vejo... Sua jornada o levou a lugares distantes e você testemunhou muito mais do que eu.\nEu invejo você por isso...", + 2: "Eu vejo... Sua jornada a levou a lugares distantes e você testemunhou muito mais do que eu.\nEu invejo você por isso...", 3: "Como isso é possível...", 4: "Não acho que nossos potenciais sejam tão diferentes.\nMas você parece ter algo mais do que isso... Que seja.", 5: "Acho que preciso de mais treinamento.", @@ -3630,42 +3293,6 @@ export const PGFdialogue: DialogueTranslationEntries = { 6: "Eu sabia que venceria!" } }, - "crispin": { - "encounter": { - 1: "Quero vencer, então é exatamente isso que vou fazer!", - 2: "Eu batalho porque quero batalhar! E sabe de uma coisa? É assim que deve ser!" - }, - "victory": { - 1: "Queria vencer... mas perdi!", - 2: "Eu perdi... porque não consegui vencer!" - }, - "defeat": { - 1: "Ei, espere um segundo. Eu acabei de vencer? Acho que acabei de vencer! Que satisfação!", - 2: "Uou! Isso foi incrível!" - } - }, - "amarys": { - "encounter": { - 1: "Quero ser a pessoa a ajudar alguém em particular. Sendo assim, não posso me dar ao luxo de perder.\n... Nossa batalha começa agora." - }, - "victory": { - 1: "Eu sou... não o suficiente, eu vejo." - }, - "defeat": { - 1: "A vitória pertence a mim. Bem lutado." - } - }, - "lacey": { - "encounter": { - 1: "Vou enfrentar você com meu time usual como membro da Elite dos Quatro." - }, - "victory": { - 1: "Foi uma excelente batalha. Estou ansiosa para o próximo desafio." - }, - "defeat": { - 1: "Fufufu... Nada mal.\nDesafiantes que derrotam a Elite dos Quatro são dignos de notar." - } - }, "drayton": { "encounter": { 1: `Cara, eu amo cadeiras. Você não ama cadeiras? Que salva-vidas. @@ -3675,7 +3302,7 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Acho que deveria ter esperado por isso!" }, "defeat": { - 1: "Heh heh! Não ligue para mim, só pegando uma vitória aqui. Entendo se você estiver chateado, mas não vá dar uma de Kieran comigo, OK?" + 1: "Heh heh! Não ligue para mim, só pegando uma vitória aqui. Entendo se você estiver chateada, mas não vá dar uma de Kieran comigo, OK?" } }, "ramos": { @@ -3690,23 +3317,6 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Hohoho... De fato. Pequenas lâminas frágeis de grama conseguem quebrar até mesmo concreto." } }, - "viola": { - "encounter": { - 1: `Seja as lágrimas de frustração que seguem uma derrota ou o florescer da alegria que vem com a vitória… - $Ambos são ótimos temas para minha câmera! Fantástico! Isso vai ser simplesmente fantástico! - $Agora venha para cima de mim!`, - 2: "Minha lente está sempre focada na vitória – não vou deixar nada estragar esta foto!" - }, - "victory": { - 1: "Você e seus Pokémon me mostraram uma nova profundidade de campo! Fantástico! Simplesmente fantástico!", - 2: `O mundo que você vê através de uma lente, e o mundo que você vê com um Pokémon ao seu lado… - $O mesmo mundo pode parecer completamente diferente dependendo do seu ponto de vista.` - }, - "defeat": { - 1: "A foto do momento da minha vitória vai ser um verdadeiro sucesso!", - 2: "Sim! Tirei ótimas fotos!" - } - }, "candice": { "encounter": { 1: `Você quer desafiar a Candice? Com certeza! Eu estava esperando por alguém forte! @@ -3735,40 +3345,6 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Sim! Meus Pokémon e eu somos perfeitamente bons!" } }, - "aaron": { - "encounter": { - 1: "Ok! Deixe-me enfrentar você!" - }, - "victory": { - 1: "Batalhar é um assunto profundo e complexo..." - }, - "defeat": { - 1: "Vencer um membro da Elite dos Quatro não é fácil." - } - }, - "cress": { - "encounter": { - 1: "Isso mesmo! Serei eu e meus estimados tipos Água que você deve enfrentar na batalha!" - }, - "victory": { - 1: "Perder? Eu? Não acredito nisso." - }, - "defeat": { - 1: "Este é o resultado apropriado quando eu sou seu oponente." - } - }, - "allister": { - "encounter": { - 1: "'M Allister.\nA-aqui... vou eu..." - }, - "victory": { - 1: `Quase perdi minha máscara de tanto choque... Isso foi… - $Uau. Posso ver sua habilidade pelo que ela é.`, - }, - "defeat": { - 1: "I-isso foi incrível!" - } - }, "clay": { "encounter": { 1: "Harrumph! Me deixou esperando, não foi, garota? Tudo bem, hora de ver o que você pode fazer!" @@ -3786,75 +3362,12 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Vou te servir um prato completo de Pokémon do tipo Água! Mas não tente comê-los!" }, "victory": { - 1: "Vaultin' Veluza! Você é animada, não é! Um pouco ANIMADO DEMAIS, se me permite dizer!" + 1: "Vaultin' Veluza! Você é animada, não é! Um pouco ANIMADA DEMAIS, se me permite dizer!" }, "defeat": { 1: "Volte para me ver novamente, ouviu?" } }, - "tulip": { - "encounter": { - 1: "Permita-me usar minhas habilidades para deixar seus lindos Pokémon ainda mais bonitos!" - }, - "victory": { - 1: "Sua força tem uma magia que não pode ser apagada." - }, - "defeat": { - 1: "Você sabe, na minha linha de trabalho, pessoas que carecem de talento em uma área ou outra frequentemente desaparecem rapidamente - nunca mais se ouve falar delas." - } - }, - "sidney": { - "encounter": { - 1: `Gostei desse olhar que você me deu. Acho que você vai ser um bom desafio. - $Isso é ótimo! Parece muito bom! Vamos nessa! - $Você e eu, vamos curtir uma batalha que só pode acontecer aqui!`, - }, - "victory": { - 1: "E aí, gostou? Eu perdi! Mas foi divertido, então não importa." - }, - "defeat": { - 1: "Sem ressentimentos, beleza?" - } - }, - "phoebe": { - "encounter": { - 1: `Enquanto treinava, adquiri a habilidade de me comunicar com Pokémon do tipo Fantasma. - $Sim, o vínculo que desenvolvi com os Pokémon é extremamente forte. - $Então, vamos lá, tente ver se você consegue até mesmo causar dano aos meus Pokémon!`, - }, - "victory": { - 1: "Ah, droga. Eu perdi." - }, - "defeat": { - 1: "Estou ansiosa para batalhar com você de novo algum dia!" - } - }, - "glacia": { - "encounter": { - 1: `Tudo o que vi foram desafios de Treinadores fracos e seus Pokémon. - $E você? Ficaria extremamente satisfeita se pudesse dar tudo de mim contra você!`, - }, - "victory": { - 1: `Você e seus Pokémon… Como seus espíritos queimam! - $O calor consumido é esmagador. - $Não é surpresa que minhas habilidades geladas falharam em te machucar.`, - }, - "defeat": { - 1: "Uma batalha intensamente apaixonada, sem dúvida." - } - }, - "drake": { - "encounter": { - 1: `Para nós, batalhar com Pokémon como parceiros, você sabe o que é necessário? Você sabe o que precisa? - $Se não souber, nunca prevalecerá contra mim!`, - }, - "victory": { - 1: "Excelente, deve-se dizer." - }, - "defeat": { - 1: "Dei meu máximo nessa batalha!" - } - }, "wallace": { "encounter": { 1: `Há algo em você… Uma diferença na sua postura. @@ -3863,7 +3376,7 @@ export const PGFdialogue: DialogueTranslationEntries = { }, "victory": { 1: `Bravo. Agora percebo sua autenticidade e magnificência como Treinadora de Pokémon. - $Tenho muita alegria em ter conhecido você e seus Pokémon. Você se mostrou digno.`, + $Tenho muita alegria em ter conhecido você e seus Pokémon. Você se mostrou digna.`, }, "defeat": { 1: "Uma grande ilusão!" @@ -3878,7 +3391,7 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Como ousa!" }, "defeat": { - 1: "Não há nada que você possa fazer quando está congelado." + 1: "Não há nada que você possa fazer quando está congelada." } }, "will": { @@ -3890,7 +3403,7 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Eu… Eu não… acredito…" }, "defeat": { - 1: "Isso foi por pouco. Me pergunto o que você está faltando." + 1: "Isso foi por pouco. Me pergunto o que está faltando em você." } }, "malva": { @@ -3905,17 +3418,6 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Estou encantada! Sim, encantada por poder esmagar você sob meu calcanhar." } }, - "hala": { - "encounter": { - 1: "O velho Hala está aqui para fazer você gritar!" - }, - "victory": { - 1: "Pude sentir o poder que você ganhou na sua jornada." - }, - "defeat": { - 1: "Haha! Que batalha deliciosa!" - } - }, "molayne": { "encounter": { 1: `Dei a posição de capitão ao meu primo Sophocles, mas estou confiante na minha habilidade. @@ -3939,17 +3441,6 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Nahahaha! Você realmente é algo mais, garota!" } }, - "bruno": { - "encounter": { - 1: "Nós vamos te triturar com nosso poder superior! Hoo hah!" - }, - "victory": { - 1: "Por quê? Como eu poderia perder?" - }, - "defeat": { - 1: "Você pode me desafiar o quanto quiser, mas os resultados nunca vão mudar!" - } - }, "bugsy": { "encounter": { 1: "Sou Bugsy! Eu nunca perco quando se trata de Pokémon do tipo Inseto!" @@ -3961,33 +3452,9 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Obrigado! Graças à nossa batalha, eu também pude fazer progressos na minha pesquisa!" } }, - "koga": { - "encounter": { - 1: "Fwahahahaha! Pokémon não são apenas sobre força bruta--você verá em breve!" - }, - "victory": { - 1: "Ah! Você provou seu valor!" - }, - "defeat": { - 1: "Você aprendeu a temer as técnicas do ninja?" - } - }, - "bertha": { - "encounter": { - 1: "Bem, você mostraria a esta velha senhora o quanto aprendeu?" - }, - "victory": { - 1: `Bem! Querida criança, devo dizer, isso foi muito impressionante. - $Seus Pokémon acreditaram em você e fizeram o melhor para te dar a vitória. - $Mesmo tendo perdido, me encontro com esse sorriso bobo!`, - }, - "defeat": { - 1: "Hahahahah! Parece que esta velha senhora ganhou!" - } - }, "lenora": { "encounter": { - 1: "Bem, desafiador, vou pesquisar como você batalha com os Pokémon que criou com tanto carinho!" + 1: "Bem, desafiadora, vou pesquisar como você batalha com os Pokémon que criou com tanto carinho!" }, "victory": { 1: "Minha teoria sobre você estava correta. Você é mais do que talentosa… Você é motivada! Eu te saúdo!" @@ -3996,18 +3463,6 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Ah ha ha! Se você perder, certifique-se de analisar o porquê e use esse conhecimento na próxima batalha!" } }, - "siebold": { - "encounter": { - 1: "Enquanto eu estiver vivo, continuarei em busca da culinária suprema... e dos oponentes mais fortes em batalha!" - }, - "victory": { - 1: "Guardarei minha memória de você e seus Pokémon para sempre em meu coração." - }, - "defeat": { - 1: `Nossa batalha Pokémon foi como alimento para minha alma. Isso vai me manter em frente. - $É assim que vou prestar meus respeitos a você por dar tudo de si na batalha!`, - } - }, "roxie": { "encounter": { 1: "Prepare-se! Vou arrancar algum senso de você!" @@ -4019,40 +3474,6 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Ei, vamos lá! Seja séria! Você tem que dar mais de si!" } }, - "olivia": { - "encounter": { - 1: "Não precisa de introdução aqui. Hora de batalhar comigo, Olivia!" - }, - "victory": { - 1: "Realmente encantador… Tanto você quanto seus Pokémon…" - }, - "defeat": { - 1: "Mmm-hmm." - } - }, - "poppy": { - "encounter": { - 1: "Oooh! Você quer ter uma batalha Pokémon comigo?" - }, - "victory": { - 1: "Uagh?! Mmmuuuggghhh…" - }, - "defeat": { - 1: `Yaaay! Eu consegui! Eu der-ro-tei você! Você pode vir para… Para… Uma revanche? - $Venha para uma revanche quando quiser!`, - } - }, - "agatha": { - "encounter": { - 1: "Pokémon são para batalhas! Vou te mostrar como um verdadeiro Treinador batalha!" - }, - "victory": { - 1: "Oh meu! Você é algo especial, criança!" - }, - "defeat": { - 1: "Bahaha. É assim que uma batalha adequada é feita!" - } - }, "flint": { "encounter": { 1: "Espero que você esteja aquecida, porque aqui vem o Big Bang!" @@ -4064,17 +3485,6 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Huh? Isso é tudo? Acho que você precisa de um pouco mais de paixão." } }, - "grimsley": { - "encounter": { - 1: "O vencedor leva tudo, e não sobra nada para o perdedor." - }, - "victory": { - 1: "Quando se perde, perde-se tudo… A próxima coisa que vou procurar será a vitória, também!" - }, - "defeat": { - 1: "Se alguém vence, a pessoa que lutou contra essa pessoa perde." - } - }, "caitlin": { "encounter": { 1: `Sou eu que apareci quando a flor se abriu. Você que estava esperando… @@ -4089,29 +3499,17 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Aspiro a reivindicar a vitória com elegância e graça." } }, - "diantha": { - "encounter": { - 1: `Batalhar contra você e seus Pokémon, todos vocês cheios de esperança para o futuro… - $Honestamente, isso apenas me enche da energia que preciso para continuar enfrentando cada novo dia! Sim!`, - }, - "victory": { - 1: "Testemunhar os espíritos nobres de você e seus Pokémon em batalha realmente tocou meu coração…" - }, - "defeat": { - 1: "Oh, fantástico! O que achou? Minha equipe foi bem legal, né?" - } - }, "wikstrom": { "encounter": { - 1: `Bem encontrado, jovem desafiador! Verdadeiramente sou a lâmina famosa de aço endurecido, Duque Wikstrom! + 1: `Bem encontrado, jovem desafiadora! Verdadeiramente sou a lâmina famosa de aço endurecido, Duque Wikstrom! $Que a batalha comece! En garde!`, }, "victory": { - 1: "Glorioso! A confiança que você compartilha com seu honrado Pokémon supera até mesmo a minha!" + 1: "Gloriosa! A confiança que você compartilha com seu honrado Pokémon supera até mesmo a minha!" }, "defeat": { 1: `Que tipo de magia é essa? Meu coração bate incessantemente no meu peito! - $Vencer contra um oponente tão digno dá asas à minha alma--assim eu voo!`, + $Vencer contra uma oponente tão digna dá asas à minha alma--assim eu voo!`, } }, "acerola": { @@ -4125,18 +3523,6 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Ehaha! Que vitória incrível!" } }, - "larry_elite": { - "encounter": { - 1: `Olá… Sou eu, Larry. - $Eu também sou membro da Elite dos Quatro, sim… Infelizmente para mim.`, - }, - "victory": { - 1: "Bem, isso tirou o vento debaixo das nossas asas…" - }, - "defeat": { - 1: "É hora de uma reunião com o chefe." - } - }, "lance": { "encounter": { 1: "Estive esperando por você. Permita-me testar suas habilidades.", @@ -4144,28 +3530,11 @@ export const PGFdialogue: DialogueTranslationEntries = { }, "victory": { 1: "Você me pegou. Você é magnífica!", - 2: "Nunca esperei que outro Treinador me derrotasse… Estou surpreso." + 2: "Nunca esperei que outra Treinadora me derrotasse… Estou surpreso." }, "defeat": { 1: "Isso foi por pouco. Quer tentar de novo?", - 2: "Não é que você seja fraco. Não se incomode com isso." - } - }, - "karen": { - "encounter": { - 1: "Eu sou Karen. Você gostaria de um duelo com meus Pokémon do tipo Sombrio?", - 2: "Sou diferente daqueles que você já conheceu.", - 3: "Você montou uma equipe charmosa. Nossa batalha deve ser boa." - }, - "victory": { - 1: "Não! Eu não posso vencer. Como você ficou tão forte?", - 2: "Não me desviarei do meu caminho escolhido.", - 3: "O Campeão está ansioso para te conhecer." - }, - "defeat": { - 1: "Isso era o que eu esperava.", - 2: "Bem, isso foi relativamente divertido.", - 3: "Venha me visitar a qualquer momento." + 2: "Não é que você seja fraca. Não se incomode com isso." } }, "milo": { @@ -4175,26 +3544,12 @@ export const PGFdialogue: DialogueTranslationEntries = { $Vou ter que usar a Dynamax no meu Pokémon se eu quiser vencer!`, }, "victory": { - 1: "O poder da Grama murchou… Que desafiador incrível!" + 1: "O poder da Grama murchou… Que desafiadora incrível!" }, "defeat": { 1: "Isso realmente vai te deixar em choque e admiração." } }, - "lucian": { - "encounter": { - 1: `Só um momento, por favor. O livro que estou lendo está quase no clímax emocionante… - $O herói obteve uma espada mística e está prestes a enfrentar sua prova final… Ah, tanto faz. - $Já que você chegou tão longe, vou deixar isso de lado e batalhar com você. - $Deixe-me ver se você alcançará tanta glória quanto o herói do meu livro!`, - }, - "victory": { - 1: "Eu vejo… Parece que você me colocou em xeque-mate." - }, - "defeat": { - 1: "Tenho uma reputação a manter." - } - }, "drasna": { "encounter": { 1: `Você deve ser uma Treinadora forte. Sim, bastante forte… @@ -4207,29 +3562,6 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Como isso é possível?" } }, - "kahili": { - "encounter": { - 1: "Então, aqui está você… Por que não vemos para quem os ventos favorecem hoje, você… ou eu?" - }, - "victory": { - 1: "É frustrante para mim como membro da Elite dos Quatro, mas parece que sua força é real." - }, - "defeat": { - 1: "Essa foi uma jogada de mestre!" - } - }, - "hassel": { - "encounter": { - 1: "Prepare-se para aprender em primeira mão como é a respiração ardente de uma batalha feroz!" - }, - "victory": { - 1: `A sorte sorriu para mim desta vez, mas… - $Julgando pelo andamento da luta, quem sabe se serei tão sortudo na próxima vez.`, - }, - "defeat": { - 1: "Essa foi uma jogada de mestre!" - } - }, "blue": { "encounter": { 1: "Você deve ser muito boa para chegar tão longe." @@ -4241,39 +3573,6 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Viu? Meu poder é o que me trouxe até aqui." } }, - "piers": { - "encounter": { - 1: "Prepare-se para uma mosh pit comigo e minha galera! Spikemuth, é hora de roquear!" - }, - "victory": { - 1: "Eu e minha equipe demos o nosso melhor. Vamos nos encontrar novamente para uma batalha algum dia…" - }, - "defeat": { - 1: "Minha garganta está desgastada de tanto gritar… Mas essa foi uma batalha empolgante!" - } - }, - "red": { - "encounter": { - 1: "…!" - }, - "victory": { - 1: "…?" - }, - "defeat": { - 1: "…!" - } - }, - "jasmine": { - "encounter": { - 1: "Oh… Seus Pokémon são impressionantes. Acho que vou gostar disso." - }, - "victory": { - 1: "Você é realmente forte. Vou ter que me esforçar muito mais também." - }, - "defeat": { - 1: "Eu nunca esperei ganhar." - } - }, "lance_champion": { "encounter": { 1: "Ainda sou o Campeão. Não vou segurar nada." @@ -4285,96 +3584,6 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Defendi com sucesso meu Campeonato." } }, - "steven": { - "encounter": { - 1: `Diga-me… O que você viu na sua jornada com seus Pokémon? - $O que você sentiu, encontrando tantos outros Treinadores por aí? - $Viajar por esta terra rica… Isso despertou algo dentro de você? - $Quero que você venha até mim com tudo o que aprendeu. - $Meus Pokémon e eu responderemos com tudo o que sabemos!`, - }, - "victory": { - 1: "Então eu, o Campeão, caio em derrota…" - }, - "defeat": { - 1: "Esse tempo foi bem gasto! Obrigado!" - } - }, - "cynthia": { - "encounter": { - 1: "Eu, Cynthia, aceito seu desafio! Não haverá nenhuma trégua da minha parte!" - }, - "victory": { - 1: "Não importa o quão divertida a batalha seja, ela sempre terminará algum dia…" - }, - "defeat": { - 1: "Mesmo que você perca, nunca perca o amor pelos Pokémon." - } - }, - "iris": { - "encounter": { - 1: `Sabe de uma coisa? Estou realmente ansiosa para ter batalhas sérias com Treinadores fortes! - $Quero dizer, vamos lá! Os Treinadores que chegam aqui são Treinadores que desejam a vitória com todas as fibras do seu ser! - #E eles estão batalhando ao lado de Pokémon que passaram por inúmeras batalhas difíceis! - $Se eu batalhar com pessoas assim, não só eu ficarei mais forte, meus Pokémon também! - $E nós vamos nos conhecer ainda melhor! OK! Prepare-se! - $Sou Iris, a Campeã da Liga Pokémon, e vou te derrotar!`, - }, - "victory": { - 1: "Aghhhh… Eu dei o meu melhor, mas nós perdemos…" - }, - "defeat": { - 1: "Yay! Nós vencemos!" - } - }, - "hau": { - "encounter": { - 1: `Eu me pergunto se um Treinador batalha de maneira diferente dependendo se ele é de uma região quente ou fria. - $Vamos testar isso!`, - }, - "victory": { - 1: "Isso foi incrível! Acho que entendi um pouco melhor seu estilo agora!" - }, - "defeat": { - 1: "Cara, essa foi uma batalha e tanto!" - } - }, - "geeta": { - "encounter": { - 1: `Decidi entrar na batalha mais uma vez. - $Venha agora… Mostre-me os frutos do seu treinamento.`, - }, - "victory": { - 1: "Estou ansiosa para notícias de todas as suas conquistas!" - }, - "defeat": { - 1: "Qual o problema? Isso é tudo?" - } - }, - "nemona": { - "encounter": { - 1: "Yesss! Estou tão empolgada! Hora de soltar tudo!" - }, - "victory": { - 1: "Bem, isso foi ruim, mas ainda me diverti! Eu te pego na próxima!" - }, - "defeat": { - 1: "Bem, essa foi uma ótima batalha! Frutífera, com certeza." - } - }, - "leon": { - "encounter": { - 1: "Vamos ter um tempo absolutamente campeão!" - }, - "victory": { - 1: `Meu tempo como Campeão acabou… - $Mas que tempo campeão foi! - $Obrigado pela melhor batalha que já tive!`, - }, - "defeat": { - 1: "Um tempo absolutamente campeão, foi!" - } - }, "whitney": { "encounter": { 1: "Eai! Você não acha que os Pokémon são, tipo, super fofos?" @@ -4408,28 +3617,6 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Coma, meu adorável Vivillon!" } }, - "pryce": { - "encounter": { - 1: "A juventude sozinha não garante a vitória! Experiência é o que conta." - }, - "victory": { - 1: "Excelente! Isso foi perfeito. Tente não esquecer o que sente agora." - }, - "defeat": { - 1: "Exatamente como eu imaginei." - } - }, - "clair": { - "encounter": { - 1: "Você sabe quem eu sou? E ainda se atreve a me desafiar?" - }, - "victory": { - 1: "Eu me pergunto até onde você pode ir com seu nível de habilidade. Isso deve ser fascinante." - }, - "defeat": { - 1: "E é isso." - } - }, "maylene": { "encounter": { 1: `Vim desafiá-la agora e não vou segurar nada. @@ -4442,18 +3629,6 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Isso foi incrível." } }, - "fantina": { - "encounter": { - 1: `Você vai me desafiar, não é? Mas eu vou ganhar. - $É o que a Líder do Ginásio de Hearthome faz, não?`, - }, - "victory": { - 1: "Você é tão incrivelmente forte. Sei porque perdi." - }, - "defeat": { - 1: "Estou tão, tão, muito feliz!" - } - }, "byron": { "encounter": { 1: `Treinadora! Você é jovem, assim como meu filho, Roark. @@ -4467,17 +3642,6 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Gwahahaha! Como foram meus Pokémon robustos?!" } }, - "olympia": { - "encounter": { - 1: "Um costume antigo decidindo o destino de alguém. A batalha começa!" - }, - "victory": { - 1: "Crie seu próprio caminho. Não deixe nada te atrapalhar. Seu destino, seu futuro." - }, - "defeat": { - 1: "Nosso caminho está claro agora." - } - }, "volkner": { "encounter": { 1: `Já que você chegou tão longe, deve ser bastante forte… @@ -4493,113 +3657,11 @@ export const PGFdialogue: DialogueTranslationEntries = { $Isso não é o que eu queria!`, } }, - "burgh": { - "encounter": { - 1: `M'hm… Se eu ganhar esta batalha, sinto que posso desenhar um quadro diferente de qualquer outro. - $OK! Posso ouvir minha musa da batalha claramente. Vamos direto ao ponto!`, - 2: `Claro, estou realmente orgulhoso de todos os meus Pokémon! - $Bem agora… Vamos direto ao ponto!` - }, - "victory": { - 1: "Acabou? Minha musa me abandonou?", - 2: "Hmm… Acabou! Você é incrível!" - }, - "defeat": { - 1: "Uau… É bonito de alguma forma, não é…", - 2: `Às vezes ouço as pessoas dizerem que foi uma vitória feia. - $Acho que se você está dando o seu melhor, qualquer vitória é bonita.` - } - }, - "elesa": { - "encounter": { - 1: `C'est fini! Quando tenho certeza disso, sinto um choque elétrico percorrer meu corpo! - $Quero sentir essa sensação, então agora meus amados Pokémon vão fazer sua cabeça girar!`, - }, - "victory": { - 1: "Eu queria fazer sua cabeça girar, mas você me surpreendeu." - }, - "defeat": { - 1: "Isso foi insatisfatório de alguma forma… Você dará tudo de si na próxima vez?" - } - }, - "skyla": { - "encounter": { - 1: `Finalmente é hora do confronto! Isso significa a batalha Pokémon que decide quem está no topo, certo? - $Eu amo estar no topo! Porque você pode ver para sempre e sempre de lugares altos! - $Então, que tal nós nos divertirmos?`, - }, - "victory": { - 1: "Ser seu oponente na batalha é uma nova fonte de força para mim. Obrigada!" - }, - "defeat": { - 1: "Ganhar ou perder, você sempre ganha algo com uma batalha, certo?" - } - }, - "brycen": { - "encounter": { - 1: `Há também força em estar com outras pessoas e Pokémon. - $Receber o apoio deles te fortalece. Vou te mostrar esse poder!`, - }, - "victory": { - 1: "A maravilhosa combinação de você e seus Pokémon! Que amizade linda!" - }, - "defeat": { - 1: "Condições extremas realmente testam e treinam você!" - } - }, - "drayden": { - "encounter": { - 1: `O que eu quero encontrar é um jovem Treinador que possa me mostrar um futuro brilhante. - $Vamos batalhar com tudo o que temos: sua habilidade, minha experiência e o amor com que criamos nossos Pokémon!`, - }, - "victory": { - 1: "Esse sentimento intenso que me invade após uma derrota… Não sei como descrevê-lo." - }, - "defeat": { - 1: "Harrumph! Sei que sua habilidade é maior que isso!" - } - }, - "grant": { - "encounter": { - 1: `Só há uma coisa que desejo. - $Que, superando um ao outro, encontremos um caminho para alturas ainda maiores.`, - }, - "victory": { - 1: "Você é uma parede que não consigo superar!" - }, - "defeat": { - 1: `Não desista. - $Isso é tudo o que realmente importa. - $As lições mais importantes da vida são simples.`, - } - }, - "korrina": { - "encounter": { - 1: "Hora da grande aparição de Lady Korrina!" - }, - "victory": { - 1: "É o seu próprio ser que permite que seus Pokémon evoluam!" - }, - "defeat": { - 1: "Que batalha explosiva!" - } - }, - "clemont": { - "encounter": { - 1: "Oh! Estou feliz por termos nos encontrado!" - }, - "victory": { - 1: "Sua paixão pela batalha me inspira!" - }, - "defeat": { - 1: "Parece que minha Máquina Treinadora-Crescer-Forte, Mach 2 está realmente funcionando!" - } - }, "valerie": { "encounter": { - 1: `Oh, se não é uma jovem Treinadora… É adorável conhecê-lo assim. + 1: `Oh, se não é uma jovem Treinadora… É adorável conhecê-la assim. $Então, suponho que você ganhou o direito a uma batalha, como recompensa por seus esforços. - $O elusivo Fada pode parecer frágil como a brisa e delicado como uma flor, mas é forte.`, + $Uma elusiva Fada pode parecer frágil como a brisa e delicado como uma flor, mas é forte.`, }, "victory": { 1: "Espero que você encontre coisas para sorrir amanhã…" @@ -4668,42 +3730,6 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Bom trabalho, eu suponho." } }, - "gordie": { - "encounter": { - 1: "Então, vamos acabar com isso." - }, - "victory": { - 1: "Eu só quero me enterrar em um buraco… Bem, acho que seria mais como cair daqui." - }, - "defeat": { - 1: "Batalhe como sempre faz, a vitória seguirá!" - } - }, - "marnie": { - "encounter": { - 1: `A verdade é que, quando tudo está dito e feito… Eu realmente só quero me tornar Campeã por mim mesma! - $Então, não leve para o pessoal quando eu chutar seu traseiro!`, - }, - "victory": { - 1: "OK, então eu perdi… Mas consegui ver muitos dos pontos bons de você e seus Pokémon!" - }, - "defeat": { - 1: "Espero que você tenha gostado das nossas táticas de batalha." - } - }, - "raihan": { - "encounter": { - 1: "Vou derrotar o Campeão, vencer todo o torneio e provar ao mundo o quão forte o grande Raihan realmente é!" - }, - "victory": { - 1: `Eu pareço bem mesmo quando perco. - $É uma verdadeira maldição. - $Acho que é hora de mais uma selfie!`, - }, - "defeat": { - 1: "Vamos tirar uma selfie para lembrar disso." - } - }, "brassius": { "encounter": { 1: "Pressuponho que você está pronta? Que nossa obra de arte colaborativa comece!" @@ -4729,17 +3755,6 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Seus olhos são MEUS!" } }, - "larry": { - "encounter": { - 1: "Quando tudo está dito e feito, a simplicidade é mais forte." - }, - "victory": { - 1: "Uma porção de derrota, hein?" - }, - "defeat": { - 1: "Vou encerrar o dia." - } - }, "ryme": { "encounter": { 1: "Vamos lá, baby! Me agite até os ossos!" @@ -4751,31 +3766,6 @@ export const PGFdialogue: DialogueTranslationEntries = { 1: "Até mais, baby!" } }, - "grusha": { - "encounter": { - 1: "Tudo o que preciso fazer é garantir que o poder do meu Pokémon te arrependa até os ossos!" - }, - "victory": { - 1: "Sua paixão ardente... Eu meio que gosto, para ser honesto." - }, - "defeat": { - 1: "As coisas não esquentaram para você." - } - }, - "marnie_elite": { - "encounter": { - 1: "Você chegou até aqui, hein? Vamos ver se você pode lidar com meus Pokémon!", - 2: "Vou dar o meu melhor, mas não pense que vou pegar leve com você!" - }, - "victory": { - 1: "Não acredito que perdi... Mas você mereceu essa vitória. Bem feito!", - 2: "Parece que ainda tenho muito a aprender. Grande batalha, porém!" - }, - "defeat": { - 1: "Você lutou bem, mas eu tenho a vantagem! Melhor sorte na próxima vez!", - 2: "Parece que meu treinamento valeu a pena. Obrigado pela batalha!" - } - }, "nessa_elite": { "encounter": { 1: "As marés estão mudando a meu favor. Pronta para ser levada pela corrente?", @@ -4790,20 +3780,6 @@ export const PGFdialogue: DialogueTranslationEntries = { 2: "Você lutou bem, mas o poder do oceano é imparável!" } }, - "bea_elite": { - "encounter": { - 1: "Prepare-se! Meu espírito de luta brilha intensamente!", - 2: "Vamos ver se você consegue acompanhar meu ritmo implacável!" - }, - "victory": { - 1: "Sua força... É impressionante. Você realmente merece essa vitória.", - 2: "Nunca senti essa intensidade antes. Trabalho incrível!" - }, - "defeat": { - 1: "Outra vitória para meu rigoroso regime de treinamento! Bem feito!", - 2: "Você tem força, mas eu treinei mais. Grande batalha!" - } - }, "allister_elite": { "encounter": { 1: "As sombras caem... Você está pronta para enfrentar seus medos?", @@ -4829,33 +3805,7 @@ export const PGFdialogue: DialogueTranslationEntries = { }, "defeat": { 1: "Outra tempestade enfrentada, outra vitória conquistada! Bem lutado!", - 2: "Você foi pego na minha tempestade! Melhor sorte na próxima vez!" - } - }, - "alder": { - "encounter": { - 1: "Se prepare para uma batalha contra o Treinador mais forte de Unova!" - }, - "victory": { - 1: "Muito bem! Você certamente é um talento incomparável." - }, - "defeat": { - 1: `Um vento fresco sopra em meu coração... - $Que esforço extraordinário!` - } - }, - "kieran": { - "encounter": { - 1: `Através do trabalho duro, eu me torno cada vez mais forte! - $Eu não perco.` - }, - "victory": { - 1: `Eu não acredito... - $Que batalha divertida e emocionante!` - }, - "defeat": { - 1: `Uau, que batalha! - $Hora de você treinar ainda mais.` + 2: "Você foi pega na minha tempestade! Melhor sorte na próxima vez!" } }, "rival": { @@ -4904,7 +3854,7 @@ export const PGFdialogue: DialogueTranslationEntries = { }, "rival_2_female": { "encounter": { - 1: `@c{smile_wave}Oh, que surpresa te encontrar aqui. Parece que você ainda está invicto. @c{angry_mopen}Hum… Nada mal! + 1: `@c{smile_wave}Oh, que surpresa te encontrar aqui. Parece que você ainda está invicta. @c{angry_mopen}Hum… Nada mal! $@c{angry_mopen}Eu sei o que você está pensando, e não, eu não estava te espionando. @c{smile_eclosed}Acontece que eu estava na área. $@c{smile_ehalf}Estou feliz por você, mas só quero te avisar que está tudo bem perder às vezes. $@c{smile}Aprendemos com nossos erros, muitas vezes mais do que se continuássemos vencendo. @@ -4923,7 +3873,7 @@ export const PGFdialogue: DialogueTranslationEntries = { }, "rival_3": { "encounter": { - 1: `@c{smile}Eai, olha quem é! Faz um tempo.\n@c{neutral}Você… ainda está invicto? Hum. + 1: `@c{smile}Eai, olha quem é! Faz um tempo.\n@c{neutral}Você… ainda está invicta? Hum. $@c{neutral_eclosed}As coisas têm sido meio… estranhas.\nNão é a mesma coisa em casa sem você. $@c{serious}Eu sei que é egoísta, mas preciso desabafar.\n@c{neutral_eclosed}Acho que você está se metendo em algo grande demais aqui. $@c{serious}Nunca perder é irrealista.\nPrecisamos perder às vezes para crescer. @@ -4960,7 +3910,7 @@ export const PGFdialogue: DialogueTranslationEntries = { $@c{serious_mopen_fists}Prepare-se.` }, "victory": { - 1: "@c{neutral}O que…@d{64} O que você é?" + 1: "@c{neutral}O que…@d{64} O que é você?" }, }, "rival_4_female": { @@ -4975,7 +3925,7 @@ export const PGFdialogue: DialogueTranslationEntries = { $@c{angry_mopen}Prepare-se.` }, "victory": { - 1: "@c{neutral}O que…@d{64} O que você é?" + 1: "@c{neutral}O que…@d{64} O que é você?" }, "defeat": { 1: "$@c{smile}Você deveria se orgulhar de até onde chegou." @@ -5046,7 +3996,7 @@ export const PGFdialogue: DialogueTranslationEntries = { }, }; -// Diálogo do chefe final do jogo quando o personagem do jogador é masculino (ou não definido) +// Dialogue of the endboss of the game when the player character is male (Or unset) export const PGMbattleSpecDialogue: SimpleTranslationEntries = { "encounter": `Parece que a hora finalmente chegou novamente.\nVocê sabe por que veio aqui, não sabe? $Você foi atraído para cá, porque já esteve aqui antes.\nInúmeras vezes. @@ -5061,7 +4011,7 @@ export const PGMbattleSpecDialogue: SimpleTranslationEntries = { "secondStageWin": "…Magnífico." }; -// Diálogo do chefe final do jogo quando o personagem do jogador é feminino. Para idiomas que não possuem pronomes de gênero, isso pode ser definido como PGMbattleSpecDialogue. +// Dialogue of the endboss of the game when the player character is female. For languages that do not have gendered pronouns, this can be set to PGMbattleSpecDialogue. export const PGFbattleSpecDialogue: SimpleTranslationEntries = { "encounter": `Parece que a hora finalmente chegou novamente.\nVocê sabe por que veio aqui, não sabe? $Você foi atraída para cá, porque já esteve aqui antes.\nInúmeras vezes. @@ -5076,10 +4026,10 @@ export const PGFbattleSpecDialogue: SimpleTranslationEntries = { "secondStageWin": "…Magnífico." }; -// Diálogo que não se enquadra em nenhuma outra categoria (por exemplo, mensagens de tutorial ou o final do jogo). Para quando o personagem do jogador é masculino +// Dialogue that does not fit into any other category (e.g. tutorial messages, or the end of the game). For when the player character is male export const PGMmiscDialogue: SimpleTranslationEntries = { "ending": - `@c{smile}Oh? Você venceu?@d{96} @c{smile_eclosed}Acho que eu deveria saber.\nMas, você está de volta agora. + `@c{smile}Oh? Você venceu?@d{96} @c{smile_eclosed}Acho que eu deveria saber.\nMas, você está de volta agora. $@c{smile}Acabou.@d{64} Você quebrou o ciclo. $@c{serious_smile_fists}Você também realizou seu sonho, não é?\nVocê não perdeu nenhuma vez. $@c{neutral}Eu sou o único que vai lembrar o que você fez.@d{96}\nAcho que está tudo bem, não é? @@ -5087,7 +4037,7 @@ export const PGMmiscDialogue: SimpleTranslationEntries = { $@c{smile_eclosed}Enfim, já tive o suficiente deste lugar, não é? Vamos para casa. $@c{serious_smile_fists}Talvez quando voltarmos, possamos ter outra batalha?\nSe você estiver disposto.`, "ending_female": - `@c{shock}Você está de volta?@d{32} Isso significa que…@d{96} você venceu?!\n@c{smile_ehalf}Eu deveria saber que você conseguiria. + `@c{shock}Você está de volta?@d{32} Isso significa que…@d{96} você venceu?!\n@c{smile_ehalf}Eu deveria saber que você conseguiria. $@c{smile_eclosed}Claro… Eu sempre tive essa sensação.\n@c{smile}Acabou agora, certo? Você quebrou o ciclo. $@c{smile_ehalf}Você também realizou seu sonho, não foi?\nVocê não perdeu nenhuma vez. $Eu serei a única a lembrar o que você fez.\n@c{angry_mopen}Eu tentarei não esquecer! @@ -5098,10 +4048,10 @@ export const PGMmiscDialogue: SimpleTranslationEntries = { "ending_name": "Desenvolvedores" }; -// Diálogo que não se enquadra em nenhuma outra categoria (por exemplo, mensagens de tutorial ou o final do jogo). Para quando o personagem do jogador é feminino. Para idiomas que não possuem pronomes de gênero, isso pode ser definido como PGMmiscDialogue. +// Dialogue that does not fit into any other category (e.g. tutorial messages, or the end of the game). For when the player character is female. For languages that do not have gendered pronouns, this can be set to PGMmiscDialogue. export const PGFmiscDialogue: SimpleTranslationEntries = { "ending": - `@c{smile}Oh? Você venceu?@d{96} @c{smile_eclosed}Acho que eu deveria saber.\nMas, você está de volta agora. + `@c{smile}Oh? Você venceu?@d{96} @c{smile_eclosed}Acho que eu deveria saber.\nMas, você está de volta agora. $@c{smile}Acabou.@d{64} Você quebrou o ciclo. $@c{serious_smile_fists}Você também realizou seu sonho, não é?\nVocê não perdeu nenhuma vez. $@c{neutral}Eu sou o único que vai lembrar o que você fez.@d{96}\nAcho que está tudo bem, não é? @@ -5109,7 +4059,7 @@ export const PGFmiscDialogue: SimpleTranslationEntries = { $@c{smile_eclosed}Enfim, já tive o suficiente deste lugar, não é? Vamos para casa. $@c{serious_smile_fists}Talvez quando voltarmos, possamos ter outra batalha?\nSe você estiver disposta.`, "ending_female": - `@c{shock}Você está de volta?@d{32} Isso significa que…@d{96} você venceu?!\n@c{smile_ehalf}Eu deveria saber que você conseguiria. + `@c{shock}Você está de volta?@d{32} Isso significa que…@d{96} você venceu?!\n@c{smile_ehalf}Eu deveria saber que você conseguiria. $@c{smile_eclosed}Claro… Eu sempre tive essa sensação.\n@c{smile}Acabou agora, certo? Você quebrou o ciclo. $@c{smile_ehalf}Você também realizou seu sonho, não foi?\nVocê não perdeu nenhuma vez. $Eu serei a única a lembrar o que você fez.\n@c{angry_mopen}Eu tentarei não esquecer! @@ -5121,7 +4071,7 @@ export const PGFmiscDialogue: SimpleTranslationEntries = { }; -// Diálogo das batalhas duplas nomeadas no jogo. Para quando o jogador é masculino (ou não definido). +// Dialogue of the named double battles in the game. For when the player is male (or unset). export const PGMdoubleBattleDialogue: DialogueTranslationEntries = { "blue_red_double": { "encounter": { @@ -5196,41 +4146,41 @@ export const PGMdoubleBattleDialogue: DialogueTranslationEntries = { }, "alder_iris_double": { "encounter": { - 1: `Alder: Somos os treinadores mais fortes de Unova! + 1: `Alder: Somos os treinadores mais fortes de Unova! $Iris: Lutas contra treinadores fortes são as melhores!`, }, "victory": { - 1: `Alder: Uau! Você é super forte! + 1: `Alder: Uau! Você é super forte! $Iris: Vamos vencer da próxima vez!`, }, }, "iris_alder_double": { "encounter": { - 1: `Iris: Bem-vindo, Desafiante! Eu sou A Campeã de Unova! + 1: `Iris: Bem-vindo, Desafiante! Eu sou A Campeã de Unova! $Alder: Iris, você não está um pouco empolgada demais?`, }, "victory": { - 1: `Iris: Uma derrota como essa não é fácil de engolir... + 1: `Iris: Uma derrota como essa não é fácil de engolir... $Alder: Mas só ficaremos mais fortes a cada derrota!`, }, }, "piers_marnie_double": { "encounter": { - 1: `Marnie: Irmão, vamos mostrar a eles o poder de Spikemuth! + 1: `Marnie: Irmão, vamos mostrar a eles o poder de Spikemuth! $Piers: Nós trazemos a escuridão!`, }, "victory": { - 1: `Marnie: Você trouxe luz para nossa escuridão! + 1: `Marnie: Você trouxe luz para nossa escuridão! $Piers: Está muito claro...`, }, }, "marnie_piers_double": { "encounter": { - 1: `Piers: Prontos para um show? + 1: `Piers: Prontos para um show? $Marnie: Irmão... Eles estão aqui para lutar, não para cantar...`, }, "victory": { - 1: `Piers: Agora esse foi um ótimo show! + 1: `Piers: Agora esse foi um ótimo show! $Marnie: Irmão...`, }, }, @@ -5312,41 +4262,41 @@ export const PGFdoubleBattleDialogue: DialogueTranslationEntries = { }, "alder_iris_double": { "encounter": { - 1: `Alder: Somos os treinadores mais fortes de Unova! + 1: `Alder: Somos os treinadores mais fortes de Unova! $Iris: Lutas contra treinadores fortes são as melhores!`, }, "victory": { - 1: `Alder: Uau! Você é super forte! + 1: `Alder: Uau! Você é super forte! $Iris: Vamos vencer da próxima vez!`, }, }, "iris_alder_double": { "encounter": { - 1: `Iris: Bem-vinda, Desafiante! Eu sou A Campeã de Unova! + 1: `Iris: Bem-vinda, Desafiante! Eu sou A Campeã de Unova! $Alder: Iris, você não está um pouco empolgada demais?`, }, "victory": { - 1: `Iris: Uma derrota como essa não é fácil de engolir... + 1: `Iris: Uma derrota como essa não é fácil de engolir... $Alder: Mas só ficaremos mais fortes a cada derrota!`, }, }, "piers_marnie_double": { "encounter": { - 1: `Marnie: Irmão, vamos mostrar a eles o poder de Spikemuth! + 1: `Marnie: Irmão, vamos mostrar a eles o poder de Spikemuth! $Piers: Nós trazemos a escuridão!`, }, "victory": { - 1: `Marnie: Você trouxe luz para nossa escuridão! + 1: `Marnie: Você trouxe luz para nossa escuridão! $Piers: Está muito claro...`, }, }, "marnie_piers_double": { "encounter": { - 1: `Piers: Prontos para um show? + 1: `Piers: Prontos para um show? $Marnie: Irmão... Eles estão aqui para lutar, não para cantar...`, }, "victory": { - 1: `Piers: Agora esse foi um ótimo show! + 1: `Piers: Agora esse foi um ótimo show! $Marnie: Irmão...`, }, }, diff --git a/src/locales/pt_BR/trainers.ts b/src/locales/pt_BR/trainers.ts index e920d07a22a..41932cd1b9a 100644 --- a/src/locales/pt_BR/trainers.ts +++ b/src/locales/pt_BR/trainers.ts @@ -20,18 +20,18 @@ export const titles: SimpleTranslationEntries = { "plasma_boss": "Chefe da Equipe Plasma", "flare_boss": "Chefe da Equipe Flare", - "rocket_admin": "Team Rocket Admin", - "rocket_admin_female": "Team Rocket Admin", - "magma_admin": "Team Magma Admin", - "magma_admin_female": "Team Magma Admin", - "aqua_admin": "Team Aqua Admin", - "aqua_admin_female": "Team Aqua Admin", - "galactic_commander": "Team Galactic Commander", - "galactic_commander_female": "Team Galactic Commander", - "plasma_sage": "Team Plasma Sage", - "plasma_admin": "Team Plasma Admin", - "flare_admin": "Team Flare Admin", - "flare_admin_female": "Team Flare Admin", + "rocket_admin": "Admin da Equipe Rocket", + "rocket_admin_female": "Admin da Equipe Rocket", + "magma_admin": "Admin da Equipe Magma", + "magma_admin_female": "Admin da Equipe Magma", + "aqua_admin": "Admin da Equipe Aqua", + "aqua_admin_female": "Admin da Equipe Aqua", + "galactic_commander": "Comandante da Equipe Galáctica", + "galactic_commander_female": "Comandante da Equipe Galáctica", + "plasma_sage": "Sábio da Equipe Plasma", + "plasma_admin": "Admin da Equipe Plasma", + "flare_admin": "Admin da Equipe Flare", + "flare_admin_female": "Admin da Equipe Flare", // Maybe if we add the evil teams we can add "Team Rocket" and "Team Aqua" etc. here as well as "Team Rocket Boss" and "Team Aqua Admin" etc. } as const; @@ -138,24 +138,24 @@ export const trainerClasses: SimpleTranslationEntries = { "worker_female": "Operária", "workers": "Operários", "youngster": "Jovem", - "rocket_grunt": "Recruta da Equipe Rocket", - "rocket_grunt_female": "Recruta da Equipe Rocket", - "rocket_grunts": "Recrutas da Equipe Rocket", - "magma_grunt": "Recruta da Equipe Magma", - "magma_grunt_female": "Recruta da Equipe Magma", - "magma_grunts": "Recrutas da Equipe Magma", - "aqua_grunt": "Recruta da Equipe Aqua", - "aqua_grunt_female": "Recruta da Equipe Aqua", - "aqua_grunts": "Recrutas da Equipe Aqua", - "galactic_grunt": "Recruta da Equipe Galáctica", - "galactic_grunt_female": "Recruta da Equipe Galáctica", - "galactic_grunts": "Recrutas da Equipe Galáctica", - "plasma_grunt": "Recruta da Equipe Plasma", - "plasma_grunt_female": "Recruta da Equipe Plasma", - "plasma_grunts": "Recrutas da Equipe Plasma", - "flare_grunt": "Recruta da Equipe Flare", - "flare_grunt_female": "Recruta da Equipe Flare", - "flare_grunts": "Recrutas da Equipe Flare", + "rocket_grunt": "Capanga da Equipe Rocket", + "rocket_grunt_female": "Capanga da Equipe Rocket", + "rocket_grunts": "Capangas da Equipe Rocket", + "magma_grunt": "Capanga da Equipe Magma", + "magma_grunt_female": "Capanga da Equipe Magma", + "magma_grunts": "Capangas da Equipe Magma", + "aqua_grunt": "Capanga da Equipe Aqua", + "aqua_grunt_female": "Capanga da Equipe Aqua", + "aqua_grunts": "Capangas da Equipe Aqua", + "galactic_grunt": "Capanga da Equipe Galáctica", + "galactic_grunt_female": "Capanga da Equipe Galáctica", + "galactic_grunts": "Capangas da Equipe Galáctica", + "plasma_grunt": "Capanga da Equipe Plasma", + "plasma_grunt_female": "Capanga da Equipe Plasma", + "plasma_grunts": "Capangas da Equipe Plasma", + "flare_grunt": "Capanga da Equipe Flare", + "flare_grunt_female": "Capanga da Equipe Flare", + "flare_grunts": "Capangas da Equipe Flare", } as const; // Names of special trainers like gym leaders, elite four, and the champion From 750d9051c4a77b04e9c5d17b7dd658768440826d Mon Sep 17 00:00:00 2001 From: Chapybara-jp Date: Fri, 9 Aug 2024 15:38:51 +0200 Subject: [PATCH 048/282] [Localization(ja)] Added kanji to battle.ts (#3446) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Added kanji 漢字に変更しました Changed spacing to full width スペースを全角スペースに変更しました --- src/locales/ja/battle.ts | 284 +++++++++++++++++++-------------------- 1 file changed, 142 insertions(+), 142 deletions(-) diff --git a/src/locales/ja/battle.ts b/src/locales/ja/battle.ts index aed24a710df..7e9313ebaf8 100644 --- a/src/locales/ja/battle.ts +++ b/src/locales/ja/battle.ts @@ -1,159 +1,159 @@ import { SimpleTranslationEntries } from "#app/interfaces/locales"; export const battle: SimpleTranslationEntries = { - "bossAppeared": "{{bossName}}が あらわれた!", - "trainerAppeared": "{{trainerName}}が\nしょうぶを しかけてきた!", - "trainerAppearedDouble": "{{trainerName}}が\nしょうぶを しかけてきた!", - "trainerSendOut": "{{trainerName}}は\n{{pokemonName}}を くりだした!", - "singleWildAppeared": "あっ! やせいの\n{{pokemonName}}が とびだしてきた!", - "multiWildAppeared": "あっ! やせいの {{pokemonName1}}と\n{{pokemonName2}}が とびだしてきた!", - "playerComeBack": "{{pokemonName}}! もどれ!", - "trainerComeBack": "{{trainerName}}は\n{{pokemonName}}を ひっこめた!", + "bossAppeared": "{{bossName}}が 現れた!", + "trainerAppeared": "{{trainerName}}が\n勝負を しかけてきた!", + "trainerAppearedDouble": "{{trainerName}}が\n勝負を しかけてきた!", + "trainerSendOut": "{{trainerName}}は\n{{pokemonName}}を 繰り出した!", + "singleWildAppeared": "あっ! 野生の {{pokemonName}}が 飛び出してきた!", + "multiWildAppeared": "あっ! 野生の {{pokemonName1}}と\n{{pokemonName2}}が 飛び出してきた!", + "playerComeBack": "{{pokemonName}}! 戻れ!", + "trainerComeBack": "{{trainerName}}は\n{{pokemonName}}を 引っ込めた!", "playerGo": "ゆけっ! {{pokemonName}}!", - "trainerGo": "{{trainerName}}は\n{{pokemonName}}を くりだした!", - "switchQuestion": "{{pokemonName}}を\nいれかえますか?", - "trainerDefeated": "{{trainerName}}\nとの しょうぶに かった!", - "moneyWon": "しょうきんとして\n₽{{moneyAmount}} てにいれた!", - "moneyPickedUp": "₽{{moneyAmount}}を ひろった!", - "pokemonCaught": "{{pokemonName}}を\nつかまえたぞ!", - "addedAsAStarter": "{{pokemonName}} has been\nadded as a starter!", - "partyFull": "てもちがいっぱいです。\n{{pokemonName}}をいれるために ポケモンを ひとり てばなしますか?", + "trainerGo": "{{trainerName}}は\n{{pokemonName}}を 繰り出した!", + "switchQuestion": "{{pokemonName}}を\n入れ替えますか?", + "trainerDefeated": "{{trainerName}} との 勝負に 勝った!", + "moneyWon": "賞金として ₽{{moneyAmount}}を 手に入れた!", + "moneyPickedUp": "₽{{moneyAmount}}を 拾った!", + "pokemonCaught": "{{pokemonName}}を 捕まえたぞ!", + "addedAsAStarter": "今から {{pokemonName}}は 最初のパートナーとして 選べられる!", + "partyFull": "手持ちが いっぱいです。\n{{pokemonName}}を入れる ために ポケモンを 一つ 逃がすか?", "pokemon": "ポケモン", - "sendOutPokemon": "がんばれ! {{pokemonName}}!", - "hitResultCriticalHit": "きゅうしょに あたった!", - "hitResultSuperEffective": "こうかは ばつぐんだ!", - "hitResultNotVeryEffective": "こうかは いまひとつの ようだ……", - "hitResultNoEffect": "{{pokemonName}}には こうかが ないようだ…", - "hitResultOneHitKO": "いちげき ひっさつ!", - "attackFailed": "しかし うまく きまらなかった!!", - "attackMissed": "{{pokemonNameWithAffix}}には あたらなかった!", - "attackHitsCount": "{{count}}かい あたった!", - "rewardGain": "{{modifierName}}を\nてにいれた!", - "expGain": "{{pokemonName}}は\n{{exp}}けいけんちを もらった!", - "levelUp": "{{pokemonName}}は\nレベル{{level}} に あがった!", - "learnMove": "{{pokemonName}}は あたらしく\n{{moveName}}を おぼえた!", - "learnMovePrompt": "{{pokemonName}}は あたらしく\n{{moveName}}を おぼえたい……", - "learnMoveLimitReached": "しかし {{pokemonName}}は わざを 4つ\nおぼえるので せいいっぱいだ!", - "learnMoveReplaceQuestion": "{{moveName}}の かわりに\nほかの わざを わすれさせますか?", - "learnMoveStopTeaching": "それでは…… {{moveName}}を\nおぼえるのを あきらめますか?", - "learnMoveNotLearned": "{{pokemonName}}は {{moveName}}を\nおぼえずに おわった!", - "learnMoveForgetQuestion": "どの わざを\nわすれさせたい?", - "learnMoveForgetSuccess": "{{pokemonName}}は {{moveName}}の\nつかいかたを きれいに わすれた!", + "sendOutPokemon": "頑張れ! {{pokemonName}}!", + "hitResultCriticalHit": "急所に 当たった!", + "hitResultSuperEffective": "効果は バツグンだ!", + "hitResultNotVeryEffective": "効果は 今ひとつの ようだ……", + "hitResultNoEffect": "{{pokemonName}}には 効果が ないようだ…", + "hitResultOneHitKO": "一撃必殺!", + "attackFailed": "しかし うまく 決まらなかった!!", + "attackMissed": "{{pokemonNameWithAffix}}には 当たらなかった!", + "attackHitsCount": "{{count}}かい 当たった!", + "rewardGain": "{{modifierName}}を 手に入れた!", + "expGain": "{{pokemonName}}は\n{{exp}}経験値を もらった!", + "levelUp": "{{pokemonName}}は\nレベル{{level}}に 上がった!", + "learnMove": "{{pokemonName}}は 新しく\n{{moveName}}を 覚えた!", + "learnMovePrompt": "{{pokemonName}}は 新しく\n{{moveName}}を 覚えたい……", + "learnMoveLimitReached": "しかし {{pokemonName}}は 技を 4つ\n覚えるので せいいっぱいだ!", + "learnMoveReplaceQuestion": "{{moveName}}の 代わりに\n他の 技を 忘れさせますか?", + "learnMoveStopTeaching": "それでは {{moveName}}を\n覚えるのを 諦めますか?", + "learnMoveNotLearned": "{{pokemonName}}は {{moveName}}を\n覚えずに 終わった!", + "learnMoveForgetQuestion": "どの 技を\n忘れさせたい?", + "learnMoveForgetSuccess": "{{pokemonName}}は {{moveName}}の\n使い方を きれいに 忘れた!", "countdownPoof": "@d{32}1 @d{15}2の @d{15}… @d{15}… @d{15}… @d{15}@s{pb_bounce_1}ポカン!", "learnMoveAnd": "そして…", - "levelCapUp": "レベルキャップの\n{{levelCap}}に あがった!", - "moveNotImplemented": "{{moveName}}は まだじっそうされておらず、せんたくできません。", - "moveNoPP": "しかし わざの\nのこりポイントが なかった!", - "moveDisabled": "かなしばりで\n{{moveName}}が だせない!", - "noPokeballForce": "みえない ちからの せいで\nボールを なげられない!", - "noPokeballTrainer": "ひとのものを\nとったら どろぼう!", - "noPokeballMulti": "あいての ポケモンが ひとつしか\n いないまえに ボールが つかえない!", - "noPokeballStrong": "あいての ポケモンが つよすぎて つかまえられない!\nまずは よわらせよう!", - "noEscapeForce": "みえない ちからの せいで\nにげることが できない!", - "noEscapeTrainer": "ダメだ! しょうぶのさいちゅうに\nあいてに せなかを みせられない!", - "noEscapePokemon": "{{pokemonName}}の {{moveName}}で {{escapeVerb}}!", - "runAwaySuccess": " うまく にげきれた!", - "runAwayCannotEscape": "にげることが できない!", - "escapeVerbSwitch": "いれかえることが できない", - "escapeVerbFlee": "にげることが できない", - "notDisabled": "{{pokemonName}}の かなしばりが とけた!\nまた {{moveName}}が つかえられる!", - "turnEndHpRestore": "{{pokemonName}}の たいりょくが かいふくした!", - "hpIsFull": "{{pokemonName}}の\nHPが まんたんだ!", - "skipItemQuestion": "ほんとに アイテムを とらない?", + "levelCapUp": "レベルキャップの\n{{levelCap}}に 上がった!", + "moveNotImplemented": "{{moveName}}は まだ 実装されておらず 選択できません。", + "moveNoPP": "しかし 技の\n残りポイントが なかった!", + "moveDisabled": "かなしばりで\n{{moveName}}が 出せない!", + "noPokeballForce": "見えない 力の せいで\nボールが 投げられない!", + "noPokeballTrainer": "人の ものを 取ったら 泥棒!", + "noPokeballMulti": "相手の ポケモンが 一つしか\nいない 前に ボールが 使えない!", + "noPokeballStrong": "相手の ポケモンが 強すぎて 捕まえられない!\nまずは 弱めよう!", + "noEscapeForce": "見えない 力の せいで\n逃げることが できない!", + "noEscapeTrainer": "ダメだ! 勝負の最中に\n相手に 背中を 見せられない!", + "noEscapePokemon": "{{pokemonName}}の {{moveName}}で {{escapeVerb}}!", + "runAwaySuccess": " うまく 逃げ切れた!", + "runAwayCannotEscape": "逃げることが できない!", + "escapeVerbSwitch": "入れ替えることが できない", + "escapeVerbFlee": "逃げることが できない", + "notDisabled": "{{pokemonName}}の かなしばりが 溶けた!\nまた {{moveName}}が 使えられる!", + "turnEndHpRestore": "{{pokemonName}}の 体力が 回復した!", + "hpIsFull": "{{pokemonName}}の\n体力が 満タンだ!", + "skipItemQuestion": "本当に アイテムを 取らずに 進みますか?", "eggHatching": "おや?", - "ivScannerUseQuestion": "{{pokemonName}}を\nこたいちスキャナーで そうさする?", - "wildPokemonWithAffix": "やせいの {{pokemonName}}", - "foePokemonWithAffix": "あいての {{pokemonName}}", - "useMove": "{{pokemonNameWithAffix}}の {{moveName}}!", - "drainMessage": "{{pokemonName}}から\nたいりょくを すいとった!", - "regainHealth": "{{pokemonName}}は\nたいりょくを かいふくした!", - "stealEatBerry": "{{pokemonName}}は {{targetName}}の\n{{berryName}}を うばって たべた!", - "ppHealBerry": "{{pokemonNameWithAffix}}は {{berryName}}で {{moveName}}のPPを かいふくした!", - "hpHealBerry": "{{pokemonNameWithAffix}}は {{berryName}}で たいりょくを かいふくした!", - "fainted": "{{pokemonNameWithAffix}}は たおれた!", + "ivScannerUseQuestion": "{{pokemonName}}を\n個体値スキャナーで 操作しますか?", + "wildPokemonWithAffix": "野生の {{pokemonName}}", + "foePokemonWithAffix": "相手の {{pokemonName}}", + "useMove": "{{pokemonNameWithAffix}}の {{moveName}}!", + "drainMessage": "{{pokemonName}}から\n体力を 吸い取った!", + "regainHealth": "{{pokemonName}}は\n体力を 回復した!", + "stealEatBerry": "{{pokemonName}}は {{targetName}}の\n{{berryName}}を うばって 食べた!", + "ppHealBerry": "{{pokemonNameWithAffix}}は {{berryName}}で {{moveName}}のPPを 回復した!", + "hpHealBerry": "{{pokemonNameWithAffix}}は {{berryName}}で 体力を 回復した!", + "fainted": "{{pokemonNameWithAffix}}は 倒れた!", "statsAnd": "と ", - "stats": "のうりょく", - "statRose_one": "{{pokemonNameWithAffix}}の {{stats}}が あがった!", - "statRose_other": "{{pokemonNameWithAffix}}の {{stats}}が あがった!", - "statSharplyRose_one": "{{pokemonNameWithAffix}}の {{stats}}が ぐーんと あがった!", - "statSharplyRose_other": "{{pokemonNameWithAffix}}の {{stats}}が ぐーんと あがった!", - "statRoseDrastically_one": "{{pokemonNameWithAffix}}の {{stats}}が ぐぐーんと あがった!", - "statRoseDrastically_other": "{{pokemonNameWithAffix}}の {{stats}}が ぐぐーんと あがった!", - "statWontGoAnyHigher_one": "{{pokemonNameWithAffix}}の {{stats}}が もう あがらない!", - "statWontGoAnyHigher_other": "{{pokemonNameWithAffix}}の {{stats}}が もう あがらない!", - "statFell_one": "{{pokemonNameWithAffix}}の {{stats}}が さがった!", - "statFell_other": "{{pokemonNameWithAffix}}の {{stats}}が さがった!", - "statHarshlyFell_one": "{{pokemonNameWithAffix}}の {{stats}}が がくっと さがった!", - "statHarshlyFell_other": "{{pokemonNameWithAffix}}の {{stats}}が がくっと さがった!", - "statSeverelyFell_one": "{{pokemonNameWithAffix}}の {{stats}}が がくーんと さがった!", - "statSeverelyFell_other": "{{pokemonNameWithAffix}}の {{stats}}が がくーんと さがった!", - "statWontGoAnyLower_one": "{{pokemonNameWithAffix}}の {{stats}}が もう さがらない!", - "statWontGoAnyLower_other": "{{pokemonNameWithAffix}}の {{stats}}が もう さがらない!", - "transformedIntoType": "{{pokemonName}}は\n{{type}}タイプに へんしんした!", - "retryBattle": "このせんとうの はじまりから やりなおす?", + "stats": "能力", + "statRose_one": "{{pokemonNameWithAffix}}の {{stats}}が 上がった!", + "statRose_other": "{{pokemonNameWithAffix}}の {{stats}}が 上がった!", + "statSharplyRose_one": "{{pokemonNameWithAffix}}の {{stats}}が ぐーんと 上がった!", + "statSharplyRose_other": "{{pokemonNameWithAffix}}の {{stats}}が ぐーんと 上がった!", + "statRoseDrastically_one": "{{pokemonNameWithAffix}}の {{stats}}が ぐぐーんと 上がった!", + "statRoseDrastically_other": "{{pokemonNameWithAffix}}の {{stats}}が ぐぐーんと 上がった!", + "statWontGoAnyHigher_one": "{{pokemonNameWithAffix}}の {{stats}}が もう 上がらない!", + "statWontGoAnyHigher_other": "{{pokemonNameWithAffix}}の {{stats}}が もう 上がらない!", + "statFell_one": "{{pokemonNameWithAffix}}の {{stats}}が 下がった!", + "statFell_other": "{{pokemonNameWithAffix}}の {{stats}}が 下がった!", + "statHarshlyFell_one": "{{pokemonNameWithAffix}}の {{stats}}が がくっと 下がった!", + "statHarshlyFell_other": "{{pokemonNameWithAffix}}の {{stats}}が がくっと 下がった!", + "statSeverelyFell_one": "{{pokemonNameWithAffix}}の {{stats}}が がくーんと 下がった!", + "statSeverelyFell_other": "{{pokemonNameWithAffix}}の {{stats}}が がくーんと 下がった!", + "statWontGoAnyLower_one": "{{pokemonNameWithAffix}}の {{stats}}が もう 下がらない!", + "statWontGoAnyLower_other": "{{pokemonNameWithAffix}}の {{stats}}が もう 下がらない!", + "transformedIntoType": "{{pokemonName}}は\n{{type}}タイプに 変身した!", + "retryBattle": "このバトルの 始まりから やり直しますか?", "unlockedSomething": "{{unlockedThing}}\nを アンロックした!", "congratulations": "おめでとうございます!!", - "beatModeFirstTime": "はじめて {{speciesName}}が {{gameMode}}モードを クリアした!\n{{newModifier}}を てにいれた!", - "ppReduced": "{{targetName}}の {{moveName}}を {{reduction}}けずった!", - "battlerTagsRechargingLapse": "{{pokemonNameWithAffix}}は こうげきの はんどうで うごけない!", - "battlerTagsTrappedOnAdd": "{{pokemonNameWithAffix}}は もう にげられない!", - "battlerTagsTrappedOnRemove": "{{pokemonNameWithAffix}}は\n{{moveName}}の こうかが とけた!", - "battlerTagsFlinchedLapse": "{{pokemonNameWithAffix}}は ひるんで わざが だせない!", - "battlerTagsConfusedOnAdd": "{{pokemonNameWithAffix}}は こんらん した!", - "battlerTagsConfusedOnRemove": "{{pokemonNameWithAffix}}の こんらんが とけた!", - "battlerTagsConfusedOnOverlap": "{{pokemonNameWithAffix}}は すでに こんらん している!", - "battlerTagsConfusedLapse": "{{pokemonNameWithAffix}}は こんらん している!", - "battlerTagsConfusedLapseHurtItself": "わけも わからず じぶんを こうげきした!", + "beatModeFirstTime": "初めて {{speciesName}}が {{gameMode}}モードを クリアした!\n{{newModifier}}を 手に入れた!", + "ppReduced": "{{targetName}}の {{moveName}}を {{reduction}}削った!", + "battlerTagsRechargingLapse": "{{pokemonNameWithAffix}}は 攻撃の 反動で 動けない!", + "battlerTagsTrappedOnAdd": "{{pokemonNameWithAffix}}は もう 逃げられない!", + "battlerTagsTrappedOnRemove": "{{pokemonNameWithAffix}}は\n{{moveName}}の 効果が 解けた!", + "battlerTagsFlinchedLapse": "{{pokemonNameWithAffix}}は ひるんで 技が出せない!", + "battlerTagsConfusedOnAdd": "{{pokemonNameWithAffix}}は 混乱 した!", + "battlerTagsConfusedOnRemove": "{{pokemonNameWithAffix}}の 混乱が 解けた!", + "battlerTagsConfusedOnOverlap": "{{pokemonNameWithAffix}}は すでに 混乱している!", + "battlerTagsConfusedLapse": "{{pokemonNameWithAffix}}は 混乱している!", + "battlerTagsConfusedLapseHurtItself": "わけも わからず 自分を 攻撃した!", "battlerTagsDestinyBondLapseIsBoss": "{{pokemonNameWithAffix}}を みちづれに できない!", - "battlerTagsDestinyBondLapse": "{{pokemonNameWithAffix}}は あいてを みちづれに した!", - "battlerTagsInfatuatedOnAdd": "{{pokemonNameWithAffix}}は {{sourcePokemonName}}に メロメロに なった!", + "battlerTagsDestinyBondLapse": "{{pokemonNameWithAffix}}は 相手を みちづれに した!", + "battlerTagsInfatuatedOnAdd": "{{pokemonNameWithAffix}}は {{sourcePokemonName}}に メロメロに なった!", "battlerTagsInfatuatedOnOverlap": "{{pokemonNameWithAffix}}は すでに メロメロだ!", "battlerTagsInfatuatedLapse": "{{pokemonNameWithAffix}}は {{sourcePokemonName}}に メロメロだ!", - "battlerTagsInfatuatedLapseImmobilize": "{{pokemonNameWithAffix}}は\nメロメロで わざが だせなかった!", - "battlerTagsInfatuatedOnRemove": "{{pokemonNameWithAffix}}は メロメロじょうたいが なおった!", - "battlerTagsSeededOnAdd": "{{pokemonNameWithAffix}}に たねを うえつけた!", - "battlerTagsSeededLapse": "やどりぎが {{pokemonNameWithAffix}}の たいりょくを うばう!", - "battlerTagsSeededLapseShed": "{{pokemonNameWithAffix}}は ヘドロえきを すいとった!", - "battlerTagsNightmareOnAdd": "{{pokemonNameWithAffix}}は あくむを みはじめた!", - "battlerTagsNightmareOnOverlap": "{{pokemonNameWithAffix}}は すでに うなされている!", - "battlerTagsNightmareLapse": "{{pokemonNameWithAffix}}は あくむに うなされている!", - "battlerTagsEncoreOnAdd": "{{pokemonNameWithAffix}}は アンコールをうけた!", - "battlerTagsEncoreOnRemove": "{{pokemonNameWithAffix}}の アンコールじょうたいが とけた!", - "battlerTagsHelpingHandOnAdd": "{{pokemonNameWithAffix}}は {{pokemonName}}を\nてだすけする たいせいに はいった!", - "battlerTagsIngrainLapse": "{{pokemonNameWithAffix}}は ねから\n ようぶんを すいとった!", - "battlerTagsIngrainOnTrap": "{{pokemonNameWithAffix}}は ねを はった!", - "battlerTagsAquaRingOnAdd": "{{pokemonNameWithAffix}}は みずのリングを まとった!", - "battlerTagsAquaRingLapse": "{{pokemonName}}は {{moveName}}で\nたいりょくを かいふくした!", - "battlerTagsDrowsyOnAdd": "{{pokemonNameWithAffix}} の ねむけを さそった!", - "battlerTagsDamagingTrapLapse": "{{pokemonNameWithAffix}}は {{moveName}}の ダメージを うけた!", - "battlerTagsBindOnTrap": "{{pokemonNameWithAffix}}は {{sourcePokemonName}}に しめつけられた!", - "battlerTagsWrapOnTrap": "{{pokemonNameWithAffix}}は {{sourcePokemonName}}に まきつかれた!", - "battlerTagsVortexOnTrap": "{{pokemonNameWithAffix}}は うずの なかに とじこめられた!", - "battlerTagsClampOnTrap": "{{pokemonName}}は {{sourcePokemonNameWithAffix}}の\nからに はさまれた!", - "battlerTagsSandTombOnTrap": "{{pokemonNameWithAffix}}は {{moveName}}に とらわれた!", - "battlerTagsMagmaStormOnTrap": "{{pokemonNameWithAffix}}は マグマの\n うずに とじこめられた!", - "battlerTagsSnapTrapOnTrap": "{{pokemonNameWithAffix}}は トラバサミに とらわれた!", - "battlerTagsThunderCageOnTrap": "{{sourcePokemonNameWithAffix}}は {{pokemonNameWithAffix}}に とじこめられた!", + "battlerTagsInfatuatedLapseImmobilize": "{{pokemonNameWithAffix}}は\nメロメロで わざが 出せなかった!", + "battlerTagsInfatuatedOnRemove": "{{pokemonNameWithAffix}}は メロメロ状態が 治った!", + "battlerTagsSeededOnAdd": "{{pokemonNameWithAffix}}に 種を 植(う)えつけた!", + "battlerTagsSeededLapse": "やどりぎが {{pokemonNameWithAffix}}の 体力を うばう!", + "battlerTagsSeededLapseShed": "{{pokemonNameWithAffix}}は ヘドロえきを 吸い取った!", + "battlerTagsNightmareOnAdd": "{{pokemonNameWithAffix}}は あくむを 見始めた!", + "battlerTagsNightmareOnOverlap": "{{pokemonNameWithAffix}}は すでに うなされている!", + "battlerTagsNightmareLapse": "{{pokemonNameWithAffix}}は あくむに うなされている!", + "battlerTagsEncoreOnAdd": "{{pokemonNameWithAffix}}は アンコールを 受けた!", + "battlerTagsEncoreOnRemove": "{{pokemonNameWithAffix}}の アンコール状態が 解けた!", + "battlerTagsHelpingHandOnAdd": "{{pokemonNameWithAffix}}は {{pokemonName}}を\nてだすけする 体制に 入った!", + "battlerTagsIngrainLapse": "{{pokemonNameWithAffix}}は 根から\n養分(ようぶん)を 吸い取った!", + "battlerTagsIngrainOnTrap": "{{pokemonNameWithAffix}}は 根を 張った!", + "battlerTagsAquaRingOnAdd": "{{pokemonNameWithAffix}}は 水のリングを まとった!", + "battlerTagsAquaRingLapse": "{{pokemonName}}は {{moveName}}で\n体力を 回復した!", + "battlerTagsDrowsyOnAdd": "{{pokemonNameWithAffix}} の ねむけを 誘(さそ)った!", + "battlerTagsDamagingTrapLapse": "{{pokemonNameWithAffix}}は {{moveName}}の ダメージを 受けた!", + "battlerTagsBindOnTrap": "{{pokemonNameWithAffix}}は {{sourcePokemonName}}に 締め付けられた!", + "battlerTagsWrapOnTrap": "{{pokemonNameWithAffix}}は {{sourcePokemonName}}に 巻き付かれた!", + "battlerTagsVortexOnTrap": "{{pokemonNameWithAffix}}は 渦(うず)の中に 閉じ込められた!", + "battlerTagsClampOnTrap": "{{pokemonName}}は {{sourcePokemonNameWithAffix}}の\nからに 挟まれた!", + "battlerTagsSandTombOnTrap": "{{pokemonNameWithAffix}}は {{moveName}}に 捕らわれた!", + "battlerTagsMagmaStormOnTrap": "{{pokemonNameWithAffix}}は マグマの\n 渦(うず)に 閉じ込められた!", + "battlerTagsSnapTrapOnTrap": "{{pokemonNameWithAffix}}は トラバサミに 捕らわれた!", + "battlerTagsThunderCageOnTrap": "{{sourcePokemonNameWithAffix}}は {{pokemonNameWithAffix}}に 閉じ込められた!", "battlerTagsInfestationOnTrap": "{{pokemonNameWithAffix}}は {{sourcePokemonNameWithAffix}}に まとわりつかれた!", - "battlerTagsProtectedOnAdd": "{{pokemonNameWithAffix}}は\nまもりの たいせいに はいった!", - "battlerTagsProtectedLapse": "{{pokemonNameWithAffix}}は\nこうげきから みを まもった!", - "battlerTagsEnduringOnAdd": "{{pokemonNameWithAffix}}は\nこらえる たいせいに はいった!", - "battlerTagsEnduringLapse": "{{pokemonNameWithAffix}}は\nこうげきを こらえた!", - "battlerTagsSturdyLapse": "{{pokemonNameWithAffix}}は\nこうげきを こらえた!", - "battlerTagsPerishSongLapse": "{{pokemonNameWithAffix}}の ほろびのカウントが {{turnCount}}になった!", - "battlerTagsCenterOfAttentionOnAdd": "{{pokemonNameWithAffix}}は ちゅうもくの まとになった!", - "battlerTagsTruantLapse": "{{pokemonNameWithAffix}}は なまけている!", - "battlerTagsSlowStartOnAdd": "{{pokemonNameWithAffix}}は ちょうしが あがらない!", - "battlerTagsSlowStartOnRemove": "{{pokemonNameWithAffix}}は ちょうしを とりもどした!", - "battlerTagsHighestStatBoostOnAdd": "{{pokemonNameWithAffix}}の {{statName}}が\nあがっている じょうたいに なった!", - "battlerTagsHighestStatBoostOnRemove": "{{pokemonNameWithAffix}}の {{abilityName}}の こうかが なくなった!", - "battlerTagsMagnetRisenOnAdd": "{{pokemonNameWithAffix}}は でんじりょくで うかびあがった!", - "battlerTagsMagnetRisenOnRemove": "{{pokemonNameWithAffix}}は でんじりょくが なくなった!", - "battlerTagsCritBoostOnAdd": "{{pokemonNameWithAffix}}は はりきっている!", - "battlerTagsCritBoostOnRemove": "{{pokemonNameWithAffix}}は おちついた。", + "battlerTagsProtectedOnAdd": "{{pokemonNameWithAffix}}は\nまもりの 体制に 入った!", + "battlerTagsProtectedLapse": "{{pokemonNameWithAffix}}は\n攻撃から 身を守った!", + "battlerTagsEnduringOnAdd": "{{pokemonNameWithAffix}}は\nこらえる 体制に 入った!", + "battlerTagsEnduringLapse": "{{pokemonNameWithAffix}}は\n攻撃を こらえた!", + "battlerTagsSturdyLapse": "{{pokemonNameWithAffix}}は\n攻撃を こらえた!", + "battlerTagsPerishSongLapse": "{{pokemonNameWithAffix}}の ほろびのカウントが {{turnCount}}になった!", + "battlerTagsCenterOfAttentionOnAdd": "{{pokemonNameWithAffix}}は 注目の 的になった!", + "battlerTagsTruantLapse": "{{pokemonNameWithAffix}}は 怠(なま)けている!", + "battlerTagsSlowStartOnAdd": "{{pokemonNameWithAffix}}は 調子が 上がらない!", + "battlerTagsSlowStartOnRemove": "{{pokemonNameWithAffix}}は 調子を 取り戻した!", + "battlerTagsHighestStatBoostOnAdd": "{{pokemonNameWithAffix}}の {{statName}}が\n上がっている 状態に なった!", + "battlerTagsHighestStatBoostOnRemove": "{{pokemonNameWithAffix}}の {{abilityName}}の 効果が なくなった!", + "battlerTagsMagnetRisenOnAdd": "{{pokemonNameWithAffix}}は 電磁力(でんじりょく)で 浮かび上がった!", + "battlerTagsMagnetRisenOnRemove": "{{pokemonNameWithAffix}}は 電磁力(でんじりょく)が なくなった!", + "battlerTagsCritBoostOnAdd": "{{pokemonNameWithAffix}}は 張り切っている!", + "battlerTagsCritBoostOnRemove": "{{pokemonNameWithAffix}}は 落ち着いた。", "battlerTagsSaltCuredOnAdd": "{{pokemonNameWithAffix}}は しおづけに なった!", - "battlerTagsSaltCuredLapse": "{{pokemonNameWithAffix}}は {{moveName}}の\n ダメージを うけている", - "battlerTagsCursedOnAdd": "{{pokemonNameWithAffix}}は じぶんの たいりょくを けずって\n{{pokemonName}}に のろいを かけた!", - "battlerTagsCursedLapse": "{{pokemonNameWithAffix}}は のろわれている!", - "battlerTagsStockpilingOnAdd": "{{pokemonNameWithAffix}}は {{stockpiledCount}}つ たくわえた!" + "battlerTagsSaltCuredLapse": "{{pokemonNameWithAffix}}は {{moveName}}の\n ダメージを 受けている", + "battlerTagsCursedOnAdd": "{{pokemonNameWithAffix}}は 自分の 体力を 削って\n{{pokemonName}}に のろいを かけた!", + "battlerTagsCursedLapse": "{{pokemonNameWithAffix}}は のろわれている!", + "battlerTagsStockpilingOnAdd": "{{pokemonNameWithAffix}}は {{stockpiledCount}}つ たくわえた!" } as const; From fe429d0c8ca6e42250ec5513a85f46b1d1a0b176 Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Fri, 9 Aug 2024 06:40:00 -0700 Subject: [PATCH 049/282] [Test] Fix hyper beam and purify test rng (#3449) --- src/test/moves/hyper_beam.test.ts | 1 + src/test/moves/purify.test.ts | 4 ++++ 2 files changed, 5 insertions(+) diff --git a/src/test/moves/hyper_beam.test.ts b/src/test/moves/hyper_beam.test.ts index 369d4cac853..f33ce4f5478 100644 --- a/src/test/moves/hyper_beam.test.ts +++ b/src/test/moves/hyper_beam.test.ts @@ -33,6 +33,7 @@ describe("Moves - Hyper Beam", () => { game.override.enemySpecies(Species.SNORLAX); game.override.enemyAbility(Abilities.BALL_FETCH); game.override.enemyMoveset(Array(4).fill(Moves.SPLASH)); + game.override.enemyLevel(100); game.override.moveset([Moves.HYPER_BEAM, Moves.TACKLE]); vi.spyOn(allMoves[Moves.HYPER_BEAM], "accuracy", "get").mockReturnValue(100); diff --git a/src/test/moves/purify.test.ts b/src/test/moves/purify.test.ts index 0367cc5a9b2..69d20ca0cc0 100644 --- a/src/test/moves/purify.test.ts +++ b/src/test/moves/purify.test.ts @@ -7,6 +7,8 @@ import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; +import { mockTurnOrder } from "../utils/testUtils"; +import { BattlerIndex } from "#app/battle.js"; const TIMEOUT = 20 * 1000; @@ -49,6 +51,7 @@ describe("Moves - Purify", () => { enemyPokemon.status = new Status(StatusEffect.BURN); game.doAttack(getMovePosition(game.scene, 0, Moves.PURIFY)); + await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEndPhase); expect(enemyPokemon.status).toBeNull(); @@ -68,6 +71,7 @@ describe("Moves - Purify", () => { const playerInitialHp = playerPokemon.hp; game.doAttack(getMovePosition(game.scene, 0, Moves.PURIFY)); + await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEndPhase); expect(playerPokemon.hp).toBe(playerInitialHp); From 57a4e1cc478d72dc57beb41a7718e01eaae78ea5 Mon Sep 17 00:00:00 2001 From: schmidtc1 <62030095+schmidtc1@users.noreply.github.com> Date: Fri, 9 Aug 2024 10:16:38 -0400 Subject: [PATCH 050/282] [Bug] Fixes bug with freezy frost not eliminating all Pokemon's stat changes (#3362) * Cherrypick due to beta roll back * Adds corrected stat eliminated message to move trigger, removes from battle.ts * Adds check for Clear Smog vs Haze/Freezy Frost for targetting purposes * Adds translations for fr, de, and pt_br * Update src/locales/ko/move-trigger.ts with translation Co-authored-by: sodam <66295123+sodaMelon@users.noreply.github.com> * Update korean move-trigger.ts with proper translation * Update src/locales/zh_CN/move-trigger.ts with translation Co-authored-by: mercurius-00 <80205689+mercurius-00@users.noreply.github.com> * Update src/locales/zh_TW/move-trigger.ts with translation Co-authored-by: mercurius-00 <80205689+mercurius-00@users.noreply.github.com> * Adds locales to ja and ca-ES * Creates unit test for Haze * Removes repeats option on Haze test left from testing * Updates title of haze tests, creates freezy frost tests * Update src/locales/es/move-trigger.ts with translation Co-authored-by: Asdar * Fixes freezy_frost.test.ts copy errors from Haze test --------- Co-authored-by: sodam <66295123+sodaMelon@users.noreply.github.com> Co-authored-by: mercurius-00 <80205689+mercurius-00@users.noreply.github.com> Co-authored-by: Asdar --- src/data/move.ts | 34 ++++++++---- src/locales/ca_ES/move-trigger.ts | 1 + src/locales/de/move-trigger.ts | 1 + src/locales/en/move-trigger.ts | 1 + src/locales/es/move-trigger.ts | 1 + src/locales/fr/move-trigger.ts | 1 + src/locales/it/move-trigger.ts | 1 + src/locales/ja/move-trigger.ts | 1 + src/locales/ko/move-trigger.ts | 1 + src/locales/pt_BR/move-trigger.ts | 1 + src/locales/zh_CN/move-trigger.ts | 1 + src/locales/zh_TW/move-trigger.ts | 1 + src/test/moves/freezy_frost.test.ts | 82 +++++++++++++++++++++++++++++ src/test/moves/haze.test.ts | 80 ++++++++++++++++++++++++++++ 14 files changed, 196 insertions(+), 11 deletions(-) create mode 100644 src/test/moves/freezy_frost.test.ts create mode 100644 src/test/moves/haze.test.ts diff --git a/src/data/move.ts b/src/data/move.ts index 2d0ea11c3a0..26652d182ca 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -2742,21 +2742,34 @@ export class InvertStatsAttr extends MoveEffectAttr { } export class ResetStatsAttr extends MoveEffectAttr { + private targetAllPokemon: boolean; + constructor(targetAllPokemon: boolean) { + super(); + this.targetAllPokemon = targetAllPokemon; + } apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { if (!super.apply(user, target, move, args)) { return false; } - for (let s = 0; s < target.summonData.battleStats.length; s++) { - target.summonData.battleStats[s] = 0; + if (this.targetAllPokemon) { // Target all pokemon on the field when Freezy Frost or Haze are used + const activePokemon = user.scene.getField(true); + activePokemon.forEach(p => this.resetStats(p)); + target.scene.queueMessage(i18next.t("moveTriggers:statEliminated")); + } else { // Affects only the single target when Clear Smog is used + this.resetStats(target); + target.scene.queueMessage(i18next.t("moveTriggers:resetStats", {pokemonName: getPokemonNameWithAffix(target)})); } - target.updateInfo(); - user.updateInfo(); - - target.scene.queueMessage(i18next.t("moveTriggers:resetStats", {pokemonName: getPokemonNameWithAffix(target)})); return true; } + + resetStats(pokemon: Pokemon) { + for (let s = 0; s < pokemon.summonData.battleStats.length; s++) { + pokemon.summonData.battleStats[s] = 0; + } + pokemon.updateInfo(); + } } /** @@ -6437,9 +6450,8 @@ export function initMoves() { new StatusMove(Moves.LIGHT_SCREEN, Type.PSYCHIC, -1, 30, -1, 0, 1) .attr(AddArenaTagAttr, ArenaTagType.LIGHT_SCREEN, 5, true) .target(MoveTarget.USER_SIDE), - new StatusMove(Moves.HAZE, Type.ICE, -1, 30, -1, 0, 1) - .target(MoveTarget.BOTH_SIDES) - .attr(ResetStatsAttr), + new SelfStatusMove(Moves.HAZE, Type.ICE, -1, 30, -1, 0, 1) + .attr(ResetStatsAttr, true), new StatusMove(Moves.REFLECT, Type.PSYCHIC, -1, 20, -1, 0, 1) .attr(AddArenaTagAttr, ArenaTagType.REFLECT, 5, true) .target(MoveTarget.USER_SIDE), @@ -7526,7 +7538,7 @@ export function initMoves() { new AttackMove(Moves.CHIP_AWAY, Type.NORMAL, MoveCategory.PHYSICAL, 70, 100, 20, -1, 0, 5) .attr(IgnoreOpponentStatChangesAttr), new AttackMove(Moves.CLEAR_SMOG, Type.POISON, MoveCategory.SPECIAL, 50, -1, 15, -1, 0, 5) - .attr(ResetStatsAttr), + .attr(ResetStatsAttr, false), new AttackMove(Moves.STORED_POWER, Type.PSYCHIC, MoveCategory.SPECIAL, 20, 100, 10, -1, 0, 5) .attr(StatChangeCountPowerAttr), new StatusMove(Moves.QUICK_GUARD, Type.FIGHTING, -1, 15, -1, 3, 5) @@ -8232,7 +8244,7 @@ export function initMoves() { .makesContact(false) .attr(AddBattlerTagAttr, BattlerTagType.SEEDED), new AttackMove(Moves.FREEZY_FROST, Type.ICE, MoveCategory.SPECIAL, 100, 90, 10, -1, 0, 7) - .attr(ResetStatsAttr), + .attr(ResetStatsAttr, true), new AttackMove(Moves.SPARKLY_SWIRL, Type.FAIRY, MoveCategory.SPECIAL, 120, 85, 5, -1, 0, 7) .attr(PartyStatusCureAttr, null, Abilities.NONE), new AttackMove(Moves.VEEVEE_VOLLEY, Type.NORMAL, MoveCategory.PHYSICAL, -1, -1, 20, -1, 0, 7) diff --git a/src/locales/ca_ES/move-trigger.ts b/src/locales/ca_ES/move-trigger.ts index b85f27228be..dc6028b116e 100644 --- a/src/locales/ca_ES/move-trigger.ts +++ b/src/locales/ca_ES/move-trigger.ts @@ -56,6 +56,7 @@ export const moveTriggers: SimpleTranslationEntries = { "sacrificialFullRestore": "{{pokemonName}}'s Healing Wish\nwas granted!", "invertStats": "{{pokemonName}}'s stat changes\nwere all reversed!", "resetStats": "{{pokemonName}}'s stat changes\nwere eliminated!", + "statEliminated": "All stat changes were eliminated!", "faintCountdown": "{{pokemonName}}\nwill faint in {{turnCount}} turns.", "copyType": "{{pokemonName}}'s type became the same as\n{{targetPokemonName}}'s type!", "suppressAbilities": "{{pokemonName}}'s ability\nwas suppressed!", diff --git a/src/locales/de/move-trigger.ts b/src/locales/de/move-trigger.ts index 53c9c847b38..4af494dea3c 100644 --- a/src/locales/de/move-trigger.ts +++ b/src/locales/de/move-trigger.ts @@ -56,6 +56,7 @@ export const moveTriggers: SimpleTranslationEntries = { "sacrificialFullRestore": "Das Heilopfer von {{pokemonName}} erreicht sein Ziel!", "invertStats": "Alle Statusveränderungen von {{pokemonName}} wurden invertiert!", "resetStats": "Die Statusveränderungen von {{pokemonName}} wurden aufgehoben!", + "statEliminated": "Alle Statusveränderungen wurden aufgehoben!", "faintCountdown": "{{pokemonName}} geht nach {{turnCount}} Runden K.O.!", "copyType": "{{pokemonName}} hat den Typ von {{targetPokemonName}} angenommen!", "suppressAbilities": "Die Fähigkeit von {{pokemonName}} wirkt nicht mehr!", diff --git a/src/locales/en/move-trigger.ts b/src/locales/en/move-trigger.ts index b85f27228be..dc6028b116e 100644 --- a/src/locales/en/move-trigger.ts +++ b/src/locales/en/move-trigger.ts @@ -56,6 +56,7 @@ export const moveTriggers: SimpleTranslationEntries = { "sacrificialFullRestore": "{{pokemonName}}'s Healing Wish\nwas granted!", "invertStats": "{{pokemonName}}'s stat changes\nwere all reversed!", "resetStats": "{{pokemonName}}'s stat changes\nwere eliminated!", + "statEliminated": "All stat changes were eliminated!", "faintCountdown": "{{pokemonName}}\nwill faint in {{turnCount}} turns.", "copyType": "{{pokemonName}}'s type became the same as\n{{targetPokemonName}}'s type!", "suppressAbilities": "{{pokemonName}}'s ability\nwas suppressed!", diff --git a/src/locales/es/move-trigger.ts b/src/locales/es/move-trigger.ts index a1d9f2e3185..e9bd5523c71 100644 --- a/src/locales/es/move-trigger.ts +++ b/src/locales/es/move-trigger.ts @@ -56,6 +56,7 @@ export const moveTriggers: SimpleTranslationEntries = { "sacrificialFullRestore": "{{pokemonName}}'s Healing Wish\nwas granted!", "invertStats": "{{pokemonName}}'s stat changes\nwere all reversed!", "resetStats": "{{pokemonName}}'s stat changes\nwere eliminated!", + "statEliminated": "¡Los cambios en estadísticas fueron eliminados!", "faintCountdown": "{{pokemonName}}\nwill faint in {{turnCount}} turns.", "copyType": "{{pokemonName}}'s type\nchanged to match {{targetPokemonName}}'s!", "suppressAbilities": "{{pokemonName}}'s ability\nwas suppressed!", diff --git a/src/locales/fr/move-trigger.ts b/src/locales/fr/move-trigger.ts index 7f9f3a471c6..0bec4de6467 100644 --- a/src/locales/fr/move-trigger.ts +++ b/src/locales/fr/move-trigger.ts @@ -56,6 +56,7 @@ export const moveTriggers: SimpleTranslationEntries = { "sacrificialFullRestore": "Le Vœu Soin est exaucé et profite\nà {{pokemonName}} !", "invertStats": "Les changements de stats\nde {{pokemonName}} sont inversés !", "resetStats": "Les changements de stats\nde {{pokemonName}} ont tous été annulés !", + "statEliminated": "Les changements de stats ont tous été annulés !", "faintCountdown": "{{pokemonName}}\nsera K.O. dans {{turnCount}} tours !", "copyType": "{{pokemonName}} prend le type\nde {{targetPokemonName}} !", "suppressAbilities": "Le talent de {{pokemonName}}\na été rendu inactif !", diff --git a/src/locales/it/move-trigger.ts b/src/locales/it/move-trigger.ts index badf2777d6f..ab17000a95d 100644 --- a/src/locales/it/move-trigger.ts +++ b/src/locales/it/move-trigger.ts @@ -56,6 +56,7 @@ export const moveTriggers: SimpleTranslationEntries = { "sacrificialFullRestore": "{{pokemonName}} riceve i benefici\neffetti di Curardore!", "invertStats": "Le modifiche alle statistiche di {{pokemonName}}\nvengono invertite!", "resetStats": "Tutte le modifiche alle statistiche sono state annullate!", + "statEliminated": "All stat changes were eliminated!", "faintCountdown": "{{pokemonName}}\nandrà KO dopo {{turnCount}} turni.", "copyType": "{{pokemonName}} assume il tipo\ndi {{targetPokemonName}}!", "suppressAbilities": "L’abilità di {{pokemonName}}\nperde ogni efficacia!", diff --git a/src/locales/ja/move-trigger.ts b/src/locales/ja/move-trigger.ts index 7c794379f55..dd741643888 100644 --- a/src/locales/ja/move-trigger.ts +++ b/src/locales/ja/move-trigger.ts @@ -56,6 +56,7 @@ export const moveTriggers: SimpleTranslationEntries = { "sacrificialFullRestore": "{{pokemonName}}の\nねがいごとが かなった!", "invertStats": "{{pokemonName}}の\nのうりょくへんかが ぎゃくてんした!", "resetStats": "{{pokemonName}}の\nのうりょくへんかが もとにもどった!", + "statEliminated": "All stat changes were eliminated!", "faintCountdown": "{{pokemonName}}は\n{{turnCount}}ターンごに ほろびてしまう!", "copyType": "{{pokemonName}}は {{targetPokemonName}}と\n同じタイプに なった!", "suppressAbilities": "{{pokemonName}}の とくせいが きかなくなった!", diff --git a/src/locales/ko/move-trigger.ts b/src/locales/ko/move-trigger.ts index 4c32e5b5b9f..ec4edb8d2ca 100644 --- a/src/locales/ko/move-trigger.ts +++ b/src/locales/ko/move-trigger.ts @@ -56,6 +56,7 @@ export const moveTriggers: SimpleTranslationEntries = { "sacrificialFullRestore": "{{pokemonName}}의\n치유소원이 이루어졌다!", "invertStats": "{{pokemonName}}[[는]]\n능력 변화가 뒤집혔다!", "resetStats": "{{pokemonName}}의 모든 상태가\n원래대로 되돌아왔다!", + "statEliminated": "모든 상태가 원래대로 되돌아왔다!", "faintCountdown": "{{pokemonName}}[[는]]\n{{turnCount}}턴 후에 쓰러져 버린다!", "copyType": "{{pokemonName}}[[는]]\n{{targetPokemonName}}[[와]] 같은 타입이 되었다!", "suppressAbilities": "{{pokemonName}}의\n특성이 효과를 발휘하지 못하게 되었다!", diff --git a/src/locales/pt_BR/move-trigger.ts b/src/locales/pt_BR/move-trigger.ts index a96cdb27953..a6a6e198b8f 100644 --- a/src/locales/pt_BR/move-trigger.ts +++ b/src/locales/pt_BR/move-trigger.ts @@ -56,6 +56,7 @@ export const moveTriggers: SimpleTranslationEntries = { "sacrificialFullRestore": "O Healing Wish de {{pokemonName}}\nfoi concedido!", "invertStats": "As mudanças de atributo de {{pokemonName}}\nforam revertidas!", "resetStats": "As mudanças de atributo de {{pokemonName}}\nforam eliminadas!", + "statEliminated": "Todas as mudanças de atributo foram eliminadas!", "faintCountdown": "{{pokemonName}}\nirá desmaiar em {{turnCount}} turnos.", "copyType": "O tipo de {{pokemonName}}\nmudou para combinar com {{targetPokemonName}}!", "suppressAbilities": "A habilidade de {{pokemonName}}\nfoi suprimida!", diff --git a/src/locales/zh_CN/move-trigger.ts b/src/locales/zh_CN/move-trigger.ts index d46ef1e313e..334e66ee33a 100644 --- a/src/locales/zh_CN/move-trigger.ts +++ b/src/locales/zh_CN/move-trigger.ts @@ -56,6 +56,7 @@ export const moveTriggers: SimpleTranslationEntries = { "sacrificialFullRestore": "{{pokemonName}}的\n治愈之愿实现了!", "invertStats": "{{pokemonName}}的\n能力变化颠倒过来了!", "resetStats": "{{pokemonName}}的\n能力变化复原了!", + "statEliminated": "所有能力都复原了!", "faintCountdown": "{{pokemonName}}\n将在{{turnCount}}回合后灭亡!", "copyType": "{{pokemonName}}\n变成了{{targetPokemonName}}的属性!", "suppressAbilities": "{{pokemonName}}的特性\n变得无效了!", diff --git a/src/locales/zh_TW/move-trigger.ts b/src/locales/zh_TW/move-trigger.ts index 0831ef82637..5342e08ed85 100644 --- a/src/locales/zh_TW/move-trigger.ts +++ b/src/locales/zh_TW/move-trigger.ts @@ -56,6 +56,7 @@ export const moveTriggers: SimpleTranslationEntries = { "sacrificialFullRestore": "{{pokemonName}}的\n治癒之願實現了!", "invertStats": "{{pokemonName}}的\n能力變化顛倒過來了!", "resetStats": "{{pokemonName}}的\n能力變化復原了!", + "statEliminated": "所有能力都復原了!", "faintCountdown": "{{pokemonName}}\n將在{{turnCount}}回合後滅亡!", "copyType": "{{pokemonName}}變成了{{targetPokemonName}}的屬性!", "suppressAbilities": "{{pokemonName}}的特性\n變得無效了!", diff --git a/src/test/moves/freezy_frost.test.ts b/src/test/moves/freezy_frost.test.ts new file mode 100644 index 00000000000..3ccd31bd29e --- /dev/null +++ b/src/test/moves/freezy_frost.test.ts @@ -0,0 +1,82 @@ +import { BattleStat } from "#app/data/battle-stat"; +import { MoveEndPhase, TurnInitPhase } from "#app/phases"; +import GameManager from "#test/utils/gameManager"; +import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; +import { allMoves } from "#app/data/move.js"; + +describe("Moves - Freezy Frost", () => { + describe("integration tests", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ type: Phaser.HEADLESS }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + + game.override.battleType("single"); + + game.override.enemySpecies(Species.RATTATA); + game.override.enemyLevel(100); + game.override.enemyMoveset(SPLASH_ONLY); + game.override.enemyAbility(Abilities.NONE); + + game.override.startingLevel(100); + game.override.moveset([Moves.FREEZY_FROST, Moves.SWORDS_DANCE, Moves.CHARM, Moves.SPLASH]); + vi.spyOn(allMoves[Moves.FREEZY_FROST], "accuracy", "get").mockReturnValue(100); + game.override.ability(Abilities.NONE); + }); + + it("Uses Swords Dance to raise own ATK by 2, Charm to lower enemy ATK by 2, player uses Freezy Frost to clear all stat changes", { timeout: 10000 }, async () => { + await game.startBattle([Species.RATTATA]); + const user = game.scene.getPlayerPokemon()!; + const enemy = game.scene.getEnemyPokemon()!; + expect(user.summonData.battleStats[BattleStat.ATK]).toBe(0); + expect(enemy.summonData.battleStats[BattleStat.ATK]).toBe(0); + + game.doAttack(getMovePosition(game.scene, 0, Moves.SWORDS_DANCE)); + await game.phaseInterceptor.to(TurnInitPhase); + + game.doAttack(getMovePosition(game.scene, 0, Moves.CHARM)); + await game.phaseInterceptor.to(TurnInitPhase); + const userAtkBefore = user.summonData.battleStats[BattleStat.ATK]; + const enemyAtkBefore = enemy.summonData.battleStats[BattleStat.ATK]; + expect(userAtkBefore).toBe(2); + expect(enemyAtkBefore).toBe(-2); + + game.doAttack(getMovePosition(game.scene, 0, Moves.FREEZY_FROST)); + await game.phaseInterceptor.to(TurnInitPhase); + expect(user.summonData.battleStats[BattleStat.ATK]).toBe(0); + expect(enemy.summonData.battleStats[BattleStat.ATK]).toBe(0); + }); + + it("Uses Swords Dance to raise own ATK by 2, Charm to lower enemy ATK by 2, enemy uses Freezy Frost to clear all stat changes", { timeout: 10000 }, async () => { + game.override.enemyMoveset([Moves.FREEZY_FROST, Moves.FREEZY_FROST, Moves.FREEZY_FROST, Moves.FREEZY_FROST]); + await game.startBattle([Species.SHUCKLE]); // Shuckle for slower Swords Dance on first turn so Freezy Frost doesn't affect it. + const user = game.scene.getPlayerPokemon()!; + expect(user.summonData.battleStats[BattleStat.ATK]).toBe(0); + + game.doAttack(getMovePosition(game.scene, 0, Moves.SWORDS_DANCE)); + await game.phaseInterceptor.to(TurnInitPhase); + + const userAtkBefore = user.summonData.battleStats[BattleStat.ATK]; + expect(userAtkBefore).toBe(2); + + game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + await game.phaseInterceptor.to(MoveEndPhase); + expect(user.summonData.battleStats[BattleStat.ATK]).toBe(0); + }); + }); +}); diff --git a/src/test/moves/haze.test.ts b/src/test/moves/haze.test.ts new file mode 100644 index 00000000000..092575b8000 --- /dev/null +++ b/src/test/moves/haze.test.ts @@ -0,0 +1,80 @@ +import { BattleStat } from "#app/data/battle-stat"; +import { MoveEndPhase, TurnInitPhase } from "#app/phases"; +import GameManager from "#test/utils/gameManager"; +import { getMovePosition } from "#test/utils/gameManagerUtils"; +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; + +describe("Moves - Haze", () => { + describe("integration tests", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ type: Phaser.HEADLESS }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + + game.override.battleType("single"); + + game.override.enemySpecies(Species.RATTATA); + game.override.enemyLevel(100); + game.override.enemyMoveset(SPLASH_ONLY); + game.override.enemyAbility(Abilities.NONE); + + game.override.startingLevel(100); + game.override.moveset([Moves.HAZE, Moves.SWORDS_DANCE, Moves.CHARM, Moves.SPLASH]); + game.override.ability(Abilities.NONE); + }); + + it("Uses Swords Dance to raise own ATK by 2, Charm to lower enemy ATK by 2, player uses Haze to clear all stat changes", { timeout: 10000 }, async () => { + await game.startBattle([Species.RATTATA]); + const user = game.scene.getPlayerPokemon()!; + const enemy = game.scene.getEnemyPokemon()!; + expect(user.summonData.battleStats[BattleStat.ATK]).toBe(0); + expect(enemy.summonData.battleStats[BattleStat.ATK]).toBe(0); + + game.doAttack(getMovePosition(game.scene, 0, Moves.SWORDS_DANCE)); + await game.phaseInterceptor.to(TurnInitPhase); + + game.doAttack(getMovePosition(game.scene, 0, Moves.CHARM)); + await game.phaseInterceptor.to(TurnInitPhase); + const userAtkBefore = user.summonData.battleStats[BattleStat.ATK]; + const enemyAtkBefore = enemy.summonData.battleStats[BattleStat.ATK]; + expect(userAtkBefore).toBe(2); + expect(enemyAtkBefore).toBe(-2); + + game.doAttack(getMovePosition(game.scene, 0, Moves.HAZE)); + await game.phaseInterceptor.to(TurnInitPhase); + expect(user.summonData.battleStats[BattleStat.ATK]).toBe(0); + expect(enemy.summonData.battleStats[BattleStat.ATK]).toBe(0); + }); + + it("Uses Swords Dance to raise own ATK by 2, Charm to lower enemy ATK by 2, enemy uses Haze to clear all stat changes", { timeout: 10000 }, async () => { + game.override.enemyMoveset([Moves.HAZE, Moves.HAZE, Moves.HAZE, Moves.HAZE]); + await game.startBattle([Species.SHUCKLE]); // Shuckle for slower Swords Dance on first turn so Haze doesn't affect it. + const user = game.scene.getPlayerPokemon()!; + expect(user.summonData.battleStats[BattleStat.ATK]).toBe(0); + + game.doAttack(getMovePosition(game.scene, 0, Moves.SWORDS_DANCE)); + await game.phaseInterceptor.to(TurnInitPhase); + + const userAtkBefore = user.summonData.battleStats[BattleStat.ATK]; + expect(userAtkBefore).toBe(2); + + game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + await game.phaseInterceptor.to(MoveEndPhase); + expect(user.summonData.battleStats[BattleStat.ATK]).toBe(0); + }); + }); +}); From d2eea967771d3573f60f9c5c8beb07a3a51a6d5d Mon Sep 17 00:00:00 2001 From: Leo Kim <47556641+KimJeongSun@users.noreply.github.com> Date: Fri, 9 Aug 2024 23:17:18 +0900 Subject: [PATCH 051/282] [Enhancement] Allow nickname assignment in the starter select UI. (#3456) * add rename nickname in starter UI * update requested changes --- src/phases.ts | 5 ++++ src/system/game-data.ts | 1 + src/ui/rename-form-ui-handler.ts | 14 ++++------- src/ui/starter-select-ui-handler.ts | 38 +++++++++++++++++++++++++++-- 4 files changed, 47 insertions(+), 11 deletions(-) diff --git a/src/phases.ts b/src/phases.ts index db14dc022c4..46d1f4b98db 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -622,6 +622,11 @@ export class SelectStarterPhase extends Phase { if (starter.pokerus) { starterPokemon.pokerus = true; } + + if (starter.nickname) { + starterPokemon.nickname = starter.nickname; + } + if (this.scene.gameMode.isSplicedOnly) { starterPokemon.generateFusionSpecies(true); } diff --git a/src/system/game-data.ts b/src/system/game-data.ts index b483ada2829..0d35032d19b 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -198,6 +198,7 @@ export interface StarterAttributes { form?: integer; female?: boolean; shiny?: boolean; + nickname?: string; } export interface StarterPreferences { diff --git a/src/ui/rename-form-ui-handler.ts b/src/ui/rename-form-ui-handler.ts index 35127564b60..33885509344 100644 --- a/src/ui/rename-form-ui-handler.ts +++ b/src/ui/rename-form-ui-handler.ts @@ -36,17 +36,13 @@ export default class RenameFormUiHandler extends FormModalUiHandler { show(args: any[]): boolean { if (super.show(args)) { const config = args[0] as ModalConfig; - this.inputs[0].text = (args[1] as PlayerPokemon).getNameToRender(); - + if (args[1] && typeof (args[1] as PlayerPokemon).getNameToRender === "function") { + this.inputs[0].text = (args[1] as PlayerPokemon).getNameToRender(); + } else { + this.inputs[0].text = args[1]; + } this.submitAction = (_) => { this.sanitizeInputs(); - // const onFail = () => { - // this.scene.ui.setModeWithoutClear(Mode.RENAME_POKEMON, Object.assign(config)); - // this.scene.ui.playError(); - // }; - // if (!this.inputs[0].text) { - // return onFail(); - // } const sanitizedName = btoa(unescape(encodeURIComponent(this.inputs[0].text))); config.buttonActions[0](sanitizedName); return true; diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index 43af8d456c1..df661c37fa4 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -55,6 +55,7 @@ export interface Starter { nature: Nature; moveset?: StarterMoveset; pokerus: boolean; + nickname?: string; } interface LanguageSetting { @@ -1542,6 +1543,33 @@ export default class StarterSelectUiHandler extends MessageUiHandler { }); } } + options.push({ + label: i18next.t("menu:rename"), + handler: () => { + ui.playSelect(); + let nickname = starterAttributes.nickname ? String(starterAttributes.nickname) : ""; + nickname = decodeURIComponent(escape(atob(nickname))); + ui.setModeWithoutClear(Mode.RENAME_POKEMON, { + buttonActions: [ + (sanitizedName: string) => { + ui.playSelect(); + starterAttributes.nickname = sanitizedName; + const name = decodeURIComponent(escape(atob(starterAttributes.nickname))); + if (name.length > 0) { + this.pokemonNameText.setText(name); + } else { + this.pokemonNameText.setText(species.name); + } + ui.setMode(Mode.STARTER_SELECT); + }, + () => { + ui.setMode(Mode.STARTER_SELECT); + } + ] + }, nickname); + return true; + } + }); const showUseCandies = () => { // this lets you use your candies const options: any[] = []; // TODO: add proper type if (!(passiveAttr & PassiveAttr.UNLOCKED)) { @@ -2573,7 +2601,12 @@ export default class StarterSelectUiHandler extends MessageUiHandler { if (species && (this.speciesStarterDexEntry?.seenAttr || this.speciesStarterDexEntry?.caughtAttr)) { this.pokemonNumberText.setText(Utils.padInt(species.speciesId, 4)); - this.pokemonNameText.setText(species.name); + if (starterAttributes?.nickname) { + const name = decodeURIComponent(escape(atob(starterAttributes.nickname))); + this.pokemonNameText.setText(name); + } else { + this.pokemonNameText.setText(species.name); + } if (this.speciesStarterDexEntry?.caughtAttr) { const colorScheme = starterColors[species.speciesId]; @@ -3215,7 +3248,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler { passive: !(thisObj.scene.gameData.starterData[starterSpecies.speciesId].passiveAttr ^ (PassiveAttr.ENABLED | PassiveAttr.UNLOCKED)), nature: thisObj.starterNatures[i] as Nature, moveset: thisObj.starterMovesets[i], - pokerus: thisObj.pokerusSpecies.includes(starterSpecies) + pokerus: thisObj.pokerusSpecies.includes(starterSpecies), + nickname: thisObj.starterPreferences[starterSpecies.speciesId]?.nickname, }; })); }; From 14b3907b11092df723b9bb24e36e4d4e115b51b6 Mon Sep 17 00:00:00 2001 From: Leo Kim <47556641+KimJeongSun@users.noreply.github.com> Date: Fri, 9 Aug 2024 23:32:30 +0900 Subject: [PATCH 052/282] [Enhancement] Add favorite filter in Starter UI (#3431) * add favorite filter. add favorite starter attribute * add error handling for undefined favorite attribute * add placeholders in each locales * add favorite icon from great art team * update favorite icon to code * update korean translation * align icons * initialize the starter preferences if they don't exist * update requested changes --- public/images/ui/favorite.png | Bin 0 -> 226 bytes public/images/ui/legacy/favorite.png | Bin 0 -> 226 bytes src/loading-scene.ts | 1 + src/locales/ca_ES/filter-bar.ts | 3 ++ .../ca_ES/starter-select-ui-handler.ts | 2 + src/locales/de/filter-bar.ts | 3 ++ src/locales/de/starter-select-ui-handler.ts | 2 + src/locales/en/filter-bar.ts | 3 ++ src/locales/en/starter-select-ui-handler.ts | 2 + src/locales/es/filter-bar.ts | 3 ++ src/locales/es/starter-select-ui-handler.ts | 2 + src/locales/fr/filter-bar.ts | 3 ++ src/locales/fr/starter-select-ui-handler.ts | 2 + src/locales/it/filter-bar.ts | 3 ++ src/locales/it/starter-select-ui-handler.ts | 2 + src/locales/ja/filter-bar.ts | 23 +++++++-- src/locales/ja/starter-select-ui-handler.ts | 2 + src/locales/ko/filter-bar.ts | 3 ++ src/locales/ko/starter-select-ui-handler.ts | 2 + src/locales/pt_BR/filter-bar.ts | 3 ++ .../pt_BR/starter-select-ui-handler.ts | 2 + src/locales/zh_CN/filter-bar.ts | 3 ++ .../zh_CN/starter-select-ui-handler.ts | 2 + src/locales/zh_TW/filter-bar.ts | 3 ++ .../zh_TW/starter-select-ui-handler.ts | 2 + src/system/game-data.ts | 1 + src/ui/starter-container.ts | 11 +++- src/ui/starter-select-ui-handler.ts | 47 +++++++++++++++++- 28 files changed, 129 insertions(+), 6 deletions(-) create mode 100644 public/images/ui/favorite.png create mode 100644 public/images/ui/legacy/favorite.png diff --git a/public/images/ui/favorite.png b/public/images/ui/favorite.png new file mode 100644 index 0000000000000000000000000000000000000000..d86dd58f5ab80374a431fab403d39ae616d25de4 GIT binary patch literal 226 zcmeAS@N?(olHy`uVBq!ia0vp^93afW1|*O0@9PFqjKx9jP7LeL$-D$|nmk<`LnNlQ zp5MrMC_%*aq5h}qVP;9oEt+>UdLPluxpPoc#*t%3Q{(}qjHOEi6;);gb!T`8ekgms z?{Ks9!5XXT*Pdm2T^_P8|9dLAoPF`xBT2O^jIVyVhMqbXzfj6dmaTUE?w{H%dNT7= zBffFowwT(osL>)N~_);T0(|mmyw18}oyFuVm Q@MI9>>FVdQ&MBb@0Ax#0x&QzG literal 0 HcmV?d00001 diff --git a/public/images/ui/legacy/favorite.png b/public/images/ui/legacy/favorite.png new file mode 100644 index 0000000000000000000000000000000000000000..d86dd58f5ab80374a431fab403d39ae616d25de4 GIT binary patch literal 226 zcmeAS@N?(olHy`uVBq!ia0vp^93afW1|*O0@9PFqjKx9jP7LeL$-D$|nmk<`LnNlQ zp5MrMC_%*aq5h}qVP;9oEt+>UdLPluxpPoc#*t%3Q{(}qjHOEi6;);gb!T`8ekgms z?{Ks9!5XXT*Pdm2T^_P8|9dLAoPF`xBT2O^jIVyVhMqbXzfj6dmaTUE?w{H%dNT7= zBffFowwT(osL>)N~_);T0(|mmyw18}oyFuVm Q@MI9>>FVdQ&MBb@0Ax#0x&QzG literal 0 HcmV?d00001 diff --git a/src/loading-scene.ts b/src/loading-scene.ts index c00112318c8..9021f638cea 100644 --- a/src/loading-scene.ts +++ b/src/loading-scene.ts @@ -93,6 +93,7 @@ export class LoadingScene extends SceneBase { this.loadImage("shiny_star_small", "ui", "shiny_small.png"); this.loadImage("shiny_star_small_1", "ui", "shiny_small_1.png"); this.loadImage("shiny_star_small_2", "ui", "shiny_small_2.png"); + this.loadImage("favorite", "ui", "favorite.png"); this.loadImage("passive_bg", "ui", "passive_bg.png"); this.loadAtlas("shiny_icons", "ui"); this.loadImage("ha_capsule", "ui", "ha_capsule.png"); diff --git a/src/locales/ca_ES/filter-bar.ts b/src/locales/ca_ES/filter-bar.ts index 7a3174957ea..1c731d1deaa 100644 --- a/src/locales/ca_ES/filter-bar.ts +++ b/src/locales/ca_ES/filter-bar.ts @@ -16,6 +16,9 @@ export const filterBar: SimpleTranslationEntries = { "costReduction": "Cost Reduction", "costReductionUnlocked": "Cost Reduction Unlocked", "costReductionLocked": "Cost Reduction Locked", + "favorite": "Favorite", + "isFavorite": "Favorite - Yes", + "notFavorite": "Favorite - No", "ribbon": "Ribbon", "hasWon": "Ribbon - Yes", "hasNotWon": "Ribbon - No", diff --git a/src/locales/ca_ES/starter-select-ui-handler.ts b/src/locales/ca_ES/starter-select-ui-handler.ts index deb4236c8ba..476ee46ae8e 100644 --- a/src/locales/ca_ES/starter-select-ui-handler.ts +++ b/src/locales/ca_ES/starter-select-ui-handler.ts @@ -28,6 +28,8 @@ export const starterSelectUiHandler: SimpleTranslationEntries = { "toggleIVs": "Toggle IVs", "manageMoves": "Manage Moves", "manageNature": "Manage Nature", + "addToFavorites": "Add to Favorites", + "removeFromFavorites": "Remove from Favorites", "useCandies": "Use Candies", "selectNature": "Select nature.", "selectMoveSwapOut": "Select a move to swap out.", diff --git a/src/locales/de/filter-bar.ts b/src/locales/de/filter-bar.ts index 1094b0fd43a..7ed7098820b 100644 --- a/src/locales/de/filter-bar.ts +++ b/src/locales/de/filter-bar.ts @@ -16,6 +16,9 @@ export const filterBar: SimpleTranslationEntries = { "costReduction": "Cost Reduction", "costReductionUnlocked": "Cost Reduction Unlocked", "costReductionLocked": "Cost Reduction Locked", + "favorite": "Favorite", + "isFavorite": "Favorite - Yes", + "notFavorite": "Favorite - No", "ribbon": "Band", "hasWon": "Hat Klassik-Modus gewonnen", "hasNotWon": "Hat Klassik-Modus nicht gewonnen", diff --git a/src/locales/de/starter-select-ui-handler.ts b/src/locales/de/starter-select-ui-handler.ts index eb0d444cbd5..284152bbd33 100644 --- a/src/locales/de/starter-select-ui-handler.ts +++ b/src/locales/de/starter-select-ui-handler.ts @@ -28,6 +28,8 @@ export const starterSelectUiHandler: SimpleTranslationEntries = { "toggleIVs": "DVs anzeigen/verbergen", "manageMoves": "Attacken ändern", "manageNature": "Wesen ändern", + "addToFavorites": "Add to Favorites", + "removeFromFavorites": "Remove from Favorites", "useCandies": "Bonbons verwenden", "selectNature": "Wähle das neue Wesen.", "selectMoveSwapOut": "Wähle die zu ersetzende Attacke.", diff --git a/src/locales/en/filter-bar.ts b/src/locales/en/filter-bar.ts index 0961df9f058..1dd0c3b2b64 100644 --- a/src/locales/en/filter-bar.ts +++ b/src/locales/en/filter-bar.ts @@ -16,6 +16,9 @@ export const filterBar: SimpleTranslationEntries = { "costReduction": "Cost Reduction", "costReductionUnlocked": "Cost Reduction Unlocked", "costReductionLocked": "Cost Reduction Locked", + "favorite": "Favorite", + "isFavorite": "Favorite - Yes", + "notFavorite": "Favorite - No", "ribbon": "Ribbon", "hasWon": "Ribbon - Yes", "hasNotWon": "Ribbon - No", diff --git a/src/locales/en/starter-select-ui-handler.ts b/src/locales/en/starter-select-ui-handler.ts index 63641479585..5e82abc8187 100644 --- a/src/locales/en/starter-select-ui-handler.ts +++ b/src/locales/en/starter-select-ui-handler.ts @@ -28,6 +28,8 @@ export const starterSelectUiHandler: SimpleTranslationEntries = { "toggleIVs": "Toggle IVs", "manageMoves": "Manage Moves", "manageNature": "Manage Nature", + "addToFavorites": "Add to Favorites", + "removeFromFavorites": "Remove from Favorites", "useCandies": "Use Candies", "selectNature": "Select nature.", "selectMoveSwapOut": "Select a move to swap out.", diff --git a/src/locales/es/filter-bar.ts b/src/locales/es/filter-bar.ts index b55a35c1adf..b0eae7542ff 100644 --- a/src/locales/es/filter-bar.ts +++ b/src/locales/es/filter-bar.ts @@ -16,6 +16,9 @@ export const filterBar: SimpleTranslationEntries = { "costReduction": "Cost Reduction", "costReductionUnlocked": "Cost Reduction Unlocked", "costReductionLocked": "Cost Reduction Locked", + "favorite": "Favorite", + "isFavorite": "Favorite - Yes", + "notFavorite": "Favorite - No", "ribbon": "Ribbon", "hasWon": "Ya ha ganado", "hasNotWon": "Aún no ha ganado", diff --git a/src/locales/es/starter-select-ui-handler.ts b/src/locales/es/starter-select-ui-handler.ts index 3bb655ddceb..1a2be0d8b75 100644 --- a/src/locales/es/starter-select-ui-handler.ts +++ b/src/locales/es/starter-select-ui-handler.ts @@ -28,6 +28,8 @@ export const starterSelectUiHandler: SimpleTranslationEntries = { "toggleIVs": "Mostrar IVs", "manageMoves": "Cambiar movs.", "manageNature": "Cambiar natur.", + "addToFavorites": "Add to Favorites", + "removeFromFavorites": "Remove from Favorites", "useCandies": "Usar Caramelos", "selectNature": "Elige Natur.", "selectMoveSwapOut": "Elige el movimiento que sustituir.", diff --git a/src/locales/fr/filter-bar.ts b/src/locales/fr/filter-bar.ts index 13656192116..0c086c8e52c 100644 --- a/src/locales/fr/filter-bar.ts +++ b/src/locales/fr/filter-bar.ts @@ -16,6 +16,9 @@ export const filterBar: SimpleTranslationEntries = { "costReduction": "Cost Reduction", "costReductionUnlocked": "Cost Reduction Unlocked", "costReductionLocked": "Cost Reduction Locked", + "favorite": "Favorite", + "isFavorite": "Favorite - Yes", + "notFavorite": "Favorite - No", "ribbon": "Ruban", "hasWon": "Ruban - Oui", "hasNotWon": "Ruban - Non", diff --git a/src/locales/fr/starter-select-ui-handler.ts b/src/locales/fr/starter-select-ui-handler.ts index fbd407a1450..aea207b140d 100644 --- a/src/locales/fr/starter-select-ui-handler.ts +++ b/src/locales/fr/starter-select-ui-handler.ts @@ -28,6 +28,8 @@ export const starterSelectUiHandler: SimpleTranslationEntries = { "toggleIVs": "Voir les IV", "manageMoves": "Modifier les Capacités", "manageNature": "Modifier la Nature", + "addToFavorites": "Add to Favorites", + "removeFromFavorites": "Remove from Favorites", "useCandies": "Utiliser des Bonbons", "selectNature": "Sélectionnez une nature.", "selectMoveSwapOut": "Sélectionnez la capacité à échanger.", diff --git a/src/locales/it/filter-bar.ts b/src/locales/it/filter-bar.ts index c6fcb2f0623..fff93ad02d4 100644 --- a/src/locales/it/filter-bar.ts +++ b/src/locales/it/filter-bar.ts @@ -16,6 +16,9 @@ export const filterBar: SimpleTranslationEntries = { "costReduction": "Cost Reduction", "costReductionUnlocked": "Cost Reduction Unlocked", "costReductionLocked": "Cost Reduction Locked", + "favorite": "Favorite", + "isFavorite": "Favorite - Yes", + "notFavorite": "Favorite - No", "ribbon": "Ribbon", "hasWon": "Ribbon - Yes", "hasNotWon": "Ribbon - No", diff --git a/src/locales/it/starter-select-ui-handler.ts b/src/locales/it/starter-select-ui-handler.ts index 9ef5ccbe3ee..f92fb5b9f67 100644 --- a/src/locales/it/starter-select-ui-handler.ts +++ b/src/locales/it/starter-select-ui-handler.ts @@ -28,6 +28,8 @@ export const starterSelectUiHandler: SimpleTranslationEntries = { "toggleIVs": "Vedi/Nascondi IV", "manageMoves": "Gestisci mosse", "manageNature": "Gestisci natura", + "addToFavorites": "Add to Favorites", + "removeFromFavorites": "Remove from Favorites", "useCandies": "Usa caramelle", "selectNature": "Seleziona natura.", "selectMoveSwapOut": "Seleziona una mossa da scambiare.", diff --git a/src/locales/ja/filter-bar.ts b/src/locales/ja/filter-bar.ts index 60c6ffb1bbc..1dd0c3b2b64 100644 --- a/src/locales/ja/filter-bar.ts +++ b/src/locales/ja/filter-bar.ts @@ -3,16 +3,31 @@ import { SimpleTranslationEntries } from "#app/interfaces/locales"; export const filterBar: SimpleTranslationEntries = { "genFilter": "Gen", "typeFilter": "Type", + "caughtFilter": "Caught", "unlocksFilter": "Unlocks", - "winFilter": "Win", + "miscFilter": "Misc", "sortFilter": "Sort", "all": "All", - "normal": "Normal", + "normal": "Not Shiny", "uncaught": "Uncaught", + "passive": "Passive", "passiveUnlocked": "Passive Unlocked", "passiveLocked": "Passive Locked", - "hasWon": "Yes", - "hasNotWon": "No", + "costReduction": "Cost Reduction", + "costReductionUnlocked": "Cost Reduction Unlocked", + "costReductionLocked": "Cost Reduction Locked", + "favorite": "Favorite", + "isFavorite": "Favorite - Yes", + "notFavorite": "Favorite - No", + "ribbon": "Ribbon", + "hasWon": "Ribbon - Yes", + "hasNotWon": "Ribbon - No", + "hiddenAbility": "Hidden Ability", + "hasHiddenAbility": "Hidden Ability - Yes", + "noHiddenAbility": "Hidden Ability - No", + "pokerus": "Pokerus", + "hasPokerus": "Pokerus - Yes", + "noPokerus": "Pokerus - No", "sortByNumber": "No.", "sortByCost": "Cost", "sortByCandies": "Candy Count", diff --git a/src/locales/ja/starter-select-ui-handler.ts b/src/locales/ja/starter-select-ui-handler.ts index 095ceeb0ca1..fe4495a3a2f 100644 --- a/src/locales/ja/starter-select-ui-handler.ts +++ b/src/locales/ja/starter-select-ui-handler.ts @@ -28,6 +28,8 @@ export const starterSelectUiHandler: SimpleTranslationEntries = { "toggleIVs": "個体値を ひょうじ", "manageMoves": "わざを ならびかえ", "manageNature": "せいかくを ならびかえ", + "addToFavorites": "Add to Favorites", + "removeFromFavorites": "Remove from Favorites", "useCandies": "アメを つかう", "selectNature": "せいかくをえらんでください", "selectMoveSwapOut": "交換する技を選択してください", diff --git a/src/locales/ko/filter-bar.ts b/src/locales/ko/filter-bar.ts index b4dcb48b581..c597ad54ee8 100644 --- a/src/locales/ko/filter-bar.ts +++ b/src/locales/ko/filter-bar.ts @@ -16,6 +16,9 @@ export const filterBar: SimpleTranslationEntries = { "costReduction": "코스트 줄이기", "costReductionUnlocked": "코스트 절감됨", "costReductionLocked": "코스트 절감 없음", + "favorite": "즐겨찾기", + "isFavorite": "즐겨찾기 등록됨", + "notFavorite": "즐겨찾기 제외됨", "ribbon": "클리어 여부", "hasWon": "클리어 완료", "hasNotWon": "클리어 안함", diff --git a/src/locales/ko/starter-select-ui-handler.ts b/src/locales/ko/starter-select-ui-handler.ts index 722780807b6..9a33f8f1baf 100644 --- a/src/locales/ko/starter-select-ui-handler.ts +++ b/src/locales/ko/starter-select-ui-handler.ts @@ -28,6 +28,8 @@ export const starterSelectUiHandler: SimpleTranslationEntries = { "toggleIVs": "개체값 토글", "manageMoves": "기술 관리", "manageNature": "성격 관리", + "addToFavorites": "즐겨찾기에 추가", + "removeFromFavorites": "즐겨찾기에서 제외", "useCandies": "사탕 사용", "selectNature": "교체할 성격을 선택해주세요.", "selectMoveSwapOut": "교체할 기술을 선택해주세요.", diff --git a/src/locales/pt_BR/filter-bar.ts b/src/locales/pt_BR/filter-bar.ts index d08d2d28707..3ee41c6ead9 100644 --- a/src/locales/pt_BR/filter-bar.ts +++ b/src/locales/pt_BR/filter-bar.ts @@ -16,6 +16,9 @@ export const filterBar: SimpleTranslationEntries = { "costReduction": "Redução de Custo", "costReductionUnlocked": "Redução de Custo Desbloq.", "costReductionLocked": "Redução de Custo Bloq.", + "favorite": "Favorite", + "isFavorite": "Favorite - Yes", + "notFavorite": "Favorite - No", "ribbon": "Fita", "hasWon": "Fita - Sim", "hasNotWon": "Fita - Não", diff --git a/src/locales/pt_BR/starter-select-ui-handler.ts b/src/locales/pt_BR/starter-select-ui-handler.ts index 8bc045f76a9..2cec9a5335e 100644 --- a/src/locales/pt_BR/starter-select-ui-handler.ts +++ b/src/locales/pt_BR/starter-select-ui-handler.ts @@ -28,6 +28,8 @@ export const starterSelectUiHandler: SimpleTranslationEntries = { "toggleIVs": "Mostrar IVs", "manageMoves": "Mudar Movimentos", "manageNature": "Mudar Natureza", + "addToFavorites": "Add to Favorites", + "removeFromFavorites": "Remove from Favorites", "useCandies": "Usar Doces", "selectNature": "Escolha uma natureza.", "selectMoveSwapOut": "Escolha um movimento para substituir.", diff --git a/src/locales/zh_CN/filter-bar.ts b/src/locales/zh_CN/filter-bar.ts index 6f484fc8635..820091af06c 100644 --- a/src/locales/zh_CN/filter-bar.ts +++ b/src/locales/zh_CN/filter-bar.ts @@ -16,6 +16,9 @@ export const filterBar: SimpleTranslationEntries = { "costReduction": "费用降低", "costReductionUnlocked": "已降费", "costReductionLocked": "未降费", + "favorite": "Favorite", + "isFavorite": "Favorite - Yes", + "notFavorite": "Favorite - No", "ribbon": "缎带", "hasWon": "有缎带", "hasNotWon": "无缎带", diff --git a/src/locales/zh_CN/starter-select-ui-handler.ts b/src/locales/zh_CN/starter-select-ui-handler.ts index 39bab560eac..2b4fc4434da 100644 --- a/src/locales/zh_CN/starter-select-ui-handler.ts +++ b/src/locales/zh_CN/starter-select-ui-handler.ts @@ -28,6 +28,8 @@ export const starterSelectUiHandler: SimpleTranslationEntries = { "toggleIVs": "显示个体", "manageMoves": "管理招式", "manageNature": "管理性格", + "addToFavorites": "Add to Favorites", + "removeFromFavorites": "Remove from Favorites", "useCandies": "使用糖果", "selectNature": "选择性格", "selectMoveSwapOut": "选择要替换的招式。", diff --git a/src/locales/zh_TW/filter-bar.ts b/src/locales/zh_TW/filter-bar.ts index 8916088d884..18c09b629b0 100644 --- a/src/locales/zh_TW/filter-bar.ts +++ b/src/locales/zh_TW/filter-bar.ts @@ -16,6 +16,9 @@ export const filterBar: SimpleTranslationEntries = { "costReduction": "Cost Reduction", "costReductionUnlocked": "Cost Reduction Unlocked", "costReductionLocked": "Cost Reduction Locked", + "favorite": "Favorite", + "isFavorite": "Favorite - Yes", + "notFavorite": "Favorite - No", "ribbon": "緞帶", "hasWon": "有緞帶", "hasNotWon": "無緞帶", diff --git a/src/locales/zh_TW/starter-select-ui-handler.ts b/src/locales/zh_TW/starter-select-ui-handler.ts index 7aecd459178..ea4cb127fea 100644 --- a/src/locales/zh_TW/starter-select-ui-handler.ts +++ b/src/locales/zh_TW/starter-select-ui-handler.ts @@ -29,6 +29,8 @@ export const starterSelectUiHandler: SimpleTranslationEntries = { "toggleIVs": "查看個體值", "manageMoves": "管理技能", "manageNature": "管理性格", + "addToFavorites": "Add to Favorites", + "removeFromFavorites": "Remove from Favorites", "useCandies": "使用糖果", "selectNature": "選擇性格", "selectMoveSwapOut": "選擇想要替換走的招式", diff --git a/src/system/game-data.ts b/src/system/game-data.ts index 0d35032d19b..d64aa8f8e91 100644 --- a/src/system/game-data.ts +++ b/src/system/game-data.ts @@ -198,6 +198,7 @@ export interface StarterAttributes { form?: integer; female?: boolean; shiny?: boolean; + favorite?: boolean; nickname?: string; } diff --git a/src/ui/starter-container.ts b/src/ui/starter-container.ts index ae589d138b9..ce21d13add8 100644 --- a/src/ui/starter-container.ts +++ b/src/ui/starter-container.ts @@ -10,6 +10,7 @@ export class StarterContainer extends Phaser.GameObjects.Container { public label: Phaser.GameObjects.Text; public starterPassiveBgs: Phaser.GameObjects.Image; public hiddenAbilityIcon: Phaser.GameObjects.Image; + public favoriteIcon: Phaser.GameObjects.Image; public classicWinIcon: Phaser.GameObjects.Image; public candyUpgradeIcon: Phaser.GameObjects.Image; public candyUpgradeOverlayIcon: Phaser.GameObjects.Image; @@ -66,8 +67,16 @@ export class StarterContainer extends Phaser.GameObjects.Container { this.add(abilityIcon); this.hiddenAbilityIcon = abilityIcon; + // favorite icon + const favoriteIcon = this.scene.add.image(0, 7, "favorite"); + favoriteIcon.setOrigin(0, 0); + favoriteIcon.setScale(0.5); + favoriteIcon.setVisible(false); + this.add(favoriteIcon); + this.favoriteIcon = favoriteIcon; + // classic win icon - const classicWinIcon = this.scene.add.image(2, 12, "champion_ribbon"); + const classicWinIcon = this.scene.add.image(0, 12, "champion_ribbon"); classicWinIcon.setOrigin(0, 0); classicWinIcon.setScale(0.5); classicWinIcon.setVisible(false); diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index df661c37fa4..d65abf70134 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -462,6 +462,11 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.filterBar.addFilter(DropDownColumn.UNLOCKS, i18next.t("filterBar:unlocksFilter"), new DropDown(this.scene, 0, 0, unlocksOptions, this.updateStarters, DropDownType.RADIAL)); // misc filter + const favoriteLabels = [ + new DropDownLabel(i18next.t("filterBar:favorite"), undefined, DropDownState.OFF), + new DropDownLabel(i18next.t("filterBar:isFavorite"), undefined, DropDownState.ON), + new DropDownLabel(i18next.t("filterBar:notFavorite"), undefined, DropDownState.EXCLUDE), + ]; const winLabels = [ new DropDownLabel(i18next.t("filterBar:ribbon"), undefined, DropDownState.OFF), new DropDownLabel(i18next.t("filterBar:hasWon"), undefined, DropDownState.ON), @@ -477,6 +482,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { new DropDownLabel(i18next.t("filterBar:hasPokerus"), undefined, DropDownState.ON), ]; const miscOptions = [ + new DropDownOption(this.scene, "FAVORITE", favoriteLabels), new DropDownOption(this.scene, "WIN", winLabels), new DropDownOption(this.scene, "HIDDEN_ABILITY", hiddenAbilityLabels), new DropDownOption(this.scene, "POKERUS", pokerusLabels), @@ -929,6 +935,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { this.allSpecies.forEach((species, s) => { const icon = this.starterContainers[s].icon; const dexEntry = this.scene.gameData.dexData[species.speciesId]; + this.starterPreferences[species.speciesId] = this.starterPreferences[species.speciesId] ?? {}; if (dexEntry.caughtAttr) { icon.clearTint(); @@ -1543,6 +1550,29 @@ export default class StarterSelectUiHandler extends MessageUiHandler { }); } } + // if container.favorite is false, show the favorite option + const isFavorite = starterAttributes?.favorite ?? false; + if (!isFavorite) { + options.push({ + label: i18next.t("starterSelectUiHandler:addToFavorites"), + handler: () => { + starterAttributes.favorite = true; + starterContainer.favoriteIcon.setVisible(starterAttributes.favorite); + ui.setMode(Mode.STARTER_SELECT); + return true; + } + }); + } else { + options.push({ + label: i18next.t("starterSelectUiHandler:removeFromFavorites"), + handler: () => { + starterAttributes.favorite = false; + starterContainer.favoriteIcon.setVisible(starterAttributes.favorite); + ui.setMode(Mode.STARTER_SELECT); + return true; + } + }); + } options.push({ label: i18next.t("menu:rename"), handler: () => { @@ -2258,6 +2288,8 @@ export default class StarterSelectUiHandler extends MessageUiHandler { const isUncaught = !isCaught && !isVariantCaught && !isVariant2Caught && !isVariant3Caught; const isPassiveUnlocked = this.scene.gameData.starterData[container.species.speciesId].passiveAttr > 0; const isCostReduced = this.scene.gameData.starterData[container.species.speciesId].valueReduction > 0; + const isFavorite = this.starterPreferences[container.species.speciesId]?.favorite ?? false; + const isWin = this.scene.gameData.starterData[container.species.speciesId].classicWinCount > 0; const isNotWin = this.scene.gameData.starterData[container.species.speciesId].classicWinCount === 0; const isUndefined = this.scene.gameData.starterData[container.species.speciesId].classicWinCount === undefined; @@ -2301,6 +2333,18 @@ export default class StarterSelectUiHandler extends MessageUiHandler { } }); + const fitsFavorite = this.filterBar.getVals(DropDownColumn.MISC).some(misc => { + if (misc.val === "FAVORITE" && misc.state === DropDownState.ON) { + return isFavorite; + } + if (misc.val === "FAVORITE" && misc.state === DropDownState.EXCLUDE) { + return !isFavorite; + } + if (misc.val === "FAVORITE" && misc.state === DropDownState.OFF) { + return true; + } + }); + const fitsWin = this.filterBar.getVals(DropDownColumn.MISC).some(misc => { if (container.species.speciesId < 10) { } @@ -2333,7 +2377,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { } }); - if (fitsGen && fitsType && fitsCaught && fitsPassive && fitsCostReduction && fitsWin && fitsHA && fitsPokerus) { + if (fitsGen && fitsType && fitsCaught && fitsPassive && fitsCostReduction && fitsFavorite && fitsWin && fitsHA && fitsPokerus) { this.filteredStarterContainers.push(container); } }); @@ -2426,6 +2470,7 @@ export default class StarterSelectUiHandler extends MessageUiHandler { container.starterPassiveBgs.setVisible(!!this.scene.gameData.starterData[speciesId].passiveAttr); container.hiddenAbilityIcon.setVisible(!!this.scene.gameData.dexData[speciesId].caughtAttr && !!(this.scene.gameData.starterData[speciesId].abilityAttr & 4)); container.classicWinIcon.setVisible(this.scene.gameData.starterData[speciesId].classicWinCount > 0); + container.favoriteIcon.setVisible(this.starterPreferences[speciesId]?.favorite ?? false); // 'Candy Icon' mode if (this.scene.candyUpgradeDisplay === 0) { From 2b123262808965b7ae0afc85a13c8576c9a42106 Mon Sep 17 00:00:00 2001 From: "Adrian T." <68144167+torranx@users.noreply.github.com> Date: Fri, 9 Aug 2024 22:37:10 +0800 Subject: [PATCH 053/282] [Dev] Move function from testUtils.ts to gameManager.ts (1/3) (#3430) * move mockHitCheck to gameManager * add abstract base class and move helper class * add param for single target miss --- src/test/abilities/hustle.test.ts | 4 +-- src/test/abilities/libero.test.ts | 4 +-- src/test/abilities/magic_guard.test.ts | 4 +-- src/test/abilities/parental_bond.test.ts | 20 +++++++------- src/test/abilities/protean.test.ts | 4 +-- src/test/abilities/sweet_veil.test.ts | 6 ++-- src/test/moves/make_it_rain.test.ts | 9 ++---- src/test/utils/gameManager.ts | 3 ++ src/test/utils/gameManagerHelper.ts | 12 ++++++++ src/test/utils/moveHelper.ts | 35 ++++++++++++++++++++++++ src/test/utils/overridesHelper.ts | 10 ++----- src/test/utils/testUtils.ts | 18 +----------- 12 files changed, 77 insertions(+), 52 deletions(-) create mode 100644 src/test/utils/gameManagerHelper.ts create mode 100644 src/test/utils/moveHelper.ts diff --git a/src/test/abilities/hustle.test.ts b/src/test/abilities/hustle.test.ts index 80a71e54d0b..dde310fda2a 100644 --- a/src/test/abilities/hustle.test.ts +++ b/src/test/abilities/hustle.test.ts @@ -8,7 +8,7 @@ import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import { mockHitCheck, SPLASH_ONLY } from "#test/utils/testUtils"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; describe("Abilities - Hustle", () => { let phaserGame: Phaser.Game; @@ -44,7 +44,7 @@ describe("Abilities - Hustle", () => { vi.spyOn(pikachu, "getBattleStat"); game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); - await mockHitCheck(game, true); + await game.move.forceHit(); await game.phaseInterceptor.to(DamagePhase); expect(pikachu.getBattleStat).toHaveReturnedWith(atk * 1.5); diff --git a/src/test/abilities/libero.test.ts b/src/test/abilities/libero.test.ts index 6046df98243..58b4ac639cb 100644 --- a/src/test/abilities/libero.test.ts +++ b/src/test/abilities/libero.test.ts @@ -12,7 +12,7 @@ import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { mockHitCheck, SPLASH_ONLY } from "#test/utils/testUtils"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; const TIMEOUT = 20 * 1000; @@ -192,7 +192,7 @@ describe("Abilities - Protean", () => { expect(leadPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); - await mockHitCheck(game, false); + await game.move.forceMiss(); await game.phaseInterceptor.to(TurnEndPhase); const enemyPokemon = game.scene.getEnemyPokemon()!; diff --git a/src/test/abilities/magic_guard.test.ts b/src/test/abilities/magic_guard.test.ts index f138ef77219..c86d65ca453 100644 --- a/src/test/abilities/magic_guard.test.ts +++ b/src/test/abilities/magic_guard.test.ts @@ -11,7 +11,7 @@ import { Abilities } from "#enums/abilities"; import { WeatherType } from "#app/data/weather.js"; import { StatusEffect, getStatusEffectCatchRateMultiplier } from "#app/data/status-effect"; import { BattlerTagType } from "#enums/battler-tag-type"; -import { mockHitCheck, SPLASH_ONLY } from "#test/utils/testUtils"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; const TIMEOUT = 20 * 1000; // 20 sec timeout @@ -258,7 +258,7 @@ describe("Abilities - Magic Guard", () => { const leadPokemon = game.scene.getPlayerPokemon()!; game.doAttack(getMovePosition(game.scene, 0, Moves.HIGH_JUMP_KICK)); - await mockHitCheck(game, false); + await game.move.forceMiss(); await game.phaseInterceptor.to(TurnEndPhase); diff --git a/src/test/abilities/parental_bond.test.ts b/src/test/abilities/parental_bond.test.ts index e5f0f969d10..182f780763c 100644 --- a/src/test/abilities/parental_bond.test.ts +++ b/src/test/abilities/parental_bond.test.ts @@ -10,7 +10,7 @@ import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { mockHitCheck, SPLASH_ONLY } from "#test/utils/testUtils"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; const TIMEOUT = 20 * 1000; @@ -129,7 +129,7 @@ describe("Abilities - Parental Bond", () => { expect(enemyPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.DOUBLE_HIT)); - await mockHitCheck(game, true); + await game.move.forceHit(); await game.phaseInterceptor.to(BerryPhase, false); @@ -172,7 +172,7 @@ describe("Abilities - Parental Bond", () => { expect(enemyPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.ROLLOUT)); - await mockHitCheck(game, true); + await game.move.forceHit(); await game.phaseInterceptor.to(DamagePhase, false); @@ -368,7 +368,7 @@ describe("Abilities - Parental Bond", () => { const enemyStartingHp = enemyPokemon.hp; game.doAttack(getMovePosition(game.scene, 0, Moves.SUPER_FANG)); - await mockHitCheck(game, true); + await game.move.forceHit(); await game.phaseInterceptor.to(DamagePhase); @@ -397,7 +397,7 @@ describe("Abilities - Parental Bond", () => { const enemyStartingHp = enemyPokemon.hp; game.doAttack(getMovePosition(game.scene, 0, Moves.SEISMIC_TOSS)); - await mockHitCheck(game, true); + await game.move.forceHit(); await game.phaseInterceptor.to(DamagePhase); @@ -423,7 +423,7 @@ describe("Abilities - Parental Bond", () => { expect(enemyPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.HYPER_BEAM)); - await mockHitCheck(game, true); + await game.move.forceHit(); await game.phaseInterceptor.to(DamagePhase); @@ -451,7 +451,7 @@ describe("Abilities - Parental Bond", () => { expect(enemyPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.ANCHOR_SHOT)); - await mockHitCheck(game, true); + await game.move.forceHit(); await game.phaseInterceptor.to(DamagePhase); @@ -481,7 +481,7 @@ describe("Abilities - Parental Bond", () => { expect(enemyPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.SMACK_DOWN)); - await mockHitCheck(game, true); + await game.move.forceHit(); await game.phaseInterceptor.to(DamagePhase); @@ -508,7 +508,7 @@ describe("Abilities - Parental Bond", () => { expect(enemyPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.U_TURN)); - await mockHitCheck(game, true); + await game.move.forceHit(); await game.phaseInterceptor.to(MoveEffectPhase); expect(leadPokemon.turnData.hitCount).toBe(2); @@ -532,7 +532,7 @@ describe("Abilities - Parental Bond", () => { expect(enemyPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.WAKE_UP_SLAP)); - await mockHitCheck(game, true); + await game.move.forceHit(); await game.phaseInterceptor.to(DamagePhase); diff --git a/src/test/abilities/protean.test.ts b/src/test/abilities/protean.test.ts index 8022f73255f..78768ce32db 100644 --- a/src/test/abilities/protean.test.ts +++ b/src/test/abilities/protean.test.ts @@ -12,7 +12,7 @@ import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { mockHitCheck, SPLASH_ONLY } from "#test/utils/testUtils"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; const TIMEOUT = 20 * 1000; @@ -192,7 +192,7 @@ describe("Abilities - Protean", () => { expect(leadPokemon).not.toBe(undefined); game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE)); - await mockHitCheck(game, false); + await game.move.forceMiss(); await game.phaseInterceptor.to(TurnEndPhase); const enemyPokemon = game.scene.getEnemyPokemon()!; diff --git a/src/test/abilities/sweet_veil.test.ts b/src/test/abilities/sweet_veil.test.ts index 5af822da061..d650455664f 100644 --- a/src/test/abilities/sweet_veil.test.ts +++ b/src/test/abilities/sweet_veil.test.ts @@ -8,7 +8,7 @@ import { getMovePosition } from "#test/utils/gameManagerUtils"; import { BattlerTagType } from "#app/enums/battler-tag-type.js"; import { Abilities } from "#app/enums/abilities.js"; import { BattlerIndex } from "#app/battle.js"; -import { mockHitCheck, SPLASH_ONLY } from "#test/utils/testUtils"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; describe("Abilities - Sweet Veil", () => { let phaserGame: Phaser.Game; @@ -80,11 +80,11 @@ describe("Abilities - Sweet Veil", () => { game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); // First pokemon move - await mockHitCheck(game, true); + await game.move.forceHit(); // Second pokemon move await game.phaseInterceptor.to(MovePhase, false); - await mockHitCheck(game, true); + await game.move.forceHit(); expect(game.scene.getPlayerField().some(p => !!p.getTag(BattlerTagType.DROWSY))).toBe(true); diff --git a/src/test/moves/make_it_rain.test.ts b/src/test/moves/make_it_rain.test.ts index 72386930873..a4440401c4b 100644 --- a/src/test/moves/make_it_rain.test.ts +++ b/src/test/moves/make_it_rain.test.ts @@ -1,12 +1,12 @@ import { BattleStat } from "#app/data/battle-stat.js"; -import { MoveEffectPhase, MoveEndPhase, StatChangePhase } from "#app/phases"; +import { MoveEndPhase, StatChangePhase } from "#app/phases"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phaser from "phaser"; -import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { SPLASH_ONLY } from "#test/utils/testUtils"; const TIMEOUT = 20 * 1000; @@ -91,11 +91,8 @@ describe("Moves - Make It Rain", () => { game.doAttack(getMovePosition(game.scene, 0, Moves.MAKE_IT_RAIN)); game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); - await game.phaseInterceptor.to(MoveEffectPhase, false); - // Make Make It Rain miss the first target - const moveEffectPhase = game.scene.getCurrentPhase() as MoveEffectPhase; - vi.spyOn(moveEffectPhase, "hitCheck").mockReturnValueOnce(false); + await game.move.forceMiss(true); await game.phaseInterceptor.to(MoveEndPhase); diff --git a/src/test/utils/gameManager.ts b/src/test/utils/gameManager.ts index 771ab1e7081..03b43ea2275 100644 --- a/src/test/utils/gameManager.ts +++ b/src/test/utils/gameManager.ts @@ -28,6 +28,7 @@ import { ModifierTypeOption, modifierTypes } from "#app/modifier/modifier-type.j import overrides from "#app/overrides.js"; import { removeEnemyHeldItems } from "./testUtils"; import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler.js"; +import { MoveHelper } from "./moveHelper"; /** * Class to manage the game state and transitions between phases. @@ -39,6 +40,7 @@ export default class GameManager { public textInterceptor: TextInterceptor; public inputsHandler: InputsHandler; public readonly override: OverridesHelper; + public readonly move: MoveHelper; /** * Creates an instance of GameManager. @@ -55,6 +57,7 @@ export default class GameManager { this.textInterceptor = new TextInterceptor(this.scene); this.gameWrapper.setScene(this.scene); this.override = new OverridesHelper(this); + this.move = new MoveHelper(this); } /** diff --git a/src/test/utils/gameManagerHelper.ts b/src/test/utils/gameManagerHelper.ts new file mode 100644 index 00000000000..2caa94ae5ed --- /dev/null +++ b/src/test/utils/gameManagerHelper.ts @@ -0,0 +1,12 @@ +import GameManager from "./gameManager"; + +/** + * Base class for defining all game helpers. + */ +export abstract class GameManagerHelper { + protected readonly game: GameManager; + + constructor(game: GameManager) { + this.game = game; + } +} diff --git a/src/test/utils/moveHelper.ts b/src/test/utils/moveHelper.ts new file mode 100644 index 00000000000..08c1f1e58e0 --- /dev/null +++ b/src/test/utils/moveHelper.ts @@ -0,0 +1,35 @@ +import { vi } from "vitest"; +import { MoveEffectPhase } from "#app/phases.js"; +import { GameManagerHelper } from "./gameManagerHelper"; + +/** + * Helper to handle a Pokemon's move + */ +export class MoveHelper extends GameManagerHelper { + /** + * Intercepts `MoveEffectPhase` and mocks the hitCheck's + * return value to `true` {@linkcode MoveEffectPhase.hitCheck}. + * Used to force a move to hit. + */ + async forceHit(): Promise { + await this.game.phaseInterceptor.to(MoveEffectPhase, false); + vi.spyOn(this.game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValue(true); + } + + /** + * Intercepts `MoveEffectPhase` and mocks the hitCheck's + * return value to `false` {@linkcode MoveEffectPhase.hitCheck}. + * Used to force a move to miss. + * @param firstTargetOnly Whether the move should force miss on the first target only, in the case of multi-hit moves. + */ + async forceMiss(firstTargetOnly: boolean = false): Promise { + await this.game.phaseInterceptor.to(MoveEffectPhase, false); + const hitCheck = vi.spyOn(this.game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck"); + + if (firstTargetOnly) { + hitCheck.mockReturnValueOnce(false); + } else { + hitCheck.mockReturnValue(false); + } + } +} diff --git a/src/test/utils/overridesHelper.ts b/src/test/utils/overridesHelper.ts index e77cd49b742..dbcb02825f2 100644 --- a/src/test/utils/overridesHelper.ts +++ b/src/test/utils/overridesHelper.ts @@ -8,19 +8,13 @@ import * as GameMode from "#app/game-mode"; import { GameModes, getGameMode } from "#app/game-mode"; import { ModifierOverride } from "#app/modifier/modifier-type.js"; import Overrides from "#app/overrides"; -import GameManager from "#test/utils/gameManager"; import { vi } from "vitest"; +import { GameManagerHelper } from "./gameManagerHelper"; /** * Helper to handle overrides in tests */ -export class OverridesHelper { - private readonly game: GameManager; - - constructor(game: GameManager) { - this.game = game; - } - +export class OverridesHelper extends GameManagerHelper { /** * Override the starting biome * @warning Any event listeners that are attached to [NewArenaEvent](events\battle-scene.ts) may need to be handled down the line diff --git a/src/test/utils/testUtils.ts b/src/test/utils/testUtils.ts index d5f266cd4ae..f1ed2bcdd07 100644 --- a/src/test/utils/testUtils.ts +++ b/src/test/utils/testUtils.ts @@ -3,7 +3,7 @@ import i18next, { type ParseKeys } from "i18next"; import { vi } from "vitest"; import GameManager from "./gameManager"; import { BattlerIndex } from "#app/battle.js"; -import { MoveEffectPhase, TurnStartPhase } from "#app/phases.js"; +import { TurnStartPhase } from "#app/phases.js"; /** Ready to use array of Moves.SPLASH x4 */ export const SPLASH_ONLY = [Moves.SPLASH, Moves.SPLASH, Moves.SPLASH, Moves.SPLASH]; @@ -54,19 +54,3 @@ export async function mockTurnOrder(game: GameManager, order: BattlerIndex[]): P vi.spyOn(game.scene.getCurrentPhase() as TurnStartPhase, "getOrder").mockReturnValue(order); } - -/** - * Intercepts `MoveEffectPhase` and mocks the hitCheck's return value {@linkcode MoveEffectPhase.hitCheck}. - * Used to force a move to either hit or miss. - * Note that this uses `mockReturnValue()`, meaning it will also apply to a - * succeeding `MoveEffectPhase` immediately following the first one - * (in the case of a multi-target move) - * - * @param {GameManager} game The GameManager instance - * @param shouldHit Whether the move should hit - */ -export async function mockHitCheck(game: GameManager, shouldHit: boolean): Promise { - await game.phaseInterceptor.to(MoveEffectPhase, false); - - vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValue(shouldHit); -} From dcbdc511cfca3b1a07a2b1330dded0a54e985c85 Mon Sep 17 00:00:00 2001 From: Leo Kim <47556641+KimJeongSun@users.noreply.github.com> Date: Sat, 10 Aug 2024 00:06:57 +0900 Subject: [PATCH 054/282] [Localization] update korean translation of filter for costReduction (#3464) --- src/locales/ko/filter-bar.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/locales/ko/filter-bar.ts b/src/locales/ko/filter-bar.ts index c597ad54ee8..2724b1ea3ac 100644 --- a/src/locales/ko/filter-bar.ts +++ b/src/locales/ko/filter-bar.ts @@ -13,9 +13,9 @@ export const filterBar: SimpleTranslationEntries = { "passive": "패시브", "passiveUnlocked": "패시브 해금", "passiveLocked": "패시브 잠김", - "costReduction": "코스트 줄이기", - "costReductionUnlocked": "코스트 절감됨", - "costReductionLocked": "코스트 절감 없음", + "costReduction": "코스트 감소", + "costReductionUnlocked": "코스트 감소됨", + "costReductionLocked": "코스트 감소 없음", "favorite": "즐겨찾기", "isFavorite": "즐겨찾기 등록됨", "notFavorite": "즐겨찾기 제외됨", From bfdcd4fc1eb062be3563545ae24b23d7849957de Mon Sep 17 00:00:00 2001 From: "Adrian T." <68144167+torranx@users.noreply.github.com> Date: Fri, 9 Aug 2024 23:07:55 +0800 Subject: [PATCH 055/282] [Dev] Move function from testUtils.ts to gameManager.ts (2/3) (#3432) * move mockTurnOrder to gameManager * change name * fix test failing * fix purify test * fix typo --- src/test/abilities/serene_grace.test.ts | 5 ++--- src/test/abilities/sheer_force.test.ts | 9 ++++----- src/test/abilities/shield_dust.test.ts | 3 +-- src/test/abilities/zen_mode.test.ts | 10 ++++++---- src/test/items/leek.test.ts | 3 +-- src/test/items/scope_lens.test.ts | 4 ++-- src/test/moves/fusion_flare_bolt.test.ts | 15 +++++++-------- src/test/moves/gastro_acid.test.ts | 4 ++-- src/test/moves/miracle_eye.test.ts | 4 ++-- src/test/moves/purify.test.ts | 5 ++--- src/test/utils/gameManager.ts | 16 ++++++++++++++++ src/test/utils/moveHelper.ts | 2 +- src/test/utils/testUtils.ts | 18 ------------------ 13 files changed, 46 insertions(+), 52 deletions(-) diff --git a/src/test/abilities/serene_grace.test.ts b/src/test/abilities/serene_grace.test.ts index 59e9ff723da..d46587e45c7 100644 --- a/src/test/abilities/serene_grace.test.ts +++ b/src/test/abilities/serene_grace.test.ts @@ -11,7 +11,6 @@ import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { mockTurnOrder } from "../utils/testUtils"; import { BattlerIndex } from "#app/battle.js"; @@ -57,7 +56,7 @@ describe("Abilities - Serene Grace", () => { (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); }); - await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEffectPhase, false); // Check chance of Air Slash without Serene Grace @@ -90,7 +89,7 @@ describe("Abilities - Serene Grace", () => { (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); }); - await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEffectPhase, false); // Check chance of Air Slash with Serene Grace diff --git a/src/test/abilities/sheer_force.test.ts b/src/test/abilities/sheer_force.test.ts index 35353bc7000..50a0f0b63fb 100644 --- a/src/test/abilities/sheer_force.test.ts +++ b/src/test/abilities/sheer_force.test.ts @@ -11,7 +11,6 @@ import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { mockTurnOrder } from "../utils/testUtils"; import { BattlerIndex } from "#app/battle.js"; @@ -58,7 +57,7 @@ describe("Abilities - Sheer Force", () => { (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); }); - await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEffectPhase, false); const phase = game.scene.getCurrentPhase() as MoveEffectPhase; @@ -97,7 +96,7 @@ describe("Abilities - Sheer Force", () => { (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); }); - await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEffectPhase, false); const phase = game.scene.getCurrentPhase() as MoveEffectPhase; @@ -136,7 +135,7 @@ describe("Abilities - Sheer Force", () => { (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); }); - await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEffectPhase, false); const phase = game.scene.getCurrentPhase() as MoveEffectPhase; @@ -177,7 +176,7 @@ describe("Abilities - Sheer Force", () => { (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); }); - await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEffectPhase, false); const phase = game.scene.getCurrentPhase() as MoveEffectPhase; diff --git a/src/test/abilities/shield_dust.test.ts b/src/test/abilities/shield_dust.test.ts index ded70eccb36..f1534551e92 100644 --- a/src/test/abilities/shield_dust.test.ts +++ b/src/test/abilities/shield_dust.test.ts @@ -12,7 +12,6 @@ import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import { BattlerIndex } from "#app/battle.js"; -import { mockTurnOrder } from "../utils/testUtils"; describe("Abilities - Shield Dust", () => { @@ -58,7 +57,7 @@ describe("Abilities - Shield Dust", () => { (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); }); - await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEffectPhase, false); // Shield Dust negates secondary effect diff --git a/src/test/abilities/zen_mode.test.ts b/src/test/abilities/zen_mode.test.ts index fc0bf282078..1bc7a6af4ce 100644 --- a/src/test/abilities/zen_mode.test.ts +++ b/src/test/abilities/zen_mode.test.ts @@ -12,7 +12,6 @@ import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; import { BattlerIndex } from "#app/battle.js"; -import { mockTurnOrder } from "../utils/testUtils"; const TIMEOUT = 20 * 1000; @@ -58,7 +57,8 @@ describe("Abilities - ZEN MODE", () => { const movePosition = getMovePosition(game.scene, 0, moveToUse); (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); }); - await mockTurnOrder(game, [BattlerIndex.ENEMY, BattlerIndex.PLAYER]); + + await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.phaseInterceptor.to(DamagePhase, false); // await game.phaseInterceptor.runFrom(DamagePhase).to(DamagePhase, false); const damagePhase = game.scene.getCurrentPhase() as DamagePhase; @@ -86,7 +86,8 @@ describe("Abilities - ZEN MODE", () => { const movePosition = getMovePosition(game.scene, 0, moveToUse); (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); }); - await mockTurnOrder(game, [BattlerIndex.ENEMY, BattlerIndex.PLAYER]); + + await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.phaseInterceptor.to(QuietFormChangePhase); await game.phaseInterceptor.to(TurnInitPhase, false); expect(game.scene.getParty()[0].hp).not.toBe(100); @@ -111,7 +112,8 @@ describe("Abilities - ZEN MODE", () => { const movePosition = getMovePosition(game.scene, 0, moveToUse); (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); }); - await mockTurnOrder(game, [BattlerIndex.ENEMY, BattlerIndex.PLAYER]); + + await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.phaseInterceptor.to(DamagePhase, false); // await game.phaseInterceptor.runFrom(DamagePhase).to(DamagePhase, false); const damagePhase = game.scene.getCurrentPhase() as DamagePhase; diff --git a/src/test/items/leek.test.ts b/src/test/items/leek.test.ts index 7ac453f797a..4abc470c6f0 100644 --- a/src/test/items/leek.test.ts +++ b/src/test/items/leek.test.ts @@ -8,7 +8,6 @@ import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phase from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import { mockTurnOrder } from "#test/utils/testUtils"; describe("Items - Leek", () => { let phaserGame: Phaser.Game; @@ -44,7 +43,7 @@ describe("Items - Leek", () => { game.doAttack(0); - await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEffectPhase); diff --git a/src/test/items/scope_lens.test.ts b/src/test/items/scope_lens.test.ts index 7e5c57c1364..4efc7ab9d05 100644 --- a/src/test/items/scope_lens.test.ts +++ b/src/test/items/scope_lens.test.ts @@ -8,7 +8,6 @@ import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phase from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; -import { mockTurnOrder } from "#test/utils/testUtils"; describe("Items - Scope Lens", () => { let phaserGame: Phaser.Game; @@ -43,7 +42,8 @@ describe("Items - Scope Lens", () => { ]); game.doAttack(0); - await mockTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]); + + await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]); await game.phaseInterceptor.to(MoveEffectPhase); diff --git a/src/test/moves/fusion_flare_bolt.test.ts b/src/test/moves/fusion_flare_bolt.test.ts index 95090214962..c2214d5442b 100644 --- a/src/test/moves/fusion_flare_bolt.test.ts +++ b/src/test/moves/fusion_flare_bolt.test.ts @@ -8,7 +8,6 @@ import { allMoves } from "#app/data/move"; import { BattlerIndex } from "#app/battle"; import { Species } from "#enums/species"; import { Moves } from "#enums/moves"; -import { mockTurnOrder } from "#test/utils/testUtils"; describe("Moves - Fusion Flare and Fusion Bolt", () => { let phaserGame: Phaser.Game; @@ -56,7 +55,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { game.doSelectTarget(BattlerIndex.ENEMY); // Force user party to act before enemy party - await mockTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]); + await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]); await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id); @@ -82,7 +81,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { game.doSelectTarget(BattlerIndex.ENEMY); // Force user party to act before enemy party - await mockTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]); + await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]); await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id); @@ -108,7 +107,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { game.doSelectTarget(0); // Force first enemy to act (and fail) in between party - await mockTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY ]); + await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY ]); await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id); @@ -140,7 +139,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { game.doSelectTarget(BattlerIndex.ENEMY); // Force first enemy to act in between party - await mockTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY ]); + await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY ]); await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id); @@ -170,7 +169,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { game.doSelectTarget(BattlerIndex.PLAYER); // Force user party to act before enemy party - await mockTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]); + await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]); await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id); @@ -222,7 +221,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { game.doSelectTarget(BattlerIndex.ENEMY); // Force first enemy to act in between party - await mockTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY ]); + await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY ]); await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id); @@ -284,7 +283,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { game.doSelectTarget(BattlerIndex.PLAYER); // Force first enemy to act in between party - await mockTurnOrder(game, [ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY ]); + await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY ]); await game.phaseInterceptor.to(MoveEffectPhase, false); expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id); diff --git a/src/test/moves/gastro_acid.test.ts b/src/test/moves/gastro_acid.test.ts index 8c5f5f14eac..cc247890754 100644 --- a/src/test/moves/gastro_acid.test.ts +++ b/src/test/moves/gastro_acid.test.ts @@ -6,7 +6,7 @@ import { MoveResult } from "#app/field/pokemon.js"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import GameManager from "#test/utils/gameManager"; import { getMovePosition } from "#test/utils/gameManagerUtils"; -import { mockTurnOrder, SPLASH_ONLY } from "#test/utils/testUtils"; +import { SPLASH_ONLY } from "#test/utils/testUtils"; const TIMEOUT = 20 * 1000; @@ -75,7 +75,7 @@ describe("Moves - Gastro Acid", () => { game.doAttack(getMovePosition(game.scene, 0, Moves.CORE_ENFORCER)); // Force player to be slower to enable Core Enforcer to proc its suppression effect - await mockTurnOrder(game, [BattlerIndex.ENEMY, BattlerIndex.PLAYER]); + await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); await game.phaseInterceptor.to("TurnInitPhase"); diff --git a/src/test/moves/miracle_eye.test.ts b/src/test/moves/miracle_eye.test.ts index 8bfa0f4bfc1..67d4d695b62 100644 --- a/src/test/moves/miracle_eye.test.ts +++ b/src/test/moves/miracle_eye.test.ts @@ -2,7 +2,7 @@ import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; import Phaser from "phaser"; import GameManager from "#test/utils/gameManager"; import { Species } from "#app/enums/species.js"; -import { mockTurnOrder, SPLASH_ONLY } from "../utils/testUtils"; +import { SPLASH_ONLY } from "../utils/testUtils"; import { Moves } from "#app/enums/moves.js"; import { getMovePosition } from "../utils/gameManagerUtils"; import { MoveEffectPhase } from "#app/phases.js"; @@ -39,7 +39,7 @@ describe("Internals", () => { const enemy = game.scene.getEnemyPokemon()!; game.doAttack(getMovePosition(game.scene, 0, Moves.CONFUSION)); - await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.toNextTurn(); expect(enemy.hp).toBe(enemy.getMaxHp()); diff --git a/src/test/moves/purify.test.ts b/src/test/moves/purify.test.ts index 69d20ca0cc0..7959927d63f 100644 --- a/src/test/moves/purify.test.ts +++ b/src/test/moves/purify.test.ts @@ -7,7 +7,6 @@ import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest"; -import { mockTurnOrder } from "../utils/testUtils"; import { BattlerIndex } from "#app/battle.js"; const TIMEOUT = 20 * 1000; @@ -51,7 +50,7 @@ describe("Moves - Purify", () => { enemyPokemon.status = new Status(StatusEffect.BURN); game.doAttack(getMovePosition(game.scene, 0, Moves.PURIFY)); - await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEndPhase); expect(enemyPokemon.status).toBeNull(); @@ -71,7 +70,7 @@ describe("Moves - Purify", () => { const playerInitialHp = playerPokemon.hp; game.doAttack(getMovePosition(game.scene, 0, Moves.PURIFY)); - await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEndPhase); expect(playerPokemon.hp).toBe(playerInitialHp); diff --git a/src/test/utils/gameManager.ts b/src/test/utils/gameManager.ts index 03b43ea2275..c782c613bb0 100644 --- a/src/test/utils/gameManager.ts +++ b/src/test/utils/gameManager.ts @@ -29,6 +29,7 @@ import overrides from "#app/overrides.js"; import { removeEnemyHeldItems } from "./testUtils"; import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler.js"; import { MoveHelper } from "./moveHelper"; +import { vi } from "vitest"; /** * Class to manage the game state and transitions between phases. @@ -357,4 +358,19 @@ export default class GameManager { partyHandler.processInput(Button.ACTION); // send out (or whatever option is at the top) }); } + + /** + * Intercepts `TurnStartPhase` and mocks the getOrder's return value {@linkcode TurnStartPhase.getOrder} + * Used to modify the turn order. + * @param {BattlerIndex[]} order The turn order to set + * @example + * ```ts + * await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2]); + * ``` + */ + async setTurnOrder(order: BattlerIndex[]): Promise { + await this.phaseInterceptor.to(TurnStartPhase, false); + + vi.spyOn(this.scene.getCurrentPhase() as TurnStartPhase, "getOrder").mockReturnValue(order); + } } diff --git a/src/test/utils/moveHelper.ts b/src/test/utils/moveHelper.ts index 08c1f1e58e0..9438952aa92 100644 --- a/src/test/utils/moveHelper.ts +++ b/src/test/utils/moveHelper.ts @@ -20,7 +20,7 @@ export class MoveHelper extends GameManagerHelper { * Intercepts `MoveEffectPhase` and mocks the hitCheck's * return value to `false` {@linkcode MoveEffectPhase.hitCheck}. * Used to force a move to miss. - * @param firstTargetOnly Whether the move should force miss on the first target only, in the case of multi-hit moves. + * @param firstTargetOnly Whether the move should force miss on the first target only, in the case of multi-target moves. */ async forceMiss(firstTargetOnly: boolean = false): Promise { await this.game.phaseInterceptor.to(MoveEffectPhase, false); diff --git a/src/test/utils/testUtils.ts b/src/test/utils/testUtils.ts index f1ed2bcdd07..d40efbbf016 100644 --- a/src/test/utils/testUtils.ts +++ b/src/test/utils/testUtils.ts @@ -2,8 +2,6 @@ import { Moves } from "#app/enums/moves.js"; import i18next, { type ParseKeys } from "i18next"; import { vi } from "vitest"; import GameManager from "./gameManager"; -import { BattlerIndex } from "#app/battle.js"; -import { TurnStartPhase } from "#app/phases.js"; /** Ready to use array of Moves.SPLASH x4 */ export const SPLASH_ONLY = [Moves.SPLASH, Moves.SPLASH, Moves.SPLASH, Moves.SPLASH]; @@ -38,19 +36,3 @@ export function removeEnemyHeldItems(game: GameManager): void { game.scene.clearEnemyModifiers(); console.log("Enemy held items removed"); } - -/** - * Intercepts `TurnStartPhase` and mocks the getOrder's return value {@linkcode TurnStartPhase.getOrder} - * Used to modify the turn order. - * @param {GameManager} game The GameManager instance - * @param {BattlerIndex[]} order The turn order to set - * @example - * ```ts - * await mockTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2]); - * ``` - */ -export async function mockTurnOrder(game: GameManager, order: BattlerIndex[]): Promise { - await game.phaseInterceptor.to(TurnStartPhase, false); - - vi.spyOn(game.scene.getCurrentPhase() as TurnStartPhase, "getOrder").mockReturnValue(order); -} From 762feea33240ce58d9900041361d756f63af20cc Mon Sep 17 00:00:00 2001 From: flx-sta <50131232+flx-sta@users.noreply.github.com> Date: Fri, 9 Aug 2024 08:17:34 -0700 Subject: [PATCH 056/282] [Bug][Localhost] fix Json parse issue when trying to load battle-anim (#3455) * add content-type check for loading battle-anims * add missing `headers` to response mocks --- src/data/battle-anims.ts | 3 ++- src/test/utils/gameWrapper.ts | 2 ++ src/test/utils/mocks/mockFetch.ts | 7 +++++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/src/data/battle-anims.ts b/src/data/battle-anims.ts index bcf3bd7bb40..634c39b7d66 100644 --- a/src/data/battle-anims.ts +++ b/src/data/battle-anims.ts @@ -485,7 +485,8 @@ export function initMoveAnim(scene: BattleScene, move: Moves): Promise { const fetchAnimAndResolve = (move: Moves) => { scene.cachedFetch(`./battle-anims/${moveName}.json`) .then(response => { - if (!response.ok) { + const contentType = response.headers.get("content-type"); + if (!response.ok || contentType?.indexOf("application/json") === -1) { console.error(`Could not load animation file for move '${moveName}'`, response.status, response.statusText); populateMoveAnim(move, moveAnims.get(defaultMoveAnim)); return resolve(); diff --git a/src/test/utils/gameWrapper.ts b/src/test/utils/gameWrapper.ts index 7edb69aef8a..80529e47194 100644 --- a/src/test/utils/gameWrapper.ts +++ b/src/test/utils/gameWrapper.ts @@ -242,6 +242,7 @@ function createFetchResponse(data) { return { ok: true, status: 200, + headers: new Headers(), json: () => Promise.resolve(data), text: () => Promise.resolve(JSON.stringify(data)), }; @@ -251,6 +252,7 @@ function createFetchBadResponse(data) { return { ok: false, status: 404, + headers: new Headers(), json: () => Promise.resolve(data), text: () => Promise.resolve(JSON.stringify(data)), }; diff --git a/src/test/utils/mocks/mockFetch.ts b/src/test/utils/mocks/mockFetch.ts index ad364a95885..8043dd993fe 100644 --- a/src/test/utils/mocks/mockFetch.ts +++ b/src/test/utils/mocks/mockFetch.ts @@ -23,10 +23,13 @@ export const MockFetch = (input, init) => { } } - return Promise.resolve({ + const response: Partial = { ok: true, status: 200, json: responseHandler, text: responseText, - }); + headers: new Headers({}), + }; + + return Promise.resolve(response); }; From d127773a89a4a774c3c17d9a9f2e74f38aaefa89 Mon Sep 17 00:00:00 2001 From: Blitzy <118096277+Blitz425@users.noreply.github.com> Date: Fri, 9 Aug 2024 12:48:10 -0500 Subject: [PATCH 057/282] [Balance] Change Some Mainline Starter's Early Learnset (#3445) * Update pokemon-level-moves.ts * Change Poipole's Early Move * Add notes --- src/data/pokemon-level-moves.ts | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/data/pokemon-level-moves.ts b/src/data/pokemon-level-moves.ts index ccf6ac022ae..bacb84930b4 100644 --- a/src/data/pokemon-level-moves.ts +++ b/src/data/pokemon-level-moves.ts @@ -2631,7 +2631,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [Species.CHIKORITA]: [ [ 1, Moves.TACKLE ], [ 1, Moves.GROWL ], - [ 6, Moves.RAZOR_LEAF ], + [ 5, Moves.RAZOR_LEAF ], //Custom, moved from 6 to 5 [ 9, Moves.POISON_POWDER ], [ 12, Moves.SYNTHESIS ], [ 17, Moves.REFLECT ], @@ -2681,8 +2681,8 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [Species.CYNDAQUIL]: [ [ 1, Moves.TACKLE ], [ 1, Moves.LEER ], - [ 6, Moves.SMOKESCREEN ], - [ 10, Moves.EMBER ], + [ 5, Moves.EMBER ], //Custom, moved to 5 + [ 10, Moves.SMOKESCREEN ], //Custom, moved to 10 [ 13, Moves.QUICK_ATTACK ], [ 19, Moves.FLAME_WHEEL ], [ 22, Moves.DEFENSE_CURL ], @@ -2736,7 +2736,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [Species.TOTODILE]: [ [ 1, Moves.SCRATCH ], [ 1, Moves.LEER ], - [ 6, Moves.WATER_GUN ], + [ 5, Moves.WATER_GUN ], //Custom, moved from 6 to 5 [ 9, Moves.BITE ], [ 13, Moves.SCARY_FACE ], [ 19, Moves.ICE_FANG ], @@ -6723,7 +6723,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [Species.TURTWIG]: [ [ 1, Moves.TACKLE ], [ 5, Moves.WITHDRAW ], - [ 9, Moves.ABSORB ], + [ 5, Moves.ABSORB ], //Custom, moved from 9 to 5 [ 13, Moves.RAZOR_LEAF ], [ 17, Moves.CURSE ], [ 21, Moves.BITE ], @@ -6768,7 +6768,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [Species.CHIMCHAR]: [ [ 1, Moves.SCRATCH ], [ 1, Moves.LEER ], - [ 7, Moves.EMBER ], + [ 5, Moves.EMBER ], //Custom, moved from 7 to 5 [ 9, Moves.TAUNT ], [ 15, Moves.FURY_SWIPES ], [ 17, Moves.FLAME_WHEEL ], @@ -6817,7 +6817,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [Species.PIPLUP]: [ [ 1, Moves.POUND ], [ 4, Moves.GROWL ], - [ 8, Moves.WATER_GUN ], + [ 5, Moves.WATER_GUN ], //Custom, moved from 8 to 5 [ 11, Moves.CHARM ], [ 15, Moves.PECK ], [ 18, Moves.BUBBLE_BEAM ], @@ -8591,7 +8591,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [Species.SNIVY]: [ [ 1, Moves.TACKLE ], [ 4, Moves.LEER ], - [ 7, Moves.VINE_WHIP ], + [ 5, Moves.VINE_WHIP ], //Custom, moved from 7 to 5 [ 10, Moves.WRAP ], [ 13, Moves.GROWTH ], [ 16, Moves.MAGICAL_LEAF ], @@ -8639,7 +8639,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [Species.TEPIG]: [ [ 1, Moves.TACKLE ], [ 3, Moves.TAIL_WHIP ], - [ 7, Moves.EMBER ], + [ 5, Moves.EMBER ], //Custom, moved from 7 to 5 [ 9, Moves.ENDURE ], [ 13, Moves.DEFENSE_CURL ], [ 15, Moves.FLAME_CHARGE ], @@ -8693,7 +8693,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [Species.OSHAWOTT]: [ [ 1, Moves.TACKLE ], [ 5, Moves.TAIL_WHIP ], - [ 7, Moves.WATER_GUN ], + [ 5, Moves.WATER_GUN ], //Custom, moved from 7 to 5 [ 11, Moves.SOAK ], [ 13, Moves.FOCUS_ENERGY ], [ 17, Moves.RAZOR_SHELL ], @@ -13850,11 +13850,11 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [ 99, Moves.CLOSE_COMBAT ], ], [Species.POIPOLE]: [ + [ RELEARN_MOVE, Moves.DRAGON_PULSE ], //Custom, made relearn [ 1, Moves.GROWL ], [ 1, Moves.ACID ], [ 1, Moves.PECK ], [ 1, Moves.HELPING_HAND ], - [ 1, Moves.DRAGON_PULSE ], [ 7, Moves.FURY_ATTACK ], [ 14, Moves.FELL_STINGER ], [ 21, Moves.CHARM ], @@ -13969,7 +13969,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [Species.GROOKEY]: [ [ 1, Moves.SCRATCH ], [ 1, Moves.GROWL ], - [ 6, Moves.BRANCH_POKE ], + [ 5, Moves.BRANCH_POKE ], //Custom, moved from 6 to 5 [ 8, Moves.TAUNT ], [ 12, Moves.RAZOR_LEAF ], [ 17, Moves.SCREECH ], @@ -14014,7 +14014,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [Species.SCORBUNNY]: [ [ 1, Moves.TACKLE ], [ 1, Moves.GROWL ], - [ 6, Moves.EMBER ], + [ 5, Moves.EMBER ], //Custom, moved from 6 to 5 [ 8, Moves.QUICK_ATTACK ], [ 12, Moves.DOUBLE_KICK ], [ 17, Moves.FLAME_CHARGE ], @@ -14056,7 +14056,7 @@ export const pokemonSpeciesLevelMoves: PokemonSpeciesLevelMoves = { [Species.SOBBLE]: [ [ 1, Moves.POUND ], [ 1, Moves.GROWL ], - [ 6, Moves.WATER_GUN ], + [ 5, Moves.WATER_GUN ], //Custom, moved from 6 to 5 [ 8, Moves.BIND ], [ 12, Moves.WATER_PULSE ], [ 17, Moves.TEARFUL_LOOK ], From e820163505dfc409570fb69cbdd3de45ee8e1b99 Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Fri, 9 Aug 2024 13:58:15 -0700 Subject: [PATCH 058/282] [Misc] Update Pull Request template (#3467) --- .github/pull_request_template.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index acfe341c075..a765ed4a114 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -2,10 +2,10 @@ -## What are the changes? +## What are the changes the user will see? -## Why am I doing these changes the user will see? +## Why am I making these changes? From 638a0a66b57cb1d5bf331be4d4dfbab21c0f6155 Mon Sep 17 00:00:00 2001 From: DustinLin <39450497+DustinLin@users.noreply.github.com> Date: Fri, 9 Aug 2024 22:27:22 -0700 Subject: [PATCH 059/282] [Bug] removing destroy() calls on enemy pokemon after BattleEndPhase and breaks endless %50 waves (#3461) --- src/phases.ts | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/phases.ts b/src/phases.ts index 46d1f4b98db..fcd3cfb8801 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -2581,15 +2581,6 @@ export class BattleEndPhase extends BattlePhase { this.scene.updateModifiers().then(() => this.end()); } - - end() { - // removing pokemon at the end of a battle - for (const p of this.scene.getEnemyParty()) { - p.destroy(); - } - - super.end(); - } } export class NewBattlePhase extends BattlePhase { From 566cd80522943790cd5102747bd790b6cae246a6 Mon Sep 17 00:00:00 2001 From: Tim Perdok <43152351+TimPerdok@users.noreply.github.com> Date: Sat, 10 Aug 2024 15:17:04 +0200 Subject: [PATCH 060/282] [Feature] Move touch controls configuration (Reopened) (#3256) * [Hotfix] Fix interactions of some moves not changing types (#3183) * [Hotfix] Fix wild spawns not having their HA (#3190) * [Hotfix] Allow to hatch pokemon with Hidden Ability again (#3222) * chore: Update TNC links layout and position in index.html * chore: Update TNC links font size in index.css (#3230) * Move Touch Controls * ConfigToolbar alignment * Insert config toolbar on open, camel-case classes, hidden setting * Better toolbar styling, fixed double configToolbar bug * Fixed typedocs --------- Co-authored-by: Adrian T. <68144167+torranx@users.noreply.github.com> Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> Co-authored-by: Frederico Santos --- index.css | 301 +++++++++----- index.html | 100 +++-- src/inputs-controller.ts | 3 + src/locales/de/settings.ts | 1 + src/locales/en/settings.ts | 1 + src/locales/es/settings.ts | 1 + src/locales/fr/settings.ts | 1 + src/locales/it/settings.ts | 1 + src/locales/ko/settings.ts | 1 + src/locales/pt_BR/settings.ts | 1 + src/locales/zh_CN/settings.ts | 1 + src/locales/zh_TW/settings.ts | 1 + src/system/settings/settings.ts | 21 +- src/test/utils/fakeMobile.html | 97 +++-- src/touch-controls.ts | 46 ++- .../settings/abstract-settings-ui-handler.ts | 26 +- .../settings/move-touch-controls-handler.ts | 380 ++++++++++++++++++ src/ui/settings/settings-audio-ui-handler.ts | 5 +- .../settings/settings-display-ui-handler.ts | 5 +- src/ui/settings/settings-ui-handler.ts | 5 +- 20 files changed, 794 insertions(+), 204 deletions(-) create mode 100644 src/ui/settings/move-touch-controls-handler.ts diff --git a/index.css b/index.css index be480ab6c78..54eda86161d 100644 --- a/index.css +++ b/index.css @@ -1,16 +1,8 @@ +/* Global */ :root { --color-base: hsl(0, 0%, 55%); --color-light: hsl(0, 0%, 90%); --color-dark: hsl(0, 0%, 10%); - --controls-size: 10vh; - --text-shadow-size: 0.65vh; -} - -@media (orientation: landscape) { - :root { - --controls-size: 20vh; - --text-shadow-size: 1.3vh; - } } html { @@ -43,33 +35,173 @@ body { transform-origin: top !important; } +#layout:fullscreen #dpad, #layout:fullscreen { + bottom: 6rem; +} + +input:-internal-autofill-selected { + -webkit-background-clip: text; + background-clip: text; +} + /* Need adjust input font-size */ input { font-size: 3.2rem; } +.hidden { + display: none !important; +} + + +input:-internal-autofill-selected { + -webkit-background-clip: text; + background-clip: text; +} + +/* Touch Controls: */ + +#touchControls { + --text-shadow-size: 0.65vh; + --controls-size: 10vh; + --touch-control-opacity: 0.6; + + --controls-padding: 1rem; + + --controls-size-with-padding: calc(var(--controls-size) + var(--controls-padding)); + --control-group-extra-size: calc(var(--controls-size) * 0.8); + + --control-group-extra-2-offset: calc(var(--controls-size-with-padding) + (var(--controls-size) - var(--control-group-extra-size)) / 2); + --control-group-extra-1-offset: calc(var(--controls-padding) + (var(--controls-size) - var(--control-group-extra-size)) / 2); + + --small-control-size: calc(var(--controls-size) / 3); + --rect-control-size: calc(var(--controls-size) * 0.74); + + font-family: 'emerald'; + font-size: var(--controls-size); + text-shadow: var(--color-dark) var(--text-shadow-size) var(--text-shadow-size); + color: var(--color-light); +} + +@media (orientation: landscape) { + #touchControls { + --controls-size: 20vh; + --text-shadow-size: 1.3vh; + --small-button-offset: 4vh; + } +} + #touchControls:not(.visible) { display: none; } -#dpad, #apad { +#touchControls .active { + opacity: var(--touch-control-opacity); +} + +.control-group { position: fixed; - bottom: 1rem; + display: flex; + flex-wrap: wrap; + justify-content: space-around; + align-items: center; + width: var(--controls-size); +} + +.control-group-dpad { + width: calc(2 * var(--controls-size)); + height: calc(2 * var(--controls-size)); +} + +.control-group-extra { + width: var(--control-group-extra-size); + height: var(--control-group-extra-size); +} +/* Hide buttons on specific UIs */ + +/* Show #cycleForm and #cycleShiny only on STARTER_SELECT and SETTINGS */ +#touchControls:not([data-ui-mode='STARTER_SELECT']):not([data-ui-mode^='SETTINGS']) #apadCycleForm, +#touchControls:not([data-ui-mode='STARTER_SELECT']):not([data-ui-mode^='SETTINGS']) #apadCycleShiny { + display: none; +} + +/* Show #apadInfo only in battle */ +#touchControls:not([data-ui-mode='COMMAND']):not([data-ui-mode='FIGHT']):not([data-ui-mode='BALL']) #apadInfo { + display: none; +} + +/* Show #apadInfo only in battle and target select */ +#touchControls:not([data-ui-mode='COMMAND']):not([data-ui-mode='FIGHT']):not([data-ui-mode='BALL']):not([data-ui-mode='TARGET_SELECT']):not([data-ui-mode='MODIFIER_SELECT']) #apadStats { + display: none; +} + +/* Show cycle buttons only on STARTER_SELECT and on touch configuration panel */ +#touchControls:not(.config-mode):not([data-ui-mode='STARTER_SELECT']) #apadCycleNature, +#touchControls:not(.config-mode):not([data-ui-mode='STARTER_SELECT']) #apadCycleAbility, +#touchControls:not(.config-mode):not([data-ui-mode='STARTER_SELECT']) #apadCycleGender, +#touchControls:not(.config-mode):not([data-ui-mode='STARTER_SELECT']) #apadCycleVariant { + display: none; +} + +/* Configuration toolbar */ + +#configToolbar { + width: 100%; + position: fixed; + top: 1rem; + left: 0; + z-index: 9; + user-select: none; +} + +#configToolbar .column { + display: flex; + flex-direction: column; + align-items: center; + gap: 10%; + padding: 0 var(--controls-padding); +} + +#configToolbar .button-row { + display: flex; + justify-content: space-evenly; + width: 100%; +} + +#configToolbar .info-row { + display: flex; + justify-content: flex-start; + width: 100%; +} + +#configToolbar .button { z-index: 3; + background-color: var(--color-base); + display: flex; + justify-content: center; + align-items: center; + text-align: center; + border-radius: 10%; + height: var(--small-control-size); + font-size: var(--small-control-size); + border-radius: 8px; + padding: 2px 8px; + text-shadow: var(--color-dark) calc(var(--text-shadow-size) / 3) calc(var(--text-shadow-size) / 3); } -@media (orientation: portrait) { - #dpad, #apad { - bottom: calc(1rem + env(safe-area-inset-bottom)); - } +#configToolbar .button:active { + opacity: var(--touch-control-opacity) } +#configToolbar .orientation-label { + font-size: var(--small-control-size); + text-shadow: var(--color-dark) calc(var(--text-shadow-size) / 3) calc(var(--text-shadow-size) / 3); +} + +/* dpad */ #dpad { - left: 1rem; -} - -#apad { - right: 1rem; + z-index: 3; + opacity: 0.8; } #dpad svg { @@ -78,114 +210,83 @@ input { fill: var(--color-base); } -#dpad svg rect { - opacity: 0.6; -} +/* apad buttons */ -#apad > * { - width: var(--controls-size); - height: var(--controls-size); -} - -#apad .apadBtn { - width: var(--controls-size); - height: var(--controls-size); +.apad-button { background-color: var(--color-base); border-radius: 50%; + display: flex; + justify-content: center; + align-items: center; + right: 0; + bottom: 0; + width: var(--controls-size); + height: var(--controls-size); + opacity: 0.8; + border-radius: 8px; } -#apad .apadLabel { - font-family: 'emerald'; - font-size: var(--controls-size); - text-shadow: var(--color-dark) var(--text-shadow-size) var(--text-shadow-size); - color: var(--color-light); +.apad-small { + width: var(--small-control-size); + height: var(--small-control-size); +} + +.apad-label { user-select: none; + height: 100%; + margin-right: -2px; } -#apad .apadLabelSmall { - font-size: calc(var(--controls-size) / 3); +.apad-small > .apad-label { + font-size: var(--small-control-size); text-shadow: var(--color-dark) calc(var(--text-shadow-size) / 3) calc(var(--text-shadow-size) / 3); } -#apad #apadLabelAction, #apad #apadLabelCancel { - margin-left: calc(var(--controls-size) / 3); - line-height: 0.9; -} - -#apad > :nth-child(2) { - position: relative; - right: var(--controls-size); -} - -#apad .apadRectBtn { - position: relative; +.apad-rectangle { text-align: center; - padding-right: 10%; - border-radius: 10%; - bottom: calc(var(--controls-size) * 0.05); - width: calc(var(--controls-size) * 0.6); - height: calc(var(--controls-size) * 0.3); + width: var(--rect-control-size); + height: var(--small-control-size); } -#apad .apadSqBtn { - border-radius: 10%; - width: calc(var(--controls-size) * 0.3); - height: calc(var(--controls-size) * 0.3); +.apad-square { + width: var(--small-control-size); + height: var(--small-control-size); } -#apad .apadBtnContainer { - position: relative; - display: flex; +.apad-circle { + width: var(--controls-size); + height: var(--controls-size); + border-radius: 50%; } -#apad .apadRectBtnContainer { - flex-wrap: wrap; - margin-top: calc(var(--controls-size) * -0.8); - left: calc(var(--controls-size) * 0.175); - height: calc(var(--controls-size) * 0.8); +/* Defaults:*/ + +#control-group-dpad { + left: var(--controls-padding); + bottom: var(--controls-padding); } -#apad .apadSqBtnContainer { - flex-wrap: wrap; - justify-content: space-evenly; - align-items: center; - margin-bottom: calc(var(--controls-size) * -0.8); - top: calc(var(--controls-size) * -0.9); - width: calc(var(--controls-size) * 0.8); - height: calc(var(--controls-size) * 0.8); +#control-group-action { + right: var(--controls-padding); + bottom: var(--controls-size-with-padding); } -#apad .apadRectBtnContainer > #apadMenu { - align-self: flex-end; +#control-group-cancel { + right: var(--controls-size-with-padding); + bottom: var(--controls-padding);; } -#apad .apadRectBtnContainer > .apadSqBtn:not(:first-child) { - margin-left: 10%; +#control-group-extra-1 { + right: var(--control-group-extra-1-offset); + bottom: var(--control-group-extra-1-offset); } -#touchControls:not([data-ui-mode='STARTER_SELECT']):not([data-ui-mode='SETTINGS']):not([data-ui-mode='SETTINGS_DISPLAY']):not([data-ui-mode='SETTINGS_AUDIO']):not([data-ui-mode='SETTINGS_GAMEPAD']):not([data-ui-mode='SETTINGS_KEYBOARD']) #apad .apadRectBtnContainer > .apadSqBtn:not(.apadBattle), -#touchControls:not([data-ui-mode='STARTER_SELECT']):not([data-ui-mode='SETTINGS']):not([data-ui-mode='SETTINGS_DISPLAY']):not([data-ui-mode='SETTINGS_AUDIO']):not([data-ui-mode='SETTINGS_GAMEPAD']):not([data-ui-mode='SETTINGS_KEYBOARD']) #apad .apadSqBtnContainer > .apadSqBtn:not(.apadBattle) -{ - display: none; +#control-group-extra-2 { + right: var(--control-group-extra-2-offset); + bottom: var(--control-group-extra-2-offset); } -#touchControls:not([data-ui-mode='COMMAND']):not([data-ui-mode='FIGHT']):not([data-ui-mode='BALL']):not([data-ui-mode='TARGET_SELECT']):not([data-ui-mode='MODIFIER_SELECT']) #apad .apadBattle { - display: none; -} - -#apad .apadRectBtnContainer + .apadSqBtnContainer { - top: calc(var(--controls-size) * -1.9); - left: calc(var(--controls-size) * -0.9); -} - -#apad .apadBtnContainer .apadLabel { - margin-left: calc(var(--controls-size) / 12); - line-height: 0.8; -} - -#dpad path:not(.active), #apad .apadBtn:not(.active) { - opacity: 0.6; -} +/* Layout */ #layout:fullscreen #dpad, #layout:fullscreen #apad { bottom: 6rem; diff --git a/index.html b/index.html index ebe5b063c52..5ebf822521e 100644 --- a/index.html +++ b/index.html @@ -64,54 +64,70 @@
-
- - - - - - - +
+
+
+ + + + + + + +
+
-
-
- A -
-
- B -
-
-
- R -
-
- V -
-
- C -
-
- Menu +
+
+
+ A
-
-
- F -
-
- G -
-
- E -
-
- N -
-
- V + +
+
+ B
+ +
+
+ R +
+
+ V +
+
+ C +
+
+ Menu +
+
+ +
+
+ F +
+
+ G +
+
+ E +
+
+ N +
+
+ V +
+
+