diff --git a/src/data/abilities/ability.ts b/src/data/abilities/ability.ts index 3124f782ff5..70195d6a152 100644 --- a/src/data/abilities/ability.ts +++ b/src/data/abilities/ability.ts @@ -24,11 +24,11 @@ import { allMoves } from "../data-lists"; import { ArenaTagSide } from "#enums/arena-tag-side"; import { BerryModifier, HitHealModifier, PokemonHeldItemModifier } from "#app/modifier/modifier"; import { TerrainType } from "#app/data/terrain"; +import { pokemonFormChanges } from "../pokemon-forms"; import { - SpeciesFormChangeRevertWeatherFormTrigger, SpeciesFormChangeWeatherTrigger, + SpeciesFormChangeAbilityTrigger, } from "../pokemon-forms/form-change-triggers"; -import { SpeciesFormChangeAbilityTrigger } from "../pokemon-forms/form-change-triggers"; import i18next from "i18next"; import { Command } from "#enums/command"; import { BerryModifierType } from "#app/modifier/modifier-type"; @@ -3971,27 +3971,32 @@ export class PostSummonFormChangeByWeatherAbAttr extends PostSummonAbAttr { this.ability = ability; } + /** + * Determine if the pokemon has a forme change that is triggered by the weather + * + * @param pokemon - The pokemon with the forme change ability + * @param _passive - unused + * @param _simulated - unused + * @param _args - unused + */ override canApplyPostSummon(pokemon: Pokemon, _passive: boolean, _simulated: boolean, _args: any[]): boolean { - const isCastformWithForecast = - pokemon.species.speciesId === SpeciesId.CASTFORM && this.ability === AbilityId.FORECAST; - const isCherrimWithFlowerGift = - pokemon.species.speciesId === SpeciesId.CHERRIM && this.ability === AbilityId.FLOWER_GIFT; - return isCastformWithForecast || isCherrimWithFlowerGift; + return !!pokemonFormChanges[pokemon.species.speciesId]?.some( + fc => fc.findTrigger(SpeciesFormChangeWeatherTrigger) && fc.canChange(pokemon), + ); } /** - * Calls the {@linkcode BattleScene.triggerPokemonFormChange | triggerPokemonFormChange} for both - * {@linkcode SpeciesFormChange.SpeciesFormChangeWeatherTrigger | SpeciesFormChangeWeatherTrigger} and - * {@linkcode SpeciesFormChange.SpeciesFormChangeWeatherTrigger | SpeciesFormChangeRevertWeatherFormTrigger} if it - * is the specific Pokemon and ability - * @param {Pokemon} pokemon the Pokemon with this ability - * @param _passive n/a - * @param _args n/a + * Trigger the pokemon's forme change by invoking + * {@linkcode BattleScene.triggerPokemonFormChange | triggerPokemonFormChange} + * + * @param pokemon - The Pokemon with this ability + * @param _passive - unused + * @param simulated - unused + * @param _args - unused */ override applyPostSummon(pokemon: Pokemon, _passive: boolean, simulated: boolean, _args: any[]): void { if (!simulated) { globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeWeatherTrigger); - globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeRevertWeatherFormTrigger); } } } @@ -5301,10 +5306,11 @@ export class PostWeatherChangeFormChangeAbAttr extends PostWeatherChangeAbAttr { /** * Calls {@linkcode Arena.triggerWeatherBasedFormChangesToNormal | triggerWeatherBasedFormChangesToNormal} when the * weather changed to form-reverting weather, otherwise calls {@linkcode Arena.triggerWeatherBasedFormChanges | triggerWeatherBasedFormChanges} - * @param {Pokemon} _pokemon the Pokemon with this ability - * @param _passive n/a - * @param _weather n/a - * @param _args n/a + * @param _pokemon - The Pokemon with this ability + * @param _passive - unused + * @param simulated - unused + * @param _weather - unused + * @param _args - unused */ override applyPostWeatherChange( _pokemon: Pokemon, diff --git a/test/abilities/forecast.test.ts b/test/abilities/forecast.test.ts index 8d3a679c917..9111766ebdf 100644 --- a/test/abilities/forecast.test.ts +++ b/test/abilities/forecast.test.ts @@ -21,26 +21,10 @@ describe("Abilities - Forecast", () => { const RAINY_FORM = 2; const SNOWY_FORM = 3; - /** - * Tests form changes based on weather changes - * @param {GameManager} game The game manager instance - * @param {WeatherType} weather The active weather to set - * @param form The expected form based on the active weather - * @param initialForm The initial form pre form change - */ - const testWeatherFormChange = async (game: GameManager, weather: WeatherType, form: number, initialForm?: number) => { - game.override.weather(weather).starterForms({ [SpeciesId.CASTFORM]: initialForm }); - await game.classicMode.startBattle([SpeciesId.CASTFORM]); - - game.move.select(MoveId.SPLASH); - - expect(game.scene.getPlayerPokemon()?.formIndex).toBe(form); - }; - /** * Tests reverting to normal form when Cloud Nine/Air Lock is active on the field - * @param {GameManager} game The game manager instance - * @param {AbilityId} ability The ability that is active on the field + * @param game - The game manager instance + * @param ability - The ability that is active on the field */ const testRevertFormAgainstAbility = async (game: GameManager, ability: AbilityId) => { game.override.starterForms({ [SpeciesId.CASTFORM]: SUNNY_FORM }).enemyAbility(ability); @@ -191,10 +175,6 @@ describe("Abilities - Forecast", () => { 30 * 1000, ); - it("reverts to Normal Form during Clear weather", async () => { - await testWeatherFormChange(game, WeatherType.NONE, NORMAL_FORM, SUNNY_FORM); - }); - it("reverts to Normal Form if a Pokémon on the field has Air Lock", async () => { await testRevertFormAgainstAbility(game, AbilityId.AIR_LOCK); }); @@ -277,4 +257,20 @@ describe("Abilities - Forecast", () => { expect(castform.formIndex).toBe(NORMAL_FORM); }); + + // NOTE: The following pairs of tests are intentionally testing the same scenario, switching the player and enemy pokemon + // as this is a regression test where the order of player and enemy mattered. + it("should trigger player's form change when summoned at the same time as an enemy with a weather changing ability", async () => { + game.override.enemyAbility(AbilityId.DROUGHT); + await game.classicMode.startBattle([SpeciesId.CASTFORM, SpeciesId.MAGIKARP]); + const castform = game.scene.getPlayerPokemon()!; + expect(castform.formIndex).toBe(SUNNY_FORM); + }); + + it("should trigger enemy's form change when summoned at the same time as a player with a weather changing ability", async () => { + game.override.ability(AbilityId.DROUGHT).enemySpecies(SpeciesId.CASTFORM).enemyAbility(AbilityId.FORECAST); + await game.classicMode.startBattle([SpeciesId.MAGIKARP]); + const castform = game.scene.getEnemyPokemon()!; + expect(castform.formIndex).toBe(SUNNY_FORM); + }); });