diff --git a/src/data/ability.ts b/src/data/ability.ts index 58824603bc3..3c73bb47c47 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -3614,22 +3614,19 @@ export class MoodyAbAttr extends PostTurnAbAttr { } } -export class PostTurnStatStageChangeAbAttr extends PostTurnAbAttr { - private stats: BattleStat[]; - private stages: number; +export class SpeedBoostAbAttr extends PostTurnAbAttr { - constructor(stats: BattleStat[], stages: number) { + constructor() { super(true); - - this.stats = Array.isArray(stats) - ? stats - : [ stats ]; - this.stages = stages; } applyPostTurn(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { if (!simulated) { - pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, this.stats, this.stages)); + if (!pokemon.turnData.switchedInThisTurn && !pokemon.turnData.failedRunAway) { + pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ Stat.SPD ], 1)); + } else { + return false; + } } return true; } @@ -4703,6 +4700,84 @@ export class PreventBypassSpeedChanceAbAttr extends AbAttr { } } +/** + * This applies a terrain-based type change to the Pokemon. + * Used by Mimicry. + */ +export class TerrainEventTypeChangeAbAttr extends PostSummonAbAttr { + constructor() { + super(true); + } + + override apply(pokemon: Pokemon, _passive: boolean, _simulated: boolean, _cancelled: Utils.BooleanHolder, _args: any[]): boolean { + if (pokemon.isTerastallized()) { + return false; + } + const currentTerrain = pokemon.scene.arena.getTerrainType(); + const typeChange: Type[] = this.determineTypeChange(pokemon, currentTerrain); + if (typeChange.length !== 0) { + if (pokemon.summonData.addedType && typeChange.includes(pokemon.summonData.addedType)) { + pokemon.summonData.addedType = null; + } + pokemon.summonData.types = typeChange; + pokemon.updateInfo(); + } + return true; + } + + /** + * Retrieves the type(s) the Pokemon should change to in response to a terrain + * @param pokemon + * @param currentTerrain {@linkcode TerrainType} + * @returns a list of type(s) + */ + private determineTypeChange(pokemon: Pokemon, currentTerrain: TerrainType): Type[] { + const typeChange: Type[] = []; + switch (currentTerrain) { + case TerrainType.ELECTRIC: + typeChange.push(Type.ELECTRIC); + break; + case TerrainType.MISTY: + typeChange.push(Type.FAIRY); + break; + case TerrainType.GRASSY: + typeChange.push(Type.GRASS); + break; + case TerrainType.PSYCHIC: + typeChange.push(Type.PSYCHIC); + break; + default: + pokemon.getTypes(false, false, true).forEach(t => { + typeChange.push(t); + }); + break; + } + return typeChange; + } + + /** + * Checks if the Pokemon should change types if summoned into an active terrain + * @returns `true` if there is an active terrain requiring a type change | `false` if not + */ + override applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean | Promise { + if (pokemon.scene.arena.getTerrainType() !== TerrainType.NONE) { + return this.apply(pokemon, passive, simulated, new Utils.BooleanHolder(false), []); + } + return false; + } + + override getTriggerMessage(pokemon: Pokemon, abilityName: string, ...args: any[]) { + const currentTerrain = pokemon.scene.arena.getTerrainType(); + const pokemonNameWithAffix = getPokemonNameWithAffix(pokemon); + if (currentTerrain === TerrainType.NONE) { + return i18next.t("abilityTriggers:pokemonTypeChangeRevert", { pokemonNameWithAffix }); + } else { + const moveType = i18next.t(`pokemonInfo:Type.${Type[this.determineTypeChange(pokemon, currentTerrain)[0]]}`); + return i18next.t("abilityTriggers:pokemonTypeChange", { pokemonNameWithAffix, moveType }); + } + } +} + async function applyAbAttrsInternal( attrType: Constructor, pokemon: Pokemon | null, @@ -4933,7 +5008,7 @@ export function initAbilities() { .attr(PostSummonWeatherChangeAbAttr, WeatherType.RAIN) .attr(PostBiomeChangeWeatherChangeAbAttr, WeatherType.RAIN), new Ability(Abilities.SPEED_BOOST, 3) - .attr(PostTurnStatStageChangeAbAttr, [ Stat.SPD ], 1), + .attr(SpeedBoostAbAttr), new Ability(Abilities.BATTLE_ARMOR, 3) .attr(BlockCritAbAttr) .ignorable(), @@ -5767,7 +5842,7 @@ export function initAbilities() { new Ability(Abilities.POWER_SPOT, 8) .attr(AllyMoveCategoryPowerBoostAbAttr, [ MoveCategory.SPECIAL, MoveCategory.PHYSICAL ], 1.3), new Ability(Abilities.MIMICRY, 8) - .unimplemented(), + .attr(TerrainEventTypeChangeAbAttr), new Ability(Abilities.SCREEN_CLEANER, 8) .attr(PostSummonRemoveArenaTagAbAttr, [ ArenaTagType.AURORA_VEIL, ArenaTagType.LIGHT_SCREEN, ArenaTagType.REFLECT ]), new Ability(Abilities.STEELY_SPIRIT, 8) @@ -5924,7 +5999,7 @@ export function initAbilities() { .attr(MovePowerBoostAbAttr, (user, target, move) => move.hasFlag(MoveFlags.SLICING_MOVE), 1.5), new Ability(Abilities.SUPREME_OVERLORD, 9) .attr(VariableMovePowerBoostAbAttr, (user, target, move) => 1 + 0.1 * Math.min(user.isPlayer() ? user.scene.currentBattle.playerFaints : user.scene.currentBattle.enemyFaints, 5)) - .partial(), // Counter resets every wave + .partial(), // Counter resets every wave instead of on arena reset new Ability(Abilities.COSTAR, 9) .attr(PostSummonCopyAllyStatsAbAttr), new Ability(Abilities.TOXIC_DEBRIS, 9) diff --git a/src/data/balance/pokemon-evolutions.ts b/src/data/balance/pokemon-evolutions.ts index 4a6e44e0d51..c0b213e4def 100644 --- a/src/data/balance/pokemon-evolutions.ts +++ b/src/data/balance/pokemon-evolutions.ts @@ -1443,7 +1443,7 @@ export const pokemonEvolutions: PokemonEvolutions = { ], [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))), - new SpeciesFormEvolution(Species.LYCANROC, "", "dusk", 25, null, new SpeciesEvolutionCondition(p => p.formIndex === 1)), + new SpeciesFormEvolution(Species.LYCANROC, "own-tempo", "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]: [ diff --git a/src/data/balance/tms.ts b/src/data/balance/tms.ts index 1a509637e05..7b65ae65ec4 100644 --- a/src/data/balance/tms.ts +++ b/src/data/balance/tms.ts @@ -12318,6 +12318,7 @@ export const tmSpecies: TmSpecies = { Species.TURTWIG, Species.GROTLE, Species.TORTERRA, + Species.BASTIODON, Species.CHINGLING, Species.BRONZOR, Species.BRONZONG, @@ -12325,6 +12326,7 @@ export const tmSpecies: TmSpecies = { Species.WEAVILE, Species.MAGNEZONE, Species.TANGROWTH, + Species.ELECTIVIRE, Species.TOGEKISS, Species.MAMOSWINE, Species.GALLADE, @@ -12357,6 +12359,8 @@ export const tmSpecies: TmSpecies = { Species.CRYOGONAL, Species.MIENFOO, Species.MIENSHAO, + Species.GOLETT, + Species.GOLURK, Species.HYDREIGON, Species.COBALION, Species.TERRAKION, @@ -40233,6 +40237,1065 @@ export const tmSpecies: TmSpecies = { Species.HISUI_ZORUA, Species.HISUI_ZOROARK, ], + [Moves.SECRET_POWER]: [ + Species.BULBASAUR, + Species.IVYSAUR, + Species.VENUSAUR, + Species.CHARMANDER, + Species.CHARMELEON, + Species.CHARIZARD, + Species.SQUIRTLE, + Species.WARTORTLE, + Species.BLASTOISE, + Species.BUTTERFREE, + Species.BEEDRILL, + Species.PIDGEY, + Species.PIDGEOTTO, + Species.PIDGEOT, + Species.RATTATA, + Species.RATICATE, + Species.SPEAROW, + Species.FEAROW, + Species.EKANS, + Species.ARBOK, + Species.PIKACHU, + Species.RAICHU, + Species.SANDSHREW, + Species.SANDSLASH, + Species.NIDORAN_F, + Species.NIDORINA, + Species.NIDOQUEEN, + Species.NIDORAN_M, + Species.NIDORINO, + Species.NIDOKING, + Species.CLEFAIRY, + Species.CLEFABLE, + Species.VULPIX, + Species.NINETALES, + Species.JIGGLYPUFF, + Species.WIGGLYTUFF, + Species.ZUBAT, + Species.GOLBAT, + Species.ODDISH, + Species.GLOOM, + Species.VILEPLUME, + Species.PARAS, + Species.PARASECT, + Species.VENONAT, + Species.VENOMOTH, + Species.DIGLETT, + Species.DUGTRIO, + Species.MEOWTH, + Species.PERSIAN, + Species.PSYDUCK, + Species.GOLDUCK, + Species.MANKEY, + Species.PRIMEAPE, + Species.GROWLITHE, + Species.ARCANINE, + Species.POLIWAG, + Species.POLIWHIRL, + Species.POLIWRATH, + Species.ABRA, + Species.KADABRA, + Species.ALAKAZAM, + Species.MACHOP, + Species.MACHOKE, + Species.MACHAMP, + Species.BELLSPROUT, + Species.WEEPINBELL, + Species.VICTREEBEL, + Species.TENTACOOL, + Species.TENTACRUEL, + Species.GEODUDE, + Species.GRAVELER, + Species.GOLEM, + Species.PONYTA, + Species.RAPIDASH, + Species.SLOWPOKE, + Species.SLOWBRO, + Species.MAGNEMITE, + Species.MAGNETON, + Species.FARFETCHD, + Species.DODUO, + Species.DODRIO, + Species.SEEL, + Species.DEWGONG, + Species.GRIMER, + Species.MUK, + Species.SHELLDER, + Species.CLOYSTER, + Species.GASTLY, + Species.HAUNTER, + Species.GENGAR, + Species.ONIX, + Species.DROWZEE, + Species.HYPNO, + Species.KRABBY, + Species.KINGLER, + Species.VOLTORB, + Species.ELECTRODE, + Species.EXEGGCUTE, + Species.EXEGGUTOR, + Species.CUBONE, + Species.MAROWAK, + Species.HITMONLEE, + Species.HITMONCHAN, + Species.LICKITUNG, + Species.KOFFING, + Species.WEEZING, + Species.RHYHORN, + Species.RHYDON, + Species.CHANSEY, + Species.TANGELA, + Species.KANGASKHAN, + Species.HORSEA, + Species.SEADRA, + Species.GOLDEEN, + Species.SEAKING, + Species.STARYU, + Species.STARMIE, + Species.MR_MIME, + Species.SCYTHER, + Species.JYNX, + Species.ELECTABUZZ, + Species.MAGMAR, + Species.PINSIR, + Species.TAUROS, + Species.GYARADOS, + Species.LAPRAS, + Species.EEVEE, + Species.VAPOREON, + Species.JOLTEON, + Species.FLAREON, + Species.PORYGON, + Species.OMANYTE, + Species.OMASTAR, + Species.KABUTO, + Species.KABUTOPS, + Species.AERODACTYL, + Species.SNORLAX, + Species.ARTICUNO, + Species.ZAPDOS, + Species.MOLTRES, + Species.DRATINI, + Species.DRAGONAIR, + Species.DRAGONITE, + Species.MEWTWO, + Species.MEW, + Species.CHIKORITA, + Species.BAYLEEF, + Species.MEGANIUM, + Species.CYNDAQUIL, + Species.QUILAVA, + Species.TYPHLOSION, + Species.TOTODILE, + Species.CROCONAW, + Species.FERALIGATR, + Species.SENTRET, + Species.FURRET, + Species.HOOTHOOT, + Species.NOCTOWL, + Species.LEDYBA, + Species.LEDIAN, + Species.SPINARAK, + Species.ARIADOS, + Species.CROBAT, + Species.CHINCHOU, + Species.LANTURN, + Species.PICHU, + Species.CLEFFA, + Species.IGGLYBUFF, + Species.TOGEPI, + Species.TOGETIC, + Species.NATU, + Species.XATU, + Species.MAREEP, + Species.FLAAFFY, + Species.AMPHAROS, + Species.BELLOSSOM, + Species.MARILL, + Species.AZUMARILL, + Species.SUDOWOODO, + Species.POLITOED, + Species.HOPPIP, + Species.SKIPLOOM, + Species.JUMPLUFF, + Species.AIPOM, + Species.SUNKERN, + Species.SUNFLORA, + Species.YANMA, + Species.WOOPER, + Species.QUAGSIRE, + Species.ESPEON, + Species.UMBREON, + Species.MURKROW, + Species.SLOWKING, + Species.MISDREAVUS, + Species.GIRAFARIG, + Species.PINECO, + Species.FORRETRESS, + Species.DUNSPARCE, + Species.GLIGAR, + Species.STEELIX, + Species.SNUBBULL, + Species.GRANBULL, + Species.QWILFISH, + Species.SCIZOR, + Species.SHUCKLE, + Species.HERACROSS, + Species.SNEASEL, + Species.TEDDIURSA, + Species.URSARING, + Species.SLUGMA, + Species.MAGCARGO, + Species.SWINUB, + Species.PILOSWINE, + Species.CORSOLA, + Species.REMORAID, + Species.OCTILLERY, + Species.DELIBIRD, + Species.MANTINE, + Species.SKARMORY, + Species.HOUNDOUR, + Species.HOUNDOOM, + Species.KINGDRA, + Species.PHANPY, + Species.DONPHAN, + Species.PORYGON2, + Species.STANTLER, + Species.TYROGUE, + Species.HITMONTOP, + Species.SMOOCHUM, + Species.ELEKID, + Species.MAGBY, + Species.MILTANK, + Species.BLISSEY, + Species.RAIKOU, + Species.ENTEI, + Species.SUICUNE, + Species.LARVITAR, + Species.PUPITAR, + Species.TYRANITAR, + Species.LUGIA, + Species.HO_OH, + Species.CELEBI, + Species.TREECKO, + Species.GROVYLE, + Species.SCEPTILE, + Species.TORCHIC, + Species.COMBUSKEN, + Species.BLAZIKEN, + Species.MUDKIP, + Species.MARSHTOMP, + Species.SWAMPERT, + Species.POOCHYENA, + Species.MIGHTYENA, + Species.ZIGZAGOON, + Species.LINOONE, + Species.BEAUTIFLY, + Species.DUSTOX, + Species.LOTAD, + Species.LOMBRE, + Species.LUDICOLO, + Species.SEEDOT, + Species.NUZLEAF, + Species.SHIFTRY, + Species.TAILLOW, + Species.SWELLOW, + Species.WINGULL, + Species.PELIPPER, + Species.RALTS, + Species.KIRLIA, + Species.GARDEVOIR, + Species.SURSKIT, + Species.MASQUERAIN, + Species.SHROOMISH, + Species.BRELOOM, + Species.SLAKOTH, + Species.VIGOROTH, + Species.SLAKING, + Species.NINCADA, + Species.NINJASK, + Species.SHEDINJA, + Species.WHISMUR, + Species.LOUDRED, + Species.EXPLOUD, + Species.MAKUHITA, + Species.HARIYAMA, + Species.AZURILL, + Species.NOSEPASS, + Species.SKITTY, + Species.DELCATTY, + Species.SABLEYE, + Species.MAWILE, + Species.ARON, + Species.LAIRON, + Species.AGGRON, + Species.MEDITITE, + Species.MEDICHAM, + Species.ELECTRIKE, + Species.MANECTRIC, + Species.PLUSLE, + Species.MINUN, + Species.VOLBEAT, + Species.ILLUMISE, + Species.ROSELIA, + Species.GULPIN, + Species.SWALOT, + Species.CARVANHA, + Species.SHARPEDO, + Species.WAILMER, + Species.WAILORD, + Species.NUMEL, + Species.CAMERUPT, + Species.TORKOAL, + Species.SPOINK, + Species.GRUMPIG, + Species.SPINDA, + Species.TRAPINCH, + Species.VIBRAVA, + Species.FLYGON, + Species.CACNEA, + Species.CACTURNE, + Species.SWABLU, + Species.ALTARIA, + Species.ZANGOOSE, + Species.SEVIPER, + Species.LUNATONE, + Species.SOLROCK, + Species.BARBOACH, + Species.WHISCASH, + Species.CORPHISH, + Species.CRAWDAUNT, + Species.BALTOY, + Species.CLAYDOL, + Species.LILEEP, + Species.CRADILY, + Species.ANORITH, + Species.ARMALDO, + Species.FEEBAS, + Species.MILOTIC, + Species.CASTFORM, + Species.KECLEON, + Species.SHUPPET, + Species.BANETTE, + Species.DUSKULL, + Species.DUSCLOPS, + Species.TROPIUS, + Species.CHIMECHO, + Species.ABSOL, + Species.SNORUNT, + Species.GLALIE, + Species.SPHEAL, + Species.SEALEO, + Species.WALREIN, + Species.CLAMPERL, + Species.HUNTAIL, + Species.GOREBYSS, + Species.RELICANTH, + Species.LUVDISC, + Species.BAGON, + Species.SHELGON, + Species.SALAMENCE, + Species.METANG, + Species.METAGROSS, + Species.REGIROCK, + Species.REGICE, + Species.REGISTEEL, + Species.LATIAS, + Species.LATIOS, + Species.KYOGRE, + Species.GROUDON, + Species.RAYQUAZA, + Species.JIRACHI, + Species.DEOXYS, + Species.TURTWIG, + Species.GROTLE, + Species.TORTERRA, + Species.CHIMCHAR, + Species.MONFERNO, + Species.INFERNAPE, + Species.PIPLUP, + Species.PRINPLUP, + Species.EMPOLEON, + Species.STARLY, + Species.STARAVIA, + Species.STARAPTOR, + Species.BIDOOF, + Species.BIBAREL, + Species.KRICKETUNE, + Species.SHINX, + Species.LUXIO, + Species.LUXRAY, + Species.BUDEW, + Species.ROSERADE, + Species.CRANIDOS, + Species.RAMPARDOS, + Species.SHIELDON, + Species.BASTIODON, + Species.WORMADAM, + Species.MOTHIM, + Species.VESPIQUEN, + Species.PACHIRISU, + Species.BUIZEL, + Species.FLOATZEL, + Species.CHERUBI, + Species.CHERRIM, + Species.SHELLOS, + Species.GASTRODON, + Species.AMBIPOM, + Species.DRIFLOON, + Species.DRIFBLIM, + Species.BUNEARY, + Species.LOPUNNY, + Species.MISMAGIUS, + Species.HONCHKROW, + Species.GLAMEOW, + Species.PURUGLY, + Species.CHINGLING, + Species.STUNKY, + Species.SKUNTANK, + Species.BRONZOR, + Species.BRONZONG, + Species.BONSLY, + Species.MIME_JR, + Species.HAPPINY, + Species.CHATOT, + Species.SPIRITOMB, + Species.GIBLE, + Species.GABITE, + Species.GARCHOMP, + Species.MUNCHLAX, + Species.RIOLU, + Species.LUCARIO, + Species.HIPPOPOTAS, + Species.HIPPOWDON, + Species.SKORUPI, + Species.DRAPION, + Species.CROAGUNK, + Species.TOXICROAK, + Species.CARNIVINE, + Species.FINNEON, + Species.LUMINEON, + Species.MANTYKE, + Species.SNOVER, + Species.ABOMASNOW, + Species.WEAVILE, + Species.MAGNEZONE, + Species.LICKILICKY, + Species.RHYPERIOR, + Species.TANGROWTH, + Species.ELECTIVIRE, + Species.MAGMORTAR, + Species.TOGEKISS, + Species.YANMEGA, + Species.LEAFEON, + Species.GLACEON, + Species.GLISCOR, + Species.MAMOSWINE, + Species.PORYGON_Z, + Species.GALLADE, + Species.PROBOPASS, + Species.DUSKNOIR, + Species.FROSLASS, + Species.ROTOM, + Species.UXIE, + Species.MESPRIT, + Species.AZELF, + Species.DIALGA, + Species.PALKIA, + Species.HEATRAN, + Species.REGIGIGAS, + Species.GIRATINA, + Species.CRESSELIA, + Species.PHIONE, + Species.MANAPHY, + Species.DARKRAI, + Species.SHAYMIN, + Species.ARCEUS, + Species.VICTINI, + Species.SNIVY, + Species.SERVINE, + Species.SERPERIOR, + Species.TEPIG, + Species.PIGNITE, + Species.EMBOAR, + Species.OSHAWOTT, + Species.DEWOTT, + Species.SAMUROTT, + Species.PATRAT, + Species.WATCHOG, + Species.LILLIPUP, + Species.HERDIER, + Species.STOUTLAND, + Species.PURRLOIN, + Species.LIEPARD, + Species.PANSAGE, + Species.SIMISAGE, + Species.PANSEAR, + Species.SIMISEAR, + Species.PANPOUR, + Species.SIMIPOUR, + Species.MUNNA, + Species.MUSHARNA, + Species.PIDOVE, + Species.TRANQUILL, + Species.UNFEZANT, + Species.BLITZLE, + Species.ZEBSTRIKA, + Species.ROGGENROLA, + Species.BOLDORE, + Species.GIGALITH, + Species.WOOBAT, + Species.SWOOBAT, + Species.DRILBUR, + Species.EXCADRILL, + Species.AUDINO, + Species.TIMBURR, + Species.GURDURR, + Species.CONKELDURR, + Species.TYMPOLE, + Species.PALPITOAD, + Species.SEISMITOAD, + Species.THROH, + Species.SAWK, + Species.SEWADDLE, + Species.SWADLOON, + Species.LEAVANNY, + Species.VENIPEDE, + Species.WHIRLIPEDE, + Species.SCOLIPEDE, + Species.COTTONEE, + Species.WHIMSICOTT, + Species.PETILIL, + Species.LILLIGANT, + Species.BASCULIN, + Species.SANDILE, + Species.KROKOROK, + Species.KROOKODILE, + Species.DARUMAKA, + Species.DARMANITAN, + Species.MARACTUS, + Species.DWEBBLE, + Species.CRUSTLE, + Species.SCRAGGY, + Species.SCRAFTY, + Species.SIGILYPH, + Species.YAMASK, + Species.COFAGRIGUS, + Species.TIRTOUGA, + Species.CARRACOSTA, + Species.ARCHEN, + Species.ARCHEOPS, + Species.TRUBBISH, + Species.GARBODOR, + Species.ZORUA, + Species.ZOROARK, + Species.MINCCINO, + Species.CINCCINO, + Species.GOTHITA, + Species.GOTHORITA, + Species.GOTHITELLE, + Species.SOLOSIS, + Species.DUOSION, + Species.REUNICLUS, + Species.DUCKLETT, + Species.SWANNA, + Species.VANILLITE, + Species.VANILLISH, + Species.VANILLUXE, + Species.DEERLING, + Species.SAWSBUCK, + Species.EMOLGA, + Species.KARRABLAST, + Species.ESCAVALIER, + Species.FOONGUS, + Species.AMOONGUSS, + Species.FRILLISH, + Species.JELLICENT, + Species.ALOMOMOLA, + Species.JOLTIK, + Species.GALVANTULA, + Species.FERROSEED, + Species.FERROTHORN, + Species.KLINK, + Species.KLANG, + Species.KLINKLANG, + Species.EELEKTRIK, + Species.EELEKTROSS, + Species.ELGYEM, + Species.BEHEEYEM, + Species.LITWICK, + Species.LAMPENT, + Species.CHANDELURE, + Species.AXEW, + Species.FRAXURE, + Species.HAXORUS, + Species.CUBCHOO, + Species.BEARTIC, + Species.CRYOGONAL, + Species.SHELMET, + Species.ACCELGOR, + Species.STUNFISK, + Species.MIENFOO, + Species.MIENSHAO, + Species.DRUDDIGON, + Species.GOLETT, + Species.GOLURK, + Species.PAWNIARD, + Species.BISHARP, + Species.BOUFFALANT, + Species.RUFFLET, + Species.BRAVIARY, + Species.VULLABY, + Species.MANDIBUZZ, + Species.HEATMOR, + Species.DURANT, + Species.DEINO, + Species.ZWEILOUS, + Species.HYDREIGON, + Species.LARVESTA, + Species.VOLCARONA, + Species.COBALION, + Species.TERRAKION, + Species.VIRIZION, + Species.TORNADUS, + Species.THUNDURUS, + Species.RESHIRAM, + Species.ZEKROM, + Species.LANDORUS, + Species.KYUREM, + Species.KELDEO, + Species.MELOETTA, + Species.GENESECT, + Species.CHESPIN, + Species.QUILLADIN, + Species.CHESNAUGHT, + Species.FENNEKIN, + Species.BRAIXEN, + Species.DELPHOX, + Species.FROAKIE, + Species.FROGADIER, + Species.GRENINJA, + Species.BUNNELBY, + Species.DIGGERSBY, + Species.FLETCHLING, + Species.FLETCHINDER, + Species.TALONFLAME, + Species.VIVILLON, + Species.LITLEO, + Species.PYROAR, + Species.FLABEBE, + Species.FLOETTE, + Species.FLORGES, + Species.SKIDDO, + Species.GOGOAT, + Species.PANCHAM, + Species.PANGORO, + Species.FURFROU, + Species.ESPURR, + Species.MEOWSTIC, + Species.HONEDGE, + Species.DOUBLADE, + Species.AEGISLASH, + Species.SPRITZEE, + Species.AROMATISSE, + Species.SWIRLIX, + Species.SLURPUFF, + Species.INKAY, + Species.MALAMAR, + Species.BINACLE, + Species.BARBARACLE, + Species.SKRELP, + Species.DRAGALGE, + Species.CLAUNCHER, + Species.CLAWITZER, + Species.HELIOPTILE, + Species.HELIOLISK, + Species.TYRUNT, + Species.TYRANTRUM, + Species.AMAURA, + Species.AURORUS, + Species.SYLVEON, + Species.HAWLUCHA, + Species.DEDENNE, + Species.CARBINK, + Species.GOOMY, + Species.SLIGGOO, + Species.GOODRA, + Species.KLEFKI, + Species.PHANTUMP, + Species.TREVENANT, + Species.PUMPKABOO, + Species.GOURGEIST, + Species.BERGMITE, + Species.AVALUGG, + Species.NOIBAT, + Species.NOIVERN, + Species.XERNEAS, + Species.YVELTAL, + Species.ZYGARDE, + Species.DIANCIE, + Species.HOOPA, + Species.VOLCANION, + Species.ROWLET, + Species.DARTRIX, + Species.DECIDUEYE, + Species.LITTEN, + Species.TORRACAT, + Species.INCINEROAR, + Species.POPPLIO, + Species.BRIONNE, + Species.PRIMARINA, + Species.PIKIPEK, + Species.TRUMBEAK, + Species.TOUCANNON, + Species.YUNGOOS, + Species.GUMSHOOS, + Species.GRUBBIN, + Species.CHARJABUG, + Species.VIKAVOLT, + Species.CRABRAWLER, + Species.CRABOMINABLE, + Species.ORICORIO, + Species.CUTIEFLY, + Species.RIBOMBEE, + Species.ROCKRUFF, + Species.LYCANROC, + Species.WISHIWASHI, + Species.MAREANIE, + Species.TOXAPEX, + Species.MUDBRAY, + Species.MUDSDALE, + Species.DEWPIDER, + Species.ARAQUANID, + Species.FOMANTIS, + Species.LURANTIS, + Species.MORELULL, + Species.SHIINOTIC, + Species.SALANDIT, + Species.SALAZZLE, + Species.STUFFUL, + Species.BEWEAR, + Species.BOUNSWEET, + Species.STEENEE, + Species.TSAREENA, + Species.COMFEY, + Species.ORANGURU, + Species.PASSIMIAN, + Species.WIMPOD, + Species.GOLISOPOD, + Species.SANDYGAST, + Species.PALOSSAND, + Species.TYPE_NULL, + Species.SILVALLY, + Species.MINIOR, + Species.KOMALA, + Species.TURTONATOR, + Species.TOGEDEMARU, + Species.MIMIKYU, + Species.BRUXISH, + Species.DRAMPA, + Species.DHELMISE, + Species.JANGMO_O, + Species.HAKAMO_O, + Species.KOMMO_O, + Species.TAPU_KOKO, + Species.TAPU_LELE, + Species.TAPU_BULU, + Species.TAPU_FINI, + Species.SOLGALEO, + Species.LUNALA, + Species.NIHILEGO, + Species.BUZZWOLE, + Species.PHEROMOSA, + Species.XURKITREE, + Species.CELESTEELA, + Species.KARTANA, + Species.GUZZLORD, + Species.NECROZMA, + Species.MAGEARNA, + Species.MARSHADOW, + Species.POIPOLE, + Species.NAGANADEL, + Species.STAKATAKA, + Species.BLACEPHALON, + Species.ZERAORA, + Species.MELTAN, + Species.MELMETAL, + Species.GROOKEY, + Species.THWACKEY, + Species.RILLABOOM, + Species.SCORBUNNY, + Species.RABOOT, + Species.CINDERACE, + Species.SOBBLE, + Species.DRIZZILE, + Species.INTELEON, + Species.SKWOVET, + Species.GREEDENT, + Species.ROOKIDEE, + Species.CORVISQUIRE, + Species.CORVIKNIGHT, + Species.DOTTLER, + Species.ORBEETLE, + Species.NICKIT, + Species.THIEVUL, + Species.GOSSIFLEUR, + Species.ELDEGOSS, + Species.WOOLOO, + Species.DUBWOOL, + Species.CHEWTLE, + Species.DREDNAW, + Species.YAMPER, + Species.BOLTUND, + Species.ROLYCOLY, + Species.CARKOL, + Species.COALOSSAL, + Species.FLAPPLE, + Species.APPLETUN, + Species.SILICOBRA, + Species.SANDACONDA, + Species.CRAMORANT, + Species.ARROKUDA, + Species.BARRASKEWDA, + Species.TOXEL, + Species.TOXTRICITY, + Species.SIZZLIPEDE, + Species.CENTISKORCH, + Species.CLOBBOPUS, + Species.GRAPPLOCT, + Species.SINISTEA, + Species.POLTEAGEIST, + Species.HATENNA, + Species.HATTREM, + Species.HATTERENE, + Species.IMPIDIMP, + Species.MORGREM, + Species.GRIMMSNARL, + Species.OBSTAGOON, + Species.PERRSERKER, + Species.CURSOLA, + Species.SIRFETCHD, + Species.MR_RIME, + Species.RUNERIGUS, + Species.MILCERY, + Species.ALCREMIE, + Species.FALINKS, + Species.PINCURCHIN, + Species.SNOM, + Species.FROSMOTH, + Species.STONJOURNER, + Species.EISCUE, + Species.INDEEDEE, + Species.MORPEKO, + Species.CUFANT, + Species.COPPERAJAH, + Species.DRACOZOLT, + Species.ARCTOZOLT, + Species.DRACOVISH, + Species.ARCTOVISH, + Species.DURALUDON, + Species.DREEPY, + Species.DRAKLOAK, + Species.DRAGAPULT, + Species.ZACIAN, + Species.ZAMAZENTA, + Species.ETERNATUS, + Species.KUBFU, + Species.URSHIFU, + Species.ZARUDE, + Species.REGIELEKI, + Species.REGIDRAGO, + Species.GLASTRIER, + Species.SPECTRIER, + Species.CALYREX, + Species.WYRDEER, + Species.KLEAVOR, + Species.URSALUNA, + Species.BASCULEGION, + Species.SNEASLER, + Species.OVERQWIL, + Species.ENAMORUS, + Species.SPRIGATITO, + Species.FLORAGATO, + Species.MEOWSCARADA, + Species.FUECOCO, + Species.CROCALOR, + Species.SKELEDIRGE, + Species.QUAXLY, + Species.QUAXWELL, + Species.QUAQUAVAL, + Species.LECHONK, + Species.OINKOLOGNE, + Species.TAROUNTULA, + Species.SPIDOPS, + Species.NYMBLE, + Species.LOKIX, + Species.PAWMI, + Species.PAWMO, + Species.PAWMOT, + Species.TANDEMAUS, + Species.MAUSHOLD, + Species.FIDOUGH, + Species.DACHSBUN, + Species.SMOLIV, + Species.DOLLIV, + Species.ARBOLIVA, + Species.SQUAWKABILLY, + Species.NACLI, + Species.NACLSTACK, + Species.GARGANACL, + Species.CHARCADET, + Species.ARMAROUGE, + Species.CERULEDGE, + Species.TADBULB, + Species.BELLIBOLT, + Species.WATTREL, + Species.KILOWATTREL, + Species.MASCHIFF, + Species.MABOSSTIFF, + Species.SHROODLE, + Species.GRAFAIAI, + Species.BRAMBLIN, + Species.BRAMBLEGHAST, + Species.TOEDSCOOL, + Species.TOEDSCRUEL, + Species.KLAWF, + Species.CAPSAKID, + Species.SCOVILLAIN, + Species.RELLOR, + Species.RABSCA, + Species.FLITTLE, + Species.ESPATHRA, + Species.TINKATINK, + Species.TINKATUFF, + Species.TINKATON, + Species.WIGLETT, + Species.WUGTRIO, + Species.BOMBIRDIER, + Species.FINIZEN, + Species.PALAFIN, + Species.VAROOM, + Species.REVAVROOM, + Species.CYCLIZAR, + Species.ORTHWORM, + Species.GLIMMET, + Species.GLIMMORA, + Species.GREAVARD, + Species.HOUNDSTONE, + Species.FLAMIGO, + Species.CETODDLE, + Species.CETITAN, + Species.VELUZA, + Species.DONDOZO, + Species.TATSUGIRI, + Species.ANNIHILAPE, + Species.CLODSIRE, + Species.FARIGIRAF, + Species.DUDUNSPARCE, + Species.KINGAMBIT, + Species.GREAT_TUSK, + Species.SCREAM_TAIL, + Species.BRUTE_BONNET, + Species.FLUTTER_MANE, + Species.SLITHER_WING, + Species.SANDY_SHOCKS, + Species.IRON_TREADS, + Species.IRON_BUNDLE, + Species.IRON_HANDS, + Species.IRON_JUGULIS, + Species.IRON_MOTH, + Species.IRON_THORNS, + Species.FRIGIBAX, + Species.ARCTIBAX, + Species.BAXCALIBUR, + Species.GIMMIGHOUL, + Species.GHOLDENGO, + Species.WO_CHIEN, + Species.CHIEN_PAO, + Species.TING_LU, + Species.CHI_YU, + Species.ROARING_MOON, + Species.IRON_VALIANT, + Species.KORAIDON, + Species.MIRAIDON, + Species.WALKING_WAKE, + Species.IRON_LEAVES, + Species.DIPPLIN, + Species.POLTCHAGEIST, + Species.SINISTCHA, + Species.OKIDOGI, + Species.MUNKIDORI, + Species.FEZANDIPITI, + Species.OGERPON, + Species.ARCHALUDON, + Species.HYDRAPPLE, + Species.GOUGING_FIRE, + Species.RAGING_BOLT, + Species.IRON_BOULDER, + Species.IRON_CROWN, + Species.TERAPAGOS, + Species.PECHARUNT, + Species.ALOLA_RATTATA, + Species.ALOLA_RATICATE, + Species.ALOLA_RAICHU, + Species.ALOLA_SANDSHREW, + Species.ALOLA_SANDSLASH, + Species.ALOLA_VULPIX, + Species.ALOLA_NINETALES, + Species.ALOLA_DIGLETT, + Species.ALOLA_DUGTRIO, + Species.ALOLA_MEOWTH, + Species.ALOLA_PERSIAN, + Species.ALOLA_GEODUDE, + Species.ALOLA_GRAVELER, + Species.ALOLA_GOLEM, + Species.ALOLA_GRIMER, + Species.ALOLA_MUK, + Species.ALOLA_EXEGGUTOR, + Species.ALOLA_MAROWAK, + Species.ETERNAL_FLOETTE, + Species.GALAR_MEOWTH, + Species.GALAR_PONYTA, + Species.GALAR_RAPIDASH, + Species.GALAR_SLOWPOKE, + Species.GALAR_SLOWBRO, + Species.GALAR_FARFETCHD, + Species.GALAR_WEEZING, + Species.GALAR_MR_MIME, + Species.GALAR_ARTICUNO, + Species.GALAR_ZAPDOS, + Species.GALAR_MOLTRES, + Species.GALAR_SLOWKING, + Species.GALAR_CORSOLA, + Species.GALAR_ZIGZAGOON, + Species.GALAR_LINOONE, + Species.GALAR_DARUMAKA, + Species.GALAR_DARMANITAN, + Species.GALAR_YAMASK, + Species.GALAR_STUNFISK, + Species.HISUI_GROWLITHE, + Species.HISUI_ARCANINE, + Species.HISUI_VOLTORB, + Species.HISUI_ELECTRODE, + Species.HISUI_TYPHLOSION, + Species.HISUI_QWILFISH, + Species.HISUI_SNEASEL, + Species.HISUI_SAMUROTT, + Species.HISUI_LILLIGANT, + Species.HISUI_ZORUA, + Species.HISUI_ZOROARK, + Species.HISUI_BRAVIARY, + Species.HISUI_SLIGGOO, + Species.HISUI_GOODRA, + Species.HISUI_AVALUGG, + Species.HISUI_DECIDUEYE, + Species.PALDEA_TAUROS, + Species.PALDEA_WOOPER, + Species.BLOODMOON_URSALUNA, + ], [Moves.DIVE]: [ Species.SQUIRTLE, Species.WARTORTLE, @@ -59529,26 +60592,6 @@ export const tmSpecies: TmSpecies = { Species.HISUI_SAMUROTT, Species.PALDEA_TAUROS, ], - [Moves.SACRED_SWORD]: [ - Species.GALLADE, - Species.OSHAWOTT, - Species.DEWOTT, - Species.SAMUROTT, - Species.COBALION, - Species.TERRAKION, - Species.VIRIZION, - Species.KELDEO, - Species.HONEDGE, - Species.DOUBLADE, - Species.AEGISLASH, - Species.KARTANA, - Species.ZACIAN, - Species.CHIEN_PAO, - Species.IRON_LEAVES, - Species.IRON_BOULDER, - Species.IRON_CROWN, - Species.HISUI_SAMUROTT, - ], [Moves.RAZOR_SHELL]: [ Species.SLOWBRO, Species.SHELLDER, @@ -67389,6 +68432,7 @@ export const tmPoolTiers: TmPoolTiers = { [Moves.ENDEAVOR]: ModifierTier.COMMON, [Moves.SKILL_SWAP]: ModifierTier.COMMON, [Moves.IMPRISON]: ModifierTier.COMMON, + [Moves.SECRET_POWER]: ModifierTier.COMMON, [Moves.DIVE]: ModifierTier.GREAT, [Moves.FEATHER_DANCE]: ModifierTier.COMMON, [Moves.BLAZE_KICK]: ModifierTier.GREAT, @@ -67517,7 +68561,6 @@ export const tmPoolTiers: TmPoolTiers = { [Moves.ELECTROWEB]: ModifierTier.GREAT, [Moves.WILD_CHARGE]: ModifierTier.GREAT, [Moves.DRILL_RUN]: ModifierTier.GREAT, - [Moves.SACRED_SWORD]: ModifierTier.ULTRA, [Moves.RAZOR_SHELL]: ModifierTier.GREAT, [Moves.HEAT_CRASH]: ModifierTier.GREAT, [Moves.TAIL_SLAP]: ModifierTier.GREAT, diff --git a/src/data/move.ts b/src/data/move.ts index 9979b24cc24..c5b14304fb2 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -1420,6 +1420,11 @@ export class RecoilAttr extends MoveEffectAttr { return false; } + // Chloroblast and Struggle should not deal recoil damage if the move was not successful + if (this.useHp && [ MoveResult.FAIL, MoveResult.MISS ].includes(user.getLastXMoves(1)[0]?.result)) { + return false; + } + const damageValue = (!this.useHp ? user.turnData.damageDealt : user.getMaxHp()) * this.damageRatio; const minValue = user.turnData.damageDealt ? 1 : 0; const recoilDamage = Utils.toDmgValue(damageValue, minValue); @@ -2177,7 +2182,10 @@ export class StatusEffectAttr extends MoveEffectAttr { getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): number { const moveChance = this.getMoveChance(user, target, move, this.selfTarget, false); - return !(this.selfTarget ? user : target).status && (this.selfTarget ? user : target).canSetStatus(this.effect, true, false, user) ? Math.floor(moveChance * -0.1) : 0; + const score = (moveChance < 0) ? -10 : Math.floor(moveChance * -0.1); + const pokemon = this.selfTarget ? user : target; + + return !pokemon.status && pokemon.canSetStatus(this.effect, true, false, user) ? score : 0; } } @@ -2197,7 +2205,10 @@ export class MultiStatusEffectAttr extends StatusEffectAttr { getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): number { const moveChance = this.getMoveChance(user, target, move, this.selfTarget, false); - return !(this.selfTarget ? user : target).status && (this.selfTarget ? user : target).canSetStatus(this.effect, true, false, user) ? Math.floor(moveChance * -0.1) : 0; + const score = (moveChance < 0) ? -10 : Math.floor(moveChance * -0.1); + const pokemon = this.selfTarget ? user : target; + + return !pokemon.status && pokemon.canSetStatus(this.effect, true, false, user) ? score : 0; } } @@ -2228,7 +2239,7 @@ export class PsychoShiftEffectAttr extends MoveEffectAttr { } getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): number { - return !(this.selfTarget ? user : target).status && (this.selfTarget ? user : target).canSetStatus(user.status?.effect, true, false, user) ? Math.floor(move.chance * -0.1) : 0; + return !target.status && target.canSetStatus(user.status?.effect, true, false, user) ? -10 : 0; } } /** @@ -5858,6 +5869,9 @@ export class RemoveTypeAttr extends MoveEffectAttr { const userTypes = user.getTypes(true); const modifiedTypes = userTypes.filter(type => type !== this.removedType); + if (modifiedTypes.length === 0) { + modifiedTypes.push(Type.UNKNOWN); + } user.summonData.types = modifiedTypes; user.updateInfo(); @@ -5880,7 +5894,11 @@ export class CopyTypeAttr extends MoveEffectAttr { return false; } - user.summonData.types = target.getTypes(true); + const targetTypes = target.getTypes(true); + if (targetTypes.includes(Type.UNKNOWN) && targetTypes.indexOf(Type.UNKNOWN) > -1) { + targetTypes[targetTypes.indexOf(Type.UNKNOWN)] = Type.NORMAL; + } + user.summonData.types = targetTypes; user.updateInfo(); user.scene.queueMessage(i18next.t("moveTriggers:copyType", { pokemonName: getPokemonNameWithAffix(user), targetPokemonName: getPokemonNameWithAffix(target) })); @@ -5889,7 +5907,7 @@ export class CopyTypeAttr extends MoveEffectAttr { } getCondition(): MoveConditionFunc { - return (user, target, move) => target.getTypes()[0] !== Type.UNKNOWN; + return (user, target, move) => target.getTypes()[0] !== Type.UNKNOWN || target.summonData.addedType !== null; } } @@ -5947,11 +5965,7 @@ export class AddTypeAttr extends MoveEffectAttr { } apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - const types = target.getTypes().slice(0, 2).filter(t => t !== Type.UNKNOWN); // TODO: Figure out some way to actually check if another version of this effect is already applied - if (this.type !== Type.UNKNOWN) { - types.push(this.type); - } - target.summonData.types = types; + target.summonData.addedType = this.type; target.updateInfo(); user.scene.queueMessage(i18next.t("moveTriggers:addType", { typeName: i18next.t(`pokemonInfo:Type.${Type[this.type]}`), pokemonName: getPokemonNameWithAffix(target) })); @@ -8983,8 +8997,7 @@ export function initMoves() { .ignoresProtect() .ignoresVirtual(), new StatusMove(Moves.TRICK_OR_TREAT, Type.GHOST, 100, 20, -1, 0, 6) - .attr(AddTypeAttr, Type.GHOST) - .edgeCase(), // Weird interaction with Forest's Curse, reflect type, burn up + .attr(AddTypeAttr, Type.GHOST), new StatusMove(Moves.NOBLE_ROAR, Type.NORMAL, 100, 30, -1, 0, 6) .attr(StatStageChangeAttr, [ Stat.ATK, Stat.SPATK ], -1) .soundBased(), @@ -8996,8 +9009,7 @@ export function initMoves() { .target(MoveTarget.ALL_NEAR_OTHERS) .triageMove(), new StatusMove(Moves.FORESTS_CURSE, Type.GRASS, 100, 20, -1, 0, 6) - .attr(AddTypeAttr, Type.GRASS) - .edgeCase(), // Weird interaction with Trick or Treat, reflect type, burn up + .attr(AddTypeAttr, Type.GRASS), new AttackMove(Moves.PETAL_BLIZZARD, Type.GRASS, MoveCategory.PHYSICAL, 90, 100, 15, -1, 0, 6) .windMove() .makesContact(false) @@ -9491,7 +9503,7 @@ export function initMoves() { .edgeCase() // I assume it needs clanging scales and Kommo-O .ignoresVirtual(), /* End Unused */ - new AttackMove(Moves.ZIPPY_ZAP, Type.ELECTRIC, MoveCategory.PHYSICAL, 50, 100, 15, -1, 2, 7) //LGPE Implementation + new AttackMove(Moves.ZIPPY_ZAP, Type.ELECTRIC, MoveCategory.PHYSICAL, 50, 100, 15, -1, 2, 7) // LGPE Implementation .attr(CritOnlyAttr), new AttackMove(Moves.SPLISHY_SPLASH, Type.WATER, MoveCategory.SPECIAL, 90, 100, 15, 30, 0, 7) .attr(StatusEffectAttr, StatusEffect.PARALYSIS) @@ -9501,7 +9513,7 @@ export function initMoves() { new AttackMove(Moves.PIKA_PAPOW, Type.ELECTRIC, MoveCategory.SPECIAL, -1, -1, 20, -1, 0, 7) .attr(FriendshipPowerAttr), new AttackMove(Moves.BOUNCY_BUBBLE, Type.WATER, MoveCategory.SPECIAL, 60, 100, 20, -1, 0, 7) - .attr(HitHealAttr, 1.0) + .attr(HitHealAttr) // Custom .triageMove() .target(MoveTarget.ALL_NEAR_ENEMIES), new AttackMove(Moves.BUZZY_BUZZ, Type.ELECTRIC, MoveCategory.SPECIAL, 60, 100, 20, 100, 0, 7) @@ -10005,6 +10017,7 @@ export function initMoves() { .attr(ConfuseAttr) .recklessMove(), new AttackMove(Moves.LAST_RESPECTS, Type.GHOST, MoveCategory.PHYSICAL, 50, 100, 10, -1, 0, 9) + .partial() // Counter resets every wave instead of on arena reset .attr(MovePowerMultiplierAttr, (user, target, move) => 1 + Math.min(user.isPlayer() ? user.scene.currentBattle.playerFaints : user.scene.currentBattle.enemyFaints, 100)) .makesContact(false), new AttackMove(Moves.LUMINA_CRASH, Type.PSYCHIC, MoveCategory.SPECIAL, 80, 100, 10, 100, 0, 9) diff --git a/src/enums/switch-type.ts b/src/enums/switch-type.ts index b25ba6ad119..752c0902636 100644 --- a/src/enums/switch-type.ts +++ b/src/enums/switch-type.ts @@ -3,6 +3,8 @@ * or {@linkcode SwitchSummonPhase} will carry out. */ export enum SwitchType { + /** Switchout specifically for when combat starts and the player is prompted if they will switch Pokemon */ + INITIAL_SWITCH, /** Basic switchout where the Pokemon to switch in is selected */ SWITCH, /** Transfers stat stages and other effects from the returning Pokemon to the switched in Pokemon */ diff --git a/src/field/arena.ts b/src/field/arena.ts index 7bfdf9a0000..09faee49d56 100644 --- a/src/field/arena.ts +++ b/src/field/arena.ts @@ -10,7 +10,14 @@ import Move from "#app/data/move"; import { ArenaTag, ArenaTagSide, ArenaTrapTag, getArenaTag } from "#app/data/arena-tag"; import { BattlerIndex } from "#app/battle"; import { Terrain, TerrainType } from "#app/data/terrain"; -import { applyPostTerrainChangeAbAttrs, applyPostWeatherChangeAbAttrs, PostTerrainChangeAbAttr, PostWeatherChangeAbAttr } from "#app/data/ability"; +import { + applyAbAttrs, + applyPostTerrainChangeAbAttrs, + applyPostWeatherChangeAbAttrs, + PostTerrainChangeAbAttr, + PostWeatherChangeAbAttr, + TerrainEventTypeChangeAbAttr +} from "#app/data/ability"; import Pokemon from "#app/field/pokemon"; import Overrides from "#app/overrides"; import { TagAddedEvent, TagRemovedEvent, TerrainChangedEvent, WeatherChangedEvent } from "#app/events/arena"; @@ -387,6 +394,7 @@ export class Arena { this.scene.getField(true).filter(p => p.isOnField()).map(pokemon => { pokemon.findAndRemoveTags(t => "terrainTypes" in t && !(t.terrainTypes as TerrainType[]).find(t => t === terrain)); applyPostTerrainChangeAbAttrs(PostTerrainChangeAbAttr, pokemon, terrain); + applyAbAttrs(TerrainEventTypeChangeAbAttr, pokemon, null, false); }); return true; diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 278a28937ef..321532fffa7 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -1258,6 +1258,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } } + // the type added to Pokemon from moves like Forest's Curse or Trick Or Treat + if (!ignoreOverride && this.summonData && this.summonData.addedType && !types.includes(this.summonData.addedType)) { + types.push(this.summonData.addedType); + } + // If both types are the same (can happen in weird custom typing scenarios), reduce to single type if (types.length > 1 && types[0] === types[1]) { types.splice(0, 1); @@ -5100,6 +5105,7 @@ export class PokemonSummonData { public moveset: (PokemonMove | null)[]; // If not initialized this value will not be populated from save data. public types: Type[] = []; + public addedType: Type | null = null; } export class PokemonBattleData { @@ -5137,6 +5143,8 @@ export class PokemonTurnData { public statStagesDecreased: boolean = false; public moveEffectiveness: TypeDamageMultiplier | null = null; public combiningPledge?: Moves; + public switchedInThisTurn: boolean = false; + public failedRunAway: boolean = false; } export enum AiType { diff --git a/src/phases/attempt-run-phase.ts b/src/phases/attempt-run-phase.ts index e0dd7fa72fd..b4768dc9a26 100644 --- a/src/phases/attempt-run-phase.ts +++ b/src/phases/attempt-run-phase.ts @@ -10,6 +10,10 @@ import { NewBattlePhase } from "./new-battle-phase"; import { PokemonPhase } from "./pokemon-phase"; export class AttemptRunPhase extends PokemonPhase { + + /** For testing purposes: this is to force the pokemon to fail and escape */ + public forceFailEscape = false; + constructor(scene: BattleScene, fieldIndex: number) { super(scene, fieldIndex); } @@ -28,7 +32,7 @@ export class AttemptRunPhase extends PokemonPhase { applyAbAttrs(RunSuccessAbAttr, playerPokemon, null, false, escapeChance); - if (playerPokemon.randSeedInt(100) < escapeChance.value) { + if (playerPokemon.randSeedInt(100) < escapeChance.value && !this.forceFailEscape) { this.scene.playSound("se/flee"); this.scene.queueMessage(i18next.t("battle:runAwaySuccess"), null, true, 500); @@ -51,6 +55,7 @@ export class AttemptRunPhase extends PokemonPhase { this.scene.pushPhase(new BattleEndPhase(this.scene)); this.scene.pushPhase(new NewBattlePhase(this.scene)); } else { + playerPokemon.turnData.failedRunAway = true; this.scene.queueMessage(i18next.t("battle:runAwayCannotEscape"), null, true, 500); } diff --git a/src/phases/check-switch-phase.ts b/src/phases/check-switch-phase.ts index 8849d304435..5e459d0e6b5 100644 --- a/src/phases/check-switch-phase.ts +++ b/src/phases/check-switch-phase.ts @@ -51,7 +51,7 @@ export class CheckSwitchPhase extends BattlePhase { this.scene.ui.setMode(Mode.CONFIRM, () => { this.scene.ui.setMode(Mode.MESSAGE); this.scene.tryRemovePhase(p => p instanceof PostSummonPhase && p.player && p.fieldIndex === this.fieldIndex); - this.scene.unshiftPhase(new SwitchPhase(this.scene, SwitchType.SWITCH, this.fieldIndex, false, true)); + this.scene.unshiftPhase(new SwitchPhase(this.scene, SwitchType.INITIAL_SWITCH, this.fieldIndex, false, true)); this.end(); }, () => { this.scene.ui.setMode(Mode.MESSAGE); diff --git a/src/phases/faint-phase.ts b/src/phases/faint-phase.ts index eee1fd52938..8eb84beded5 100644 --- a/src/phases/faint-phase.ts +++ b/src/phases/faint-phase.ts @@ -65,6 +65,15 @@ export class FaintPhase extends PokemonPhase { } } + /** In case the current pokemon was just switched in, make sure it is counted as participating in the combat */ + this.scene.getPlayerField().forEach((pokemon, i) => { + if (pokemon?.isActive(true)) { + if (pokemon.isPlayer()) { + this.scene.currentBattle.addParticipant(pokemon as PlayerPokemon); + } + } + }); + if (!this.tryOverrideForBattleSpec()) { this.doFaint(); } diff --git a/src/phases/switch-summon-phase.ts b/src/phases/switch-summon-phase.ts index 37652b3cfa4..c7e7bbe011e 100644 --- a/src/phases/switch-summon-phase.ts +++ b/src/phases/switch-summon-phase.ts @@ -64,10 +64,8 @@ export class SwitchSummonPhase extends SummonPhase { } const pokemon = this.getPokemon(); - (this.player ? this.scene.getEnemyField() : this.scene.getPlayerField()).forEach(enemyPokemon => enemyPokemon.removeTagsBySourceId(pokemon.id)); - - if (this.switchType === SwitchType.SWITCH) { + if (this.switchType === SwitchType.SWITCH || this.switchType === SwitchType.INITIAL_SWITCH) { const substitute = pokemon.getTag(SubstituteTag); if (substitute) { this.scene.tweens.add({ @@ -186,6 +184,11 @@ export class SwitchSummonPhase extends SummonPhase { } } + if (this.switchType !== SwitchType.INITIAL_SWITCH) { + pokemon.resetTurnData(); + pokemon.turnData.switchedInThisTurn = true; + } + this.lastPokemon?.resetSummonData(); this.scene.triggerPokemonFormChange(pokemon, SpeciesFormChangeActiveTrigger, true); diff --git a/src/test/abilities/mimicry.test.ts b/src/test/abilities/mimicry.test.ts new file mode 100644 index 00000000000..4e62ddc0b76 --- /dev/null +++ b/src/test/abilities/mimicry.test.ts @@ -0,0 +1,91 @@ +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import { Type } from "#app/data/type"; +import GameManager from "#test/utils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; + +describe("Abilities - Mimicry", () => { + 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 + .moveset([ Moves.SPLASH ]) + .ability(Abilities.MIMICRY) + .battleType("single") + .disableCrits() + .enemySpecies(Species.MAGIKARP) + .enemyMoveset(Moves.SPLASH); + }); + + it("Mimicry activates after the Pokémon with Mimicry is switched in while terrain is present, or whenever there is a change in terrain", async () => { + game.override.enemyAbility(Abilities.MISTY_SURGE); + await game.classicMode.startBattle([ Species.FEEBAS, Species.ABRA ]); + + const [ playerPokemon1, playerPokemon2 ] = game.scene.getParty(); + game.move.select(Moves.SPLASH); + await game.toNextTurn(); + expect(playerPokemon1.getTypes().includes(Type.FAIRY)).toBe(true); + + game.doSwitchPokemon(1); + await game.toNextTurn(); + + expect(playerPokemon2.getTypes().includes(Type.FAIRY)).toBe(true); + }); + + it("Pokemon should revert back to its original, root type once terrain ends", async () => { + game.override + .moveset([ Moves.SPLASH, Moves.TRANSFORM ]) + .enemyAbility(Abilities.MIMICRY) + .enemyMoveset([ Moves.SPLASH, Moves.PSYCHIC_TERRAIN ]); + await game.classicMode.startBattle([ Species.REGIELEKI ]); + + const playerPokemon = game.scene.getPlayerPokemon(); + game.move.select(Moves.TRANSFORM); + await game.forceEnemyMove(Moves.PSYCHIC_TERRAIN); + await game.toNextTurn(); + expect(playerPokemon?.getTypes().includes(Type.PSYCHIC)).toBe(true); + + if (game.scene.arena.terrain) { + game.scene.arena.terrain.turnsLeft = 1; + } + + game.move.select(Moves.SPLASH); + await game.forceEnemyMove(Moves.SPLASH); + await game.toNextTurn(); + expect(playerPokemon?.getTypes().includes(Type.ELECTRIC)).toBe(true); + }); + + it("If the Pokemon is under the effect of a type-adding move and an equivalent terrain activates, the move's effect disappears", async () => { + game.override + .enemyMoveset([ Moves.FORESTS_CURSE, Moves.GRASSY_TERRAIN ]); + await game.classicMode.startBattle([ Species.FEEBAS ]); + + const playerPokemon = game.scene.getPlayerPokemon(); + game.move.select(Moves.SPLASH); + await game.forceEnemyMove(Moves.FORESTS_CURSE); + await game.toNextTurn(); + + expect(playerPokemon?.summonData.addedType).toBe(Type.GRASS); + + game.move.select(Moves.SPLASH); + await game.forceEnemyMove(Moves.GRASSY_TERRAIN); + await game.phaseInterceptor.to("TurnEndPhase"); + + expect(playerPokemon?.summonData.addedType).toBeNull(); + expect(playerPokemon?.getTypes().includes(Type.GRASS)).toBe(true); + }); +}); diff --git a/src/test/abilities/speed_boost.test.ts b/src/test/abilities/speed_boost.test.ts new file mode 100644 index 00000000000..dd2e83aaa88 --- /dev/null +++ b/src/test/abilities/speed_boost.test.ts @@ -0,0 +1,125 @@ +import { Stat } from "#enums/stat"; +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import { CommandPhase } from "#app/phases/command-phase"; +import { Command } from "#app/ui/command-ui-handler"; +import { AttemptRunPhase } from "#app/phases/attempt-run-phase"; + +describe("Abilities - Speed Boost", () => { + 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.DRAGAPULT) + .ability(Abilities.SPEED_BOOST) + .enemyMoveset(Moves.SPLASH) + .moveset([ Moves.SPLASH, Moves.U_TURN ]); + }); + + it("should increase speed by 1 stage at end of turn", + async () => { + await game.classicMode.startBattle(); + + const playerPokemon = game.scene.getPlayerPokemon()!; + game.move.select(Moves.SPLASH); + await game.toNextTurn(); + + expect(playerPokemon.getStatStage(Stat.SPD)).toBe(1); + }); + + it("should not trigger this turn if pokemon was switched into combat via attack, but the turn after", + async () => { + await game.classicMode.startBattle([ + Species.SHUCKLE, + Species.NINJASK + ]); + + game.move.select(Moves.U_TURN); + game.doSelectPartyPokemon(1); + await game.toNextTurn(); + const playerPokemon = game.scene.getPlayerPokemon()!; + expect(playerPokemon.getStatStage(Stat.SPD)).toBe(0); + + game.move.select(Moves.SPLASH); + await game.toNextTurn(); + expect(playerPokemon.getStatStage(Stat.SPD)).toBe(1); + }); + + it("checking back to back swtiches", + async () => { + await game.classicMode.startBattle([ + Species.SHUCKLE, + Species.NINJASK + ]); + + game.move.select(Moves.U_TURN); + game.doSelectPartyPokemon(1); + await game.toNextTurn(); + let playerPokemon = game.scene.getPlayerPokemon()!; + expect(playerPokemon.getStatStage(Stat.SPD)).toBe(0); + + game.move.select(Moves.U_TURN); + game.doSelectPartyPokemon(1); + await game.toNextTurn(); + playerPokemon = game.scene.getPlayerPokemon()!; + expect(playerPokemon.getStatStage(Stat.SPD)).toBe(0); + + game.move.select(Moves.SPLASH); + await game.toNextTurn(); + expect(playerPokemon.getStatStage(Stat.SPD)).toBe(1); + }); + + it("should not trigger this turn if pokemon was switched into combat via normal switch, but the turn after", + async () => { + await game.classicMode.startBattle([ + Species.SHUCKLE, + Species.NINJASK + ]); + + game.doSwitchPokemon(1); + await game.toNextTurn(); + const playerPokemon = game.scene.getPlayerPokemon()!; + expect(playerPokemon.getStatStage(Stat.SPD)).toBe(0); + + game.move.select(Moves.SPLASH); + await game.toNextTurn(); + expect(playerPokemon.getStatStage(Stat.SPD)).toBe(1); + }); + + it("should not trigger if pokemon fails to escape", + async () => { + await game.classicMode.startBattle([ Species.SHUCKLE ]); + + const commandPhase = game.scene.getCurrentPhase() as CommandPhase; + commandPhase.handleCommand(Command.RUN, 0); + const runPhase = game.scene.getCurrentPhase() as AttemptRunPhase; + runPhase.forceFailEscape = true; + await game.phaseInterceptor.to(AttemptRunPhase); + await game.toNextTurn(); + + const playerPokemon = game.scene.getPlayerPokemon()!; + expect(playerPokemon.getStatStage(Stat.SPD)).toBe(0); + + game.move.select(Moves.SPLASH); + await game.toNextTurn(); + expect(playerPokemon.getStatStage(Stat.SPD)).toBe(1); + }); +}); diff --git a/src/test/moves/chloroblast.test.ts b/src/test/moves/chloroblast.test.ts new file mode 100644 index 00000000000..5e55bf46958 --- /dev/null +++ b/src/test/moves/chloroblast.test.ts @@ -0,0 +1,42 @@ +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; + +describe("Moves - Chloroblast", () => { + 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 + .moveset([ Moves.CHLOROBLAST ]) + .ability(Abilities.BALL_FETCH) + .battleType("single") + .disableCrits() + .enemySpecies(Species.MAGIKARP) + .enemyAbility(Abilities.BALL_FETCH) + .enemyMoveset(Moves.PROTECT); + }); + + it("should not deal recoil damage if the opponent uses protect", async () => { + await game.classicMode.startBattle([ Species.FEEBAS ]); + + game.move.select(Moves.CHLOROBLAST); + await game.phaseInterceptor.to("BerryPhase"); + + expect(game.scene.getPlayerPokemon()!.isFullHp()).toBe(true); + }); +}); diff --git a/src/test/moves/forests_curse.test.ts b/src/test/moves/forests_curse.test.ts new file mode 100644 index 00000000000..c49bdab5255 --- /dev/null +++ b/src/test/moves/forests_curse.test.ts @@ -0,0 +1,47 @@ +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import { Type } from "#app/data/type"; +import GameManager from "#test/utils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; + +describe("Moves - Forest's Curse", () => { + 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 + .moveset([ Moves.FORESTS_CURSE, Moves.TRICK_OR_TREAT ]) + .ability(Abilities.BALL_FETCH) + .battleType("single") + .disableCrits() + .enemySpecies(Species.MAGIKARP) + .enemyAbility(Abilities.BALL_FETCH) + .enemyMoveset(Moves.SPLASH); + }); + + it("will replace the added type from Trick Or Treat", async () => { + await game.classicMode.startBattle([ Species.FEEBAS ]); + + const enemyPokemon = game.scene.getEnemyPokemon(); + game.move.select(Moves.TRICK_OR_TREAT); + await game.phaseInterceptor.to("TurnEndPhase"); + expect(enemyPokemon!.summonData.addedType).toBe(Type.GHOST); + + game.move.select(Moves.FORESTS_CURSE); + await game.phaseInterceptor.to("TurnEndPhase"); + expect(enemyPokemon?.summonData.addedType).toBe(Type.GRASS); + }); +}); diff --git a/src/test/moves/reflect_type.test.ts b/src/test/moves/reflect_type.test.ts new file mode 100644 index 00000000000..0e47d4b00fc --- /dev/null +++ b/src/test/moves/reflect_type.test.ts @@ -0,0 +1,59 @@ +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import { Type } from "#app/data/type"; +import GameManager from "#test/utils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; + +describe("Moves - Reflect Type", () => { + 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 + .ability(Abilities.BALL_FETCH) + .battleType("single") + .disableCrits() + .enemyAbility(Abilities.BALL_FETCH); + }); + + it("will make the user Normal/Grass if targetting a typeless Pokemon affected by Forest's Curse", async () => { + game.override + .moveset([ Moves.FORESTS_CURSE, Moves.REFLECT_TYPE ]) + .startingLevel(60) + .enemySpecies(Species.CHARMANDER) + .enemyMoveset([ Moves.BURN_UP, Moves.SPLASH ]); + await game.classicMode.startBattle([ Species.FEEBAS ]); + + const playerPokemon = game.scene.getPlayerPokemon(); + const enemyPokemon = game.scene.getEnemyPokemon(); + + game.move.select(Moves.SPLASH); + await game.forceEnemyMove(Moves.BURN_UP); + await game.toNextTurn(); + + game.move.select(Moves.FORESTS_CURSE); + await game.forceEnemyMove(Moves.SPLASH); + await game.toNextTurn(); + expect(enemyPokemon?.getTypes().includes(Type.UNKNOWN)).toBe(true); + expect(enemyPokemon?.getTypes().includes(Type.GRASS)).toBe(true); + + game.move.select(Moves.REFLECT_TYPE); + await game.forceEnemyMove(Moves.SPLASH); + await game.phaseInterceptor.to("TurnEndPhase"); + expect(playerPokemon?.getTypes()[0]).toBe(Type.NORMAL); + expect(playerPokemon?.getTypes().includes(Type.GRASS)).toBe(true); + }); +}); diff --git a/src/test/moves/trick_or_treat.test.ts b/src/test/moves/trick_or_treat.test.ts new file mode 100644 index 00000000000..7ecd00ed076 --- /dev/null +++ b/src/test/moves/trick_or_treat.test.ts @@ -0,0 +1,47 @@ +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import { Type } from "#app/data/type"; +import GameManager from "#test/utils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; + +describe("Moves - Trick Or Treat", () => { + 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 + .moveset([ Moves.FORESTS_CURSE, Moves.TRICK_OR_TREAT ]) + .ability(Abilities.BALL_FETCH) + .battleType("single") + .disableCrits() + .enemySpecies(Species.MAGIKARP) + .enemyAbility(Abilities.BALL_FETCH) + .enemyMoveset(Moves.SPLASH); + }); + + it("will replace added type from Forest's Curse", async () => { + await game.classicMode.startBattle([ Species.FEEBAS ]); + + const enemyPokemon = game.scene.getEnemyPokemon(); + game.move.select(Moves.FORESTS_CURSE); + await game.phaseInterceptor.to("TurnEndPhase"); + expect(enemyPokemon!.summonData.addedType).toBe(Type.GRASS); + + game.move.select(Moves.TRICK_OR_TREAT); + await game.phaseInterceptor.to("TurnEndPhase"); + expect(enemyPokemon?.summonData.addedType).toBe(Type.GHOST); + }); +}); diff --git a/src/ui/menu-ui-handler.ts b/src/ui/menu-ui-handler.ts index 301d54daa3a..fea0a70af91 100644 --- a/src/ui/menu-ui-handler.ts +++ b/src/ui/menu-ui-handler.ts @@ -32,7 +32,7 @@ let wikiUrl = "https://wiki.pokerogue.net/start"; const discordUrl = "https://discord.gg/uWpTfdKG49"; const githubUrl = "https://github.com/pagefaultgames/pokerogue"; const redditUrl = "https://www.reddit.com/r/pokerogue"; -const donateUrl = "https://github.com/sponsors/patapancakes"; +const donateUrl = "https://github.com/sponsors/pagefaultgames"; export default class MenuUiHandler extends MessageUiHandler { private readonly textPadding = 8; diff --git a/src/ui/pokemon-info-container.ts b/src/ui/pokemon-info-container.ts index 5c3a22639dd..6cc70bd598f 100644 --- a/src/ui/pokemon-info-container.ts +++ b/src/ui/pokemon-info-container.ts @@ -237,14 +237,20 @@ export default class PokemonInfoContainer extends Phaser.GameObjects.Container { const formKey = (pokemon.species?.forms?.[pokemon.formIndex!]?.formKey); const formText = Utils.capitalizeString(formKey, "-", false, false) || ""; - const speciesName = Utils.capitalizeString(Species[pokemon.species.getRootSpeciesId()], "_", true, false); + const speciesName = Utils.capitalizeString(Species[pokemon.species.speciesId], "_", true, false); let formName = ""; if (pokemon.species.speciesId === Species.ARCEUS) { formName = i18next.t(`pokemonInfo:Type.${formText?.toUpperCase()}`); } else { const i18key = `pokemonForm:${speciesName}${formText}`; - formName = i18next.exists(i18key) ? i18next.t(i18key) : formText; + if (i18next.exists(i18key)) { + formName = i18next.t(i18key); + } else { + const rootSpeciesName = Utils.capitalizeString(Species[pokemon.species.getRootSpeciesId()], "_", true, false); + const i18RootKey = `pokemonForm:${rootSpeciesName}${formText}`; + formName = i18next.exists(i18RootKey) ? i18next.t(i18RootKey) : formText; + } } if (formName) {