From 8e6e702525e2d01490ebe615995e743c451d3264 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Bastos=20Dias?= Date: Sat, 22 Nov 2025 16:01:52 +0000 Subject: [PATCH 1/5] Fix Air Lock, Cloud Nine, Flower Gift and Forecast --- data/abilities.ts | 23 ++++++++++++--- data/mods/gen4/abilities.ts | 41 +++++++++++++++++++++++---- test/sim/abilities/neutralizinggas.js | 11 +++++++ 3 files changed, 65 insertions(+), 10 deletions(-) diff --git a/data/abilities.ts b/data/abilities.ts index cbc7bf08b4..64bc1f3d93 100644 --- a/data/abilities.ts +++ b/data/abilities.ts @@ -1328,8 +1328,8 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = { this.singleEvent('WeatherChange', this.effect, this.effectState, pokemon); }, onWeatherChange(pokemon) { - if (!pokemon.isActive || pokemon.baseSpecies.baseSpecies !== 'Cherrim' || pokemon.transformed) return; - if (!pokemon.hp) return; + if (!pokemon.isActive || !pokemon.hp || pokemon.baseSpecies.baseSpecies !== 'Cherrim' || + pokemon.transformed) return; if (['sunnyday', 'desolateland'].includes(pokemon.effectiveWeather())) { if (pokemon.species.id !== 'cherrimsunshine') { pokemon.formeChange('Cherrim-Sunshine', this.effect, false, '0', '[msg]'); @@ -1340,6 +1340,13 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = { } } }, + onEnd(pokemon) { + if (!pokemon.isActive || !pokemon.hp || pokemon.baseSpecies.baseSpecies !== 'Cherrim' || + pokemon.transformed || pokemon.beingCalledBack) return; + if (pokemon.species.id !== 'cherrim') { + pokemon.formeChange('Cherrim', this.effect, false, '0', '[msg]'); + } + }, onAllyModifyAtkPriority: 3, onAllyModifyAtk(atk, pokemon) { if (this.effectState.target.baseSpecies.baseSpecies !== 'Cherrim') return; @@ -1416,7 +1423,8 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = { this.singleEvent('WeatherChange', this.effect, this.effectState, pokemon); }, onWeatherChange(pokemon) { - if (pokemon.baseSpecies.baseSpecies !== 'Castform' || pokemon.transformed) return; + if (!pokemon.isActive || !pokemon.hp || pokemon.baseSpecies.baseSpecies !== 'Castform' || + pokemon.transformed) return; let forme = null; switch (pokemon.effectiveWeather()) { case 'sunnyday': @@ -1435,10 +1443,17 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = { if (pokemon.species.id !== 'castform') forme = 'Castform'; break; } - if (pokemon.isActive && forme) { + if (forme) { pokemon.formeChange(forme, this.effect, false, '0', '[msg]'); } }, + onEnd(pokemon) { + if (!pokemon.isActive || !pokemon.hp || pokemon.baseSpecies.baseSpecies !== 'Castform' || + pokemon.transformed || pokemon.beingCalledBack) return; + if (pokemon.species.id !== 'castform') { + pokemon.formeChange('Castform', this.effect, false, '0', '[msg]'); + } + }, flags: { failroleplay: 1, noreceiver: 1, noentrain: 1, notrace: 1 }, name: "Forecast", rating: 2, diff --git a/data/mods/gen4/abilities.ts b/data/mods/gen4/abilities.ts index e1af9904bf..4ab232ea36 100644 --- a/data/mods/gen4/abilities.ts +++ b/data/mods/gen4/abilities.ts @@ -2,9 +2,6 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa airlock: { inherit: true, onSwitchIn() {}, - onStart(pokemon) { - pokemon.abilityState.ending = false; - }, }, angerpoint: { inherit: true, @@ -37,9 +34,6 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa cloudnine: { inherit: true, onSwitchIn() {}, - onStart(pokemon) { - pokemon.abilityState.ending = false; - }, }, colorchange: { inherit: true, @@ -145,6 +139,19 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa }, flowergift: { inherit: true, + onWeatherChange(pokemon) { + if (!pokemon.isActive || !pokemon.hp || pokemon.species.baseSpecies !== 'Cherrim') return; + if (pokemon.effectiveWeather() !== 'sunnyday') { + if (pokemon.species.id !== 'cherrimsunshine') { + pokemon.formeChange('Cherrim-Sunshine', this.effect, false, '0', '[msg]'); + } + } else { + if (pokemon.species.id === 'cherrimsunshine') { + pokemon.formeChange('Cherrim', this.effect, false, '0', '[msg]'); + } + } + }, + onEnd() {}, onAllyModifyAtk(atk) { if (this.field.isWeather('sunnyday')) { return this.chainModify(1.5); @@ -159,6 +166,28 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa }, forecast: { inherit: true, + onWeatherChange(pokemon) { + if (!pokemon.isActive || !pokemon.hp || pokemon.species.baseSpecies !== 'Castform') return; + let forme = null; + switch (pokemon.effectiveWeather()) { + case 'sunnyday': + if (pokemon.species.id !== 'castformsunny') forme = 'Castform-Sunny'; + break; + case 'raindance': + if (pokemon.species.id !== 'castformrainy') forme = 'Castform-Rainy'; + break; + case 'hail': + if (pokemon.species.id !== 'castformsnowy') forme = 'Castform-Snowy'; + break; + default: + if (pokemon.species.id !== 'castform') forme = 'Castform'; + break; + } + if (forme) { + pokemon.formeChange(forme, this.effect, false, '0', '[msg]'); + } + }, + onEnd() {}, flags: { notrace: 1 }, }, forewarn: { diff --git a/test/sim/abilities/neutralizinggas.js b/test/sim/abilities/neutralizinggas.js index 9aff3055a4..3cc0f81861 100644 --- a/test/sim/abilities/neutralizinggas.js +++ b/test/sim/abilities/neutralizinggas.js @@ -162,6 +162,17 @@ describe('Neutralizing Gas', () => { assert(battle.log.some(line => line.includes('|-end|p1a: Zoroark|Illusion'))); }); + it(`should cause Cherrim-Sunshine to instantly revert form`, () => { + battle = common.createBattle([[ + { species: "Cherrim", ability: 'flowergift', moves: ['sleeptalk'] }, + ], [ + { species: "Torkoal", ability: 'drought', moves: ['sleeptalk'] }, + { species: "Weezing", ability: 'neutralizinggas', moves: ['sleeptalk'] }, + ]]); + battle.makeChoices('auto', 'switch 2'); + assert.species(battle.p1.active[0], 'Cherrim'); + }); + it(`should cause Slow Start to instantly wear off/restart when Neutralizing Gas leaves/enters the field`, () => { battle = common.createBattle([[ { species: "Regigigas", ability: 'slowstart', moves: ['sleeptalk'] }, From 4e2570348fe6ae8ba6cdea00777280a2a6df48f3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Bastos=20Dias?= Date: Sat, 22 Nov 2025 16:14:30 +0000 Subject: [PATCH 2/5] NGas should end their effects --- data/abilities.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/abilities.ts b/data/abilities.ts index 64bc1f3d93..b76fa2f4e9 100644 --- a/data/abilities.ts +++ b/data/abilities.ts @@ -2857,7 +2857,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = { onSwitchIn(pokemon) { this.add('-ability', pokemon, 'Neutralizing Gas'); pokemon.abilityState.ending = false; - const strongWeathers = ['desolateland', 'primordialsea', 'deltastream']; + const strongWeathers = ['desolateland', 'primordialsea', 'deltastream', 'flowergift', 'forecast']; for (const target of this.getAllActive()) { if (target.hasItem('Ability Shield')) { this.add('-block', target, 'item: Ability Shield'); From a7fda8e89a3ea71a9f5a5cafb668edf6420deb44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Bastos=20Dias?= Date: Mon, 2 Feb 2026 11:12:51 +0000 Subject: [PATCH 3/5] Gen 4: Cherrim transformation should be independent of Flower Gift --- data/mods/gen4/abilities.ts | 18 ++++-------------- data/mods/gen4/conditions.ts | 19 +++++++++++++++++++ sim/battle.ts | 2 +- test/sim/abilities/flowergift.js | 16 ++++++++++++++++ 4 files changed, 40 insertions(+), 15 deletions(-) diff --git a/data/mods/gen4/abilities.ts b/data/mods/gen4/abilities.ts index 4ab232ea36..f66278e5f7 100644 --- a/data/mods/gen4/abilities.ts +++ b/data/mods/gen4/abilities.ts @@ -139,25 +139,15 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa }, flowergift: { inherit: true, - onWeatherChange(pokemon) { - if (!pokemon.isActive || !pokemon.hp || pokemon.species.baseSpecies !== 'Cherrim') return; - if (pokemon.effectiveWeather() !== 'sunnyday') { - if (pokemon.species.id !== 'cherrimsunshine') { - pokemon.formeChange('Cherrim-Sunshine', this.effect, false, '0', '[msg]'); - } - } else { - if (pokemon.species.id === 'cherrimsunshine') { - pokemon.formeChange('Cherrim', this.effect, false, '0', '[msg]'); - } - } - }, + onStart() {}, + onWeatherChange() {}, onEnd() {}, - onAllyModifyAtk(atk) { + onAllyModifyAtk() { if (this.field.isWeather('sunnyday')) { return this.chainModify(1.5); } }, - onAllyModifySpD(spd) { + onAllyModifySpD() { if (this.field.isWeather('sunnyday')) { return this.chainModify(1.5); } diff --git a/data/mods/gen4/conditions.ts b/data/mods/gen4/conditions.ts index 116a067c80..7b979e1463 100644 --- a/data/mods/gen4/conditions.ts +++ b/data/mods/gen4/conditions.ts @@ -173,4 +173,23 @@ export const Conditions: import('../../../sim/dex-conditions').ModdedConditionDa } }, }, + cherrim: { + name: "Cherrim", + onSwitchIn(pokemon) { + this.singleEvent('WeatherChange', this.effect, this.effectState, pokemon); + }, + onWeatherChange(pokemon) { + if (!pokemon.isActive || !pokemon.hp) return; + this.debug('Cherrim form change check'); + if (pokemon.effectiveWeather() === 'sunnyday') { + if (pokemon.species.id !== 'cherrimsunshine') { + pokemon.formeChange('Cherrim-Sunshine', null, false, '0', '[msg]'); + } + } else { + if (pokemon.species.id === 'cherrimsunshine') { + pokemon.formeChange('Cherrim', null, false, '0', '[msg]'); + } + } + }, + }, }; diff --git a/sim/battle.ts b/sim/battle.ts index e4c6e2ee87..290679abc0 100644 --- a/sim/battle.ts +++ b/sim/battle.ts @@ -1129,7 +1129,7 @@ export class Battle { effect: item, callback, state: pokemon.itemState, end: pokemon.clearItem, effectHolder: pokemon, }, callbackName)); } - const species = pokemon.baseSpecies; + const species = this.gen >= 5 ? pokemon.baseSpecies : pokemon.species; callback = this.getCallback(pokemon, species, callbackName); if (callback !== undefined) { handlers.push(this.resolvePriority({ diff --git a/test/sim/abilities/flowergift.js b/test/sim/abilities/flowergift.js index af125bb07d..62cb54fc04 100644 --- a/test/sim/abilities/flowergift.js +++ b/test/sim/abilities/flowergift.js @@ -77,4 +77,20 @@ describe('Flower Gift', () => { assert.equal(battle.field.weather, 'sunnyday'); assert.species(battle.p1.active[0], 'Cherrim'); }); + + describe('[Gen 4]', () => { + it(`Cherrim should transform without Flower Gift`, () => { + battle = common.gen(4).createBattle([[ + { species: 'Cherrim', ability: 'pressure', moves: ['sleeptalk'] }, + ], [ + { species: 'Torkoal', ability: 'drought', moves: ['sleeptalk'] }, + { species: 'Bulbasaur', ability: 'drizzle', moves: ['sleeptalk'] }, + ]]); + assert.equal(battle.field.weather, 'sunnyday'); + assert.species(battle.p1.active[0], 'Cherrim-Sunshine'); + battle.makeChoices('auto', 'switch 2'); + assert.equal(battle.field.weather, 'raindance'); + assert.species(battle.p1.active[0], 'Cherrim'); + }); + }); }); From ffe58a6c1b6f33aae0e3c55f72f8b85f55f25575 Mon Sep 17 00:00:00 2001 From: andrebastosdias Date: Thu, 26 Mar 2026 10:38:18 +0000 Subject: [PATCH 4/5] Fix --- data/mods/gen4/abilities.ts | 6 ------ 1 file changed, 6 deletions(-) diff --git a/data/mods/gen4/abilities.ts b/data/mods/gen4/abilities.ts index b31d14b13b..beebdc46e4 100644 --- a/data/mods/gen4/abilities.ts +++ b/data/mods/gen4/abilities.ts @@ -2,9 +2,6 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa airlock: { inherit: true, onSwitchIn: undefined, // no inherit - onStart(pokemon) { - pokemon.abilityState.ending = false; - }, }, angerpoint: { inherit: true, @@ -37,9 +34,6 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa cloudnine: { inherit: true, onSwitchIn: undefined, // no inherit - onStart(pokemon) { - pokemon.abilityState.ending = false; - }, }, colorchange: { inherit: true, From ce1b45c8b9bf26f4ccc35f1631aacbd70ef8ef86 Mon Sep 17 00:00:00 2001 From: andrebastosdias Date: Sun, 19 Apr 2026 22:14:42 +0100 Subject: [PATCH 5/5] Add more tests --- test/sim/abilities/flowergift.js | 18 ++++++++++++++++ test/sim/abilities/forecast.js | 36 ++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) create mode 100644 test/sim/abilities/forecast.js diff --git a/test/sim/abilities/flowergift.js b/test/sim/abilities/flowergift.js index 62cb54fc04..5c74b5cb0d 100644 --- a/test/sim/abilities/flowergift.js +++ b/test/sim/abilities/flowergift.js @@ -92,5 +92,23 @@ describe('Flower Gift', () => { assert.equal(battle.field.weather, 'raindance'); assert.species(battle.p1.active[0], 'Cherrim'); }); + + it(`transformed Cherrim should transform without Flower Gift`, () => { + battle = common.gen(4).createBattle([[ + { species: 'Ditto', moves: ['transform'] }, + ], [ + { species: 'Cherrim', moves: ['sleeptalk'] }, + { species: 'Torkoal', ability: 'drought', moves: ['sleeptalk'] }, + { species: 'Bulbasaur', ability: 'drizzle', moves: ['sleeptalk'] }, + ]]); + battle.makeChoices(); + battle.makeChoices('move sleeptalk', 'switch 2'); + + assert.equal(battle.field.weather, 'sunnyday'); + assert.species(battle.p1.active[0], 'Cherrim-Sunshine'); + battle.makeChoices('auto', 'switch 3'); + assert.equal(battle.field.weather, 'raindance'); + assert.species(battle.p1.active[0], 'Cherrim'); + }); }); }); diff --git a/test/sim/abilities/forecast.js b/test/sim/abilities/forecast.js new file mode 100644 index 0000000000..579f86c05e --- /dev/null +++ b/test/sim/abilities/forecast.js @@ -0,0 +1,36 @@ +'use strict'; + +const assert = require('./../../assert'); +const common = require('./../../common'); + +let battle; + +describe('Forecast', () => { + afterEach(() => { + battle.destroy(); + }); + + it(`should revert form if it loses its ability`, () => { + battle = common.createBattle([[ + { species: "Castform", ability: 'forecast', moves: ['sleeptalk'] }, + ], [ + { species: "Groudon", ability: 'drought', moves: ['skillswap'] }, + ]]); + assert.species(battle.p1.active[0], 'Castform-Sunny'); + battle.makeChoices(); + assert.species(battle.p1.active[0], 'Castform'); + }); + + describe('[Gen 4]', () => { + it(`should not revert form if it loses its ability`, () => { + battle = common.gen(4).createBattle([[ + { species: "Castform", ability: 'forecast', moves: ['sleeptalk'] }, + ], [ + { species: "Groudon", ability: 'drought', moves: ['skillswap'] }, + ]]); + assert.species(battle.p1.active[0], 'Castform-Sunny'); + battle.makeChoices(); + assert.species(battle.p1.active[0], 'Castform-Sunny'); + }); + }); +});