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/257] [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/257] [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/257] [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/257] 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/257] 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 3277551ce470b6099e9e32158e03fa4ae06dc50d Mon Sep 17 00:00:00 2001 From: protimita Date: Wed, 7 Aug 2024 09:34:30 +0530 Subject: [PATCH 006/257] [Localization] JA Translation move-trigger.ts (#3396) Health translations need to be checked in-game to see if they are used correctly. acquiredAbility is improvived. --- src/locales/ja/move-trigger.ts | 116 ++++++++++++++++----------------- 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/src/locales/ja/move-trigger.ts b/src/locales/ja/move-trigger.ts index 1d9d6459d83..720ae5df5a8 100644 --- a/src/locales/ja/move-trigger.ts +++ b/src/locales/ja/move-trigger.ts @@ -1,62 +1,62 @@ import { SimpleTranslationEntries } from "#app/interfaces/locales"; export const moveTriggers: SimpleTranslationEntries = { - "hitWithRecoil" : "{{pokemonName}} was damaged by the recoil!", - "cutHpPowerUpMove": "{{pokemonName}} cut its own HP to power up its move!", - "absorbedElectricity": "{{pokemonName}} absorbed electricity!", - "switchedStatChanges": "{{pokemonName}} switched stat changes with the target!", - "goingAllOutForAttack": "{{pokemonName}} is going all out for this attack!", - "regainedHealth": "{{pokemonName}} regained\nhealth!", - "keptGoingAndCrashed": "{{pokemonName}} kept going\nand crashed!", - "fled": "{{pokemonName}} fled!", - "cannotBeSwitchedOut": "{{pokemonName}} can't be switched out!", - "swappedAbilitiesWithTarget": "{{pokemonName}} swapped\nabilities with its target!", - "coinsScatteredEverywhere": "Coins were scattered everywhere!", - "attackedByItem": "{{pokemonName}} is about to be attacked by its {{itemName}}!", - "whippedUpAWhirlwind": "{{pokemonName}} whipped\nup a whirlwind!", - "flewUpHigh": "{{pokemonName}} flew\nup high!", - "tookInSunlight": "{{pokemonName}} absorbed light!", - "dugAHole": "{{pokemonName}} burrowed its way under the ground!", - "loweredItsHead": "{{pokemonName}} tucked in its head!", - "isGlowing": "{{pokemonName}} became cloaked in a harsh light!", - "bellChimed": "A bell chimed!", - "foresawAnAttack": "{{pokemonName}} foresaw\nan attack!", - "hidUnderwater": "{{pokemonName}} hid\nunderwater!", - "soothingAromaWaftedThroughArea": "A soothing aroma wafted through the area!", - "sprangUp": "{{pokemonName}} sprang up!", - "choseDoomDesireAsDestiny": "{{pokemonName}} chose\nDoom Desire as its destiny!", - "vanishedInstantly": "{{pokemonName}} vanished\ninstantly!", - "tookTargetIntoSky": "{{pokemonName}} took {{targetName}}\ninto the sky!", - "becameCloakedInFreezingLight": "{{pokemonName}} became cloaked\nin a freezing light!", - "becameCloakedInFreezingAir": "{{pokemonName}} became cloaked\nin freezing air!", - "isChargingPower": "{{pokemonName}} is absorbing power!", - "burnedItselfOut": "{{pokemonName}} burned itself out!", - "startedHeatingUpBeak": "{{pokemonName}} started\nheating up its beak!", - "isOverflowingWithSpacePower": "{{pokemonName}} is overflowing\nwith space power!", - "usedUpAllElectricity": "{{pokemonName}} used up all its electricity!", - "stoleItem": "{{pokemonName}} stole\n{{targetName}}'s {{itemName}}!", - "incineratedItem": "{{pokemonName}} incinerated\n{{targetName}}'s {{itemName}}!", - "knockedOffItem": "{{pokemonName}} knocked off\n{{targetName}}'s {{itemName}}!", - "tookMoveAttack": "{{pokemonName}} took\nthe {{moveName}} attack!", - "cutOwnHpAndMaximizedStat": "{{pokemonName}} cut its own HP\nand maximized its {{statName}}!", - "copiedStatChanges": "{{pokemonName}} copied\n{{targetName}}'s stat changes!", - "magnitudeMessage": "Magnitude {{magnitude}}!", - "tookAimAtTarget": "{{pokemonName}} took aim\nat {{targetName}}!", - "transformedIntoType": "{{pokemonName}} transformed\ninto the {{typeName}} type!", - "copiedMove": "{{pokemonName}} copied\n{{moveName}}!", - "sketchedMove": "{{pokemonName}} sketched\n{{moveName}}!", - "acquiredAbility": "The {{pokemonName}} acquired\n{{abilityName}}!", - "copiedTargetAbility": "{{pokemonName}} copied the {{targetName}}'s\n{{abilityName}}!", - "transformedIntoTarget": "{{pokemonName}} transformed\ninto {{targetName}}!", - "tryingToTakeFoeDown": "{{pokemonName}} is hoping to take its attacker down with it!", - "addType": "{{typeName}} was added to\n{{pokemonName}}!", - "cannotUseMove": "{{pokemonName}} cannot use {{moveName}}!", - "healHp": "{{pokemonName}} had its HP restored.", - "sacrificialFullRestore": "{{pokemonName}}'s Healing Wish\nwas granted!", - "invertStats": "{{pokemonName}}'s stat changes\nwere all reversed!", - "resetStats": "{{pokemonName}}'s stat changes\nwere 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!", - "swapArenaTags": "{{pokemonName}} swapped the battle effects affecting each side of the field!", + "hitWithRecoil" : "{{pokemonName}}は\nはんどうによる ダメージを うけた!", + "cutHpPowerUpMove": "{{pokemonName}}は\nたいりょくを けずって パワーぜんかい!", + "absorbedElectricity": "{{pokemonName}}は\n でんきを きゅうしゅうした!", + "switchedStatChanges": "{{pokemonName}}は あいてと じぶんのn\のうりょくへんかを いれかえた!", + "goingAllOutForAttack": "{{pokemonName}}は\nほんきを だした!", + "regainedHealth": "{{pokemonName}}は\nたいりょくを かいふくした!", + "keptGoingAndCrashed": "いきおいあまって {{pokemonName}}は\nじめんに ぶつかった!", + "fled": "{{pokemonName}}は にげだした!", + "cannotBeSwitchedOut": "{{pokemonName}}を\nもどすことが できない!", + "swappedAbilitiesWithTarget": "{{pokemonName}}は\nおたがいの とくせいを いれかえた!", + "coinsScatteredEverywhere": "こばんが あたりに ちらばった!", + "attackedByItem": "{{pokemonName}}に\n{{itemName}}が おそいかかる!", + "whippedUpAWhirlwind": "{{pokemonName}}の まわりで\nくうきが うずをまく!", + "flewUpHigh": "{{pokemonName}}は\nそらたかく とびあがった!", + "tookInSunlight": "{{pokemonName}}は\nひかりを きゅうしゅうした!", + "dugAHole": "{{pokemonName}}は\nじめんに もぐった!", + "loweredItsHead": "{{pokemonName}}は\nくびを ひっこめた!", + "isGlowing": "{{pokemonName}}を\nはげしいひかりが つつむ!", + "bellChimed": "すずのおとが ひびきわたった!", + "foresawAnAttack": "{{pokemonName}}は\nみらいに こうげきを よちした!", + "hidUnderwater": "{{pokemonName}}は\nすいちゅうに みをひそめた!", + "soothingAromaWaftedThroughArea": "ここちよい かおりが ひろがった!", + "sprangUp": "{{pokemonName}}は\nたかく とびはねた!", + "choseDoomDesireAsDestiny": "{{pokemonName}}は\nはめつのねがいを みらいに たくした!", + "vanishedInstantly": "{{pokemonName}}の すがたが\nいっしゅんにして きえた!", + "tookTargetIntoSky": "{{pokemonName}}は {{targetName}}を\nじょうくうに つれさった!", + "becameCloakedInFreezingLight": "{{pokemonName}}は\nつめたいひかりに つつまれた!", + "becameCloakedInFreezingAir": "{{pokemonName}}は\nこごえるくうきに つつまれた!", + "isChargingPower": "{{pokemonName}}は\nパワーを ためこんでいる!", + "burnedItselfOut": "{{pokemonName}}の ほのうは\nもえつきた!", + "startedHeatingUpBeak": "{{pokemonName}}は\nクチバシを かねつしはじめた!", + "isOverflowingWithSpacePower": "{{pokemonName}}に\nうちゅうの ちからが あふれだす!", + "usedUpAllElectricity": "{{pokemonName}}は\nでんきを つかいきった!", + "stoleItem": "{{pokemonName}}は\n{{targetName}}の {{itemName}}を ぬすんだ!", + "incineratedItem": "{{pokemonName}}は\n{{targetName}}の {{itemName}}を もやした!", + "knockedOffItem": "{{pokemonName}}は\n{{targetName}}の {{itemName}}を はたきおとした!", + "tookMoveAttack": "{{pokemonName}}は\n{{moveName}}の こうげきを うけた!", + "cutOwnHpAndMaximizedStat": "{{pokemonName}}は\nたいりょくを けずって {{statName}}ぜんかい!", + "copiedStatChanges": "{{pokemonName}}は {{targetName}}の\nのうりょくへんかを コピーした!", + "magnitudeMessage": "マグニチュード{{magnitude}}!", + "tookAimAtTarget": "{{pokemonName}}は {{targetName}}に\nねらいを さだめた!", + "transformedIntoType": "{{pokemonName}}は\n{{typeName}}タイプに なった!", + "copiedMove": "{{pokemonName}}は\n{{moveName}}を コピーした!", + "sketchedMove": "{{pokemonName}}は\n{{moveName}}を スケッチした!", + "acquiredAbility": "{{pokemonName}}の とくせいが\n{{abilityName}}に なった!", + "copiedTargetAbility": "{{pokemonName}}は\n{{targetName}}の {{abilityName}}を コピーした!", + "transformedIntoTarget": "{{pokemonName}}は\n{{targetName}}に へんしんした!", + "tryingToTakeFoeDown": "{{pokemonName}}は あいてを\nみちづれに しようとしている!", + "addType": "{{pokemonName}}に\n{{typeName}}タイプが ついかされた!", + "cannotUseMove": "{{pokemonName}}は\n{{moveName}}を つかえなかった!", + "healHp": "{{pokemonName}}の\nたいりょくが かいふくした!", + "sacrificialFullRestore": "{{pokemonName}}の\nねがいごとが かなった!", + "invertStats": "{{pokemonName}}の\nのうりょくへんかが ぎゃくてんした!", + "resetStats": "{{pokemonName}}の\nのうりょくへんかが もとにもどった!", + "faintCountdown": "{{pokemonName}}は\n{{turnCount}}ターンごに ほろびてしまう!", + "copyType": "{{pokemonName}}は {{targetPokemonName}}と\n同じタイプに なった!", + "suppressAbilities": "{{pokemonName}}の とくせいが きかなくなった!", + "swapArenaTags": "{{pokemonName}}は\nおたがいの ばのこうかを いれかえた!", } as const; From d2e1340c0c75a3e8bcf098ab96a660ec02fcb7b9 Mon Sep 17 00:00:00 2001 From: sodam <66295123+sodaMelon@users.noreply.github.com> Date: Wed, 7 Aug 2024 13:37:22 +0900 Subject: [PATCH 007/257] [Localization] Fixed some trainer names (ko) (#3397) * fixed trainers name wrong * removed note(it checked by LeKaaN with pokerogue wiki) * removed unnecessary spaces --- src/locales/ko/trainers.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/locales/ko/trainers.ts b/src/locales/ko/trainers.ts index 3a139026448..1671dd7a45b 100644 --- a/src/locales/ko/trainers.ts +++ b/src/locales/ko/trainers.ts @@ -36,7 +36,7 @@ export const trainerClasses: SimpleTranslationEntries = { "baker": "제빵사", "battle_girl": "배틀걸", "beauty": "아가씨", - "beginners": "반바지 꼬마 & 짧은 치마", // 확인 필요 + "beginners": "반바지 꼬마 & 짧은 치마", "biker": "폭주족", "black_belt": "태권왕", "breeder": "포켓몬 브리더", @@ -62,7 +62,7 @@ export const trainerClasses: SimpleTranslationEntries = { "guitarist_female": "기타리스트", "harlequin": "어릿광대", "hiker": "등산가", - "hooligans": "폭주족 & 빡빡이", // 확인 필요 + "hooligans": "폭주족 & 빡빡이", "hoopster": "농구선수", "infielder": "야구선수", "janitor": "청소부", @@ -92,7 +92,7 @@ export const trainerClasses: SimpleTranslationEntries = { "pokémon_ranger_female": "포켓몬 레인저", "pokémon_rangers": "포켓몬 레인저", "ranger": "포켓몬 레인저", - "restaurant_staff": "요리사", // 혹은 오너로 추정 + "restaurant_staff": "레스토랑 직원", "rich": "신사", "rich_female": "마담", "rich_boy": "도련님", @@ -114,7 +114,7 @@ export const trainerClasses: SimpleTranslationEntries = { "school_kids": "학원끝난 아이", "swimmer": "수영팬티 소년", "swimmer_female": "비키니 아가씨", - "swimmers": "수영팬티 소년 & 비키니 아가씨", // 확인 필요 + "swimmers": "수영팬티 소년 & 비키니 아가씨", "twins": "쌍둥이", "veteran": "베테랑 트레이너", "veteran_female": "베테랑 트레이너", From f555dd6dc849338c5edb938f168d8b3cea554f19 Mon Sep 17 00:00:00 2001 From: Alex Van Liew Date: Tue, 6 Aug 2024 23:29:51 -0700 Subject: [PATCH 008/257] [Bug] Fix a couple small issues with uturn and friends (#3321) * prevent double-application of status contact abilities and switch out abilities * use SwitchPhase for ForceSwitchOutAbAttr instead of switchOut() * add tests for baton pass/uturn * PR comments * Update src/test/moves/baton_pass.test.ts * add test for forced switch after mutual KO + revive * tweak condition to fix uturn/baton pass * improve docs * style/typo nits from CR Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> * CR feedback * use doSelectPartyPokemon + rename * int -> number Co-authored-by: Adrian T. <68144167+torranx@users.noreply.github.com> --------- Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com> Co-authored-by: Adrian T. <68144167+torranx@users.noreply.github.com> --- src/data/move.ts | 17 +++--- src/phases.ts | 23 ++++++- src/test/battle/battle.test.ts | 48 ++++++++++++++- src/test/moves/baton_pass.test.ts | 93 ++++++++++++++++++++++++++++ src/test/moves/u_turn.test.ts | 98 ++++++++++++++++++++++++++++++ src/test/utils/gameManager.ts | 47 +++++++++----- src/test/utils/phaseInterceptor.ts | 11 +++- src/ui/party-ui-handler.ts | 74 ++++++++++++++++++++-- 8 files changed, 376 insertions(+), 35 deletions(-) create mode 100644 src/test/moves/baton_pass.test.ts create mode 100644 src/test/moves/u_turn.test.ts diff --git a/src/data/move.ts b/src/data/move.ts index 28cfc6f2668..d93869dedb9 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -1,5 +1,5 @@ import { ChargeAnim, MoveChargeAnim, initMoveAnim, loadMoveAnimAssets } from "./battle-anims"; -import { BattleEndPhase, MoveEndPhase, MovePhase, NewBattlePhase, PartyStatusCurePhase, PokemonHealPhase, StatChangePhase, SwitchSummonPhase } from "../phases"; +import { BattleEndPhase, MoveEndPhase, MovePhase, NewBattlePhase, PartyStatusCurePhase, PokemonHealPhase, StatChangePhase, SwitchPhase, SwitchSummonPhase } from "../phases"; import { BattleStat, getBattleStatName } from "./battle-stat"; import { EncoreTag, GulpMissileTag, HelpingHandTag, SemiInvulnerableTag, StockpilingTag, TypeBoostTag } from "./battler-tags"; import { getPokemonNameWithAffix } from "../messages"; @@ -10,7 +10,7 @@ import { Constructor } from "#app/utils"; import * as Utils from "../utils"; import { WeatherType } from "./weather"; import { ArenaTagSide, ArenaTrapTag, WeakenMoveTypeTag } from "./arena-tag"; -import { UnswappableAbilityAbAttr, UncopiableAbilityAbAttr, UnsuppressableAbilityAbAttr, BlockRecoilDamageAttr, BlockOneHitKOAbAttr, IgnoreContactAbAttr, MaxMultiHitAbAttr, applyAbAttrs, BlockNonDirectDamageAbAttr, applyPreSwitchOutAbAttrs, PreSwitchOutAbAttr, applyPostDefendAbAttrs, PostDefendContactApplyStatusEffectAbAttr, MoveAbilityBypassAbAttr, ReverseDrainAbAttr, FieldPreventExplosiveMovesAbAttr, ForceSwitchOutImmunityAbAttr, BlockItemTheftAbAttr, applyPostAttackAbAttrs, ConfusionOnStatusEffectAbAttr, HealFromBerryUseAbAttr, IgnoreProtectOnContactAbAttr, IgnoreMoveEffectsAbAttr, applyPreDefendAbAttrs, MoveEffectChanceMultiplierAbAttr, WonderSkinAbAttr, applyPreAttackAbAttrs, MoveTypeChangeAttr, UserFieldMoveTypePowerBoostAbAttr, FieldMoveTypePowerBoostAbAttr, AllyMoveCategoryPowerBoostAbAttr, VariableMovePowerAbAttr } from "./ability"; +import { UnswappableAbilityAbAttr, UncopiableAbilityAbAttr, UnsuppressableAbilityAbAttr, BlockRecoilDamageAttr, BlockOneHitKOAbAttr, IgnoreContactAbAttr, MaxMultiHitAbAttr, applyAbAttrs, BlockNonDirectDamageAbAttr, MoveAbilityBypassAbAttr, ReverseDrainAbAttr, FieldPreventExplosiveMovesAbAttr, ForceSwitchOutImmunityAbAttr, BlockItemTheftAbAttr, applyPostAttackAbAttrs, ConfusionOnStatusEffectAbAttr, HealFromBerryUseAbAttr, IgnoreProtectOnContactAbAttr, IgnoreMoveEffectsAbAttr, applyPreDefendAbAttrs, MoveEffectChanceMultiplierAbAttr, WonderSkinAbAttr, applyPreAttackAbAttrs, MoveTypeChangeAttr, UserFieldMoveTypePowerBoostAbAttr, FieldMoveTypePowerBoostAbAttr, AllyMoveCategoryPowerBoostAbAttr, VariableMovePowerAbAttr } from "./ability"; import { allAbilities } from "./ability"; import { PokemonHeldItemModifier, BerryModifier, PreserveBerryModifier, PokemonMoveAccuracyBoosterModifier, AttackTypeBoosterModifier, PokemonMultiHitModifier } from "../modifier/modifier"; import { BattlerIndex, BattleType } from "../battle"; @@ -4806,13 +4806,15 @@ export class ForceSwitchOutAttr extends MoveEffectAttr { this.batonPass = !!batonPass; } + isBatonPass() { + return this.batonPass; + } + apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): Promise { return new Promise(resolve => { // Check if the move category is not STATUS or if the switch out condition is not met if (!this.getSwitchOutCondition()(user, target, move)) { - //Apply effects before switch out i.e. poison point, flame body, etc - applyPostDefendAbAttrs(PostDefendContactApplyStatusEffectAbAttr, target, user, move, null); return resolve(false); } @@ -4820,10 +4822,11 @@ export class ForceSwitchOutAttr extends MoveEffectAttr { // This ensures that the switch out only happens when the conditions are met const switchOutTarget = this.user ? user : target; if (switchOutTarget instanceof PlayerPokemon) { + switchOutTarget.leaveField(!this.batonPass); + if (switchOutTarget.hp > 0) { - applyPreSwitchOutAbAttrs(PreSwitchOutAbAttr, switchOutTarget); - // switchOut below sets the UI to select party(this is not a separate Phase), then adds a SwitchSummonPhase with selected 'mon - (switchOutTarget as PlayerPokemon).switchOut(this.batonPass).then(() => resolve(true)); + user.scene.prependToPhase(new SwitchPhase(user.scene, switchOutTarget.getFieldIndex(), true, true), MoveEndPhase); + resolve(true); } else { resolve(false); } diff --git a/src/phases.ts b/src/phases.ts index e88f0699918..f561ea6f3fc 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -4464,11 +4464,24 @@ export class PostGameOverPhase extends Phase { } } +/** + * Opens the party selector UI and transitions into a {@linkcode SwitchSummonPhase} + * for the player (if a switch would be valid for the current battle state). + */ export class SwitchPhase extends BattlePhase { protected fieldIndex: integer; private isModal: boolean; private doReturn: boolean; + /** + * Creates a new SwitchPhase + * @param scene {@linkcode BattleScene} Current battle scene + * @param fieldIndex Field index to switch out + * @param isModal Indicates if the switch should be forced (true) or is + * optional (false). + * @param doReturn Indicates if the party member on the field should be + * recalled to ball or has already left the field. Passed to {@linkcode SwitchSummonPhase}. + */ constructor(scene: BattleScene, fieldIndex: integer, isModal: boolean, doReturn: boolean) { super(scene); @@ -4480,13 +4493,17 @@ export class SwitchPhase extends BattlePhase { start() { super.start(); - // Skip modal switch if impossible + // Skip modal switch if impossible (no remaining party members that aren't in battle) if (this.isModal && !this.scene.getParty().filter(p => p.isAllowedInBattle() && !p.isActive(true)).length) { return super.end(); } - // Skip if the fainted party member has been revived already - if (this.isModal && !this.scene.getParty()[this.fieldIndex].isFainted()) { + // Skip if the fainted party member has been revived already. doReturn is + // only passed as `false` from FaintPhase (as opposed to other usages such + // as ForceSwitchOutAttr or CheckSwitchPhase), so we only want to check this + // if the mon should have already been returned but is still alive and well + // on the field. see also; battle.test.ts + if (this.isModal && !this.doReturn && !this.scene.getParty()[this.fieldIndex].isFainted()) { return super.end(); } diff --git a/src/test/battle/battle.test.ts b/src/test/battle/battle.test.ts index 35eae9b96d2..21b890d9cf0 100644 --- a/src/test/battle/battle.test.ts +++ b/src/test/battle/battle.test.ts @@ -1,9 +1,24 @@ import { allSpecies } from "#app/data/pokemon-species"; +import { TempBattleStat } from "#app/data/temp-battle-stat.js"; import { GameModes } from "#app/game-mode"; import { getGameMode } from "#app/game-mode.js"; -import { CommandPhase, DamagePhase, EncounterPhase, EnemyCommandPhase, LoginPhase, SelectGenderPhase, SelectModifierPhase, SelectStarterPhase, SummonPhase, TitlePhase, TurnInitPhase, VictoryPhase } from "#app/phases"; -import GameManager from "#test/utils/gameManager"; -import { generateStarter, getMovePosition, } from "#test/utils/gameManagerUtils"; +import { + BattleEndPhase, + CommandPhase, DamagePhase, + EncounterPhase, + EnemyCommandPhase, + LoginPhase, + NextEncounterPhase, + SelectGenderPhase, + SelectModifierPhase, + SelectStarterPhase, + SummonPhase, + SwitchPhase, + TitlePhase, + TurnInitPhase, VictoryPhase, +} from "#app/phases"; +import GameManager from "#app/test/utils/gameManager"; +import { generateStarter, getMovePosition, } from "#app/test/utils/gameManagerUtils"; import { Command } from "#app/ui/command-ui-handler"; import { Mode } from "#app/ui/ui"; import { Abilities } from "#enums/abilities"; @@ -12,6 +27,7 @@ import { PlayerGender } from "#enums/player-gender"; import { Species } from "#enums/species"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import { SPLASH_ONLY } from "../utils/testUtils"; describe("Test Battle Phase", () => { let phaserGame: Phaser.Game; @@ -312,5 +328,31 @@ describe("Test Battle Phase", () => { await game.toNextWave(); expect(game.scene.currentBattle.waveIndex).toBeGreaterThan(waveIndex); }, 20000); + + it("does not force switch if active pokemon faints at same time as enemy mon and is revived in post-battle", async () => { + const moveToUse = Moves.TAKE_DOWN; + game.override + .battleType("single") + .starterSpecies(Species.SAWK) + .enemySpecies(Species.RATTATA) + .startingWave(1) + .startingLevel(100) + .moveset([moveToUse]) + .enemyMoveset(SPLASH_ONLY) + .startingHeldItems([{ name: "TEMP_STAT_BOOSTER", type: TempBattleStat.ACC }]); + + await game.startBattle(); + game.scene.getPlayerPokemon().hp = 1; + game.doAttack(getMovePosition(game.scene, 0, moveToUse)); + + await game.phaseInterceptor.to(BattleEndPhase); + game.doRevivePokemon(0); // pretend max revive was picked + game.doSelectModifier(); + + game.onNextPrompt("SwitchPhase", Mode.PARTY, () => { + expect.fail("Switch was forced"); + }, () => game.isCurrentPhase(NextEncounterPhase)); + await game.phaseInterceptor.to(SwitchPhase); + }, 20000); }); diff --git a/src/test/moves/baton_pass.test.ts b/src/test/moves/baton_pass.test.ts new file mode 100644 index 00000000000..ba961613998 --- /dev/null +++ b/src/test/moves/baton_pass.test.ts @@ -0,0 +1,93 @@ +import { BattleStat } from "#app/data/battle-stat.js"; +import { PostSummonPhase, TurnEndPhase } from "#app/phases.js"; +import GameManager from "#app/test/utils/gameManager"; +import { getMovePosition } from "#app/test/utils/gameManagerUtils"; +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 "../utils/testUtils"; + + +describe("Moves - Baton Pass", () => { + 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") + .enemySpecies(Species.DUGTRIO) + .startingLevel(1) + .startingWave(97) + .moveset([Moves.BATON_PASS, Moves.NASTY_PLOT, Moves.SPLASH]) + .enemyMoveset(SPLASH_ONLY) + .disableCrits(); + }); + + it("passes stat stage buffs when player uses it", async() => { + // arrange + await game.startBattle([ + Species.RAICHU, + Species.SHUCKLE + ]); + + // 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); + + // round 2 - baton pass + game.doAttack(getMovePosition(game.scene, 0, Moves.BATON_PASS)); + game.doSelectPartyPokemon(1); + 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); + }, 20000); + + it("passes stat stage buffs when AI uses it", async() => { + // arrange + game.override + .startingWave(5) + .enemyMoveset(new Array(4).fill([Moves.NASTY_PLOT])); + await game.startBattle([ + Species.RAICHU, + Species.SHUCKLE + ]); + + // round 1 - ai buffs + game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + await game.toNextTurn(); + + // round 2 - baton pass + 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); + // 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.phaseInterceptor.log.slice(-4)).toEqual([ + "MoveEffectPhase", + "SwitchSummonPhase", + "SummonPhase", + "PostSummonPhase" + ]); + }, 20000); +}); diff --git a/src/test/moves/u_turn.test.ts b/src/test/moves/u_turn.test.ts new file mode 100644 index 00000000000..c54a94dde2b --- /dev/null +++ b/src/test/moves/u_turn.test.ts @@ -0,0 +1,98 @@ +import { Abilities } from "#app/enums/abilities.js"; +import { SwitchPhase, TurnEndPhase } from "#app/phases"; +import GameManager from "#app/test/utils/gameManager"; +import { getMovePosition } from "#app/test/utils/gameManagerUtils"; +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 { StatusEffect } from "#app/enums/status-effect.js"; +import { SPLASH_ONLY } from "../utils/testUtils"; + +describe("Moves - U-turn", () => { + 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") + .enemySpecies(Species.GENGAR) + .startingLevel(90) + .startingWave(97) + .moveset([Moves.U_TURN]) + .enemyMoveset(SPLASH_ONLY) + .disableCrits(); + }); + + it("triggers regenerator a single time when a regenerator user switches out with u-turn", async() => { + // arrange + const playerHp = 1; + game.override.ability(Abilities.REGENERATOR); + await game.startBattle([ + Species.RAICHU, + Species.SHUCKLE + ]); + game.scene.getPlayerPokemon().hp = playerHp; + + // act + game.doAttack(getMovePosition(game.scene, 0, Moves.U_TURN)); + game.doSelectPartyPokemon(1); + await game.phaseInterceptor.to(TurnEndPhase); + + // 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); + }, 20000); + + it("triggers rough skin on the u-turn user before a new pokemon is switched in", async() => { + // arrange + game.override.enemyAbility(Abilities.ROUGH_SKIN); + await game.startBattle([ + Species.RAICHU, + Species.SHUCKLE + ]); + + // act + game.doAttack(getMovePosition(game.scene, 0, Moves.U_TURN)); + game.doSelectPartyPokemon(1); + 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); + expect(game.phaseInterceptor.log).not.toContain("SwitchSummonPhase"); + }, 20000); + + it("triggers contact abilities on the u-turn user (eg poison point) before a new pokemon is switched in", async() => { + // arrange + game.override.enemyAbility(Abilities.POISON_POINT); + await game.startBattle([ + Species.RAICHU, + Species.SHUCKLE + ]); + 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 + expect(game.phaseInterceptor.log).not.toContain("SwitchSummonPhase"); + }, 20000); +}); diff --git a/src/test/utils/gameManager.ts b/src/test/utils/gameManager.ts index ac7f7aea4d2..5540295d341 100644 --- a/src/test/utils/gameManager.ts +++ b/src/test/utils/gameManager.ts @@ -1,7 +1,7 @@ import GameWrapper from "#test/utils/gameWrapper"; import { Mode } from "#app/ui/ui"; import { generateStarter, waitUntil } from "#test/utils/gameManagerUtils"; -import { CommandPhase, EncounterPhase, FaintPhase, LoginPhase, NewBattlePhase, SelectStarterPhase, SelectTargetPhase, TitlePhase, TurnEndPhase, TurnInitPhase, TurnStartPhase } from "#app/phases"; +import { CommandPhase, EncounterPhase, FaintPhase, LoginPhase, MovePhase, NewBattlePhase, SelectStarterPhase, SelectTargetPhase, TitlePhase, TurnEndPhase, TurnInitPhase, TurnStartPhase } from "#app/phases"; import BattleScene from "#app/battle-scene.js"; import PhaseInterceptor from "#test/utils/phaseInterceptor"; import TextInterceptor from "#test/utils/TextInterceptor"; @@ -9,13 +9,12 @@ import { GameModes, getGameMode } from "#app/game-mode"; import fs from "fs"; import { AES, enc } from "crypto-js"; import { updateUserInfo } from "#app/account"; -import InputsHandler from "#test/utils/inputsHandler"; -import ErrorInterceptor from "#test/utils/errorInterceptor"; +import InputsHandler from "#app/test/utils/inputsHandler"; +import ErrorInterceptor from "#app/test/utils/errorInterceptor"; import { EnemyPokemon, PlayerPokemon } from "#app/field/pokemon"; -import { MockClock } from "#test/utils/mocks/mockClock"; -import { Command } from "#app/ui/command-ui-handler"; -import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler"; -import PartyUiHandler, { PartyUiMode } from "#app/ui/party-ui-handler"; +import { MockClock } from "#app/test/utils/mocks/mockClock"; +import PartyUiHandler from "#app/ui/party-ui-handler"; +import CommandUiHandler, { Command } from "#app/ui/command-ui-handler"; import Trainer from "#app/field/trainer"; import { ExpNotification } from "#enums/exp-notification"; import { GameDataType } from "#enums/game-data-type"; @@ -28,6 +27,7 @@ import { OverridesHelper } from "./overridesHelper"; import { ModifierTypeOption, modifierTypes } from "#app/modifier/modifier-type.js"; import overrides from "#app/overrides.js"; import { removeEnemyHeldItems } from "./testUtils"; +import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler.js"; /** * Class to manage the game state and transitions between phases. @@ -178,7 +178,7 @@ export default class GameManager { if (move.isMultiTarget()) { handler.processInput(Button.ACTION); } - }, () => this.isCurrentPhase(CommandPhase) || this.isCurrentPhase(TurnEndPhase)); + }, () => this.isCurrentPhase(CommandPhase) || this.isCurrentPhase(MovePhase) || this.isCurrentPhase(TurnEndPhase)); } /** @@ -313,20 +313,20 @@ export default class GameManager { } /** - * Switch pokemon and transition to the enemy command phase + * Command an in-battle switch to another Pokemon via the main battle menu. * @param pokemonIndex the index of the pokemon in your party to switch to */ doSwitchPokemon(pokemonIndex: number) { this.onNextPrompt("CommandPhase", Mode.COMMAND, () => { - this.scene.ui.setMode(Mode.PARTY, PartyUiMode.SWITCH, (this.scene.getCurrentPhase() as CommandPhase).getPokemon().getFieldIndex(), null, PartyUiHandler.FilterNonFainted); - }); - this.onNextPrompt("CommandPhase", Mode.PARTY, () => { - (this.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.POKEMON, pokemonIndex, false); + (this.scene.ui.getHandler() as CommandUiHandler).setCursor(2); + (this.scene.ui.getHandler() as CommandUiHandler).processInput(Button.ACTION); }); + + this.doSelectPartyPokemon(pokemonIndex, "CommandPhase"); } /** - * Revive pokemon, currently player's only. + * Revive pokemon, currently players only. * @param pokemonIndex the index of the pokemon in your party to revive */ doRevivePokemon(pokemonIndex: number) { @@ -335,4 +335,23 @@ export default class GameManager { const modifier = candidate.type.newModifier(party[pokemonIndex]); this.scene.addModifier(modifier, false); } + + /** + * Select a pokemon from the party menu. Only really handles the basic cases + * of the party UI, where you just need to navigate to a party slot and press + * Action twice - navigating any menus that come up after you select a party member + * is not supported. + * @param slot the index of the pokemon in your party to switch to + * @param inPhase Which phase to expect the selection to occur in. Typically + * non-command switch actions happen in SwitchPhase. + */ + doSelectPartyPokemon(slot: number, inPhase = "SwitchPhase") { + this.onNextPrompt(inPhase, Mode.PARTY, () => { + const partyHandler = this.scene.ui.getHandler() as PartyUiHandler; + + partyHandler.setCursor(slot); + partyHandler.processInput(Button.ACTION); // select party slot + partyHandler.processInput(Button.ACTION); // send out (or whatever option is at the top) + }); + } } diff --git a/src/test/utils/phaseInterceptor.ts b/src/test/utils/phaseInterceptor.ts index 383624bf298..aabde643aa8 100644 --- a/src/test/utils/phaseInterceptor.ts +++ b/src/test/utils/phaseInterceptor.ts @@ -42,7 +42,7 @@ import { QuietFormChangePhase } from "#app/form-change-phase"; export default class PhaseInterceptor { public scene; public phases = {}; - public log; + public log: string[]; private onHold; private interval; private promptInterval; @@ -104,13 +104,20 @@ export default class PhaseInterceptor { */ constructor(scene) { this.scene = scene; - this.log = []; this.onHold = []; this.prompts = []; + this.clearLogs(); this.startPromptHandler(); this.initPhases(); } + /** + * Clears phase logs + */ + clearLogs() { + this.log = []; + } + rejectAll(error) { if (this.inProgress) { clearInterval(this.promptInterval); diff --git a/src/ui/party-ui-handler.ts b/src/ui/party-ui-handler.ts index 80ce318532b..7b77b71f4ec 100644 --- a/src/ui/party-ui-handler.ts +++ b/src/ui/party-ui-handler.ts @@ -1,13 +1,13 @@ import { CommandPhase, SelectModifierPhase } from "../phases"; import BattleScene from "../battle-scene"; -import { PlayerPokemon, PokemonMove } from "../field/pokemon"; +import { MoveResult, PlayerPokemon, PokemonMove } from "../field/pokemon"; import { addBBCodeTextObject, addTextObject, getTextColor, TextStyle } from "./text"; import { Command } from "./command-ui-handler"; import MessageUiHandler from "./message-ui-handler"; import { Mode } from "./ui"; import * as Utils from "../utils"; import { PokemonBaseStatModifier, PokemonFormChangeItemModifier, PokemonHeldItemModifier, SwitchEffectTransferModifier } from "../modifier/modifier"; -import { allMoves } from "../data/move"; +import { allMoves, ForceSwitchOutAttr } from "../data/move"; import { getGenderColor, getGenderSymbol } from "../data/gender"; import { StatusEffect } from "../data/status-effect"; import PokemonIconAnimHandler, { PokemonIconAnimMode } from "./pokemon-icon-anim-handler"; @@ -25,18 +25,69 @@ import { getPokemonNameWithAffix } from "#app/messages.js"; const defaultMessage = i18next.t("partyUiHandler:choosePokemon"); +/** + * Indicates the reason why the party UI is being opened. + */ export enum PartyUiMode { + /** + * Indicates that the party UI is open because of a user-opted switch. This + * type of switch can be cancelled. + */ SWITCH, + /** + * Indicates that the party UI is open because of a faint or other forced + * switch (eg, move effect). This type of switch cannot be cancelled. + */ FAINT_SWITCH, + /** + * Indicates that the party UI is open because of a start-of-encounter optional + * switch. This type of switch can be cancelled. + */ POST_BATTLE_SWITCH, + /** + * Indicates that the party UI is open because of the move Revival Blessing. + * This selection cannot be cancelled. + */ REVIVAL_BLESSING, + /** + * Indicates that the party UI is open to select a mon to apply a modifier to. + * This type of selection can be cancelled. + */ MODIFIER, + /** + * Indicates that the party UI is open to select a mon to apply a move + * modifier to (such as an Ether or PP Up). This type of selection can be cancelled. + */ MOVE_MODIFIER, + /** + * Indicates that the party UI is open to select a mon to teach a TM. This + * type of selection can be cancelled. + */ TM_MODIFIER, + /** + * Indicates that the party UI is open to select a mon to remember a move. + * This type of selection can be cancelled. + */ REMEMBER_MOVE_MODIFIER, + /** + * Indicates that the party UI is open to transfer items between mons. This + * type of selection can be cancelled. + */ MODIFIER_TRANSFER, + /** + * Indicates that the party UI is open because of a DNA Splicer. This + * type of selection can be cancelled. + */ SPLICE, + /** + * Indicates that the party UI is open to release a party member. This + * type of selection can be cancelled. + */ RELEASE, + /** + * Indicates that the party UI is open to check the team. This + * type of selection can be cancelled. + */ CHECK } @@ -767,10 +818,21 @@ export default class PartyUiHandler extends MessageUiHandler { case PartyUiMode.FAINT_SWITCH: case PartyUiMode.POST_BATTLE_SWITCH: if (this.cursor >= this.scene.currentBattle.getBattlerCount()) { - this.options.push(PartyOption.SEND_OUT); - if (this.partyUiMode !== PartyUiMode.FAINT_SWITCH - && this.scene.findModifier(m => m instanceof SwitchEffectTransferModifier - && (m as SwitchEffectTransferModifier).pokemonId === this.scene.getPlayerField()[this.fieldIndex].id)) { + const allowBatonModifierSwitch = + this.partyUiMode !== PartyUiMode.FAINT_SWITCH + && this.scene.findModifier(m => m instanceof SwitchEffectTransferModifier + && (m as SwitchEffectTransferModifier).pokemonId === this.scene.getPlayerField()[this.fieldIndex].id); + + const moveHistory = this.scene.getPlayerField()[this.fieldIndex].getMoveHistory(); + const isBatonPassMove = this.partyUiMode === PartyUiMode.FAINT_SWITCH && moveHistory.length && allMoves[moveHistory[moveHistory.length - 1].move].getAttrs(ForceSwitchOutAttr)[0]?.isBatonPass() && moveHistory[moveHistory.length - 1].result === MoveResult.SUCCESS; + + // isBatonPassMove and allowBatonModifierSwitch shouldn't ever be true + // at the same time, because they both explicitly check for a mutually + // exclusive partyUiMode. But better safe than sorry. + this.options.push(isBatonPassMove && !allowBatonModifierSwitch ? PartyOption.PASS_BATON : PartyOption.SEND_OUT); + if (allowBatonModifierSwitch && !isBatonPassMove) { + // the BATON modifier gives an extra switch option for + // pokemon-command switches, allowing buffs to be optionally passed this.options.push(PartyOption.PASS_BATON); } } From a4c913d963a3c2e74237c7a53a4b3685844cc792 Mon Sep 17 00:00:00 2001 From: innerthunder <168692175+innerthunder@users.noreply.github.com> Date: Tue, 6 Aug 2024 23:31:54 -0700 Subject: [PATCH 009/257] [Move] Implement (or re-implement?) Lucky Chant (#3352) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Implement Lucky Chant * Add i18n keys for NoCritTag messages * Add Lucky Chant message translations (DE, FR, KO, PT-BR) 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 * Add ZH translations Co-authored-by: Sonny Ding <93831983+sonnyding1@users.noreply.github.com> * Add keys for JA locale --------- 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/arena-tag.ts | 35 +++++++++ src/data/battler-tags.ts | 2 - src/data/move.ts | 6 +- src/enums/arena-tag-type.ts | 3 +- src/enums/battler-tag-type.ts | 1 - src/field/pokemon.ts | 11 +-- src/locales/de/arena-tag.ts | 3 + src/locales/en/arena-tag.ts | 3 + src/locales/es/arena-tag.ts | 3 + src/locales/fr/arena-tag.ts | 3 + src/locales/it/arena-tag.ts | 3 + src/locales/ja/arena-tag.ts | 3 + src/locales/ko/arena-tag.ts | 3 + src/locales/pt_BR/arena-tag.ts | 3 + src/locales/zh_CN/arena-tag.ts | 3 + src/locales/zh_TW/arena-tag.ts | 3 + src/test/moves/dragon_rage.test.ts | 8 +- src/test/moves/lucky_chant.test.ts | 113 +++++++++++++++++++++++++++++ 18 files changed, 194 insertions(+), 15 deletions(-) create mode 100644 src/test/moves/lucky_chant.test.ts diff --git a/src/data/arena-tag.ts b/src/data/arena-tag.ts index fd72ab21026..9c846d2f3cb 100644 --- a/src/data/arena-tag.ts +++ b/src/data/arena-tag.ts @@ -303,6 +303,39 @@ class CraftyShieldTag extends ConditionalProtectTag { } } +/** + * Arena Tag class for {@link https://bulbapedia.bulbagarden.net/wiki/Lucky_Chant_(move) Lucky Chant}. + * Prevents critical hits against the tag's side. + */ +export class NoCritTag extends ArenaTag { + /** + * Constructor method for the NoCritTag class + * @param turnCount `integer` the number of turns this effect lasts + * @param sourceMove {@linkcode Moves} the move that created this effect + * @param sourceId `integer` the ID of the {@linkcode Pokemon} that created this effect + * @param side {@linkcode ArenaTagSide} the side to which this effect belongs + */ + constructor(turnCount: integer, sourceMove: Moves, sourceId: integer, side: ArenaTagSide) { + super(ArenaTagType.NO_CRIT, turnCount, sourceMove, sourceId, side); + } + + /** Queues a message upon adding this effect to the field */ + onAdd(arena: Arena): void { + arena.scene.queueMessage(i18next.t(`arenaTag:noCritOnAdd${this.side === ArenaTagSide.PLAYER ? "Player" : "Enemy"}`, { + moveName: this.getMoveName() + })); + } + + /** Queues a message upon removing this effect from the field */ + onRemove(arena: Arena): void { + const source = arena.scene.getPokemonById(this.sourceId); + arena.scene.queueMessage(i18next.t("arenaTag:noCritOnRemove", { + pokemonNameWithAffix: getPokemonNameWithAffix(source), + moveName: this.getMoveName() + })); + } +} + /** * Arena Tag class for {@link https://bulbapedia.bulbagarden.net/wiki/Wish_(move) Wish}. * Heals the Pokémon in the user's position the turn after Wish is used. @@ -803,6 +836,8 @@ export function getArenaTag(tagType: ArenaTagType, turnCount: integer, sourceMov return new MatBlockTag(sourceId, side); case ArenaTagType.CRAFTY_SHIELD: return new CraftyShieldTag(sourceId, side); + case ArenaTagType.NO_CRIT: + return new NoCritTag(turnCount, sourceMove, sourceId, side); case ArenaTagType.MUD_SPORT: return new MudSportTag(turnCount, sourceId); case ArenaTagType.WATER_SPORT: diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index d2f462d5a44..4fad0ddbd08 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -1774,8 +1774,6 @@ export function getBattlerTag(tagType: BattlerTagType, turnCount: number, source case BattlerTagType.ALWAYS_CRIT: case BattlerTagType.IGNORE_ACCURACY: return new BattlerTag(tagType, BattlerTagLapseType.TURN_END, 2, sourceMove); - case BattlerTagType.NO_CRIT: - return new BattlerTag(tagType, BattlerTagLapseType.AFTER_MOVE, turnCount, sourceMove); case BattlerTagType.ALWAYS_GET_HIT: case BattlerTagType.RECEIVE_DOUBLE_DAMAGE: return new BattlerTag(tagType, BattlerTagLapseType.PRE_MOVE, 1, sourceMove); diff --git a/src/data/move.ts b/src/data/move.ts index d93869dedb9..dbb29d4c9d1 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -4258,7 +4258,6 @@ export class AddBattlerTagAttr extends MoveEffectAttr { case BattlerTagType.INFATUATED: case BattlerTagType.NIGHTMARE: case BattlerTagType.DROWSY: - case BattlerTagType.NO_CRIT: return -5; case BattlerTagType.SEEDED: case BattlerTagType.SALT_CURED: @@ -7120,9 +7119,8 @@ export function initMoves() { new StatusMove(Moves.GASTRO_ACID, Type.POISON, 100, 10, -1, 0, 4) .attr(SuppressAbilitiesAttr), new StatusMove(Moves.LUCKY_CHANT, Type.NORMAL, -1, 30, -1, 0, 4) - .attr(AddBattlerTagAttr, BattlerTagType.NO_CRIT, false, false, 5) - .target(MoveTarget.USER_SIDE) - .unimplemented(), + .attr(AddArenaTagAttr, ArenaTagType.NO_CRIT, 5, true, true) + .target(MoveTarget.USER_SIDE), new StatusMove(Moves.ME_FIRST, Type.NORMAL, -1, 20, -1, 0, 4) .ignoresVirtual() .target(MoveTarget.NEAR_ENEMY) diff --git a/src/enums/arena-tag-type.ts b/src/enums/arena-tag-type.ts index 722096c42cd..1265b815bf4 100644 --- a/src/enums/arena-tag-type.ts +++ b/src/enums/arena-tag-type.ts @@ -21,5 +21,6 @@ export enum ArenaTagType { MAT_BLOCK = "MAT_BLOCK", CRAFTY_SHIELD = "CRAFTY_SHIELD", TAILWIND = "TAILWIND", - HAPPY_HOUR = "HAPPY_HOUR" + HAPPY_HOUR = "HAPPY_HOUR", + NO_CRIT = "NO_CRIT" } diff --git a/src/enums/battler-tag-type.ts b/src/enums/battler-tag-type.ts index 7ef73bef281..eeba56d6532 100644 --- a/src/enums/battler-tag-type.ts +++ b/src/enums/battler-tag-type.ts @@ -48,7 +48,6 @@ export enum BattlerTagType { FIRE_BOOST = "FIRE_BOOST", CRIT_BOOST = "CRIT_BOOST", ALWAYS_CRIT = "ALWAYS_CRIT", - NO_CRIT = "NO_CRIT", IGNORE_ACCURACY = "IGNORE_ACCURACY", BYPASS_SLEEP = "BYPASS_SLEEP", IGNORE_FLYING = "IGNORE_FLYING", diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 7fc5f14d0e1..ea7acc12588 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -22,7 +22,7 @@ import { BattleStat } from "../data/battle-stat"; import { BattlerTag, BattlerTagLapseType, EncoreTag, GroundedTag, HighestStatBoostTag, TypeImmuneTag, getBattlerTag, SemiInvulnerableTag, TypeBoostTag } from "../data/battler-tags"; import { WeatherType } from "../data/weather"; import { TempBattleStat } from "../data/temp-battle-stat"; -import { ArenaTagSide, WeakenMoveScreenTag } from "../data/arena-tag"; +import { ArenaTagSide, NoCritTag, WeakenMoveScreenTag } from "../data/arena-tag"; import { Ability, AbAttr, BattleStatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, IgnoreOpponentStatChangesAbAttr, MoveImmunityAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr, IgnoreTypeImmunityAbAttr, DamageBoostAbAttr, IgnoreTypeStatusEffectImmunityAbAttr, ConditionalCritAbAttr, applyFieldBattleStatMultiplierAbAttrs, FieldMultiplyBattleStatAbAttr, AddSecondStrikeAbAttr, IgnoreOpponentEvasionAbAttr, UserFieldStatusEffectImmunityAbAttr, UserFieldBattlerTagImmunityAbAttr, BattlerTagImmunityAbAttr } from "../data/ability"; import PokemonData from "../system/pokemon-data"; import { BattlerIndex } from "../battle"; @@ -1885,6 +1885,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { apply(source: Pokemon, move: Move): HitResult { let result: HitResult; const damage = new Utils.NumberHolder(0); + const defendingSide = this.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY; const defendingSidePlayField = this.isPlayer() ? this.scene.getPlayerField() : this.scene.getEnemyField(); const variableCategory = new Utils.IntegerHolder(move.category); @@ -1911,7 +1912,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { // Apply arena tags for conditional protection if (!move.checkFlag(MoveFlags.IGNORE_PROTECT, source, this) && !move.isAllyTarget()) { - const defendingSide = this.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY; this.scene.arena.applyTagsForSide(ArenaTagType.QUICK_GUARD, defendingSide, cancelled, this, move.priority); this.scene.arena.applyTagsForSide(ArenaTagType.WIDE_GUARD, defendingSide, cancelled, this, move.moveTarget); this.scene.arena.applyTagsForSide(ArenaTagType.MAT_BLOCK, defendingSide, cancelled, this, move.category); @@ -1978,15 +1978,16 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } console.log(`crit stage: +${critLevel.value}`); const critChance = [24, 8, 2, 1][Math.max(0, Math.min(critLevel.value, 3))]; - isCritical = !source.getTag(BattlerTagType.NO_CRIT) && (critChance === 1 || !this.scene.randBattleSeedInt(critChance)); + isCritical = critChance === 1 || !this.scene.randBattleSeedInt(critChance); if (Overrides.NEVER_CRIT_OVERRIDE) { isCritical = false; } } if (isCritical) { + const noCritTag = this.scene.arena.getTagOnSide(NoCritTag, defendingSide); const blockCrit = new Utils.BooleanHolder(false); applyAbAttrs(BlockCritAbAttr, this, null, blockCrit); - if (blockCrit.value) { + if (noCritTag || blockCrit.value) { isCritical = false; } } @@ -1996,7 +1997,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { applyAbAttrs(MultCritAbAttr, source, null, criticalMultiplier); const screenMultiplier = new Utils.NumberHolder(1); if (!isCritical) { - this.scene.arena.applyTagsForSide(WeakenMoveScreenTag, this.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY, move.category, this.scene.currentBattle.double, screenMultiplier); + this.scene.arena.applyTagsForSide(WeakenMoveScreenTag, defendingSide, move.category, this.scene.currentBattle.double, screenMultiplier); } const isTypeImmune = (typeMultiplier.value * arenaAttackTypeMultiplier.value) === 0; const sourceTypes = source.getTypes(); diff --git a/src/locales/de/arena-tag.ts b/src/locales/de/arena-tag.ts index cc0a821aade..65699742331 100644 --- a/src/locales/de/arena-tag.ts +++ b/src/locales/de/arena-tag.ts @@ -22,6 +22,9 @@ export const arenaTag: SimpleTranslationEntries = { "conditionalProtectOnAddEnemy": "Die Pokémon auf der gegnerischen Seite werden von {{moveName}} behütet!", "conditionalProtectApply": "{{pokemonNameWithAffix}} wird durch {{moveName}} geschützt!", "matBlockOnAdd": "{{pokemonNameWithAffix}} bringt seinen Tatami-Schild in Position!", + "noCritOnAddPlayer": "{{moveName}} schützt dein Team vor Volltreffern!", + "noCritOnAddEnemy": "{{moveName}} schützt das gegnerische Team vor Volltreffern!", + "noCritOnRemove": "{{moveName}} von {{pokemonNameWithAffix}} hört auf zu wirken!", "wishTagOnAdd": "Der Wunschtraum von {{pokemonNameWithAffix}} erfüllt sich!", "mudSportOnAdd": "Die Stärke aller Elektro-Attacken wurde reduziert!", "mudSportOnRemove": "Lehmsuhler hört auf zu wirken!", diff --git a/src/locales/en/arena-tag.ts b/src/locales/en/arena-tag.ts index 8bc2302368a..22612795308 100644 --- a/src/locales/en/arena-tag.ts +++ b/src/locales/en/arena-tag.ts @@ -22,6 +22,9 @@ export const arenaTag: SimpleTranslationEntries = { "conditionalProtectOnAddEnemy": "{{moveName}} protected the\nopposing team!", "conditionalProtectApply": "{{moveName}} protected {{pokemonNameWithAffix}}!", "matBlockOnAdd": "{{pokemonNameWithAffix}} intends to flip up a mat\nand block incoming attacks!", + "noCritOnAddPlayer": "The {{moveName}} shielded your\nteam from critical hits!", + "noCritOnAddEnemy": "The {{moveName}} shielded the opposing\nteam from critical hits!", + "noCritOnRemove": "{{pokemonNameWithAffix}}'s {{moveName}}\nwore off!", "wishTagOnAdd": "{{pokemonNameWithAffix}}'s wish\ncame true!", "mudSportOnAdd": "Electricity's power was weakened!", "mudSportOnRemove": "The effects of Mud Sport\nhave faded.", diff --git a/src/locales/es/arena-tag.ts b/src/locales/es/arena-tag.ts index 8bc2302368a..22612795308 100644 --- a/src/locales/es/arena-tag.ts +++ b/src/locales/es/arena-tag.ts @@ -22,6 +22,9 @@ export const arenaTag: SimpleTranslationEntries = { "conditionalProtectOnAddEnemy": "{{moveName}} protected the\nopposing team!", "conditionalProtectApply": "{{moveName}} protected {{pokemonNameWithAffix}}!", "matBlockOnAdd": "{{pokemonNameWithAffix}} intends to flip up a mat\nand block incoming attacks!", + "noCritOnAddPlayer": "The {{moveName}} shielded your\nteam from critical hits!", + "noCritOnAddEnemy": "The {{moveName}} shielded the opposing\nteam from critical hits!", + "noCritOnRemove": "{{pokemonNameWithAffix}}'s {{moveName}}\nwore off!", "wishTagOnAdd": "{{pokemonNameWithAffix}}'s wish\ncame true!", "mudSportOnAdd": "Electricity's power was weakened!", "mudSportOnRemove": "The effects of Mud Sport\nhave faded.", diff --git a/src/locales/fr/arena-tag.ts b/src/locales/fr/arena-tag.ts index cc97cb4e34f..62ef203cf68 100644 --- a/src/locales/fr/arena-tag.ts +++ b/src/locales/fr/arena-tag.ts @@ -22,6 +22,9 @@ export const arenaTag: SimpleTranslationEntries = { "conditionalProtectOnAddEnemy": "La capacité {{moveName}}\nprotège l’équipe ennemie !", "conditionalProtectApply": "{{pokemonNameWithAffix}} est protégé\npar {{moveName}} !", "matBlockOnAdd": "{{pokemonNameWithAffix}} se prépare\nà utiliser un tatami pour bloquer les attaques !", + "noCritOnAddPlayer": "{{moveName}} immunise votre équipe\ncontre les coups critiques !", + "noCritOnAddEnemy": "{{moveName}} immunise l’équipe ennemie\ncontre les coups critiques !", + "noCritOnRemove": "Les effets d’{{moveName}}\nsur {{pokemonNameWithAffix}} prennent fin !", "wishTagOnAdd": "Le vœu de{{pokemonNameWithAffix}}\nse réalise !", "mudSportOnAdd": "La puissance des capacités\nde type Électrik diminue !", "mudSportOnRemove": "L’effet de Lance-Boue se dissipe !", diff --git a/src/locales/it/arena-tag.ts b/src/locales/it/arena-tag.ts index 8bc2302368a..22612795308 100644 --- a/src/locales/it/arena-tag.ts +++ b/src/locales/it/arena-tag.ts @@ -22,6 +22,9 @@ export const arenaTag: SimpleTranslationEntries = { "conditionalProtectOnAddEnemy": "{{moveName}} protected the\nopposing team!", "conditionalProtectApply": "{{moveName}} protected {{pokemonNameWithAffix}}!", "matBlockOnAdd": "{{pokemonNameWithAffix}} intends to flip up a mat\nand block incoming attacks!", + "noCritOnAddPlayer": "The {{moveName}} shielded your\nteam from critical hits!", + "noCritOnAddEnemy": "The {{moveName}} shielded the opposing\nteam from critical hits!", + "noCritOnRemove": "{{pokemonNameWithAffix}}'s {{moveName}}\nwore off!", "wishTagOnAdd": "{{pokemonNameWithAffix}}'s wish\ncame true!", "mudSportOnAdd": "Electricity's power was weakened!", "mudSportOnRemove": "The effects of Mud Sport\nhave faded.", diff --git a/src/locales/ja/arena-tag.ts b/src/locales/ja/arena-tag.ts index 8bc2302368a..22612795308 100644 --- a/src/locales/ja/arena-tag.ts +++ b/src/locales/ja/arena-tag.ts @@ -22,6 +22,9 @@ export const arenaTag: SimpleTranslationEntries = { "conditionalProtectOnAddEnemy": "{{moveName}} protected the\nopposing team!", "conditionalProtectApply": "{{moveName}} protected {{pokemonNameWithAffix}}!", "matBlockOnAdd": "{{pokemonNameWithAffix}} intends to flip up a mat\nand block incoming attacks!", + "noCritOnAddPlayer": "The {{moveName}} shielded your\nteam from critical hits!", + "noCritOnAddEnemy": "The {{moveName}} shielded the opposing\nteam from critical hits!", + "noCritOnRemove": "{{pokemonNameWithAffix}}'s {{moveName}}\nwore off!", "wishTagOnAdd": "{{pokemonNameWithAffix}}'s wish\ncame true!", "mudSportOnAdd": "Electricity's power was weakened!", "mudSportOnRemove": "The effects of Mud Sport\nhave faded.", diff --git a/src/locales/ko/arena-tag.ts b/src/locales/ko/arena-tag.ts index ca1039e2bc0..2211ced6c4c 100644 --- a/src/locales/ko/arena-tag.ts +++ b/src/locales/ko/arena-tag.ts @@ -22,6 +22,9 @@ export const arenaTag: SimpleTranslationEntries = { "conditionalProtectOnAddEnemy": "상대 주변을\n{{moveName}}[[가]] 보호하고 있다!", "conditionalProtectApply": "{{pokemonNameWithAffix}}[[를]]\n{{moveName}}[[가]] 지켜주고 있다!", "matBlockOnAdd": "{{pokemonNameWithAffix}}[[는]]\n마룻바닥세워막기를 노리고 있다!", + "noCritOnAddPlayer": "{{moveName}}의 힘으로\n우리 편의 급소가 숨겨졌다!", + "noCritOnAddEnemy": "{{moveName}}의 힘으로\n상대의 급소가 숨겨졌다!", + "noCritOnRemove": "{{pokemonNameWithAffix}}의 {{moveName}}[[가]] 풀렸다!", "wishTagOnAdd": "{{pokemonNameWithAffix}}의\n희망사항이 이루어졌다!", "mudSportOnAdd": "전기의 위력이 약해졌다!", "mudSportOnRemove": "흙놀이의 효과가\n없어졌다!", diff --git a/src/locales/pt_BR/arena-tag.ts b/src/locales/pt_BR/arena-tag.ts index 0d3b8ff587f..ebdf886f9a6 100644 --- a/src/locales/pt_BR/arena-tag.ts +++ b/src/locales/pt_BR/arena-tag.ts @@ -22,6 +22,9 @@ export const arenaTag: SimpleTranslationEntries = { "conditionalProtectOnAddEnemy": "{{moveName}} protegeu a\nequipe adversária!", "conditionalProtectApply": "{{moveName}} protegeu {{pokemonNameWithAffix}}!", "matBlockOnAdd": "{{pokemonNameWithAffix}} pretende levantar um tapete\npara bloquear ataques!", + "noCritOnAddPlayer": "{{moveName}} protegeu sua\equipe de acertos críticos!", + "noCritOnAddEnemy": "{{moveName}} protegeu a\equipe adversária de acertos críticos", + "noCritOnRemove": "{{moveName}} de {{pokemonNameWithAffix}}\nacabou!", "wishTagOnAdd": "O desejo de {{pokemonNameWithAffix}}\nfoi concedido!", "mudSportOnAdd": "O poder de movimentos elétricos foi enfraquecido!", "mudSportOnRemove": "Os efeitos de Mud Sport\nsumiram.", diff --git a/src/locales/zh_CN/arena-tag.ts b/src/locales/zh_CN/arena-tag.ts index 027a5667415..974ef36d7af 100644 --- a/src/locales/zh_CN/arena-tag.ts +++ b/src/locales/zh_CN/arena-tag.ts @@ -22,6 +22,9 @@ export const arenaTag: SimpleTranslationEntries = { "conditionalProtectOnAddEnemy": "{{moveName}}\n保护了敌方!", "conditionalProtectApply": "{{moveName}}\n保护了{{pokemonNameWithAffix}}!", "matBlockOnAdd": "{{pokemonNameWithAffix}}正在\n伺机使出掀榻榻米!", + "noCritOnAddPlayer": "{{moveName}}保护了你的\n队伍不被击中要害!", + "noCritOnAddEnemy": "{{moveName}}保护了对方的\n队伍不被击中要害!", + "noCritOnRemove": "{{pokemonNameWithAffix}}的{{moveName}}\n效果消失了!", "wishTagOnAdd": "{{pokemonNameWithAffix}}的\n祈愿实现了!", "mudSportOnAdd": "电气的威力减弱了!", "mudSportOnRemove": "玩泥巴的效果消失了!", diff --git a/src/locales/zh_TW/arena-tag.ts b/src/locales/zh_TW/arena-tag.ts index 8bc2302368a..ee7d2eb7bc5 100644 --- a/src/locales/zh_TW/arena-tag.ts +++ b/src/locales/zh_TW/arena-tag.ts @@ -22,6 +22,9 @@ export const arenaTag: SimpleTranslationEntries = { "conditionalProtectOnAddEnemy": "{{moveName}} protected the\nopposing team!", "conditionalProtectApply": "{{moveName}} protected {{pokemonNameWithAffix}}!", "matBlockOnAdd": "{{pokemonNameWithAffix}} intends to flip up a mat\nand block incoming attacks!", + "noCritOnAddPlayer": "{{moveName}}保護了你的\n隊伍不被擊中要害!", + "noCritOnAddEnemy": "{{moveName}}保護了對方的\n隊伍不被擊中要害!", + "noCritOnRemove": "{{pokemonNameWithAffix}}的{{moveName}}\n效果消失了!", "wishTagOnAdd": "{{pokemonNameWithAffix}}'s wish\ncame true!", "mudSportOnAdd": "Electricity's power was weakened!", "mudSportOnRemove": "The effects of Mud Sport\nhave faded.", diff --git a/src/test/moves/dragon_rage.test.ts b/src/test/moves/dragon_rage.test.ts index 2facff3428f..3c6e2b83baa 100644 --- a/src/test/moves/dragon_rage.test.ts +++ b/src/test/moves/dragon_rage.test.ts @@ -35,7 +35,6 @@ describe("Moves - Dragon Rage", () => { game = new GameManager(phaserGame); game.override.battleType("single"); - game.override.disableCrits(); game.override.starterSpecies(Species.SNORLAX); game.override.moveset([Moves.DRAGON_RAGE]); @@ -60,6 +59,7 @@ describe("Moves - Dragon Rage", () => { }); it("ignores weaknesses", async () => { + game.override.disableCrits(); vi.spyOn(enemyPokemon, "getTypes").mockReturnValue([Type.DRAGON]); game.doAttack(getMovePosition(game.scene, 0, Moves.DRAGON_RAGE)); @@ -70,6 +70,7 @@ describe("Moves - Dragon Rage", () => { }); it("ignores resistances", async () => { + game.override.disableCrits(); vi.spyOn(enemyPokemon, "getTypes").mockReturnValue([Type.STEEL]); game.doAttack(getMovePosition(game.scene, 0, Moves.DRAGON_RAGE)); @@ -80,6 +81,7 @@ describe("Moves - Dragon Rage", () => { }); it("ignores stat changes", async () => { + game.override.disableCrits(); partyPokemon.summonData.battleStats[BattleStat.SPATK] = 2; game.doAttack(getMovePosition(game.scene, 0, Moves.DRAGON_RAGE)); @@ -90,6 +92,7 @@ describe("Moves - Dragon Rage", () => { }); it("ignores stab", async () => { + game.override.disableCrits(); vi.spyOn(partyPokemon, "getTypes").mockReturnValue([Type.DRAGON]); game.doAttack(getMovePosition(game.scene, 0, Moves.DRAGON_RAGE)); @@ -100,7 +103,6 @@ describe("Moves - Dragon Rage", () => { }); it("ignores criticals", async () => { - partyPokemon.removeTag(BattlerTagType.NO_CRIT); partyPokemon.addTag(BattlerTagType.ALWAYS_CRIT, 99); game.doAttack(getMovePosition(game.scene, 0, Moves.DRAGON_RAGE)); @@ -111,6 +113,7 @@ describe("Moves - Dragon Rage", () => { }); it("ignores damage modification from abilities such as ice scales", async () => { + game.override.disableCrits(); game.override.enemyAbility(Abilities.ICE_SCALES); game.doAttack(getMovePosition(game.scene, 0, Moves.DRAGON_RAGE)); @@ -121,6 +124,7 @@ describe("Moves - Dragon Rage", () => { }); it("ignores multi hit", async () => { + game.override.disableCrits(); game.scene.addModifier(modifierTypes.MULTI_LENS().newModifier(partyPokemon), false); game.doAttack(getMovePosition(game.scene, 0, Moves.DRAGON_RAGE)); diff --git a/src/test/moves/lucky_chant.test.ts b/src/test/moves/lucky_chant.test.ts new file mode 100644 index 00000000000..1a29edb8052 --- /dev/null +++ b/src/test/moves/lucky_chant.test.ts @@ -0,0 +1,113 @@ +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import GameManager from "../utils/gameManager"; +import { getMovePosition } from "../utils/gameManagerUtils"; +import { Moves } from "#app/enums/moves.js"; +import { Species } from "#app/enums/species.js"; +import { Abilities } from "#app/enums/abilities.js"; +import { BerryPhase, TurnEndPhase } from "#app/phases.js"; +import { BattlerTagType } from "#app/enums/battler-tag-type.js"; + +const TIMEOUT = 20 * 1000; + +describe("Moves - Lucky Chant", () => { + 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.LUCKY_CHANT, Moves.SPLASH, Moves.FOLLOW_ME]) + .enemySpecies(Species.SNORLAX) + .enemyAbility(Abilities.INSOMNIA) + .enemyMoveset(Array(4).fill(Moves.FLOWER_TRICK)) + .startingLevel(100) + .enemyLevel(100); + }); + + it( + "should prevent critical hits from moves", + async () => { + await game.startBattle([Species.CHARIZARD]); + + const playerPokemon = game.scene.getPlayerPokemon(); + + game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + + await game.phaseInterceptor.to(TurnEndPhase); + + const firstTurnDamage = playerPokemon.getMaxHp() - playerPokemon.hp; + + game.doAttack(getMovePosition(game.scene, 0, Moves.LUCKY_CHANT)); + + await game.phaseInterceptor.to(BerryPhase, false); + + const secondTurnDamage = playerPokemon.getMaxHp() - playerPokemon.hp - firstTurnDamage; + expect(secondTurnDamage).toBeLessThan(firstTurnDamage); + }, TIMEOUT + ); + + it( + "should prevent critical hits against the user's ally", + async () => { + game.override.battleType("double"); + + await game.startBattle([Species.CHARIZARD, Species.BLASTOISE]); + + const playerPokemon = game.scene.getPlayerField(); + + game.doAttack(getMovePosition(game.scene, 0, Moves.FOLLOW_ME)); + game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + + await game.phaseInterceptor.to(TurnEndPhase); + + const firstTurnDamage = playerPokemon[0].getMaxHp() - playerPokemon[0].hp; + + game.doAttack(getMovePosition(game.scene, 0, Moves.FOLLOW_ME)); + game.doAttack(getMovePosition(game.scene, 1, Moves.LUCKY_CHANT)); + + await game.phaseInterceptor.to(BerryPhase, false); + + const secondTurnDamage = playerPokemon[0].getMaxHp() - playerPokemon[0].hp - firstTurnDamage; + expect(secondTurnDamage).toBeLessThan(firstTurnDamage); + }, TIMEOUT + ); + + it( + "should prevent critical hits from field effects", + async () => { + game.override.enemyMoveset(Array(4).fill(Moves.TACKLE)); + + await game.startBattle([Species.CHARIZARD]); + + const playerPokemon = game.scene.getPlayerPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon(); + + enemyPokemon.addTag(BattlerTagType.ALWAYS_CRIT, 2, Moves.NONE, 0); + + game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + + await game.phaseInterceptor.to(TurnEndPhase); + + const firstTurnDamage = playerPokemon.getMaxHp() - playerPokemon.hp; + + game.doAttack(getMovePosition(game.scene, 0, Moves.LUCKY_CHANT)); + + await game.phaseInterceptor.to(BerryPhase, false); + + const secondTurnDamage = playerPokemon.getMaxHp() - playerPokemon.hp - firstTurnDamage; + expect(secondTurnDamage).toBeLessThan(firstTurnDamage); + }, TIMEOUT + ); +}); From df9596a9dc5eda137a8901d0f1b0bf817185a983 Mon Sep 17 00:00:00 2001 From: Jannik Tappert <38758606+CodeTappert@users.noreply.github.com> Date: Wed, 7 Aug 2024 10:45:29 +0200 Subject: [PATCH 010/257] Added catalan as a language (#3400) --- src/locales/ca-ES/ability-trigger.ts | 63 + src/locales/ca-ES/ability.ts | 1244 ++++++ src/locales/ca-ES/achv.ts | 274 ++ src/locales/ca-ES/arena-flyout.ts | 49 + src/locales/ca-ES/arena-tag.ts | 53 + src/locales/ca-ES/battle-info.ts | 5 + .../ca-ES/battle-message-ui-handler.ts | 10 + src/locales/ca-ES/battle.ts | 159 + src/locales/ca-ES/battler-tags.ts | 12 + src/locales/ca-ES/berry.ts | 48 + src/locales/ca-ES/bgm-name.ts | 146 + src/locales/ca-ES/biome.ts | 40 + src/locales/ca-ES/challenges.ts | 32 + src/locales/ca-ES/command-ui-handler.ts | 9 + src/locales/ca-ES/common.ts | 10 + src/locales/ca-ES/config.ts | 116 + src/locales/ca-ES/dialogue.ts | 2746 ++++++++++++ src/locales/ca-ES/egg.ts | 28 + src/locales/ca-ES/fight-ui-handler.ts | 9 + src/locales/ca-ES/filter-bar.ts | 33 + src/locales/ca-ES/game-mode.ts | 10 + src/locales/ca-ES/game-stats-ui-handler.ts | 44 + src/locales/ca-ES/growth.ts | 10 + src/locales/ca-ES/menu-ui-handler.ts | 28 + src/locales/ca-ES/menu.ts | 62 + .../ca-ES/modifier-select-ui-handler.ts | 14 + src/locales/ca-ES/modifier-type.ts | 456 ++ src/locales/ca-ES/modifier.ts | 14 + src/locales/ca-ES/move-trigger.ts | 62 + src/locales/ca-ES/move.ts | 3812 +++++++++++++++++ src/locales/ca-ES/nature.ts | 29 + src/locales/ca-ES/party-ui-handler.ts | 54 + src/locales/ca-ES/pokeball.ts | 10 + src/locales/ca-ES/pokemon-form.ts | 197 + src/locales/ca-ES/pokemon-info-container.ts | 9 + src/locales/ca-ES/pokemon-info.ts | 43 + src/locales/ca-ES/pokemon-summary.ts | 20 + src/locales/ca-ES/pokemon.ts | 1086 +++++ .../ca-ES/save-slot-select-ui-handler.ts | 9 + src/locales/ca-ES/settings.ts | 100 + src/locales/ca-ES/splash-messages.ts | 38 + .../ca-ES/starter-select-ui-handler.ts | 49 + src/locales/ca-ES/status-effect.ts | 67 + src/locales/ca-ES/trainers.ts | 302 ++ src/locales/ca-ES/tutorial.ts | 44 + src/locales/ca-ES/voucher.ts | 11 + src/locales/ca-ES/weather.ts | 66 + src/plugins/i18n.ts | 10 +- src/system/settings/settings.ts | 4 + .../settings/settings-display-ui-handler.ts | 6 + src/ui/starter-select-ui-handler.ts | 6 +- 51 files changed, 11754 insertions(+), 4 deletions(-) create mode 100644 src/locales/ca-ES/ability-trigger.ts create mode 100644 src/locales/ca-ES/ability.ts create mode 100644 src/locales/ca-ES/achv.ts create mode 100644 src/locales/ca-ES/arena-flyout.ts create mode 100644 src/locales/ca-ES/arena-tag.ts create mode 100644 src/locales/ca-ES/battle-info.ts create mode 100644 src/locales/ca-ES/battle-message-ui-handler.ts create mode 100644 src/locales/ca-ES/battle.ts create mode 100644 src/locales/ca-ES/battler-tags.ts create mode 100644 src/locales/ca-ES/berry.ts create mode 100644 src/locales/ca-ES/bgm-name.ts create mode 100644 src/locales/ca-ES/biome.ts create mode 100644 src/locales/ca-ES/challenges.ts create mode 100644 src/locales/ca-ES/command-ui-handler.ts create mode 100644 src/locales/ca-ES/common.ts create mode 100644 src/locales/ca-ES/config.ts create mode 100644 src/locales/ca-ES/dialogue.ts create mode 100644 src/locales/ca-ES/egg.ts create mode 100644 src/locales/ca-ES/fight-ui-handler.ts create mode 100644 src/locales/ca-ES/filter-bar.ts create mode 100644 src/locales/ca-ES/game-mode.ts create mode 100644 src/locales/ca-ES/game-stats-ui-handler.ts create mode 100644 src/locales/ca-ES/growth.ts create mode 100644 src/locales/ca-ES/menu-ui-handler.ts create mode 100644 src/locales/ca-ES/menu.ts create mode 100644 src/locales/ca-ES/modifier-select-ui-handler.ts create mode 100644 src/locales/ca-ES/modifier-type.ts create mode 100644 src/locales/ca-ES/modifier.ts create mode 100644 src/locales/ca-ES/move-trigger.ts create mode 100644 src/locales/ca-ES/move.ts create mode 100644 src/locales/ca-ES/nature.ts create mode 100644 src/locales/ca-ES/party-ui-handler.ts create mode 100644 src/locales/ca-ES/pokeball.ts create mode 100644 src/locales/ca-ES/pokemon-form.ts create mode 100644 src/locales/ca-ES/pokemon-info-container.ts create mode 100644 src/locales/ca-ES/pokemon-info.ts create mode 100644 src/locales/ca-ES/pokemon-summary.ts create mode 100644 src/locales/ca-ES/pokemon.ts create mode 100644 src/locales/ca-ES/save-slot-select-ui-handler.ts create mode 100644 src/locales/ca-ES/settings.ts create mode 100644 src/locales/ca-ES/splash-messages.ts create mode 100644 src/locales/ca-ES/starter-select-ui-handler.ts create mode 100644 src/locales/ca-ES/status-effect.ts create mode 100644 src/locales/ca-ES/trainers.ts create mode 100644 src/locales/ca-ES/tutorial.ts create mode 100644 src/locales/ca-ES/voucher.ts create mode 100644 src/locales/ca-ES/weather.ts diff --git a/src/locales/ca-ES/ability-trigger.ts b/src/locales/ca-ES/ability-trigger.ts new file mode 100644 index 00000000000..ce41a964922 --- /dev/null +++ b/src/locales/ca-ES/ability-trigger.ts @@ -0,0 +1,63 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +export const abilityTriggers: SimpleTranslationEntries = { + "blockRecoilDamage": "{{pokemonName}}'s {{abilityName}}\nprotected it from recoil!", + "badDreams": "{{pokemonName}} is tormented!", + "costar": "{{pokemonName}} copied {{allyName}}'s stat changes!", + "iceFaceAvoidedDamage": "{{pokemonName}} avoided\ndamage with {{abilityName}}!", + "perishBody": "{{pokemonName}}'s {{abilityName}}\nwill faint both pokemon in 3 turns!", + "poisonHeal": "{{pokemonName}}'s {{abilityName}}\nrestored its HP a little!", + "trace": "{{pokemonName}} copied {{targetName}}'s\n{{abilityName}}!", + "windPowerCharged": "Being hit by {{moveName}} charged {{pokemonName}} with power!", + "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!", + "preventBerryUse": "{{pokemonNameWithAffix}} is too\nnervous to eat berries!", +} as const; diff --git a/src/locales/ca-ES/ability.ts b/src/locales/ca-ES/ability.ts new file mode 100644 index 00000000000..7e81f90afff --- /dev/null +++ b/src/locales/ca-ES/ability.ts @@ -0,0 +1,1244 @@ +import { AbilityTranslationEntries } from "#app/interfaces/locales.js"; + +export const ability: AbilityTranslationEntries = { + stench: { + name: "Stench", + description: "By releasing stench when attacking, this Pokémon may cause the target to flinch.", + }, + drizzle: { + name: "Drizzle", + description: "The Pokémon makes it rain when it enters a battle.", + }, + speedBoost: { + name: "Speed Boost", + description: "Its Speed stat is boosted every turn.", + }, + battleArmor: { + name: "Battle Armor", + description: "Hard armor protects the Pokémon from critical hits.", + }, + sturdy: { + name: "Sturdy", + description: "It cannot be knocked out with one hit. One-hit KO moves cannot knock it out, either.", + }, + damp: { + name: "Damp", + description: "Prevents the use of explosive moves, such as Self-Destruct, by dampening its surroundings.", + }, + limber: { + name: "Limber", + description: "Its limber body protects the Pokémon from paralysis.", + }, + sandVeil: { + name: "Sand Veil", + description: "Boosts the Pokémon's evasiveness in a sandstorm.", + }, + static: { + name: "Static", + description: "The Pokémon is charged with static electricity, so contact with it may cause paralysis.", + }, + voltAbsorb: { + name: "Volt Absorb", + description: "Restores HP if hit by an Electric-type move instead of taking damage.", + }, + waterAbsorb: { + name: "Water Absorb", + description: "Restores HP if hit by a Water-type move instead of taking damage.", + }, + oblivious: { + name: "Oblivious", + description: "The Pokémon is oblivious, and that keeps it from being infatuated or falling for taunts.", + }, + cloudNine: { + name: "Cloud Nine", + description: "Eliminates the effects of weather.", + }, + compoundEyes: { + name: "Compound Eyes", + description: "The Pokémon's compound eyes boost its accuracy.", + }, + insomnia: { + name: "Insomnia", + description: "The Pokémon is suffering from insomnia and cannot fall asleep.", + }, + colorChange: { + name: "Color Change", + description: "The Pokémon's type becomes the type of the move used on it.", + }, + immunity: { + name: "Immunity", + description: "The immune system of the Pokémon prevents it from getting poisoned.", + }, + flashFire: { + name: "Flash Fire", + description: "Powers up the Pokémon's Fire-type moves if it's hit by one.", + }, + shieldDust: { + name: "Shield Dust", + description: "This Pokémon's dust blocks the additional effects of attacks taken.", + }, + ownTempo: { + name: "Own Tempo", + description: "This Pokémon has its own tempo, and that prevents it from becoming confused.", + }, + suctionCups: { + name: "Suction Cups", + description: "This Pokémon uses suction cups to stay in one spot to negate all moves and items that force switching out.", + }, + intimidate: { + name: "Intimidate", + description: "The Pokémon intimidates opposing Pokémon upon entering battle, lowering their Attack stat.", + }, + shadowTag: { + name: "Shadow Tag", + description: "This Pokémon steps on the opposing Pokémon's shadow to prevent it from escaping.", + }, + roughSkin: { + name: "Rough Skin", + description: "This Pokémon inflicts damage with its rough skin to the attacker on contact.", + }, + wonderGuard: { + name: "Wonder Guard", + description: "Its mysterious power only lets supereffective moves hit the Pokémon.", + }, + levitate: { + name: "Levitate", + description: "By floating in the air, the Pokémon receives full immunity to all Ground-type moves.", + }, + effectSpore: { + name: "Effect Spore", + description: "Contact with the Pokémon may inflict poison, sleep, or paralysis on its attacker.", + }, + synchronize: { + name: "Synchronize", + description: "The attacker will receive the same status condition if it inflicts a burn, poison, or paralysis to the Pokémon.", + }, + clearBody: { + name: "Clear Body", + description: "Prevents other Pokémon's moves or Abilities from lowering the Pokémon's stats.", + }, + naturalCure: { + name: "Natural Cure", + description: "All status conditions heal when the Pokémon switches out.", + }, + lightningRod: { + name: "Lightning Rod", + description: "The Pokémon draws in all Electric-type moves. Instead of being hit by Electric-type moves, it boosts its Sp. Atk.", + }, + sereneGrace: { + name: "Serene Grace", + description: "Boosts the likelihood of additional effects occurring when attacking.", + }, + swiftSwim: { + name: "Swift Swim", + description: "Boosts the Pokémon's Speed stat in rain.", + }, + chlorophyll: { + name: "Chlorophyll", + description: "Boosts the Pokémon's Speed stat in harsh sunlight.", + }, + illuminate: { + name: "Illuminate", + description: "By illuminating its surroundings, the Pokémon raises the likelihood of meeting wild Pokémon and prevents its accuracy from being lowered.", + }, + trace: { + name: "Trace", + description: "When it enters a battle, the Pokémon copies an opposing Pokémon's Ability.", + }, + hugePower: { + name: "Huge Power", + description: "Doubles the Pokémon's Attack stat.", + }, + poisonPoint: { + name: "Poison Point", + description: "Contact with the Pokémon may poison the attacker.", + }, + innerFocus: { + name: "Inner Focus", + description: "The Pokémon's intensely focused, and that protects the Pokémon from flinching.", + }, + magmaArmor: { + name: "Magma Armor", + description: "The Pokémon is covered with hot magma, which prevents the Pokémon from becoming frozen.", + }, + waterVeil: { + name: "Water Veil", + description: "The Pokémon is covered with a water veil, which prevents the Pokémon from getting a burn.", + }, + magnetPull: { + name: "Magnet Pull", + description: "Prevents Steel-type Pokémon from escaping using its magnetic force.", + }, + soundproof: { + name: "Soundproof", + description: "Soundproofing gives the Pokémon full immunity to all sound-based moves.", + }, + rainDish: { + name: "Rain Dish", + description: "The Pokémon gradually regains HP in rain.", + }, + sandStream: { + name: "Sand Stream", + description: "The Pokémon summons a sandstorm when it enters a battle.", + }, + pressure: { + name: "Pressure", + description: "By putting pressure on the opposing Pokémon, it raises their PP usage.", + }, + thickFat: { + name: "Thick Fat", + description: "The Pokémon is protected by a layer of thick fat, which halves the damage taken from Fire- and Ice-type moves.", + }, + earlyBird: { + name: "Early Bird", + description: "The Pokémon awakens from sleep twice as fast as other Pokémon.", + }, + flameBody: { + name: "Flame Body", + description: "Contact with the Pokémon may burn the attacker.", + }, + runAway: { + name: "Run Away", + description: "Enables a sure getaway from wild Pokémon.", + }, + keenEye: { + name: "Keen Eye", + description: "Keen eyes prevent other Pokémon from lowering this Pokémon's accuracy.", + }, + hyperCutter: { + name: "Hyper Cutter", + description: "The Pokémon's proud of its powerful pincers. They prevent other Pokémon from lowering its Attack stat.", + }, + pickup: { + name: "Pickup", + description: "The Pokémon may pick up the item an opposing Pokémon held during a battle.", + }, + truant: { + name: "Truant", + description: "The Pokémon can't use a move if it had used a move on the previous turn.", + }, + hustle: { + name: "Hustle", + description: "Boosts the Attack stat, but lowers accuracy.", + }, + cuteCharm: { + name: "Cute Charm", + description: "Contact with the Pokémon may cause infatuation.", + }, + plus: { + name: "Plus", + description: "Boosts the Sp. Atk stat of the Pokémon if an ally with the Plus or Minus Ability is also in battle.", + }, + minus: { + name: "Minus", + description: "Boosts the Sp. Atk stat of the Pokémon if an ally with the Plus or Minus Ability is also in battle.", + }, + forecast: { + name: "Forecast", + description: "The Pokémon transforms with the weather to change its type to Water, Fire, or Ice.", + }, + stickyHold: { + name: "Sticky Hold", + description: "Items held by the Pokémon are stuck fast and cannot be removed by other Pokémon.", + }, + shedSkin: { + name: "Shed Skin", + description: "The Pokémon may heal its own status conditions by shedding its skin.", + }, + guts: { + name: "Guts", + description: "It's so gutsy that having a status condition boosts the Pokémon's Attack stat.", + }, + marvelScale: { + name: "Marvel Scale", + description: "The Pokémon's marvelous scales boost the Defense stat if it has a status condition.", + }, + liquidOoze: { + name: "Liquid Ooze", + description: "The oozed liquid has a strong stench, which damages attackers using any draining move.", + }, + overgrow: { + name: "Overgrow", + description: "Powers up Grass-type moves when the Pokémon's HP is low.", + }, + blaze: { + name: "Blaze", + description: "Powers up Fire-type moves when the Pokémon's HP is low.", + }, + torrent: { + name: "Torrent", + description: "Powers up Water-type moves when the Pokémon's HP is low.", + }, + swarm: { + name: "Swarm", + description: "Powers up Bug-type moves when the Pokémon's HP is low.", + }, + rockHead: { + name: "Rock Head", + description: "Protects the Pokémon from recoil damage.", + }, + drought: { + name: "Drought", + description: "Turns the sunlight harsh when the Pokémon enters a battle.", + }, + arenaTrap: { + name: "Arena Trap", + description: "Prevents opposing Pokémon from fleeing.", + }, + vitalSpirit: { + name: "Vital Spirit", + description: "The Pokémon is full of vitality, and that prevents it from falling asleep.", + }, + whiteSmoke: { + name: "White Smoke", + description: "The Pokémon is protected by its white smoke, which prevents other Pokémon from lowering its stats.", + }, + purePower: { + name: "Pure Power", + description: "Using its pure power, the Pokémon doubles its Attack stat.", + }, + shellArmor: { + name: "Shell Armor", + description: "A hard shell protects the Pokémon from critical hits.", + }, + airLock: { + name: "Air Lock", + description: "Eliminates the effects of weather.", + }, + tangledFeet: { + name: "Tangled Feet", + description: "Raises evasiveness if the Pokémon is confused.", + }, + motorDrive: { + name: "Motor Drive", + description: "Boosts its Speed stat if hit by an Electric-type move instead of taking damage.", + }, + rivalry: { + name: "Rivalry", + description: "Becomes competitive and deals more damage to Pokémon of the same gender, but deals less to Pokémon of the opposite gender.", + }, + steadfast: { + name: "Steadfast", + description: "The Pokémon's determination boosts the Speed stat each time the Pokémon flinches.", + }, + snowCloak: { + name: "Snow Cloak", + description: "Boosts the Pokémon's evasiveness in snow.", + }, + gluttony: { + name: "Gluttony", + description: "Makes the Pokémon eat a held Berry when its HP drops to half or less, which is sooner than usual.", + }, + angerPoint: { + name: "Anger Point", + description: "The Pokémon is angered when it takes a critical hit, and that maxes its Attack stat.", + }, + unburden: { + name: "Unburden", + description: "Boosts the Speed stat if the Pokémon's held item is used or lost.", + }, + heatproof: { + name: "Heatproof", + description: "The heatproof body of the Pokémon halves the damage from Fire-type moves that hit it.", + }, + simple: { + name: "Simple", + description: "The stat changes the Pokémon receives are doubled.", + }, + drySkin: { + name: "Dry Skin", + description: "Restores HP in rain or when hit by Water-type moves. Reduces HP in harsh sunlight, and increases the damage received from Fire-type moves.", + }, + download: { + name: "Download", + description: "Compares an opposing Pokémon's Defense and Sp. Def stats before raising its own Attack or Sp. Atk stat—whichever will be more effective.", + }, + ironFist: { + name: "Iron Fist", + description: "Powers up punching moves.", + }, + poisonHeal: { + name: "Poison Heal", + description: "Restores HP if the Pokémon is poisoned instead of losing HP.", + }, + adaptability: { + name: "Adaptability", + description: "Powers up moves of the same type as the Pokémon.", + }, + skillLink: { + name: "Skill Link", + description: "Maximizes the number of times multistrike moves hit.", + }, + hydration: { + name: "Hydration", + description: "Heals status conditions if it's raining.", + }, + solarPower: { + name: "Solar Power", + description: "Boosts the Sp. Atk stat in harsh sunlight, but HP decreases every turn.", + }, + quickFeet: { + name: "Quick Feet", + description: "Boosts the Speed stat if the Pokémon has a status condition.", + }, + normalize: { + name: "Normalize", + description: "All the Pokémon's moves become Normal type. The power of those moves is boosted a little.", + }, + sniper: { + name: "Sniper", + description: "Powers up moves if they become critical hits when attacking.", + }, + magicGuard: { + name: "Magic Guard", + description: "The Pokémon only takes damage from attacks.", + }, + noGuard: { + name: "No Guard", + description: "The Pokémon employs no-guard tactics to ensure incoming and outgoing attacks always land.", + }, + stall: { + name: "Stall", + description: "The Pokémon moves after all other Pokémon do.", + }, + technician: { + name: "Technician", + description: "Powers up the Pokémon's weaker moves.", + }, + leafGuard: { + name: "Leaf Guard", + description: "Prevents status conditions in harsh sunlight.", + }, + klutz: { + name: "Klutz", + description: "The Pokémon can't use any held items.", + }, + moldBreaker: { + name: "Mold Breaker", + description: "Moves can be used on the target regardless of its Abilities.", + }, + superLuck: { + name: "Super Luck", + description: "The Pokémon is so lucky that the critical-hit ratios of its moves are boosted.", + }, + aftermath: { + name: "Aftermath", + description: "Damages the attacker if it contacts the Pokémon with a finishing hit.", + }, + anticipation: { + name: "Anticipation", + description: "The Pokémon can sense an opposing Pokémon's dangerous moves.", + }, + forewarn: { + name: "Forewarn", + description: "When it enters a battle, the Pokémon can tell one of the moves an opposing Pokémon has.", + }, + unaware: { + name: "Unaware", + description: "When attacking, the Pokémon ignores the target Pokémon's stat changes.", + }, + tintedLens: { + name: "Tinted Lens", + description: "The Pokémon can use \"not very effective\" moves to deal regular damage.", + }, + filter: { + name: "Filter", + description: "Reduces the power of supereffective attacks taken.", + }, + slowStart: { + name: "Slow Start", + description: "For five turns, the Pokémon's Attack and Speed stats are halved.", + }, + scrappy: { + name: "Scrappy", + description: "The Pokémon can hit Ghost-type Pokémon with Normal- and Fighting-type moves.", + }, + stormDrain: { + name: "Storm Drain", + description: "Draws in all Water-type moves. Instead of being hit by Water-type moves, it boosts its Sp. Atk.", + }, + iceBody: { + name: "Ice Body", + description: "The Pokémon gradually regains HP in snow.", + }, + solidRock: { + name: "Solid Rock", + description: "Reduces the power of supereffective attacks taken.", + }, + snowWarning: { + name: "Snow Warning", + description: "The Pokémon makes it snow when it enters a battle.", + }, + honeyGather: { + name: "Honey Gather", + description: "The Pokémon gathers Honey after a battle. The Honey is then sold for money.", + }, + frisk: { + name: "Frisk", + description: "When it enters a battle, the Pokémon can check an opposing Pokémon's Ability.", + }, + reckless: { + name: "Reckless", + description: "Powers up moves that have recoil damage.", + }, + multitype: { + name: "Multitype", + description: "Changes the Pokémon's type to match the Plate or Z-Crystal it holds.", + }, + flowerGift: { + name: "Flower Gift", + description: "Boosts the Attack and Sp. Def stats of itself and allies in harsh sunlight.", + }, + badDreams: { + name: "Bad Dreams", + description: "Reduces the HP of sleeping opposing Pokémon.", + }, + pickpocket: { + name: "Pickpocket", + description: "Steals an item from an attacker that made direct contact.", + }, + sheerForce: { + name: "Sheer Force", + description: "Removes additional effects to increase the power of moves when attacking.", + }, + contrary: { + name: "Contrary", + description: "Makes stat changes have an opposite effect.", + }, + unnerve: { + name: "Unnerve", + description: "Unnerves opposing Pokémon and makes them unable to eat Berries.", + }, + defiant: { + name: "Defiant", + description: "Boosts the Pokémon's Attack stat sharply when its stats are lowered.", + }, + defeatist: { + name: "Defeatist", + description: "Halves the Pokémon's Attack and Sp. Atk stats when its HP becomes half or less.", + }, + cursedBody: { + name: "Cursed Body", + description: "May disable a move used on the Pokémon.", + }, + healer: { + name: "Healer", + description: "Sometimes heals an ally's status condition.", + }, + friendGuard: { + name: "Friend Guard", + description: "Reduces damage done to allies.", + }, + weakArmor: { + name: "Weak Armor", + description: "Physical attacks to the Pokémon lower its Defense stat but sharply raise its Speed stat.", + }, + heavyMetal: { + name: "Heavy Metal", + description: "Doubles the Pokémon's weight.", + }, + lightMetal: { + name: "Light Metal", + description: "Halves the Pokémon's weight.", + }, + multiscale: { + name: "Multiscale", + description: "Reduces the amount of damage the Pokémon takes while its HP is full.", + }, + toxicBoost: { + name: "Toxic Boost", + description: "Powers up physical attacks when the Pokémon is poisoned.", + }, + flareBoost: { + name: "Flare Boost", + description: "Powers up special attacks when the Pokémon is burned.", + }, + harvest: { + name: "Harvest", + description: "May create another Berry after one is used.", + }, + telepathy: { + name: "Telepathy", + description: "Anticipates an ally's attack and dodges it.", + }, + moody: { + name: "Moody", + description: "Raises one stat sharply and lowers another every turn.", + }, + overcoat: { + name: "Overcoat", + description: "Protects the Pokémon from things like sand, hail, and powder.", + }, + poisonTouch: { + name: "Poison Touch", + description: "May poison a target when the Pokémon makes contact.", + }, + regenerator: { + name: "Regenerator", + description: "Restores a little HP when withdrawn from battle.", + }, + bigPecks: { + name: "Big Pecks", + description: "Protects the Pokémon from Defense-lowering effects.", + }, + sandRush: { + name: "Sand Rush", + description: "Boosts the Pokémon's Speed stat in a sandstorm.", + }, + wonderSkin: { + name: "Wonder Skin", + description: "Makes status moves more likely to miss.", + }, + analytic: { + name: "Analytic", + description: "Boosts move power when the Pokémon moves last.", + }, + illusion: { + name: "Illusion", + description: "Comes out disguised as the Pokémon in the party's last spot.", + }, + imposter: { + name: "Imposter", + description: "The Pokémon transforms itself into the Pokémon it's facing.", + }, + infiltrator: { + name: "Infiltrator", + description: "Passes through the opposing Pokémon's barrier, substitute, and the like and strikes.", + }, + mummy: { + name: "Mummy", + description: "Contact with the Pokémon changes the attacker's Ability to Mummy.", + }, + moxie: { + name: "Moxie", + description: "The Pokémon shows moxie, and that boosts the Attack stat after knocking out any Pokémon.", + }, + justified: { + name: "Justified", + description: "Being hit by a Dark-type move boosts the Attack stat of the Pokémon, for justice.", + }, + rattled: { + name: "Rattled", + description: "Intimidate or being hit by a Dark-, Ghost-, or Bug-type move will scare the Pokémon and boost its Speed stat.", + }, + magicBounce: { + name: "Magic Bounce", + description: "Reflects status moves instead of getting hit by them.", + }, + sapSipper: { + name: "Sap Sipper", + description: "Boosts the Attack stat if hit by a Grass-type move instead of taking damage.", + }, + prankster: { + name: "Prankster", + description: "Gives priority to a status move.", + }, + sandForce: { + name: "Sand Force", + description: "Boosts the power of Rock-, Ground-, and Steel-type moves in a sandstorm.", + }, + ironBarbs: { + name: "Iron Barbs", + description: "Inflicts damage on the attacker upon contact with iron barbs.", + }, + zenMode: { + name: "Zen Mode", + description: "Changes the Pokémon's shape when HP is half or less.", + }, + victoryStar: { + name: "Victory Star", + description: "Boosts the accuracy of its allies and itself.", + }, + turboblaze: { + name: "Turboblaze", + description: "Moves can be used on the target regardless of its Abilities.", + }, + teravolt: { + name: "Teravolt", + description: "Moves can be used on the target regardless of its Abilities.", + }, + aromaVeil: { + name: "Aroma Veil", + description: "Protects itself and its allies from attacks that limit their move choices.", + }, + flowerVeil: { + name: "Flower Veil", + description: "Ally Grass-type Pokémon are protected from status conditions and the lowering of their stats.", + }, + cheekPouch: { + name: "Cheek Pouch", + description: "Restores HP as well when the Pokémon eats a Berry.", + }, + protean: { + name: "Protean", + description: "Changes the Pokémon's type to the type of the move it's about to use.", + }, + furCoat: { + name: "Fur Coat", + description: "Halves the damage from physical moves.", + }, + magician: { + name: "Magician", + description: "The Pokémon steals the held item of a Pokémon it hits with a move.", + }, + bulletproof: { + name: "Bulletproof", + description: "Protects the Pokémon from some ball and bomb moves.", + }, + competitive: { + name: "Competitive", + description: "Boosts the Sp. Atk stat sharply when a stat is lowered.", + }, + strongJaw: { + name: "Strong Jaw", + description: "The Pokémon's strong jaw boosts the power of its biting moves.", + }, + refrigerate: { + name: "Refrigerate", + description: "Normal-type moves become Ice-type moves. The power of those moves is boosted a little.", + }, + sweetVeil: { + name: "Sweet Veil", + description: "Prevents itself and ally Pokémon from falling asleep.", + }, + stanceChange: { + name: "Stance Change", + description: "The Pokémon changes its form to Blade Forme when it uses an attack move and changes to Shield Forme when it uses King's Shield.", + }, + galeWings: { + name: "Gale Wings", + description: "Gives priority to Flying-type moves when the Pokémon's HP is full.", + }, + megaLauncher: { + name: "Mega Launcher", + description: "Powers up aura and pulse moves.", + }, + grassPelt: { + name: "Grass Pelt", + description: "Boosts the Pokémon's Defense stat on Grassy Terrain.", + }, + symbiosis: { + name: "Symbiosis", + description: "The Pokémon passes its item to an ally that has used up an item.", + }, + toughClaws: { + name: "Tough Claws", + description: "Powers up moves that make direct contact.", + }, + pixilate: { + name: "Pixilate", + description: "Normal-type moves become Fairy-type moves. The power of those moves is boosted a little.", + }, + gooey: { + name: "Gooey", + description: "Contact with the Pokémon lowers the attacker's Speed stat.", + }, + aerilate: { + name: "Aerilate", + description: "Normal-type moves become Flying-type moves. The power of those moves is boosted a little.", + }, + parentalBond: { + name: "Parental Bond", + description: "Parent and child each attacks.", + }, + darkAura: { + name: "Dark Aura", + description: "Powers up each Pokémon's Dark-type moves.", + }, + fairyAura: { + name: "Fairy Aura", + description: "Powers up each Pokémon's Fairy-type moves.", + }, + auraBreak: { + name: "Aura Break", + description: "The effects of \"Aura\" Abilities are reversed to lower the power of affected moves.", + }, + primordialSea: { + name: "Primordial Sea", + description: "The Pokémon changes the weather to nullify Fire-type attacks.", + }, + desolateLand: { + name: "Desolate Land", + description: "The Pokémon changes the weather to nullify Water-type attacks.", + }, + deltaStream: { + name: "Delta Stream", + description: "The Pokémon changes the weather to eliminate all of the Flying type's weaknesses.", + }, + stamina: { + name: "Stamina", + description: "Boosts the Defense stat when hit by an attack.", + }, + wimpOut: { + name: "Wimp Out", + description: "The Pokémon cowardly switches out when its HP becomes half or less.", + }, + emergencyExit: { + name: "Emergency Exit", + description: "The Pokémon, sensing danger, switches out when its HP becomes half or less.", + }, + waterCompaction: { + name: "Water Compaction", + description: "Boosts the Pokémon's Defense stat sharply when hit by a Water-type move.", + }, + merciless: { + name: "Merciless", + description: "The Pokémon's attacks become critical hits if the target is poisoned.", + }, + shieldsDown: { + name: "Shields Down", + description: "When its HP becomes half or less, the Pokémon's shell breaks and it becomes aggressive.", + }, + stakeout: { + name: "Stakeout", + description: "Doubles the damage dealt to the target's replacement if the target switches out.", + }, + waterBubble: { + name: "Water Bubble", + description: "Lowers the power of Fire-type moves done to the Pokémon and prevents the Pokémon from getting a burn.", + }, + steelworker: { + name: "Steelworker", + description: "Powers up Steel-type moves.", + }, + berserk: { + name: "Berserk", + description: "Boosts the Pokémon's Sp. Atk stat when it takes a hit that causes its HP to become half or less.", + }, + slushRush: { + name: "Slush Rush", + description: "Boosts the Pokémon's Speed stat in snow.", + }, + longReach: { + name: "Long Reach", + description: "The Pokémon uses its moves without making contact with the target.", + }, + liquidVoice: { + name: "Liquid Voice", + description: "All sound-based moves become Water-type moves.", + }, + triage: { + name: "Triage", + description: "Gives priority to a healing move.", + }, + galvanize: { + name: "Galvanize", + description: "Normal-type moves become Electric-type moves. The power of those moves is boosted a little.", + }, + surgeSurfer: { + name: "Surge Surfer", + description: "Doubles the Pokémon's Speed stat on Electric Terrain.", + }, + schooling: { + name: "Schooling", + description: "When it has a lot of HP, the Pokémon forms a powerful school. It stops schooling when its HP is low.", + }, + disguise: { + name: "Disguise", + description: "Once per battle, the shroud that covers the Pokémon can protect it from an attack.", + }, + battleBond: { + name: "Battle Bond", + description: "Defeating an opposing Pokémon strengthens the Pokémon's bond with its Trainer, and it becomes Ash-Greninja. Water Shuriken gets more powerful.", + }, + powerConstruct: { + name: "Power Construct", + description: "Other Cells gather to aid when its HP becomes half or less. Then the Pokémon changes its form to Complete Forme.", + }, + corrosion: { + name: "Corrosion", + description: "The Pokémon can poison the target even if it's a Steel or Poison type.", + }, + comatose: { + name: "Comatose", + description: "It's always drowsing and will never wake up. It can attack without waking up.", + }, + queenlyMajesty: { + name: "Queenly Majesty", + description: "Its majesty pressures the opposing Pokémon, making it unable to attack using priority moves.", + }, + innardsOut: { + name: "Innards Out", + description: "Damages the attacker landing the finishing hit by the amount equal to its last HP.", + }, + dancer: { + name: "Dancer", + description: "When another Pokémon uses a dance move, it can use a dance move following it regardless of its Speed.", + }, + battery: { + name: "Battery", + description: "Powers up ally Pokémon's special moves.", + }, + fluffy: { + name: "Fluffy", + description: "Halves the damage taken from moves that make direct contact, but doubles that of Fire-type moves.", + }, + dazzling: { + name: "Dazzling", + description: "Surprises the opposing Pokémon, making it unable to attack using priority moves.", + }, + soulHeart: { + name: "Soul-Heart", + description: "Boosts its Sp. Atk stat every time a Pokémon faints.", + }, + tanglingHair: { + name: "Tangling Hair", + description: "Contact with the Pokémon lowers the attacker's Speed stat.", + }, + receiver: { + name: "Receiver", + description: "The Pokémon copies the Ability of a defeated ally.", + }, + powerOfAlchemy: { + name: "Power of Alchemy", + description: "The Pokémon copies the Ability of a defeated ally.", + }, + beastBoost: { + name: "Beast Boost", + description: "The Pokémon boosts its most proficient stat each time it knocks out a Pokémon.", + }, + rksSystem: { + name: "RKS System", + description: "Changes the Pokémon's type to match the memory disc it holds.", + }, + electricSurge: { + name: "Electric Surge", + description: "Turns the ground into Electric Terrain when the Pokémon enters a battle.", + }, + psychicSurge: { + name: "Psychic Surge", + description: "Turns the ground into Psychic Terrain when the Pokémon enters a battle.", + }, + mistySurge: { + name: "Misty Surge", + description: "Turns the ground into Misty Terrain when the Pokémon enters a battle.", + }, + grassySurge: { + name: "Grassy Surge", + description: "Turns the ground into Grassy Terrain when the Pokémon enters a battle.", + }, + fullMetalBody: { + name: "Full Metal Body", + description: "Prevents other Pokémon's moves or Abilities from lowering the Pokémon's stats.", + }, + shadowShield: { + name: "Shadow Shield", + description: "Reduces the amount of damage the Pokémon takes while its HP is full.", + }, + prismArmor: { + name: "Prism Armor", + description: "Reduces the power of supereffective attacks taken.", + }, + neuroforce: { + name: "Neuroforce", + description: "Powers up moves that are super effective.", + }, + intrepidSword: { + name: "Intrepid Sword", + description: "Boosts the Pokémon's Attack stat when the Pokémon enters a battle.", + }, + dauntlessShield: { + name: "Dauntless Shield", + description: "Boosts the Pokémon's Defense stat when the Pokémon enters a battle.", + }, + libero: { + name: "Libero", + description: "Changes the Pokémon's type to the type of the move it's about to use.", + }, + ballFetch: { + name: "Ball Fetch", + description: "The Pokémon will fetch the Poké Ball from the first failed throw of the battle.", + }, + cottonDown: { + name: "Cotton Down", + description: "When the Pokémon is hit by an attack, it scatters cotton fluff around and lowers the Speed stat of all Pokémon except itself.", + }, + propellerTail: { + name: "Propeller Tail", + description: "Ignores the effects of opposing Pokémon's Abilities and moves that draw in moves.", + }, + mirrorArmor: { + name: "Mirror Armor", + description: "Bounces back only the stat-lowering effects that the Pokémon receives.", + }, + gulpMissile: { + name: "Gulp Missile", + description: "When the Pokémon uses Surf or Dive, it will come back with prey. When it takes damage, it will spit out the prey to attack.", + }, + stalwart: { + name: "Stalwart", + description: "Ignores the effects of opposing Pokémon's Abilities and moves that draw in moves.", + }, + steamEngine: { + name: "Steam Engine", + description: "Boosts the Pokémon's Speed stat drastically if hit by a Fire- or Water-type move.", + }, + punkRock: { + name: "Punk Rock", + description: "Boosts the power of sound-based moves. The Pokémon also takes half the damage from these kinds of moves.", + }, + sandSpit: { + name: "Sand Spit", + description: "The Pokémon creates a sandstorm when it's hit by an attack.", + }, + iceScales: { + name: "Ice Scales", + description: "The Pokémon is protected by ice scales, which halve the damage taken from special moves.", + }, + ripen: { + name: "Ripen", + description: "Ripens Berries and doubles their effect.", + }, + iceFace: { + name: "Ice Face", + description: "The Pokémon's ice head can take a physical attack as a substitute, but the attack also changes the Pokémon's appearance. The ice will be restored when it hails.", + }, + powerSpot: { + name: "Power Spot", + description: "Just being next to the Pokémon powers up moves.", + }, + mimicry: { + name: "Mimicry", + description: "Changes the Pokémon's type depending on the terrain.", + }, + screenCleaner: { + name: "Screen Cleaner", + description: "When the Pokémon enters a battle, the effects of Light Screen, Reflect, and Aurora Veil are nullified for both opposing and ally Pokémon.", + }, + steelySpirit: { + name: "Steely Spirit", + description: "Powers up ally Pokémon's Steel-type moves.", + }, + perishBody: { + name: "Perish Body", + description: "When hit by a move that makes direct contact, the Pokémon and the attacker will faint after three turns unless they switch out of battle.", + }, + wanderingSpirit: { + name: "Wandering Spirit", + description: "The Pokémon exchanges Abilities with a Pokémon that hits it with a move that makes direct contact.", + }, + gorillaTactics: { + name: "Gorilla Tactics", + description: "Boosts the Pokémon's Attack stat but only allows the use of the first selected move.", + }, + neutralizingGas: { + name: "Neutralizing Gas", + description: "If the Pokémon with Neutralizing Gas is in the battle, the effects of all Pokémon's Abilities will be nullified or will not be triggered.", + }, + pastelVeil: { + name: "Pastel Veil", + description: "Protects the Pokémon and its ally Pokémon from being poisoned.", + }, + hungerSwitch: { + name: "Hunger Switch", + description: "The Pokémon changes its form, alternating between its Full Belly Mode and Hangry Mode after the end of each turn.", + }, + quickDraw: { + name: "Quick Draw", + description: "Enables the Pokémon to move first occasionally.", + }, + unseenFist: { + name: "Unseen Fist", + description: "If the Pokémon uses moves that make direct contact, it can attack the target even if the target protects itself.", + }, + curiousMedicine: { + name: "Curious Medicine", + description: "When the Pokémon enters a battle, it scatters medicine from its shell, which removes all stat changes from allies.", + }, + transistor: { + name: "Transistor", + description: "Powers up Electric-type moves.", + }, + dragonsMaw: { + name: "Dragon's Maw", + description: "Powers up Dragon-type moves.", + }, + chillingNeigh: { + name: "Chilling Neigh", + description: "When the Pokémon knocks out a target, it utters a chilling neigh, which boosts its Attack stat.", + }, + grimNeigh: { + name: "Grim Neigh", + description: "When the Pokémon knocks out a target, it utters a terrifying neigh, which boosts its Sp. Atk stat.", + }, + asOneGlastrier: { + name: "As One", + description: "This Ability combines the effects of both Calyrex's Unnerve Ability and Glastrier's Chilling Neigh Ability.", + }, + asOneSpectrier: { + name: "As One", + description: "This Ability combines the effects of both Calyrex's Unnerve Ability and Spectrier's Grim Neigh Ability.", + }, + lingeringAroma: { + name: "Lingering Aroma", + description: "Contact with the Pokémon changes the attacker's Ability to Lingering Aroma.", + }, + seedSower: { + name: "Seed Sower", + description: "Turns the ground into Grassy Terrain when the Pokémon is hit by an attack.", + }, + thermalExchange: { + name: "Thermal Exchange", + description: "Boosts the Attack stat when the Pokémon is hit by a Fire-type move. The Pokémon also cannot be burned.", + }, + angerShell: { + name: "Anger Shell", + description: "When an attack causes its HP to drop to half or less, the Pokémon gets angry. This lowers its Defense and Sp. Def stats but boosts its Attack, Sp. Atk, and Speed stats.", + }, + purifyingSalt: { + name: "Purifying Salt", + description: "The Pokémon's pure salt protects it from status conditions and halves the damage taken from Ghost-type moves.", + }, + wellBakedBody: { + name: "Well-Baked Body", + description: "The Pokémon takes no damage when hit by Fire-type moves. Instead, its Defense stat is sharply boosted.", + }, + windRider: { + name: "Wind Rider", + description: "Boosts the Pokémon's Attack stat if Tailwind takes effect or if the Pokémon is hit by a wind move. The Pokémon also takes no damage from wind moves.", + }, + guardDog: { + name: "Guard Dog", + description: "Boosts the Pokémon's Attack stat if intimidated. Moves and items that would force the Pokémon to switch out also fail to work.", + }, + rockyPayload: { + name: "Rocky Payload", + description: "Powers up Rock-type moves.", + }, + windPower: { + name: "Wind Power", + description: "The Pokémon becomes charged when it is hit by a wind move, boosting the power of the next Electric-type move the Pokémon uses.", + }, + zeroToHero: { + name: "Zero to Hero", + description: "The Pokémon transforms into its Hero Form when it switches out.", + }, + commander: { + name: "Commander", + description: "When the Pokémon enters a battle, it goes inside the mouth of an ally Dondozo if one is on the field. The Pokémon then issues commands from there.", + }, + electromorphosis: { + name: "Electromorphosis", + description: "The Pokémon becomes charged when it takes damage, boosting the power of the next Electric-type move the Pokémon uses.", + }, + protosynthesis: { + name: "Protosynthesis", + description: "Boosts the Pokémon's most proficient stat in harsh sunlight or if the Pokémon is holding Booster Energy.", + }, + quarkDrive: { + name: "Quark Drive", + description: "Boosts the Pokémon's most proficient stat on Electric Terrain or if the Pokémon is holding Booster Energy.", + }, + goodAsGold: { + name: "Good as Gold", + description: "A body of pure, solid gold gives the Pokémon full immunity to other Pokémon's status moves.", + }, + vesselOfRuin: { + name: "Vessel of Ruin", + description: "The power of the Pokémon's ruinous vessel lowers the Sp. Atk stats of all Pokémon except itself.", + }, + swordOfRuin: { + name: "Sword of Ruin", + description: "The power of the Pokémon's ruinous sword lowers the Defense stats of all Pokémon except itself.", + }, + tabletsOfRuin: { + name: "Tablets of Ruin", + description: "The power of the Pokémon's ruinous wooden tablets lowers the Attack stats of all Pokémon except itself.", + }, + beadsOfRuin: { + name: "Beads of Ruin", + description: "The power of the Pokémon's ruinous beads lowers the Sp. Def stats of all Pokémon except itself.", + }, + orichalcumPulse: { + name: "Orichalcum Pulse", + description: "Turns the sunlight harsh when the Pokémon enters a battle. The ancient pulse thrumming through the Pokémon also boosts its Attack stat in harsh sunlight.", + }, + hadronEngine: { + name: "Hadron Engine", + description: "Turns the ground into Electric Terrain when the Pokémon enters a battle. The futuristic engine within the Pokémon also boosts its Sp. Atk stat on Electric Terrain.", + }, + opportunist: { + name: "Opportunist", + description: "If an opponent's stat is boosted, the Pokémon seizes the opportunity to boost the same stat for itself.", + }, + cudChew: { + name: "Cud Chew", + description: "When the Pokémon eats a Berry, it will regurgitate that Berry at the end of the next turn and eat it one more time.", + }, + sharpness: { + name: "Sharpness", + description: "Powers up slicing moves.", + }, + supremeOverlord: { + name: "Supreme Overlord", + description: "When the Pokémon enters a battle, its Attack and Sp. Atk stats are slightly boosted for each of the allies in its party that have already been defeated.", + }, + costar: { + name: "Costar", + description: "When the Pokémon enters a battle, it copies an ally's stat changes.", + }, + toxicDebris: { + name: "Toxic Debris", + description: "Scatters poison spikes at the feet of the opposing team when the Pokémon takes damage from physical moves.", + }, + armorTail: { + name: "Armor Tail", + description: "The mysterious tail covering the Pokémon's head makes opponents unable to use priority moves against the Pokémon or its allies.", + }, + earthEater: { + name: "Earth Eater", + description: "If hit by a Ground-type move, the Pokémon has its HP restored instead of taking damage.", + }, + myceliumMight: { + name: "Mycelium Might", + description: "The Pokémon will always act more slowly when using status moves, but these moves will be unimpeded by the Ability of the target.", + }, + mindsEye: { + name: "Mind's Eye", + description: "The Pokémon ignores changes to opponents' evasiveness, its accuracy can't be lowered, and it can hit Ghost types with Normal- and Fighting-type moves.", + }, + supersweetSyrup: { + name: "Supersweet Syrup", + description: "A sickly sweet scent spreads across the field the first time the Pokémon enters a battle, lowering the evasiveness of opposing Pokémon.", + }, + hospitality: { + name: "Hospitality", + description: "When the Pokémon enters a battle, it showers its ally with hospitality, restoring a small amount of the ally's HP.", + }, + toxicChain: { + name: "Toxic Chain", + description: "The power of the Pokémon's toxic chain may badly poison any target the Pokémon hits with a move.", + }, + embodyAspectTeal: { + name: "Embody Aspect", + description: "The Pokémon's heart fills with memories, causing the Teal Mask to shine and the Pokémon's Speed stat to be boosted.", + }, + embodyAspectWellspring: { + name: "Embody Aspect", + description: "The Pokémon's heart fills with memories, causing the Wellspring Mask to shine and the Pokémon's Sp. Def stat to be boosted.", + }, + embodyAspectHearthflame: { + name: "Embody Aspect", + description: "The Pokémon's heart fills with memories, causing the Hearthflame Mask to shine and the Pokémon's Attack stat to be boosted.", + }, + embodyAspectCornerstone: { + name: "Embody Aspect", + description: "The Pokémon's heart fills with memories, causing the Cornerstone Mask to shine and the Pokémon's Defense stat to be boosted.", + }, + teraShift: { + name: "Tera Shift", + description: "When the Pokémon enters a battle, it absorbs the energy around itself and transforms into its Terastal Form.", + }, + teraShell: { + name: "Tera Shell", + description: "The Pokémon's shell contains the powers of each type. All damage-dealing moves that hit the Pokémon when its HP is full will not be very effective.", + }, + teraformZero: { + name: "Teraform Zero", + description: "When Terapagos changes into its Stellar Form, it uses its hidden powers to eliminate all effects of weather and terrain, reducing them to zero.", + }, + poisonPuppeteer: { + name: "Poison Puppeteer", + description: "Pokémon poisoned by Pecharunt's moves will also become confused.", + }, +} as const; diff --git a/src/locales/ca-ES/achv.ts b/src/locales/ca-ES/achv.ts new file mode 100644 index 00000000000..6123b735c4e --- /dev/null +++ b/src/locales/ca-ES/achv.ts @@ -0,0 +1,274 @@ +import { AchievementTranslationEntries } from "#app/interfaces/locales.js"; + +// Achievement translations for the when the player character is male +export const PGMachv: AchievementTranslationEntries = { + "Achievements": { + name: "Achievements", + }, + "Locked": { + name: "Locked", + }, + + "MoneyAchv": { + description: "Accumulate a total of ₽{{moneyAmount}}", + }, + "10K_MONEY": { + name: "Money Haver", + }, + "100K_MONEY": { + name: "Rich", + }, + "1M_MONEY": { + name: "Millionaire", + }, + "10M_MONEY": { + name: "One Percenter", + }, + + "DamageAchv": { + description: "Inflict {{damageAmount}} damage in one hit", + }, + "250_DMG": { + name: "Hard Hitter", + }, + "1000_DMG": { + name: "Harder Hitter", + }, + "2500_DMG": { + name: "That's a Lotta Damage!", + }, + "10000_DMG": { + name: "One Punch Man", + }, + + "HealAchv": { + description: "Heal {{healAmount}} {{HP}} at once with a move, ability, or held item", + }, + "250_HEAL": { + name: "Novice Healer", + }, + "1000_HEAL": { + name: "Big Healer", + }, + "2500_HEAL": { + name: "Cleric", + }, + "10000_HEAL": { + name: "Recovery Master", + }, + + "LevelAchv": { + description: "Level up a Pokémon to Lv{{level}}", + }, + "LV_100": { + name: "But Wait, There's More!", + }, + "LV_250": { + name: "Elite", + }, + "LV_1000": { + name: "To Go Even Further Beyond", + }, + + "RibbonAchv": { + description: "Accumulate a total of {{ribbonAmount}} Ribbons", + }, + "10_RIBBONS": { + name: "Pokémon League Champion", + }, + "25_RIBBONS": { + name: "Great League Champion", + }, + "50_RIBBONS": { + name: "Ultra League Champion", + }, + "75_RIBBONS": { + name: "Rogue League Champion", + }, + "100_RIBBONS": { + name: "Master League Champion", + }, + + "TRANSFER_MAX_BATTLE_STAT": { + name: "Teamwork", + description: "Baton pass to another party member with at least one stat maxed out", + }, + "MAX_FRIENDSHIP": { + name: "Friendmaxxing", + description: "Reach max friendship on a Pokémon", + }, + "MEGA_EVOLVE": { + name: "Megamorph", + description: "Mega evolve a Pokémon", + }, + "GIGANTAMAX": { + name: "Absolute Unit", + description: "Gigantamax a Pokémon", + }, + "TERASTALLIZE": { + name: "STAB Enthusiast", + description: "Terastallize a Pokémon", + }, + "STELLAR_TERASTALLIZE": { + name: "The Hidden Type", + description: "Stellar Terastallize a Pokémon", + }, + "SPLICE": { + name: "Infinite Fusion", + description: "Splice two Pokémon together with DNA Splicers", + }, + "MINI_BLACK_HOLE": { + name: "A Hole Lot of Items", + description: "Acquire a Mini Black Hole", + }, + "CATCH_MYTHICAL": { + name: "Mythical", + description: "Catch a mythical Pokémon", + }, + "CATCH_SUB_LEGENDARY": { + name: "(Sub-)Legendary", + description: "Catch a sub-legendary Pokémon", + }, + "CATCH_LEGENDARY": { + name: "Legendary", + description: "Catch a legendary Pokémon", + }, + "SEE_SHINY": { + name: "Shiny", + description: "Find a shiny Pokémon in the wild", + }, + "SHINY_PARTY": { + name: "That's Dedication", + description: "Have a full party of shiny Pokémon", + }, + "HATCH_MYTHICAL": { + name: "Mythical Egg", + description: "Hatch a mythical Pokémon from an egg", + }, + "HATCH_SUB_LEGENDARY": { + name: "Sub-Legendary Egg", + description: "Hatch a sub-legendary Pokémon from an egg", + }, + "HATCH_LEGENDARY": { + name: "Legendary Egg", + description: "Hatch a legendary Pokémon from an egg", + }, + "HATCH_SHINY": { + name: "Shiny Egg", + description: "Hatch a shiny Pokémon from an egg", + }, + "HIDDEN_ABILITY": { + name: "Hidden Potential", + description: "Catch a Pokémon with a hidden ability", + }, + "PERFECT_IVS": { + name: "Certificate of Authenticity", + description: "Get perfect IVs on a Pokémon", + }, + "CLASSIC_VICTORY": { + name: "Undefeated", + description: "Beat the game in classic mode", + }, + + "MONO_GEN_ONE": { + name: "The Original Rival", + description: "Complete the generation one only challenge.", + }, + "MONO_GEN_TWO": { + name: "Generation 1.5", + description: "Complete the generation two only challenge.", + }, + "MONO_GEN_THREE": { + name: "Too much water?", + description: "Complete the generation three only challenge.", + }, + "MONO_GEN_FOUR": { + name: "Is she really the hardest?", + description: "Complete the generation four only challenge.", + }, + "MONO_GEN_FIVE": { + name: "All Original", + description: "Complete the generation five only challenge.", + }, + "MONO_GEN_SIX": { + name: "Almost Royalty", + description: "Complete the generation six only challenge.", + }, + "MONO_GEN_SEVEN": { + name: "Only Technically", + description: "Complete the generation seven only challenge.", + }, + "MONO_GEN_EIGHT": { + name: "A Champion Time!", + description: "Complete the generation eight only challenge.", + }, + "MONO_GEN_NINE": { + name: "She was going easy on you", + description: "Complete the generation nine only challenge.", + }, + + "MonoType": { + description: "Complete the {{type}} monotype challenge.", + }, + "MONO_NORMAL": { + name: "Extra Ordinary", + }, + "MONO_FIGHTING": { + name: "I Know Kung Fu", + }, + "MONO_FLYING": { + name: "Angry Birds", + }, + "MONO_POISON": { + name: "Kanto's Favourite", + }, + "MONO_GROUND": { + name: "Forecast: Earthquakes", + }, + "MONO_ROCK": { + name: "Brock Hard", + }, + "MONO_BUG": { + name: "You Like Jazz?", + }, + "MONO_GHOST": { + name: "Who You Gonna Call?", + }, + "MONO_STEEL": { + name: "Iron Giant", + }, + "MONO_FIRE": { + name: "I Cast Fireball!", + }, + "MONO_WATER": { + name: "When It Rains, It Pours", + }, + "MONO_GRASS": { + name: "Can't Touch This", + }, + "MONO_ELECTRIC": { + name: "Aim For The Horn!", + }, + "MONO_PSYCHIC": { + name: "Big Brain Energy", + }, + "MONO_ICE": { + name: "Walking On Thin Ice", + }, + "MONO_DRAGON": { + name: "Pseudo-Legend Club", + }, + "MONO_DARK": { + name: "It's Just A Phase", + }, + "MONO_FAIRY": { + name: "Hey! Listen!", + }, + "FRESH_START": { + name: "First Try!", + description: "Complete the Fresh Start challenge." + } +} as const; + +// Achievement translations for the when the player character is female (it for now uses the same translations as the male version) +export const PGFachv: AchievementTranslationEntries = PGMachv; diff --git a/src/locales/ca-ES/arena-flyout.ts b/src/locales/ca-ES/arena-flyout.ts new file mode 100644 index 00000000000..8a31d37b10c --- /dev/null +++ b/src/locales/ca-ES/arena-flyout.ts @@ -0,0 +1,49 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +export const arenaFlyout: SimpleTranslationEntries = { + // Title + "activeBattleEffects": "Active Battle Effects", + "player": "Player", + "neutral": "Neutral", + "enemy": "Enemy", + + // WeatherType + "sunny": "Sunny", + "rain": "Rain", + "sandstorm": "Sandstorm", + "hail": "Hail", + "snow": "Snow", + "fog": "Fog", + "heavyRain": "Heavy Rain", + "harshSun": "Harsh Sun", + "strongWinds": "Strong Winds", + + // TerrainType + "misty": "Misty Terrain", + "electric": "Electric Terrain", + "grassy": "Grassy Terrain", + "psychic": "Psychic Terrain", + + // ArenaTagType + "mudSport": "Mud Sport", + "waterSport": "Water Sport", + "spikes": "Spikes", + "toxicSpikes": "Toxic Spikes", + "mist": "Mist", + "futureSight": "Future Sight", + "doomDesire": "Doom Desire", + "wish": "Wish", + "stealthRock": "Stealth Rock", + "stickyWeb": "Sticky Web", + "trickRoom": "Trick Room", + "gravity": "Gravity", + "reflect": "Reflect", + "lightScreen": "Light Screen", + "auroraVeil": "Aurora Veil", + "quickGuard": "Quick Guard", + "wideGuard": "Wide Guard", + "matBlock": "Mat Block", + "craftyShield": "Crafty Shield", + "tailwind": "Tailwind", + "happyHour": "Happy Hour", +}; diff --git a/src/locales/ca-ES/arena-tag.ts b/src/locales/ca-ES/arena-tag.ts new file mode 100644 index 00000000000..22612795308 --- /dev/null +++ b/src/locales/ca-ES/arena-tag.ts @@ -0,0 +1,53 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +export const arenaTag: SimpleTranslationEntries = { + "yourTeam": "your team", + "opposingTeam": "the opposing team", + "arenaOnRemove": "{{moveName}}'s effect wore off.", + "arenaOnRemovePlayer": "{{moveName}}'s effect wore off\non your side.", + "arenaOnRemoveEnemy": "{{moveName}}'s effect wore off\non the foe's side.", + "mistOnAdd": "{{pokemonNameWithAffix}}'s team became\nshrouded in mist!", + "mistApply": "The mist prevented\nthe lowering of stats!", + "reflectOnAdd": "Reflect reduced the damage of physical moves.", + "reflectOnAddPlayer": "Reflect reduced the damage of physical moves on your side.", + "reflectOnAddEnemy": "Reflect reduced the damage of physical moves on the foe's side.", + "lightScreenOnAdd": "Light Screen reduced the damage of special moves.", + "lightScreenOnAddPlayer": "Light Screen reduced the damage of special moves on your side.", + "lightScreenOnAddEnemy": "Light Screen reduced the damage of special moves on the foe's side.", + "auroraVeilOnAdd": "Aurora Veil reduced the damage of moves.", + "auroraVeilOnAddPlayer": "Aurora Veil reduced the damage of moves on your side.", + "auroraVeilOnAddEnemy": "Aurora Veil reduced the damage of moves on the foe's side.", + "conditionalProtectOnAdd": "{{moveName}} protected team!", + "conditionalProtectOnAddPlayer": "{{moveName}} protected your team!", + "conditionalProtectOnAddEnemy": "{{moveName}} protected the\nopposing team!", + "conditionalProtectApply": "{{moveName}} protected {{pokemonNameWithAffix}}!", + "matBlockOnAdd": "{{pokemonNameWithAffix}} intends to flip up a mat\nand block incoming attacks!", + "noCritOnAddPlayer": "The {{moveName}} shielded your\nteam from critical hits!", + "noCritOnAddEnemy": "The {{moveName}} shielded the opposing\nteam from critical hits!", + "noCritOnRemove": "{{pokemonNameWithAffix}}'s {{moveName}}\nwore off!", + "wishTagOnAdd": "{{pokemonNameWithAffix}}'s wish\ncame true!", + "mudSportOnAdd": "Electricity's power was weakened!", + "mudSportOnRemove": "The effects of Mud Sport\nhave faded.", + "waterSportOnAdd": "Fire's power was weakened!", + "waterSportOnRemove": "The effects of Water Sport\nhave faded.", + "spikesOnAdd": "{{moveName}} were scattered\nall around {{opponentDesc}}'s feet!", + "spikesActivateTrap": "{{pokemonNameWithAffix}} is hurt\nby the spikes!", + "toxicSpikesOnAdd": "{{moveName}} were scattered\nall around {{opponentDesc}}'s feet!", + "toxicSpikesActivateTrapPoison": "{{pokemonNameWithAffix}} absorbed the {{moveName}}!", + "stealthRockOnAdd": "Pointed stones float in the air\naround {{opponentDesc}}!", + "stealthRockActivateTrap": "Pointed stones dug into\n{{pokemonNameWithAffix}}!", + "stickyWebOnAdd": "A {{moveName}} has been laid out on the ground around the opposing team!", + "stickyWebActivateTrap": "The opposing {{pokemonName}} was caught in a sticky web!", + "trickRoomOnAdd": "{{pokemonNameWithAffix}} twisted\nthe dimensions!", + "trickRoomOnRemove": "The twisted dimensions\nreturned to normal!", + "gravityOnAdd": "Gravity intensified!", + "gravityOnRemove": "Gravity returned to normal!", + "tailwindOnAdd": "The Tailwind blew from behind team!", + "tailwindOnAddPlayer": "The Tailwind blew from behind\nyour team!", + "tailwindOnAddEnemy": "The Tailwind blew from behind\nthe opposing team!", + "tailwindOnRemove": "Team's Tailwind petered out!", + "tailwindOnRemovePlayer": "Your team's Tailwind petered out!", + "tailwindOnRemoveEnemy": "The opposing team's Tailwind petered out!", + "happyHourOnAdd": "Everyone is caught up in the happy atmosphere!", + "happyHourOnRemove": "The atmosphere returned to normal.", +} as const; diff --git a/src/locales/ca-ES/battle-info.ts b/src/locales/ca-ES/battle-info.ts new file mode 100644 index 00000000000..f24dad46c6c --- /dev/null +++ b/src/locales/ca-ES/battle-info.ts @@ -0,0 +1,5 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +export const battleInfo: SimpleTranslationEntries = { + "generation": "Generation {{generation}}", +} as const; diff --git a/src/locales/ca-ES/battle-message-ui-handler.ts b/src/locales/ca-ES/battle-message-ui-handler.ts new file mode 100644 index 00000000000..34ca72276f5 --- /dev/null +++ b/src/locales/ca-ES/battle-message-ui-handler.ts @@ -0,0 +1,10 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +export const battleMessageUiHandler: SimpleTranslationEntries = { + "ivBest": "Best", + "ivFantastic": "Fantastic", + "ivVeryGood": "Very Good", + "ivPrettyGood": "Pretty Good", + "ivDecent": "Decent", + "ivNoGood": "No Good", +} as const; diff --git a/src/locales/ca-ES/battle.ts b/src/locales/ca-ES/battle.ts new file mode 100644 index 00000000000..12a0f2c99c6 --- /dev/null +++ b/src/locales/ca-ES/battle.ts @@ -0,0 +1,159 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +export const battle: SimpleTranslationEntries = { + "bossAppeared": "{{bossName}} appeared.", + "trainerAppeared": "{{trainerName}}\nwould like to battle!", + "trainerAppearedDouble": "{{trainerName}}\nwould like to battle!", + "trainerSendOut": "{{trainerName}} sent out\n{{pokemonName}}!", + "singleWildAppeared": "A wild {{pokemonName}} appeared!", + "multiWildAppeared": "A wild {{pokemonName1}}\nand {{pokemonName2}} appeared!", + "playerComeBack": "Come back, {{pokemonName}}!", + "trainerComeBack": "{{trainerName}} withdrew {{pokemonName}}!", + "playerGo": "Go! {{pokemonName}}!", + "trainerGo": "{{trainerName}} sent out {{pokemonName}}!", + "switchQuestion": "Will you switch\n{{pokemonName}}?", + "trainerDefeated": "You defeated\n{{trainerName}}!", + "moneyWon": "You got\n₽{{moneyAmount}} for winning!", + "moneyPickedUp": "You picked up ₽{{moneyAmount}}!", + "pokemonCaught": "{{pokemonName}} was caught!", + "addedAsAStarter": "{{pokemonName}} has been\nadded as a starter!", + "partyFull": "Your party is full.\nRelease a Pokémon to make room for {{pokemonName}}?", + "pokemon": "Pokémon", + "sendOutPokemon": "Go! {{pokemonName}}!", + "hitResultCriticalHit": "A critical hit!", + "hitResultSuperEffective": "It's super effective!", + "hitResultNotVeryEffective": "It's not very effective…", + "hitResultNoEffect": "It doesn't affect {{pokemonName}}!", + "hitResultOneHitKO": "It's a one-hit KO!", + "attackFailed": "But it failed!", + "attackMissed": "{{pokemonNameWithAffix}} avoided the attack!", + "attackHitsCount": "Hit {{count}} time(s)!", + "rewardGain": "You received\n{{modifierName}}!", + "expGain": "{{pokemonName}} gained\n{{exp}} EXP. Points!", + "levelUp": "{{pokemonName}} grew to\nLv. {{level}}!", + "learnMove": "{{pokemonName}} learned\n{{moveName}}!", + "learnMovePrompt": "{{pokemonName}} wants to learn the\nmove {{moveName}}.", + "learnMoveLimitReached": "However, {{pokemonName}} already\nknows four moves.", + "learnMoveReplaceQuestion": "Should a move be forgotten and\nreplaced with {{moveName}}?", + "learnMoveStopTeaching": "Stop trying to teach\n{{moveName}}?", + "learnMoveNotLearned": "{{pokemonName}} did not learn the\nmove {{moveName}}.", + "learnMoveForgetQuestion": "Which move should be forgotten?", + "learnMoveForgetSuccess": "{{pokemonName}} forgot how to\nuse {{moveName}}.", + "countdownPoof": "@d{32}1, @d{15}2, and@d{15}… @d{15}… @d{15}… @d{15}@s{pb_bounce_1}Poof!", + "learnMoveAnd": "And…", + "levelCapUp": "The level cap\nhas increased to {{levelCap}}!", + "moveNotImplemented": "{{moveName}} is not yet implemented and cannot be selected.", + "moveNoPP": "There's no PP left for\nthis move!", + "moveDisabled": "{{moveName}} is disabled!", + "noPokeballForce": "An unseen force\nprevents using Poké Balls.", + "noPokeballTrainer": "You can't catch\nanother trainer's Pokémon!", + "noPokeballMulti": "You can only throw a Poké Ball\nwhen there is one Pokémon remaining!", + "noPokeballStrong": "The target Pokémon is too strong to be caught!\nYou need to weaken it first!", + "noEscapeForce": "An unseen force\nprevents escape.", + "noEscapeTrainer": "You can't run\nfrom a trainer battle!", + "noEscapePokemon": "{{pokemonName}}'s {{moveName}}\nprevents {{escapeVerb}}!", + "runAwaySuccess": "You got away safely!", + "runAwayCannotEscape": "You can't escape!", + "escapeVerbSwitch": "switching", + "escapeVerbFlee": "fleeing", + "notDisabled": "{{pokemonName}}'s {{moveName}} is disabled\nno more!", + "turnEndHpRestore": "{{pokemonName}}'s HP was restored.", + "hpIsFull": "{{pokemonName}}'s\nHP is full!", + "skipItemQuestion": "Are you sure you want to skip taking an item?", + "eggHatching": "Oh?", + "ivScannerUseQuestion": "Use IV Scanner on {{pokemonName}}?", + "wildPokemonWithAffix": "Wild {{pokemonName}}", + "foePokemonWithAffix": "Foe {{pokemonName}}", + "useMove": "{{pokemonNameWithAffix}} used {{moveName}}!", + "drainMessage": "{{pokemonName}} had its\nenergy drained!", + "regainHealth": "{{pokemonName}} regained\nhealth!", + "stealEatBerry": "{{pokemonName}} stole and ate\n{{targetName}}'s {{berryName}}!", + "ppHealBerry": "{{pokemonNameWithAffix}} restored PP to its move {{moveName}}\nusing its {{berryName}}!", + "hpHealBerry": "{{pokemonNameWithAffix}} restored its health using\nits {{berryName}}!", + "fainted": "{{pokemonNameWithAffix}} fainted!", + "statsAnd": "and", + "stats": "Stats", + "statRose_one": "{{pokemonNameWithAffix}}'s {{stats}} rose!", + "statRose_other": "{{pokemonNameWithAffix}}'s {{stats}} rose!", + "statSharplyRose_one": "{{pokemonNameWithAffix}}'s {{stats}} sharply rose!", + "statSharplyRose_other": "{{pokemonNameWithAffix}}'s {{stats}} sharply rose!", + "statRoseDrastically_one": "{{pokemonNameWithAffix}}'s {{stats}} rose drastically!", + "statRoseDrastically_other": "{{pokemonNameWithAffix}}'s {{stats}} rose drastically!", + "statWontGoAnyHigher_one": "{{pokemonNameWithAffix}}'s {{stats}} won't go any higher!", + "statWontGoAnyHigher_other": "{{pokemonNameWithAffix}}'s {{stats}} won't go any higher!", + "statFell_one": "{{pokemonNameWithAffix}}'s {{stats}} fell!", + "statFell_other": "{{pokemonNameWithAffix}}'s {{stats}} fell!", + "statHarshlyFell_one": "{{pokemonNameWithAffix}}'s {{stats}} harshly fell!", + "statHarshlyFell_other": "{{pokemonNameWithAffix}}'s {{stats}} harshly fell!", + "statSeverelyFell_one": "{{pokemonNameWithAffix}}'s {{stats}} severely fell!", + "statSeverelyFell_other": "{{pokemonNameWithAffix}}'s {{stats}} severely fell!", + "statWontGoAnyLower_one": "{{pokemonNameWithAffix}}'s {{stats}} won't go any lower!", + "statWontGoAnyLower_other": "{{pokemonNameWithAffix}}'s {{stats}} won't go any lower!", + "transformedIntoType": "{{pokemonName}} transformed\ninto the {{type}} type!", + "retryBattle": "Would you like to retry from the start of the battle?", + "unlockedSomething": "{{unlockedThing}}\nhas been unlocked.", + "congratulations": "Congratulations!", + "beatModeFirstTime": "{{speciesName}} beat {{gameMode}} Mode for the first time!\nYou received {{newModifier}}!", + "ppReduced": "It reduced the PP of {{targetName}}'s\n{{moveName}} by {{reduction}}!", + "battlerTagsRechargingLapse": "{{pokemonNameWithAffix}} must\nrecharge!", + "battlerTagsTrappedOnAdd": "{{pokemonNameWithAffix}} can no\nlonger escape!", + "battlerTagsTrappedOnRemove": "{{pokemonNameWithAffix}} was freed\nfrom {{moveName}}!", + "battlerTagsFlinchedLapse": "{{pokemonNameWithAffix}} flinched!", + "battlerTagsConfusedOnAdd": "{{pokemonNameWithAffix}} became\nconfused!", + "battlerTagsConfusedOnRemove": "{{pokemonNameWithAffix}} snapped\nout of confusion!", + "battlerTagsConfusedOnOverlap": "{{pokemonNameWithAffix}} is\nalready confused!", + "battlerTagsConfusedLapse": "{{pokemonNameWithAffix}} is\nconfused!", + "battlerTagsConfusedLapseHurtItself": "It hurt itself in its\nconfusion!", + "battlerTagsDestinyBondLapseIsBoss": "{{pokemonNameWithAffix}} is unaffected\nby the effects of Destiny Bond.", + "battlerTagsDestinyBondLapse": "{{pokemonNameWithAffix}} took\n{{pokemonNameWithAffix2}} down with it!", + "battlerTagsInfatuatedOnAdd": "{{pokemonNameWithAffix}} fell in love\nwith {{sourcePokemonName}}!", + "battlerTagsInfatuatedOnOverlap": "{{pokemonNameWithAffix}} is\nalready in love!", + "battlerTagsInfatuatedLapse": "{{pokemonNameWithAffix}} is in love\nwith {{sourcePokemonName}}!", + "battlerTagsInfatuatedLapseImmobilize": "{{pokemonNameWithAffix}} is\nimmobilized by love!", + "battlerTagsInfatuatedOnRemove": "{{pokemonNameWithAffix}} got over\nits infatuation.", + "battlerTagsSeededOnAdd": "{{pokemonNameWithAffix}} was seeded!", + "battlerTagsSeededLapse": "{{pokemonNameWithAffix}}'s health is\nsapped by Leech Seed!", + "battlerTagsSeededLapseShed": "{{pokemonNameWithAffix}}'s Leech Seed\nsucked up the liquid ooze!", + "battlerTagsNightmareOnAdd": "{{pokemonNameWithAffix}} began\nhaving a Nightmare!", + "battlerTagsNightmareOnOverlap": "{{pokemonNameWithAffix}} is\nalready locked in a Nightmare!", + "battlerTagsNightmareLapse": "{{pokemonNameWithAffix}} is locked\nin a Nightmare!", + "battlerTagsEncoreOnAdd": "{{pokemonNameWithAffix}} got\nan Encore!", + "battlerTagsEncoreOnRemove": "{{pokemonNameWithAffix}}'s Encore\nended!", + "battlerTagsHelpingHandOnAdd": "{{pokemonNameWithAffix}} is ready to\nhelp {{pokemonName}}!", + "battlerTagsIngrainLapse": "{{pokemonNameWithAffix}} absorbed\nnutrients with its roots!", + "battlerTagsIngrainOnTrap": "{{pokemonNameWithAffix}} planted its roots!", + "battlerTagsAquaRingOnAdd": "{{pokemonNameWithAffix}} surrounded\nitself with a veil of water!", + "battlerTagsAquaRingLapse": "{{moveName}} restored\n{{pokemonName}}'s HP!", + "battlerTagsDrowsyOnAdd": "{{pokemonNameWithAffix}} grew drowsy!", + "battlerTagsDamagingTrapLapse": "{{pokemonNameWithAffix}} is hurt\nby {{moveName}}!", + "battlerTagsBindOnTrap": "{{pokemonNameWithAffix}} was squeezed by\n{{sourcePokemonName}}'s {{moveName}}!", + "battlerTagsWrapOnTrap": "{{pokemonNameWithAffix}} was Wrapped\nby {{sourcePokemonName}}!", + "battlerTagsVortexOnTrap": "{{pokemonNameWithAffix}} was trapped\nin the vortex!", + "battlerTagsClampOnTrap": "{{sourcePokemonNameWithAffix}} Clamped\n{{pokemonName}}!", + "battlerTagsSandTombOnTrap": "{{pokemonNameWithAffix}} became trapped\nby {{moveName}}!", + "battlerTagsMagmaStormOnTrap": "{{pokemonNameWithAffix}} became trapped\nby swirling magma!", + "battlerTagsSnapTrapOnTrap": "{{pokemonNameWithAffix}} got trapped\nby a snap trap!", + "battlerTagsThunderCageOnTrap": "{{sourcePokemonNameWithAffix}} trapped\n{{pokemonNameWithAffix}}!", + "battlerTagsInfestationOnTrap": "{{pokemonNameWithAffix}} has been afflicted \nwith an infestation by {{sourcePokemonNameWithAffix}}!", + "battlerTagsProtectedOnAdd": "{{pokemonNameWithAffix}}\nprotected itself!", + "battlerTagsProtectedLapse": "{{pokemonNameWithAffix}}\nprotected itself!", + "battlerTagsEnduringOnAdd": "{{pokemonNameWithAffix}} braced\nitself!", + "battlerTagsEnduringLapse": "{{pokemonNameWithAffix}} endured\nthe hit!", + "battlerTagsSturdyLapse": "{{pokemonNameWithAffix}} endured\nthe hit!", + "battlerTagsPerishSongLapse": "{{pokemonNameWithAffix}}'s perish count fell to {{turnCount}}.", + "battlerTagsCenterOfAttentionOnAdd": "{{pokemonNameWithAffix}} became the center\nof attention!", + "battlerTagsTruantLapse": "{{pokemonNameWithAffix}} is\nloafing around!", + "battlerTagsSlowStartOnAdd": "{{pokemonNameWithAffix}} can't\nget it going!", + "battlerTagsSlowStartOnRemove": "{{pokemonNameWithAffix}} finally\ngot its act together!", + "battlerTagsHighestStatBoostOnAdd": "{{pokemonNameWithAffix}}'s {{statName}}\nwas heightened!", + "battlerTagsHighestStatBoostOnRemove": "The effects of {{pokemonNameWithAffix}}'s\n{{abilityName}} wore off!", + "battlerTagsMagnetRisenOnAdd": "{{pokemonNameWithAffix}} levitated with electromagnetism!", + "battlerTagsMagnetRisenOnRemove": "{{pokemonNameWithAffix}}'s electromagnetism wore off!", + "battlerTagsCritBoostOnAdd": "{{pokemonNameWithAffix}} is getting\npumped!", + "battlerTagsCritBoostOnRemove": "{{pokemonNameWithAffix}} relaxed.", + "battlerTagsSaltCuredOnAdd": "{{pokemonNameWithAffix}} is being salt cured!", + "battlerTagsSaltCuredLapse": "{{pokemonNameWithAffix}} is hurt by {{moveName}}!", + "battlerTagsCursedOnAdd": "{{pokemonNameWithAffix}} cut its own HP and put a curse on the {{pokemonName}}!", + "battlerTagsCursedLapse": "{{pokemonNameWithAffix}} is afflicted by the Curse!", + "battlerTagsStockpilingOnAdd": "{{pokemonNameWithAffix}} stockpiled {{stockpiledCount}}!" +} as const; diff --git a/src/locales/ca-ES/battler-tags.ts b/src/locales/ca-ES/battler-tags.ts new file mode 100644 index 00000000000..1d897c70f3d --- /dev/null +++ b/src/locales/ca-ES/battler-tags.ts @@ -0,0 +1,12 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +export const battlerTags: SimpleTranslationEntries = { + "trappedDesc": "trapping", + "flinchedDesc": "flinching", + "confusedDesc": "confusion", + "infatuatedDesc": "infatuation", + "seedDesc": "seeding", + "nightmareDesc": "nightmares", + "ingrainDesc": "roots", + "drowsyDesc": "drowsiness", +} as const; diff --git a/src/locales/ca-ES/berry.ts b/src/locales/ca-ES/berry.ts new file mode 100644 index 00000000000..3c4930b1591 --- /dev/null +++ b/src/locales/ca-ES/berry.ts @@ -0,0 +1,48 @@ +import { BerryTranslationEntries } from "#app/interfaces/locales"; + +export const berry: BerryTranslationEntries = { + "SITRUS": { + name: "Sitrus Berry", + effect: "Restores 25% HP if HP is below 50%", + }, + "LUM": { + name: "Lum Berry", + effect: "Cures any non-volatile status condition and confusion", + }, + "ENIGMA": { + name: "Enigma Berry", + effect: "Restores 25% HP if hit by a super effective move", + }, + "LIECHI": { + name: "Liechi Berry", + effect: "Raises Attack if HP is below 25%", + }, + "GANLON": { + name: "Ganlon Berry", + effect: "Raises Defense if HP is below 25%", + }, + "PETAYA": { + name: "Petaya Berry", + effect: "Raises Sp. Atk if HP is below 25%", + }, + "APICOT": { + name: "Apicot Berry", + effect: "Raises Sp. Def if HP is below 25%", + }, + "SALAC": { + name: "Salac Berry", + effect: "Raises Speed if HP is below 25%", + }, + "LANSAT": { + name: "Lansat Berry", + effect: "Raises critical hit ratio if HP is below 25%", + }, + "STARF": { + name: "Starf Berry", + effect: "Sharply raises a random stat if HP is below 25%", + }, + "LEPPA": { + name: "Leppa Berry", + effect: "Restores 10 PP to a move if its PP reaches 0", + }, +} as const; diff --git a/src/locales/ca-ES/bgm-name.ts b/src/locales/ca-ES/bgm-name.ts new file mode 100644 index 00000000000..be9a8f621c7 --- /dev/null +++ b/src/locales/ca-ES/bgm-name.ts @@ -0,0 +1,146 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +export const bgmName: SimpleTranslationEntries = { + "music": "Music: ", + "missing_entries" : "{{name}}", + "battle_kanto_champion": "B2W2 Kanto Champion Battle", + "battle_johto_champion": "B2W2 Johto Champion Battle", + "battle_hoenn_champion_g5": "B2W2 Hoenn Champion Battle", + "battle_hoenn_champion_g6": "ORAS Hoenn Champion Battle", + "battle_sinnoh_champion": "B2W2 Sinnoh Champion Battle", + "battle_champion_alder": "BW Unova Champion Battle", + "battle_champion_iris": "B2W2 Unova Champion Battle", + "battle_kalos_champion": "XY Kalos Champion Battle", + "battle_alola_champion": "USUM Alola Champion Battle", + "battle_galar_champion": "SWSH Galar Champion Battle", + "battle_champion_geeta": "SV Champion Geeta Battle", + "battle_champion_nemona": "SV Champion Nemona Battle", + "battle_champion_kieran": "SV Champion Kieran Battle", + "battle_hoenn_elite": "ORAS Elite Four Battle", + "battle_unova_elite": "BW Elite Four Battle", + "battle_kalos_elite": "XY Elite Four Battle", + "battle_alola_elite": "SM Elite Four Battle", + "battle_galar_elite": "SWSH League Tournament Battle", + "battle_paldea_elite": "SV Elite Four Battle", + "battle_bb_elite": "SV BB League Elite Four Battle", + "battle_final_encounter": "PMD RTDX Rayquaza's Domain", + "battle_final": "BW Ghetsis Battle", + "battle_kanto_gym": "B2W2 Kanto Gym Battle", + "battle_johto_gym": "B2W2 Johto Gym Battle", + "battle_hoenn_gym": "B2W2 Hoenn Gym Battle", + "battle_sinnoh_gym": "B2W2 Sinnoh Gym Battle", + "battle_unova_gym": "BW Unova Gym Battle", + "battle_kalos_gym": "XY Kalos Gym Battle", + "battle_galar_gym": "SWSH Galar Gym Battle", + "battle_paldea_gym": "SV Paldea Gym Battle", + "battle_legendary_kanto": "XY Kanto Legendary Battle", + "battle_legendary_raikou": "HGSS Raikou Battle", + "battle_legendary_entei": "HGSS Entei Battle", + "battle_legendary_suicune": "HGSS Suicune Battle", + "battle_legendary_lugia": "HGSS Lugia Battle", + "battle_legendary_ho_oh": "HGSS Ho-oh Battle", + "battle_legendary_regis_g5": "B2W2 Legendary Titan Battle", + "battle_legendary_regis_g6": "ORAS Legendary Titan Battle", + "battle_legendary_gro_kyo": "ORAS Groudon & Kyogre Battle", + "battle_legendary_rayquaza": "ORAS Rayquaza Battle", + "battle_legendary_deoxys": "ORAS Deoxys Battle", + "battle_legendary_lake_trio": "ORAS Lake Guardians Battle", + "battle_legendary_sinnoh": "ORAS Sinnoh Legendary Battle", + "battle_legendary_dia_pal": "ORAS Dialga & Palkia Battle", + "battle_legendary_giratina": "ORAS Giratina Battle", + "battle_legendary_arceus": "HGSS Arceus Battle", + "battle_legendary_unova": "BW Unova Legendary Battle", + "battle_legendary_kyurem": "BW Kyurem Battle", + "battle_legendary_res_zek": "BW Reshiram & Zekrom Battle", + "battle_legendary_xern_yvel": "XY Xerneas & Yveltal Battle", + "battle_legendary_tapu": "SM Tapu Battle", + "battle_legendary_sol_lun": "SM Solgaleo & Lunala Battle", + "battle_legendary_ub": "SM Ultra Beast Battle", + "battle_legendary_dusk_dawn": "USUM Dusk Mane & Dawn Wings Necrozma Battle", + "battle_legendary_ultra_nec": "USUM Ultra Necrozma Battle", + "battle_legendary_zac_zam": "SWSH Zacian & Zamazenta Battle", + "battle_legendary_glas_spec": "SWSH Glastrier & Spectrier Battle", + "battle_legendary_calyrex": "SWSH Calyrex Battle", + "battle_legendary_birds_galar": "SWSH Galarian Legendary Birds Battle", + "battle_legendary_ruinous": "SV Treasures of Ruin Battle", + "battle_legendary_kor_mir": "SV Depths of Area Zero Battle", + "battle_legendary_loyal_three": "SV Loyal Three Battle", + "battle_legendary_ogerpon": "SV Ogerpon Battle", + "battle_legendary_terapagos": "SV Terapagos Battle", + "battle_legendary_pecharunt": "SV Pecharunt Battle", + "battle_rival": "BW Rival Battle", + "battle_rival_2": "BW N Battle", + "battle_rival_3": "BW Final N Battle", + "battle_trainer": "BW Trainer Battle", + "battle_wild": "BW Wild Battle", + "battle_wild_strong": "BW Strong Wild Battle", + "end_summit": "PMD RTDX Sky Tower Summit", + "battle_rocket_grunt": "HGSS Team Rocket Battle", + "battle_aqua_magma_grunt": "ORAS Team Aqua & Magma Battle", + "battle_galactic_grunt": "BDSP Team Galactic Battle", + "battle_plasma_grunt": "BW Team Plasma Battle", + "battle_flare_grunt": "XY Team Flare Battle", + "battle_rocket_boss": "USUM Giovanni Battle", + "battle_aqua_magma_boss": "ORAS Archie & Maxie Battle", + "battle_galactic_boss": "BDSP Cyrus Battle", + "battle_plasma_boss": "B2W2 Ghetsis Battle", + "battle_flare_boss": "XY Lysandre Battle", + + // Biome Music + "abyss": "PMD EoS Dark Crater", + "badlands": "PMD EoS Barren Valley", + "beach": "PMD EoS Drenched Bluff", + "cave": "PMD EoS Sky Peak Cave", + "construction_site": "PMD EoS Boulder Quarry", + "desert": "PMD EoS Northern Desert", + "dojo": "PMD EoS Marowak Dojo", + "end": "PMD RTDX Sky Tower", + "factory": "PMD EoS Concealed Ruins", + "fairy_cave": "PMD EoS Star Cave", + "forest": "PMD EoS Dusk Forest", + "grass": "PMD EoS Apple Woods", + "graveyard": "PMD EoS Mystifying Forest", + "ice_cave": "PMD EoS Vast Ice Mountain", + "island": "PMD EoS Craggy Coast", + "jungle": "Lmz - Jungle", // The composer thinks about a more creative name + "laboratory": "Firel - Laboratory", // The composer thinks about a more creative name + "lake": "PMD EoS Crystal Cave", + "meadow": "PMD EoS Sky Peak Forest", + "metropolis": "Firel - Metropolis", // The composer thinks about a more creative name + "mountain": "PMD EoS Mt. Horn", + "plains": "PMD EoS Sky Peak Prairie", + "power_plant": "PMD EoS Far Amp Plains", + "ruins": "PMD EoS Deep Sealed Ruin", + "sea": "Andr06 - Marine Mystique", // Name defined by the composer + "seabed": "Firel - Seabed", // The composer thinks about a more creative name + "slum": "Andr06 - Sneaky Snom", // Name defined by the composer + "snowy_forest": "PMD EoS Sky Peak Snowfield", + "space": "Firel - Aether", + "swamp": "PMD EoS Surrounded Sea", + "tall_grass": "PMD EoS Foggy Forest", + "temple": "PMD EoS Aegis Cave", + "town": "PMD EoS Random Dungeon Theme 3", + "volcano": "PMD EoS Steam Cave", + "wasteland": "PMD EoS Hidden Highland", + + // Encounter + "encounter_ace_trainer": "BW Trainers' Eyes Meet (Ace Trainer)", + "encounter_backpacker": "BW Trainers' Eyes Meet (Backpacker)", + "encounter_clerk": "BW Trainers' Eyes Meet (Clerk)", + "encounter_cyclist": "BW Trainers' Eyes Meet (Cyclist)", + "encounter_lass": "BW Trainers' Eyes Meet (Lass)", + "encounter_parasol_lady": "BW Trainers' Eyes Meet (Parasol Lady)", + "encounter_pokefan": "BW Trainers' Eyes Meet (Poke Fan)", + "encounter_psychic": "BW Trainers' Eyes Meet (Psychic)", + "encounter_rich": "BW Trainers' Eyes Meet (Gentleman)", + "encounter_rival": "BW Cheren", + "encounter_roughneck": "BW Trainers' Eyes Meet (Roughneck)", + "encounter_scientist": "BW Trainers' Eyes Meet (Scientist)", + "encounter_twins": "BW Trainers' Eyes Meet (Twins)", + "encounter_youngster": "BW Trainers' Eyes Meet (Youngster)", + + // Other + "heal": "BW Pokémon Heal", + "menu": "PMD EoS Welcome to the World of Pokémon!", + "title": "PMD EoS Top Menu Theme", +} as const; diff --git a/src/locales/ca-ES/biome.ts b/src/locales/ca-ES/biome.ts new file mode 100644 index 00000000000..d3f34c021d4 --- /dev/null +++ b/src/locales/ca-ES/biome.ts @@ -0,0 +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", + "END": "???", +} as const; diff --git a/src/locales/ca-ES/challenges.ts b/src/locales/ca-ES/challenges.ts new file mode 100644 index 00000000000..e3302876201 --- /dev/null +++ b/src/locales/ca-ES/challenges.ts @@ -0,0 +1,32 @@ +import { TranslationEntries } from "#app/interfaces/locales.js"; + +export const challenges: TranslationEntries = { + "title": "Challenge Modifiers", + "illegalEvolution": "{{pokemon}} changed into an ineligble pokémon\nfor this challenge!", + "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", + }, + "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." + //types in pokemon-info + }, + "freshStart": { + "name": "Fresh Start", + "desc": "You can only use the original starters, and only as if you had just started PokéRogue.", + "value.0": "Off", + "value.1": "On", + } +} as const; diff --git a/src/locales/ca-ES/command-ui-handler.ts b/src/locales/ca-ES/command-ui-handler.ts new file mode 100644 index 00000000000..c4c65db0aa0 --- /dev/null +++ b/src/locales/ca-ES/command-ui-handler.ts @@ -0,0 +1,9 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +export const commandUiHandler: SimpleTranslationEntries = { + "fight": "Fight", + "ball": "Ball", + "pokemon": "Pokémon", + "run": "Run", + "actionMessage": "What will\n{{pokemonName}} do?", +} as const; diff --git a/src/locales/ca-ES/common.ts b/src/locales/ca-ES/common.ts new file mode 100644 index 00000000000..750322e1f09 --- /dev/null +++ b/src/locales/ca-ES/common.ts @@ -0,0 +1,10 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +export const common: SimpleTranslationEntries = { + "start": "Start", + "luckIndicator": "Luck:", + "shinyOnHover": "Shiny", + "commonShiny": "Common", + "rareShiny": "Rare", + "epicShiny": "Epic", +} as const; diff --git a/src/locales/ca-ES/config.ts b/src/locales/ca-ES/config.ts new file mode 100644 index 00000000000..831ab5d99f5 --- /dev/null +++ b/src/locales/ca-ES/config.ts @@ -0,0 +1,116 @@ +import { common } from "./common.js"; +import { settings } from "./settings.js"; +import { ability } from "./ability"; +import { abilityTriggers } from "./ability-trigger"; +import { arenaFlyout } from "./arena-flyout"; +import { arenaTag } from "./arena-tag"; +import { PGFachv, PGMachv } from "./achv"; +import { battle } from "./battle"; +import { battleInfo } from "./battle-info"; +import { battleMessageUiHandler } from "./battle-message-ui-handler"; +import { battlerTags } from "./battler-tags"; +import { berry } from "./berry"; +import { bgmName } from "./bgm-name"; +import { biome } from "./biome"; +import { challenges } from "./challenges"; +import { commandUiHandler } from "./command-ui-handler"; +import { + PGFbattleSpecDialogue, + PGFdialogue, + PGFdoubleBattleDialogue, + PGFmiscDialogue, + PGMbattleSpecDialogue, + PGMdialogue, + PGMdoubleBattleDialogue, + PGMmiscDialogue +} from "./dialogue"; +import { egg } from "./egg"; +import { fightUiHandler } from "./fight-ui-handler"; +import { filterBar } from "./filter-bar"; +import { gameMode } from "./game-mode"; +import { gameStatsUiHandler } from "./game-stats-ui-handler"; +import { growth } from "./growth"; +import { menu } from "./menu"; +import { menuUiHandler } from "./menu-ui-handler"; +import { modifier } from "./modifier"; +import { modifierType } from "./modifier-type"; +import { move } from "./move"; +import { nature } from "./nature"; +import { partyUiHandler } from "./party-ui-handler"; +import { pokeball } from "./pokeball"; +import { pokemon } from "./pokemon"; +import { pokemonForm, battlePokemonForm } from "./pokemon-form"; +import { pokemonInfo } from "./pokemon-info"; +import { pokemonInfoContainer } from "./pokemon-info-container"; +import { pokemonSummary } from "./pokemon-summary"; +import { saveSlotSelectUiHandler } from "./save-slot-select-ui-handler"; +import { splashMessages } from "./splash-messages"; +import { starterSelectUiHandler } from "./starter-select-ui-handler"; +import { statusEffect } from "./status-effect"; +import { titles, trainerClasses, trainerNames } from "./trainers"; +import { tutorial } from "./tutorial"; +import { voucher } from "./voucher"; +import { terrain, weather } from "./weather"; +import { modifierSelectUiHandler } from "./modifier-select-ui-handler"; +import { moveTriggers } from "./move-trigger"; + +export const caESConfig = { + ability: ability, + abilityTriggers: abilityTriggers, + arenaFlyout: arenaFlyout, + arenaTag: arenaTag, + battle: battle, + battleInfo: battleInfo, + battleMessageUiHandler: battleMessageUiHandler, + battlePokemonForm: battlePokemonForm, + battlerTags: battlerTags, + berry: berry, + bgmName: bgmName, + biome: biome, + challenges: challenges, + commandUiHandler: commandUiHandler, + common: common, + PGMachv: PGMachv, + PGFachv: PGFachv, + PGMdialogue: PGMdialogue, + PGFdialogue: PGFdialogue, + PGMbattleSpecDialogue: PGMbattleSpecDialogue, + PGFbattleSpecDialogue: PGFbattleSpecDialogue, + PGMmiscDialogue: PGMmiscDialogue, + PGFmiscDialogue: PGFmiscDialogue, + PGMdoubleBattleDialogue: PGMdoubleBattleDialogue, + PGFdoubleBattleDialogue: PGFdoubleBattleDialogue, + egg: egg, + fightUiHandler: fightUiHandler, + filterBar: filterBar, + gameMode: gameMode, + gameStatsUiHandler: gameStatsUiHandler, + growth: growth, + menu: menu, + menuUiHandler: menuUiHandler, + modifier: modifier, + modifierType: modifierType, + move: move, + nature: nature, + pokeball: pokeball, + pokemon: pokemon, + pokemonForm: pokemonForm, + pokemonInfo: pokemonInfo, + pokemonInfoContainer: pokemonInfoContainer, + pokemonSummary: pokemonSummary, + saveSlotSelectUiHandler: saveSlotSelectUiHandler, + settings: settings, + splashMessages: splashMessages, + starterSelectUiHandler: starterSelectUiHandler, + statusEffect: statusEffect, + terrain: terrain, + titles: titles, + trainerClasses: trainerClasses, + trainerNames: trainerNames, + tutorial: tutorial, + voucher: voucher, + weather: weather, + partyUiHandler: partyUiHandler, + modifierSelectUiHandler: modifierSelectUiHandler, + moveTriggers: moveTriggers +}; diff --git a/src/locales/ca-ES/dialogue.ts b/src/locales/ca-ES/dialogue.ts new file mode 100644 index 00000000000..44693c38aa1 --- /dev/null +++ b/src/locales/ca-ES/dialogue.ts @@ -0,0 +1,2746 @@ +import { DialogueTranslationEntries, SimpleTranslationEntries } from "#app/interfaces/locales"; + +// Dialogue of the NPCs in the game when the player character is male (or unset) +export const PGMdialogue: DialogueTranslationEntries = { + "youngster": { + "encounter": { + 1: "Hey, wanna battle?", + 2: "Are you a new trainer too?", + 3: "Hey, I haven't seen you before. Let's battle!", + 4: "I just lost, so I'm trying to find more Pokémon.\nWait! You look weak! Come on, let's battle!", + 5: "Have we met or not? I don't really remember. Well, I guess it's nice to meet you anyway!", + 6: "All right! Let's go!", + 7: "All right! Here I come! I'll show you my power!", + 8: "Haw haw haw... I'll show you how hawesome my Pokémon are!", + 9: "No need to waste time saying hello. Bring it on whenever you're ready!", + 10: "Don't let your guard down, or you may be crying when a kid beats you.", + 11: "I've raised my Pokémon with great care. You're not allowed to hurt them!", + 12: "Glad you made it! It won't be an easy job from here.", + 13: "The battles continue forever! Welcome to the world with no end!" + }, + "victory": { + 1: "Wow! You're strong!", + 2: "I didn't stand a chance, huh?", + 3: "I'll find you again when I'm older and beat you!", + 4: "Ugh. I don't have any more Pokémon.", + 5: "No way… NO WAY! How could I lose again…", + 6: "No! I lost!", + 7: "Whoa! You are incredible! I'm amazed and surprised!", + 8: "Could it be… How… My Pokémon and I are the strongest, though…", + 9: "I won't lose next time! Let's battle again sometime!", + 10: "Sheesh! Can't you see that I'm just a kid! It wasn't fair of you to go all out like that!", + 11: "Your Pokémon are more amazing! Trade with me!", + 12: "I got a little carried away earlier, but what job was I talking about?", + 13: "Ahaha! There it is! That's right! You're already right at home in this world!" + } + }, + "lass": { + "encounter": { + 1: "Let's have a battle, shall we?", + 2: "You look like a new trainer. Let's have a battle!", + 3: "I don't recognize you. How about a battle?", + 4: "Let's have a fun Pokémon battle!", + 5: "I'll show you the ropes of how to really use Pokémon!", + 6: "A serious battle starts from a serious beginning! Are you sure you're ready?", + 7: "You're only young once. And you only get one shot at a given battle. Soon, you'll be nothing but a memory.", + 8: "You'd better go easy on me, OK? Though I'll be seriously fighting!", + 9: "School is boring. I've got nothing to do. Yawn. I'm only battling to kill the time." + }, + "victory": { + 1: "That was impressive! I've got a lot to learn.", + 2: "I didn't think you'd beat me that bad…", + 3: "I hope we get to have a rematch some day.", + 4: "That was pretty amazingly fun! You've totally exhausted me…", + 5: "You actually taught me a lesson! You're pretty amazing!", + 6: "Seriously, I lost. That is, like, seriously depressing, but you were seriously cool.", + 7: "I don't need memories like this. Deleting memory…", + 8: "Hey! I told you to go easy on me! Still, you're pretty cool when you're serious.", + 9: "I'm actually getting tired of battling… There's gotta be something new to do…" + } + }, + "breeder": { + "encounter": { + 1: "Obedient Pokémon, selfish Pokémon… Pokémon have unique characteristics.", + 2: "Even though my upbringing and behavior are poor, I've raised my Pokémon well.", + 3: "Hmm, do you discipline your Pokémon? Pampering them too much is no good.", + }, + "victory": { + 1: "It is important to nurture and train each Pokémon's characteristics.", + 2: "Unlike my diabolical self, these are some good Pokémon.", + 3: "Too much praise can spoil both Pokémon and people.", + }, + "defeat": { + 1: "You should not get angry at your Pokémon, even if you lose a battle.", + 2: "Right? Pretty good Pokémon, huh? I'm suited to raising things.", + 3: "No matter how much you love your Pokémon, you still have to discipline them when they misbehave." + } + }, + "breeder_female": { + "encounter": { + 1: "Pokémon never betray you. They return all the love you give them.", + 2: "Shall I give you a tip for training good Pokémon?", + 3: "I have raised these very special Pokémon using a special method." + }, + "victory": { + 1: "Ugh… It wasn't supposed to be like this. Did I administer the wrong blend?", + 2: "How could that happen to my Pokémon… What are you feeding your Pokémon?", + 3: "If I lose, that tells you I was just killing time. It doesn't damage my ego at all." + }, + "defeat": { + 1: "This proves my Pokémon have accepted my love.", + 2: "The real trick behind training good Pokémon is catching good Pokémon.", + 3: "Pokémon will be strong or weak depending on how you raise them." + } + }, + "fisherman": { + "encounter": { + 1: "Aack! You made me lose a bite!\nWhat are you going to do about it?", + 2: "Go away! You're scaring the Pokémon!", + 3: "Let's see if you can reel in a victory!", + }, + "victory": { + 1: "Just forget about it.", + 2: "Next time, I'll be reelin' in the triumph!", + 3: "Guess I underestimated the currents this time.", + }, + }, + "fisherman_female": { + "encounter": { + 1: "Woah! I've hooked a big one!", + 2: "Line's in, ready to reel in success!", + 3: "Ready to make waves!" + }, + "victory": { + 1: "I'll be back with a stronger hook.", + 2: "I'll reel in victory next time.", + 3: "I'm just sharpening my hooks for the comeback!" + }, + }, + "swimmer": { + "encounter": { + 1: "Time to dive in!", + 2: "Let's ride the waves of victory!", + 3: "Ready to make a splash!", + }, + "victory": { + 1: "Drenched in defeat!", + 2: "A wave of defeat!", + 3: "Back to shore, I guess.", + }, + }, + "backpacker": { + "encounter": { + 1: "Pack up, game on!", + 2: "Let's see if you can keep pace!", + 3: "Gear up, challenger!", + 4: "I've spent 20 years trying to find myself… But where am I?" + }, + "victory": { + 1: "Tripped up this time!", + 2: "Oh, I think I'm lost.", + 3: "Dead end!", + 4: "Wait up a second! Hey! Don't you know who I am?" + }, + }, + "ace_trainer": { + "encounter": { + 1: "You seem quite confident.", + 2: "Your Pokémon… Show them to me…", + 3: "Because I'm an Ace Trainer, people think I'm strong.", + 4: "Are you aware of what it takes to be an Ace Trainer?" + }, + "victory": { + 1: "Yes… You have good Pokémon…", + 2: "What?! But I'm a battling genius!", + 3: "Of course, you are the main character!", + 4: "OK! OK! You could be an Ace Trainer!" + }, + "defeat": { + 1: "I am devoting my body and soul to Pokémon battles!", + 2: "All within my expectations… Nothing to be surprised about…", + 3: "I thought I'd grow up to be a frail person who looked like they would break if you squeezed them too hard.", + 4: "Of course I'm strong and don't lose. It's important that I win gracefully." + } + }, + "parasol_lady": { + "encounter": { + 1: "Time to grace the battlefield with elegance and poise!", + }, + "victory": { + 1: "My elegance remains unbroken!", + } + }, + "twins": { + "encounter": { + 1: "Get ready, because when we team up, it's double the trouble!", + 2: "Two hearts, one strategy – let's see if you can keep up with our twin power!", + 3: "Hope you're ready for double trouble, because we're about to bring the heat!" + }, + "victory": { + 1: "We may have lost this round, but our bond remains unbreakable!", + 2: "Our twin spirit won't be dimmed for long.", + 3: "We'll come back stronger as a dynamic duo!" + }, + "defeat": { + 1: "Twin power reigns supreme!", + 2: "Two hearts, one triumph!", + 3: "Double the smiles, double the victory dance!" + } + }, + "cyclist": { + "encounter": { + 1: "Get ready to eat my dust!", + 2: "Gear up, challenger! I'm about to leave you in the dust!", + 3: "Pedal to the metal, let's see if you can keep pace!" + }, + "victory": { + 1: "Spokes may be still, but determination pedals on.", + 2: "Outpaced!", + 3: "The road to victory has many twists and turns yet to explore." + }, + }, + "black_belt": { + "encounter": { + 1: "I praise your courage in challenging me! For I am the one with the strongest kick!", + 2: "Oh, I see. Would you like to be cut to pieces? Or do you prefer the role of punching bag?" + }, + "victory": { + 1: "Oh. The Pokémon did the fighting. My strong kick didn't help a bit.", + 2: "Hmmm… If I was going to lose anyway, I was hoping to get totally messed up in the process." + }, + }, + "battle_girl": { + "encounter": { + 1: "You don't have to try to impress me. You can lose against me.", + }, + "victory": { + 1: "It's hard to say good-bye, but we are running out of time…", + }, + }, + "hiker": { + "encounter": { + 1: "My middle-age spread has given me as much gravitas as the mountains I hike!", + 2: "I inherited this big-boned body from my parents… I'm like a living mountain range…", + }, + "victory": { + 1: "At least I cannot lose when it comes to BMI!", + 2: "It's not enough… It's never enough. My bad cholesterol isn't high enough…" + }, + }, + "ranger": { + "encounter": { + 1: "When I am surrounded by nature, most other things cease to matter.", + 2: "When I'm living without nature in my life, sometimes I'll suddenly feel an anxiety attack coming on." + }, + "victory": { + 1: "It doesn't matter to the vastness of nature whether I win or lose…", + 2: "Something like this is pretty trivial compared to the stifling feelings of city life." + }, + "defeat": { + 1: "I won the battle. But victory is nothing compared to the vastness of nature…", + 2: "I'm sure how you feel is not so bad if you compare it to my anxiety attacks…" + } + }, + "scientist": { + "encounter": { + 1: "My research will lead this world to peace and joy.", + }, + "victory": { + 1: "I am a genius… I am not supposed to lose against someone like you…", + }, + }, + "school_kid": { + "encounter": { + 1: "…Heehee. I'm confident in my calculations and analysis.", + 2: "I'm gaining as much experience as I can because I want to be a Gym Leader someday." + }, + "victory": { + 1: "Ohhhh… Calculation and analysis are perhaps no match for chance…", + 2: "Even difficult, trying experiences have their purpose, I suppose." + } + }, + "artist": { + "encounter": { + 1: "I used to be popular, but now I am all washed up.", + }, + "victory": { + 1: "As times change, values also change. I realized that too late.", + }, + }, + "guitarist": { + "encounter": { + 1: "Get ready to feel the rhythm of defeat as I strum my way to victory!", + }, + "victory": { + 1: "Silenced for now, but my melody of resilience will play on.", + }, + }, + "worker": { + "encounter": { + 1: "It bothers me that people always misunderstand me. I'm a lot more pure than everyone thinks.", + }, + "victory": { + 1: "I really don't want my skin to burn, so I want to stay in the shade while I work.", + }, + }, + "worker_female": { + "encounter": { + 1: `It bothers me that people always misunderstand me. + $I'm a lot more pure than everyone thinks.` + }, + "victory": { + 1: "I really don't want my skin to burn, so I want to stay in the shade while I work." + }, + "defeat": { + 1: "My body and mind aren't necessarily always in sync." + } + }, + "worker_double": { + "encounter": { + 1: "I'll show you we can break you. We've been training in the field!", + }, + "victory": { + 1: "How strange… How could this be… I shouldn't have been outmuscled.", + }, + }, + "hex_maniac": { + "encounter": { + 1: "I normally only ever listen to classical music, but if I lose, I think I shall try a bit of new age!", + 2: "I grow stronger with each tear I cry." + }, + "victory": { + 1: "Is this the dawning of the age of Aquarius?", + 2: "Now I can get even stronger. I grow with every grudge." + }, + "defeat": { + 1: "New age simply refers to twentieth century classical composers, right?", + 2: "Don't get hung up on sadness or frustration. You can use your grudges to motivate yourself." + } + }, + "psychic": { + "encounter": { + 1: "Hi! Focus!", + }, + "victory": { + 1: "Eeeeek!", + }, + }, + "officer": { + "encounter": { + 1: "Brace yourself, because justice is about to be served!", + 2: "Ready to uphold the law and serve justice on the battlefield!" + }, + "victory": { + 1: "The weight of justice feels heavier than ever…", + 2: "The shadows of defeat linger in the precinct." + } + }, + "beauty": { + "encounter": { + 1: "My last ever battle… That's the way I'd like us to view this match…", + }, + "victory": { + 1: "It's been fun… Let's have another last battle again someday…", + }, + }, + "baker": { + "encounter": { + 1: "Hope you're ready to taste defeat!" + }, + "victory": { + 1: "I'll bake a comeback." + }, + }, + "biker": { + "encounter": { + 1: "Time to rev up and leave you in the dust!" + }, + "victory": { + 1: "I'll tune up for the next race." + }, + }, + "firebreather": { + "encounter": { + 1: "My flames shall devour you!", + 2: "My soul is on fire. I'll show you how hot it burns!", + 3: "Step right up and take a look!" + }, + "victory": { + 1: "I burned down to ashes...", + 2: "Yow! That's hot!", + 3: "Ow! I scorched the tip of my nose!" + }, + }, + "sailor": { + "encounter": { + 1: "Matey, you're walking the plank if you lose!", + 2: "Come on then! My sailor's pride is at stake!", + 3: "Ahoy there! Are you seasick?" + }, + "victory": { + 1: "Argh! Beaten by a kid!", + 2: "Your spirit sank me!", + 3: "I think it's me that's seasick..." + }, + }, + "rocket_grunt": { + "encounter": { + 1: "Prepare for trouble!" + }, + "victory": { + 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!" + }, + "victory": { + 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!" + }, + "victory": { + 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!" + }, + "victory": { + 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!" + }, + "victory": { + 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!" + }, + "victory": { + 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!" + }, + "victory": { + 1: "WHAT! This cannot be!" + }, + "defeat": { + 1: "Mark my words. Not being able to measure your own strength shows that you are still a child." + } + }, + "rocket_boss_giovanni_2": { + "encounter": { + 1: "My old associates need me... Are you going to get in my way?" + }, + "victory": { + 1: "How is this possible...? The precious dream of Team Rocket has become little more than an illusion..." + }, + "defeat": { + 1: "Team Rocket will be reborn again, and I will rule the world!" + } + }, + "magma_boss_maxie_1": { + "encounter": { + 1: "I will bury you by my own hand. I hope you appreciate this honor!" + }, + "victory": { + 1: "Ugh! You are... quite capable...\nI fell behind, but only by an inch..." + }, + "defeat": { + 1: "Team Magma will prevail!" + } + }, + "magma_boss_maxie_2": { + "encounter": { + 1: `You are the final obstacle remaining between me and my goals. + $Brace yourself for my ultimate attack! Fuhahaha!` + }, + "victory": { + 1: "This... This is not.. Ngh..." + }, + "defeat": { + 1: "And now... I will transform this planet to a land ideal for humanity." + } + }, + "aqua_boss_archie_1": { + "encounter": { + 1: "I'm the leader of Team Aqua, so I'm afraid it's the rope's end for you." + }, + "victory": { + 1: "Let's meet again somewhere. I'll be sure to remember that face." + }, + "defeat": { + 1: "Brilliant! My team won't hold back now!" + } + }, + "aqua_boss_archie_2": { + "encounter": { + 1: "I've been waiting so long for this day to come.\nThis is the true power of my team!" + }, + "victory": { + 1: "Like I figured..." + }, + "defeat": { + 1: "I'll return everything in this world to its original, pure state!!" + } + }, + "galactic_boss_cyrus_1": { + "encounter": { + 1: `You were compelled to come here by such vacuous sentimentality. + $I will make you regret paying heed to your heart!` + }, + "victory": { + 1: "Interesting. And quite curious." + }, + "defeat": { + 1: "I will create my new world..." + } + }, + "galactic_boss_cyrus_2": { + "encounter": { + 1: `So we meet again. It seems our fates have become intertwined. + $But here and now, I will finally break that bond!` + }, + "victory": { + 1: "How? How? HOW?!" + }, + "defeat": { + 1: "Farewell." + } + }, + "plasma_boss_ghetsis_1": { + "encounter": { + 1: "I won't allow anyone to stop me! No matter who does what!" + }, + "victory": { + 1: "How can this be? I'm the creator of Team Plasma! I'm perfect!" + }, + "defeat": { + 1: "I am the perfect ruler of a perfect new world! Mwa ha ha!" + } + }, + "plasma_boss_ghetsis_2": { + "encounter": { + 1: "Come now! I want to see your face at the moment you lose all hope!" + }, + "victory": { + 1: "My calculations... No! My careful schemes! The world should be mine!" + }, + "defeat": { + 1: "Kyurem! Use Absofusion!" + } + }, + "flare_boss_lysandre_1": { + "encounter": { + 1: "Do you want to stop me? Show me in battle." + }, + "victory": { + 1: "You are here to stop me. But I ask you to wait. " + }, + "defeat": { + 1: "Pokemon...Shall no longer exist." + } + }, + "flare_boss_lysandre_2": { + "encounter": { + 1: "The future you want, or the future I want... Let us see which one is more deserving, shall we?" + }, + "victory": { + 1: "Whaugh!" + }, + "defeat": { + 1: "Fools with no vision will continue to befoul this beautiful world." + } + }, + "brock": { + "encounter": { + 1: "My expertise on Rock-type Pokémon will take you down! Come on!", + 2: "My rock-hard willpower will overwhelm you!", + 3: "Allow me to show you the true strength of my Pokémon!" + }, + "victory": { + 1: "Your Pokémon's strength have overcome my rock-hard defenses!", + 2: "The world is huge! I'm glad to have had a chance to battle you.", + 3: "Perhaps I should go back to pursuing my dream as a Pokémon Breeder…" + }, + "defeat": { + 1: "The best offense is a good defense!\nThat's my way of doing things!", + 2: "Come study rocks with me next time to better learn how to fight them!", + 3: "Hah, all my traveling around the regions is paying off!" + } + }, + "misty": { + "encounter": { + 1: "My policy is an all out offensive with Water-type Pokémon!", + 2: "Hiya, I'll show you the strength of my aquatic Pokémon!", + 3: "My dream was to go on a journey and battle powerful trainers…\nWill you be a sufficient challenge?" + }, + "victory": { + 1: "You really are strong… I'll admit that you are skilled…", + 2: "Grrr… You know you just got lucky, right?!", + 3: "Wow, you're too much! I can't believe you beat me!" + }, + "defeat": { + 1: "Was the mighty Misty too much for you?", + 2: "I hope you saw my Pokémon's elegant swimming techniques!", + 3: "Your Pokémon were no match for my pride and joys!" + } + }, + "lt_surge": { + "encounter": { + 1: "My Electric Pokémon saved me during the war! I'll show you how!", + 2: "Ten-hut! I'll shock you into surrender!", + 3: "I'll zap you just like I do to all my enemies in battle!" + }, + "victory": { + 1: "Whoa! Your team's the real deal, kid!", + 2: "Aaargh, you're strong! Even my electric tricks lost against you.", + 3: "That was an absolutely shocking loss!" + }, + "defeat": { + 1: "Oh yeah! When it comes to Electric-type Pokémon, I'm number one in the world!", + 2: "Hahaha! That was an electrifying battle, kid!", + 3: "A Pokémon battle is war, and I have showed you first-hand combat!" + } + }, + "erika": { + "encounter": { + 1: "Ah, the weather is lovely here…\nOh, a battle? Very well then.", + 2: "My Pokémon battling skills rival that of my flower arranging skills.", + 3: "Oh, I hope the pleasant aroma of my Pokémon doesn't put me to sleep again…", + 4: "Seeing flowers in a garden is so soothing." + }, + "victory": { + 1: "Oh! I concede defeat.", + 2: "That match was most delightful.", + 3: "Ah, it appears it is my loss…", + 4: "Oh, my goodness." + }, + "defeat": { + 1: "I was afraid I would doze off…", + 2: "Oh my, it seems my Grass Pokémon overwhelmed you.", + 3: "That battle was such a soothing experience.", + 4: "Oh… Is that all?" + } + }, + "janine": { + "encounter": { + 1: "I am mastering the art of poisonous attacks.\nI shall spar with you today!", + 2: "Father trusts that I can hold my own.\nI will prove him right!", + 3: "My ninja techniques are only second to my Father's!\nCan you keep up?" + }, + "victory": { + 1: "Even now, I still need training… I understand.", + 2: "Your battle technique has outmatched mine.", + 3: "I'm going to really apply myself and improve my skills." + }, + "defeat": { + 1: "Fufufu… the poison has sapped all your strength to battle.", + 2: "Ha! You didn't stand a chance against my superior ninja skills!", + 3: "Father's faith in me has proven to not be misplaced." + } + }, + "sabrina": { + "encounter": { + 1: "Through my psychic ability, I had a vision of your arrival!", + 2: "I dislike fighting, but if you wish, I will show you my powers!", + 3: "I can sense great ambition in you. I shall see if it not unfounded." + }, + "victory": { + 1: "Your power… It far exceeds what I foresaw…", + 2: "I failed to accurately predict your power.", + 3: "Even with my immense psychic powers, I cannot sense another as strong as you." + }, + "defeat": { + 1: "This victory… It is exactly as I foresaw in my visions!", + 2: "Perhaps it was another I sensed a great desire in…", + 3: "Hone your abilities before recklessly charging into battle.\nYou never know what the future may hold if you do…" + } + }, + "blaine": { + "encounter": { + 1: "Hah! Hope you brought a Burn Heal!", + 2: "My fiery Pokémon will incinerate all challengers!", + 3: "Get ready to play with fire!" + }, + "victory": { + 1: "I have burned down to nothing! Not even ashes remain!", + 2: "Didn't I stoke the flames high enough?", + 3: "I'm all burned out… But this makes my motivation to improve burn even hotter!" + }, + "defeat": { + 1: "My raging inferno cannot be quelled!", + 2: "My Pokémon have been powered up with the heat from this victory!", + 3: "Hah! My passion burns brighter than yours!" + } + }, + "giovanni": { + "encounter": { + 1: "I, the leader of Team Rocket, will make you feel a world of pain!", + 2: "My training here will be vital before I am to face my old associates again.", + 3: "I do not think you are prepared for the level of failure you are about to experience!" + }, + "victory": { + 1: "WHAT! Me, lose?! There is nothing I wish to say to you!", + 2: "Hmph… You could never understand what I hope to achieve.", + 3: "This defeat is merely delaying the inevitable.\nI will rise Team Rocket from the ashes in due time." + }, + "defeat": { + 1: "Not being able to measure your own strength shows that you are still but a child.", + 2: "Do not try to interfere with me again.", + 3: "I hope you understand how foolish challenging me was." + } + }, + "roxanne": { + "encounter": { + 1: "Would you kindly demonstrate how you battle?", + 2: "You can learn many things by battling many trainers.", + 3: "Oh, you caught me strategizing.\nWould you like to battle?" + }, + "victory": { + 1: "Oh, I appear to have lost.\nI understand.", + 2: "It seems that I still have so much more to learn when it comes to battle.", + 3: "I'll take what I learned here today to heart." + }, + "defeat": { + 1: "I have learned many things from our battle.\nI hope you have too.", + 2: "I look forward to battling you again.\nI hope you'll use what you've learned here.", + 3: "I won due to everything I have learned." + } + }, + "brawly": { + "encounter": { + 1: "Oh man, a challenger!\nLet's see what you can do!", + 2: "You seem like a big splash.\nLet's battle!", + 3: "Time to create a storm!\nLet's go!" + }, + "victory": { + 1: "Oh woah, you've washed me out!", + 2: "You surfed my wave and crashed me down!", + 3: "I feel like I'm lost in Granite Cave!" + }, + "defeat": { + 1: "Haha, I surfed the big wave!\nChallenge me again sometime.", + 2: "Surf with me again some time!", + 3: "Just like the tides come in and out, I hope you return to challenge me again." + } + }, + "wattson": { + "encounter": { + 1: "Time to get shocked!\nWahahahaha!", + 2: "I'll make sparks fly!\nWahahahaha!", + 3: "I hope you brought Paralyz Heal!\nWahahahaha!" + }, + "victory": { + 1: "Seems like I'm out of charge!\nWahahahaha!", + 2: "You've completely grounded me!\nWahahahaha!", + 3: "Thanks for the thrill!\nWahahahaha!" + }, + "defeat": { + 1: "Recharge your batteries and challenge me again sometime!\nWahahahaha!", + 2: "I hope you found our battle electrifying!\nWahahahaha!", + 3: "Aren't you shocked I won?\nWahahahaha!" + } + }, + "flannery": { + "encounter": { + 1: "Nice to meet you! Wait, no…\nI will crush you!", + 2: "I've only been a leader for a little while, but I'll smoke you!", + 3: "It's time to demonstrate the moves my grandfather has taught me! Let's battle!" + }, + "victory": { + 1: "You remind me of my grandfather…\nNo wonder I lost.", + 2: "Am I trying too hard?\nI should relax, can't get too heated.", + 3: "Losing isn't going to smother me out.\nTime to reignite training!" + }, + "defeat": { + 1: "I hope I've made my grandfather proud…\nLet's battle again some time.", + 2: "I…I can't believe I won!\nDoing things my way worked!", + 3: "Let's exchange burning hot moves again soon!" + } + }, + "norman": { + "encounter": { + 1: "I'm surprised you managed to get here.\nLet's battle.", + 2: "I'll do everything in my power as a Gym Leader to win.\nLet's go!", + 3: "You better give this your all.\nIt's time to battle!" + }, + "victory": { + 1: "I lost to you…?\nRules are rules, though.", + 2: "Was moving from Olivine a mistake…?", + 3: "I can't believe it.\nThat was a great match." + }, + "defeat": { + 1: "We both tried our best.\nI hope we can battle again soon.", + 2: "You should try challenging my kid instead.\nYou might learn something!", + 3: "Thank you for the excellent battle.\nBetter luck next time." + } + }, + "winona": { + "encounter": { + 1: "I've been soaring the skies looking for prey…\nAnd you're my target!", + 2: "No matter how our battle is, my Flying Pokémon and I will triumph with grace. Let's battle!", + 3: "I hope you aren't scared of heights.\nLet's ascend!" + }, + "victory": { + 1: "You're the first Trainer I've seen with more grace than I.\nExcellently played.", + 2: "Oh, my Flying Pokémon have plummeted!\nVery well.", + 3: "Though I may have fallen, my Pokémon will continue to fly!" + }, + "defeat": { + 1: "My Flying Pokémon and I will forever dance elegantly!", + 2: "I hope you enjoyed our show.\nOur graceful dance is finished.", + 3: "Won't you come see our elegant choreography again?" + } + }, + "tate": { + "encounter": { + 1: "Hehehe…\nWere you surprised to see me without my sister?", + 2: "I can see what you're thinking…\nYou want to battle!", + 3: "How can you defeat someone…\nWho knows your every move?" + }, + "victory": { + 1: "It can't be helped…\nI miss Liza…", + 2: "Your bond with your Pokémon was stronger than mine.", + 3: "If I were with Liza, we would have won.\nWe can finish each other's thoughts!" + }, + "defeat": { + 1: "My Pokémon and I are superior!", + 2: "If you can't even defeat me, you'll never be able to defeat Liza either.", + 3: "It's all thanks to my strict training with Liza.\nI can make myself one with Pokémon." + } + }, + "liza": { + "encounter": { + 1: "Fufufu…\nWere you surprised to see me without my brother?", + 2: "I can determine what you desire…\nYou want to battle, don't you?", + 3: "How can you defeat someone…\nWho's one with their Pokémon?" + }, + "victory": { + 1: "It can't be helped…\nI miss Tate…", + 2: "Your bond with your Pokémon…\nIt's stronger than mine.", + 3: "If I were with Tate, we would have won.\nWe can finish each other's sentences!" + }, + "defeat": { + 1: "My Pokémon and I are victorious.", + 2: "If you can't even defeat me, you'll never be able to defeat Tate either.", + 3: "It's all thanks to my strict training with Tate.\nI can synchronize myself with my Pokémon." + } + }, + "juan": { + "encounter": { + 1: "Now's not the time to act coy.\nLet's battle!", + 2: "Ahahaha, You'll be witness to my artistry with Water Pokémon!", + 3: "A typhoon approaches!\nWill you be able to test me?", + 4: "Please, you shall bear witness to our artistry.\nA grand illusion of water sculpted by my Pokémon and myself!" + }, + "victory": { + 1: "You may be a genius who can take on Wallace!", + 2: "I focused on elegance while you trained.\nIt's only natural that you defeated me.", + 3: "Ahahaha!\nVery well, You have won this time.", + 4: "From you, I sense the brilliant shine of skill that will overcome all." + }, + "defeat": { + 1: "My Pokémon and I have sculpted an illusion of Water and come out victorious.", + 2: "Ahahaha, I have won, and you have lost.", + 3: "Shall I loan you my outfit? It may help you battle!\nAhahaha, I jest!", + 4: "I'm the winner! Which is to say, you lost." + } + }, + "crasher_wake": { + "encounter": { + 1: "Crash! Crash! Watch out!\nCrasher Wake…is…heeere!", + 2: "Crash! Crash! Crasher Wake!", + 3: "I'm the tidal wave of power to wash you away!" + }, + "victory": { + 1: "That puts a grin on my face!\nGuhahaha! That was a blast!", + 2: "Hunwah! It's gone and ended!\nHow will I say this…\nI want more! I wanted to battle a lot more!", + 3: "WHAAAAT!?" + }, + "defeat": { + 1: "Yeeeeah! That's right!", + 2: "I won, but I want more! I wanted to battle a lot more!", + 3: "So long!" + } + }, + "falkner": { + "encounter": { + 1: "I'll show you the real power of the magnificent bird Pokémon!", + 2: "Winds, stay with me!", + 3: "Dad! I hope you're watching me battle from above!" + }, + "victory": { + 1: "I understand… I'll bow out gracefully.", + 2: "A defeat is a defeat. You are strong indeed.", + 3: "…Shoot! Yeah, I lost." + }, + "defeat": { + 1: "Dad! I won with your cherished bird Pokémon…", + 2: "Bird Pokémon are the best after all!", + 3: "Feels like I'm catching up to my dad!" + } + }, + "nessa": { + "encounter": { + 1: "No matter what kind of plan your refined mind may be plotting, my partner and I will be sure to sink it.", + 2: "I'm not here to chat. I'm here to win!", + 3: "This is a little gift from my Pokémon… I hope you can take it!" + }, + "victory": { + 1: "You and your Pokémon are just too much…", + 2: "How…? How can this be?!", + 3: "I was totally washed away!" + }, + "defeat": { + 1: "The raging wave crashes again!", + 2: "Time to ride the wave of victory!", + 3: "Ehehe!" + } + }, + "melony": { + "encounter": { + 1: "I'm not going to hold back!", + 2: "All righty, I suppose we should get started.", + 3: "I'll freeze you solid!" + }, + "victory": { + 1: "You… You're pretty good, huh?", + 2: "If you find Gordie around, be sure to give him a right trashing, would you?", + 3: "I think you took breaking the ice a little too literally…" + }, + "defeat": { + 1: "Now do you see how severe battles can be?", + 2: "Hee! Looks like I went and won again!", + 3: "Are you holding back?" + } + }, + "marlon": { + "encounter": { + 1: "You look strong! Shoots! Let's start!", + 2: "I'm strong like the ocean's wide. You're gonna get swept away, fo' sho'.", + 3: "Oh ho, so I'm facing you! That's off the wall." + }, + "victory": { + 1: "You totally rocked that! You're raising some wicked Pokémon. You got this Trainer thing down!", + 2: "You don't just look strong, you're strong fo' reals! Eh, I was swept away, too!", + 3: "You're strong as a gnarly wave!" + }, + "defeat": { + 1: "You're tough, but it's not enough to sway the sea, 'K!", + 2: "Hee! Looks like I went and won again!", + 3: "Sweet, sweet victory!" + } + }, + "shauntal": { + "encounter": { + 1: "Excuse me. You're a challenger, right?\nI'm the Elite Four's Ghost-type Pokémon user, Shauntal, and I shall be your opponent.", + 2: "I absolutely love writing about Trainers who come here and the Pokémon they train.\nCould I use you and your Pokémon as a subject?", + 3: "Every person who works with Pokémon has a story to tell.\nWhat story is about to be told?" + }, + "victory": { + 1: "Wow. I'm dumbstruck!", + 2: "S-sorry! First, I must apologize to my Pokémon…\n\nI'm really sorry you had a bad experience because of me!", + 3: "Even in light of that, I'm still one of the Elite Four!" + }, + "defeat": { + 1: "Eheh.", + 2: "That gave me excellent material for my next novel!", + 3: "And so, another tale ends…" + } + }, + "marshal": { + "encounter": { + 1: "My mentor, Alder, sees your potential as a Trainer and is taking an interest in you.\nIt is my intention to test you--to take you to the limits of your strength. Kiai!", + 2: "Victory, decisive victory, is my intention! Challenger, here I come!", + 3: "In myself, I seek to develop the strength of a fighter and shatter any weakness in myself!\nPrevailing with the force of my convictions!" + }, + "victory": { + 1: "Whew! Well done!", + 2: "As your battles continue, aim for even greater heights!", + 3: "The strength shown by you and your Pokémon has deeply impressed me…" + }, + "defeat": { + 1: "Hmm.", + 2: "That was good battle.", + 3: "Haaah! Haaah! Haiyaaaah!" + } + }, + "cheren": { + "encounter": { + 1: "You remind me of an old friend. That makes me excited about this Pokémon battle!", + 2: `Pokémon battles have no meaning if you don't think why you battle. + $Or better said, it makes battling together with Pokémon meaningless.`, + 3: "My name's Cheren! I'm a Gym Leader and a teacher! Pleasure to meet you." + }, + "victory": { + 1: "Thank you! I saw what was missing in me.", + 2: "Thank you! I feel like I saw a little of the way toward my ideals.", + 3: "Hmm… This is problematic." + }, + "defeat": { + 1: "As a Gym Leader, I aim to be a wall for you to overcome.", + 2: "All right!", + 3: "I made it where I am because Pokémon were by my side.\nPerhaps we need to think about why Pokémon help us not in terms of Pokémon and Trainers but as a relationship between living beings." + } + }, + "chili": { + "encounter": { + 1: "Yeeeeooow! Time to play with FIRE!! I'm the strongest of us brothers!", + 2: "Ta-da! The Fire-type scorcher Chili--that's me--will be your opponent!", + 3: "I'm going to show you what me and my blazing Fire types can do!" + }, + "victory": { + 1: "You got me. I am… burned… out…", + 2: "Whoa ho! You're on fire!", + 3: "Augh! You got me!" + }, + "defeat": { + 1: "I'm on fire! Play with me, and you'll get burned!", + 2: "When you play with fire, you get burned!", + 3: "I mean, c'mon, your opponent was me! You didn't have a chance!" + } + }, + "cilan": { + "encounter": { + 1: `Nothing personal... No hard feelings... Me and my Grass-type Pokémon will... + $Um... We're gonna battle come what may.`, + 2: "So, um, if you're OK with me, I'll, um, put everything I've got into being, er, you know, your opponent.", + 3: "OK… So, um, I'm Cilan, I like Grass-type Pokémon." + }, + "victory": { + 1: "Er… Is it over now?", + 2: `…What a surprise. You are very strong, aren't you? + $I guess my brothers wouldn't have been able to defeat you either…`, + 3: "…Huh. Looks like my timing was, um, off?" + }, + "defeat": { + 1: "Huh? Did I win?", + 2: `I guess… + $I suppose I won, because I've been competing with my brothers Chili and Cress, and we all were able to get tougher.`, + 3: "It…it was quite a thrilling experience…" + } + }, + "roark": { + "encounter": { + 1: "I need to see your potential as a Trainer. And, I'll need to see the toughness of the Pokémon that battle with you!", + 2: "Here goes! These are my rocking Pokémon, my pride and joy!", + 3: "Rock-type Pokémon are simply the best!", + 4: "I need to see your potential as a Trainer. And, I'll need to see the toughness of the Pokémon that battle with you!" + }, + "victory": { + 1: "W-what? That can't be! My buffed-up Pokémon!", + 2: "…We lost control there. Next time I'd like to challenge you to a Fossil-digging race underground.", + 3: "With skill like yours, it's natural for you to win.", + 4: "Wh-what?! It can't be! Even that wasn't enough?", + 5: "I blew it." + }, + "defeat": { + 1: "See? I'm proud of my rocking battle style!", + 2: "Thanks! The battle gave me confidence that I may be able to beat my dad!", + 3: "I feel like I just smashed through a really stubborn boulder!" + } + }, + "morty": { + "encounter": { + 1: `With a little more, I could see a future in which I meet the legendary Pokémon. + $You're going to help me reach that level!`, + 2: `It's said that a rainbow-hued Pokémon will come down to appear before a truly powerful Trainer. + $I believed that tale, so I have secretly trained here all my life. As a result, I can now see what others cannot. + $I see a shadow of the person who will make the Pokémon appear. + $I believe that person is me! You're going to help me reach that level!`, + 3: "Whether you choose to believe or not, mystic power does exist.", + 4: "You can bear witness to the fruits of my training.", + 5: "You must make your soul one with that of Pokémon. Can you do this?", + 6: "Say, do you want to be part of my training?" + }, + "victory": { + 1: "I'm not good enough yet…", + 2: `I see… Your journey has taken you to far-away places and you have witnessed much more than I. + $I envy you for that…`, + 3: "How is this possible…", + 4: `I don't think our potentials are so different. + $But you seem to have something more than that… So be it.`, + 5: "Guess I need more training.", + 6: "That's a shame." + }, + "defeat": { + 1: "I moved… one step ahead again.", + 2: "Fufufu…", + 3: "Wh-what?! It can't be! Even that wasn't enough?", + 4: "I feel like I just smashed through a really stubborn boulder!", + 5: "Ahahahah!", + 6: "I knew I would win!" + } + }, + "crispin": { + "encounter": { + 1: "I wanna win, so that's exactly what I'll do!", + 2: "I battle because I wanna battle! And you know what? That's how it should be!" + }, + "victory": { + 1: "I wanted to win…but I lost!", + 2: "I lost…'cause I couldn't win!" + }, + "defeat": { + 1: "Hey, wait a sec. Did I just win? I think I just won! Talk about satisfying!", + 2: "Wooo! That was amazing!" + } + }, + "amarys": { + "encounter": { + 1: `I want to be the one to help a certain person. That being the case, I cannot afford to lose. + $… Our battle starts now.`, + }, + "victory": { + 1: "I am… not enough, I see." + }, + "defeat": { + 1: "Victory belongs to me. Well fought." + } + }, + "lacey": { + "encounter": { + 1: "I'll be facing you with my usual party as a member of the Elite Four." + }, + "victory": { + 1: "That was a great battle!" + }, + "defeat": { + 1: "Let's give your Pokémon a nice round of applause for their efforts!" + } + }, + "drayton": { + "encounter": { + 1: `Man, I love chairs. Don't you love chairs? What lifesavers. + $I don't get why everyone doesn't just sit all the time. Standing up's tiring work!`, + }, + "victory": { + 1: "Guess I should've expected that!" + }, + "defeat": { + 1: "Heh heh! Don't mind me, just scooping up a W over here. I get it if you're upset, but don't go full Kieran on me, OK?" + } + }, + "ramos": { + "encounter": { + 1: `Did yeh enjoy the garden playground I made with all these sturdy plants o' mine? + $Their strength is a sign o' my strength as a gardener and a Gym Leader! Yeh sure yer up to facing all that?`, + }, + "victory": { + 1: "Yeh believe in yer Pokémon… And they believe in yeh, too… It was a fine battle, sprout." + }, + "defeat": { + 1: "Hohoho… Indeed. Frail little blades o' grass'll break through even concrete." + } + }, + "viola": { + "encounter": { + 1: `Whether it's the tears of frustration that follow a loss or the blossoming of joy that comes with victory… + $They're both great subjects for my camera! Fantastic! This'll be just fantastic! + $Now come at me!`, + 2: "My lens is always focused on victory--I won't let anything ruin this shot!" + }, + "victory": { + 1: "You and your Pokémon have shown me a whole new depth of field! Fantastic! Just fantastic!", + 2: `The world you see through a lens, and the world you see with a Pokémon by your side… + $The same world can look entirely different depending on your view.` + }, + "defeat": { + 1: "The photo from the moment of my victory will be a real winner, all right!", + 2: "Yes! I took some great photos!" + } + }, + "candice": { + "encounter": { + 1: `You want to challenge Candice? Sure thing! I was waiting for someone tough! + $But I should tell you, I'm tough because I know how to focus.`, + 2: `Pokémon, fashion, romance… It's all about focus! + $I'll show you just what I mean. Get ready to lose!` + }, + "victory": { + 1: "I must say, I'm warmed up to you! I might even admire you a little.", + 2: `Wow! You're great! You've earned my respect! + $I think your focus and will bowled us over totally. ` + }, + "defeat": { + 1: "I sensed your will to win, but I don't lose!", + 2: "See? Candice's focus! My Pokémon's focus is great, too!" + } + }, + "gardenia": { + "encounter": { + 1: "You have a winning aura about you. So, anyway, this will be fun. Let's have our battle!" + }, + "victory": { + 1: "Amazing! You're very good, aren't you?" + }, + "defeat": { + 1: "Yes! My Pokémon and I are perfectly good!" + } + }, + "aaron": { + "encounter": { + 1: "Ok! Let me take you on!" + }, + "victory": { + 1: "Battling is a deep and complex affair…" + }, + "defeat": { + 1: "Victory over an Elite Four member doesn't come easily." + } + }, + "cress": { + "encounter": { + 1: "That is correct! It shall be I and my esteemed Water types that you must face in battle!" + }, + "victory": { + 1: "Lose? Me? I don't believe this." + }, + "defeat": { + 1: "This is the appropriate result when I'm your opponent." + } + }, + "allister": { + "encounter": { + 1: "'M Allister.\nH-here… I go…" + }, + "victory": { + 1: `I nearly lost my mask from the shock… That was… + $Wow. I can see your skill for what it is.`, + }, + "defeat": { + 1: "Th-that was ace!" + } + }, + "clay": { + "encounter": { + 1: "Harrumph! Kept me waitin', didn't ya, kid? All right, time to see what ya can do!" + }, + "victory": { + 1: "Man oh man… It feels good to go all out and still be defeated!" + }, + "defeat": { + 1: `What's important is how ya react to losin'. + $That's why folks who use losin' as fuel to get better are tough.`, + } + }, + "kofu": { + "encounter": { + 1: "I'mma serve you a full course o' Water-type Pokémon! Don't try to eat 'em, though!" + }, + "victory": { + 1: "Vaultin' Veluza! Yer a lively one, aren't ya! A little TOO lively, if I do say so myself!" + }, + "defeat": { + 1: "You come back to see me again now, ya hear?" + } + }, + "tulip": { + "encounter": { + 1: "Allow me to put my skills to use to make your cute little Pokémon even more beautiful!" + }, + "victory": { + 1: "Your strength has a magic to it that cannot be washed away." + }, + "defeat": { + 1: "You know, in my line of work, people who lack talent in one area or the other often fade away quickly—never to be heard of again." + } + }, + "sidney": { + "encounter": { + 1: `I like that look you're giving me. I guess you'll give me a good match. + $That's good! Looking real good! All right! + $You and me, let's enjoy a battle that can only be staged here!`, + }, + "victory": { + 1: "Well, how do you like that? I lost! Eh, it was fun, so it doesn't matter." + }, + "defeat": { + 1: "No hard feelings, alright?" + } + }, + "phoebe": { + "encounter": { + 1: `While I trained, I gained the ability to commune with Ghost-type Pokémon. + $Yes, the bond I developed with Pokémon is extremely tight. + $So, come on, just try and see if you can even inflict damage on my Pokémon!`, + }, + "victory": { + 1: "Oh, darn. I've gone and lost." + }, + "defeat": { + 1: "I look forward to battling you again sometime!" + } + }, + "glacia": { + "encounter": { + 1: `All I have seen are challenges by weak Trainers and their Pokémon. + $What about you? It would please me to no end if I could go all out against you!`, + }, + "victory": { + 1: `You and your Pokémon… How hot your spirits burn! + $The all-consuming heat overwhelms. + $It's no surprise that my icy skills failed to harm you.`, + }, + "defeat": { + 1: "A fiercely passionate battle, indeed." + } + }, + "drake": { + "encounter": { + 1: `For us to battle with Pokémon as partners, do you know what it takes? Do you know what is needed? + $If you don't, then you will never prevail over me!`, + }, + "victory": { + 1: "Superb, it should be said." + }, + "defeat": { + 1: "I gave my all for that battle!" + } + }, + "wallace": { + "encounter": { + 1: `There's something about you… A difference in your demeanor. + $I think I sense that in you. Now, show me. Show me the power you wield with your Pokémon. + $And I, in turn, shall present you with a performance of illusions in water by me and my Pokémon!`, + }, + "victory": { + 1: `Bravo. I realize now your authenticity and magnificence as a Pokémon Trainer. + $I find much joy in having met you and your Pokémon. You have proven yourself worthy.`, + }, + "defeat": { + 1: "A grand illusion!" + } + }, + "lorelei": { + "encounter": { + 1: `No one can best me when it comes to icy Pokémon! Freezing moves are powerful! + $Your Pokémon will be at my mercy when they are frozen solid! Hahaha! Are you ready?`, + }, + "victory": { + 1: "How dare you!" + }, + "defeat": { + 1: "There's nothing you can do once you're frozen." + } + }, + "will": { + "encounter": { + 1: `I have trained all around the world, making my psychic Pokémon powerful. + $I can only keep getting better! Losing is not an option!`, + }, + "victory": { + 1: "I… I can't… believe it…" + }, + "defeat": { + 1: "That was close. I wonder what it is that you lack." + } + }, + "malva": { + "encounter": { + 1: `I feel like my heart might just burst into flames. + $I'm burning up with my hatred for you, runt!`, + }, + "victory": { + 1: "What news… So a new challenger has defeated Malva!" + }, + "defeat": { + 1: "I am delighted! Yes, delighted that I could squash you beneath my heel." + } + }, + "hala": { + "encounter": { + 1: "Old Hala is here to make you holler!" + }, + "victory": { + 1: "I could feel the power you gained on your journey." + }, + "defeat": { + 1: "Haha! What a delightful battle!" + } + }, + "molayne": { + "encounter": { + 1: `I gave the captain position to my cousin Sophocles, but I'm confident in my ability. + $My strength is like that of a supernova!`, + }, + "victory": { + 1: "I certainly found an interesting Trainer to face!" + }, + "defeat": { + 1: "Ahaha. What an interesting battle." + } + }, + "rika": { + "encounter": { + 1: "I'd say I'll go easy on you, but… I'd be lying! Think fast!" + }, + "victory": { + 1: "Not bad, kiddo." + }, + "defeat": { + 1: "Nahahaha! You really are something else, kiddo!" + } + }, + "bruno": { + "encounter": { + 1: "We will grind you down with our superior power! Hoo hah!" + }, + "victory": { + 1: "Why? How could I lose?" + }, + "defeat": { + 1: "You can challenge me all you like, but the results will never change!" + } + }, + "bugsy": { + "encounter": { + 1: "I'm Bugsy! I never lose when it comes to bug Pokémon!" + }, + "victory": { + 1: "Whoa, amazing! You're an expert on Pokémon!\nMy research isn't complete yet. OK, you win." + }, + "defeat": { + 1: "Thanks! Thanks to our battle, I was also able to make progress in my research!" + } + }, + "koga": { + "encounter": { + 1: "Fwahahahaha! Pokémon are not merely about brute force--you shall see soon enough!" + }, + "victory": { + 1: "Ah! You've proven your worth!" + }, + "defeat": { + 1: "Have you learned to fear the techniques of the ninja?" + } + }, + "bertha": { + "encounter": { + 1: "Well, would you show this old lady how much you've learned?" + }, + "victory": { + 1: `Well! Dear child, I must say, that was most impressive. + $Your Pokémon believed in you and did their best to earn you the win. + $Even though I've lost, I find myself with this silly grin!`, + }, + "defeat": { + 1: "Hahahahah! Looks like this old lady won!" + } + }, + "lenora": { + "encounter": { + 1: "Well then, challenger, I'm going to research how you battle with the Pokémon you've so lovingly raised!" + }, + "victory": { + 1: "My theory about you was correct. You're more than just talented… You're motivated! I salute you!" + }, + "defeat": { + 1: "Ah ha ha! If you lose, make sure to analyze why, and use that knowledge in your next battle!" + } + }, + "siebold": { + "encounter": { + 1: "As long as I am alive, I shall strive onward to seek the ultimate cuisine... and the strongest opponents in battle!" + }, + "victory": { + 1: "I shall store my memory of you and your Pokémon forever away within my heart." + }, + "defeat": { + 1: `Our Pokémon battle was like food for my soul. It shall keep me going. + $That is how I will pay my respects to you for giving your all in battle!`, + } + }, + "roxie": { + "encounter": { + 1: "Get ready! I'm gonna knock some sense outta ya!" + }, + "victory": { + 1: "Wild! Your reason's already more toxic than mine!" + }, + "defeat": { + 1: "Hey, c'mon! Get serious! You gotta put more out there!" + } + }, + "olivia": { + "encounter": { + 1: "No introduction needed here. Time to battle me, Olivia!" + }, + "victory": { + 1: "Really lovely… Both you and your Pokémon…" + }, + "defeat": { + 1: "Mmm-hmm." + } + }, + "poppy": { + "encounter": { + 1: "Oooh! Do you wanna have a Pokémon battle with me?" + }, + "victory": { + 1: "Uagh?! Mmmuuuggghhh…" + }, + "defeat": { + 1: `Yaaay! I did it! I de-feet-ed you! You can come for… For… An avenge match? + $Come for an avenge match anytime you want!`, + } + }, + "agatha": { + "encounter": { + 1: "Pokémon are for battling! I'll show you how a real Trainer battles!" + }, + "victory": { + 1: "Oh my! You're something special, child!" + }, + "defeat": { + 1: "Bahaha. That's how a proper battle's done!" + } + }, + "flint": { + "encounter": { + 1: "Hope you're warmed up, cause here comes the Big Bang!" + }, + "victory": { + 1: "Incredible! Your moves are so hot, they make mine look lukewarm!" + }, + "defeat": { + 1: "Huh? Is that it? I think you need a bit more passion." + } + }, + "grimsley": { + "encounter": { + 1: "The winner takes everything, and there's nothing left for the loser." + }, + "victory": { + 1: "When one loses, they lose everything… The next thing I'll look for will be victory, too!" + }, + "defeat": { + 1: "If somebody wins, the person who fought against that person will lose." + } + }, + "caitlin": { + "encounter": { + 1: `It's me who appeared when the flower opened up. You who have been waiting… + $You look like a Pokémon Trainer with refined strength and deepened kindness. + $What I look for in my opponent is superb strength… + $Please unleash your power to the fullest!`, + }, + "victory": { + 1: "My Pokémon and I learned so much! I offer you my thanks." + }, + "defeat": { + 1: "I aspire to claim victory with elegance and grace." + } + }, + "diantha": { + "encounter": { + 1: `Battling against you and your Pokémon, all of you brimming with hope for the future… + $Honestly, it just fills me up with energy I need to keep facing each new day! It does!`, + }, + "victory": { + 1: "Witnessing the noble spirits of you and your Pokémon in battle has really touched my heart…" + }, + "defeat": { + 1: "Oh, fantastic! What did you think? My team was pretty cool, right?" + } + }, + "wikstrom": { + "encounter": { + 1: `Well met, young challenger! Verily am I the famed blade of hardened steel, Duke Wikstrom! + $Let the battle begin! En garde!`, + }, + "victory": { + 1: "Glorious! The trust that you share with your honorable Pokémon surpasses even mine!" + }, + "defeat": { + 1: `What manner of magic is this? My heart, it doth hammer ceaselessly in my breast! + $Winning against such a worthy opponent doth give my soul wings--thus do I soar!`, + } + }, + "acerola": { + "encounter": { + 1: "Battling is just plain fun! Come on, I can take you!" + }, + "victory": { + 1: "I'm… I'm speechless! How did you do it?!" + }, + "defeat": { + 1: "Ehaha! What an amazing victory!" + } + }, + "larry_elite": { + "encounter": { + 1: `Hello there… It's me, Larry. + $I serve as a member of the Elite Four too, yes… Unfortunately for me.`, + }, + "victory": { + 1: "Well, that took the wind from under our wings…" + }, + "defeat": { + 1: "It's time for a meeting with the boss." + } + }, + "lance": { + "encounter": { + 1: "I've been waiting for you. Allow me to test your skill.", + 2: "I thought that you would be able to get this far. Let's get this started." + }, + "victory": { + 1: "You got me. You are magnificent!", + 2: "I never expected another trainer to beat me… I'm surprised." + }, + "defeat": { + 1: "That was close. Want to try again?", + 2: "It's not that you are weak. Don't let it bother you." + } + }, + "karen": { + "encounter": { + 1: "I am Karen. Would you care for a showdown with my Dark-type Pokémon?", + 2: "I am unlike those you've already met.", + 3: "You've assembled a charming team. Our battle should be a good one." + }, + "victory": { + 1: "No! I can't win. How did you become so strong?", + 2: "I will not stray from my chosen path.", + 3: "The Champion is looking forward to meeting you." + }, + "defeat": { + 1: "That's about what I expected.", + 2: "Well, that was relatively entertaining.", + 3: "Come visit me anytime." + } + }, + "milo": { + "encounter": { + 1: `Sure seems like you understand Pokémon real well. + $This is gonna be a doozy of a battle! + $I'll have to Dynamax my Pokémon if I want to win!`, + }, + "victory": { + 1: "The power of Grass has wilted… What an incredible Challenger!" + }, + "defeat": { + 1: "This'll really leave you in shock and awe." + } + }, + "lucian": { + "encounter": { + 1: `Just a moment, please. The book I'm reading has nearly reached its thrilling climax… + $The hero has obtained a mystic sword and is about to face their final trial… Ah, never mind. + $Since you've made it this far, I'll put that aside and battle you. + $Let me see if you'll achieve as much glory as the hero of my book!` + }, + "victory": { + 1: "I see… It appears you've put me in checkmate." + }, + "defeat": { + 1: "I have a reputation to uphold." + } + }, + "drasna": { + "encounter": { + 1: `You must be a strong Trainer. Yes, quite strong indeed… + $That's just wonderful news! Facing opponents like you and your team will make my Pokémon grow like weeds!` + }, + "victory": { + 1: "Oh, dear me. That sure was a quick battle… I do hope you'll come back again sometime!" + }, + "defeat": { + 1: "How can this be?" + } + }, + "kahili": { + "encounter": { + 1: "So, here you are… Why don't we see who the winds favor today, you… Or me?" + }, + "victory": { + 1: "It's frustrating to me as a member of the Elite Four, but it seems your strength is the real deal." + }, + "defeat": { + 1: "That was an ace!" + } + }, + "hassel": { + "encounter": { + 1: "Prepare to learn firsthand how the fiery breath of ferocious battle feels!" + }, + "victory": { + 1: `Fortune smiled on me this time, but… + $Judging from how the match went, who knows if I will be so lucky next time.`, + }, + "defeat": { + 1: "That was an ace!" + } + }, + "blue": { + "encounter": { + 1: "You must be pretty good to get this far." + }, + "victory": { + 1: "I've only lost to him and now to you… Him? Hee, hee…" + }, + "defeat": { + 1: "See? My power is what got me here." + } + }, + "piers": { + "encounter": { + 1: "Get ready for a mosh pit with me and my party! Spikemuth, it's time to rock!" + }, + "victory": { + 1: "Me an' my team gave it our best. Let's meet up again for a battle some time…" + }, + "defeat": { + 1: "My throat's ragged from shoutin'… But 'at was an excitin' battle!" + } + }, + "red": { + "encounter": { + 1: "…!" + }, + "victory": { + 1: "…?" + }, + "defeat": { + 1: "…!" + } + }, + "jasmine": { + "encounter": { + 1: "Oh… Your Pokémon are impressive. I think I will enjoy this." + }, + "victory": { + 1: "You are truly strong. I'll have to try much harder, too." + }, + "defeat": { + 1: "I never expected to win." + } + }, + "lance_champion": { + "encounter": { + 1: "I am still the Champion. I won't hold anything back." + }, + "victory": { + 1: "This is the emergence of a new Champion." + }, + "defeat": { + 1: "I successfully defended my Championship." + } + }, + "steven": { + "encounter": { + 1: `Tell me… What have you seen on your journey with your Pokémon? + $What have you felt, meeting so many other Trainers out there? + $Traveling this rich land… Has it awoken something inside you? + $I want you to come at me with all that you've learned. + $My Pokémon and I will respond in turn with all that we know!`, + }, + "victory": { + 1: "So I, the Champion, fall in defeat…" + }, + "defeat": { + 1: "That was time well spent! Thank you!" + } + }, + "cynthia": { + "encounter": { + 1: "I, Cynthia, accept your challenge! There won't be any letup from me!" + }, + "victory": { + 1: "No matter how fun the battle is, it will always end sometime…" + }, + "defeat": { + 1: "Even if you lose, never lose your love of Pokémon." + } + }, + "iris": { + "encounter": { + 1: `Know what? I really look forward to having serious battles with strong Trainers! + $I mean, come on! The Trainers who make it here are Trainers who desire victory with every fiber of their being! + $And they are battling alongside Pokémon that have been through countless difficult battles! + $If I battle with people like that, not only will I get stronger, my Pokémon will, too! + $And we'll get to know each other even better! OK! Brace yourself! + $I'm Iris, the Pokémon League Champion, and I'm going to defeat you!`, + }, + "victory": { + 1: "Aghhhh… I did my best, but we lost…" + }, + "defeat": { + 1: "Yay! We won!" + } + }, + "hau": { + "encounter": { + 1: `I wonder if a Trainer battles differently depending on whether they're from a warm region or a cold region. + $Let's test it out!`, + }, + "victory": { + 1: "That was awesome! I think I kinda understand your vibe a little better now!" + }, + "defeat": { + 1: "Ma-an, that was some kinda battle!" + } + }, + "geeta": { + "encounter": { + 1: `I decided to throw my hat in the ring once more. + $Come now… Show me the fruits of your training.`, + }, + "victory": { + 1: "I eagerly await news of all your achievements!" + }, + "defeat": { + 1: "What's the matter? This isn't all, is it?" + } + }, + "nemona": { + "encounter": { + 1: "Yesss! I'm so psyched! Time for us to let loose!" + }, + "victory": { + 1: "Well, that stinks, but I still had fun! I'll getcha next time!" + }, + "defeat": { + 1: "Well, that was a great battle! Fruitful for sure." + } + }, + "leon": { + "encounter": { + 1: "We're gonna have an absolutely champion time!" + }, + "victory": { + 1: `My time as Champion is over… + $But what a champion time it's been! + $Thank you for the greatest battle I've ever had!`, + }, + "defeat": { + 1: "An absolute champion time, that was!" + } + }, + "whitney": { + "encounter": { + 1: "Hey! Don't you think Pokémon are, like, super cute?" + }, + "victory": { + 1: "Waaah! Waaah! You're so mean!" + }, + "defeat": { + 1: "And that's that!" + } + }, + "chuck": { + "encounter": { + 1: "Hah! You want to challenge me? Are you brave or just ignorant?" + }, + "victory": { + 1: "You're strong! Would you please make me your apprentice?" + }, + "defeat": { + 1: "There. Do you realize how much more powerful I am than you?" + } + }, + "katy": { + "encounter": { + 1: "Don't let your guard down unless you would like to find yourself knocked off your feet!" + }, + "victory": { + 1: "All of my sweet little Pokémon dropped like flies!" + }, + "defeat": { + 1: "Eat up, my cute little Vivillon!" + } + }, + "pryce": { + "encounter": { + 1: "Youth alone does not ensure victory! Experience is what counts." + }, + "victory": { + 1: "Outstanding! That was perfect. Try not to forget what you feel now." + }, + "defeat": { + 1: "Just as I envisioned." + } + }, + "clair": { + "encounter": { + 1: "Do you know who I am? And you still dare to challenge me?" + }, + "victory": { + 1: "I wonder how far you can get with your skill level. This should be fascinating." + }, + "defeat": { + 1: "That's that." + } + }, + "maylene": { + "encounter": { + 1: `I've come to challenge you now, and I won't hold anything back. + $Please prepare yourself for battle!`, + }, + "victory": { + 1: "I admit defeat…" + }, + "defeat": { + 1: "That was awesome." + } + }, + "fantina": { + "encounter": { + 1: `You shall challenge me, yes? But I shall win. + $That is what the Gym Leader of Hearthome does, non?`, + }, + "victory": { + 1: "You are so fantastically strong. I know why I have lost." + }, + "defeat": { + 1: "I am so, so, very happy!" + } + }, + "byron": { + "encounter": { + 1: `Trainer! You're young, just like my son, Roark. + $With more young Trainers taking charge, the future of Pokémon is bright! + $So, as a wall for young people, I'll take your challenge!`, + }, + "victory": { + 1: "Hmm! My sturdy Pokémon--defeated!" + }, + "defeat": { + 1: "Gwahahaha! How were my sturdy Pokémon?!" + } + }, + "olympia": { + "encounter": { + 1: "An ancient custom deciding one's destiny. The battle begins!" + }, + "victory": { + 1: "Create your own path. Let nothing get in your way. Your fate, your future." + }, + "defeat": { + 1: "Our path is clear now." + } + }, + "volkner": { + "encounter": { + 1: `Since you've come this far, you must be quite strong… + $I hope you're the Trainer who'll make me remember how fun it is to battle!`, + }, + "victory": { + 1: `You've got me beat… + $Your desire and the noble way your Pokémon battled for you… + $I even felt thrilled during our match. That was a very good battle.`, + }, + "defeat": { + 1: `It was not shocking at all… + $That is not what I wanted!`, + } + }, + "burgh": { + "encounter": { + 1: `M'hm… If I win this battle, I feel like I can draw a picture unlike any before it. + $OK! I can hear my battle muse loud and clear. Let's get straight to it!`, + 2: `Of course, I'm really proud of all of my Pokémon! + $Well now… Let's get right to it!` + }, + "victory": { + 1: "Is it over? Has my muse abandoned me?", + 2: "Hmm… It's over! You're incredible!" + }, + "defeat": { + 1: "Wow… It's beautiful somehow, isn't it…", + 2: `Sometimes I hear people say something was an ugly win. + $I think if you're trying your best, any win is beautiful.` + } + }, + "elesa": { + "encounter": { + 1: `C'est fini! When I'm certain of that, I feel an electric jolt run through my body! + $I want to feel the sensation, so now my beloved Pokémon are going to make your head spin!`, + }, + "victory": { + 1: "I meant to make your head spin, but you shocked me instead." + }, + "defeat": { + 1: "That was unsatisfying somehow… Will you give it your all next time?" + } + }, + "skyla": { + "encounter": { + 1: `It's finally time for a showdown! That means the Pokémon battle that decides who's at the top, right? + $I love being on the summit! 'Cause you can see forever and ever from high places! + $So, how about you and I have some fun?`, + }, + "victory": { + 1: "Being your opponent in battle is a new source of strength to me. Thank you!" + }, + "defeat": { + 1: "Win or lose, you always gain something from a battle, right?" + } + }, + "brycen": { + "encounter": { + 1: `There is also strength in being with other people and Pokémon. + $Receiving their support makes you stronger. I'll show you this power!`, + }, + "victory": { + 1: "The wonderful combination of you and your Pokémon! What a beautiful friendship!" + }, + "defeat": { + 1: "Extreme conditions really test you and train you!" + } + }, + "drayden": { + "encounter": { + 1: `What I want to find is a young Trainer who can show me a bright future. + $Let's battle with everything we have: your skill, my experience, and the love we've raised our Pokémon with!`, + }, + "victory": { + 1: "This intense feeling that floods me after a defeat… I don't know how to describe it." + }, + "defeat": { + 1: "Harrumph! I know your ability is greater than that!" + } + }, + "grant": { + "encounter": { + 1: `There is only one thing I wish for. + $That by surpassing one another, we find a way to even greater heights.`, + }, + "victory": { + 1: "You are a wall that I am unable to surmount!" + }, + "defeat": { + 1: `Do not give up. + $That is all there really is to it. + $The most important lessons in life are simple.`, + } + }, + "korrina": { + "encounter": { + 1: "Time for Lady Korrina's big appearance!" + }, + "victory": { + 1: "It's your very being that allows your Pokémon to evolve!" + }, + "defeat": { + 1: "What an explosive battle!" + } + }, + "clemont": { + "encounter": { + 1: "Oh! I'm glad that we got to meet!" + }, + "victory": { + 1: "Your passion for battle inspires me!" + }, + "defeat": { + 1: "Looks like my Trainer-Grow-Stronger Machine, Mach 2 is really working!" + } + }, + "valerie": { + "encounter": { + 1: `Oh, if it isn't a young Trainer… It is lovely to get to meet you like this. + $Then I suppose you have earned yourself the right to a battle, as a reward for your efforts. + $The elusive Fairy may appear frail as the breeze and delicate as a bloom, but it is strong.`, + }, + "victory": { + 1: "I hope that you will find things worth smiling about tomorrow…" + }, + "defeat": { + 1: "Oh goodness, what a pity…" + } + }, + "wulfric": { + "encounter": { + 1: `You know what? We all talk big about what you learn from battling and bonds and all that… + $But really, I just do it 'cause it's fun. + $Who cares about the grandstanding? Let's get to battling!`, + }, + "victory": { + 1: "Outstanding! I'm tough as an iceberg, but you smashed me through and through!" + }, + "defeat": { + 1: "Tussle with me and this is what happens!" + } + }, + "kabu": { + "encounter": { + 1: `Every Trainer and Pokémon trains hard in pursuit of victory. + $But that means your opponent is also working hard to win. + $In the end, the match is decided by which side is able to unleash their true potential.`, + }, + "victory": { + 1: "I'm glad I could battle you today!" + }, + "defeat": { + 1: "That's a great way for me to feel my own growth!" + } + }, + "bea": { + "encounter": { + 1: `Do you have an unshakable spirit that won't be moved, no matter how you are attacked? + $I think I'll just test that out, shall I?`, + }, + "victory": { + 1: "I felt the fighting spirit of your Pokémon as you led them in battle." + }, + "defeat": { + 1: "That was the best sort of match anyone could ever hope for." + } + }, + "opal": { + "encounter": { + 1: "Let me have a look at how you and your partner Pokémon behave!" + }, + "victory": { + 1: "Your pink is still lacking, but you're an excellent Trainer with excellent Pokémon." + }, + "defeat": { + 1: "Too bad for you, I guess." + } + }, + "bede": { + "encounter": { + 1: "I suppose I should prove beyond doubt just how pathetic you are and how strong I am." + }, + "victory": { + 1: "I see… Well, that's fine. I wasn't really trying all that hard anyway." + }, + "defeat": { + 1: "Not a bad job, I suppose." + } + }, + "gordie": { + "encounter": { + 1: "So, let's get this over with." + }, + "victory": { + 1: "I just want to climb into a hole… Well, I guess it'd be more like falling from here." + }, + "defeat": { + 1: "Battle like you always do, victory will follow!" + } + }, + "marnie": { + "encounter": { + 1: `The truth is, when all's said and done… I really just wanna become Champion for myself! + $So don't take it personal when I kick your butt!`, + }, + "victory": { + 1: "OK, so I lost… But I got to see a lot of the good points of you and your Pokémon!" + }, + "defeat": { + 1: "Hope you enjoyed our battle tactics." + } + }, + "raihan": { + "encounter": { + 1: "I'm going to defeat the Champion, win the whole tournament, and prove to the world just how strong the great Raihan really is!" + }, + "victory": { + 1: `I look this good even when I lose. + $It's a real curse. + $Guess it's time for another selfie!`, + }, + "defeat": { + 1: "Let's take a selfie to remember this." + } + }, + "brassius": { + "encounter": { + 1: "I assume you are ready? Let our collaborative work of art begin!" + }, + "victory": { + 1: "Ahhh…vant-garde!" + }, + "defeat": { + 1: "I will begin on a new piece at once!" + } + }, + "iono": { + "encounter": { + 1: `How're ya feelin' about this battle? + $... + $Let's get this show on the road! How strong is our challenger? + $I 'unno! Let's find out together!`, + }, + "victory": { + 1: "You're as flashy and bright as a 10,000,000-volt Thunderbolt, friendo!" + }, + "defeat": { + 1: "Your eyeballs are MINE!" + } + }, + "larry": { + "encounter": { + 1: "When all's said and done, simplicity is strongest." + }, + "victory": { + 1: "A serving of defeat, huh?" + }, + "defeat": { + 1: "I'll call it a day." + } + }, + "ryme": { + "encounter": { + 1: "Come on, baby! Rattle me down to the bone!" + }, + "victory": { + 1: "You're cool, my friend—you move my SOUL!" + }, + "defeat": { + 1: "Later, baby!" + } + }, + "grusha": { + "encounter": { + 1: "All I need to do is make sure the power of my Pokémon chills you to the bone!" + }, + "victory": { + 1: "Your burning passion… I kinda like it, to be honest." + }, + "defeat": { + 1: "Things didn't heat up for you." + } + }, + "marnie_elite": { + "encounter": { + 1: "You've made it this far, huh? Let's see if you can handle my Pokémon!", + 2: "I'll give it my best shot, but don't think I'll go easy on you!" + }, + "victory": { + 1: "I can't believe I lost... But you deserved that win. Well done!", + 2: "Looks like I've still got a lot to learn. Great battle, though!" + }, + "defeat": { + 1: "You put up a good fight, but I've got the edge! Better luck next time!", + 2: "Seems like my training's paid off. Thanks for the battle!" + } + }, + "nessa_elite": { + "encounter": { + 1: "The tides are turning in my favor. Ready to get swept away?", + 2: "Let's make some waves with this battle! I hope you're prepared!" + }, + "victory": { + 1: "You navigated those waters perfectly... Well done!", + 2: "Looks like my currents were no match for you. Great job!" + }, + "defeat": { + 1: "Water always finds a way. That was a refreshing battle!", + 2: "You fought well, but the ocean's power is unstoppable!" + } + }, + "bea_elite": { + "encounter": { + 1: "Prepare yourself! My fighting spirit burns bright!", + 2: "Let's see if you can keep up with my relentless pace!" + }, + "victory": { + 1: "Your strength... It's impressive. You truly deserve this win.", + 2: "I've never felt this intensity before. Amazing job!" + }, + "defeat": { + 1: "Another victory for my intense training regimen! Well done!", + 2: "You've got strength, but I trained harder. Great battle!" + } + }, + "allister_elite": { + "encounter": { + 1: "Shadows fall... Are you ready to face your fears?", + 2: "Let's see if you can handle the darkness that I command." + }, + "victory": { + 1: "You've dispelled the shadows... For now. Well done.", + 2: "Your light pierced through my darkness. Great job." + }, + "defeat": { + 1: "The shadows have spoken... Your strength isn't enough.", + 2: "Darkness triumphs... Maybe next time you'll see the light." + } + }, + "raihan_elite": { + "encounter": { + 1: "Storm's brewing! Let's see if you can weather this fight!", + 2: "Get ready to face the eye of the storm!" + }, + "victory": { + 1: "You've bested the storm... Incredible job!", + 2: "You rode the winds perfectly... Great battle!" + }, + "defeat": { + 1: "Another storm weathered, another victory claimed! Well fought!", + 2: "You got caught in my storm! Better luck next time!" + } + }, + "alder": { + "encounter": { + 1: "Prepare yourself for a match against the strongest Trainer in Unova!" + }, + "victory": { + 1: "Well done! You certainly are an unmatched talent." + }, + "defeat": { + 1: `A fresh wind blows through my heart... + $What an extraordinary effort!` + } + }, + "kieran": { + "encounter": { + 1: `Through hard work, I become stronger and stronger! + $I don't lose.` + }, + "victory": { + 1: `I don't believe it... + $What a fun and heart-pounding battle!` + }, + "defeat": { + 1: `Wowzers, what a battle! + $Time for you to train even harder.` + } + }, + "rival": { + "encounter": { + 1: `@c{smile}Hey, I was looking for you! I knew you were eager to get going but I expected at least a goodbye… + $@c{smile_eclosed}So you're really pursuing your dream after all?\n I almost can't believe it. + $@c{serious_smile_fists}Since we're here, how about a battle?\nAfter all, I want to make sure you're ready. + $@c{serious_mopen_fists}Don't hold back, I want you to give me everything you've got!` + }, + "victory": { + 1: `@c{shock}Wow… You cleaned me out.\nAre you actually a beginner? + $@c{smile}Maybe it was a bit of luck but…\nWho knows you might just be able to go all the way. + $By the way, the professor asked me to give you these items. They look pretty cool. + $@c{serious_smile_fists}Good luck out there!` + }, + }, + "rival_female": { + "encounter": { + 1: `@c{smile_wave}There you are! I've been looking everywhere for you!\n@c{angry_mopen}Did you forget to say goodbye to your best friend? + $@c{smile_ehalf}You're going after your dream, huh?\nThat day is really today isn't it… + $@c{smile}Anyway, I'll forgive you for forgetting me, but on one condition. @c{smile_wave_wink}You have to battle me! + $@c{angry_mopen}Give it your all! Wouldn't want your adventure to be over before it started, right?` + }, + "victory": { + 1: `@c{shock}You just started and you're already this strong?!@d{96}\n@c{angry}You totally cheated, didn't you? + $@c{smile_wave_wink}Just kidding!@d{64} @c{smile_eclosed}I lost fair and square… I have a feeling you're going to do really well out there. + $@c{smile}By the way, the professor wanted me to give you some items. Hopefully they're helpful! + $@c{smile_wave}Do your best like always! I believe in you!` + }, + }, + "rival_2": { + "encounter": { + 1: `@c{smile}Hey, you're here too?\n@c{smile_eclosed}Still a perfect record, huh…? + $@c{serious_mopen_fists}I know it kind of looks like I followed you here, but that's mostly not true. + $@c{serious_smile_fists}Honestly though, I've been itching for a rematch since you beat me back at home. + $I've been doing a lot of my own training so I'll definitely put up a fight this time. + $@c{serious_mopen_fists}Don't hold back, just like before!\nLet's go!` + }, + "victory": { + 1: `@c{neutral_eclosed}Oh. I guess I was overconfident. + $@c{smile}That's alright, though. I figured this might happen.\n@c{serious_mopen_fists}It just means I need to try harder for next time!\n + $@c{smile}Oh, not that you really need the help, but I had an extra one of these lying around and figured you might want it.\n + $@c{serious_smile_fists}Don't expect another one after this, though!\nI can't keep giving my opponent an advantage after all. + $@c{smile}Anyway, take care!` + }, + }, + "rival_2_female": { + "encounter": { + 1: `@c{smile_wave}Oh, fancy meeting you here. Looks like you're still undefeated. @c{angry_mopen}Huh… Not bad! + $@c{angry_mopen}I know what you're thinking, and no, I wasn't creeping on you. @c{smile_eclosed}I just happened to be in the area. + $@c{smile_ehalf}I'm happy for you but I just want to let you know that it's OK to lose sometimes. + $@c{smile}We learn from our mistakes, often more than we would if we kept succeeding. + $@c{angry_mopen}In any case, I've been training hard for our rematch, so you'd better give it your all!` + }, + "victory": { + 1: `@c{neutral}I… wasn't supposed to lose that time… + $@c{smile}Aw well. That just means I'll have to train even harder for next time! + $@c{smile_wave}I also got you another one of these!\n@c{smile_wave_wink}No need to thank me~. + $@c{angry_mopen}This is the last one, though! You won't be getting anymore freebies from me after this! + $@c{smile_wave}Keep at it!` + }, + "defeat": { + 1: "It's OK to lose sometimes…" + } + }, + "rival_3": { + "encounter": { + 1: `@c{smile}Hey, look who it is! It's been a while.\n@c{neutral}You're… still undefeated? Huh. + $@c{neutral_eclosed}Things have been kind of… strange.\nIt's not the same back home without you. + $@c{serious}I know it's selfish, but I need to get this off my chest.\n@c{neutral_eclosed}I think you're in over your head here. + $@c{serious}Never losing once is just unrealistic.\nWe need to lose sometimes in order to grow. + $@c{neutral_eclosed}You've had a great run but there's still so much ahead, and it only gets harder. @c{neutral}Are you prepared for that? + $@c{serious_mopen_fists}If so, prove it to me.` + }, + "victory": { + 1: "@c{angry_mhalf}This is ridiculous… I've hardly stopped training…\nHow are we still so far apart?" + }, + }, + "rival_3_female": { + "encounter": { + 1: `@c{smile_wave}Long time no see! Still haven't lost, huh.\n@c{angry}You're starting to get on my nerves. @c{smile_wave_wink}Just kidding! + $@c{smile_ehalf}But really, don't you miss home by now? Or… me?\nI… I mean, we've really missed you. + $@c{smile_eclosed}I support you in your dream and everything, but the reality is you're going to lose sooner or later. + $@c{smile}And when you do, I'll be there for you like always.\n@c{angry_mopen}Now, let me show you how strong I've become!` + }, + "victory": { + 1: "@c{shock}After all that… it wasn't enough…?\nYou'll never come back at this rate…" + + }, + "defeat": { + 1: "You gave it your best, now let's go home." + } + }, + "rival_4": { + "encounter": { + 1: `@c{neutral}Hey. + $I won't mince words or pleasantries with you.\n@c{neutral_eclosed}I'm here to win, plain and simple. + $@c{serious_mhalf_fists}I've learned to maximize my potential by putting all my time into training. + $@c{smile}You get a lot of extra time when you cut out the unnecessary sleep and social interaction. + $@c{serious_mopen_fists}None of that matters anymore, not until I win. + $@c{neutral_eclosed}I've even reached the point where I don't lose anymore.\n@c{smile_eclosed}I suppose your philosophy wasn't so wrong after all. + $@c{angry_mhalf}Losing is for the weak, and I'm not weak anymore. + $@c{serious_mopen_fists}Prepare yourself.` + }, + "victory": { + 1: "@c{neutral}What…@d{64} What are you?" + }, + }, + "rival_4_female": { + "encounter": { + 1: `@c{neutral}It's me! You didn't forget about me again… did you? + $@c{smile}You should be proud of how far you made it. Congrats!\nBut it looks like it's the end of your journey. + $@c{smile_eclosed}You've awoken something in me I never knew was there.\nIt seems like all I do now is train. + $@c{smile_ehalf}I hardly even eat or sleep now, I just train my Pokémon all day, getting stronger every time. + $@c{neutral}In fact, I… hardly recognize myself. + $And now, I've finally reached peak performance.\nI don't think anyone could beat me now. + $And you know what? It's all because of you.\n@c{smile_ehalf}I don't know whether to thank you or hate you. + $@c{angry_mopen}Prepare yourself.` + }, + "victory": { + 1: "@c{neutral}What…@d{64} What are you?" + + }, + "defeat": { + 1: "$@c{smile}You should be proud of how far you made it." + } + }, + "rival_5": { + "encounter": { + 1: "@c{neutral}…" + }, + "victory": { + 1: "@c{neutral}…" + }, + }, + "rival_5_female": { + "encounter": { + 1: "@c{neutral}…" + }, + "victory": { + 1: "@c{neutral}…" + + }, + "defeat": { + 1: "$@c{smile_ehalf}…" + } + }, + "rival_6": { + "encounter": { + 1: `@c{smile_eclosed}We meet again. + $@c{neutral}I've had some time to reflect on all this.\nThere's a reason this all seems so strange. + $@c{neutral_eclosed}Your dream, my drive to beat you…\nIt's all a part of something greater. + $@c{serious}This isn't about me, or about you… This is about the world, @c{serious_mhalf_fists}and it's my purpose to push you to your limits. + $@c{neutral_eclosed}Whether I've fulfilled that purpose I can't say, but I've done everything in my power. + $@c{neutral}This place we ended up in is terrifying… Yet somehow I feel unphased, like I've been here before. + $@c{serious_mhalf_fists}You feel the same, don't you? + $@c{serious}…and it's like something here is speaking to me.\nThis is all the world's known for a long time now. + $Those times we cherished together that seem so recent are nothing but a distant memory. + $@c{neutral_eclosed}Who can say whether they were ever even real in the first place. + $@c{serious_mopen_fists}You need to keep pushing, because if you don't, it will never end. You're the only one who can do this. + $@c{serious_smile_fists}I hardly know what any of this means, I just know that it's true. + $@c{serious_mopen_fists}If you can't defeat me here and now, you won't stand a chance.` + }, + "victory": { + 1: `@c{smile_eclosed}It looks like my work is done here. + $I want you to promise me one thing.\n@c{smile}After you heal the world, please come home.` + }, + }, + "rival_6_female": { + "encounter": { + 1: `@c{smile_ehalf}So it's just us again. + $@c{smile_eclosed}You know, I keep going around and around in my head… + $@c{smile_ehalf}There's something to all this, why everything seems so strange now… + $@c{smile}You have your dream, and I have this ambition in me… + $I just can't help but feel there's a greater purpose to all this, to what we're doing, you and I. + $@c{smile_eclosed}I think I'm supposed to push you… to your limits. + $@c{smile_ehalf}I'm not sure if I've been doing a good job at that, but I've tried my best up to now. + $It's something about this strange and dreadful place… Everything seems so clear… + $This… is all the world's known for a long time now. + $@c{smile_eclosed}It's like I can barely remember the memories we cherished together. + $@c{smile_ehalf}Were they even real? They seem so far away now… + $@c{angry_mopen}You need to keep pushing, because if you don't, it will never end. You're the only one who can do this. + $@c{smile_ehalf}I… don't know what all this means… but I feel it's true. + $@c{neutral}If you can't defeat me here and now, you won't stand a chance.` + }, + "victory": { + 1: `@c{smile_ehalf}I… I think I fulfilled my purpose… + $@c{smile_eclosed}Promise me… After you heal the world… Please… come home safe. + $@c{smile_ehalf}…Thank you.` + + }, + }, +}; + + +// 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 = PGMdialogue; + +// Dialogue of the endboss of the game when the player character is male (Or unset) +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. + $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? + $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.`, + "secondStageWin": "…Magnificent." +}; + +// 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 = PGMbattleSpecDialogue; + +// 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}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? + $@c{serious_smile_fists}Your legend will always live on in our hearts. + $@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{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! + $@c{smile_wave_wink}Just kidding!@d{64} @c{smile}I'd never forget.@d{32}\nYour legend will live on in our hearts. + $@c{smile_wave}Anyway,@d{64} it's getting late…@d{96} I think?\nIt's hard to tell in this place. + $Let's go home. @c{smile_wave_wink}Maybe tomorrow, we can have another battle, for old time's sake?`, + "ending_endless": "Congratulations on reaching the current end!\nMore content is coming soon.", + "ending_name": "Devs" +}; +// 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 = PGMmiscDialogue; + + +// 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": { + 1: `Blue: Hey Red, let's show them what we're made of! + $Red: ... + $Blue: This is Pallet Town Power!`, + }, + "victory": { + 1: `Blue: That was a great battle! + $Red: ...`, + }, + }, + "red_blue_double": { + "encounter": { + 1: `Red: ...! + $Blue: He never talks much. + $Blue: But dont let that fool you! He is a champ after all!`, + }, + "victory": { + 1: `Red: ...! + $Blue: Next time we will beat you!`, + }, + }, + "tate_liza_double": { + "encounter": { + 1: `Tate: Are you surprised? + $Liza: We are two gym leaders at once! + $Tate: We are twins! + $Liza: We dont need to talk to understand each other! + $Tate: Twice the power... + $Liza: Can you handle it?`, + }, + "victory": { + 1: `Tate: What? Our combination was perfect! + $Liza: Looks like we need to train more...`, + }, + }, + "liza_tate_double": { + "encounter": { + 1: `Liza: Hihihi... Are you surprised? + $Tate: Yes, we are really two gym leaders at once! + $Liza: This is my twin brother Tate! + $Tate: And this is my twin sister Liza! + $Liza: Don't you think we are a perfect combination?` + }, + "victory": { + 1: `Liza: Are we... + $Tate: ...not as strong as we thought?`, + }, + }, + "wallace_steven_double": { + "encounter": { + 1: `Steven: Wallace, let's show them the power of the champions! + $Wallace: We will show you the power of Hoenn! + $Steven: Let's go!`, + }, + "victory": { + 1: `Steven: That was a great battle! + $Wallace: We will win next time!`, + }, + }, + "steven_wallace_double": { + "encounter": { + 1: `Steven: Do you have any rare Pokémon? + $Wallace: Steven... We are here for a battle, not to show off our Pokémon. + $Steven: Oh... I see... Let's go then!`, + }, + "victory": { + 1: `Steven: Now that we are done with the battle, let's show off our Pokémon! + $Wallace: Steven...`, + }, + }, + "alder_iris_double": { + "encounter": { + 1: `Alder: We are the strongest trainers in Unova! + $Iris: Fights against strong trainers are the best!`, + }, + "victory": { + 1: `Alder: Wow! You are super strong! + $Iris: We will win next time!`, + }, + }, + "iris_alder_double": { + "encounter": { + 1: `Iris: Welcome Challenger! I am THE Unova Champion! + $Alder: Iris, aren't you a bit too excited?`, + }, + "victory": { + 1: `Iris: A loss like this is not easy to take... + $Alder: But we will only get stronger with every loss!`, + }, + }, + "piers_marnie_double": { + "encounter": { + 1: `Marnie: Brother, let's show them the power of Spikemuth! + $Piers: We bring darkness!`, + }, + "victory": { + 1: `Marnie: You brought light to our darkness! + $Piers: Its too bright...`, + }, + }, + "marnie_piers_double": { + "encounter": { + 1: `Piers: Ready for a concert? + $Marnie: Brother... They are here to fight, not to sing...`, + }, + "victory": { + 1: `Piers: Now that was a great concert! + $Marnie: Brother...`, + }, + }, +}; + +// Dialogue of the named double battles in the game. For when the player is female. For languages that do not have gendered pronouns, this can be set to PGMdoubleBattleDialogue. +export const PGFdoubleBattleDialogue: DialogueTranslationEntries = PGMdoubleBattleDialogue; diff --git a/src/locales/ca-ES/egg.ts b/src/locales/ca-ES/egg.ts new file mode 100644 index 00000000000..9f699ce0fdc --- /dev/null +++ b/src/locales/ca-ES/egg.ts @@ -0,0 +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!", + "legendaryUPGacha": "UP!", +} as const; diff --git a/src/locales/ca-ES/fight-ui-handler.ts b/src/locales/ca-ES/fight-ui-handler.ts new file mode 100644 index 00000000000..8ceb503c34a --- /dev/null +++ b/src/locales/ca-ES/fight-ui-handler.ts @@ -0,0 +1,9 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +export const fightUiHandler: SimpleTranslationEntries = { + "pp": "PP", + "power": "Power", + "accuracy": "Accuracy", + "abilityFlyInText": " {{pokemonName}}'s {{passive}}{{abilityName}}", + "passive": "Passive ", // The space at the end is important +} as const; diff --git a/src/locales/ca-ES/filter-bar.ts b/src/locales/ca-ES/filter-bar.ts new file mode 100644 index 00000000000..7a3174957ea --- /dev/null +++ b/src/locales/ca-ES/filter-bar.ts @@ -0,0 +1,33 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +export const filterBar: SimpleTranslationEntries = { + "genFilter": "Gen", + "typeFilter": "Type", + "caughtFilter": "Caught", + "unlocksFilter": "Unlocks", + "miscFilter": "Misc", + "sortFilter": "Sort", + "all": "All", + "normal": "Normal", + "uncaught": "Uncaught", + "passive": "Passive", + "passiveUnlocked": "Passive Unlocked", + "passiveLocked": "Passive Locked", + "costReduction": "Cost Reduction", + "costReductionUnlocked": "Cost Reduction Unlocked", + "costReductionLocked": "Cost Reduction Locked", + "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", + "sortByIVs": "IVs", + "sortByName": "Name", +}; diff --git a/src/locales/ca-ES/game-mode.ts b/src/locales/ca-ES/game-mode.ts new file mode 100644 index 00000000000..903f1a63072 --- /dev/null +++ b/src/locales/ca-ES/game-mode.ts @@ -0,0 +1,10 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +export const gameMode: SimpleTranslationEntries = { + "classic": "Classic", + "endless": "Endless", + "endlessSpliced": "Endless (Spliced)", + "dailyRun": "Daily Run", + "unknown": "Unknown", + "challenge": "Challenge", +} as const; diff --git a/src/locales/ca-ES/game-stats-ui-handler.ts b/src/locales/ca-ES/game-stats-ui-handler.ts new file mode 100644 index 00000000000..a29eaf5d1b6 --- /dev/null +++ b/src/locales/ca-ES/game-stats-ui-handler.ts @@ -0,0 +1,44 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +export const gameStatsUiHandler: SimpleTranslationEntries = { + "stats": "Stats", + "playTime": "Play Time", + "totalBattles": "Total Battles", + "starters": "Starters", + "shinyStarters": "Shiny Starters", + "speciesSeen": "Species Seen", + "speciesCaught": "Species Caught", + "ribbonsOwned": "Ribbons Owned", + "classicRuns": "Classic Runs", + "classicWins": "Classic Wins", + "dailyRunAttempts": "Daily Run Attempts", + "dailyRunWins": "Daily Run Wins", + "endlessRuns": "Endless Runs", + "highestWaveEndless": "Highest Wave (Endless)", + "highestMoney": "Highest Money", + "highestDamage": "Highest Damage", + "highestHPHealed": "Highest HP Healed", + "pokemonEncountered": "Pokémon Encountered", + "pokemonDefeated": "Pokémon Defeated", + "pokemonCaught": "Pokémon Caught", + "eggsHatched": "Eggs Hatched", + "subLegendsSeen": "Sub-Legends Seen", + "subLegendsCaught": "Sub-Legends Caught", + "subLegendsHatched": "Sub-Legends Hatched", + "legendsSeen": "Legends Seen", + "legendsCaught": "Legends Caught", + "legendsHatched": "Legends Hatched", + "mythicalsSeen": "Mythicals Seen", + "mythicalsCaught": "Mythicals Caught", + "mythicalsHatched": "Mythicals Hatched", + "shiniesSeen": "Shinies Seen", + "shiniesCaught": "Shinies Caught", + "shiniesHatched": "Shinies Hatched", + "pokemonFused": "Pokémon Fused", + "trainersDefeated": "Trainers Defeated", + "eggsPulled": "Eggs Pulled", + "rareEggsPulled": "Rare Eggs Pulled", + "epicEggsPulled": "Epic Eggs Pulled", + "legendaryEggsPulled": "Legendary Eggs Pulled", + "manaphyEggsPulled": "Manaphy Eggs Pulled", +} as const; diff --git a/src/locales/ca-ES/growth.ts b/src/locales/ca-ES/growth.ts new file mode 100644 index 00000000000..410355b143b --- /dev/null +++ b/src/locales/ca-ES/growth.ts @@ -0,0 +1,10 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +export const growth: SimpleTranslationEntries = { + "Erratic": "Erratic", + "Fast": "Fast", + "Medium_Fast": "Medium Fast", + "Medium_Slow": "Medium Slow", + "Slow": "Slow", + "Fluctuating": "Fluctuating" +} as const; diff --git a/src/locales/ca-ES/menu-ui-handler.ts b/src/locales/ca-ES/menu-ui-handler.ts new file mode 100644 index 00000000000..6eb680544ed --- /dev/null +++ b/src/locales/ca-ES/menu-ui-handler.ts @@ -0,0 +1,28 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +export const menuUiHandler: SimpleTranslationEntries = { + "GAME_SETTINGS": "Game Settings", + "ACHIEVEMENTS": "Achievements", + "STATS": "Stats", + "VOUCHERS": "Vouchers", + "EGG_LIST": "Egg List", + "EGG_GACHA": "Egg Gacha", + "MANAGE_DATA": "Manage Data", + "COMMUNITY": "Community", + "SAVE_AND_QUIT": "Save and Quit", + "LOG_OUT": "Log Out", + "slot": "Slot {{slotNumber}}", + "importSession": "Import Session", + "importSlotSelect": "Select a slot to import to.", + "exportSession": "Export Session", + "exportSlotSelect": "Select a slot to export from.", + "importData": "Import Data", + "exportData": "Export Data", + "linkDiscord": "Link Discord", + "unlinkDiscord": "Unlink Discord", + "linkGoogle": "Link Google", + "unlinkGoogle": "Unlink Google", + "cancel": "Cancel", + "losingProgressionWarning": "You will lose any progress since the beginning of the battle. Proceed?", + "noEggs": "You are not hatching\nany eggs at the moment!" +} as const; diff --git a/src/locales/ca-ES/menu.ts b/src/locales/ca-ES/menu.ts new file mode 100644 index 00000000000..fe4d96c5120 --- /dev/null +++ b/src/locales/ca-ES/menu.ts @@ -0,0 +1,62 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +/** + * The menu namespace holds most miscellaneous text that isn't directly part of the game's + * contents or directly related to Pokemon data. This includes menu navigation, settings, + * account interactions, descriptive text, etc. + */ +export const menu: SimpleTranslationEntries = { + "cancel": "Cancel", + "continue": "Continue", + "dailyRun": "Daily Run (Beta)", + "loadGame": "Load Game", + "newGame": "New Game", + "settings": "Settings", + "selectGameMode": "Select a game mode.", + "logInOrCreateAccount": "Log in or create an account to start. No email required!", + "username": "Username", + "password": "Password", + "login": "Login", + "orUse": "Or use", + "register": "Register", + "emptyUsername": "Username must not be empty", + "invalidLoginUsername": "The provided username is invalid", + "invalidRegisterUsername": "Username must only contain letters, numbers, or underscores", + "invalidLoginPassword": "The provided password is invalid", + "invalidRegisterPassword": "Password must be 6 characters or longer", + "usernameAlreadyUsed": "The provided username is already in use", + "accountNonExistent": "The provided user does not exist", + "unmatchingPassword": "The provided password does not match", + "passwordNotMatchingConfirmPassword": "Password must match confirm password", + "confirmPassword": "Confirm Password", + "registrationAgeWarning": "By registering, you confirm you are of 13 years of age or older.", + "backToLogin": "Back to Login", + "failedToLoadSaveData": "Failed to load save data. Please reload the page.\nIf this persists, please check #announcements in Discord.", + "sessionSuccess": "Session loaded successfully.", + "failedToLoadSession": "Your session data could not be loaded.\nIt may be corrupted.", + "boyOrGirl": "Are you a boy or a girl?", + "evolving": "What?\n{{pokemonName}} is evolving!", + "stoppedEvolving": "{{pokemonName}} stopped evolving.", + "pauseEvolutionsQuestion": "Would you like to pause evolutions for {{pokemonName}}?\nEvolutions can be re-enabled from the party screen.", + "evolutionsPaused": "Evolutions have been paused for {{pokemonName}}.", + "evolutionDone": "Congratulations!\nYour {{pokemonName}} evolved into {{evolvedPokemonName}}!", + "dailyRankings": "Daily Rankings", + "weeklyRankings": "Weekly Rankings", + "noRankings": "No Rankings", + "positionIcon": "#", + "usernameScoreboard": "Username", + "score": "Score", + "wave": "Wave", + "loading": "Loading…", + "loadingAsset": "Loading asset: {{assetName}}", + "playersOnline": "Players Online", + "yes":"Yes", + "no":"No", + "disclaimer": "DISCLAIMER", + "disclaimerDescription": "This game is an unfinished product; it might have playability issues (including the potential loss of save data),\n change without notice, and may or may not be updated further or completed.", + "choosePokemon": "Choose a Pokémon.", + "renamePokemon": "Rename Pokémon", + "rename": "Rename", + "nickname": "Nickname", + "errorServerDown": "Oops! There was an issue contacting the server.\n\nYou may leave this window open,\nthe game will automatically reconnect.", +} as const; diff --git a/src/locales/ca-ES/modifier-select-ui-handler.ts b/src/locales/ca-ES/modifier-select-ui-handler.ts new file mode 100644 index 00000000000..75299a08ba7 --- /dev/null +++ b/src/locales/ca-ES/modifier-select-ui-handler.ts @@ -0,0 +1,14 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +export const modifierSelectUiHandler: SimpleTranslationEntries = { + "transfer": "Transfer", + "reroll": "Reroll", + "lockRarities": "Lock Rarities", + "checkTeam": "Check Team", + "transferDesc": "Transfer a held item from one Pokémon to another.", + "rerollDesc": "Spend money to reroll your item options.", + "lockRaritiesDesc": "Lock item rarities on reroll (affects reroll cost).", + "checkTeamDesc": "Check your team or use a form changing item.", + "rerollCost": "₽{{formattedMoney}}", + "itemCost": "₽{{formattedMoney}}" +} as const; diff --git a/src/locales/ca-ES/modifier-type.ts b/src/locales/ca-ES/modifier-type.ts new file mode 100644 index 00000000000..c6c98e44a92 --- /dev/null +++ b/src/locales/ca-ES/modifier-type.ts @@ -0,0 +1,456 @@ +import { ModifierTypeTranslationEntries } from "#app/interfaces/locales"; + +export const modifierType: ModifierTypeTranslationEntries = { + ModifierType: { + "AddPokeballModifierType": { + name: "{{modifierCount}}x {{pokeballName}}", + description: "Receive {{pokeballName}} x{{modifierCount}} (Inventory: {{pokeballAmount}}) \nCatch Rate: {{catchRate}}", + }, + "AddVoucherModifierType": { + name: "{{modifierCount}}x {{voucherTypeName}}", + description: "Receive {{voucherTypeName}} x{{modifierCount}}.", + }, + "PokemonHeldItemModifierType": { + extra: { + "inoperable": "{{pokemonName}} can't take\nthis item!", + "tooMany": "{{pokemonName}} has too many\nof this item!", + } + }, + "PokemonHpRestoreModifierType": { + description: "Restores {{restorePoints}} HP or {{restorePercent}}% HP for one Pokémon, whichever is higher.", + extra: { + "fully": "Fully restores HP for one Pokémon.", + "fullyWithStatus": "Fully restores HP for one Pokémon and heals any status ailment.", + } + }, + "PokemonReviveModifierType": { + description: "Revives one Pokémon and restores {{restorePercent}}% HP.", + }, + "PokemonStatusHealModifierType": { + description: "Heals any status ailment for one Pokémon.", + }, + "PokemonPpRestoreModifierType": { + description: "Restores {{restorePoints}} PP for one Pokémon move.", + extra: { + "fully": "Restores all PP for one Pokémon move.", + } + }, + "PokemonAllMovePpRestoreModifierType": { + description: "Restores {{restorePoints}} PP for all of one Pokémon's moves.", + extra: { + "fully": "Restores all PP for all of one Pokémon's moves.", + } + }, + "PokemonPpUpModifierType": { + description: "Permanently increases PP for one Pokémon move by {{upPoints}} for every 5 maximum PP (maximum 3).", + }, + "PokemonNatureChangeModifierType": { + name: "{{natureName}} Mint", + description: "Changes a Pokémon's nature to {{natureName}} and permanently unlocks the nature for the starter.", + }, + "DoubleBattleChanceBoosterModifierType": { + description: "Doubles the chance of an encounter being a double battle for {{battleCount}} battles.", + }, + "TempBattleStatBoosterModifierType": { + description: "Increases the {{tempBattleStatName}} of all party members by 1 stage for 5 battles.", + }, + "AttackTypeBoosterModifierType": { + description: "Increases the power of a Pokémon's {{moveType}}-type moves by 20%.", + }, + "PokemonLevelIncrementModifierType": { + description: "Increases a Pokémon's level by {{levels}}.", + }, + "AllPokemonLevelIncrementModifierType": { + description: "Increases all party members' level by {{levels}}.", + }, + "PokemonBaseStatBoosterModifierType": { + description: "Increases the holder's base {{statName}} by 10%. The higher your IVs, the higher the stack limit.", + }, + "AllPokemonFullHpRestoreModifierType": { + description: "Restores 100% HP for all Pokémon.", + }, + "AllPokemonFullReviveModifierType": { + description: "Revives all fainted Pokémon, fully restoring HP.", + }, + "MoneyRewardModifierType": { + description: "Grants a {{moneyMultiplier}} amount of money (₽{{moneyAmount}}).", + extra: { + "small": "small", + "moderate": "moderate", + "large": "large", + }, + }, + "ExpBoosterModifierType": { + description: "Increases gain of EXP. Points by {{boostPercent}}%.", + }, + "PokemonExpBoosterModifierType": { + description: "Increases the holder's gain of EXP. Points by {{boostPercent}}%.", + }, + "PokemonFriendshipBoosterModifierType": { + description: "Increases friendship gain per victory by 50%.", + }, + "PokemonMoveAccuracyBoosterModifierType": { + description: "Increases move accuracy by {{accuracyAmount}} (maximum 100).", + }, + "PokemonMultiHitModifierType": { + description: "Attacks hit one additional time at the cost of a 60/75/82.5% power reduction per stack respectively.", + }, + "TmModifierType": { + name: "TM{{moveId}} - {{moveName}}", + description: "Teach {{moveName}} to a Pokémon.", + }, + "TmModifierTypeWithInfo": { + name: "TM{{moveId}} - {{moveName}}", + description: "Teach {{moveName}} to a Pokémon\n(Hold C or Shift for more info).", + }, + "EvolutionItemModifierType": { + description: "Causes certain Pokémon to evolve.", + }, + "FormChangeItemModifierType": { + description: "Causes certain Pokémon to change form.", + }, + "FusePokemonModifierType": { + description: "Combines two Pokémon (transfers Ability, splits base stats and types, shares move pool).", + }, + "TerastallizeModifierType": { + name: "{{teraType}} Tera Shard", + description: "{{teraType}} Terastallizes the holder for up to 10 battles.", + }, + "ContactHeldItemTransferChanceModifierType": { + description: "Upon attacking, there is a {{chancePercent}}% chance the foe's held item will be stolen.", + }, + "TurnHeldItemTransferModifierType": { + description: "Every turn, the holder acquires one held item from the foe.", + }, + "EnemyAttackStatusEffectChanceModifierType": { + description: "Adds a {{chancePercent}}% chance to inflict {{statusEffect}} with attack moves.", + }, + "EnemyEndureChanceModifierType": { + description: "Adds a {{chancePercent}}% chance of enduring a hit.", + }, + + "RARE_CANDY": { name: "Rare Candy" }, + "RARER_CANDY": { name: "Rarer Candy" }, + + "MEGA_BRACELET": { name: "Mega Bracelet", description: "Mega Stones become available." }, + "DYNAMAX_BAND": { name: "Dynamax Band", description: "Max Mushrooms become available." }, + "TERA_ORB": { name: "Tera Orb", description: "Tera Shards become available." }, + + "MAP": { name: "Map", description: "Allows you to choose your destination at a crossroads." }, + + "POTION": { name: "Potion" }, + "SUPER_POTION": { name: "Super Potion" }, + "HYPER_POTION": { name: "Hyper Potion" }, + "MAX_POTION": { name: "Max Potion" }, + "FULL_RESTORE": { name: "Full Restore" }, + + "REVIVE": { name: "Revive" }, + "MAX_REVIVE": { name: "Max Revive" }, + + "FULL_HEAL": { name: "Full Heal" }, + + "SACRED_ASH": { name: "Sacred Ash" }, + + "REVIVER_SEED": { name: "Reviver Seed", description: "Revives the holder for 1/2 HP upon fainting from a direct hit." }, + + "WHITE_HERB": { name: "White Herb", description: "An item to be held by a Pokémon. It will restore any lowered stat in battle." }, + + "ETHER": { name: "Ether" }, + "MAX_ETHER": { name: "Max Ether" }, + + "ELIXIR": { name: "Elixir" }, + "MAX_ELIXIR": { name: "Max Elixir" }, + + "PP_UP": { name: "PP Up" }, + "PP_MAX": { name: "PP Max" }, + + "LURE": { name: "Lure" }, + "SUPER_LURE": { name: "Super Lure" }, + "MAX_LURE": { name: "Max Lure" }, + + "MEMORY_MUSHROOM": { name: "Memory Mushroom", description: "Recall one Pokémon's forgotten move." }, + + "EXP_SHARE": { name: "EXP. All", description: "Non-participants receive 20% of a single participant's EXP. Points." }, + "EXP_BALANCE": { name: "EXP. Balance", description: "Weighs EXP. Points received from battles towards lower-leveled party members." }, + + "OVAL_CHARM": { name: "Oval Charm", description: "When multiple Pokémon participate in a battle, each gets an extra 10% of the total EXP." }, + + "EXP_CHARM": { name: "EXP. Charm" }, + "SUPER_EXP_CHARM": { name: "Super EXP. Charm" }, + "GOLDEN_EXP_CHARM": { name: "Golden EXP. Charm" }, + + "LUCKY_EGG": { name: "Lucky Egg" }, + "GOLDEN_EGG": { name: "Golden Egg" }, + + "SOOTHE_BELL": { name: "Soothe Bell" }, + + "SCOPE_LENS": { name: "Scope Lens", description: "It's a lens for scoping out weak points. It boosts the holder's critical-hit ratio."}, + "LEEK": { name: "Leek", description: "This very long and stiff stalk of leek boosts the critical-hit ratio of Farfetch'd's moves."}, + + "EVIOLITE": { name: "Eviolite", description: "This mysterious evolutionary lump boosts the Defense and Sp. Def stats when held by a Pokémon that can still evolve." }, + + "SOUL_DEW": { name: "Soul Dew", description: "Increases the influence of a Pokémon's nature on its stats by 10% (additive)." }, + + "NUGGET": { name: "Nugget" }, + "BIG_NUGGET": { name: "Big Nugget" }, + "RELIC_GOLD": { name: "Relic Gold" }, + + "AMULET_COIN": { name: "Amulet Coin", description: "Increases money rewards by 20%." }, + "GOLDEN_PUNCH": { name: "Golden Punch", description: "Grants 50% of direct damage inflicted as money." }, + "COIN_CASE": { name: "Coin Case", description: "After every 10th battle, receive 10% of your money in interest." }, + + "LOCK_CAPSULE": { name: "Lock Capsule", description: "Allows you to lock item rarities when rerolling items." }, + + "GRIP_CLAW": { name: "Grip Claw" }, + "WIDE_LENS": { name: "Wide Lens" }, + + "MULTI_LENS": { name: "Multi Lens" }, + + "HEALING_CHARM": { name: "Healing Charm", description: "Increases the effectiveness of HP restoring moves and items by 10% (excludes Revives)." }, + "CANDY_JAR": { name: "Candy Jar", description: "Increases the number of levels added by Rare Candy items by 1." }, + + "BERRY_POUCH": { name: "Berry Pouch", description: "Adds a 30% chance that a used berry will not be consumed." }, + + "FOCUS_BAND": { name: "Focus Band", description: "Adds a 10% chance to survive with 1 HP after being damaged enough to faint." }, + + "QUICK_CLAW": { name: "Quick Claw", description: "Adds a 10% chance to move first regardless of speed (after priority)." }, + + "KINGS_ROCK": { name: "King's Rock", description: "Adds a 10% chance an attack move will cause the opponent to flinch." }, + + "LEFTOVERS": { name: "Leftovers", description: "Heals 1/16 of a Pokémon's maximum HP every turn." }, + "SHELL_BELL": { name: "Shell Bell", description: "Heals 1/8 of a Pokémon's dealt damage." }, + + "TOXIC_ORB": { name: "Toxic Orb", description: "It's a bizarre orb that exudes toxins when touched and will badly poison the holder during battle." }, + "FLAME_ORB": { name: "Flame Orb", description: "It's a bizarre orb that gives off heat when touched and will affect the holder with a burn during battle." }, + + "BATON": { name: "Baton", description: "Allows passing along effects when switching Pokémon, which also bypasses traps." }, + + "SHINY_CHARM": { name: "Shiny Charm", description: "Dramatically increases the chance of a wild Pokémon being Shiny." }, + "ABILITY_CHARM": { name: "Ability Charm", description: "Dramatically increases the chance of a wild Pokémon having a Hidden Ability." }, + + "IV_SCANNER": { name: "IV Scanner", description: "Allows scanning the IVs of wild Pokémon. 2 IVs are revealed per stack. The best IVs are shown first." }, + + "DNA_SPLICERS": { name: "DNA Splicers" }, + + "MINI_BLACK_HOLE": { name: "Mini Black Hole" }, + + "GOLDEN_POKEBALL": { name: "Golden Poké Ball", description: "Adds 1 extra item option at the end of every battle." }, + + "ENEMY_DAMAGE_BOOSTER": { name: "Damage Token", description: "Increases damage by 5%." }, + "ENEMY_DAMAGE_REDUCTION": { name: "Protection Token", description: "Reduces incoming damage by 2.5%." }, + "ENEMY_HEAL": { name: "Recovery Token", description: "Heals 2% of max HP every turn." }, + "ENEMY_ATTACK_POISON_CHANCE": { name: "Poison Token" }, + "ENEMY_ATTACK_PARALYZE_CHANCE": { name: "Paralyze Token" }, + "ENEMY_ATTACK_BURN_CHANCE": { name: "Burn Token" }, + "ENEMY_STATUS_EFFECT_HEAL_CHANCE": { name: "Full Heal Token", description: "Adds a 2.5% chance every turn to heal a status condition." }, + "ENEMY_ENDURE_CHANCE": { name: "Endure Token" }, + "ENEMY_FUSED_CHANCE": { name: "Fusion Token", description: "Adds a 1% chance that a wild Pokémon will be a fusion." }, + }, + SpeciesBoosterItem: { + "LIGHT_BALL": { name: "Light Ball", description: "It's a mysterious orb that boosts Pikachu's Attack and Sp. Atk stats." }, + "THICK_CLUB": { name: "Thick Club", description: "This hard bone of unknown origin boosts Cubone or Marowak's Attack stat." }, + "METAL_POWDER": { name: "Metal Powder", description: "Extremely fine yet hard, this odd powder boosts Ditto's Defense stat." }, + "QUICK_POWDER": { name: "Quick Powder", description: "Extremely fine yet hard, this odd powder boosts Ditto's Speed stat." } + }, + TempBattleStatBoosterItem: { + "x_attack": "X Attack", + "x_defense": "X Defense", + "x_sp_atk": "X Sp. Atk", + "x_sp_def": "X Sp. Def", + "x_speed": "X Speed", + "x_accuracy": "X Accuracy", + "dire_hit": "Dire Hit", + }, + + TempBattleStatBoosterStatName: { + "ATK": "Attack", + "DEF": "Defense", + "SPATK": "Sp. Atk", + "SPDEF": "Sp. Def", + "SPD": "Speed", + "ACC": "Accuracy", + "CRIT": "Critical Hit Ratio", + "EVA": "Evasiveness", + "DEFAULT": "???", + }, + + AttackTypeBoosterItem: { + "silk_scarf": "Silk Scarf", + "black_belt": "Black Belt", + "sharp_beak": "Sharp Beak", + "poison_barb": "Poison Barb", + "soft_sand": "Soft Sand", + "hard_stone": "Hard Stone", + "silver_powder": "Silver Powder", + "spell_tag": "Spell Tag", + "metal_coat": "Metal Coat", + "charcoal": "Charcoal", + "mystic_water": "Mystic Water", + "miracle_seed": "Miracle Seed", + "magnet": "Magnet", + "twisted_spoon": "Twisted Spoon", + "never_melt_ice": "Never-Melt Ice", + "dragon_fang": "Dragon Fang", + "black_glasses": "Black Glasses", + "fairy_feather": "Fairy Feather", + }, + BaseStatBoosterItem: { + "hp_up": "HP Up", + "protein": "Protein", + "iron": "Iron", + "calcium": "Calcium", + "zinc": "Zinc", + "carbos": "Carbos", + }, + EvolutionItem: { + "NONE": "None", + + "LINKING_CORD": "Linking Cord", + "SUN_STONE": "Sun Stone", + "MOON_STONE": "Moon Stone", + "LEAF_STONE": "Leaf Stone", + "FIRE_STONE": "Fire Stone", + "WATER_STONE": "Water Stone", + "THUNDER_STONE": "Thunder Stone", + "ICE_STONE": "Ice Stone", + "DUSK_STONE": "Dusk Stone", + "DAWN_STONE": "Dawn Stone", + "SHINY_STONE": "Shiny Stone", + "CRACKED_POT": "Cracked Pot", + "SWEET_APPLE": "Sweet Apple", + "TART_APPLE": "Tart Apple", + "STRAWBERRY_SWEET": "Strawberry Sweet", + "UNREMARKABLE_TEACUP": "Unremarkable Teacup", + + "CHIPPED_POT": "Chipped Pot", + "BLACK_AUGURITE": "Black Augurite", + "GALARICA_CUFF": "Galarica Cuff", + "GALARICA_WREATH": "Galarica Wreath", + "PEAT_BLOCK": "Peat Block", + "AUSPICIOUS_ARMOR": "Auspicious Armor", + "MALICIOUS_ARMOR": "Malicious Armor", + "MASTERPIECE_TEACUP": "Masterpiece Teacup", + "METAL_ALLOY": "Metal Alloy", + "SCROLL_OF_DARKNESS": "Scroll Of Darkness", + "SCROLL_OF_WATERS": "Scroll Of Waters", + "SYRUPY_APPLE": "Syrupy Apple", + }, + FormChangeItem: { + "NONE": "None", + + "ABOMASITE": "Abomasite", + "ABSOLITE": "Absolite", + "AERODACTYLITE": "Aerodactylite", + "AGGRONITE": "Aggronite", + "ALAKAZITE": "Alakazite", + "ALTARIANITE": "Altarianite", + "AMPHAROSITE": "Ampharosite", + "AUDINITE": "Audinite", + "BANETTITE": "Banettite", + "BEEDRILLITE": "Beedrillite", + "BLASTOISINITE": "Blastoisinite", + "BLAZIKENITE": "Blazikenite", + "CAMERUPTITE": "Cameruptite", + "CHARIZARDITE_X": "Charizardite X", + "CHARIZARDITE_Y": "Charizardite Y", + "DIANCITE": "Diancite", + "GALLADITE": "Galladite", + "GARCHOMPITE": "Garchompite", + "GARDEVOIRITE": "Gardevoirite", + "GENGARITE": "Gengarite", + "GLALITITE": "Glalitite", + "GYARADOSITE": "Gyaradosite", + "HERACRONITE": "Heracronite", + "HOUNDOOMINITE": "Houndoominite", + "KANGASKHANITE": "Kangaskhanite", + "LATIASITE": "Latiasite", + "LATIOSITE": "Latiosite", + "LOPUNNITE": "Lopunnite", + "LUCARIONITE": "Lucarionite", + "MANECTITE": "Manectite", + "MAWILITE": "Mawilite", + "MEDICHAMITE": "Medichamite", + "METAGROSSITE": "Metagrossite", + "MEWTWONITE_X": "Mewtwonite X", + "MEWTWONITE_Y": "Mewtwonite Y", + "PIDGEOTITE": "Pidgeotite", + "PINSIRITE": "Pinsirite", + "RAYQUAZITE": "Rayquazite", + "SABLENITE": "Sablenite", + "SALAMENCITE": "Salamencite", + "SCEPTILITE": "Sceptilite", + "SCIZORITE": "Scizorite", + "SHARPEDONITE": "Sharpedonite", + "SLOWBRONITE": "Slowbronite", + "STEELIXITE": "Steelixite", + "SWAMPERTITE": "Swampertite", + "TYRANITARITE": "Tyranitarite", + "VENUSAURITE": "Venusaurite", + + "BLUE_ORB": "Blue Orb", + "RED_ORB": "Red Orb", + "SHARP_METEORITE": "Sharp Meteorite", + "HARD_METEORITE": "Hard Meteorite", + "SMOOTH_METEORITE": "Smooth Meteorite", + "ADAMANT_CRYSTAL": "Adamant Crystal", + "LUSTROUS_GLOBE": "Lustrous Globe", + "GRISEOUS_CORE": "Griseous Core", + "REVEAL_GLASS": "Reveal Glass", + "GRACIDEA": "Gracidea", + "MAX_MUSHROOMS": "Max Mushrooms", + "DARK_STONE": "Dark Stone", + "LIGHT_STONE": "Light Stone", + "PRISON_BOTTLE": "Prison Bottle", + "N_LUNARIZER": "N Lunarizer", + "N_SOLARIZER": "N Solarizer", + "RUSTED_SWORD": "Rusted Sword", + "RUSTED_SHIELD": "Rusted Shield", + "ICY_REINS_OF_UNITY": "Icy Reins Of Unity", + "SHADOW_REINS_OF_UNITY": "Shadow Reins Of Unity", + "WELLSPRING_MASK": "Wellspring Mask", + "HEARTHFLAME_MASK": "Hearthflame Mask", + "CORNERSTONE_MASK": "Cornerstone Mask", + "SHOCK_DRIVE": "Shock Drive", + "BURN_DRIVE": "Burn Drive", + "CHILL_DRIVE": "Chill Drive", + "DOUSE_DRIVE": "Douse Drive", + + "FIST_PLATE": "Fist Plate", + "SKY_PLATE": "Sky Plate", + "TOXIC_PLATE": "Toxic Plate", + "EARTH_PLATE": "Earth Plate", + "STONE_PLATE": "Stone Plate", + "INSECT_PLATE": "Insect Plate", + "SPOOKY_PLATE": "Spooky Plate", + "IRON_PLATE": "Iron Plate", + "FLAME_PLATE": "Flame Plate", + "SPLASH_PLATE": "Splash Plate", + "MEADOW_PLATE": "Meadow Plate", + "ZAP_PLATE": "Zap Plate", + "MIND_PLATE": "Mind Plate", + "ICICLE_PLATE": "Icicle Plate", + "DRACO_PLATE": "Draco Plate", + "DREAD_PLATE": "Dread Plate", + "PIXIE_PLATE": "Pixie Plate", + "BLANK_PLATE": "Blank Plate", + "LEGEND_PLATE": "Legend Plate", + "FIGHTING_MEMORY": "Fighting Memory", + "FLYING_MEMORY": "Flying Memory", + "POISON_MEMORY": "Poison Memory", + "GROUND_MEMORY": "Ground Memory", + "ROCK_MEMORY": "Rock Memory", + "BUG_MEMORY": "Bug Memory", + "GHOST_MEMORY": "Ghost Memory", + "STEEL_MEMORY": "Steel Memory", + "FIRE_MEMORY": "Fire Memory", + "WATER_MEMORY": "Water Memory", + "GRASS_MEMORY": "Grass Memory", + "ELECTRIC_MEMORY": "Electric Memory", + "PSYCHIC_MEMORY": "Psychic Memory", + "ICE_MEMORY": "Ice Memory", + "DRAGON_MEMORY": "Dragon Memory", + "DARK_MEMORY": "Dark Memory", + "FAIRY_MEMORY": "Fairy Memory", + "BLANK_MEMORY": "Blank Memory", + }, +} as const; diff --git a/src/locales/ca-ES/modifier.ts b/src/locales/ca-ES/modifier.ts new file mode 100644 index 00000000000..26a6a9c18ae --- /dev/null +++ b/src/locales/ca-ES/modifier.ts @@ -0,0 +1,14 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +export const modifier: SimpleTranslationEntries = { + "surviveDamageApply": "{{pokemonNameWithAffix}} hung on\nusing its {{typeName}}!", + "turnHealApply": "{{pokemonNameWithAffix}} restored a little HP using\nits {{typeName}}!", + "hitHealApply": "{{pokemonNameWithAffix}} restored a little HP using\nits {{typeName}}!", + "pokemonInstantReviveApply": "{{pokemonNameWithAffix}} was revived\nby its {{typeName}}!", + "pokemonResetNegativeStatStageApply": "{{pokemonNameWithAffix}}'s lowered stats were restored\nby its {{typeName}}!", + "moneyInterestApply": "You received interest of ₽{{moneyAmount}}\nfrom the {{typeName}}!", + "turnHeldItemTransferApply": "{{pokemonNameWithAffix}}'s {{itemName}} was absorbed\nby {{pokemonName}}'s {{typeName}}!", + "contactHeldItemTransferApply": "{{pokemonNameWithAffix}}'s {{itemName}} was snatched\nby {{pokemonName}}'s {{typeName}}!", + "enemyTurnHealApply": "{{pokemonNameWithAffix}}\nrestored some HP!", + "bypassSpeedChanceApply": "{{pokemonName}} can act faster than normal, thanks to its {{itemName}}!", +} as const; diff --git a/src/locales/ca-ES/move-trigger.ts b/src/locales/ca-ES/move-trigger.ts new file mode 100644 index 00000000000..1d9d6459d83 --- /dev/null +++ b/src/locales/ca-ES/move-trigger.ts @@ -0,0 +1,62 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +export const moveTriggers: SimpleTranslationEntries = { + "hitWithRecoil" : "{{pokemonName}} was damaged by the recoil!", + "cutHpPowerUpMove": "{{pokemonName}} cut its own HP to power up its move!", + "absorbedElectricity": "{{pokemonName}} absorbed electricity!", + "switchedStatChanges": "{{pokemonName}} switched stat changes with the target!", + "goingAllOutForAttack": "{{pokemonName}} is going all out for this attack!", + "regainedHealth": "{{pokemonName}} regained\nhealth!", + "keptGoingAndCrashed": "{{pokemonName}} kept going\nand crashed!", + "fled": "{{pokemonName}} fled!", + "cannotBeSwitchedOut": "{{pokemonName}} can't be switched out!", + "swappedAbilitiesWithTarget": "{{pokemonName}} swapped\nabilities with its target!", + "coinsScatteredEverywhere": "Coins were scattered everywhere!", + "attackedByItem": "{{pokemonName}} is about to be attacked by its {{itemName}}!", + "whippedUpAWhirlwind": "{{pokemonName}} whipped\nup a whirlwind!", + "flewUpHigh": "{{pokemonName}} flew\nup high!", + "tookInSunlight": "{{pokemonName}} absorbed light!", + "dugAHole": "{{pokemonName}} burrowed its way under the ground!", + "loweredItsHead": "{{pokemonName}} tucked in its head!", + "isGlowing": "{{pokemonName}} became cloaked in a harsh light!", + "bellChimed": "A bell chimed!", + "foresawAnAttack": "{{pokemonName}} foresaw\nan attack!", + "hidUnderwater": "{{pokemonName}} hid\nunderwater!", + "soothingAromaWaftedThroughArea": "A soothing aroma wafted through the area!", + "sprangUp": "{{pokemonName}} sprang up!", + "choseDoomDesireAsDestiny": "{{pokemonName}} chose\nDoom Desire as its destiny!", + "vanishedInstantly": "{{pokemonName}} vanished\ninstantly!", + "tookTargetIntoSky": "{{pokemonName}} took {{targetName}}\ninto the sky!", + "becameCloakedInFreezingLight": "{{pokemonName}} became cloaked\nin a freezing light!", + "becameCloakedInFreezingAir": "{{pokemonName}} became cloaked\nin freezing air!", + "isChargingPower": "{{pokemonName}} is absorbing power!", + "burnedItselfOut": "{{pokemonName}} burned itself out!", + "startedHeatingUpBeak": "{{pokemonName}} started\nheating up its beak!", + "isOverflowingWithSpacePower": "{{pokemonName}} is overflowing\nwith space power!", + "usedUpAllElectricity": "{{pokemonName}} used up all its electricity!", + "stoleItem": "{{pokemonName}} stole\n{{targetName}}'s {{itemName}}!", + "incineratedItem": "{{pokemonName}} incinerated\n{{targetName}}'s {{itemName}}!", + "knockedOffItem": "{{pokemonName}} knocked off\n{{targetName}}'s {{itemName}}!", + "tookMoveAttack": "{{pokemonName}} took\nthe {{moveName}} attack!", + "cutOwnHpAndMaximizedStat": "{{pokemonName}} cut its own HP\nand maximized its {{statName}}!", + "copiedStatChanges": "{{pokemonName}} copied\n{{targetName}}'s stat changes!", + "magnitudeMessage": "Magnitude {{magnitude}}!", + "tookAimAtTarget": "{{pokemonName}} took aim\nat {{targetName}}!", + "transformedIntoType": "{{pokemonName}} transformed\ninto the {{typeName}} type!", + "copiedMove": "{{pokemonName}} copied\n{{moveName}}!", + "sketchedMove": "{{pokemonName}} sketched\n{{moveName}}!", + "acquiredAbility": "The {{pokemonName}} acquired\n{{abilityName}}!", + "copiedTargetAbility": "{{pokemonName}} copied the {{targetName}}'s\n{{abilityName}}!", + "transformedIntoTarget": "{{pokemonName}} transformed\ninto {{targetName}}!", + "tryingToTakeFoeDown": "{{pokemonName}} is hoping to take its attacker down with it!", + "addType": "{{typeName}} was added to\n{{pokemonName}}!", + "cannotUseMove": "{{pokemonName}} cannot use {{moveName}}!", + "healHp": "{{pokemonName}} had its HP restored.", + "sacrificialFullRestore": "{{pokemonName}}'s Healing Wish\nwas granted!", + "invertStats": "{{pokemonName}}'s stat changes\nwere all reversed!", + "resetStats": "{{pokemonName}}'s stat changes\nwere 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!", + "swapArenaTags": "{{pokemonName}} swapped the battle effects affecting each side of the field!", +} as const; diff --git a/src/locales/ca-ES/move.ts b/src/locales/ca-ES/move.ts new file mode 100644 index 00000000000..cec7c93ede5 --- /dev/null +++ b/src/locales/ca-ES/move.ts @@ -0,0 +1,3812 @@ +import { MoveTranslationEntries } from "#app/interfaces/locales"; + +export const move: MoveTranslationEntries = { + "pound": { + name: "Pound", + effect: "The target is physically pounded with a long tail, a foreleg, or the like." + }, + "karateChop": { + name: "Karate Chop", + effect: "The target is attacked with a sharp chop. Critical hits land more easily." + }, + "doubleSlap": { + name: "Double Slap", + effect: "The target is slapped repeatedly, back and forth, two to five times in a row." + }, + "cometPunch": { + name: "Comet Punch", + effect: "The target is hit with a flurry of punches that strike two to five times in a row." + }, + "megaPunch": { + name: "Mega Punch", + effect: "The target is slugged by a punch thrown with muscle-packed power." + }, + "payDay": { + name: "Pay Day", + effect: "Numerous coins are hurled at the target to inflict damage. Money is earned after the battle." + }, + "firePunch": { + name: "Fire Punch", + effect: "The target is punched with a fiery fist. This may also leave the target with a burn." + }, + "icePunch": { + name: "Ice Punch", + effect: "The target is punched with an icy fist. This may also leave the target frozen." + }, + "thunderPunch": { + name: "Thunder Punch", + effect: "The target is punched with an electrified fist. This may also leave the target with paralysis." + }, + "scratch": { + name: "Scratch", + effect: "Hard, pointed, sharp claws rake the target to inflict damage." + }, + "viseGrip": { + name: "Vise Grip", + effect: "The target is gripped and squeezed from both sides to inflict damage." + }, + "guillotine": { + name: "Guillotine", + effect: "A vicious, tearing attack with big pincers. The target faints instantly if this attack hits." + }, + "razorWind": { + name: "Razor Wind", + effect: "In this two-turn attack, blades of wind hit opposing Pokémon on the second turn. Critical hits land more easily." + }, + "swordsDance": { + name: "Swords Dance", + effect: "A frenetic dance to uplift the fighting spirit. This sharply raises the user's Attack stat." + }, + "cut": { + name: "Cut", + effect: "The target is cut with a scythe or claw." + }, + "gust": { + name: "Gust", + effect: "A gust of wind is whipped up by wings and launched at the target to inflict damage." + }, + "wingAttack": { + name: "Wing Attack", + effect: "The target is struck with large, imposing wings spread wide to inflict damage." + }, + "whirlwind": { + name: "Whirlwind", + effect: "The target is blown away, and a different Pokémon is dragged out. In the wild, this ends a battle against a single Pokémon." + }, + "fly": { + name: "Fly", + effect: "The user flies up into the sky and then strikes its target on the next turn." + }, + "bind": { + name: "Bind", + effect: "Things such as long bodies or tentacles are used to bind and squeeze the target for four to five turns." + }, + "slam": { + name: "Slam", + effect: "The target is slammed with a long tail, vines, or the like to inflict damage." + }, + "vineWhip": { + name: "Vine Whip", + effect: "The target is struck with slender, whiplike vines to inflict damage." + }, + "stomp": { + name: "Stomp", + effect: "The target is stomped with a big foot. This may also make the target flinch." + }, + "doubleKick": { + name: "Double Kick", + effect: "The target is quickly kicked twice in succession using both feet." + }, + "megaKick": { + name: "Mega Kick", + effect: "The target is attacked by a kick launched with muscle-packed power." + }, + "jumpKick": { + name: "Jump Kick", + effect: "The user jumps up high, then strikes with a kick. If the kick misses, the user hurts itself." + }, + "rollingKick": { + name: "Rolling Kick", + effect: "The user lashes out with a quick, spinning kick. This may also make the target flinch." + }, + "sandAttack": { + name: "Sand Attack", + effect: "Sand is hurled in the target's face, reducing the target's accuracy." + }, + "headbutt": { + name: "Headbutt", + effect: "The user sticks out its head and attacks by charging straight into the target. This may also make the target flinch." + }, + "hornAttack": { + name: "Horn Attack", + effect: "The target is jabbed with a sharply pointed horn to inflict damage." + }, + "furyAttack": { + name: "Fury Attack", + effect: "The target is jabbed repeatedly with a horn or beak two to five times in a row." + }, + "hornDrill": { + name: "Horn Drill", + effect: "The user stabs the target with a horn that rotates like a drill. The target faints instantly if this attack hits." + }, + "tackle": { + name: "Tackle", + effect: "A physical attack in which the user charges and slams into the target with its whole body." + }, + "bodySlam": { + name: "Body Slam", + effect: "The user drops onto the target with its full body weight. This may also leave the target with paralysis." + }, + "wrap": { + name: "Wrap", + effect: "A long body, vines, or the like are used to wrap and squeeze the target for four to five turns." + }, + "takeDown": { + name: "Take Down", + effect: "A reckless, full-body charge attack for slamming into the target. This also damages the user a little." + }, + "thrash": { + name: "Thrash", + effect: "The user rampages and attacks for two to three turns. The user then becomes confused." + }, + "doubleEdge": { + name: "Double-Edge", + effect: "A reckless, life-risking tackle in which the user rushes the target. This also damages the user quite a lot." + }, + "tailWhip": { + name: "Tail Whip", + effect: "The user wags its tail cutely, making opposing Pokémon less wary and lowering their Defense stats." + }, + "poisonSting": { + name: "Poison Sting", + effect: "The user stabs the target with a poisonous stinger. This may also poison the target." + }, + "twineedle": { + name: "Twineedle", + effect: "The user damages the target twice in succession by jabbing it with two spikes. This may also poison the target." + }, + "pinMissile": { + name: "Pin Missile", + effect: "Sharp spikes are shot at the target in rapid succession. They hit two to five times in a row." + }, + "leer": { + name: "Leer", + effect: "The user gives opposing Pokémon an intimidating leer that lowers the Defense stat." + }, + "bite": { + name: "Bite", + effect: "The target is bitten with viciously sharp fangs. This may also make the target flinch." + }, + "growl": { + name: "Growl", + effect: "The user growls in an endearing way, making opposing Pokémon less wary. This lowers their Attack stats." + }, + "roar": { + name: "Roar", + effect: "The target is scared off, and a different Pokémon is dragged out. In the wild, this ends a battle against a single Pokémon." + }, + "sing": { + name: "Sing", + effect: "A soothing lullaby is sung in a calming voice that puts the target into a deep slumber." + }, + "supersonic": { + name: "Supersonic", + effect: "The user generates odd sound waves from its body that confuse the target." + }, + "sonicBoom": { + name: "Sonic Boom", + effect: "The target is hit with a destructive shock wave that always inflicts 20 HP damage." + }, + "disable": { + name: "Disable", + effect: "For four turns, this move prevents the target from using the move it last used." + }, + "acid": { + name: "Acid", + effect: "Opposing Pokémon are attacked with a spray of harsh acid. This may also lower their Sp. Def stats." + }, + "ember": { + name: "Ember", + effect: "The target is attacked with small flames. This may also leave the target with a burn." + }, + "flamethrower": { + name: "Flamethrower", + effect: "The target is scorched with an intense blast of fire. This may also leave the target with a burn." + }, + "mist": { + name: "Mist", + effect: "The user cloaks itself and its allies in a white mist that prevents any of their stats from being lowered for five turns." + }, + "waterGun": { + name: "Water Gun", + effect: "The target is blasted with a forceful shot of water." + }, + "hydroPump": { + name: "Hydro Pump", + effect: "The target is blasted by a huge volume of water launched under great pressure." + }, + "surf": { + name: "Surf", + effect: "The user attacks everything around it by swamping its surroundings with a giant wave." + }, + "iceBeam": { + name: "Ice Beam", + effect: "The target is struck with an icy-cold beam of energy. This may also leave the target frozen." + }, + "blizzard": { + name: "Blizzard", + effect: "A howling blizzard is summoned to strike opposing Pokémon. This may also leave the opposing Pokémon frozen." + }, + "psybeam": { + name: "Psybeam", + effect: "The target is attacked with a peculiar ray. This may also leave the target confused." + }, + "bubbleBeam": { + name: "Bubble Beam", + effect: "A spray of bubbles is forcefully ejected at the target. This may also lower the target's Speed stat." + }, + "auroraBeam": { + name: "Aurora Beam", + effect: "The target is hit with a rainbow-colored beam. This may also lower the target's Attack stat." + }, + "hyperBeam": { + name: "Hyper Beam", + effect: "The target is attacked with a powerful beam. The user can't move on the next turn." + }, + "peck": { + name: "Peck", + effect: "The target is jabbed with a sharply pointed beak or horn." + }, + "drillPeck": { + name: "Drill Peck", + effect: "A corkscrewing attack that strikes the target with a sharp beak acting as a drill." + }, + "submission": { + name: "Submission", + effect: "The user grabs the target and recklessly dives for the ground. This also damages the user a little." + }, + "lowKick": { + name: "Low Kick", + effect: "A powerful low kick that makes the target fall over. The heavier the target, the greater the move's power." + }, + "counter": { + name: "Counter", + effect: "A retaliation move that counters any physical attack, inflicting double the damage taken." + }, + "seismicToss": { + name: "Seismic Toss", + effect: "The target is thrown using the power of gravity. It inflicts damage equal to the user's level." + }, + "strength": { + name: "Strength", + effect: "The target is slugged with a punch thrown at maximum power." + }, + "absorb": { + name: "Absorb", + effect: "A nutrient-draining attack. The user's HP is restored by half the damage taken by the target." + }, + "megaDrain": { + name: "Mega Drain", + effect: "A nutrient-draining attack. The user's HP is restored by half the damage taken by the target." + }, + "leechSeed": { + name: "Leech Seed", + effect: "A seed is planted on the target. It steals some HP from the target every turn." + }, + "growth": { + name: "Growth", + effect: "The user's body grows all at once, raising the Attack and Sp. Atk stats." + }, + "razorLeaf": { + name: "Razor Leaf", + effect: "Sharp-edged leaves are launched to slash at opposing Pokémon. Critical hits land more easily." + }, + "solarBeam": { + name: "Solar Beam", + effect: "In this two-turn attack, the user gathers light, then blasts a bundled beam on the next turn." + }, + "poisonPowder": { + name: "Poison Powder", + effect: "The user scatters a cloud of poisonous dust that poisons the target." + }, + "stunSpore": { + name: "Stun Spore", + effect: "The user scatters a cloud of numbing powder that paralyzes the target." + }, + "sleepPowder": { + name: "Sleep Powder", + effect: "The user scatters a big cloud of sleep-inducing dust around the target." + }, + "petalDance": { + name: "Petal Dance", + effect: "The user attacks the target by scattering petals for two to three turns. The user then becomes confused." + }, + "stringShot": { + name: "String Shot", + effect: "Opposing Pokémon are bound with silk blown from the user's mouth that harshly lowers the Speed stat." + }, + "dragonRage": { + name: "Dragon Rage", + effect: "This attack hits the target with a shock wave of pure rage. This attack always inflicts 40 HP damage." + }, + "fireSpin": { + name: "Fire Spin", + effect: "The target becomes trapped within a fierce vortex of fire that rages for four to five turns." + }, + "thunderShock": { + name: "Thunder Shock", + effect: "A jolt of electricity crashes down on the target to inflict damage. This may also leave the target with paralysis." + }, + "thunderbolt": { + name: "Thunderbolt", + effect: "A strong electric blast crashes down on the target. This may also leave the target with paralysis." + }, + "thunderWave": { + name: "Thunder Wave", + effect: "The user launches a weak jolt of electricity that paralyzes the target." + }, + "thunder": { + name: "Thunder", + effect: "A wicked thunderbolt is dropped on the target to inflict damage. This may also leave the target with paralysis." + }, + "rockThrow": { + name: "Rock Throw", + effect: "The user picks up and throws a small rock at the target to attack." + }, + "earthquake": { + name: "Earthquake", + effect: "The user sets off an earthquake that strikes every Pokémon around it." + }, + "fissure": { + name: "Fissure", + effect: "The user opens up a fissure in the ground and drops the target in. The target faints instantly if this attack hits." + }, + "dig": { + name: "Dig", + effect: "The user burrows into the ground, then attacks on the next turn." + }, + "toxic": { + name: "Toxic", + effect: "A move that leaves the target badly poisoned. Its poison damage worsens every turn." + }, + "confusion": { + name: "Confusion", + effect: "The target is hit by a weak telekinetic force. This may also confuse the target." + }, + "psychic": { + name: "Psychic", + effect: "The target is hit by a strong telekinetic force. This may also lower the target's Sp. Def stat." + }, + "hypnosis": { + name: "Hypnosis", + effect: "The user employs hypnotic suggestion to make the target fall into a deep sleep." + }, + "meditate": { + name: "Meditate", + effect: "The user meditates to awaken the power deep within its body and raise its Attack stat." + }, + "agility": { + name: "Agility", + effect: "The user relaxes and lightens its body to move faster. This sharply raises the Speed stat." + }, + "quickAttack": { + name: "Quick Attack", + effect: "The user lunges at the target at a speed that makes it almost invisible. This move always goes first." + }, + "rage": { + name: "Rage", + effect: "As long as this move is in use, the power of rage raises the Attack stat each time the user is hit in battle." + }, + "teleport": { + name: "Teleport", + effect: "The user switches places with a party Pokémon in waiting, if any. If a wild Pokémon uses this move, it flees." + }, + "nightShade": { + name: "Night Shade", + effect: "The user makes the target see a frightening mirage. It inflicts damage equal to the user's level." + }, + "mimic": { + name: "Mimic", + effect: "The user copies the target's last move. The move can be used during battle until the Pokémon is switched out." + }, + "screech": { + name: "Screech", + effect: "An earsplitting screech harshly lowers the target's Defense stat." + }, + "doubleTeam": { + name: "Double Team", + effect: "By moving rapidly, the user makes illusory copies of itself to raise its evasiveness." + }, + "recover": { + name: "Recover", + effect: "Restoring its own cells, the user restores its own HP by half of its max HP." + }, + "harden": { + name: "Harden", + effect: "The user stiffens all the muscles in its body to raise its Defense stat." + }, + "minimize": { + name: "Minimize", + effect: "The user compresses its body to make itself look smaller, which sharply raises its evasiveness." + }, + "smokescreen": { + name: "Smokescreen", + effect: "The user releases an obscuring cloud of smoke or ink. This lowers the target's accuracy." + }, + "confuseRay": { + name: "Confuse Ray", + effect: "The target is exposed to a sinister ray that triggers confusion." + }, + "withdraw": { + name: "Withdraw", + effect: "The user withdraws its body into its hard shell, raising its Defense stat." + }, + "defenseCurl": { + name: "Defense Curl", + effect: "The user curls up to conceal weak spots and raise its Defense stat." + }, + "barrier": { + name: "Barrier", + effect: "The user throws up a sturdy wall that sharply raises its Defense stat." + }, + "lightScreen": { + name: "Light Screen", + effect: "A wondrous wall of light is put up to reduce damage from special attacks for five turns." + }, + "haze": { + name: "Haze", + effect: "The user creates a haze that eliminates every stat change among all the Pokémon engaged in battle." + }, + "reflect": { + name: "Reflect", + effect: "A wondrous wall of light is put up to reduce damage from physical attacks for five turns." + }, + "focusEnergy": { + name: "Focus Energy", + effect: "The user takes a deep breath and focuses so that critical hits land more easily." + }, + "bide": { + name: "Bide", + effect: "The user endures attacks for two turns, then strikes back to cause double the damage taken." + }, + "metronome": { + name: "Metronome", + effect: "The user waggles a finger and stimulates its brain into randomly using nearly any move." + }, + "mirrorMove": { + name: "Mirror Move", + effect: "The user counters the target by mimicking the target's last move." + }, + "selfDestruct": { + name: "Self-Destruct", + effect: "The user attacks everything around it by causing an explosion. The user faints upon using this move." + }, + "eggBomb": { + name: "Egg Bomb", + effect: "A large egg is hurled at the target with maximum force to inflict damage." + }, + "lick": { + name: "Lick", + effect: "The target is licked with a long tongue, causing damage. This may also leave the target with paralysis." + }, + "smog": { + name: "Smog", + effect: "The target is attacked with a discharge of filthy gases. This may also poison the target." + }, + "sludge": { + name: "Sludge", + effect: "Unsanitary sludge is hurled at the target. This may also poison the target." + }, + "boneClub": { + name: "Bone Club", + effect: "The user clubs the target with a bone. This may also make the target flinch." + }, + "fireBlast": { + name: "Fire Blast", + effect: "The target is attacked with an intense blast of all-consuming fire. This may also leave the target with a burn." + }, + "waterfall": { + name: "Waterfall", + effect: "The user charges at the target and may make it flinch." + }, + "clamp": { + name: "Clamp", + effect: "The target is clamped and squeezed by the user's very thick and sturdy shell for four to five turns." + }, + "swift": { + name: "Swift", + effect: "Star-shaped rays are shot at opposing Pokémon. This attack never misses." + }, + "skullBash": { + name: "Skull Bash", + effect: "The user tucks in its head to raise its Defense stat on the first turn, then rams the target on the next turn." + }, + "spikeCannon": { + name: "Spike Cannon", + effect: "Sharp spikes are shot at the target in rapid succession. They hit two to five times in a row." + }, + "constrict": { + name: "Constrict", + effect: "The target is attacked with long, creeping tentacles, vines, or the like. This may also lower the target's Speed stat." + }, + "amnesia": { + name: "Amnesia", + effect: "The user temporarily empties its mind to forget its concerns. This sharply raises the user's Sp. Def stat." + }, + "kinesis": { + name: "Kinesis", + effect: "The user distracts the target by bending a spoon. This lowers the target's accuracy." + }, + "softBoiled": { + name: "Soft-Boiled", + effect: "The user restores its own HP by up to half of its max HP." + }, + "highJumpKick": { + name: "High Jump Kick", + effect: "The target is attacked with a knee kick from a jump. If it misses, the user is hurt instead." + }, + "glare": { + name: "Glare", + effect: "The user intimidates the target with the pattern on its belly to cause paralysis." + }, + "dreamEater": { + name: "Dream Eater", + effect: "The user eats the dreams of a sleeping target. The user's HP is restored by half the damage taken by the target." + }, + "poisonGas": { + name: "Poison Gas", + effect: "A cloud of poison gas is sprayed in the face of opposing Pokémon, poisoning those it hits." + }, + "barrage": { + name: "Barrage", + effect: "Round objects are hurled at the target to strike two to five times in a row." + }, + "leechLife": { + name: "Leech Life", + effect: "The user drains the target's blood. The user's HP is restored by half the damage taken by the target." + }, + "lovelyKiss": { + name: "Lovely Kiss", + effect: "With a scary face, the user tries to force a kiss on the target. If it succeeds, the target falls asleep." + }, + "skyAttack": { + name: "Sky Attack", + effect: "A second-turn attack move where critical hits land more easily. This may also make the target flinch." + }, + "transform": { + name: "Transform", + effect: "The user transforms into a copy of the target right down to having the same move set." + }, + "bubble": { + name: "Bubble", + effect: "A spray of countless bubbles is jetted at the opposing Pokémon. This may also lower their Speed stat." + }, + "dizzyPunch": { + name: "Dizzy Punch", + effect: "The target is hit with rhythmically launched punches. This may also leave the target confused." + }, + "spore": { + name: "Spore", + effect: "The user scatters bursts of spores that induce sleep." + }, + "flash": { + name: "Flash", + effect: "The user flashes a bright light that cuts the target's accuracy." + }, + "psywave": { + name: "Psywave", + effect: "The target is attacked with an odd psychic wave. The attack varies in intensity." + }, + "splash": { + name: "Splash", + effect: "The user just flops and splashes around to no effect at all..." + }, + "acidArmor": { + name: "Acid Armor", + effect: "The user alters its cellular structure to liquefy itself, sharply raising its Defense stat." + }, + "crabhammer": { + name: "Crabhammer", + effect: "The target is hammered with a large pincer. Critical hits land more easily." + }, + "explosion": { + name: "Explosion", + effect: "The user attacks everything around it by causing a tremendous explosion. The user faints upon using this move." + }, + "furySwipes": { + name: "Fury Swipes", + effect: "The target is raked with sharp claws or scythes quickly two to five times in a row." + }, + "bonemerang": { + name: "Bonemerang", + effect: "The user throws the bone it holds. The bone loops around to hit the target twice—coming and going." + }, + "rest": { + name: "Rest", + effect: "The user goes to sleep for two turns. This fully restores the user's HP and heals any status conditions." + }, + "rockSlide": { + name: "Rock Slide", + effect: "Large boulders are hurled at opposing Pokémon to inflict damage. This may also make the opposing Pokémon flinch." + }, + "hyperFang": { + name: "Hyper Fang", + effect: "The user bites hard on the target with its sharp front fangs. This may also make the target flinch." + }, + "sharpen": { + name: "Sharpen", + effect: "The user makes its edges more jagged, which raises its Attack stat." + }, + "conversion": { + name: "Conversion", + effect: "The user changes its type to become the same type as the move at the top of the list of moves it knows." + }, + "triAttack": { + name: "Tri Attack", + effect: "The user strikes with a simultaneous three-beam attack. This may also burn, freeze, or paralyze the target." + }, + "superFang": { + name: "Super Fang", + effect: "The user chomps hard on the target with its sharp front fangs. This cuts the target's HP in half." + }, + "slash": { + name: "Slash", + effect: "The target is attacked with a slash of claws or blades. Critical hits land more easily." + }, + "substitute": { + name: "Substitute", + effect: "The user creates a substitute for itself using some of its HP. The substitute serves as the user's decoy." + }, + "struggle": { + name: "Struggle", + effect: "This attack is used in desperation only if the user has no PP. It also damages the user a little." + }, + "sketch": { + name: "Sketch", + effect: "It enables the user to permanently learn the move last used by the target. Once used, Sketch disappears." + }, + "tripleKick": { + name: "Triple Kick", + effect: "A consecutive three-kick attack that becomes more powerful with each successful hit." + }, + "thief": { + name: "Thief", + effect: "The user attacks and has a 30% chance to steal the target's held item simultaneously." + }, + "spiderWeb": { + name: "Spider Web", + effect: "The user ensnares the target with thin, gooey silk so it can't flee from battle." + }, + "mindReader": { + name: "Mind Reader", + effect: "The user senses the target's movements with its mind to ensure its next attack does not miss the target." + }, + "nightmare": { + name: "Nightmare", + effect: "A sleeping target sees a nightmare that inflicts some damage every turn." + }, + "flameWheel": { + name: "Flame Wheel", + effect: "The user cloaks itself in fire and charges at the target. This may also leave the target with a burn." + }, + "snore": { + name: "Snore", + effect: "This attack can be used only if the user is asleep. The harsh noise may also make the target flinch." + }, + "curse": { + name: "Curse", + effect: "A move that works differently for the Ghost type than for all other types." + }, + "flail": { + name: "Flail", + effect: "The user flails about aimlessly to attack. The less HP the user has, the greater the move's power." + }, + "conversion2": { + name: "Conversion 2", + effect: "The user changes its type to make itself resistant to the type of the attack the target used last." + }, + "aeroblast": { + name: "Aeroblast", + effect: "A vortex of air is shot at the target to inflict damage. Critical hits land more easily." + }, + "cottonSpore": { + name: "Cotton Spore", + effect: "The user releases cotton-like spores that cling to opposing Pokémon, which harshly lowers their Speed stats." + }, + "reversal": { + name: "Reversal", + effect: "An all-out attack that becomes more powerful the less HP the user has." + }, + "spite": { + name: "Spite", + effect: "The user unleashes its grudge on the move last used by the target by cutting 4 PP from it." + }, + "powderSnow": { + name: "Powder Snow", + effect: "The user attacks with a chilling gust of powdery snow. This may also freeze opposing Pokémon." + }, + "protect": { + name: "Protect", + effect: "This move enables the user to protect itself from all attacks. Its chance of failing rises if it is used in succession." + }, + "machPunch": { + name: "Mach Punch", + effect: "The user throws a punch at blinding speed. This move always goes first." + }, + "scaryFace": { + name: "Scary Face", + effect: "The user frightens the target with a scary face to harshly lower its Speed stat." + }, + "feintAttack": { + name: "Feint Attack", + effect: "The user approaches the target disarmingly, then throws a sucker punch. This attack never misses." + }, + "sweetKiss": { + name: "Sweet Kiss", + effect: "The user kisses the target with a sweet, angelic cuteness that causes confusion." + }, + "bellyDrum": { + name: "Belly Drum", + effect: "The user maximizes its Attack stat in exchange for HP equal to half its max HP." + }, + "sludgeBomb": { + name: "Sludge Bomb", + effect: "Unsanitary sludge is hurled at the target. This may also poison the target." + }, + "mudSlap": { + name: "Mud-Slap", + effect: "The user hurls mud in the target's face to inflict damage and lower its accuracy." + }, + "octazooka": { + name: "Octazooka", + effect: "The user attacks by spraying ink in the target's face or eyes. This may also lower the target's accuracy." + }, + "spikes": { + name: "Spikes", + effect: "The user lays a trap of spikes at the opposing team's feet. The trap hurts Pokémon that switch into battle." + }, + "zapCannon": { + name: "Zap Cannon", + effect: "The user fires an electric blast like a cannon to inflict damage and cause paralysis." + }, + "foresight": { + name: "Foresight", + effect: "Enables a Ghost-type target to be hit by Normal- and Fighting-type attacks. This also enables an evasive target to be hit." + }, + "destinyBond": { + name: "Destiny Bond", + effect: "After using this move, if the user faints, the Pokémon that landed the knockout hit also faints. Its chance of failing rises if it is used in succession." + }, + "perishSong": { + name: "Perish Song", + effect: "Any Pokémon that hears this song faints in three turns, unless it switches out of battle." + }, + "icyWind": { + name: "Icy Wind", + effect: "The user attacks with a gust of chilled air. This also lowers opposing Pokémon's Speed stats." + }, + "detect": { + name: "Detect", + effect: "This move enables the user to protect itself from all attacks. Its chance of failing rises if it is used in succession." + }, + "boneRush": { + name: "Bone Rush", + effect: "The user strikes the target with a hard bone two to five times in a row." + }, + "lockOn": { + name: "Lock-On", + effect: "The user takes sure aim at the target. This ensures the next attack does not miss the target." + }, + "outrage": { + name: "Outrage", + effect: "The user rampages and attacks for two to three turns. The user then becomes confused." + }, + "sandstorm": { + name: "Sandstorm", + effect: "A five-turn sandstorm is summoned to hurt all combatants except Rock, Ground, and Steel types. It raises the Sp. Def stat of Rock types." + }, + "gigaDrain": { + name: "Giga Drain", + effect: "A nutrient-draining attack. The user's HP is restored by half the damage taken by the target." + }, + "endure": { + name: "Endure", + effect: "The user endures any attack with at least 1 HP. Its chance of failing rises if it is used in succession." + }, + "charm": { + name: "Charm", + effect: "The user gazes at the target rather charmingly, making it less wary. This harshly lowers the target's Attack stat." + }, + "rollout": { + name: "Rollout", + effect: "The user continually rolls into the target over five turns. It becomes more powerful each time it hits." + }, + "falseSwipe": { + name: "False Swipe", + effect: "A restrained attack that prevents the target from fainting. The target is left with at least 1 HP." + }, + "swagger": { + name: "Swagger", + effect: "The user enrages and confuses the target. However, this also sharply raises the target's Attack stat." + }, + "milkDrink": { + name: "Milk Drink", + effect: "The user restores its own HP by up to half of its max HP." + }, + "spark": { + name: "Spark", + effect: "The user throws an electrically charged tackle at the target. This may also leave the target with paralysis." + }, + "furyCutter": { + name: "Fury Cutter", + effect: "The target is slashed with scythes or claws. This attack becomes more powerful if it hits in succession." + }, + "steelWing": { + name: "Steel Wing", + effect: "The target is hit with wings of steel. This may also raise the user's Defense stat." + }, + "meanLook": { + name: "Mean Look", + effect: "The user pins the target with a dark, arresting look. The target becomes unable to flee." + }, + "attract": { + name: "Attract", + effect: "If it is the opposite gender of the user, the target becomes infatuated and less likely to attack." + }, + "sleepTalk": { + name: "Sleep Talk", + effect: "While it is asleep, the user randomly uses one of the moves it knows." + }, + "healBell": { + name: "Heal Bell", + effect: "The user makes a soothing bell chime to heal the status conditions of all the party Pokémon." + }, + "return": { + name: "Return", + effect: "This full-power attack grows more powerful the more the user likes its Trainer." + }, + "present": { + name: "Present", + effect: "The user attacks by giving the target a gift with a hidden trap. It restores HP sometimes, however." + }, + "frustration": { + name: "Frustration", + effect: "This full-power attack grows more powerful the less the user likes its Trainer." + }, + "safeguard": { + name: "Safeguard", + effect: "The user creates a protective field that prevents status conditions for five turns." + }, + "painSplit": { + name: "Pain Split", + effect: "The user adds its HP to the target's HP, then equally shares the combined HP with the target." + }, + "sacredFire": { + name: "Sacred Fire", + effect: "The target is razed with a mystical fire of great intensity. This may also leave the target with a burn." + }, + "magnitude": { + name: "Magnitude", + effect: "The user attacks everything around it with a ground-shaking quake. Its power varies." + }, + "dynamicPunch": { + name: "Dynamic Punch", + effect: "The user punches the target with full, concentrated power. This confuses the target if it hits." + }, + "megahorn": { + name: "Megahorn", + effect: "Using its tough and impressive horn, the user rams into the target with no letup." + }, + "dragonBreath": { + name: "Dragon Breath", + effect: "The user exhales a mighty gust that inflicts damage. This may also leave the target with paralysis." + }, + "batonPass": { + name: "Baton Pass", + effect: "The user switches places with a party Pokémon in waiting and passes along any stat changes." + }, + "encore": { + name: "Encore", + effect: "The user compels the target to keep using the move it encored for three turns." + }, + "pursuit": { + name: "Pursuit", + effect: "The power of this attack move is doubled if it's used on a target that's switching out of battle." + }, + "rapidSpin": { + name: "Rapid Spin", + effect: "A spin attack that can also eliminate such moves as Bind, Wrap, and Leech Seed. This also raises the user's Speed stat." + }, + "sweetScent": { + name: "Sweet Scent", + effect: "A sweet scent that harshly lowers opposing Pokémon's evasiveness." + }, + "ironTail": { + name: "Iron Tail", + effect: "The target is slammed with a steel-hard tail. This may also lower the target's Defense stat." + }, + "metalClaw": { + name: "Metal Claw", + effect: "The target is raked with steel claws. This may also raise the user's Attack stat." + }, + "vitalThrow": { + name: "Vital Throw", + effect: "The user attacks last. In return, this throw move never misses." + }, + "morningSun": { + name: "Morning Sun", + effect: "The user restores its own HP. The amount of HP regained varies with the weather." + }, + "synthesis": { + name: "Synthesis", + effect: "The user restores its own HP. The amount of HP regained varies with the weather." + }, + "moonlight": { + name: "Moonlight", + effect: "The user restores its own HP. The amount of HP regained varies with the weather." + }, + "hiddenPower": { + name: "Hidden Power", + effect: "A unique attack that varies in type depending on the Pokémon using it." + }, + "crossChop": { + name: "Cross Chop", + effect: "The user delivers a double chop with its forearms crossed. Critical hits land more easily." + }, + "twister": { + name: "Twister", + effect: "The user whips up a vicious tornado to tear at opposing Pokémon. This may also make them flinch." + }, + "rainDance": { + name: "Rain Dance", + effect: "The user summons a heavy rain that falls for five turns, powering up Water-type moves. It lowers the power of Fire-type moves." + }, + "sunnyDay": { + name: "Sunny Day", + effect: "The user intensifies the sun for five turns, powering up Fire-type moves. It lowers the power of Water-type moves." + }, + "crunch": { + name: "Crunch", + effect: "The user crunches up the target with sharp fangs. This may also lower the target's Defense stat." + }, + "mirrorCoat": { + name: "Mirror Coat", + effect: "A retaliation move that counters any special attack, inflicting double the damage taken." + }, + "psychUp": { + name: "Psych Up", + effect: "The user hypnotizes itself into copying any stat change made by the target." + }, + "extremeSpeed": { + name: "Extreme Speed", + effect: "The user charges the target at blinding speed. This move always goes first." + }, + "ancientPower": { + name: "Ancient Power", + effect: "The user attacks with a prehistoric power. This may also raise all the user's stats at once." + }, + "shadowBall": { + name: "Shadow Ball", + effect: "The user hurls a shadowy blob at the target. This may also lower the target's Sp. Def stat." + }, + "futureSight": { + name: "Future Sight", + effect: "Two turns after this move is used, a hunk of psychic energy attacks the target." + }, + "rockSmash": { + name: "Rock Smash", + effect: "The user attacks with a punch. This may also lower the target's Defense stat." + }, + "whirlpool": { + name: "Whirlpool", + effect: "The user traps the target in a violent swirling whirlpool for four to five turns." + }, + "beatUp": { + name: "Beat Up", + effect: "The user gets all party Pokémon to attack the target. The more party Pokémon, the greater the number of attacks." + }, + "fakeOut": { + name: "Fake Out", + effect: "This attack hits first and makes the target flinch. It only works the first turn each time the user enters battle." + }, + "uproar": { + name: "Uproar", + effect: "The user attacks in an uproar for three turns. During that time, no Pokémon can fall asleep." + }, + "stockpile": { + name: "Stockpile", + effect: "The user charges up power and raises both its Defense and Sp. Def stats. The move can be used three times." + }, + "spitUp": { + name: "Spit Up", + effect: "The power stored using the move Stockpile is released at once in an attack. The more power is stored, the greater the move's power." + }, + "swallow": { + name: "Swallow", + effect: "The power stored using the move Stockpile is absorbed by the user to heal its HP. Storing more power heals more HP." + }, + "heatWave": { + name: "Heat Wave", + effect: "The user attacks by exhaling hot breath on opposing Pokémon. This may also leave those Pokémon with a burn." + }, + "hail": { + name: "Hail", + effect: "The user summons a hailstorm lasting five turns. It damages all Pokémon except Ice types." + }, + "torment": { + name: "Torment", + effect: "The user torments and enrages the target, making it incapable of using the same move twice in a row." + }, + "flatter": { + name: "Flatter", + effect: "Flattery is used to confuse the target. However, this also raises the target's Sp. Atk stat." + }, + "willOWisp": { + name: "Will-O-Wisp", + effect: "The user shoots a sinister flame at the target to inflict a burn." + }, + "memento": { + name: "Memento", + effect: "The user faints when using this move. In return, this harshly lowers the target's Attack and Sp. Atk stats." + }, + "facade": { + name: "Facade", + effect: "This attack move doubles its power if the user is poisoned, burned, or paralyzed." + }, + "focusPunch": { + name: "Focus Punch", + effect: "The user focuses its mind before launching a punch. This move fails if the user is hit before it is used." + }, + "smellingSalts": { + name: "Smelling Salts", + effect: "This attack's power is doubled when used on a target with paralysis. This also cures the target's paralysis, however." + }, + "followMe": { + name: "Follow Me", + effect: "The user draws attention to itself, making all targets take aim only at the user." + }, + "naturePower": { + name: "Nature Power", + effect: "This attack makes use of nature's power. Its effects vary depending on the user's environment." + }, + "charge": { + name: "Charge", + effect: "The user boosts the power of the Electric move it uses on the next turn. This also raises the user's Sp. Def stat." + }, + "taunt": { + name: "Taunt", + effect: "The target is taunted into a rage that allows it to use only attack moves for three turns." + }, + "helpingHand": { + name: "Helping Hand", + effect: "The user assists an ally by boosting the power of that ally's attack." + }, + "trick": { + name: "Trick", + effect: "The user catches the target off guard and swaps its held item with its own." + }, + "rolePlay": { + name: "Role Play", + effect: "The user mimics the target completely, copying the target's Ability." + }, + "wish": { + name: "Wish", + effect: "One turn after this move is used, the user's or its replacement's HP is restored by half the user's max HP." + }, + "assist": { + name: "Assist", + effect: "The user hurriedly and randomly uses a move among those known by ally Pokémon." + }, + "ingrain": { + name: "Ingrain", + effect: "The user lays roots that restore its HP on every turn. Because it's rooted, it can't switch out." + }, + "superpower": { + name: "Superpower", + effect: "The user attacks the target with great power. However, this also lowers the user's Attack and Defense stats." + }, + "magicCoat": { + name: "Magic Coat", + effect: "Moves like Leech Seed and moves that inflict status conditions are blocked by a barrier and reflected back to the user of those moves." + }, + "recycle": { + name: "Recycle", + effect: "The user recycles a held item that has been used in battle so it can be used again." + }, + "revenge": { + name: "Revenge", + effect: "This attack move's power is doubled if the user has been hurt by the opponent in the same turn." + }, + "brickBreak": { + name: "Brick Break", + effect: "The user attacks with a swift chop. It can also break barriers, such as Light Screen and Reflect." + }, + "yawn": { + name: "Yawn", + effect: "The user lets loose a huge yawn that lulls the target into falling asleep on the next turn." + }, + "knockOff": { + name: "Knock Off", + effect: "The user slaps down the target's held item, and that item can't be used in that battle. The move does more damage if the target has a held item." + }, + "endeavor": { + name: "Endeavor", + effect: "This attack move cuts down the target's HP to equal the user's HP." + }, + "eruption": { + name: "Eruption", + effect: "The user attacks opposing Pokémon with explosive fury. The lower the user's HP, the lower the move's power." + }, + "skillSwap": { + name: "Skill Swap", + effect: "The user employs its psychic power to exchange Abilities with the target." + }, + "imprison": { + name: "Imprison", + effect: "If opposing Pokémon know any move also known by the user, they are prevented from using it." + }, + "refresh": { + name: "Refresh", + effect: "The user rests to cure itself of poisoning, a burn, or paralysis." + }, + "grudge": { + name: "Grudge", + effect: "If the user faints, the user's grudge fully depletes the PP of the opponent's move that knocked it out." + }, + "snatch": { + name: "Snatch", + effect: "The user steals the effects of any attempts to use a healing or stat-changing move." + }, + "secretPower": { + name: "Secret Power", + effect: "The additional effects of this attack depend upon where it was used." + }, + "dive": { + name: "Dive", + effect: "Diving on the first turn, the user floats up and attacks on the next turn." + }, + "armThrust": { + name: "Arm Thrust", + effect: "The user lets loose a flurry of open-palmed arm thrusts that hit two to five times in a row." + }, + "camouflage": { + name: "Camouflage", + effect: "The user's type is changed depending on its environment, such as at water's edge, in grass, or in a cave." + }, + "tailGlow": { + name: "Tail Glow", + effect: "The user stares at flashing lights to focus its mind, drastically raising its Sp. Atk stat." + }, + "lusterPurge": { + name: "Luster Purge", + effect: "The user lets loose a damaging burst of light. This may also lower the target's Sp. Def stat." + }, + "mistBall": { + name: "Mist Ball", + effect: "A mist-like flurry of down envelops and damages the target. This may also lower the target's Sp. Atk stat." + }, + "featherDance": { + name: "Feather Dance", + effect: "The user covers the target's body with a mass of down that harshly lowers its Attack stat." + }, + "teeterDance": { + name: "Teeter Dance", + effect: "The user performs a wobbly dance that confuses the Pokémon around it." + }, + "blazeKick": { + name: "Blaze Kick", + effect: "The user launches a kick that lands a critical hit more easily. This may also leave the target with a burn." + }, + "mudSport": { + name: "Mud Sport", + effect: "The user kicks up mud on the battlefield. This weakens Electric-type moves for five turns." + }, + "iceBall": { + name: "Ice Ball", + effect: "The user attacks the target for five turns. The move's power increases each time it hits." + }, + "needleArm": { + name: "Needle Arm", + effect: "The user attacks by wildly swinging its thorny arms. This may also make the target flinch." + }, + "slackOff": { + name: "Slack Off", + effect: "The user slacks off, restoring its own HP by up to half of its max HP." + }, + "hyperVoice": { + name: "Hyper Voice", + effect: "The user lets loose a horribly echoing shout with the power to inflict damage." + }, + "poisonFang": { + name: "Poison Fang", + effect: "The user bites the target with toxic fangs. This may also leave the target badly poisoned." + }, + "crushClaw": { + name: "Crush Claw", + effect: "The user slashes the target with hard and sharp claws. This may also lower the target's Defense stat." + }, + "blastBurn": { + name: "Blast Burn", + effect: "The target is razed by a fiery explosion. The user can't move on the next turn." + }, + "hydroCannon": { + name: "Hydro Cannon", + effect: "The target is hit with a watery blast. The user can't move on the next turn." + }, + "meteorMash": { + name: "Meteor Mash", + effect: "The target is hit with a hard punch fired like a meteor. This may also raise the user's Attack stat." + }, + "astonish": { + name: "Astonish", + effect: "The user attacks the target while shouting in a startling fashion. This may also make the target flinch." + }, + "weatherBall": { + name: "Weather Ball", + effect: "This attack move varies in power and type depending on the weather." + }, + "aromatherapy": { + name: "Aromatherapy", + effect: "The user releases a soothing scent that heals all status conditions affecting the user's party." + }, + "fakeTears": { + name: "Fake Tears", + effect: "The user feigns crying to fluster the target, harshly lowering its Sp. Def stat." + }, + "airCutter": { + name: "Air Cutter", + effect: "The user launches razor-like wind to slash opposing Pokémon. Critical hits land more easily." + }, + "overheat": { + name: "Overheat", + effect: "The user attacks the target at full power. The attack's recoil harshly lowers the user's Sp. Atk stat." + }, + "odorSleuth": { + name: "Odor Sleuth", + effect: "Enables a Ghost-type target to be hit by Normal- and Fighting-type attacks. This also enables an evasive target to be hit." + }, + "rockTomb": { + name: "Rock Tomb", + effect: "Boulders are hurled at the target. This also lowers the target's Speed stat by preventing its movement." + }, + "silverWind": { + name: "Silver Wind", + effect: "The target is attacked with powdery scales blown by the wind. This may also raise all the user's stats." + }, + "metalSound": { + name: "Metal Sound", + effect: "A horrible sound like scraping metal harshly lowers the target's Sp. Def stat." + }, + "grassWhistle": { + name: "Grass Whistle", + effect: "The user plays a pleasant melody that lulls the target into a deep sleep." + }, + "tickle": { + name: "Tickle", + effect: "The user tickles the target into laughing, reducing its Attack and Defense stats." + }, + "cosmicPower": { + name: "Cosmic Power", + effect: "The user absorbs a mystical power from space to raise its Defense and Sp. Def stats." + }, + "waterSpout": { + name: "Water Spout", + effect: "The user spouts water to damage opposing Pokémon. The lower the user's HP, the lower the move's power." + }, + "signalBeam": { + name: "Signal Beam", + effect: "The user attacks with a sinister beam of light. This may also confuse the target." + }, + "shadowPunch": { + name: "Shadow Punch", + effect: "The user throws a punch from the shadows. This attack never misses." + }, + "extrasensory": { + name: "Extrasensory", + effect: "The user attacks with an odd, unseeable power. This may also make the target flinch." + }, + "skyUppercut": { + name: "Sky Uppercut", + effect: "The user attacks the target with an uppercut thrown skyward with force." + }, + "sandTomb": { + name: "Sand Tomb", + effect: "The user traps the target inside a harshly raging sandstorm for four to five turns." + }, + "sheerCold": { + name: "Sheer Cold", + effect: "The target faints instantly. It's less likely to hit the target if it's used by Pokémon other than Ice types." + }, + "muddyWater": { + name: "Muddy Water", + effect: "The user attacks by shooting muddy water at opposing Pokémon. This may also lower their accuracy." + }, + "bulletSeed": { + name: "Bullet Seed", + effect: "The user forcefully shoots seeds at the target two to five times in a row." + }, + "aerialAce": { + name: "Aerial Ace", + effect: "The user confounds the target with speed, then slashes. This attack never misses." + }, + "icicleSpear": { + name: "Icicle Spear", + effect: "The user launches sharp icicles at the target two to five times in a row." + }, + "ironDefense": { + name: "Iron Defense", + effect: "The user hardens its body's surface like iron, sharply raising its Defense stat." + }, + "block": { + name: "Block", + effect: "The user blocks the target's way with arms spread wide to prevent escape." + }, + "howl": { + name: "Howl", + effect: "The user howls loudly to raise the spirit of itself and allies. This raises their Attack stats." + }, + "dragonClaw": { + name: "Dragon Claw", + effect: "The user slashes the target with huge sharp claws." + }, + "frenzyPlant": { + name: "Frenzy Plant", + effect: "The user slams the target with the roots of an enormous tree. The user can't move on the next turn." + }, + "bulkUp": { + name: "Bulk Up", + effect: "The user tenses its muscles to bulk up its body, raising both its Attack and Defense stats." + }, + "bounce": { + name: "Bounce", + effect: "The user bounces up high, then drops on the target on the second turn. This may also leave the target with paralysis." + }, + "mudShot": { + name: "Mud Shot", + effect: "The user attacks by hurling a blob of mud at the target. This also lowers the target's Speed stat." + }, + "poisonTail": { + name: "Poison Tail", + effect: "The user hits the target with its tail. This may also poison the target. Critical hits land more easily." + }, + "covet": { + name: "Covet", + effect: "The user endearingly approaches the target, then has a 30% chance to steal the target's held item." + }, + "voltTackle": { + name: "Volt Tackle", + effect: "The user electrifies itself and charges the target. This also damages the user quite a lot. This attack may leave the target with paralysis." + }, + "magicalLeaf": { + name: "Magical Leaf", + effect: "The user scatters curious leaves that chase the target. This attack never misses." + }, + "waterSport": { + name: "Water Sport", + effect: "The user soaks the battlefield with water. This weakens Fire-type moves for five turns." + }, + "calmMind": { + name: "Calm Mind", + effect: "The user quietly focuses its mind and calms its spirit to raise its Sp. Atk and Sp. Def stats." + }, + "leafBlade": { + name: "Leaf Blade", + effect: "The user handles a sharp leaf like a sword and attacks by cutting its target. Critical hits land more easily." + }, + "dragonDance": { + name: "Dragon Dance", + effect: "The user vigorously performs a mystic, powerful dance that raises its Attack and Speed stats." + }, + "rockBlast": { + name: "Rock Blast", + effect: "The user hurls hard rocks at the target. Two to five rocks are launched in a row." + }, + "shockWave": { + name: "Shock Wave", + effect: "The user strikes the target with a quick jolt of electricity. This attack never misses." + }, + "waterPulse": { + name: "Water Pulse", + effect: "The user attacks the target with a pulsing blast of water. This may also confuse the target." + }, + "doomDesire": { + name: "Doom Desire", + effect: "Two turns after this move is used, a concentrated bundle of light blasts the target." + }, + "psychoBoost": { + name: "Psycho Boost", + effect: "The user attacks the target at full power. The attack's recoil harshly lowers the user's Sp. Atk stat." + }, + "roost": { + name: "Roost", + effect: "The user lands and rests its body. This move restores the user's HP by up to half of its max HP." + }, + "gravity": { + name: "Gravity", + effect: "This move enables Flying-type Pokémon or Pokémon with the Levitate Ability to be hit by Ground-type moves. Moves that involve flying can't be used." + }, + "miracleEye": { + name: "Miracle Eye", + effect: "Enables a Dark-type target to be hit by Psychic-type attacks. This also enables an evasive target to be hit." + }, + "wakeUpSlap": { + name: "Wake-Up Slap", + effect: "This attack inflicts big damage on a sleeping target. This also wakes the target up, however." + }, + "hammerArm": { + name: "Hammer Arm", + effect: "The user swings and hits with its strong, heavy fist. It lowers the user's Speed, however." + }, + "gyroBall": { + name: "Gyro Ball", + effect: "The user tackles the target with a high-speed spin. The slower the user compared to the target, the greater the move's power." + }, + "healingWish": { + name: "Healing Wish", + effect: "The user faints. In return, the Pokémon taking its place will have its HP restored and status conditions cured." + }, + "brine": { + name: "Brine", + effect: "If the target's HP is half or less, this attack will hit with double the power." + }, + "naturalGift": { + name: "Natural Gift", + effect: "The user draws power to attack by using its held Berry. The Berry determines the move's type and power." + }, + "feint": { + name: "Feint", + effect: "This attack hits a target using a move such as Protect or Detect. This also lifts the effects of those moves." + }, + "pluck": { + name: "Pluck", + effect: "The user pecks the target. If the target is holding a Berry, the user eats it and gains its effect." + }, + "tailwind": { + name: "Tailwind", + effect: "The user whips up a turbulent whirlwind that ups the Speed stats of the user and its allies for four turns." + }, + "acupressure": { + name: "Acupressure", + effect: "The user applies pressure to stress points, sharply boosting one of its or its allies' stats." + }, + "metalBurst": { + name: "Metal Burst", + effect: "The user retaliates with much greater force against the opponent that last inflicted damage on it." + }, + "uTurn": { + name: "U-turn", + effect: "After making its attack, the user rushes back to switch places with a party Pokémon in waiting." + }, + "closeCombat": { + name: "Close Combat", + effect: "The user fights the target up close without guarding itself. This also lowers the user's Defense and Sp. Def stats." + }, + "payback": { + name: "Payback", + effect: "The user stores power, then attacks. If the user moves after the target, this attack's power will be doubled." + }, + "assurance": { + name: "Assurance", + effect: "If the target has already taken some damage in the same turn, this attack's power is doubled." + }, + "embargo": { + name: "Embargo", + effect: "This move prevents the target from using its held item for five turns. Its Trainer is also prevented from using items on it." + }, + "fling": { + name: "Fling", + effect: "The user flings its held item at the target to attack. This move's power and effects depend on the item." + }, + "psychoShift": { + name: "Psycho Shift", + effect: "Using its psychic power of suggestion, the user transfers its status conditions to the target." + }, + "trumpCard": { + name: "Trump Card", + effect: "The fewer PP this move has, the greater its power." + }, + "healBlock": { + name: "Heal Block", + effect: "For five turns, the user prevents the opposing team from using any moves, Abilities, or held items that recover HP." + }, + "wringOut": { + name: "Wring Out", + effect: "The user powerfully wrings the target. The more HP the target has, the greater the move's power." + }, + "powerTrick": { + name: "Power Trick", + effect: "The user employs its psychic power to switch its Attack stat with its Defense stat." + }, + "gastroAcid": { + name: "Gastro Acid", + effect: "The user hurls up its stomach acids on the target. The fluid eliminates the effect of the target's Ability." + }, + "luckyChant": { + name: "Lucky Chant", + effect: "The user chants an incantation toward the sky, preventing opposing Pokémon from landing critical hits for five turns." + }, + "meFirst": { + name: "Me First", + effect: "The user cuts ahead of the target to copy and use the target's intended move with greater power. This move fails if it isn't used first." + }, + "copycat": { + name: "Copycat", + effect: "The user mimics the move used immediately before it. The move fails if no other move has been used yet." + }, + "powerSwap": { + name: "Power Swap", + effect: "The user employs its psychic power to switch changes to its Attack and Sp. Atk stats with the target." + }, + "guardSwap": { + name: "Guard Swap", + effect: "The user employs its psychic power to switch changes to its Defense and Sp. Def stats with the target." + }, + "punishment": { + name: "Punishment", + effect: "The more the target has powered up with stat changes, the greater the move's power." + }, + "lastResort": { + name: "Last Resort", + effect: "This move can be used only after the user has used all the other moves it knows in the battle." + }, + "worrySeed": { + name: "Worry Seed", + effect: "A seed that causes worry is planted on the target. It prevents sleep by making the target's Ability Insomnia." + }, + "suckerPunch": { + name: "Sucker Punch", + effect: "This move enables the user to attack first. This move fails if the target is not readying an attack." + }, + "toxicSpikes": { + name: "Toxic Spikes", + effect: "The user lays a trap of poison spikes at the feet of the opposing team. The spikes will poison opposing Pokémon that switch into battle." + }, + "heartSwap": { + name: "Heart Swap", + effect: "The user employs its psychic power to switch stat changes with the target." + }, + "aquaRing": { + name: "Aqua Ring", + effect: "The user envelops itself in a veil made of water. It regains some HP every turn." + }, + "magnetRise": { + name: "Magnet Rise", + effect: "The user levitates using electrically generated magnetism for five turns." + }, + "flareBlitz": { + name: "Flare Blitz", + effect: "The user cloaks itself in fire and charges the target. This also damages the user quite a lot. This attack may leave the target with a burn." + }, + "forcePalm": { + name: "Force Palm", + effect: "The target is attacked with a shock wave. This may also leave the target with paralysis." + }, + "auraSphere": { + name: "Aura Sphere", + effect: "The user lets loose a blast of aura power from deep within its body at the target. This attack never misses." + }, + "rockPolish": { + name: "Rock Polish", + effect: "The user polishes its body to reduce drag. This sharply raises the Speed stat." + }, + "poisonJab": { + name: "Poison Jab", + effect: "The target is stabbed with a tentacle, arm, or the like steeped in poison. This may also poison the target." + }, + "darkPulse": { + name: "Dark Pulse", + effect: "The user releases a horrible aura imbued with dark thoughts. This may also make the target flinch." + }, + "nightSlash": { + name: "Night Slash", + effect: "The user slashes the target the instant an opportunity arises. Critical hits land more easily." + }, + "aquaTail": { + name: "Aqua Tail", + effect: "The user attacks by swinging its tail as if it were a vicious wave in a raging storm." + }, + "seedBomb": { + name: "Seed Bomb", + effect: "The user slams a barrage of hard-shelled seeds down on the target from above." + }, + "airSlash": { + name: "Air Slash", + effect: "The user attacks with a blade of air that slices even the sky. This may also make the target flinch." + }, + "xScissor": { + name: "X-Scissor", + effect: "The user slashes at the target by crossing its scythes or claws as if they were a pair of scissors." + }, + "bugBuzz": { + name: "Bug Buzz", + effect: "The user generates a damaging sound wave by vibration. This may also lower the target's Sp. Def stat." + }, + "dragonPulse": { + name: "Dragon Pulse", + effect: "The target is attacked with a shock wave generated by the user's gaping mouth." + }, + "dragonRush": { + name: "Dragon Rush", + effect: "The user tackles the target while exhibiting overwhelming menace. This may also make the target flinch." + }, + "powerGem": { + name: "Power Gem", + effect: "The user attacks with a ray of light that sparkles as if it were made of gemstones." + }, + "drainPunch": { + name: "Drain Punch", + effect: "An energy-draining punch. The user's HP is restored by half the damage taken by the target." + }, + "vacuumWave": { + name: "Vacuum Wave", + effect: "The user whirls its fists to send a wave of pure vacuum at the target. This move always goes first." + }, + "focusBlast": { + name: "Focus Blast", + effect: "The user heightens its mental focus and unleashes its power. This may also lower the target's Sp. Def stat." + }, + "energyBall": { + name: "Energy Ball", + effect: "The user draws power from nature and fires it at the target. This may also lower the target's Sp. Def stat." + }, + "braveBird": { + name: "Brave Bird", + effect: "The user tucks in its wings and charges from a low altitude. This also damages the user quite a lot." + }, + "earthPower": { + name: "Earth Power", + effect: "The user makes the ground under the target erupt with power. This may also lower the target's Sp. Def stat." + }, + "switcheroo": { + name: "Switcheroo", + effect: "The user trades held items with the target faster than the eye can follow." + }, + "gigaImpact": { + name: "Giga Impact", + effect: "The user charges at the target using every bit of its power. The user can't move on the next turn." + }, + "nastyPlot": { + name: "Nasty Plot", + effect: "The user stimulates its brain by thinking bad thoughts. This sharply raises the user's Sp. Atk stat." + }, + "bulletPunch": { + name: "Bullet Punch", + effect: "The user strikes the target with tough punches as fast as bullets. This move always goes first." + }, + "avalanche": { + name: "Avalanche", + effect: "The power of this attack move is doubled if the user has been hurt by the target in the same turn." + }, + "iceShard": { + name: "Ice Shard", + effect: "The user flash-freezes chunks of ice and hurls them at the target. This move always goes first." + }, + "shadowClaw": { + name: "Shadow Claw", + effect: "The user slashes with a sharp claw made from shadows. Critical hits land more easily." + }, + "thunderFang": { + name: "Thunder Fang", + effect: "The user bites with electrified fangs. This may also make the target flinch or leave it with paralysis." + }, + "iceFang": { + name: "Ice Fang", + effect: "The user bites with cold-infused fangs. This may also make the target flinch or leave it frozen." + }, + "fireFang": { + name: "Fire Fang", + effect: "The user bites with flame-cloaked fangs. This may also make the target flinch or leave it with a burn." + }, + "shadowSneak": { + name: "Shadow Sneak", + effect: "The user extends its shadow and attacks the target from behind. This move always goes first." + }, + "mudBomb": { + name: "Mud Bomb", + effect: "The user launches a hard-packed mud ball to attack. This may also lower the target's accuracy." + }, + "psychoCut": { + name: "Psycho Cut", + effect: "The user tears at the target with blades formed by psychic power. Critical hits land more easily." + }, + "zenHeadbutt": { + name: "Zen Headbutt", + effect: "The user focuses its willpower to its head and attacks the target. This may also make the target flinch." + }, + "mirrorShot": { + name: "Mirror Shot", + effect: "The user lets loose a flash of energy at the target from its polished body. This may also lower the target's accuracy." + }, + "flashCannon": { + name: "Flash Cannon", + effect: "The user gathers all its light energy and releases it all at once. This may also lower the target's Sp. Def stat." + }, + "rockClimb": { + name: "Rock Climb", + effect: "The user attacks the target by smashing into it with incredible force. This may also confuse the target." + }, + "defog": { + name: "Defog", + effect: "A strong wind blows away the target's barriers such as Reflect or Light Screen. This also lowers the target's evasiveness." + }, + "trickRoom": { + name: "Trick Room", + effect: "The user creates a bizarre area in which slower Pokémon get to move first for five turns." + }, + "dracoMeteor": { + name: "Draco Meteor", + effect: "Comets are summoned down from the sky onto the target. The attack's recoil harshly lowers the user's Sp. Atk stat." + }, + "discharge": { + name: "Discharge", + effect: "The user strikes everything around it by letting loose a flare of electricity. This may also cause paralysis." + }, + "lavaPlume": { + name: "Lava Plume", + effect: "The user torches everything around it in an inferno of scarlet flames. This may also leave those it hits with a burn." + }, + "leafStorm": { + name: "Leaf Storm", + effect: "The user whips up a storm of leaves around the target. The attack's recoil harshly lowers the user's Sp. Atk stat." + }, + "powerWhip": { + name: "Power Whip", + effect: "The user violently whirls its vines, tentacles, or the like to harshly lash the target." + }, + "rockWrecker": { + name: "Rock Wrecker", + effect: "The user launches a huge boulder at the target to attack. The user can't move on the next turn." + }, + "crossPoison": { + name: "Cross Poison", + effect: "A slashing attack with a poisonous blade that may also poison the target. Critical hits land more easily." + }, + "gunkShot": { + name: "Gunk Shot", + effect: "The user shoots filthy garbage at the target to attack. This may also poison the target." + }, + "ironHead": { + name: "Iron Head", + effect: "The user slams the target with its steel-hard head. This may also make the target flinch." + }, + "magnetBomb": { + name: "Magnet Bomb", + effect: "The user launches steel bombs that stick to the target. This attack never misses." + }, + "stoneEdge": { + name: "Stone Edge", + effect: "The user stabs the target from below with sharpened stones. Critical hits land more easily." + }, + "captivate": { + name: "Captivate", + effect: "If any opposing Pokémon is the opposite gender of the user, it is charmed, which harshly lowers its Sp. Atk stat." + }, + "stealthRock": { + name: "Stealth Rock", + effect: "The user lays a trap of levitating stones around the opposing team. The trap hurts opposing Pokémon that switch into battle." + }, + "grassKnot": { + name: "Grass Knot", + effect: "The user snares the target with grass and trips it. The heavier the target, the greater the move's power." + }, + "chatter": { + name: "Chatter", + effect: "The user attacks the target with sound waves of deafening chatter. This confuses the target." + }, + "judgment": { + name: "Judgment", + effect: "The user releases countless shots of light at the target. This move's type varies depending on the kind of Plate the user is holding." + }, + "bugBite": { + name: "Bug Bite", + effect: "The user bites the target. If the target is holding a Berry, the user eats it and gains its effect." + }, + "chargeBeam": { + name: "Charge Beam", + effect: "The user attacks the target with an electric charge. The user may use any remaining electricity to raise its Sp. Atk stat." + }, + "woodHammer": { + name: "Wood Hammer", + effect: "The user slams its rugged body into the target to attack. This also damages the user quite a lot." + }, + "aquaJet": { + name: "Aqua Jet", + effect: "The user lunges at the target at a speed that makes it almost invisible. This move always goes first." + }, + "attackOrder": { + name: "Attack Order", + effect: "The user calls out its underlings to pummel the target. Critical hits land more easily." + }, + "defendOrder": { + name: "Defend Order", + effect: "The user calls out its underlings to shield its body, raising its Defense and Sp. Def stats." + }, + "healOrder": { + name: "Heal Order", + effect: "The user calls out its underlings to heal it. The user regains up to half of its max HP." + }, + "headSmash": { + name: "Head Smash", + effect: "The user attacks the target with a hazardous, full-power headbutt. This also damages the user terribly." + }, + "doubleHit": { + name: "Double Hit", + effect: "The user slams the target with a long tail, vines, or a tentacle. The target is hit twice in a row." + }, + "roarOfTime": { + name: "Roar of Time", + effect: "The user blasts the target with power that distorts even time. The user can't move on the next turn." + }, + "spacialRend": { + name: "Spacial Rend", + effect: "The user tears the target along with the space around it. Critical hits land more easily." + }, + "lunarDance": { + name: "Lunar Dance", + effect: "The user faints. In return, the Pokémon taking its place will have its status and HP fully restored." + }, + "crushGrip": { + name: "Crush Grip", + effect: "The target is crushed with great force. The more HP the target has left, the greater this move's power." + }, + "magmaStorm": { + name: "Magma Storm", + effect: "The target becomes trapped within a maelstrom of fire that rages for four to five turns." + }, + "darkVoid": { + name: "Dark Void", + effect: "Opposing Pokémon are dragged into a world of total darkness that makes them sleep." + }, + "seedFlare": { + name: "Seed Flare", + effect: "The user emits a shock wave from its body to attack its target. This may also harshly lower the target's Sp. Def stat." + }, + "ominousWind": { + name: "Ominous Wind", + effect: "The user blasts the target with a gust of repulsive wind. This may also raise all the user's stats at once." + }, + "shadowForce": { + name: "Shadow Force", + effect: "The user disappears, then strikes the target on the next turn. This move hits even if the target protects itself." + }, + "honeClaws": { + name: "Hone Claws", + effect: "The user sharpens its claws to boost its Attack stat and accuracy." + }, + "wideGuard": { + name: "Wide Guard", + effect: "The user and its allies are protected from wide-ranging attacks for one turn." + }, + "guardSplit": { + name: "Guard Split", + effect: "The user employs its psychic power to average its Defense and Sp. Def stats with those of the target." + }, + "powerSplit": { + name: "Power Split", + effect: "The user employs its psychic power to average its Attack and Sp. Atk stats with those of the target." + }, + "wonderRoom": { + name: "Wonder Room", + effect: "The user creates a bizarre area in which Pokémon's Defense and Sp. Def stats are swapped for five turns." + }, + "psyshock": { + name: "Psyshock", + effect: "The user materializes an odd psychic wave to attack the target. This attack does physical damage." + }, + "venoshock": { + name: "Venoshock", + effect: "The user drenches the target in a special poisonous liquid. This move's power is doubled if the target is poisoned." + }, + "autotomize": { + name: "Autotomize", + effect: "The user sheds part of its body to make itself lighter and sharply raise its Speed stat." + }, + "ragePowder": { + name: "Rage Powder", + effect: "The user scatters a cloud of irritating powder to draw attention to itself. Opposing Pokémon aim only at the user." + }, + "telekinesis": { + name: "Telekinesis", + effect: "The user makes the target float with its psychic power. The target is easier to hit for three turns." + }, + "magicRoom": { + name: "Magic Room", + effect: "The user creates a bizarre area in which Pokémon's held items lose their effects for five turns." + }, + "smackDown": { + name: "Smack Down", + effect: "The user throws a stone or similar projectile to attack the target. A flying Pokémon will fall to the ground when it's hit." + }, + "stormThrow": { + name: "Storm Throw", + effect: "The user strikes the target with a fierce blow. This attack always results in a critical hit." + }, + "flameBurst": { + name: "Flame Burst", + effect: "The user attacks the target with a bursting flame. The bursting flame damages Pokémon next to the target as well." + }, + "sludgeWave": { + name: "Sludge Wave", + effect: "The user strikes everything around it by swamping the area with a giant sludge wave. This may also poison those hit." + }, + "quiverDance": { + name: "Quiver Dance", + effect: "The user lightly performs a beautiful, mystic dance. This boosts the user's Sp. Atk, Sp. Def, and Speed stats." + }, + "heavySlam": { + name: "Heavy Slam", + effect: "The user slams into the target with its heavy body. The more the user outweighs the target, the greater the move's power." + }, + "synchronoise": { + name: "Synchronoise", + effect: "Using an odd shock wave, the user inflicts damage on any Pokémon of the same type in the area around it." + }, + "electroBall": { + name: "Electro Ball", + effect: "The user hurls an electric orb at the target. The faster the user is than the target, the greater the move's power." + }, + "soak": { + name: "Soak", + effect: "The user shoots a torrent of water at the target and changes the target's type to Water." + }, + "flameCharge": { + name: "Flame Charge", + effect: "Cloaking itself in flame, the user attacks the target. Then, building up more power, the user raises its Speed stat." + }, + "coil": { + name: "Coil", + effect: "The user coils up and concentrates. This raises its Attack and Defense stats as well as its accuracy." + }, + "lowSweep": { + name: "Low Sweep", + effect: "The user makes a swift attack on the target's legs, which lowers the target's Speed stat." + }, + "acidSpray": { + name: "Acid Spray", + effect: "The user spits fluid that works to melt the target. This harshly lowers the target's Sp. Def stat." + }, + "foulPlay": { + name: "Foul Play", + effect: "The user turns the target's power against it. The higher the target's Attack stat, the greater the damage it deals." + }, + "simpleBeam": { + name: "Simple Beam", + effect: "The user's mysterious psychic wave changes the target's Ability to Simple." + }, + "entrainment": { + name: "Entrainment", + effect: "The user dances with an odd rhythm that compels the target to mimic it, making the target's Ability the same as the user's." + }, + "afterYou": { + name: "After You", + effect: "The user helps the target and makes it use its move right after the user." + }, + "round": { + name: "Round", + effect: "The user attacks the target with a song. Others can join in the Round to increase the power of the attack." + }, + "echoedVoice": { + name: "Echoed Voice", + effect: "The user attacks the target with an echoing voice. If this move is used every turn, its power is increased." + }, + "chipAway": { + name: "Chip Away", + effect: "Looking for an opening, the user strikes consistently. The target's stat changes don't affect this attack's damage." + }, + "clearSmog": { + name: "Clear Smog", + effect: "The user attacks the target by throwing a clump of special mud. All stat changes are returned to normal." + }, + "storedPower": { + name: "Stored Power", + effect: "The user attacks the target with stored power. The more the user's stats are raised, the greater the move's power." + }, + "quickGuard": { + name: "Quick Guard", + effect: "The user protects itself and its allies from priority moves." + }, + "allySwitch": { + name: "Ally Switch", + effect: "The user teleports using a strange power and switches places with one of its allies." + }, + "scald": { + name: "Scald", + effect: "The user shoots boiling hot water at its target. This may also leave the target with a burn." + }, + "shellSmash": { + name: "Shell Smash", + effect: "The user breaks its shell, which lowers Defense and Sp. Def stats but sharply raises its Attack, Sp. Atk, and Speed stats." + }, + "healPulse": { + name: "Heal Pulse", + effect: "The user emits a healing pulse that restores the target's HP by up to half of its max HP." + }, + "hex": { + name: "Hex", + effect: "This relentless attack does massive damage to a target affected by status conditions." + }, + "skyDrop": { + name: "Sky Drop", + effect: "The user takes the target into the sky, then drops it during the next turn. The target cannot attack while in the sky." + }, + "shiftGear": { + name: "Shift Gear", + effect: "The user rotates its gears, raising its Attack stat and sharply raising its Speed stat." + }, + "circleThrow": { + name: "Circle Throw", + effect: "The target is thrown, and a different Pokémon is dragged out. In the wild, this ends a battle against a single Pokémon." + }, + "incinerate": { + name: "Incinerate", + effect: "The user attacks opposing Pokémon with fire. If a Pokémon is holding a certain item, such as a Berry, the item becomes burned up and unusable." + }, + "quash": { + name: "Quash", + effect: "The user suppresses the target and makes its move go last." + }, + "acrobatics": { + name: "Acrobatics", + effect: "The user nimbly strikes the target. The fewer held items, the higher the damage it inflicts." + }, + "reflectType": { + name: "Reflect Type", + effect: "The user reflects the target's type, making the user the same type as the target." + }, + "retaliate": { + name: "Retaliate", + effect: "The user gets revenge for a fainted ally. If an ally fainted in the previous turn, this move's power is increased." + }, + "finalGambit": { + name: "Final Gambit", + effect: "The user risks everything to attack its target. The user faints but does damage equal to its HP." + }, + "bestow": { + name: "Bestow", + effect: "The user passes its held item to the target when the target isn't holding an item." + }, + "inferno": { + name: "Inferno", + effect: "The user attacks by engulfing the target in an intense fire. This leaves the target with a burn." + }, + "waterPledge": { + name: "Water Pledge", + effect: "A column of water hits the target. When used with its fire equivalent, its power increases and a rainbow appears." + }, + "firePledge": { + name: "Fire Pledge", + effect: "A column of fire hits the target. When used with its grass equivalent, its power increases and a vast sea of fire appears." + }, + "grassPledge": { + name: "Grass Pledge", + effect: "A column of grass hits the target. When used with its water equivalent, its power increases and a vast swamp appears." + }, + "voltSwitch": { + name: "Volt Switch", + effect: "After making its attack, the user rushes back to switch places with a party Pokémon in waiting." + }, + "struggleBug": { + name: "Struggle Bug", + effect: "While resisting, the user attacks opposing Pokémon. This lowers the Sp. Atk stats of those hit." + }, + "bulldoze": { + name: "Bulldoze", + effect: "The user strikes everything around it by stomping down on the ground. This lowers the Speed stats of those hit." + }, + "frostBreath": { + name: "Frost Breath", + effect: "The user blows its cold breath on the target. This attack always results in a critical hit." + }, + "dragonTail": { + name: "Dragon Tail", + effect: "The target is knocked away, and a different Pokémon is dragged out. In the wild, this ends a battle against a single Pokémon." + }, + "workUp": { + name: "Work Up", + effect: "The user is roused, and its Attack and Sp. Atk stats increase." + }, + "electroweb": { + name: "Electroweb", + effect: "The user attacks and captures opposing Pokémon using an electric net. This lowers their Speed stats." + }, + "wildCharge": { + name: "Wild Charge", + effect: "The user shrouds itself in electricity and smashes into its target. This also damages the user a little." + }, + "drillRun": { + name: "Drill Run", + effect: "The user crashes into its target while rotating its body like a drill. Critical hits land more easily." + }, + "dualChop": { + name: "Dual Chop", + effect: "The user attacks its target by hitting it with brutal strikes. The target is hit twice in a row." + }, + "heartStamp": { + name: "Heart Stamp", + effect: "The user unleashes a vicious blow after its cute act makes the target less wary. This may also make the target flinch." + }, + "hornLeech": { + name: "Horn Leech", + effect: "The user drains the target's energy with its horns. The user's HP is restored by half the damage taken by the target." + }, + "sacredSword": { + name: "Sacred Sword", + effect: "The user attacks by slicing with a long horn. The target's stat changes don't affect this attack's damage." + }, + "razorShell": { + name: "Razor Shell", + effect: "The user cuts its target with sharp shells. This may also lower the target's Defense stat." + }, + "heatCrash": { + name: "Heat Crash", + effect: "The user slams its target with its flame-covered body. The more the user outweighs the target, the greater the move's power." + }, + "leafTornado": { + name: "Leaf Tornado", + effect: "The user attacks its target by encircling it in sharp leaves. This attack may also lower the target's accuracy." + }, + "steamroller": { + name: "Steamroller", + effect: "The user crushes its target by rolling over the target with its rolled-up body. This may also make the target flinch." + }, + "cottonGuard": { + name: "Cotton Guard", + effect: "The user protects itself by wrapping its body in soft cotton, which drastically raises the user's Defense stat." + }, + "nightDaze": { + name: "Night Daze", + effect: "The user lets loose a pitch-black shock wave at its target. This may also lower the target's accuracy." + }, + "psystrike": { + name: "Psystrike", + effect: "The user materializes an odd psychic wave to attack the target. This attack does physical damage." + }, + "tailSlap": { + name: "Tail Slap", + effect: "The user attacks by striking the target with its hard tail. It hits the target two to five times in a row." + }, + "hurricane": { + name: "Hurricane", + effect: "The user attacks by wrapping its opponent in a fierce wind that flies up into the sky. This may also confuse the target." + }, + "headCharge": { + name: "Head Charge", + effect: "The user charges its head into its target, using its powerful guard hair. This also damages the user a little." + }, + "gearGrind": { + name: "Gear Grind", + effect: "The user attacks by throwing steel gears at its target twice." + }, + "searingShot": { + name: "Searing Shot", + effect: "The user torches everything around it in an inferno of scarlet flames. This may also leave those it hits with a burn." + }, + "technoBlast": { + name: "Techno Blast", + effect: "The user fires a beam of light at its target. The move's type changes depending on the Drive the user holds." + }, + "relicSong": { + name: "Relic Song", + effect: "The user sings an ancient song and attacks by appealing to the hearts of the listening opposing Pokémon. This may also induce sleep." + }, + "secretSword": { + name: "Secret Sword", + effect: "The user cuts with its long horn. The odd power contained in the horn does physical damage to the target." + }, + "glaciate": { + name: "Glaciate", + effect: "The user attacks by blowing freezing cold air at opposing Pokémon. This lowers their Speed stats." + }, + "boltStrike": { + name: "Bolt Strike", + effect: "The user surrounds itself with a great amount of electricity and charges its target. This may also leave the target with paralysis." + }, + "blueFlare": { + name: "Blue Flare", + effect: "The user attacks by engulfing the target in an intense, yet beautiful, blue flame. This may also leave the target with a burn." + }, + "fieryDance": { + name: "Fiery Dance", + effect: "Cloaked in flames, the user attacks the target by dancing and flapping its wings. This may also raise the user's Sp. Atk stat." + }, + "freezeShock": { + name: "Freeze Shock", + effect: "On the second turn, the user hits the target with electrically charged ice. This may also leave the target with paralysis." + }, + "iceBurn": { + name: "Ice Burn", + effect: "On the second turn, an ultracold, freezing wind surrounds the target. This may leave the target with a burn." + }, + "snarl": { + name: "Snarl", + effect: "The user yells as if it's ranting about something, which lowers the Sp. Atk stats of opposing Pokémon." + }, + "icicleCrash": { + name: "Icicle Crash", + effect: "The user attacks by harshly dropping large icicles onto the target. This may also make the target flinch." + }, + "vCreate": { + name: "V-create", + effect: "With a hot flame on its forehead, the user hurls itself at its target. This lowers the user's Defense, Sp. Def, and Speed stats." + }, + "fusionFlare": { + name: "Fusion Flare", + effect: "The user brings down a giant flame. This move's power is increased when influenced by an enormous lightning bolt." + }, + "fusionBolt": { + name: "Fusion Bolt", + effect: "The user throws down a giant lightning bolt. This move's power is increased when influenced by an enormous flame." + }, + "flyingPress": { + name: "Flying Press", + effect: "The user dives down onto the target from the sky. This move is Fighting and Flying type simultaneously." + }, + "matBlock": { + name: "Mat Block", + effect: "Using a pulled-up mat as a shield, the user protects itself and its allies from damaging moves. This does not stop status moves." + }, + "belch": { + name: "Belch", + effect: "The user lets out a damaging belch at the target. The user must eat a held Berry to use this move." + }, + "rototiller": { + name: "Rototiller", + effect: "Tilling the soil, the user makes it easier for plants to grow. This raises the Attack and Sp. Atk stats of Grass-type Pokémon." + }, + "stickyWeb": { + name: "Sticky Web", + effect: "The user weaves a sticky net around the opposing team, which lowers their Speed stats upon switching into battle." + }, + "fellStinger": { + name: "Fell Stinger", + effect: "When the user knocks out a target with this move, the user's Attack stat rises drastically." + }, + "phantomForce": { + name: "Phantom Force", + effect: "The user vanishes somewhere, then strikes the target on the next turn. This move hits even if the target protects itself." + }, + "trickOrTreat": { + name: "Trick-or-Treat", + effect: "The user takes the target trick-or-treating. This adds Ghost type to the target's type." + }, + "nobleRoar": { + name: "Noble Roar", + effect: "Letting out a noble roar, the user intimidates the target and lowers its Attack and Sp. Atk stats." + }, + "ionDeluge": { + name: "Ion Deluge", + effect: "The user disperses electrically charged particles, which changes Normal-type moves to Electric-type moves." + }, + "parabolicCharge": { + name: "Parabolic Charge", + effect: "The user attacks everything around it. The user's HP is restored by half the damage taken by those hit." + }, + "forestsCurse": { + name: "Forest's Curse", + effect: "The user puts a forest curse on the target. The target is now Grass type as well." + }, + "petalBlizzard": { + name: "Petal Blizzard", + effect: "The user stirs up a violent petal blizzard and attacks everything around it." + }, + "freezeDry": { + name: "Freeze-Dry", + effect: "The user rapidly cools the target. This may also leave the target frozen. This move is super effective on Water types." + }, + "disarmingVoice": { + name: "Disarming Voice", + effect: "Letting out a charming cry, the user does emotional damage to opposing Pokémon. This attack never misses." + }, + "partingShot": { + name: "Parting Shot", + effect: "With a parting threat, the user lowers the target's Attack and Sp. Atk stats. Then it switches with a party Pokémon." + }, + "topsyTurvy": { + name: "Topsy-Turvy", + effect: "All stat changes affecting the target turn topsy-turvy and become the opposite of what they were." + }, + "drainingKiss": { + name: "Draining Kiss", + effect: "The user steals the target's HP with a kiss. The user's HP is restored by over half of the damage taken by the target." + }, + "craftyShield": { + name: "Crafty Shield", + effect: "The user protects itself and its allies from status moves with a mysterious power. This does not stop moves that do damage." + }, + "flowerShield": { + name: "Flower Shield", + effect: "The user raises the Defense stats of all Grass-type Pokémon in battle with a mysterious power." + }, + "grassyTerrain": { + name: "Grassy Terrain", + effect: "The user turns the ground to grass for five turns. This restores the HP of Pokémon on the ground a little every turn and powers up Grass-type moves." + }, + "mistyTerrain": { + name: "Misty Terrain", + effect: "This protects Pokémon on the ground from status conditions and halves damage from Dragon-type moves for five turns." + }, + "electrify": { + name: "Electrify", + effect: "If the target is electrified before it uses a move during that turn, the target's move becomes Electric type." + }, + "playRough": { + name: "Play Rough", + effect: "The user plays rough with the target and attacks it. This may also lower the target's Attack stat." + }, + "fairyWind": { + name: "Fairy Wind", + effect: "The user stirs up a fairy wind and strikes the target with it." + }, + "moonblast": { + name: "Moonblast", + effect: "Borrowing the power of the moon, the user attacks the target. This may also lower the target's Sp. Atk stat." + }, + "boomburst": { + name: "Boomburst", + effect: "The user attacks everything around it with the destructive power of a terrible, explosive sound." + }, + "fairyLock": { + name: "Fairy Lock", + effect: "By locking down the battlefield, the user keeps all Pokémon from fleeing during the next turn." + }, + "kingsShield": { + name: "King's Shield", + effect: "The user takes a defensive stance while it protects itself from damage. It also lowers the Attack stat of any attacker that makes direct contact." + }, + "playNice": { + name: "Play Nice", + effect: "The user and the target become friends, and the target loses its will to fight. This lowers the target's Attack stat." + }, + "confide": { + name: "Confide", + effect: "The user tells the target a secret, and the target loses its ability to concentrate. This lowers the target's Sp. Atk stat." + }, + "diamondStorm": { + name: "Diamond Storm", + effect: "The user whips up a storm of diamonds to damage opposing Pokémon. This may also sharply raise the user's Defense stat." + }, + "steamEruption": { + name: "Steam Eruption", + effect: "The user immerses the target in superheated steam. This may also leave the target with a burn." + }, + "hyperspaceHole": { + name: "Hyperspace Hole", + effect: "Using a hyperspace hole, the user appears right next to the target and strikes. This also hits a target using a move such as Protect or Detect." + }, + "waterShuriken": { + name: "Water Shuriken", + effect: "The user hits the target with throwing stars two to five times in a row. This move always goes first." + }, + "mysticalFire": { + name: "Mystical Fire", + effect: "The user attacks by breathing a special, hot fire. This also lowers the target's Sp. Atk stat." + }, + "spikyShield": { + name: "Spiky Shield", + effect: "In addition to protecting the user from attacks, this move also damages any attacker that makes direct contact." + }, + "aromaticMist": { + name: "Aromatic Mist", + effect: "The user raises the Sp. Def stat of an ally Pokémon by using a mysterious aroma." + }, + "eerieImpulse": { + name: "Eerie Impulse", + effect: "The user's body generates an eerie impulse. Exposing the target to it harshly lowers the target's Sp. Atk stat." + }, + "venomDrench": { + name: "Venom Drench", + effect: "Opposing Pokémon are drenched in an odd poisonous liquid. This lowers the Attack, Sp. Atk, and Speed stats of a poisoned target." + }, + "powder": { + name: "Powder", + effect: "The user covers the target in a combustible powder. If the target uses a Fire-type move, the powder explodes and damages the target." + }, + "geomancy": { + name: "Geomancy", + effect: "The user absorbs energy and sharply raises its Sp. Atk, Sp. Def, and Speed stats on the next turn." + }, + "magneticFlux": { + name: "Magnetic Flux", + effect: "The user manipulates magnetic fields, which raises the Defense and Sp. Def stats of ally Pokémon with the Plus or Minus Ability." + }, + "happyHour": { + name: "Happy Hour", + effect: "Using Happy Hour doubles the amount of prize money received after battle." + }, + "electricTerrain": { + name: "Electric Terrain", + effect: "The user electrifies the ground for five turns, powering up Electric-type moves. Pokémon on the ground no longer fall asleep." + }, + "dazzlingGleam": { + name: "Dazzling Gleam", + effect: "The user damages opposing Pokémon by emitting a powerful flash." + }, + "celebrate": { + name: "Celebrate", + effect: "The Pokémon congratulates you on your special day!" + }, + "holdHands": { + name: "Hold Hands", + effect: "The user and an ally hold hands. This makes them very happy." + }, + "babyDollEyes": { + name: "Baby-Doll Eyes", + effect: "The user stares at the target with its baby-doll eyes, which lowers the target's Attack stat. This move always goes first." + }, + "nuzzle": { + name: "Nuzzle", + effect: "The user attacks by nuzzling its electrified cheeks against the target. This also leaves the target with paralysis." + }, + "holdBack": { + name: "Hold Back", + effect: "The user holds back when it attacks, and the target is left with at least 1 HP." + }, + "infestation": { + name: "Infestation", + effect: "The target is infested and attacked for four to five turns. The target can't flee during this time." + }, + "powerUpPunch": { + name: "Power-Up Punch", + effect: "Striking opponents over and over makes the user's fists harder. Hitting a target raises the Attack stat." + }, + "oblivionWing": { + name: "Oblivion Wing", + effect: "The user absorbs its target's HP. The user's HP is restored by over half of the damage taken by the target." + }, + "thousandArrows": { + name: "Thousand Arrows", + effect: "This move also hits opposing Pokémon that are in the air. Those Pokémon are knocked down to the ground." + }, + "thousandWaves": { + name: "Thousand Waves", + effect: "The user attacks with a wave that crawls along the ground. Those it hits can't flee from battle." + }, + "landsWrath": { + name: "Land's Wrath", + effect: "The user gathers the energy of the land and focuses that power on opposing Pokémon to damage them." + }, + "lightOfRuin": { + name: "Light of Ruin", + effect: "Drawing power from the Eternal Flower, the user fires a powerful beam of light. This also damages the user quite a lot." + }, + "originPulse": { + name: "Origin Pulse", + effect: "The user attacks opposing Pokémon with countless beams of light that glow a deep and brilliant blue." + }, + "precipiceBlades": { + name: "Precipice Blades", + effect: "The user attacks opposing Pokémon by manifesting the power of the land in fearsome blades of stone." + }, + "dragonAscent": { + name: "Dragon Ascent", + effect: "After soaring upward, the user attacks its target by dropping out of the sky at high speeds. But it lowers its own Defense and Sp. Def stats in the process." + }, + "hyperspaceFury": { + name: "Hyperspace Fury", + effect: "Using its many arms, the user unleashes a barrage of attacks that ignore the effects of moves like Protect and Detect. But the user's Defense stat falls." + }, + "breakneckBlitzPhysical": { + name: "Breakneck Blitz", + effect: "The user builds up its momentum using its Z-Power and crashes into the target at full speed. The power varies, depending on the original move." + }, + "breakneckBlitzSpecial": { + name: "Breakneck Blitz", + effect: "Dummy Data" + }, + "allOutPummelingPhysical": { + name: "All-Out Pummeling", + effect: "The user rams an energy orb created by its Z-Power into the target with full force. The power varies, depending on the original move." + }, + "allOutPummelingSpecial": { + name: "All-Out Pummeling", + effect: "Dummy Data" + }, + "supersonicSkystrikePhysical": { + name: "Supersonic Skystrike", + effect: "The user soars up with its Z-Power and plummets toward the target at full speed. The power varies, depending on the original move." + }, + "supersonicSkystrikeSpecial": { + name: "Supersonic Skystrike", + effect: "Dummy Data" + }, + "acidDownpourPhysical": { + name: "Acid Downpour", + effect: "The user creates a poisonous swamp using its Z-Power and sinks the target into it at full force. The power varies, depending on the original move." + }, + "acidDownpourSpecial": { + name: "Acid Downpour", + effect: "Dummy Data" + }, + "tectonicRagePhysical": { + name: "Tectonic Rage", + effect: "The user burrows deep into the ground and slams into the target with the full force of its Z-Power. The power varies, depending on the original move." + }, + "tectonicRageSpecial": { + name: "Tectonic Rage", + effect: "Dummy Data" + }, + "continentalCrushPhysical": { + name: "Continental Crush", + effect: "The user summons a huge rock mountain using its Z-Power and drops it onto the target with full force. The power varies, depending on the original move." + }, + "continentalCrushSpecial": { + name: "Continental Crush", + effect: "Dummy Data" + }, + "savageSpinOutPhysical": { + name: "Savage Spin-Out", + effect: "The user binds the target with full force with threads of silk that the user spits using its Z-Power. The power varies, depending on the original move." + }, + "savageSpinOutSpecial": { + name: "Savage Spin-Out", + effect: "Dummy Data" + }, + "neverEndingNightmarePhysical": { + name: "Never-Ending Nightmare", + effect: "Deep-seated grudges summoned by the user's Z-Power trap the target. The power varies, depending on the original move." + }, + "neverEndingNightmareSpecial": { + name: "Never-Ending Nightmare", + effect: "Dummy Data" + }, + "corkscrewCrashPhysical": { + name: "Corkscrew Crash", + effect: "The user spins very fast and rams into the target with the full force of its Z-Power. The power varies, depending on the original move." + }, + "corkscrewCrashSpecial": { + name: "Corkscrew Crash", + effect: "Dummy Data" + }, + "infernoOverdrivePhysical": { + name: "Inferno Overdrive", + effect: "The user breathes a stream of intense fire toward the target with the full force of its Z-Power. The power varies depending on the original move." + }, + "infernoOverdriveSpecial": { + name: "Inferno Overdrive", + effect: "Dummy Data" + }, + "hydroVortexPhysical": { + name: "Hydro Vortex", + effect: "The user creates a huge whirling current using its Z-Power to swallow the target with full force. The power varies, depending on the original move." + }, + "hydroVortexSpecial": { + name: "Hydro Vortex", + effect: "Dummy Data" + }, + "bloomDoomPhysical": { + name: "Bloom Doom", + effect: "The user collects energy from plants using its Z-Power and attacks the target with full force. The power varies, depending on the original move." + }, + "bloomDoomSpecial": { + name: "Bloom Doom", + effect: "Dummy Data" + }, + "gigavoltHavocPhysical": { + name: "Gigavolt Havoc", + effect: "The user hits the target with a powerful electric current collected by its Z-Power. The power varies, depending on the original move." + }, + "gigavoltHavocSpecial": { + name: "Gigavolt Havoc", + effect: "Dummy Data" + }, + "shatteredPsychePhysical": { + name: "Shattered Psyche", + effect: "The user controls the target with its Z-Power and hurts the target with full force. The power varies, depending on the original move." + }, + "shatteredPsycheSpecial": { + name: "Shattered Psyche", + effect: "Dummy Data" + }, + "subzeroSlammerPhysical": { + name: "Subzero Slammer", + effect: "The user dramatically drops the temperature using its Z-Power and freezes the target with full force. The power varies, depending on the original move." + }, + "subzeroSlammerSpecial": { + name: "Subzero Slammer", + effect: "Dummy Data" + }, + "devastatingDrakePhysical": { + name: "Devastating Drake", + effect: "The user materializes its aura using its Z-Power and attacks the target with full force. The power varies, depending on the original move." + }, + "devastatingDrakeSpecial": { + name: "Devastating Drake", + effect: "Dummy Data" + }, + "blackHoleEclipsePhysical": { + name: "Black Hole Eclipse", + effect: "The user gathers dark energy using its Z-Power and sucks the target into it. The power varies, depending on the original move." + }, + "blackHoleEclipseSpecial": { + name: "Black Hole Eclipse", + effect: "Dummy Data" + }, + "twinkleTacklePhysical": { + name: "Twinkle Tackle", + effect: "The user creates a very charming space using its Z-Power and totally toys with the target. The power varies, depending on the original move." + }, + "twinkleTackleSpecial": { + name: "Twinkle Tackle", + effect: "Dummy Data" + }, + "catastropika": { + name: "Catastropika", + effect: "The user, Pikachu, surrounds itself with the maximum amount of electricity using its Z-Power and pounces on its target with full force." + }, + "shoreUp": { + name: "Shore Up", + effect: "The user regains up to half of its max HP. It restores more HP in a sandstorm." + }, + "firstImpression": { + name: "First Impression", + effect: "Although this move has great power, it only works the first turn each time the user enters battle." + }, + "banefulBunker": { + name: "Baneful Bunker", + effect: "In addition to protecting the user from attacks, this move also poisons any attacker that makes direct contact." + }, + "spiritShackle": { + name: "Spirit Shackle", + effect: "The user attacks while simultaneously stitching the target's shadow to the ground to prevent the target from escaping." + }, + "darkestLariat": { + name: "Darkest Lariat", + effect: "The user swings both arms and hits the target. The target's stat changes don't affect this attack's damage." + }, + "sparklingAria": { + name: "Sparkling Aria", + effect: "The user bursts into song, emitting many bubbles. Any Pokémon suffering from a burn will be healed by the touch of these bubbles." + }, + "iceHammer": { + name: "Ice Hammer", + effect: "The user swings and hits with its strong, heavy fist. It lowers the user's Speed, however." + }, + "floralHealing": { + name: "Floral Healing", + effect: "The user restores the target's HP by up to half of its max HP. It restores more HP when the terrain is grass." + }, + "highHorsepower": { + name: "High Horsepower", + effect: "The user fiercely attacks the target using its entire body." + }, + "strengthSap": { + name: "Strength Sap", + effect: "The user restores its HP by the same amount as the target's Attack stat. It also lowers the target's Attack stat." + }, + "solarBlade": { + name: "Solar Blade", + effect: "In this two-turn attack, the user gathers light and fills a blade with the light's energy, attacking the target on the next turn." + }, + "leafage": { + name: "Leafage", + effect: "The user attacks by pelting the target with leaves." + }, + "spotlight": { + name: "Spotlight", + effect: "The user shines a spotlight on the target so that only the target will be attacked during the turn." + }, + "toxicThread": { + name: "Toxic Thread", + effect: "The user shoots poisonous threads to poison the target and lower the target's Speed stat." + }, + "laserFocus": { + name: "Laser Focus", + effect: "The user concentrates intensely. The attack on the next turn always results in a critical hit." + }, + "gearUp": { + name: "Gear Up", + effect: "The user engages its gears to raise the Attack and Sp. Atk stats of ally Pokémon with the Plus or Minus Ability." + }, + "throatChop": { + name: "Throat Chop", + effect: "The user attacks the target's throat, and the resultant suffering prevents the target from using moves that emit sound for two turns." + }, + "pollenPuff": { + name: "Pollen Puff", + effect: "The user attacks the enemy with a pollen puff that explodes. If the target is an ally, it gives the ally a pollen puff that restores its HP instead." + }, + "anchorShot": { + name: "Anchor Shot", + effect: "The user entangles the target with its anchor chain while attacking. The target becomes unable to flee." + }, + "psychicTerrain": { + name: "Psychic Terrain", + effect: "This protects Pokémon on the ground from priority moves and powers up Psychic-type moves for five turns." + }, + "lunge": { + name: "Lunge", + effect: "The user makes a lunge at the target, attacking with full force. This also lowers the target's Attack stat." + }, + "fireLash": { + name: "Fire Lash", + effect: "The user strikes the target with a burning lash. This also lowers the target's Defense stat." + }, + "powerTrip": { + name: "Power Trip", + effect: "The user boasts its strength and attacks the target. The more the user's stats are raised, the greater the move's power." + }, + "burnUp": { + name: "Burn Up", + effect: "To inflict massive damage, the user burns itself out. After using this move, the user will no longer be Fire type." + }, + "speedSwap": { + name: "Speed Swap", + effect: "The user exchanges Speed stats with the target." + }, + "smartStrike": { + name: "Smart Strike", + effect: "The user stabs the target with a sharp horn. This attack never misses." + }, + "purify": { + name: "Purify", + effect: "The user heals the target's status condition. If the move succeeds, it also restores the user's own HP." + }, + "revelationDance": { + name: "Revelation Dance", + effect: "The user attacks the target by dancing very hard. The user's type determines the type of this move." + }, + "coreEnforcer": { + name: "Core Enforcer", + effect: "If the Pokémon the user has inflicted damage on have already used their moves, this move eliminates the effect of the target's Ability." + }, + "tropKick": { + name: "Trop Kick", + effect: "The user lands an intense kick of tropical origins on the target. This also lowers the target's Attack stat." + }, + "instruct": { + name: "Instruct", + effect: "The user instructs the target to use the target's last move again." + }, + "beakBlast": { + name: "Beak Blast", + effect: "The user first heats up its beak, and then it attacks the target. Making direct contact with the Pokémon while it's heating up its beak results in a burn." + }, + "clangingScales": { + name: "Clanging Scales", + effect: "The user rubs the scales on its entire body and makes a huge noise to attack opposing Pokémon. The user's Defense stat goes down after the attack." + }, + "dragonHammer": { + name: "Dragon Hammer", + effect: "The user uses its body like a hammer to attack the target and inflict damage." + }, + "brutalSwing": { + name: "Brutal Swing", + effect: "The user swings its body around violently to inflict damage on everything in its vicinity." + }, + "auroraVeil": { + name: "Aurora Veil", + effect: "This move reduces damage from physical and special moves for five turns. This can be used only when it is snowing." + }, + "sinisterArrowRaid": { + name: "Sinister Arrow Raid", + effect: "The user, Decidueye, creates countless arrows using its Z-Power and shoots the target with full force." + }, + "maliciousMoonsault": { + name: "Malicious Moonsault", + effect: "The user, Incineroar, strengthens its body using its Z-Power and crashes into the target with full force." + }, + "oceanicOperetta": { + name: "Oceanic Operetta", + effect: "The user, Primarina, summons a massive amount of water using its Z-Power and attacks the target with full force." + }, + "guardianOfAlola": { + name: "Guardian of Alola", + effect: "The user, the Land Spirit Pokémon, obtains Alola's energy using its Z-Power and attacks the target with full force. This reduces the target's HP greatly." + }, + "soulStealing7StarStrike": { + name: "Soul-Stealing 7-Star Strike", + effect: "After obtaining Z-Power, the user, Marshadow, punches and kicks the target consecutively with full force." + }, + "stokedSparksurfer": { + name: "Stoked Sparksurfer", + effect: "After obtaining Z-Power, the user, Alolan Raichu, attacks the target with full force. This move leaves the target with paralysis." + }, + "pulverizingPancake": { + name: "Pulverizing Pancake", + effect: "Z-Power brings out the true capabilities of the user, Snorlax. The Pokémon moves its enormous body energetically and attacks the target with full force." + }, + "extremeEvoboost": { + name: "Extreme Evoboost", + effect: "After obtaining Z-Power, the user, Eevee, gets energy from its evolved friends and boosts its stats sharply." + }, + "genesisSupernova": { + name: "Genesis Supernova", + effect: "After obtaining Z-Power, the user, Mew, attacks the target with full force. The terrain will be charged with psychic energy." + }, + "shellTrap": { + name: "Shell Trap", + effect: "The user sets a shell trap. If the user is hit by a physical move, the trap will explode and inflict damage on opposing Pokémon." + }, + "fleurCannon": { + name: "Fleur Cannon", + effect: "The user unleashes a strong beam. The attack's recoil harshly lowers the user's Sp. Atk stat." + }, + "psychicFangs": { + name: "Psychic Fangs", + effect: "The user bites the target with its psychic capabilities. This can also destroy Light Screen and Reflect." + }, + "stompingTantrum": { + name: "Stomping Tantrum", + effect: "Driven by frustration, the user attacks the target. If the user's previous move has failed, the power of this move doubles." + }, + "shadowBone": { + name: "Shadow Bone", + effect: "The user attacks by beating the target with a bone that contains a spirit. This may also lower the target's Defense stat." + }, + "accelerock": { + name: "Accelerock", + effect: "The user smashes into the target at high speed. This move always goes first." + }, + "liquidation": { + name: "Liquidation", + effect: "The user slams into the target using a full-force blast of water. This may also lower the target's Defense stat." + }, + "prismaticLaser": { + name: "Prismatic Laser", + effect: "The user shoots powerful lasers using the power of a prism. The user can't move on the next turn." + }, + "spectralThief": { + name: "Spectral Thief", + effect: "The user hides in the target's shadow, steals the target's stat boosts, and then attacks." + }, + "sunsteelStrike": { + name: "Sunsteel Strike", + effect: "The user slams into the target with the force of a meteor. This move can be used on the target regardless of its Abilities." + }, + "moongeistBeam": { + name: "Moongeist Beam", + effect: "The user emits a sinister ray to attack the target. This move can be used on the target regardless of its Abilities." + }, + "tearfulLook": { + name: "Tearful Look", + effect: "The user gets teary eyed to make the target lose its combative spirit. This lowers the target's Attack and Sp. Atk stats." + }, + "zingZap": { + name: "Zing Zap", + effect: "A strong electric blast crashes down on the target, giving it an electric shock. This may also make the target flinch." + }, + "naturesMadness": { + name: "Nature's Madness", + effect: "The user hits the target with the force of nature. It halves the target's HP." + }, + "multiAttack": { + name: "Multi-Attack", + effect: "Cloaking itself in high energy, the user slams into the target. The memory held determines the move's type." + }, + "tenMillionVoltThunderbolt": { + name: "10,000,000 Volt Thunderbolt", + effect: "The user, Pikachu wearing a cap, powers up a jolt of electricity using its Z-Power and unleashes it. Critical hits land more easily." + }, + "mindBlown": { + name: "Mind Blown", + effect: "The user attacks everything around it by causing its own head to explode. This also damages the user." + }, + "plasmaFists": { + name: "Plasma Fists", + effect: "The user attacks with electrically charged fists. This move changes Normal-type moves to Electric-type moves." + }, + "photonGeyser": { + name: "Photon Geyser", + effect: "The user attacks a target with a pillar of light. This move inflicts Attack or Sp. Atk damage—whichever stat is higher for the user." + }, + "lightThatBurnsTheSky": { + name: "Light That Burns the Sky", + effect: "This attack inflicts Attack or Sp. Atk damage—whichever stat is higher for the user, Necrozma. This move ignores the target's Ability." + }, + "searingSunrazeSmash": { + name: "Searing Sunraze Smash", + effect: "After obtaining Z-Power, the user, Solgaleo, attacks the target with full force. This move can ignore the effect of the target's Ability." + }, + "menacingMoonrazeMaelstrom": { + name: "Menacing Moonraze Maelstrom", + effect: "After obtaining Z-Power, the user, Lunala, attacks the target with full force. This move can ignore the effect of the target's Ability." + }, + "letsSnuggleForever": { + name: "Let's Snuggle Forever", + effect: "After obtaining Z-Power, the user, Mimikyu, punches the target with full force." + }, + "splinteredStormshards": { + name: "Splintered Stormshards", + effect: "After obtaining Z-Power, the user, Lycanroc, attacks the target with full force. This move negates the effect on the battlefield." + }, + "clangorousSoulblaze": { + name: "Clangorous Soulblaze", + effect: "After obtaining Z-Power, the user, Kommo-o, attacks the opposing Pokémon with full force. This move boosts the user's stats." + }, + "zippyZap": { + name: "Zippy Zap", + effect: "The user attacks the target with bursts of electricity at high speed. This move always goes first and raises the user's evasiveness." + }, + "splishySplash": { + name: "Splishy Splash", + effect: "The user charges a huge wave with electricity and hits the opposing Pokémon with the wave. This may also leave the opposing Pokémon with paralysis." + }, + "floatyFall": { + name: "Floaty Fall", + effect: "The user floats in the air, and then dives at a steep angle to attack the target. This may also make the target flinch." + }, + "pikaPapow": { + name: "Pika Papow", + effect: "The more Pikachu loves its Trainer, the greater the move's power. It never misses." + }, + "bouncyBubble": { + name: "Bouncy Bubble", + effect: "The user attacks by shooting water bubbles at the target. It then absorbs water and restores its HP by the damage taken by the target." + }, + "buzzyBuzz": { + name: "Buzzy Buzz", + effect: "The user shoots a jolt of electricity to attack the target. This also leaves the target with paralysis." + }, + "sizzlySlide": { + name: "Sizzly Slide", + effect: "The user cloaks itself in fire and charges at the target. This also leaves the target with a burn." + }, + "glitzyGlow": { + name: "Glitzy Glow", + effect: "The user bombards the target with telekinetic force. A wondrous wall of light is put up to weaken the power of the opposing Pokémon's special moves." + }, + "baddyBad": { + name: "Baddy Bad", + effect: "The user acts bad and attacks the target. A wondrous wall of light is put up to weaken the power of the opposing Pokémon's physical moves." + }, + "sappySeed": { + name: "Sappy Seed", + effect: "The user grows a gigantic stalk that scatters seeds to attack the target. The seeds drain the target's HP every turn." + }, + "freezyFrost": { + name: "Freezy Frost", + effect: "The user attacks with a crystal made of cold frozen haze. It eliminates every stat change among all the Pokémon engaged in battle." + }, + "sparklySwirl": { + name: "Sparkly Swirl", + effect: "The user attacks the target by wrapping it with a whirlwind of an overpowering scent. This also heals all status conditions of the user's party." + }, + "veeveeVolley": { + name: "Veevee Volley", + effect: "The more Eevee loves its Trainer, the greater the move's power. It never misses." + }, + "doubleIronBash": { + name: "Double Iron Bash", + effect: "The user rotates, centering the hex nut in its chest, and then strikes with its arms twice in a row. This may also make the target flinch." + }, + "maxGuard": { + name: "Max Guard", + effect: "This move enables the user to protect itself from all attacks. Its chance of failing rises if it is used in succession." + }, + "dynamaxCannon": { + name: "Dynamax Cannon", + effect: "The user unleashes a strong beam from its core. Deals up to twice the damage if the target is overly leveled." + }, + "snipeShot": { + name: "Snipe Shot", + effect: "The user ignores the effects of opposing Pokémon's moves and Abilities that draw in moves, allowing this move to hit the chosen target." + }, + "jawLock": { + name: "Jaw Lock", + effect: "This move prevents the user and the target from switching out until either of them faints. The effect goes away if either of the Pokémon leaves the field." + }, + "stuffCheeks": { + name: "Stuff Cheeks", + effect: "The user eats its held Berry, then sharply raises its Defense stat." + }, + "noRetreat": { + name: "No Retreat", + effect: "This move raises all the user's stats but prevents the user from switching out or fleeing." + }, + "tarShot": { + name: "Tar Shot", + effect: "The user pours sticky tar over the target, lowering the target's Speed stat. The target becomes weaker to Fire-type moves." + }, + "magicPowder": { + name: "Magic Powder", + effect: "The user scatters a cloud of magic powder that changes the target to Psychic type." + }, + "dragonDarts": { + name: "Dragon Darts", + effect: "The user attacks twice using Dreepy. If there are two targets, this move hits each target once." + }, + "teatime": { + name: "Teatime", + effect: "The user has teatime with all the Pokémon in the battle. Each Pokémon eats its held Berry." + }, + "octolock": { + name: "Octolock", + effect: "The user locks the target in and prevents it from fleeing. This move also lowers the target's Defense and Sp. Def every turn." + }, + "boltBeak": { + name: "Bolt Beak", + effect: "The user stabs the target with its electrified beak. If the user attacks before the target, the power of this move is doubled." + }, + "fishiousRend": { + name: "Fishious Rend", + effect: "The user rends the target with its hard gills. If the user attacks before the target, the power of this move is doubled." + }, + "courtChange": { + name: "Court Change", + effect: "With its mysterious power, the user swaps the effects on either side of the field." + }, + "maxFlare": { + name: "Max Flare", + effect: "This is a Fire-type attack Dynamax Pokémon use. The user intensifies the sun for five turns." + }, + "maxFlutterby": { + name: "Max Flutterby", + effect: "This is a Bug-type attack Dynamax Pokémon use. This lowers the target's Sp. Atk stat." + }, + "maxLightning": { + name: "Max Lightning", + effect: "This is an Electric-type attack Dynamax Pokémon use. The user turns the ground into Electric Terrain for five turns." + }, + "maxStrike": { + name: "Max Strike", + effect: "This is a Normal-type attack Dynamax Pokémon use. This lowers the target's Speed stat." + }, + "maxKnuckle": { + name: "Max Knuckle", + effect: "This is a Fighting-type attack Dynamax Pokémon use. This raises ally Pokémon's Attack stats." + }, + "maxPhantasm": { + name: "Max Phantasm", + effect: "This is a Ghost-type attack Dynamax Pokémon use. This lowers the target's Defense stat." + }, + "maxHailstorm": { + name: "Max Hailstorm", + effect: "This is an Ice-type attack Dynamax Pokémon use. The user summons a hailstorm lasting five turns." + }, + "maxOoze": { + name: "Max Ooze", + effect: "This is a Poison-type attack Dynamax Pokémon use. This raises ally Pokémon's Sp. Atk stats." + }, + "maxGeyser": { + name: "Max Geyser", + effect: "This is a Water-type attack Dynamax Pokémon use. The user summons a heavy rain that falls for five turns." + }, + "maxAirstream": { + name: "Max Airstream", + effect: "This is a Flying-type attack Dynamax Pokémon use. This raises ally Pokémon's Speed stats." + }, + "maxStarfall": { + name: "Max Starfall", + effect: "This is a Fairy-type attack Dynamax Pokémon use. The user turns the ground into Misty Terrain for five turns." + }, + "maxWyrmwind": { + name: "Max Wyrmwind", + effect: "This is a Dragon-type attack Dynamax Pokémon use. This lowers the target's Attack stat." + }, + "maxMindstorm": { + name: "Max Mindstorm", + effect: "This is a Psychic-type attack Dynamax Pokémon use. The user turns the ground into Psychic Terrain for five turns." + }, + "maxRockfall": { + name: "Max Rockfall", + effect: "This is a Rock-type attack Dynamax Pokémon use. The user summons a sandstorm lasting five turns." + }, + "maxQuake": { + name: "Max Quake", + effect: "This is a Ground-type attack Dynamax Pokémon use. This raises ally Pokémon's Sp. Def stats." + }, + "maxDarkness": { + name: "Max Darkness", + effect: "This is a Dark-type attack Dynamax Pokémon use. This lowers the target's Sp. Def stat." + }, + "maxOvergrowth": { + name: "Max Overgrowth", + effect: "This is a Grass-type attack Dynamax Pokémon use. The user turns the ground into Grassy Terrain for five turns." + }, + "maxSteelspike": { + name: "Max Steelspike", + effect: "This is a Steel-type attack Dynamax Pokémon use. This raises ally Pokémon's Defense stats." + }, + "clangorousSoul": { + name: "Clangorous Soul", + effect: "The user raises all its stats by using some of its HP." + }, + "bodyPress": { + name: "Body Press", + effect: "The user attacks by slamming its body into the target. The higher the user's Defense, the more damage it can inflict on the target." + }, + "decorate": { + name: "Decorate", + effect: "The user sharply raises the target's Attack and Sp. Atk stats by decorating the target." + }, + "drumBeating": { + name: "Drum Beating", + effect: "The user plays its drum, controlling the drum's roots to attack the target. This also lowers the target's Speed stat." + }, + "snapTrap": { + name: "Snap Trap", + effect: "The user snares the target in a snap trap for four to five turns." + }, + "pyroBall": { + name: "Pyro Ball", + effect: "The user attacks by igniting a small stone and launching it as a fiery ball at the target. This may also leave the target with a burn." + }, + "behemothBlade": { + name: "Behemoth Blade", + effect: "The user wields a large, powerful sword using its whole body and cuts the target in a vigorous attack." + }, + "behemothBash": { + name: "Behemoth Bash", + effect: "The user's body becomes a firm shield and slams into the target fiercely." + }, + "auraWheel": { + name: "Aura Wheel", + effect: "Morpeko attacks and raises its Speed with the energy stored in its cheeks. This move's type changes depending on the user's form." + }, + "breakingSwipe": { + name: "Breaking Swipe", + effect: "The user swings its tough tail wildly and attacks opposing Pokémon. This also lowers their Attack stats." + }, + "branchPoke": { + name: "Branch Poke", + effect: "The user attacks the target by poking it with a sharply pointed branch." + }, + "overdrive": { + name: "Overdrive", + effect: "The user attacks opposing Pokémon by twanging a guitar or bass guitar, causing a huge echo and strong vibration." + }, + "appleAcid": { + name: "Apple Acid", + effect: "The user attacks the target with an acidic liquid created from tart apples. This also lowers the target's Sp. Def stat." + }, + "gravApple": { + name: "Grav Apple", + effect: "The user inflicts damage by dropping an apple from high above. This also lowers the target's Defense stat." + }, + "spiritBreak": { + name: "Spirit Break", + effect: "The user attacks the target with so much force that it could break the target's spirit. This also lowers the target's Sp. Atk stat." + }, + "strangeSteam": { + name: "Strange Steam", + effect: "The user attacks the target by emitting steam. This may also confuse the target." + }, + "lifeDew": { + name: "Life Dew", + effect: "The user scatters mysterious water around and restores the HP of itself and its ally Pokémon in the battle." + }, + "obstruct": { + name: "Obstruct", + effect: "This move enables the user to protect itself from all attacks. Its chance of failing rises if it is used in succession. Direct contact harshly lowers the attacker's Defense stat." + }, + "falseSurrender": { + name: "False Surrender", + effect: "The user pretends to bow its head, but then it stabs the target with its disheveled hair. This attack never misses." + }, + "meteorAssault": { + name: "Meteor Assault", + effect: "The user attacks wildly with its thick leek. The user can't move on the next turn, because the force of this move makes it stagger." + }, + "eternabeam": { + name: "Eternabeam", + effect: "This is Eternatus's most powerful attack in its original form. The user can't move on the next turn." + }, + "steelBeam": { + name: "Steel Beam", + effect: "The user fires a beam of steel that it collected from its entire body. This also damages the user." + }, + "expandingForce": { + name: "Expanding Force", + effect: "The user attacks the target with its psychic power. This move's power goes up and damages all opposing Pokémon on Psychic Terrain." + }, + "steelRoller": { + name: "Steel Roller", + effect: "The user attacks while destroying the terrain. This move fails when the ground hasn't turned into a terrain." + }, + "scaleShot": { + name: "Scale Shot", + effect: "The user attacks by shooting scales two to five times in a row. This move boosts the user's Speed stat but lowers its Defense stat." + }, + "meteorBeam": { + name: "Meteor Beam", + effect: "In this two-turn attack, the user gathers space power and boosts its Sp. Atk stat, then attacks the target on the next turn." + }, + "shellSideArm": { + name: "Shell Side Arm", + effect: "This move inflicts physical or special damage, whichever will be more effective. This may also poison the target." + }, + "mistyExplosion": { + name: "Misty Explosion", + effect: "The user attacks everything around it and faints upon using this move. This move's power is increased on Misty Terrain." + }, + "grassyGlide": { + name: "Grassy Glide", + effect: "Gliding on the ground, the user attacks the target. This move always goes first on Grassy Terrain." + }, + "risingVoltage": { + name: "Rising Voltage", + effect: "The user attacks with electric voltage rising from the ground. This move's power doubles when the target is on Electric Terrain." + }, + "terrainPulse": { + name: "Terrain Pulse", + effect: "The user utilizes the power of the terrain to attack. This move's type and power changes depending on the terrain when it's used." + }, + "skitterSmack": { + name: "Skitter Smack", + effect: "The user skitters behind the target to attack. This also lowers the target's Sp. Atk stat." + }, + "burningJealousy": { + name: "Burning Jealousy", + effect: "The user attacks with energy from jealousy. This leaves all opposing Pokémon that have had their stats boosted during the turn with a burn." + }, + "lashOut": { + name: "Lash Out", + effect: "The user lashes out to vent its frustration toward the target. If the user's stats were lowered during this turn, the power of this move is doubled." + }, + "poltergeist": { + name: "Poltergeist", + effect: "The user attacks the target by controlling the target's item. The move fails if the target doesn't have an item." + }, + "corrosiveGas": { + name: "Corrosive Gas", + effect: "The user surrounds everything around it with highly acidic gas and melts away items they hold." + }, + "coaching": { + name: "Coaching", + effect: "The user properly coaches its ally Pokémon, boosting their Attack and Defense stats." + }, + "flipTurn": { + name: "Flip Turn", + effect: "After making its attack, the user rushes back to switch places with a party Pokémon in waiting." + }, + "tripleAxel": { + name: "Triple Axel", + effect: "A consecutive three-kick attack that becomes more powerful with each successful hit." + }, + "dualWingbeat": { + name: "Dual Wingbeat", + effect: "The user slams the target with its wings. The target is hit twice in a row." + }, + "scorchingSands": { + name: "Scorching Sands", + effect: "The user throws scorching sand at the target to attack. This may also leave the target with a burn." + }, + "jungleHealing": { + name: "Jungle Healing", + effect: "The user becomes one with the jungle, restoring HP and healing any status conditions of itself and its ally Pokémon in battle." + }, + "wickedBlow": { + name: "Wicked Blow", + effect: "The user, having mastered the Dark style, strikes the target with a fierce blow. This attack always results in a critical hit." + }, + "surgingStrikes": { + name: "Surging Strikes", + effect: "The user, having mastered the Water style, strikes the target with a flowing motion three times in a row. This attack always results in a critical hit." + }, + "thunderCage": { + name: "Thunder Cage", + effect: "The user traps the target in a cage of sparking electricity for four to five turns." + }, + "dragonEnergy": { + name: "Dragon Energy", + effect: "Converting its life-force into power, the user attacks opposing Pokémon. The lower the user's HP, the lower the move's power." + }, + "freezingGlare": { + name: "Freezing Glare", + effect: "The user shoots its psychic power from its eyes to attack. This may also leave the target frozen." + }, + "fieryWrath": { + name: "Fiery Wrath", + effect: "The user transforms its wrath into a fire-like aura to attack. This may also make opposing Pokémon flinch." + }, + "thunderousKick": { + name: "Thunderous Kick", + effect: "The user overwhelms the target with lightning-like movement before delivering a kick. This also lowers the target's Defense stat." + }, + "glacialLance": { + name: "Glacial Lance", + effect: "The user attacks by hurling a blizzard-cloaked icicle lance at opposing Pokémon." + }, + "astralBarrage": { + name: "Astral Barrage", + effect: "The user attacks by sending a frightful amount of small ghosts at opposing Pokémon." + }, + "eerieSpell": { + name: "Eerie Spell", + effect: "The user attacks with its tremendous psychic power. This also removes 3 PP from the target's last move." + }, + "direClaw": { + name: "Dire Claw", + effect: "The user lashes out at the target with ruinous claws. This may also leave the target poisoned, paralyzed, or asleep." + }, + "psyshieldBash": { + name: "Psyshield Bash", + effect: "Cloaking itself in psychic energy, the user slams into the target. This also boosts the user's Defense stat." + }, + "powerShift": { + name: "Power Shift", + effect: "The user swaps its Attack and Defense stats." + }, + "stoneAxe": { + name: "Stone Axe", + effect: "The user swings its stone axes at the target. Stone splinters left behind by this attack float around the target." + }, + "springtideStorm": { + name: "Springtide Storm", + effect: "The user attacks by wrapping opposing Pokémon in fierce winds brimming with love and hate. This may also lower their Attack stats." + }, + "mysticalPower": { + name: "Mystical Power", + effect: "The user attacks by emitting a mysterious power. This also boosts the user's Sp. Atk stat." + }, + "ragingFury": { + name: "Raging Fury", + effect: "The user rampages around spewing flames for two to three turns. The user then becomes confused." + }, + "waveCrash": { + name: "Wave Crash", + effect: "The user shrouds itself in water and slams into the target with its whole body to inflict damage. This also damages the user quite a lot." + }, + "chloroblast": { + name: "Chloroblast", + effect: "The user launches its amassed chlorophyll to inflict damage on the target. This also damages the user." + }, + "mountainGale": { + name: "Mountain Gale", + effect: "The user hurls giant chunks of ice at the target to inflict damage. This may also make the target flinch." + }, + "victoryDance": { + name: "Victory Dance", + effect: "The user performs an intense dance to usher in victory, boosting its Attack, Defense, and Speed stats." + }, + "headlongRush": { + name: "Headlong Rush", + effect: "The user smashes into the target in a full-body tackle. This also lowers the user's Defense and Sp. Def stats." + }, + "barbBarrage": { + name: "Barb Barrage", + effect: "The user launches countless toxic barbs to inflict damage. This may also poison the target. This move's power is doubled if the target is already poisoned." + }, + "esperWing": { + name: "Esper Wing", + effect: "The user slashes the target with aura-enriched wings. This also boosts the user's Speed stat. This move has a heightened chance of landing a critical hit." + }, + "bitterMalice": { + name: "Bitter Malice", + effect: "The user attacks the target with spine-chilling resentment. This also lowers the target's Attack stat." + }, + "shelter": { + name: "Shelter", + effect: "The user makes its skin as hard as an iron shield, sharply boosting its Defense stat." + }, + "tripleArrows": { + name: "Triple Arrows", + effect: "The user kicks, then fires three arrows. This move has a heightened chance of landing a critical hit and may also lower the target's Defense stat or make it flinch." + }, + "infernalParade": { + name: "Infernal Parade", + effect: "The user attacks with myriad fireballs. This may also leave the target with a burn. This move's power is doubled if the target has a status condition." + }, + "ceaselessEdge": { + name: "Ceaseless Edge", + effect: "The user slashes its shell blade at the target. Shell splinters left behind by this attack remain scattered under the target as spikes." + }, + "bleakwindStorm": { + name: "Bleakwind Storm", + effect: "The user attacks with savagely cold winds that cause both body and spirit to tremble. This may also lower the Speed stats of opposing Pokémon." + }, + "wildboltStorm": { + name: "Wildbolt Storm", + effect: "The user summons a thunderous tempest and savagely attacks with lightning and wind. This may also leave opposing Pokémon with paralysis." + }, + "sandsearStorm": { + name: "Sandsear Storm", + effect: "The user attacks by wrapping opposing Pokémon in fierce winds and searingly hot sand. This may also leave them with a burn." + }, + "lunarBlessing": { + name: "Lunar Blessing", + effect: "The user receives a blessing from the crescent moon, restoring HP and curing status conditions for itself and its ally Pokémon currently in the battle." + }, + "takeHeart": { + name: "Take Heart", + effect: "The user lifts its spirits, curing its own status conditions and boosting its Sp. Atk and Sp. Def stats." + }, + "gMaxWildfire": { + name: "G-Max Wildfire", + effect: "A Fire-type attack that Gigantamax Charizard use. This move continues to deal damage to opponents for four turns." + }, + "gMaxBefuddle": { + name: "G-Max Befuddle", + effect: "A Bug-type attack that Gigantamax Butterfree use. This move inflicts the poisoned, paralyzed, or asleep status condition on opponents." + }, + "gMaxVoltCrash": { + name: "G-Max Volt Crash", + effect: "An Electric-type attack that Gigantamax Pikachu use. This move paralyzes opponents." + }, + "gMaxGoldRush": { + name: "G-Max Gold Rush", + effect: "A Normal-type attack that Gigantamax Meowth use. This move confuses opponents and also earns extra money." + }, + "gMaxChiStrike": { + name: "G-Max Chi Strike", + effect: "A Fighting-type attack that Gigantamax Machamp use. This move raises the chance of critical hits." + }, + "gMaxTerror": { + name: "G-Max Terror", + effect: "A Ghost-type attack that Gigantamax Gengar use. This Pokémon steps on the opposing Pokémon's shadow to prevent them from escaping." + }, + "gMaxResonance": { + name: "G-Max Resonance", + effect: "An Ice-type attack that Gigantamax Lapras use. This move reduces the damage received for five turns." + }, + "gMaxCuddle": { + name: "G-Max Cuddle", + effect: "A Normal-type attack that Gigantamax Eevee use. This move infatuates opponents." + }, + "gMaxReplenish": { + name: "G-Max Replenish", + effect: "A Normal-type attack that Gigantamax Snorlax use. This move restores Berries that have been eaten." + }, + "gMaxMalodor": { + name: "G-Max Malodor", + effect: "A Poison-type attack that Gigantamax Garbodor use. This move poisons opponents." + }, + "gMaxStonesurge": { + name: "G-Max Stonesurge", + effect: "A Water-type attack that Gigantamax Drednaw use. This move scatters sharp rocks around the field." + }, + "gMaxWindRage": { + name: "G-Max Wind Rage", + effect: "A Flying-type attack that Gigantamax Corviknight use. This move removes the effects of moves like Reflect and Light Screen." + }, + "gMaxStunShock": { + name: "G-Max Stun Shock", + effect: "An Electric-type attack that Gigantamax Toxtricity use. This move poisons or paralyzes opponents." + }, + "gMaxFinale": { + name: "G-Max Finale", + effect: "A Fairy-type attack that Gigantamax Alcremie use. This move heals the HP of allies." + }, + "gMaxDepletion": { + name: "G-Max Depletion", + effect: "A Dragon-type attack that Gigantamax Duraludon use. Reduces the PP of the last move used." + }, + "gMaxGravitas": { + name: "G-Max Gravitas", + effect: "A Psychic-type attack that Gigantamax Orbeetle use. This move changes gravity for five turns." + }, + "gMaxVolcalith": { + name: "G-Max Volcalith", + effect: "A Rock-type attack that Gigantamax Coalossal use. This move continues to deal damage to opponents for four turns." + }, + "gMaxSandblast": { + name: "G-Max Sandblast", + effect: "A Ground-type attack that Gigantamax Sandaconda use. Opponents are trapped in a raging sandstorm for four to five turns." + }, + "gMaxSnooze": { + name: "G-Max Snooze", + effect: "A Dark-type attack that Gigantamax Grimmsnarl use. The user lets loose a huge yawn that lulls the targets into falling asleep on the next turn." + }, + "gMaxTartness": { + name: "G-Max Tartness", + effect: "A Grass-type attack that Gigantamax Flapple use. This move reduces the opponents' evasiveness." + }, + "gMaxSweetness": { + name: "G-Max Sweetness", + effect: "A Grass-type attack that Gigantamax Appletun use. This move heals the status conditions of allies." + }, + "gMaxSmite": { + name: "G-Max Smite", + effect: "A Fairy-type attack that Gigantamax Hatterene use. This move confuses opponents." + }, + "gMaxSteelsurge": { + name: "G-Max Steelsurge", + effect: "A Steel-type attack that Gigantamax Copperajah use. This move scatters sharp spikes around the field." + }, + "gMaxMeltdown": { + name: "G-Max Meltdown", + effect: "A Steel-type attack that Gigantamax Melmetal use. This move makes opponents incapable of using the same move twice in a row." + }, + "gMaxFoamBurst": { + name: "G-Max Foam Burst", + effect: "A Water-type attack that Gigantamax Kingler use. This move harshly lowers the Speed of opponents." + }, + "gMaxCentiferno": { + name: "G-Max Centiferno", + effect: "A Fire-type attack that Gigantamax Centiskorch use. This move traps opponents in flames for four to five turns." + }, + "gMaxVineLash": { + name: "G-Max Vine Lash", + effect: "A Grass-type attack that Gigantamax Venusaur use. This move continues to deal damage to opponents for four turns." + }, + "gMaxCannonade": { + name: "G-Max Cannonade", + effect: "A Water-type attack that Gigantamax Blastoise use. This move continues to deal damage to opponents for four turns." + }, + "gMaxDrumSolo": { + name: "G-Max Drum Solo", + effect: "A Grass-type attack that Gigantamax Rillaboom use. This move can be used on the target regardless of its Abilities." + }, + "gMaxFireball": { + name: "G-Max Fireball", + effect: "A Fire-type attack that Gigantamax Cinderace use. This move can be used on the target regardless of its Abilities." + }, + "gMaxHydrosnipe": { + name: "G-Max Hydrosnipe", + effect: "A Water-type attack that Gigantamax Inteleon use. This move can be used on the target regardless of its Abilities." + }, + "gMaxOneBlow": { + name: "G-Max One Blow", + effect: "A Dark-type attack that Gigantamax Urshifu use. This single-strike move can ignore Max Guard." + }, + "gMaxRapidFlow": { + name: "G-Max Rapid Flow", + effect: "A Water-type attack that Gigantamax Urshifu use. This rapid-strike move can ignore Max Guard." + }, + "teraBlast": { + name: "Tera Blast", + effect: "If the user has Terastallized, it unleashes energy of its Tera Type. This move inflicts damage using the Attack or Sp. Atk stat-whichever is higher for the user." + }, + "silkTrap": { + name: "Silk Trap", + effect: "The user spins a silken trap, protecting itself from damage while lowering the Speed stat of any attacker that makes direct contact." + }, + "axeKick": { + name: "Axe Kick", + effect: "The user attacks by kicking up into the air and slamming its heel down upon the target. This may also confuse the target. If it misses, the user takes damage instead." + }, + "lastRespects": { + name: "Last Respects", + effect: "The user attacks to avenge its allies. The more defeated allies there are in the user's party, the greater the move's power." + }, + "luminaCrash": { + name: "Lumina Crash", + effect: "The user attacks by unleashing a peculiar light that even affects the mind. This also harshly lowers the target's Sp. Def stat." + }, + "orderUp": { + name: "Order Up", + effect: "The user attacks with elegant poise. If the user has a Tatsugiri in its mouth, this move boosts one of the user's stats based on the Tatsugiri's form." + }, + "jetPunch": { + name: "Jet Punch", + effect: "The user summons a torrent around its fist and punches at blinding speed. This move always goes first." + }, + "spicyExtract": { + name: "Spicy Extract", + effect: "The user emits an incredibly spicy extract, sharply boosting the target's Attack stat and harshly lowering the target's Defense stat." + }, + "spinOut": { + name: "Spin Out", + effect: "The user spins furiously by straining its legs, inflicting damage on the target. This also harshly lowers the user's Speed stat." + }, + "populationBomb": { + name: "Population Bomb", + effect: "The user's fellows gather in droves to perform a combo attack that hits the target one to ten times in a row." + }, + "iceSpinner": { + name: "Ice Spinner", + effect: "The user covers its feet in thin ice and twirls around, slamming into the target. This move's spinning motion also destroys the terrain." + }, + "glaiveRush": { + name: "Glaive Rush", + effect: "The user throws its entire body into a reckless charge. After this move is used, attacks on the user cannot miss and will inflict double damage until the user's next turn." + }, + "revivalBlessing": { + name: "Revival Blessing", + effect: "The user bestows a loving blessing, reviving a party Pokémon that has fainted and restoring half that Pokémon's max HP." + }, + "saltCure": { + name: "Salt Cure", + effect: "The user salt cures the target, inflicting damage every turn. Steel and Water types are more strongly affected by this move." + }, + "tripleDive": { + name: "Triple Dive", + effect: "The user performs a perfectly timed triple dive, hitting the target with splashes of water three times in a row." + }, + "mortalSpin": { + name: "Mortal Spin", + effect: "The user performs a spin attack that can also eliminate the effects of such moves as Bind, Wrap, and Leech Seed. This also poisons opposing Pokémon." + }, + "doodle": { + name: "Doodle", + effect: "The user captures the very essence of the target in a sketch. This changes the Abilities of the user and its ally Pokémon to that of the target." + }, + "filletAway": { + name: "Fillet Away", + effect: "The user sharply boosts its Attack, Sp. Atk, and Speed stats by using its own HP." + }, + "kowtowCleave": { + name: "Kowtow Cleave", + effect: "The user slashes at the target after kowtowing to make the target let down its guard. This attack never misses." + }, + "flowerTrick": { + name: "Flower Trick", + effect: "The user throws a rigged bouquet of flowers at the target. This attack never misses and always lands a critical hit." + }, + "torchSong": { + name: "Torch Song", + effect: "The user blows out raging flames as if singing a song, scorching the target. This also boosts the user's Sp. Atk stat." + }, + "aquaStep": { + name: "Aqua Step", + effect: "The user toys with the target and attacks it using light and fluid dance steps. This also boosts the user's Speed stat." + }, + "ragingBull": { + name: "Raging Bull", + effect: "The user performs a tackle like a raging bull. This move's type depends on the user's form. It can also break barriers, such as Light Screen and Reflect." + }, + "makeItRain": { + name: "Make It Rain", + effect: "The user attacks by throwing out a mass of coins. This also lowers the user's Sp. Atk stat. Money is earned after the battle." + }, + "psyblade": { + name: "Psyblade", + effect: "The user rends the target with an ethereal blade. This move's power is boosted by 50 percent if the user is on Electric Terrain." + }, + "hydroSteam": { + name: "Hydro Steam", + effect: "The user blasts the target with boiling-hot water. This move's power is not lowered in harsh sunlight but rather boosted by 50 percent." + }, + "ruination": { + name: "Ruination", + effect: "The user summons a ruinous disaster. This cuts the target's HP in half." + }, + "collisionCourse": { + name: "Collision Course", + effect: "The user transforms and crashes to the ground, causing a massive prehistoric explosion. This move's power is boosted more than usual if it's a supereffective hit." + }, + "electroDrift": { + name: "Electro Drift", + effect: "The user races forward at ultrafast speeds, piercing its target with futuristic electricity. This move's power is boosted more than usual if it's a supereffective hit." + }, + "shedTail": { + name: "Shed Tail", + effect: "The user creates a substitute for itself using its own HP before switching places with a party Pokémon in waiting." + }, + "chillyReception": { + name: "Chilly Reception", + effect: "The user tells a chillingly bad joke before switching places with a party Pokémon in waiting. This summons a snowstorm lasting five turns." + }, + "tidyUp": { + name: "Tidy Up", + effect: "The user tidies up and removes the effects of Spikes, Stealth Rock, Sticky Web, Toxic Spikes, and Substitute. This also boosts the user's Attack and Speed stats." + }, + "snowscape": { + name: "Snowscape", + effect: "The user summons a snowstorm lasting five turns. This boosts the Defense stats of Ice types." + }, + "pounce": { + name: "Pounce", + effect: "The user attacks by pouncing on the target. This also lowers the target's Speed stat." + }, + "trailblaze": { + name: "Trailblaze", + effect: "The user attacks suddenly as if leaping out from tall grass. The user's nimble footwork boosts its Speed stat." + }, + "chillingWater": { + name: "Chilling Water", + effect: "The user attacks the target by showering it with water that's so cold it saps the target's power. This also lowers the target's Attack stat." + }, + "hyperDrill": { + name: "Hyper Drill", + effect: "The user spins the pointed part of its body at high speed to pierce the target. This attack can hit a target using a move such as Protect or Detect." + }, + "twinBeam": { + name: "Twin Beam", + effect: "The user shoots mystical beams from its eyes to inflict damage. The target is hit twice in a row." + }, + "rageFist": { + name: "Rage Fist", + effect: "The user converts its rage into energy to attack. The more times the user has been hit by attacks, the greater the move's power." + }, + "armorCannon": { + name: "Armor Cannon", + effect: "The user shoots its own armor out as blazing projectiles. This also lowers the user's Defense and Sp. Def stats." + }, + "bitterBlade": { + name: "Bitter Blade", + effect: "The user focuses its bitter feelings toward the world of the living into a slashing attack. The user's HP is restored by up to half the damage taken by the target." + }, + "doubleShock": { + name: "Double Shock", + effect: "The user discharges all the electricity from its body to perform a high-damage attack. After using this move, the user will no longer be Electric type." + }, + "gigatonHammer": { + name: "Gigaton Hammer", + effect: "The user swings its whole body around to attack with its huge hammer. This move can't be used twice in a row." + }, + "comeuppance": { + name: "Comeuppance", + effect: "The user retaliates with much greater force against the opponent that last inflicted damage on it." + }, + "aquaCutter": { + name: "Aqua Cutter", + effect: "The user expels pressurized water to cut at the target like a blade. This move has a heightened chance of landing a critical hit." + }, + "blazingTorque": { + name: "Blazing Torque", + effect: "The user revs their blazing engine into the target. This may also leave the target with a burn." + }, + "wickedTorque": { + name: "Wicked Torque", + effect: "The user revs their engine into the target with malicious intent. This may put the target to sleep." + }, + "noxiousTorque": { + name: "Noxious Torque", + effect: "The user revs their poisonous engine into the target. This may also poison the target." + }, + "combatTorque": { + name: "Combat Torque", + effect: "The user revs their engine forcefully into the target. This may also leave the target with paralysis." + }, + "magicalTorque": { + name: "Magical Torque", + effect: "The user revs their fae-like engine into the target. This may also confuse the target." + }, + "bloodMoon": { + name: "Blood Moon", + effect: "The user unleashes the full brunt of its spirit from a full moon that shines as red as blood. This move can't be used twice in a row." + }, + "matchaGotcha": { + name: "Matcha Gotcha", + effect: "The user fires a blast of tea that it mixed. The user's HP is restored by up to half the damage taken by the target. This may also leave the target with a burn." + }, + "syrupBomb": { + name: "Syrup Bomb", + effect: "The user sets off an explosion of sticky candy syrup, which coats the target and causes the target's Speed stat to drop each turn for three turns." + }, + "ivyCudgel": { + name: "Ivy Cudgel", + effect: "The user strikes with an ivy-wrapped cudgel. This move's type changes depending on the mask worn by the user, and it has a heightened chance of landing a critical hit." + }, + "electroShot": { + name: "Electro Shot", + effect: "The user gathers electricity on the first turn, boosting its Sp. Atk stat, then fires a high-voltage shot on the next turn. The shot will be fired immediately in rain." + }, + "teraStarstorm": { + name: "Tera Starstorm", + effect: "With the power of its crystals, the user bombards and eliminates the target. When used by Terapagos in its Stellar Form, this move damages all opposing Pokémon." + }, + "fickleBeam": { + name: "Fickle Beam", + effect: "The user shoots a beam of light to inflict damage. Sometimes all the user's heads shoot beams in unison, doubling the move's power." + }, + "burningBulwark": { + name: "Burning Bulwark", + effect: "The user's intensely hot fur protects it from attacks and also burns any attacker that makes direct contact with it." + }, + "thunderclap": { + name: "Thunderclap", + effect: "This move enables the user to attack first with a jolt of electricity. This move fails if the target is not readying an attack." + }, + "mightyCleave": { + name: "Mighty Cleave", + effect: "The user wields the light that has accumulated atop its head to cleave the target. This move hits even if the target protects itself." + }, + "tachyonCutter": { + name: "Tachyon Cutter", + effect: "The user attacks by launching particle blades at the target twice in a row. This attack never misses." + }, + "hardPress": { + name: "Hard Press", + effect: "The target is crushed with an arm, a claw, or the like to inflict damage. The more HP the target has left, the greater the move's power." + }, + "dragonCheer": { + name: "Dragon Cheer", + effect: "The user raises its allies' morale with a draconic cry so that their future attacks have a heightened chance of landing critical hits. This rouses Dragon types more." + }, + "alluringVoice": { + name: "Alluring Voice", + effect: "The user attacks the target using its angelic voice. This also confuses the target if its stats have been boosted during the turn." + }, + "temperFlare": { + name: "Temper Flare", + effect: "Spurred by desperation, the user attacks the target. This move's power is doubled if the user's previous move failed." + }, + "supercellSlam": { + name: "Supercell Slam", + effect: "The user electrifies its body and drops onto the target to inflict damage. If this move misses, the user takes damage instead." + }, + "psychicNoise": { + name: "Psychic Noise", + effect: "The user attacks the target with unpleasant sound waves. For two turns, the target is prevented from recovering HP through moves, Abilities, or held items." + }, + "upperHand": { + name: "Upper Hand", + effect: "The user reacts to the target's movement and strikes with the heel of its palm, making the target flinch. This move fails if the target is not readying a priority move." + }, + "malignantChain": { + name: "Malignant Chain", + effect: "The user pours toxins into the target by wrapping them in a toxic, corrosive chain. This may also leave the target badly poisoned." + } +} as const; diff --git a/src/locales/ca-ES/nature.ts b/src/locales/ca-ES/nature.ts new file mode 100644 index 00000000000..9ab26f3eb2a --- /dev/null +++ b/src/locales/ca-ES/nature.ts @@ -0,0 +1,29 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +export const nature: SimpleTranslationEntries = { + "Hardy": "Hardy", + "Lonely": "Lonely", + "Brave": "Brave", + "Adamant": "Adamant", + "Naughty": "Naughty", + "Bold": "Bold", + "Docile": "Docile", + "Relaxed": "Relaxed", + "Impish": "Impish", + "Lax": "Lax", + "Timid": "Timid", + "Hasty": "Hasty", + "Serious": "Serious", + "Jolly": "Jolly", + "Naive": "Naive", + "Modest": "Modest", + "Mild": "Mild", + "Quiet": "Quiet", + "Bashful": "Bashful", + "Rash": "Rash", + "Calm": "Calm", + "Gentle": "Gentle", + "Sassy": "Sassy", + "Careful": "Careful", + "Quirky": "Quirky" +} as const; diff --git a/src/locales/ca-ES/party-ui-handler.ts b/src/locales/ca-ES/party-ui-handler.ts new file mode 100644 index 00000000000..4f300dd36ea --- /dev/null +++ b/src/locales/ca-ES/party-ui-handler.ts @@ -0,0 +1,54 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +export const partyUiHandler: SimpleTranslationEntries = { + "SEND_OUT": "Send Out", + "SUMMARY": "Summary", + "CANCEL": "Cancel", + "RELEASE": "Release", + "APPLY": "Apply", + "TEACH": "Teach", + "SPLICE": "Splice", + "UNSPLICE": "Unsplice", + "ACTIVATE": "Activate", + "DEACTIVATE": "Deactivate", + "TRANSFER": "Transfer", + "ALL": "All", + "PASS_BATON": "Pass Baton", + "UNPAUSE_EVOLUTION": "Unpause Evolution", + "REVIVE": "Revive", + "RENAME": "Rename", + + "choosePokemon": "Choose a Pokémon.", + "doWhatWithThisPokemon": "Do what with this Pokémon?", + "noEnergy": "{{pokemonName}} has no energy\nleft to battle!", + "hasEnergy": "{{pokemonName}} still has energy\nto battle!", + "cantBeUsed": "{{pokemonName}} can't be used in\nthis challenge!", + "tooManyItems": "{{pokemonName}} has too many\nof this item!", + "anyEffect": "It won't have any effect.", + "unpausedEvolutions": "Evolutions have been unpaused for {{pokemonName}}.", + "unspliceConfirmation": "Do you really want to unsplice {{fusionName}}\nfrom {{pokemonName}}? {{fusionName}} will be lost.", + "wasReverted": "{{fusionName}} was reverted to {{pokemonName}}.", + "releaseConfirmation": "Do you really want to release {{pokemonName}}?", + "releaseInBattle": "You can't release a Pokémon that's in battle!", + "selectAMove": "Select a move.", + "changeQuantity": "Select a held item to transfer.\nUse < and > to change the quantity.", + "selectAnotherPokemonToSplice": "Select another Pokémon to splice.", + "cancel": "Cancel", + + // Slot TM text + "able": "Able", + "notAble": "Not able", + "learned": "Learned", + + // Releasing messages + "goodbye": "Goodbye, {{pokemonName}}!", + "byebye": "Byebye, {{pokemonName}}!", + "farewell": "Farewell, {{pokemonName}}!", + "soLong": "So long, {{pokemonName}}!", + "thisIsWhereWePart": "This is where we part, {{pokemonName}}!", + "illMissYou": "I'll miss you, {{pokemonName}}!", + "illNeverForgetYou": "I'll never forget you, {{pokemonName}}!", + "untilWeMeetAgain": "Until we meet again, {{pokemonName}}!", + "sayonara": "Sayonara, {{pokemonName}}!", + "smellYaLater": "Smell ya later, {{pokemonName}}!", +} as const; diff --git a/src/locales/ca-ES/pokeball.ts b/src/locales/ca-ES/pokeball.ts new file mode 100644 index 00000000000..01017cac46d --- /dev/null +++ b/src/locales/ca-ES/pokeball.ts @@ -0,0 +1,10 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +export const pokeball: SimpleTranslationEntries = { + "pokeBall": "Poké Ball", + "greatBall": "Great Ball", + "ultraBall": "Ultra Ball", + "rogueBall": "Rogue Ball", + "masterBall": "Master Ball", + "luxuryBall": "Luxury Ball", +} as const; diff --git a/src/locales/ca-ES/pokemon-form.ts b/src/locales/ca-ES/pokemon-form.ts new file mode 100644 index 00000000000..e8d6fb8df4a --- /dev/null +++ b/src/locales/ca-ES/pokemon-form.ts @@ -0,0 +1,197 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +export const battlePokemonForm: SimpleTranslationEntries = { + "mega": "Mega {{pokemonName}}", + "mega-x": "Mega {{pokemonName}} X", + "mega-y": "Mega {{pokemonName}} Y", + "primal": "Primal {{pokemonName}}", + "gigantamax": "G-Max {{pokemonName}}", + "eternamax": "E-Max {{pokemonName}}", + + "megaChange": "{{preName}} Mega Evolved\ninto {{pokemonName}}!", + "gigantamaxChange": "{{preName}} Gigantamaxed\ninto {{pokemonName}}!", + "eternamaxChange": "{{preName}} Eternamaxed\ninto {{pokemonName}}!", + "revertChange": "{{pokemonName}} reverted\nto its original form!", + "formChange": "{{preName}} changed form!", +} as const; + +export const pokemonForm: SimpleTranslationEntries = { + // Starters forms + // 1G + "pikachuCosplay": "Cosplay", + "pikachuCoolCosplay": "Cool Cosplay", + "pikachuBeautyCosplay": "Beauty Cosplay", + "pikachuCuteCosplay": "Cute Cosplay", + "pikachuSmartCosplay": "Smart Cosplay", + "pikachuToughCosplay": "Tough Cosplay", + "pikachuPartner": "Partner", + "eeveePartner": "Partner", + // 2G + "pichuSpiky": "Spiky", + "unownA": "A", + "unownB": "B", + "unownC": "C", + "unownD": "D", + "unownE": "E", + "unownF": "F", + "unownG": "G", + "unownH": "H", + "unownI": "I", + "unownJ": "J", + "unownK": "K", + "unownL": "L", + "unownM": "M", + "unownN": "N", + "unownO": "O", + "unownP": "P", + "unownQ": "Q", + "unownR": "R", + "unownS": "S", + "unownT": "T", + "unownU": "U", + "unownV": "V", + "unownW": "W", + "unownX": "X", + "unownY": "Y", + "unownZ": "Z", + "unownExclamation": "!", + "unownQuestion": "?", + // 3G + "castformSunny": "Sunny", + "castformRainy": "Rainy", + "castformSnowy": "Snowy", + "deoxysNormal": "Normal", + // 4G + "burmyPlant": "Plant", + "burmySandy": "Sandy", + "burmyTrash": "Trash", + "shellosEast": "East", + "shellosWest": "West", + "rotomHeat": "Heat", + "rotomWash": "Wash", + "rotomFrost": "Frost", + "rotomFan": "Fan", + "rotomMow": "Mow", + "giratinaAltered": "Altered", + "shayminLand": "Land", + // 5G + "basculinRedStriped": "Red Striped", + "basculinBlueStriped": "Blue Striped", + "basculinWhiteStriped": "White Striped", + "deerlingSpring": "Spring", + "deerlingSummer": "Summer", + "deerlingAutumn": "Autumn", + "deerlingWinter": "Winter", + "tornadusIncarnate": "Incarnate", + "thundurusIncarnate": "Incarnate", + "landorusIncarnate": "Incarnate", + "keldeoOrdinary": "Ordinary", + "meloettaAria": "Aria", + // 6G + "froakieBattleBond": "Battle Bond", + "scatterbugMeadow": "Meadow", + "scatterbugIcySnow": "Icy Snow", + "scatterbugPolar": "Polar", + "scatterbugTundra": "Tundra", + "scatterbugContinental": "Continental", + "scatterbugGarden": "Garden", + "scatterbugElegant": "Elegant", + "scatterbugModern": "Modern", + "scatterbugMarine": "Marine", + "scatterbugArchipelago": "Archipelago", + "scatterbugHighPlains": "High Plains", + "scatterbugSandstorm": "Sandstorm", + "scatterbugRiver": "River", + "scatterbugMonsoon": "Monsoon", + "scatterbugSavanna": "Savanna", + "scatterbugSun": "Sun", + "scatterbugOcean": "Ocean", + "scatterbugJungle": "Jungle", + "scatterbugFancy": "Fancy", + "scatterbugPokeBall": "Poké Ball", + "flabebeRed": "Red", + "flabebeYellow": "Yellow", + "flabebeOrange": "Orange", + "flabebeBlue": "Blue", + "flabebeWhite": "White", + "furfrouHeart": "Heart", + "furfrouStar": "Star", + "furfrouDiamond": "Diamond", + "furfrouDebutante": "Debutante", + "furfrouMatron": "Matron", + "furfrouDandy": "Dandy", + "furfrouLaReine": "La Reine", + "furfrouKabuki": "Kabuki", + "furfrouPharaoh": "Pharaoh", + "pumpkabooSmall": "Small", + "pumpkabooLarge": "Large", + "pumpkabooSuper": "Super", + "xerneasNeutral": "Neutral", + "xerneasActive": "Active", + "zygarde50": "50% Forme", + "zygarde10": "10% Forme", + "zygarde50Pc": "50% Forme Power Construct", + "zygarde10Pc": "10% Forme Power Construct", + "zygardeComplete": "Complete Forme", + // 7G + "oricorioBaile": "Baile", + "oricorioPompom": "Pom-Pom", + "oricorioPau": "Pau", + "oricorioSensu": "Sensu", + "rockruffOwnTempo": "Own Tempo", + "miniorRedMeteor": "Red Meteor", + "miniorOrangeMeteor": "Orange Meteor", + "miniorYellowMeteor": "Yellow Meteor", + "miniorGreenMeteor": "Green Meteor", + "miniorBlueMeteor": "Blue Meteor", + "miniorIndigoMeteor": "Indigo Meteor", + "miniorVioletMeteor": "Violet Meteor", + "miniorRed": "Red", + "miniorOrange": "Orange", + "miniorYellow": "Yellow", + "miniorGreen": "Green", + "miniorBlue": "Blue", + "miniorIndigo": "Indigo", + "miniorViolet": "Violet", + "mimikyuDisguised": "Disguised", + "mimikyuBusted": "Busted", + "magearnaOriginal": "Original", + "marshadowZenith": "Zenith", + // 8G + "sinisteaPhony": "Phony", + "sinisteaAntique": "Antique", + "eiscueNoIce": "No Ice", + "indeedeeMale": "Male", + "indeedeeFemale": "Female", + "morpekoFullBelly": "Full Belly", + "zacianHeroOfManyBattles": "Hero Of Many Battles", + "zamazentaHeroOfManyBattles": "Hero Of Many Battles", + "zarudeDada": "Dada", + "enamorusIncarnate": "Incarnate", + // 9G + "squawkabillyGreenPlumage": "Green Plumage", + "squawkabillyBluePlumage": "Blue Plumage", + "squawkabillyYellowPlumage": "Yellow Plumage", + "squawkabillyWhitePlumage": "White Plumage", + "tatsugiriCurly": "Curly", + "tatsugiriDroopy": "Droopy", + "tatsugiriStretchy": "Stretchy", + "gimmighoulChest": "Chest", + "gimmighoulRoaming": "Roaming", + "koraidonApexBuild": "Apex Build", + "koraidonLimitedBuild":"Limited Build", + "koraidonSprintingBuild":"Sprinting Build", + "koraidonSwimmingBuild":"Swimming Build", + "koraidonGlidingBuild":"Gliding Build", + "miraidonUltimateMode":"Ultimate Mode", + "miraidonLowPowerMode":"Low Power Mode", + "miraidonDriveMode":"Drive Mode", + "miraidonAquaticMode":"Aquatic Mode", + "miraidonGlideMode":"Glide Mode", + "poltchageistCounterfeit": "Counterfeit", + "poltchageistArtisan": "Artisan", + "paldeaTaurosCombat": "Combat", + "paldeaTaurosBlaze": "Blaze", + "paldeaTaurosAqua": "Aqua", + +} as const; diff --git a/src/locales/ca-ES/pokemon-info-container.ts b/src/locales/ca-ES/pokemon-info-container.ts new file mode 100644 index 00000000000..fd8acfb2e3e --- /dev/null +++ b/src/locales/ca-ES/pokemon-info-container.ts @@ -0,0 +1,9 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +export const pokemonInfoContainer: SimpleTranslationEntries = { + "moveset": "Moveset", + "gender": "Gender:", + "ability": "Ability:", + "nature": "Nature:", + "form": "Form:" +} as const; diff --git a/src/locales/ca-ES/pokemon-info.ts b/src/locales/ca-ES/pokemon-info.ts new file mode 100644 index 00000000000..f31fdac69ab --- /dev/null +++ b/src/locales/ca-ES/pokemon-info.ts @@ -0,0 +1,43 @@ +import { PokemonInfoTranslationEntries } from "#app/interfaces/locales"; + +export const pokemonInfo: PokemonInfoTranslationEntries = { + Stat: { + "HP": "Max. HP", + "HPshortened": "MaxHP", + "ATK": "Attack", + "ATKshortened": "Atk", + "DEF": "Defense", + "DEFshortened": "Def", + "SPATK": "Sp. Atk", + "SPATKshortened": "SpAtk", + "SPDEF": "Sp. Def", + "SPDEFshortened": "SpDef", + "SPD": "Speed", + "SPDshortened": "Spd", + "ACC": "Accuracy", + "EVA": "Evasiveness" + }, + + Type: { + "UNKNOWN": "Unknown", + "NORMAL": "Normal", + "FIGHTING": "Fighting", + "FLYING": "Flying", + "POISON": "Poison", + "GROUND": "Ground", + "ROCK": "Rock", + "BUG": "Bug", + "GHOST": "Ghost", + "STEEL": "Steel", + "FIRE": "Fire", + "WATER": "Water", + "GRASS": "Grass", + "ELECTRIC": "Electric", + "PSYCHIC": "Psychic", + "ICE": "Ice", + "DRAGON": "Dragon", + "DARK": "Dark", + "FAIRY": "Fairy", + "STELLAR": "Stellar", + }, +} as const; diff --git a/src/locales/ca-ES/pokemon-summary.ts b/src/locales/ca-ES/pokemon-summary.ts new file mode 100644 index 00000000000..484ea2a9d67 --- /dev/null +++ b/src/locales/ca-ES/pokemon-summary.ts @@ -0,0 +1,20 @@ +import { TranslationEntries } from "#app/interfaces/locales"; + +export const pokemonSummary: TranslationEntries = { + "pokemonInfo": "Pokémon Info", + "status": "Status", + "powerAccuracyCategory": "Power\nAccuracy\nCategory", + "type": "Type", + "unknownTrainer": "Unknown", + "ot": "OT", + "nature": "nature", + "expPoints": "Exp. Points", + "nextLv": "Next Lv.", + "cancel": "Cancel", + + "memoString": "{{natureFragment}} nature,\n{{metFragment}}", + "metFragment": { + "normal": "met at Lv{{level}},\n{{biome}}.", + "apparently": "apparently met at Lv{{level}},\n{{biome}}.", + }, +} as const; diff --git a/src/locales/ca-ES/pokemon.ts b/src/locales/ca-ES/pokemon.ts new file mode 100644 index 00000000000..297bbcc3975 --- /dev/null +++ b/src/locales/ca-ES/pokemon.ts @@ -0,0 +1,1086 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +export const pokemon: SimpleTranslationEntries = { + "bulbasaur": "Bulbasaur", + "ivysaur": "Ivysaur", + "venusaur": "Venusaur", + "charmander": "Charmander", + "charmeleon": "Charmeleon", + "charizard": "Charizard", + "squirtle": "Squirtle", + "wartortle": "Wartortle", + "blastoise": "Blastoise", + "caterpie": "Caterpie", + "metapod": "Metapod", + "butterfree": "Butterfree", + "weedle": "Weedle", + "kakuna": "Kakuna", + "beedrill": "Beedrill", + "pidgey": "Pidgey", + "pidgeotto": "Pidgeotto", + "pidgeot": "Pidgeot", + "rattata": "Rattata", + "raticate": "Raticate", + "spearow": "Spearow", + "fearow": "Fearow", + "ekans": "Ekans", + "arbok": "Arbok", + "pikachu": "Pikachu", + "raichu": "Raichu", + "sandshrew": "Sandshrew", + "sandslash": "Sandslash", + "nidoran_f": "Nidoran♀", + "nidorina": "Nidorina", + "nidoqueen": "Nidoqueen", + "nidoran_m": "Nidoran♂", + "nidorino": "Nidorino", + "nidoking": "Nidoking", + "clefairy": "Clefairy", + "clefable": "Clefable", + "vulpix": "Vulpix", + "ninetales": "Ninetales", + "jigglypuff": "Jigglypuff", + "wigglytuff": "Wigglytuff", + "zubat": "Zubat", + "golbat": "Golbat", + "oddish": "Oddish", + "gloom": "Gloom", + "vileplume": "Vileplume", + "paras": "Paras", + "parasect": "Parasect", + "venonat": "Venonat", + "venomoth": "Venomoth", + "diglett": "Diglett", + "dugtrio": "Dugtrio", + "meowth": "Meowth", + "persian": "Persian", + "psyduck": "Psyduck", + "golduck": "Golduck", + "mankey": "Mankey", + "primeape": "Primeape", + "growlithe": "Growlithe", + "arcanine": "Arcanine", + "poliwag": "Poliwag", + "poliwhirl": "Poliwhirl", + "poliwrath": "Poliwrath", + "abra": "Abra", + "kadabra": "Kadabra", + "alakazam": "Alakazam", + "machop": "Machop", + "machoke": "Machoke", + "machamp": "Machamp", + "bellsprout": "Bellsprout", + "weepinbell": "Weepinbell", + "victreebel": "Victreebel", + "tentacool": "Tentacool", + "tentacruel": "Tentacruel", + "geodude": "Geodude", + "graveler": "Graveler", + "golem": "Golem", + "ponyta": "Ponyta", + "rapidash": "Rapidash", + "slowpoke": "Slowpoke", + "slowbro": "Slowbro", + "magnemite": "Magnemite", + "magneton": "Magneton", + "farfetchd": "Farfetch'd", + "doduo": "Doduo", + "dodrio": "Dodrio", + "seel": "Seel", + "dewgong": "Dewgong", + "grimer": "Grimer", + "muk": "Muk", + "shellder": "Shellder", + "cloyster": "Cloyster", + "gastly": "Gastly", + "haunter": "Haunter", + "gengar": "Gengar", + "onix": "Onix", + "drowzee": "Drowzee", + "hypno": "Hypno", + "krabby": "Krabby", + "kingler": "Kingler", + "voltorb": "Voltorb", + "electrode": "Electrode", + "exeggcute": "Exeggcute", + "exeggutor": "Exeggutor", + "cubone": "Cubone", + "marowak": "Marowak", + "hitmonlee": "Hitmonlee", + "hitmonchan": "Hitmonchan", + "lickitung": "Lickitung", + "koffing": "Koffing", + "weezing": "Weezing", + "rhyhorn": "Rhyhorn", + "rhydon": "Rhydon", + "chansey": "Chansey", + "tangela": "Tangela", + "kangaskhan": "Kangaskhan", + "horsea": "Horsea", + "seadra": "Seadra", + "goldeen": "Goldeen", + "seaking": "Seaking", + "staryu": "Staryu", + "starmie": "Starmie", + "mr_mime": "Mr. Mime", + "scyther": "Scyther", + "jynx": "Jynx", + "electabuzz": "Electabuzz", + "magmar": "Magmar", + "pinsir": "Pinsir", + "tauros": "Tauros", + "magikarp": "Magikarp", + "gyarados": "Gyarados", + "lapras": "Lapras", + "ditto": "Ditto", + "eevee": "Eevee", + "vaporeon": "Vaporeon", + "jolteon": "Jolteon", + "flareon": "Flareon", + "porygon": "Porygon", + "omanyte": "Omanyte", + "omastar": "Omastar", + "kabuto": "Kabuto", + "kabutops": "Kabutops", + "aerodactyl": "Aerodactyl", + "snorlax": "Snorlax", + "articuno": "Articuno", + "zapdos": "Zapdos", + "moltres": "Moltres", + "dratini": "Dratini", + "dragonair": "Dragonair", + "dragonite": "Dragonite", + "mewtwo": "Mewtwo", + "mew": "Mew", + "chikorita": "Chikorita", + "bayleef": "Bayleef", + "meganium": "Meganium", + "cyndaquil": "Cyndaquil", + "quilava": "Quilava", + "typhlosion": "Typhlosion", + "totodile": "Totodile", + "croconaw": "Croconaw", + "feraligatr": "Feraligatr", + "sentret": "Sentret", + "furret": "Furret", + "hoothoot": "Hoothoot", + "noctowl": "Noctowl", + "ledyba": "Ledyba", + "ledian": "Ledian", + "spinarak": "Spinarak", + "ariados": "Ariados", + "crobat": "Crobat", + "chinchou": "Chinchou", + "lanturn": "Lanturn", + "pichu": "Pichu", + "cleffa": "Cleffa", + "igglybuff": "Igglybuff", + "togepi": "Togepi", + "togetic": "Togetic", + "natu": "Natu", + "xatu": "Xatu", + "mareep": "Mareep", + "flaaffy": "Flaaffy", + "ampharos": "Ampharos", + "bellossom": "Bellossom", + "marill": "Marill", + "azumarill": "Azumarill", + "sudowoodo": "Sudowoodo", + "politoed": "Politoed", + "hoppip": "Hoppip", + "skiploom": "Skiploom", + "jumpluff": "Jumpluff", + "aipom": "Aipom", + "sunkern": "Sunkern", + "sunflora": "Sunflora", + "yanma": "Yanma", + "wooper": "Wooper", + "quagsire": "Quagsire", + "espeon": "Espeon", + "umbreon": "Umbreon", + "murkrow": "Murkrow", + "slowking": "Slowking", + "misdreavus": "Misdreavus", + "unown": "Unown", + "wobbuffet": "Wobbuffet", + "girafarig": "Girafarig", + "pineco": "Pineco", + "forretress": "Forretress", + "dunsparce": "Dunsparce", + "gligar": "Gligar", + "steelix": "Steelix", + "snubbull": "Snubbull", + "granbull": "Granbull", + "qwilfish": "Qwilfish", + "scizor": "Scizor", + "shuckle": "Shuckle", + "heracross": "Heracross", + "sneasel": "Sneasel", + "teddiursa": "Teddiursa", + "ursaring": "Ursaring", + "slugma": "Slugma", + "magcargo": "Magcargo", + "swinub": "Swinub", + "piloswine": "Piloswine", + "corsola": "Corsola", + "remoraid": "Remoraid", + "octillery": "Octillery", + "delibird": "Delibird", + "mantine": "Mantine", + "skarmory": "Skarmory", + "houndour": "Houndour", + "houndoom": "Houndoom", + "kingdra": "Kingdra", + "phanpy": "Phanpy", + "donphan": "Donphan", + "porygon2": "Porygon2", + "stantler": "Stantler", + "smeargle": "Smeargle", + "tyrogue": "Tyrogue", + "hitmontop": "Hitmontop", + "smoochum": "Smoochum", + "elekid": "Elekid", + "magby": "Magby", + "miltank": "Miltank", + "blissey": "Blissey", + "raikou": "Raikou", + "entei": "Entei", + "suicune": "Suicune", + "larvitar": "Larvitar", + "pupitar": "Pupitar", + "tyranitar": "Tyranitar", + "lugia": "Lugia", + "ho_oh": "Ho-Oh", + "celebi": "Celebi", + "treecko": "Treecko", + "grovyle": "Grovyle", + "sceptile": "Sceptile", + "torchic": "Torchic", + "combusken": "Combusken", + "blaziken": "Blaziken", + "mudkip": "Mudkip", + "marshtomp": "Marshtomp", + "swampert": "Swampert", + "poochyena": "Poochyena", + "mightyena": "Mightyena", + "zigzagoon": "Zigzagoon", + "linoone": "Linoone", + "wurmple": "Wurmple", + "silcoon": "Silcoon", + "beautifly": "Beautifly", + "cascoon": "Cascoon", + "dustox": "Dustox", + "lotad": "Lotad", + "lombre": "Lombre", + "ludicolo": "Ludicolo", + "seedot": "Seedot", + "nuzleaf": "Nuzleaf", + "shiftry": "Shiftry", + "taillow": "Taillow", + "swellow": "Swellow", + "wingull": "Wingull", + "pelipper": "Pelipper", + "ralts": "Ralts", + "kirlia": "Kirlia", + "gardevoir": "Gardevoir", + "surskit": "Surskit", + "masquerain": "Masquerain", + "shroomish": "Shroomish", + "breloom": "Breloom", + "slakoth": "Slakoth", + "vigoroth": "Vigoroth", + "slaking": "Slaking", + "nincada": "Nincada", + "ninjask": "Ninjask", + "shedinja": "Shedinja", + "whismur": "Whismur", + "loudred": "Loudred", + "exploud": "Exploud", + "makuhita": "Makuhita", + "hariyama": "Hariyama", + "azurill": "Azurill", + "nosepass": "Nosepass", + "skitty": "Skitty", + "delcatty": "Delcatty", + "sableye": "Sableye", + "mawile": "Mawile", + "aron": "Aron", + "lairon": "Lairon", + "aggron": "Aggron", + "meditite": "Meditite", + "medicham": "Medicham", + "electrike": "Electrike", + "manectric": "Manectric", + "plusle": "Plusle", + "minun": "Minun", + "volbeat": "Volbeat", + "illumise": "Illumise", + "roselia": "Roselia", + "gulpin": "Gulpin", + "swalot": "Swalot", + "carvanha": "Carvanha", + "sharpedo": "Sharpedo", + "wailmer": "Wailmer", + "wailord": "Wailord", + "numel": "Numel", + "camerupt": "Camerupt", + "torkoal": "Torkoal", + "spoink": "Spoink", + "grumpig": "Grumpig", + "spinda": "Spinda", + "trapinch": "Trapinch", + "vibrava": "Vibrava", + "flygon": "Flygon", + "cacnea": "Cacnea", + "cacturne": "Cacturne", + "swablu": "Swablu", + "altaria": "Altaria", + "zangoose": "Zangoose", + "seviper": "Seviper", + "lunatone": "Lunatone", + "solrock": "Solrock", + "barboach": "Barboach", + "whiscash": "Whiscash", + "corphish": "Corphish", + "crawdaunt": "Crawdaunt", + "baltoy": "Baltoy", + "claydol": "Claydol", + "lileep": "Lileep", + "cradily": "Cradily", + "anorith": "Anorith", + "armaldo": "Armaldo", + "feebas": "Feebas", + "milotic": "Milotic", + "castform": "Castform", + "kecleon": "Kecleon", + "shuppet": "Shuppet", + "banette": "Banette", + "duskull": "Duskull", + "dusclops": "Dusclops", + "tropius": "Tropius", + "chimecho": "Chimecho", + "absol": "Absol", + "wynaut": "Wynaut", + "snorunt": "Snorunt", + "glalie": "Glalie", + "spheal": "Spheal", + "sealeo": "Sealeo", + "walrein": "Walrein", + "clamperl": "Clamperl", + "huntail": "Huntail", + "gorebyss": "Gorebyss", + "relicanth": "Relicanth", + "luvdisc": "Luvdisc", + "bagon": "Bagon", + "shelgon": "Shelgon", + "salamence": "Salamence", + "beldum": "Beldum", + "metang": "Metang", + "metagross": "Metagross", + "regirock": "Regirock", + "regice": "Regice", + "registeel": "Registeel", + "latias": "Latias", + "latios": "Latios", + "kyogre": "Kyogre", + "groudon": "Groudon", + "rayquaza": "Rayquaza", + "jirachi": "Jirachi", + "deoxys": "Deoxys", + "turtwig": "Turtwig", + "grotle": "Grotle", + "torterra": "Torterra", + "chimchar": "Chimchar", + "monferno": "Monferno", + "infernape": "Infernape", + "piplup": "Piplup", + "prinplup": "Prinplup", + "empoleon": "Empoleon", + "starly": "Starly", + "staravia": "Staravia", + "staraptor": "Staraptor", + "bidoof": "Bidoof", + "bibarel": "Bibarel", + "kricketot": "Kricketot", + "kricketune": "Kricketune", + "shinx": "Shinx", + "luxio": "Luxio", + "luxray": "Luxray", + "budew": "Budew", + "roserade": "Roserade", + "cranidos": "Cranidos", + "rampardos": "Rampardos", + "shieldon": "Shieldon", + "bastiodon": "Bastiodon", + "burmy": "Burmy", + "wormadam": "Wormadam", + "mothim": "Mothim", + "combee": "Combee", + "vespiquen": "Vespiquen", + "pachirisu": "Pachirisu", + "buizel": "Buizel", + "floatzel": "Floatzel", + "cherubi": "Cherubi", + "cherrim": "Cherrim", + "shellos": "Shellos", + "gastrodon": "Gastrodon", + "ambipom": "Ambipom", + "drifloon": "Drifloon", + "drifblim": "Drifblim", + "buneary": "Buneary", + "lopunny": "Lopunny", + "mismagius": "Mismagius", + "honchkrow": "Honchkrow", + "glameow": "Glameow", + "purugly": "Purugly", + "chingling": "Chingling", + "stunky": "Stunky", + "skuntank": "Skuntank", + "bronzor": "Bronzor", + "bronzong": "Bronzong", + "bonsly": "Bonsly", + "mime_jr": "Mime Jr.", + "happiny": "Happiny", + "chatot": "Chatot", + "spiritomb": "Spiritomb", + "gible": "Gible", + "gabite": "Gabite", + "garchomp": "Garchomp", + "munchlax": "Munchlax", + "riolu": "Riolu", + "lucario": "Lucario", + "hippopotas": "Hippopotas", + "hippowdon": "Hippowdon", + "skorupi": "Skorupi", + "drapion": "Drapion", + "croagunk": "Croagunk", + "toxicroak": "Toxicroak", + "carnivine": "Carnivine", + "finneon": "Finneon", + "lumineon": "Lumineon", + "mantyke": "Mantyke", + "snover": "Snover", + "abomasnow": "Abomasnow", + "weavile": "Weavile", + "magnezone": "Magnezone", + "lickilicky": "Lickilicky", + "rhyperior": "Rhyperior", + "tangrowth": "Tangrowth", + "electivire": "Electivire", + "magmortar": "Magmortar", + "togekiss": "Togekiss", + "yanmega": "Yanmega", + "leafeon": "Leafeon", + "glaceon": "Glaceon", + "gliscor": "Gliscor", + "mamoswine": "Mamoswine", + "porygon_z": "Porygon-Z", + "gallade": "Gallade", + "probopass": "Probopass", + "dusknoir": "Dusknoir", + "froslass": "Froslass", + "rotom": "Rotom", + "uxie": "Uxie", + "mesprit": "Mesprit", + "azelf": "Azelf", + "dialga": "Dialga", + "palkia": "Palkia", + "heatran": "Heatran", + "regigigas": "Regigigas", + "giratina": "Giratina", + "cresselia": "Cresselia", + "phione": "Phione", + "manaphy": "Manaphy", + "darkrai": "Darkrai", + "shaymin": "Shaymin", + "arceus": "Arceus", + "victini": "Victini", + "snivy": "Snivy", + "servine": "Servine", + "serperior": "Serperior", + "tepig": "Tepig", + "pignite": "Pignite", + "emboar": "Emboar", + "oshawott": "Oshawott", + "dewott": "Dewott", + "samurott": "Samurott", + "patrat": "Patrat", + "watchog": "Watchog", + "lillipup": "Lillipup", + "herdier": "Herdier", + "stoutland": "Stoutland", + "purrloin": "Purrloin", + "liepard": "Liepard", + "pansage": "Pansage", + "simisage": "Simisage", + "pansear": "Pansear", + "simisear": "Simisear", + "panpour": "Panpour", + "simipour": "Simipour", + "munna": "Munna", + "musharna": "Musharna", + "pidove": "Pidove", + "tranquill": "Tranquill", + "unfezant": "Unfezant", + "blitzle": "Blitzle", + "zebstrika": "Zebstrika", + "roggenrola": "Roggenrola", + "boldore": "Boldore", + "gigalith": "Gigalith", + "woobat": "Woobat", + "swoobat": "Swoobat", + "drilbur": "Drilbur", + "excadrill": "Excadrill", + "audino": "Audino", + "timburr": "Timburr", + "gurdurr": "Gurdurr", + "conkeldurr": "Conkeldurr", + "tympole": "Tympole", + "palpitoad": "Palpitoad", + "seismitoad": "Seismitoad", + "throh": "Throh", + "sawk": "Sawk", + "sewaddle": "Sewaddle", + "swadloon": "Swadloon", + "leavanny": "Leavanny", + "venipede": "Venipede", + "whirlipede": "Whirlipede", + "scolipede": "Scolipede", + "cottonee": "Cottonee", + "whimsicott": "Whimsicott", + "petilil": "Petilil", + "lilligant": "Lilligant", + "basculin": "Basculin", + "sandile": "Sandile", + "krokorok": "Krokorok", + "krookodile": "Krookodile", + "darumaka": "Darumaka", + "darmanitan": "Darmanitan", + "maractus": "Maractus", + "dwebble": "Dwebble", + "crustle": "Crustle", + "scraggy": "Scraggy", + "scrafty": "Scrafty", + "sigilyph": "Sigilyph", + "yamask": "Yamask", + "cofagrigus": "Cofagrigus", + "tirtouga": "Tirtouga", + "carracosta": "Carracosta", + "archen": "Archen", + "archeops": "Archeops", + "trubbish": "Trubbish", + "garbodor": "Garbodor", + "zorua": "Zorua", + "zoroark": "Zoroark", + "minccino": "Minccino", + "cinccino": "Cinccino", + "gothita": "Gothita", + "gothorita": "Gothorita", + "gothitelle": "Gothitelle", + "solosis": "Solosis", + "duosion": "Duosion", + "reuniclus": "Reuniclus", + "ducklett": "Ducklett", + "swanna": "Swanna", + "vanillite": "Vanillite", + "vanillish": "Vanillish", + "vanilluxe": "Vanilluxe", + "deerling": "Deerling", + "sawsbuck": "Sawsbuck", + "emolga": "Emolga", + "karrablast": "Karrablast", + "escavalier": "Escavalier", + "foongus": "Foongus", + "amoonguss": "Amoonguss", + "frillish": "Frillish", + "jellicent": "Jellicent", + "alomomola": "Alomomola", + "joltik": "Joltik", + "galvantula": "Galvantula", + "ferroseed": "Ferroseed", + "ferrothorn": "Ferrothorn", + "klink": "Klink", + "klang": "Klang", + "klinklang": "Klinklang", + "tynamo": "Tynamo", + "eelektrik": "Eelektrik", + "eelektross": "Eelektross", + "elgyem": "Elgyem", + "beheeyem": "Beheeyem", + "litwick": "Litwick", + "lampent": "Lampent", + "chandelure": "Chandelure", + "axew": "Axew", + "fraxure": "Fraxure", + "haxorus": "Haxorus", + "cubchoo": "Cubchoo", + "beartic": "Beartic", + "cryogonal": "Cryogonal", + "shelmet": "Shelmet", + "accelgor": "Accelgor", + "stunfisk": "Stunfisk", + "mienfoo": "Mienfoo", + "mienshao": "Mienshao", + "druddigon": "Druddigon", + "golett": "Golett", + "golurk": "Golurk", + "pawniard": "Pawniard", + "bisharp": "Bisharp", + "bouffalant": "Bouffalant", + "rufflet": "Rufflet", + "braviary": "Braviary", + "vullaby": "Vullaby", + "mandibuzz": "Mandibuzz", + "heatmor": "Heatmor", + "durant": "Durant", + "deino": "Deino", + "zweilous": "Zweilous", + "hydreigon": "Hydreigon", + "larvesta": "Larvesta", + "volcarona": "Volcarona", + "cobalion": "Cobalion", + "terrakion": "Terrakion", + "virizion": "Virizion", + "tornadus": "Tornadus", + "thundurus": "Thundurus", + "reshiram": "Reshiram", + "zekrom": "Zekrom", + "landorus": "Landorus", + "kyurem": "Kyurem", + "keldeo": "Keldeo", + "meloetta": "Meloetta", + "genesect": "Genesect", + "chespin": "Chespin", + "quilladin": "Quilladin", + "chesnaught": "Chesnaught", + "fennekin": "Fennekin", + "braixen": "Braixen", + "delphox": "Delphox", + "froakie": "Froakie", + "frogadier": "Frogadier", + "greninja": "Greninja", + "bunnelby": "Bunnelby", + "diggersby": "Diggersby", + "fletchling": "Fletchling", + "fletchinder": "Fletchinder", + "talonflame": "Talonflame", + "scatterbug": "Scatterbug", + "spewpa": "Spewpa", + "vivillon": "Vivillon", + "litleo": "Litleo", + "pyroar": "Pyroar", + "flabebe": "Flabébé", + "floette": "Floette", + "florges": "Florges", + "skiddo": "Skiddo", + "gogoat": "Gogoat", + "pancham": "Pancham", + "pangoro": "Pangoro", + "furfrou": "Furfrou", + "espurr": "Espurr", + "meowstic": "Meowstic", + "honedge": "Honedge", + "doublade": "Doublade", + "aegislash": "Aegislash", + "spritzee": "Spritzee", + "aromatisse": "Aromatisse", + "swirlix": "Swirlix", + "slurpuff": "Slurpuff", + "inkay": "Inkay", + "malamar": "Malamar", + "binacle": "Binacle", + "barbaracle": "Barbaracle", + "skrelp": "Skrelp", + "dragalge": "Dragalge", + "clauncher": "Clauncher", + "clawitzer": "Clawitzer", + "helioptile": "Helioptile", + "heliolisk": "Heliolisk", + "tyrunt": "Tyrunt", + "tyrantrum": "Tyrantrum", + "amaura": "Amaura", + "aurorus": "Aurorus", + "sylveon": "Sylveon", + "hawlucha": "Hawlucha", + "dedenne": "Dedenne", + "carbink": "Carbink", + "goomy": "Goomy", + "sliggoo": "Sliggoo", + "goodra": "Goodra", + "klefki": "Klefki", + "phantump": "Phantump", + "trevenant": "Trevenant", + "pumpkaboo": "Pumpkaboo", + "gourgeist": "Gourgeist", + "bergmite": "Bergmite", + "avalugg": "Avalugg", + "noibat": "Noibat", + "noivern": "Noivern", + "xerneas": "Xerneas", + "yveltal": "Yveltal", + "zygarde": "Zygarde", + "diancie": "Diancie", + "hoopa": "Hoopa", + "volcanion": "Volcanion", + "rowlet": "Rowlet", + "dartrix": "Dartrix", + "decidueye": "Decidueye", + "litten": "Litten", + "torracat": "Torracat", + "incineroar": "Incineroar", + "popplio": "Popplio", + "brionne": "Brionne", + "primarina": "Primarina", + "pikipek": "Pikipek", + "trumbeak": "Trumbeak", + "toucannon": "Toucannon", + "yungoos": "Yungoos", + "gumshoos": "Gumshoos", + "grubbin": "Grubbin", + "charjabug": "Charjabug", + "vikavolt": "Vikavolt", + "crabrawler": "Crabrawler", + "crabominable": "Crabominable", + "oricorio": "Oricorio", + "cutiefly": "Cutiefly", + "ribombee": "Ribombee", + "rockruff": "Rockruff", + "lycanroc": "Lycanroc", + "wishiwashi": "Wishiwashi", + "mareanie": "Mareanie", + "toxapex": "Toxapex", + "mudbray": "Mudbray", + "mudsdale": "Mudsdale", + "dewpider": "Dewpider", + "araquanid": "Araquanid", + "fomantis": "Fomantis", + "lurantis": "Lurantis", + "morelull": "Morelull", + "shiinotic": "Shiinotic", + "salandit": "Salandit", + "salazzle": "Salazzle", + "stufful": "Stufful", + "bewear": "Bewear", + "bounsweet": "Bounsweet", + "steenee": "Steenee", + "tsareena": "Tsareena", + "comfey": "Comfey", + "oranguru": "Oranguru", + "passimian": "Passimian", + "wimpod": "Wimpod", + "golisopod": "Golisopod", + "sandygast": "Sandygast", + "palossand": "Palossand", + "pyukumuku": "Pyukumuku", + "type_null": "Type: Null", + "silvally": "Silvally", + "minior": "Minior", + "komala": "Komala", + "turtonator": "Turtonator", + "togedemaru": "Togedemaru", + "mimikyu": "Mimikyu", + "bruxish": "Bruxish", + "drampa": "Drampa", + "dhelmise": "Dhelmise", + "jangmo_o": "Jangmo-o", + "hakamo_o": "Hakamo-o", + "kommo_o": "Kommo-o", + "tapu_koko": "Tapu Koko", + "tapu_lele": "Tapu Lele", + "tapu_bulu": "Tapu Bulu", + "tapu_fini": "Tapu Fini", + "cosmog": "Cosmog", + "cosmoem": "Cosmoem", + "solgaleo": "Solgaleo", + "lunala": "Lunala", + "nihilego": "Nihilego", + "buzzwole": "Buzzwole", + "pheromosa": "Pheromosa", + "xurkitree": "Xurkitree", + "celesteela": "Celesteela", + "kartana": "Kartana", + "guzzlord": "Guzzlord", + "necrozma": "Necrozma", + "magearna": "Magearna", + "marshadow": "Marshadow", + "poipole": "Poipole", + "naganadel": "Naganadel", + "stakataka": "Stakataka", + "blacephalon": "Blacephalon", + "zeraora": "Zeraora", + "meltan": "Meltan", + "melmetal": "Melmetal", + "grookey": "Grookey", + "thwackey": "Thwackey", + "rillaboom": "Rillaboom", + "scorbunny": "Scorbunny", + "raboot": "Raboot", + "cinderace": "Cinderace", + "sobble": "Sobble", + "drizzile": "Drizzile", + "inteleon": "Inteleon", + "skwovet": "Skwovet", + "greedent": "Greedent", + "rookidee": "Rookidee", + "corvisquire": "Corvisquire", + "corviknight": "Corviknight", + "blipbug": "Blipbug", + "dottler": "Dottler", + "orbeetle": "Orbeetle", + "nickit": "Nickit", + "thievul": "Thievul", + "gossifleur": "Gossifleur", + "eldegoss": "Eldegoss", + "wooloo": "Wooloo", + "dubwool": "Dubwool", + "chewtle": "Chewtle", + "drednaw": "Drednaw", + "yamper": "Yamper", + "boltund": "Boltund", + "rolycoly": "Rolycoly", + "carkol": "Carkol", + "coalossal": "Coalossal", + "applin": "Applin", + "flapple": "Flapple", + "appletun": "Appletun", + "silicobra": "Silicobra", + "sandaconda": "Sandaconda", + "cramorant": "Cramorant", + "arrokuda": "Arrokuda", + "barraskewda": "Barraskewda", + "toxel": "Toxel", + "toxtricity": "Toxtricity", + "sizzlipede": "Sizzlipede", + "centiskorch": "Centiskorch", + "clobbopus": "Clobbopus", + "grapploct": "Grapploct", + "sinistea": "Sinistea", + "polteageist": "Polteageist", + "hatenna": "Hatenna", + "hattrem": "Hattrem", + "hatterene": "Hatterene", + "impidimp": "Impidimp", + "morgrem": "Morgrem", + "grimmsnarl": "Grimmsnarl", + "obstagoon": "Obstagoon", + "perrserker": "Perrserker", + "cursola": "Cursola", + "sirfetchd": "Sirfetch'd", + "mr_rime": "Mr. Rime", + "runerigus": "Runerigus", + "milcery": "Milcery", + "alcremie": "Alcremie", + "falinks": "Falinks", + "pincurchin": "Pincurchin", + "snom": "Snom", + "frosmoth": "Frosmoth", + "stonjourner": "Stonjourner", + "eiscue": "Eiscue", + "indeedee": "Indeedee", + "morpeko": "Morpeko", + "cufant": "Cufant", + "copperajah": "Copperajah", + "dracozolt": "Dracozolt", + "arctozolt": "Arctozolt", + "dracovish": "Dracovish", + "arctovish": "Arctovish", + "duraludon": "Duraludon", + "dreepy": "Dreepy", + "drakloak": "Drakloak", + "dragapult": "Dragapult", + "zacian": "Zacian", + "zamazenta": "Zamazenta", + "eternatus": "Eternatus", + "kubfu": "Kubfu", + "urshifu": "Urshifu", + "zarude": "Zarude", + "regieleki": "Regieleki", + "regidrago": "Regidrago", + "glastrier": "Glastrier", + "spectrier": "Spectrier", + "calyrex": "Calyrex", + "wyrdeer": "Wyrdeer", + "kleavor": "Kleavor", + "ursaluna": "Ursaluna", + "basculegion": "Basculegion", + "sneasler": "Sneasler", + "overqwil": "Overqwil", + "enamorus": "Enamorus", + "sprigatito": "Sprigatito", + "floragato": "Floragato", + "meowscarada": "Meowscarada", + "fuecoco": "Fuecoco", + "crocalor": "Crocalor", + "skeledirge": "Skeledirge", + "quaxly": "Quaxly", + "quaxwell": "Quaxwell", + "quaquaval": "Quaquaval", + "lechonk": "Lechonk", + "oinkologne": "Oinkologne", + "tarountula": "Tarountula", + "spidops": "Spidops", + "nymble": "Nymble", + "lokix": "Lokix", + "pawmi": "Pawmi", + "pawmo": "Pawmo", + "pawmot": "Pawmot", + "tandemaus": "Tandemaus", + "maushold": "Maushold", + "fidough": "Fidough", + "dachsbun": "Dachsbun", + "smoliv": "Smoliv", + "dolliv": "Dolliv", + "arboliva": "Arboliva", + "squawkabilly": "Squawkabilly", + "nacli": "Nacli", + "naclstack": "Naclstack", + "garganacl": "Garganacl", + "charcadet": "Charcadet", + "armarouge": "Armarouge", + "ceruledge": "Ceruledge", + "tadbulb": "Tadbulb", + "bellibolt": "Bellibolt", + "wattrel": "Wattrel", + "kilowattrel": "Kilowattrel", + "maschiff": "Maschiff", + "mabosstiff": "Mabosstiff", + "shroodle": "Shroodle", + "grafaiai": "Grafaiai", + "bramblin": "Bramblin", + "brambleghast": "Brambleghast", + "toedscool": "Toedscool", + "toedscruel": "Toedscruel", + "klawf": "Klawf", + "capsakid": "Capsakid", + "scovillain": "Scovillain", + "rellor": "Rellor", + "rabsca": "Rabsca", + "flittle": "Flittle", + "espathra": "Espathra", + "tinkatink": "Tinkatink", + "tinkatuff": "Tinkatuff", + "tinkaton": "Tinkaton", + "wiglett": "Wiglett", + "wugtrio": "Wugtrio", + "bombirdier": "Bombirdier", + "finizen": "Finizen", + "palafin": "Palafin", + "varoom": "Varoom", + "revavroom": "Revavroom", + "cyclizar": "Cyclizar", + "orthworm": "Orthworm", + "glimmet": "Glimmet", + "glimmora": "Glimmora", + "greavard": "Greavard", + "houndstone": "Houndstone", + "flamigo": "Flamigo", + "cetoddle": "Cetoddle", + "cetitan": "Cetitan", + "veluza": "Veluza", + "dondozo": "Dondozo", + "tatsugiri": "Tatsugiri", + "annihilape": "Annihilape", + "clodsire": "Clodsire", + "farigiraf": "Farigiraf", + "dudunsparce": "Dudunsparce", + "kingambit": "Kingambit", + "great_tusk": "Great Tusk", + "scream_tail": "Scream Tail", + "brute_bonnet": "Brute Bonnet", + "flutter_mane": "Flutter Mane", + "slither_wing": "Slither Wing", + "sandy_shocks": "Sandy Shocks", + "iron_treads": "Iron Treads", + "iron_bundle": "Iron Bundle", + "iron_hands": "Iron Hands", + "iron_jugulis": "Iron Jugulis", + "iron_moth": "Iron Moth", + "iron_thorns": "Iron Thorns", + "frigibax": "Frigibax", + "arctibax": "Arctibax", + "baxcalibur": "Baxcalibur", + "gimmighoul": "Gimmighoul", + "gholdengo": "Gholdengo", + "wo_chien": "Wo-Chien", + "chien_pao": "Chien-Pao", + "ting_lu": "Ting-Lu", + "chi_yu": "Chi-Yu", + "roaring_moon": "Roaring Moon", + "iron_valiant": "Iron Valiant", + "koraidon": "Koraidon", + "miraidon": "Miraidon", + "walking_wake": "Walking Wake", + "iron_leaves": "Iron Leaves", + "dipplin": "Dipplin", + "poltchageist": "Poltchageist", + "sinistcha": "Sinistcha", + "okidogi": "Okidogi", + "munkidori": "Munkidori", + "fezandipiti": "Fezandipiti", + "ogerpon": "Ogerpon", + "archaludon": "Archaludon", + "hydrapple": "Hydrapple", + "gouging_fire": "Gouging Fire", + "raging_bolt": "Raging Bolt", + "iron_boulder": "Iron Boulder", + "iron_crown": "Iron Crown", + "terapagos": "Terapagos", + "pecharunt": "Pecharunt", + "alola_rattata": "Rattata", + "alola_raticate": "Raticate", + "alola_raichu": "Raichu", + "alola_sandshrew": "Sandshrew", + "alola_sandslash": "Sandslash", + "alola_vulpix": "Vulpix", + "alola_ninetales": "Ninetales", + "alola_diglett": "Diglett", + "alola_dugtrio": "Dugtrio", + "alola_meowth": "Meowth", + "alola_persian": "Persian", + "alola_geodude": "Geodude", + "alola_graveler": "Graveler", + "alola_golem": "Golem", + "alola_grimer": "Grimer", + "alola_muk": "Muk", + "alola_exeggutor": "Exeggutor", + "alola_marowak": "Marowak", + "eternal_floette": "Floette", + "galar_meowth": "Meowth", + "galar_ponyta": "Ponyta", + "galar_rapidash": "Rapidash", + "galar_slowpoke": "Slowpoke", + "galar_slowbro": "Slowbro", + "galar_farfetchd": "Farfetch'd", + "galar_weezing": "Weezing", + "galar_mr_mime": "Mr. Mime", + "galar_articuno": "Articuno", + "galar_zapdos": "Zapdos", + "galar_moltres": "Moltres", + "galar_slowking": "Slowking", + "galar_corsola": "Corsola", + "galar_zigzagoon": "Zigzagoon", + "galar_linoone": "Linoone", + "galar_darumaka": "Darumaka", + "galar_darmanitan": "Darmanitan", + "galar_yamask": "Yamask", + "galar_stunfisk": "Stunfisk", + "hisui_growlithe": "Growlithe", + "hisui_arcanine": "Arcanine", + "hisui_voltorb": "Voltorb", + "hisui_electrode": "Electrode", + "hisui_typhlosion": "Typhlosion", + "hisui_qwilfish": "Qwilfish", + "hisui_sneasel": "Sneasel", + "hisui_samurott": "Samurott", + "hisui_lilligant": "Lilligant", + "hisui_zorua": "Zorua", + "hisui_zoroark": "Zoroark", + "hisui_braviary": "Braviary", + "hisui_sliggoo": "Sliggoo", + "hisui_goodra": "Goodra", + "hisui_avalugg": "Avalugg", + "hisui_decidueye": "Decidueye", + "paldea_tauros": "Tauros", + "paldea_wooper": "Wooper", + "bloodmoon_ursaluna": "Ursaluna", +} as const; diff --git a/src/locales/ca-ES/save-slot-select-ui-handler.ts b/src/locales/ca-ES/save-slot-select-ui-handler.ts new file mode 100644 index 00000000000..f4efa3de734 --- /dev/null +++ b/src/locales/ca-ES/save-slot-select-ui-handler.ts @@ -0,0 +1,9 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +export const saveSlotSelectUiHandler: SimpleTranslationEntries = { + "overwriteData": "Overwrite the data in the selected slot?", + "loading": "Loading...", + "wave": "Wave", + "lv": "Lv", + "empty": "Empty", +} as const; diff --git a/src/locales/ca-ES/settings.ts b/src/locales/ca-ES/settings.ts new file mode 100644 index 00000000000..491bfa4a481 --- /dev/null +++ b/src/locales/ca-ES/settings.ts @@ -0,0 +1,100 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales.js"; + +export const settings: SimpleTranslationEntries = { + "boy": "Boy", + "girl": "Girl", + "general": "General", + "display": "Display", + "audio": "Audio", + "gamepad": "Gamepad", + "keyboard": "Keyboard", + "gameSpeed": "Game Speed", + "hpBarSpeed": "HP Bar Speed", + "expGainsSpeed": "EXP Gains Speed", + "expPartyDisplay": "Show EXP Party", + "skipSeenDialogues": "Skip Seen Dialogues", + "battleStyle": "Battle Style", + "enableRetries": "Enable Retries", + "tutorials": "Tutorials", + "touchControls": "Touch Controls", + "vibrations": "Vibrations", + "normal": "Normal", + "fast": "Fast", + "faster": "Faster", + "skip": "Skip", + "levelUpNotifications": "Level Up Notifications", + "on": "On", + "off": "Off", + "switch": "Switch", + "set": "Set", + "auto": "Auto", + "disabled": "Disabled", + "language": "Language", + "change": "Change", + "uiTheme": "UI Theme", + "default": "Default", + "legacy": "Legacy", + "windowType": "Window Type", + "moneyFormat": "Money Format", + "damageNumbers": "Damage Numbers", + "simple": "Simple", + "fancy": "Fancy", + "abbreviated": "Abbreviated", + "moveAnimations": "Move Animations", + "showStatsOnLevelUp": "Show Stats on Level Up", + "candyUpgradeNotification": "Candy Upgrade Notification", + "passivesOnly": "Passives Only", + "candyUpgradeDisplay": "Candy Upgrade Display", + "icon": "Icon", + "animation": "Animation", + "moveInfo": "Move Info", + "showMovesetFlyout": "Show Moveset Flyout", + "showArenaFlyout": "Show Arena Flyout", + "showTimeOfDayWidget": "Show Time of Day Widget", + "timeOfDayAnimation": "Time of Day Animation", + "bounce": "Bounce", + "timeOfDay_back": "Back", + "spriteSet": "Sprite Set", + "consistent": "Consistent", + "mixedAnimated": "Mixed Animated", + "fusionPaletteSwaps": "Fusion Palette Swaps", + "playerGender": "Player Gender", + "typeHints": "Type Hints", + "masterVolume": "Master Volume", + "bgmVolume": "BGM Volume", + "seVolume": "SE Volume", + "musicPreference": "Music Preference", + "mixed": "Mixed", + "gamepadPleasePlug": "Please Plug in a Gamepad or Press a Button", + "delete": "Delete", + "keyboardPleasePress": "Please Press a Key on Your Keyboard", + "reset": "Reset", + "requireReload": "Reload Required", + "action": "Action", + "back": "Back", + "pressToBind": "Press to Bind", + "pressButton": "Press a Button...", + "buttonUp": "Up", + "buttonDown": "Down", + "buttonLeft": "Left", + "buttonRight": "Right", + "buttonAction": "Action", + "buttonMenu": "Menu", + "buttonSubmit": "Submit", + "buttonCancel": "Cancel", + "buttonStats": "Stats", + "buttonCycleForm": "Cycle Form", + "buttonCycleShiny": "Cycle Shiny", + "buttonCycleGender": "Cycle Gender", + "buttonCycleAbility": "Cycle Ability", + "buttonCycleNature": "Cycle Nature", + "buttonCycleVariant": "Cycle Variant", + "buttonSpeedUp": "Speed Up", + "buttonSlowDown": "Slow Down", + "alt": " (Alt)", + "mute": "Mute", + "controller": "Controller", + "gamepadSupport": "Gamepad Support", + "showBgmBar": "Show Music Names", + "shopOverlayOpacity": "Shop Overlay Opacity" +} as const; diff --git a/src/locales/ca-ES/splash-messages.ts b/src/locales/ca-ES/splash-messages.ts new file mode 100644 index 00000000000..e549bc24f19 --- /dev/null +++ b/src/locales/ca-ES/splash-messages.ts @@ -0,0 +1,38 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +export const splashMessages: SimpleTranslationEntries = { + "battlesWon": "Battles Won!", + "joinTheDiscord": "Join the Discord!", + "infiniteLevels": "Infinite Levels!", + "everythingStacks": "Everything Stacks!", + "optionalSaveScumming": "Optional Save Scumming!", + "biomes": "35 Biomes!", + "openSource": "Open Source!", + "playWithSpeed": "Play with 5x Speed!", + "liveBugTesting": "Live Bug Testing!", + "heavyInfluence": "Heavy RoR2 Influence!", + "pokemonRiskAndPokemonRain": "Pokémon Risk and Pokémon Rain!", + "nowWithMoreSalt": "Now with 33% More Salt!", + "infiniteFusionAtHome": "Infinite Fusion at Home!", + "brokenEggMoves": "Broken Egg Moves!", + "magnificent": "Magnificent!", + "mubstitute": "Mubstitute!", + "thatsCrazy": "That's Crazy!", + "oranceJuice": "Orance Juice!", + "questionableBalancing": "Questionable Balancing!", + "coolShaders": "Cool Shaders!", + "aiFree": "AI-Free!", + "suddenDifficultySpikes": "Sudden Difficulty Spikes!", + "basedOnAnUnfinishedFlashGame": "Based on an Unfinished Flash Game!", + "moreAddictiveThanIntended": "More Addictive than Intended!", + "mostlyConsistentSeeds": "Mostly Consistent Seeds!", + "achievementPointsDontDoAnything": "Achievement Points Don't Do Anything!", + "youDoNotStartAtLevel": "You Do Not Start at Level 2000!", + "dontTalkAboutTheManaphyEggIncident": "Don't Talk About the Manaphy Egg Incident!", + "alsoTryPokengine": "Also Try Pokéngine!", + "alsoTryEmeraldRogue": "Also Try Emerald Rogue!", + "alsoTryRadicalRed": "Also Try Radical Red!", + "eeveeExpo": "Eevee Expo!", + "ynoproject": "YNOproject!", + "breedersInSpace": "Breeders in space!", +} as const; diff --git a/src/locales/ca-ES/starter-select-ui-handler.ts b/src/locales/ca-ES/starter-select-ui-handler.ts new file mode 100644 index 00000000000..deb4236c8ba --- /dev/null +++ b/src/locales/ca-ES/starter-select-ui-handler.ts @@ -0,0 +1,49 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +/** + * The menu namespace holds most miscellaneous text that isn't directly part of the game's + * contents or directly related to Pokemon data. This includes menu navigation, settings, + * account interactions, descriptive text, etc. + */ +export const starterSelectUiHandler: SimpleTranslationEntries = { + "confirmStartTeam": "Begin with these Pokémon?", + "confirmExit": "Do you want to exit?", + "invalidParty": "This is not a valid starting party!", + "gen1": "I", + "gen2": "II", + "gen3": "III", + "gen4": "IV", + "gen5": "V", + "gen6": "VI", + "gen7": "VII", + "gen8": "VIII", + "gen9": "IX", + "growthRate": "Growth Rate:", + "ability": "Ability:", + "passive": "Passive:", + "nature": "Nature:", + "eggMoves": "Egg Moves", + "addToParty": "Add to Party", + "removeFromParty": "Remove from Party", + "toggleIVs": "Toggle IVs", + "manageMoves": "Manage Moves", + "manageNature": "Manage Nature", + "useCandies": "Use Candies", + "selectNature": "Select nature.", + "selectMoveSwapOut": "Select a move to swap out.", + "selectMoveSwapWith": "Select a move to swap with", + "unlockPassive": "Unlock Passive", + "reduceCost": "Reduce Cost", + "sameSpeciesEgg": "Buy an Egg", + "cycleShiny": ": Shiny", + "cycleForm": ": Form", + "cycleGender": ": Gender", + "cycleAbility": ": Ability", + "cycleNature": ": Nature", + "cycleVariant": ": Variant", + "enablePassive": "Enable Passive", + "disablePassive": "Disable Passive", + "locked": "Locked", + "disabled": "Disabled", + "uncaught": "Uncaught" +}; diff --git a/src/locales/ca-ES/status-effect.ts b/src/locales/ca-ES/status-effect.ts new file mode 100644 index 00000000000..5914fc27298 --- /dev/null +++ b/src/locales/ca-ES/status-effect.ts @@ -0,0 +1,67 @@ +import { StatusEffectTranslationEntries } from "#app/interfaces/locales.js"; + +export const statusEffect: StatusEffectTranslationEntries = { + none: { + name: "None", + description: "", + obtain: "", + obtainSource: "", + activation: "", + overlap: "", + 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!" + }, + 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!" + }, + 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!" + }, + 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!" + }, + 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!" + }, + 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!" + }, +} as const; diff --git a/src/locales/ca-ES/trainers.ts b/src/locales/ca-ES/trainers.ts new file mode 100644 index 00000000000..00367865d14 --- /dev/null +++ b/src/locales/ca-ES/trainers.ts @@ -0,0 +1,302 @@ +import {SimpleTranslationEntries} from "#app/interfaces/locales"; + +// Titles of special trainers like gym leaders, elite four, and the champion +export const titles: SimpleTranslationEntries = { + "elite_four": "Elite Four", + "elite_four_female": "Elite Four", + "gym_leader": "Gym Leader", + "gym_leader_female": "Gym Leader", + "gym_leader_double": "Gym Leader Duo", + "champion": "Champion", + "champion_female": "Champion", + "champion_double": "Champion Duo", + "rival": "Rival", + "professor": "Professor", + "frontier_brain": "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", + // 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; + +// Titles of trainers like "Youngster" or "Lass" +export const trainerClasses: SimpleTranslationEntries = { + "ace_trainer": "Ace Trainer", + "ace_trainer_female": "Ace Trainer", + "ace_duo": "Ace Duo", + "artist": "Artist", + "artist_female": "Artist", + "backers": "Backers", + "backpacker": "Backpacker", + "backpacker_female": "Backpacker", + "backpackers": "Backpackers", + "baker": "Baker", + "battle_girl": "Battle Girl", + "beauty": "Beauty", + "beginners": "Beginners", + "biker": "Biker", + "black_belt": "Black Belt", + "breeder": "Breeder", + "breeder_female": "Breeder", + "breeders": "Breeders", + "clerk": "Clerk", + "clerk_female": "Clerk", + "colleagues": "Colleagues", + "crush_kin": "Crush Kin", + "cyclist": "Cyclist", + "cyclist_female": "Cyclist", + "cyclists": "Cyclists", + "dancer": "Dancer", + "dancer_female": "Dancer", + "depot_agent": "Depot Agent", + "doctor": "Doctor", + "doctor_female": "Doctor", + "firebreather": "Firebreather", + "fisherman": "Fisherman", + "fisherman_female": "Fisherman", + "gentleman": "Gentleman", + "guitarist": "Guitarist", + "guitarist_female": "Guitarist", + "harlequin": "Harlequin", + "hiker": "Hiker", + "hooligans": "Hooligans", + "hoopster": "Hoopster", + "infielder": "Infielder", + "janitor": "Janitor", + "lady": "Lady", + "lass": "Lass", + "linebacker": "Linebacker", + "maid": "Maid", + "madame": "Madame", + "medical_team": "Medical Team", + "musician": "Musician", + "hex_maniac": "Hex Maniac", + "nurse": "Nurse", + "nursery_aide": "Nursery Aide", + "officer": "Officer", + "parasol_lady": "Parasol Lady", + "pilot": "Pilot", + "pokéfan": "Poké Fan", + "pokéfan_female": "Poké Fan", + "pokéfan_family": "Poké Fan Family", + "preschooler": "Preschooler", + "preschooler_female": "Preschooler", + "preschoolers": "Preschoolers", + "psychic": "Psychic", + "psychic_female": "Psychic", + "psychics": "Psychics", + "pokémon_ranger": "Pokémon Ranger", + "pokémon_ranger_female": "Pokémon Ranger", + "pokémon_rangers": "Pokémon Ranger", + "ranger": "Ranger", + "restaurant_staff": "Restaurant Staff", + "rich": "Rich", + "rich_female": "Rich", + "rich_boy": "Rich Boy", + "rich_couple": "Rich Couple", + "rich_kid": "Rich Kid", + "rich_kid_female": "Rich Kid", + "rich_kids": "Rich Kids", + "roughneck": "Roughneck", + "sailor": "Sailor", + "scientist": "Scientist", + "scientist_female": "Scientist", + "scientists": "Scientists", + "smasher": "Smasher", + "snow_worker": "Snow Worker", + "snow_worker_female": "Snow Worker", + "striker": "Striker", + "school_kid": "School Kid", + "school_kid_female": "School Kid", + "school_kids": "School Kids", + "swimmer": "Swimmer", + "swimmer_female": "Swimmer", + "swimmers": "Swimmers", + "twins": "Twins", + "veteran": "Veteran", + "veteran_female": "Veteran", + "veteran_duo": "Veteran Duo", + "waiter": "Waiter", + "waitress": "Waitress", + "worker": "Worker", + "worker_female": "Worker", + "workers": "Workers", + "youngster": "Youngster", + "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 +export const trainerNames: SimpleTranslationEntries = { + "brock": "Brock", + "misty": "Misty", + "lt_surge": "Lt Surge", + "erika": "Erika", + "janine": "Janine", + "sabrina": "Sabrina", + "blaine": "Blaine", + "giovanni": "Giovanni", + "falkner": "Falkner", + "bugsy": "Bugsy", + "whitney": "Whitney", + "morty": "Morty", + "chuck": "Chuck", + "jasmine": "Jasmine", + "pryce": "Pryce", + "clair": "Clair", + "roxanne": "Roxanne", + "brawly": "Brawly", + "wattson": "Wattson", + "flannery": "Flannery", + "norman": "Norman", + "winona": "Winona", + "tate": "Tate", + "liza": "Liza", + "juan": "Juan", + "roark": "Roark", + "gardenia": "Gardenia", + "maylene": "Maylene", + "crasher_wake": "Crasher Wake", + "fantina": "Fantina", + "byron": "Byron", + "candice": "Candice", + "volkner": "Volkner", + "cilan": "Cilan", + "chili": "Chili", + "cress": "Cress", + "cheren": "Cheren", + "lenora": "Lenora", + "roxie": "Roxie", + "burgh": "Burgh", + "elesa": "Elesa", + "clay": "Clay", + "skyla": "Skyla", + "brycen": "Brycen", + "drayden": "Drayden", + "marlon": "Marlon", + "viola": "Viola", + "grant": "Grant", + "korrina": "Korrina", + "ramos": "Ramos", + "clemont": "Clemont", + "valerie": "Valerie", + "olympia": "Olympia", + "wulfric": "Wulfric", + "milo": "Milo", + "nessa": "Nessa", + "kabu": "Kabu", + "bea": "Bea", + "allister": "Allister", + "opal": "Opal", + "bede": "Bede", + "gordie": "Gordie", + "melony": "Melony", + "piers": "Piers", + "marnie": "Marnie", + "raihan": "Raihan", + "katy": "Katy", + "brassius": "Brassius", + "iono": "Iono", + "kofu": "Kofu", + "larry": "Larry", + "ryme": "Ryme", + "tulip": "Tulip", + "grusha": "Grusha", + "lorelei": "Lorelei", + "bruno": "Bruno", + "agatha": "Agatha", + "lance": "Lance", + "will": "Will", + "koga": "Koga", + "karen": "Karen", + "sidney": "Sidney", + "phoebe": "Phoebe", + "glacia": "Glacia", + "drake": "Drake", + "aaron": "Aaron", + "bertha": "Bertha", + "flint": "Flint", + "lucian": "Lucian", + "shauntal": "Shauntal", + "marshal": "Marshal", + "grimsley": "Grimsley", + "caitlin": "Caitlin", + "malva": "Malva", + "siebold": "Siebold", + "wikstrom": "Wikstrom", + "drasna": "Drasna", + "hala": "Hala", + "molayne": "Molayne", + "olivia": "Olivia", + "acerola": "Acerola", + "kahili": "Kahili", + "rika": "Rika", + "poppy": "Poppy", + "hassel": "Hassel", + "crispin": "Crispin", + "amarys": "Amarys", + "lacey": "Lacey", + "drayton": "Drayton", + "blue": "Blue", + "red": "Red", + "steven": "Steven", + "wallace": "Wallace", + "cynthia": "Cynthia", + "alder": "Alder", + "iris": "Iris", + "diantha": "Diantha", + "hau": "Hau", + "geeta": "Geeta", + "nemona": "Nemona", + "kieran": "Kieran", + "leon": "Leon", + "rival": "Finn", + "rival_female": "Ivy", + "maxie": "Maxie", + "archie": "Archie", + "cyrus": "Cyrus", + "ghetsis": "Ghetsis", + "lysandre": "Lysandre", + + // Double Names + "blue_red_double": "Blue & Red", + "red_blue_double": "Red & Blue", + "tate_liza_double": "Tate & Liza", + "liza_tate_double": "Liza & Tate", + "steven_wallace_double": "Steven & Wallace", + "wallace_steven_double": "Wallace & Steven", + "alder_iris_double": "Alder & Iris", + "iris_alder_double": "Iris & Alder", + "marnie_piers_double": "Marnie & Piers", + "piers_marnie_double": "Piers & Marnie", +} as const; diff --git a/src/locales/ca-ES/tutorial.ts b/src/locales/ca-ES/tutorial.ts new file mode 100644 index 00000000000..3c4aa2b46f6 --- /dev/null +++ b/src/locales/ca-ES/tutorial.ts @@ -0,0 +1,44 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +export const tutorial: SimpleTranslationEntries = { + "intro": `Welcome to PokéRogue! This is a battle-focused Pokémon fangame with roguelite elements. + $This game is not monetized and we claim no ownership of Pokémon nor of the copyrighted assets used. + $The game is a work in progress, but fully playable.\nFor bug reports, please use the Discord community. + $If the game runs slowly, please ensure 'Hardware Acceleration' is turned on in your browser settings.`, + + "accessMenu": "To access the menu, press M or Escape while awaiting input.\nThe menu contains settings and various features.", + + "menu": `From this menu you can access the settings. + $From the settings you can change game speed, window style, and other options. + $There are also various other features here, so be sure to check them all!`, + + "starterSelect": `From this screen, you can select your starters by pressing\nZ or the Space bar. These are your initial party members. + $Each starter has a value. Your party can have up to\n6 members as long as the total does not exceed 10. + $You can also select gender, ability, and form depending on\nthe variants you've caught or hatched. + $The IVs for a species are also the best of every one you've\ncaught or hatched, so try to get lots of the same species!`, + + "pokerus": `A daily random 3 selectable starters have a purple border. + $If you see a starter you own with one of these,\ntry adding it to your party. Be sure to check its summary!`, + + "statChange": `Stat changes persist across battles as long as your Pokémon aren't recalled. + $Your Pokémon are recalled before a trainer battle and before entering a new biome. + $You can view the stat changes for any Pokémon on the field by holding C or Shift. + $You can also view the moveset for an enemy Pokémon by holding V. + $This only reveals moves that you've seen the Pokémon use this battle.`, + + "selectItem": `After every battle, you are given a choice of 3 random items.\nYou may only pick one. + $These range from consumables, to Pokémon held items, to passive permanent items. + $Most non-consumable item effects will stack in various ways. + $Some items will only show up if they can be used, such as evolution items. + $You can also transfer held items between Pokémon using the transfer option. + $The transfer option will appear in the bottom right once you have obtained a held item. + $You may purchase consumable items with money, and a larger variety will be available the further you get. + $Be sure to buy these before you pick your random item, as it will progress to the next battle once you do.`, + + "eggGacha": `From this screen, you can redeem your vouchers for\nPokémon eggs. + $Eggs have to be hatched and get closer to hatching after\nevery battle. Rarer eggs take longer to hatch. + $Hatched Pokémon also won't be added to your party, they will\nbe added to your starters. + $Pokémon hatched from eggs generally have better IVs than\nwild Pokémon. + $Some Pokémon can only even be obtained from eggs. + $There are 3 different machines to pull from with different\nbonuses, so pick the one that suits you best!`, +} as const; diff --git a/src/locales/ca-ES/voucher.ts b/src/locales/ca-ES/voucher.ts new file mode 100644 index 00000000000..b2894711020 --- /dev/null +++ b/src/locales/ca-ES/voucher.ts @@ -0,0 +1,11 @@ +import { SimpleTranslationEntries } from "#app/interfaces/locales"; + +export const voucher: SimpleTranslationEntries = { + "vouchers": "Vouchers", + "eggVoucher": "Egg Voucher", + "eggVoucherPlus": "Egg Voucher Plus", + "eggVoucherPremium": "Egg Voucher Premium", + "eggVoucherGold": "Egg Voucher Gold", + "locked": "Locked", + "defeatTrainer": "Defeat {{trainerName}}" +} as const; diff --git a/src/locales/ca-ES/weather.ts b/src/locales/ca-ES/weather.ts new file mode 100644 index 00000000000..8222064f341 --- /dev/null +++ b/src/locales/ca-ES/weather.ts @@ -0,0 +1,66 @@ +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.", + + "rainStartMessage": "A downpour started!", + "rainLapseMessage": "The downpour continues.", + "rainClearMessage": "The rain stopped.", + + "sandstormStartMessage": "A sandstorm brewed!", + "sandstormLapseMessage": "The sandstorm rages.", + "sandstormClearMessage": "The sandstorm subsided.", + "sandstormDamageMessage": "{{pokemonNameWithAffix}} is buffeted\nby the sandstorm!", + + "hailStartMessage": "It started to hail!", + "hailLapseMessage": "Hail continues to fall.", + "hailClearMessage": "The hail stopped.", + "hailDamageMessage": "{{pokemonNameWithAffix}} is pelted\nby the hail!", + + "snowStartMessage": "It started to snow!", + "snowLapseMessage": "The snow is falling down.", + "snowClearMessage": "The snow stopped.", + + "fogStartMessage": "A thick fog emerged!", + "fogLapseMessage": "The fog continues.", + "fogClearMessage": "The fog disappeared.", + + "heavyRainStartMessage": "A heavy downpour started!", + "heavyRainLapseMessage": "The heavy downpour continues.", + "heavyRainClearMessage": "The heavy rain stopped.", + + "harshSunStartMessage": "The sunlight got hot!", + "harshSunLapseMessage": "The sun is scorching hot.", + "harshSunClearMessage": "The harsh sunlight faded.", + + "strongWindsStartMessage": "A heavy wind began!", + "strongWindsLapseMessage": "The wind blows intensely.", + "strongWindsEffectMessage": "The mysterious air current weakened the attack!", + "strongWindsClearMessage": "The heavy wind stopped." +}; + +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!", + + "electric": "Electric", + "electricStartMessage": "An electric current ran across the battlefield!", + "electricClearMessage": "The electricity disappeared from the battlefield.", + + "grassy": "Grassy", + "grassyStartMessage": "Grass grew to cover the battlefield!", + "grassyClearMessage": "The grass disappeared from the battlefield.", + + "psychic": "Psychic", + "psychicStartMessage": "The battlefield got weird!", + "psychicClearMessage": "The weirdness disappeared from the battlefield!", + + "defaultBlockMessage": "{{pokemonNameWithAffix}} is protected by the {{terrainName}} Terrain!" +}; diff --git a/src/plugins/i18n.ts b/src/plugins/i18n.ts index 7b8a56a62f7..54dc545868c 100644 --- a/src/plugins/i18n.ts +++ b/src/plugins/i18n.ts @@ -2,6 +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 { deConfig } from "#app/locales/de/config.js"; import { enConfig } from "#app/locales/en/config.js"; import { esConfig } from "#app/locales/es/config.js"; @@ -44,12 +45,12 @@ const fonts: Array = [ { face: new FontFace("emerald", "url(./fonts/unifont-15.1.05.subset.woff2)", { unicodeRange: rangesByLanguage.chinese }), extraOptions: { sizeAdjust: "70%", format: "woff2" }, - only: [ "en", "es", "fr", "it", "de", "zh", "pt", "ko" ], + only: [ "en", "es", "fr", "it", "de", "zh", "pt", "ko", "ca" ], }, { face: new FontFace("pkmnems", "url(./fonts/unifont-15.1.05.subset.woff2)", { unicodeRange: rangesByLanguage.chinese }), extraOptions: { format: "woff2" }, - only: [ "en", "es", "fr", "it", "de", "zh", "pt", "ko" ], + only: [ "en", "es", "fr", "it", "de", "zh", "pt", "ko", "ca" ], }, // japanese { @@ -108,7 +109,7 @@ export async function initI18n(): Promise { await i18next.init({ nonExplicitSupportedLngs: true, fallbackLng: "en", - supportedLngs: ["en", "es", "fr", "it", "de", "zh", "pt", "ko", "ja"], + supportedLngs: ["en", "es", "fr", "it", "de", "zh", "pt", "ko", "ja", "ca"], defaultNS: "menu", ns: Object.keys(enConfig), detection: { @@ -148,6 +149,9 @@ export async function initI18n(): Promise { }, ja: { ...jaConfig + }, + "ca-ES": { + ...caESConfig } }, postProcess: ["korean-postposition"], diff --git a/src/system/settings/settings.ts b/src/system/settings/settings.ts index ce061846a1d..96acffd6bfb 100644 --- a/src/system/settings/settings.ts +++ b/src/system/settings/settings.ts @@ -767,6 +767,10 @@ export function setSetting(scene: BattleScene, setting: string, value: integer): label: "日本語", handler: () => changeLocaleHandler("ja") }, + { + label: "Català", + handler: () => changeLocaleHandler("ca-ES") + }, { label: i18next.t("settings:back"), handler: () => cancelHandler() diff --git a/src/ui/settings/settings-display-ui-handler.ts b/src/ui/settings/settings-display-ui-handler.ts index 73b8c5ce5ca..5193f76a5e0 100644 --- a/src/ui/settings/settings-display-ui-handler.ts +++ b/src/ui/settings/settings-display-ui-handler.ts @@ -85,6 +85,12 @@ export default class SettingsDisplayUiHandler extends AbstractSettingsUiHandler label: "日本語", }; break; + case "ca-ES": + this.settings[languageIndex].options[0] = { + value: "Català", + label: "Català", + }; + break; default: this.settings[languageIndex].options[0] = { value: "English", diff --git a/src/ui/starter-select-ui-handler.ts b/src/ui/starter-select-ui-handler.ts index 8716c9c73ec..c1f7639ca99 100644 --- a/src/ui/starter-select-ui-handler.ts +++ b/src/ui/starter-select-ui-handler.ts @@ -107,7 +107,11 @@ const languageSettings: { [key: string]: LanguageSetting } = { "ja":{ starterInfoTextSize: "51px", instructionTextSize: "38px", - } + }, + "ca-ES":{ + starterInfoTextSize: "56px", + instructionTextSize: "38px", + }, }; const starterCandyCosts: { passive: integer, costReduction: [integer, integer], egg: integer }[] = [ From 0ef329e8eb208b3b1e53c1d0ed36c4f144567816 Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Wed, 7 Aug 2024 05:52:20 -0700 Subject: [PATCH 011/257] [Test] Add helper function to modify the turn order for tests (#3374) * Add helper function to modify the turn order for tests * Replace manual speed modification with new helper function * Replace `vi.spyOn()` instances with helper function --- 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 | 14 ++++++----- src/test/items/leek.test.ts | 7 +++--- src/test/items/scope_lens.test.ts | 8 +++--- src/test/moves/fusion_flare_bolt.test.ts | 31 +++++++----------------- src/test/moves/gastro_acid.test.ts | 9 +++---- src/test/utils/gameManager.ts | 2 +- src/test/utils/testUtils.ts | 27 +++++++++++++++++---- 10 files changed, 62 insertions(+), 56 deletions(-) diff --git a/src/test/abilities/serene_grace.test.ts b/src/test/abilities/serene_grace.test.ts index 25ffc2ed2c6..3e8ff0bbea0 100644 --- a/src/test/abilities/serene_grace.test.ts +++ b/src/test/abilities/serene_grace.test.ts @@ -11,6 +11,8 @@ 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 { BattlerIndex } from "#app/battle.js"; describe("Abilities - Serene Grace", () => { @@ -45,7 +47,6 @@ describe("Abilities - Serene Grace", () => { game.scene.getEnemyParty()[0].stats[Stat.SPDEF] = 10000; - game.scene.getEnemyParty()[0].stats[Stat.SPD] = 1; expect(game.scene.getParty()[0].formIndex).toBe(0); game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { @@ -56,6 +57,7 @@ describe("Abilities - Serene Grace", () => { (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); }); + await changeTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEffectPhase, false); // Check chance of Air Slash without Serene Grace @@ -78,7 +80,6 @@ describe("Abilities - Serene Grace", () => { ]); game.scene.getEnemyParty()[0].stats[Stat.SPDEF] = 10000; - game.scene.getEnemyParty()[0].stats[Stat.SPD] = 1; expect(game.scene.getParty()[0].formIndex).toBe(0); game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { @@ -89,6 +90,7 @@ describe("Abilities - Serene Grace", () => { (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); }); + await changeTurnOrder(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 8d315e3caad..d3e1ae904cc 100644 --- a/src/test/abilities/sheer_force.test.ts +++ b/src/test/abilities/sheer_force.test.ts @@ -11,6 +11,8 @@ 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 { BattlerIndex } from "#app/battle.js"; describe("Abilities - Sheer Force", () => { @@ -46,7 +48,6 @@ describe("Abilities - Sheer Force", () => { game.scene.getEnemyParty()[0].stats[Stat.SPDEF] = 10000; - game.scene.getEnemyParty()[0].stats[Stat.SPD] = 1; expect(game.scene.getParty()[0].formIndex).toBe(0); game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { @@ -57,6 +58,7 @@ describe("Abilities - Sheer Force", () => { (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); }); + await changeTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEffectPhase, false); const phase = game.scene.getCurrentPhase() as MoveEffectPhase; @@ -85,7 +87,6 @@ describe("Abilities - Sheer Force", () => { game.scene.getEnemyParty()[0].stats[Stat.DEF] = 10000; - game.scene.getEnemyParty()[0].stats[Stat.SPD] = 1; expect(game.scene.getParty()[0].formIndex).toBe(0); game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { @@ -96,6 +97,7 @@ describe("Abilities - Sheer Force", () => { (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); }); + await changeTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEffectPhase, false); const phase = game.scene.getCurrentPhase() as MoveEffectPhase; @@ -124,7 +126,6 @@ describe("Abilities - Sheer Force", () => { game.scene.getEnemyParty()[0].stats[Stat.DEF] = 10000; - game.scene.getEnemyParty()[0].stats[Stat.SPD] = 1; expect(game.scene.getParty()[0].formIndex).toBe(0); game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { @@ -135,6 +136,7 @@ describe("Abilities - Sheer Force", () => { (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); }); + await changeTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY]); await game.phaseInterceptor.to(MoveEffectPhase, false); const phase = game.scene.getCurrentPhase() as MoveEffectPhase; @@ -165,7 +167,6 @@ describe("Abilities - Sheer Force", () => { game.scene.getEnemyParty()[0].stats[Stat.DEF] = 10000; - game.scene.getEnemyParty()[0].stats[Stat.SPD] = 1; expect(game.scene.getParty()[0].formIndex).toBe(0); game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { @@ -176,6 +177,7 @@ describe("Abilities - Sheer Force", () => { (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); }); + await changeTurnOrder(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 6050e6d4c9a..f6906cb7b85 100644 --- a/src/test/abilities/shield_dust.test.ts +++ b/src/test/abilities/shield_dust.test.ts @@ -11,6 +11,8 @@ import { Moves } from "#enums/moves"; 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"; describe("Abilities - Shield Dust", () => { @@ -46,7 +48,6 @@ describe("Abilities - Shield Dust", () => { game.scene.getEnemyParty()[0].stats[Stat.SPDEF] = 10000; - game.scene.getEnemyParty()[0].stats[Stat.SPD] = 1; expect(game.scene.getParty()[0].formIndex).toBe(0); game.onNextPrompt("CommandPhase", Mode.COMMAND, () => { @@ -57,6 +58,7 @@ describe("Abilities - Shield Dust", () => { (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); }); + await changeTurnOrder(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 f11694b061c..01d3724825c 100644 --- a/src/test/abilities/zen_mode.test.ts +++ b/src/test/abilities/zen_mode.test.ts @@ -11,6 +11,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 { BattlerIndex } from "#app/battle.js"; +import { changeTurnOrder } from "../utils/testUtils"; const TIMEOUT = 20 * 1000; @@ -45,7 +47,6 @@ describe("Abilities - ZEN MODE", () => { async () => { const moveToUse = Moves.SPLASH; await game.startBattle([Species.DARMANITAN]); - game.scene.getParty()[0].stats[Stat.SPD] = 1; game.scene.getParty()[0].stats[Stat.HP] = 100; game.scene.getParty()[0].hp = 100; expect(game.scene.getParty()[0].formIndex).toBe(0); @@ -57,7 +58,8 @@ describe("Abilities - ZEN MODE", () => { const movePosition = getMovePosition(game.scene, 0, moveToUse); (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); }); - await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(DamagePhase, false); + await changeTurnOrder(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; damagePhase.updateAmount(40); @@ -73,7 +75,6 @@ describe("Abilities - ZEN MODE", () => { async () => { const moveToUse = Moves.SPLASH; await game.startBattle([Species.DARMANITAN]); - game.scene.getParty()[0].stats[Stat.SPD] = 1; game.scene.getParty()[0].stats[Stat.HP] = 1000; game.scene.getParty()[0].hp = 100; expect(game.scene.getParty()[0].formIndex).toBe(0); @@ -85,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 game.phaseInterceptor.runFrom(EnemyCommandPhase).to(QuietFormChangePhase); + await changeTurnOrder(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); expect(game.scene.getParty()[0].formIndex).not.toBe(0); @@ -98,7 +100,6 @@ describe("Abilities - ZEN MODE", () => { async () => { const moveToUse = Moves.SPLASH; await game.startBattle([Species.DARMANITAN, Species.CHARIZARD]); - game.scene.getParty()[0].stats[Stat.SPD] = 1; game.scene.getParty()[0].stats[Stat.HP] = 1000; game.scene.getParty()[0].hp = 100; expect(game.scene.getParty()[0].formIndex).toBe(0); @@ -110,7 +111,8 @@ describe("Abilities - ZEN MODE", () => { const movePosition = getMovePosition(game.scene, 0, moveToUse); (game.scene.getCurrentPhase() as CommandPhase).handleCommand(Command.FIGHT, movePosition, false); }); - await game.phaseInterceptor.runFrom(EnemyCommandPhase).to(DamagePhase, false); + await changeTurnOrder(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; damagePhase.updateAmount(80); diff --git a/src/test/items/leek.test.ts b/src/test/items/leek.test.ts index 7a2dd369e4e..8532f0df8d9 100644 --- a/src/test/items/leek.test.ts +++ b/src/test/items/leek.test.ts @@ -1,13 +1,14 @@ import { BattlerIndex } from "#app/battle"; import { CritBoosterModifier } from "#app/modifier/modifier"; import { modifierTypes } from "#app/modifier/modifier-type"; -import { MoveEffectPhase, TurnStartPhase } from "#app/phases"; +import { MoveEffectPhase } from "#app/phases"; import GameManager from "#test/utils/gameManager"; import * as Utils from "#app/utils"; 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"; describe("Items - Leek", () => { let phaserGame: Phaser.Game; @@ -43,9 +44,7 @@ describe("Items - Leek", () => { game.doAttack(0); - await game.phaseInterceptor.to(TurnStartPhase, false); - - vi.spyOn(game.scene.getCurrentPhase() as TurnStartPhase, "getOrder").mockReturnValue([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]); + await changeTurnOrder(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 59702ee51ac..72dc838548e 100644 --- a/src/test/items/scope_lens.test.ts +++ b/src/test/items/scope_lens.test.ts @@ -1,13 +1,14 @@ import { BattlerIndex } from "#app/battle"; import { CritBoosterModifier } from "#app/modifier/modifier"; import { modifierTypes } from "#app/modifier/modifier-type"; -import { MoveEffectPhase, TurnStartPhase } from "#app/phases"; +import { MoveEffectPhase } from "#app/phases"; import GameManager from "#test/utils/gameManager"; import * as Utils from "#app/utils"; 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"; describe("Items - Scope Lens", () => { let phaserGame: Phaser.Game; @@ -42,10 +43,7 @@ describe("Items - Scope Lens", () => { ]); game.doAttack(0); - - await game.phaseInterceptor.to(TurnStartPhase, false); - - vi.spyOn(game.scene.getCurrentPhase() as TurnStartPhase, "getOrder").mockReturnValue([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]); + await changeTurnOrder(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 e04d766f848..b0c374c1cd3 100644 --- a/src/test/moves/fusion_flare_bolt.test.ts +++ b/src/test/moves/fusion_flare_bolt.test.ts @@ -1,13 +1,14 @@ import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; import Phaser from "phaser"; import GameManager from "#test/utils/gameManager"; -import { MoveEffectPhase, MovePhase, MoveEndPhase, TurnStartPhase, DamagePhase } from "#app/phases"; +import { MoveEffectPhase, MovePhase, MoveEndPhase, DamagePhase } from "#app/phases"; import { getMovePosition } from "#test/utils/gameManagerUtils"; import { Stat } from "#app/data/pokemon-stat"; 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"; describe("Moves - Fusion Flare and Fusion Bolt", () => { let phaserGame: Phaser.Game; @@ -54,10 +55,8 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { game.doAttack(getMovePosition(game.scene, 0, fusionBolt.id)); game.doSelectTarget(BattlerIndex.ENEMY); - await game.phaseInterceptor.to(TurnStartPhase, false); - // Force user party to act before enemy party - vi.spyOn(game.scene.getCurrentPhase() as TurnStartPhase, "getOrder").mockReturnValue([ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]); + await changeTurnOrder(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,10 +81,8 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { game.doAttack(getMovePosition(game.scene, 0, fusionFlare.id)); game.doSelectTarget(BattlerIndex.ENEMY); - await game.phaseInterceptor.to(TurnStartPhase, false); - // Force user party to act before enemy party - vi.spyOn(game.scene.getCurrentPhase() as TurnStartPhase, "getOrder").mockReturnValue([ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]); + await changeTurnOrder(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); @@ -110,10 +107,8 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { game.doAttack(getMovePosition(game.scene, 0, fusionBolt.id)); game.doSelectTarget(0); - await game.phaseInterceptor.to(TurnStartPhase, false); - // Force first enemy to act (and fail) in between party - vi.spyOn(game.scene.getCurrentPhase() as TurnStartPhase, "getOrder").mockReturnValue([ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY ]); + await changeTurnOrder(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); @@ -144,10 +139,8 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { game.doAttack(getMovePosition(game.scene, 0, fusionBolt.id)); game.doSelectTarget(BattlerIndex.ENEMY); - await game.phaseInterceptor.to(TurnStartPhase, false); - // Force first enemy to act in between party - vi.spyOn(game.scene.getCurrentPhase() as TurnStartPhase, "getOrder").mockReturnValue([ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY ]); + await changeTurnOrder(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); @@ -176,10 +169,8 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { game.doAttack(getMovePosition(game.scene, 0, fusionFlare.id)); game.doSelectTarget(BattlerIndex.PLAYER); - await game.phaseInterceptor.to(TurnStartPhase, false); - // Force user party to act before enemy party - vi.spyOn(game.scene.getCurrentPhase() as TurnStartPhase, "getOrder").mockReturnValue([ BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2 ]); + await changeTurnOrder(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); @@ -230,10 +221,8 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { game.doAttack(getMovePosition(game.scene, 0, fusionBolt.id)); game.doSelectTarget(BattlerIndex.ENEMY); - await game.phaseInterceptor.to(TurnStartPhase, false); - // Force first enemy to act in between party - vi.spyOn(game.scene.getCurrentPhase() as TurnStartPhase, "getOrder").mockReturnValue([ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY ]); + await changeTurnOrder(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); @@ -294,10 +283,8 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => { game.doAttack(getMovePosition(game.scene, 0, fusionBolt.id)); game.doSelectTarget(BattlerIndex.PLAYER); - await game.phaseInterceptor.to(TurnStartPhase, false); - // Force first enemy to act in between party - vi.spyOn(game.scene.getCurrentPhase() as TurnStartPhase, "getOrder").mockReturnValue([ BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY ]); + await changeTurnOrder(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 cd1f0e4ab12..c6692d3442c 100644 --- a/src/test/moves/gastro_acid.test.ts +++ b/src/test/moves/gastro_acid.test.ts @@ -1,5 +1,4 @@ import { BattlerIndex } from "#app/battle.js"; -import { Stat } from "#app/data/pokemon-stat.js"; import { Abilities } from "#app/enums/abilities.js"; import { Moves } from "#app/enums/moves.js"; import { Species } from "#app/enums/species.js"; @@ -7,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 { SPLASH_ONLY } from "#test/utils/testUtils"; +import { changeTurnOrder, SPLASH_ONLY } from "#test/utils/testUtils"; const TIMEOUT = 20 * 1000; @@ -74,11 +73,9 @@ describe("Moves - Gastro Acid", () => { await game.startBattle(); - // Force player to be slower to enable Core Enforcer to proc its suppression effect - game.scene.getPlayerPokemon().stats[Stat.SPD] = 1; - game.scene.getEnemyPokemon().stats[Stat.SPD] = 2; - 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 game.phaseInterceptor.to("TurnInitPhase"); diff --git a/src/test/utils/gameManager.ts b/src/test/utils/gameManager.ts index 5540295d341..842c6086058 100644 --- a/src/test/utils/gameManager.ts +++ b/src/test/utils/gameManager.ts @@ -133,7 +133,7 @@ export default class GameManager { await this.phaseInterceptor.run(EncounterPhase); if (overrides.OPP_HELD_ITEMS_OVERRIDE.length === 0) { - removeEnemyHeldItems(this.scene); + removeEnemyHeldItems(this); } } diff --git a/src/test/utils/testUtils.ts b/src/test/utils/testUtils.ts index 476775fd268..6ba46e6fc16 100644 --- a/src/test/utils/testUtils.ts +++ b/src/test/utils/testUtils.ts @@ -1,7 +1,9 @@ -import BattleScene from "#app/battle-scene.js"; 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]; @@ -29,10 +31,25 @@ export function arrayOfRange(start: integer, end: integer) { /** * Removes all held items from enemy pokemon - * @param scene `game.scene` + * @param game The {@link GameManager} instance */ -export function removeEnemyHeldItems(scene: BattleScene) { - scene.clearEnemyHeldItemModifiers(); - scene.clearEnemyModifiers(); +export function removeEnemyHeldItems(game: GameManager): void { + game.scene.clearEnemyHeldItemModifiers(); + game.scene.clearEnemyModifiers(); console.log("Enemy held items removed"); } + +/** + * 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 + * @example + * ```ts + * await changeTurnOrder(game, [BattlerIndex.PLAYER, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2]); + * ``` + */ +export async function changeTurnOrder(game: GameManager, order: BattlerIndex[]): Promise { + await game.phaseInterceptor.to(TurnStartPhase, false); + + vi.spyOn(game.scene.getCurrentPhase() as TurnStartPhase, "getOrder").mockReturnValue(order); +} 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 012/257] [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 013/257] [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 014/257] [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 015/257] [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 016/257] [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 017/257] [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 018/257] [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 019/257] [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 020/257] [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 021/257] [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 022/257] [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 023/257] [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 024/257] [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 025/257] [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 026/257] 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 027/257] [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 028/257] [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 029/257] [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 030/257] [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 031/257] [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 032/257] [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 033/257] [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 034/257] [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 035/257] [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 036/257] [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 037/257] [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 038/257] 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 039/257] [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 040/257] [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 041/257] [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 042/257] [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 043/257] [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 044/257] [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 045/257] [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 046/257] [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 047/257] [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 048/257] [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 049/257] [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 050/257] 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 051/257] [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 052/257] [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 053/257] [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 054/257] [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 055/257] [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 056/257] [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 057/257] [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 058/257] [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 059/257] [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 060/257] [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 061/257] [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 062/257] [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 063/257] [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 064/257] [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 065/257] [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 066/257] [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 +
+
+