diff --git a/data/abilities.ts b/data/abilities.ts index ed2efbc174a9..5bb4a47fc502 100644 --- a/data/abilities.ts +++ b/data/abilities.ts @@ -605,7 +605,7 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = { }, onUpdate(pokemon) { if (this.gameType !== 'doubles') return; - // don't run between when a Pokemon switches in and the resulting onSwitchIn event + // don't run between when a Pokemon switches in and the resulting SwitchIn event if (this.queue.peek()?.choice === 'runSwitch') return; const ally = pokemon.allies()[0]; @@ -3438,8 +3438,21 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = { // Protosynthesis is not affected by Utility Umbrella if (this.field.isWeather('sunnyday')) { pokemon.addVolatile('protosynthesis'); - } else if (!pokemon.volatiles['protosynthesis']?.fromBooster && !this.field.isWeather('sunnyday')) { - pokemon.removeVolatile('protosynthesis'); + } else { + if (!pokemon.volatiles['protosynthesis']?.fromBooster) { + pokemon.removeVolatile('protosynthesis'); + } + if (!pokemon.volatiles['protosynthesis'] && pokemon.hasItem('boosterenergy')) { + pokemon.useItem(pokemon, this.dex.abilities.get('protosynthesis')); + } + } + }, + onUpdate(pokemon) { + // don't run between when a Pokemon switches in and the resulting SwitchIn event + if (this.queue.peek()?.choice === 'runSwitch') return; + + if (!pokemon.volatiles['protosynthesis'] && !this.field.isWeather('sunnyday') && pokemon.hasItem('boosterenergy')) { + pokemon.useItem(pokemon, this.dex.abilities.get('protosynthesis')); } }, onEnd(pokemon) { @@ -3574,8 +3587,21 @@ export const Abilities: import('../sim/dex-abilities').AbilityDataTable = { onTerrainChange(pokemon) { if (this.field.isTerrain('electricterrain')) { pokemon.addVolatile('quarkdrive'); - } else if (!pokemon.volatiles['quarkdrive']?.fromBooster) { - pokemon.removeVolatile('quarkdrive'); + } else { + if (!pokemon.volatiles['quarkdrive']?.fromBooster) { + pokemon.removeVolatile('quarkdrive'); + } + if (!pokemon.volatiles['quarkdrive'] && pokemon.hasItem('boosterenergy')) { + pokemon.useItem(pokemon, this.dex.abilities.get('quarkdrive')); + } + } + }, + onUpdate(pokemon) { + // don't run between when a Pokemon switches in and the resulting SwitchIn event + if (this.queue.peek()?.choice === 'runSwitch') return; + + if (!pokemon.volatiles['quarkdrive'] && !this.field.isTerrain('electricterrain') && pokemon.hasItem('boosterenergy')) { + pokemon.useItem(pokemon, this.dex.abilities.get('quarkdrive')); } }, onEnd(pokemon) { diff --git a/data/items.ts b/data/items.ts index 78e6d7a9e290..c1ea6fbcc8ee 100644 --- a/data/items.ts +++ b/data/items.ts @@ -613,20 +613,11 @@ export const Items: import('../sim/dex-items').ItemDataTable = { fling: { basePower: 30, }, - onSwitchInPriority: -2, - onStart(pokemon) { - this.effectState.started = true; - ((this.effect as any).onUpdate as (p: Pokemon) => void).call(this, pokemon); + onUseItem(item, pokemon, source, sourceEffect) { + return pokemon === source && ['protosynthesis', 'quarkdrive'].includes(sourceEffect.id); }, - onUpdate(pokemon) { - if (!this.effectState.started || pokemon.transformed) return; - - if (pokemon.hasAbility('protosynthesis') && !this.field.isWeather('sunnyday') && pokemon.useItem()) { - pokemon.addVolatile('protosynthesis'); - } - if (pokemon.hasAbility('quarkdrive') && !this.field.isTerrain('electricterrain') && pokemon.useItem()) { - pokemon.addVolatile('quarkdrive'); - } + onUse(pokemon, source, sourceEffect) { + pokemon.addVolatile(sourceEffect.id); }, onTakeItem(item, source) { if (source.baseSpecies.tags.includes("Paradox")) return false; diff --git a/data/mods/gen9dlc1/abilities.ts b/data/mods/gen9dlc1/abilities.ts index ad0c66018f16..2097febfe0d4 100644 --- a/data/mods/gen9dlc1/abilities.ts +++ b/data/mods/gen9dlc1/abilities.ts @@ -13,9 +13,13 @@ export const Abilities: import('../../../sim/dex-abilities').ModdedAbilityDataTa // Protosynthesis is not affected by Utility Umbrella if (this.field.isWeather('sunnyday')) { pokemon.addVolatile('protosynthesis'); - } else if (!pokemon.volatiles['protosynthesis']?.fromBooster && this.field.weather !== 'sunnyday') { - // Protosynthesis will not deactivite if Sun is suppressed, hence the direct ID check (isWeather respects supression) - pokemon.removeVolatile('protosynthesis'); + } else { + if (!pokemon.volatiles['protosynthesis']?.fromBooster && this.field.weather !== 'sunnyday') { + pokemon.removeVolatile('protosynthesis'); + } + if (!pokemon.volatiles['protosynthesis'] && pokemon.hasItem('boosterenergy')) { + pokemon.useItem(pokemon, this.dex.abilities.get('protosynthesis')); + } } }, condition: { diff --git a/sim/dex-conditions.ts b/sim/dex-conditions.ts index f8c160c98046..8742385f145a 100644 --- a/sim/dex-conditions.ts +++ b/sim/dex-conditions.ts @@ -115,7 +115,7 @@ export interface EventMethods { onTryMove?: MoveEventMethods['onTryMove']; onTryPrimaryHit?: (this: Battle, target: Pokemon, source: Pokemon, move: ActiveMove) => boolean | null | number | void; onType?: (this: Battle, types: string[], pokemon: Pokemon) => string[] | void; - onUseItem?: (this: Battle, item: Item, pokemon: Pokemon) => void; + onUseItem?: (this: Battle, item: Item, pokemon: Pokemon, source: Pokemon, sourceEffect: Effect) => void; onUpdate?: (this: Battle, pokemon: Pokemon) => void; onWeather?: (this: Battle, target: Pokemon, source: null, effect: Condition) => void; onWeatherModifyDamage?: CommonHandlers['ModifierSourceMove']; diff --git a/sim/dex-items.ts b/sim/dex-items.ts index f0bbf26ae466..dea026bf0177 100644 --- a/sim/dex-items.ts +++ b/sim/dex-items.ts @@ -103,7 +103,7 @@ export class Item extends BasicEffect implements Readonly { declare readonly boosts?: SparseBoostsTable | false; declare readonly onEat?: ((this: Battle, pokemon: Pokemon) => void) | false; - declare readonly onUse?: ((this: Battle, pokemon: Pokemon) => void) | false; + declare readonly onUse?: ((this: Battle, pokemon: Pokemon, source: Pokemon, sourceEffect: Effect) => void) | false; declare readonly onStart?: (this: Battle, target: Pokemon) => void; declare readonly onEnd?: (this: Battle, target: Pokemon) => void; diff --git a/sim/pokemon.ts b/sim/pokemon.ts index 0b5056ffccef..76ed7abadc20 100644 --- a/sim/pokemon.ts +++ b/sim/pokemon.ts @@ -1492,9 +1492,6 @@ export class Pokemon { this.volatileStaleness = undefined; - delete this.abilityState.started; - delete this.itemState.started; - this.setSpecies(this.baseSpecies); } @@ -1748,7 +1745,7 @@ export class Pokemon { if (!sourceEffect && this.battle.effect) sourceEffect = this.battle.effect; if (!source && this.battle.event && this.battle.event.target) source = this.battle.event.target; const item = this.getItem(); - if (this.battle.runEvent('UseItem', this, null, null, item)) { + if (this.battle.runEvent('UseItem', this, source, sourceEffect, item)) { switch (item.id) { case 'redcard': this.battle.add('-enditem', this, item, '[of] ' + source); diff --git a/test/sim/items/boosterenergy.js b/test/sim/items/boosterenergy.js index 742f18a29ddb..a1c07349707e 100644 --- a/test/sim/items/boosterenergy.js +++ b/test/sim/items/boosterenergy.js @@ -24,4 +24,19 @@ describe('Booster Energy', function () { assert.equal(bundle.volatiles['quarkdrive'].bestStat, 'spa', `Iron Bundle's Speed should have been lowered before Booster Energy activated, boosting its SpA instead.`); }); + + it(`should activate right after weather changes`, function () { + battle = common.createBattle({gameType: 'doubles'}, [[ + {species: 'Ninetales-Alola', ability: 'snowwarning', moves: ['sleeptalk']}, + {species: 'Roaring Moon', item: 'boosterenergy', ability: 'protosynthesis', moves: ['sleeptalk']}, + ], [ + {species: 'Incineroar', ability: 'intimidate', moves: ['sleeptalk']}, + {species: 'Torkoal', ability: 'drought', moves: ['sleeptalk']}, + ]]); + + const roaringMoon = battle.p1.active[1]; + assert(roaringMoon.volatiles['protosynthesis'].fromBooster); + assert.equal(roaringMoon.volatiles['protosynthesis'].bestStat, 'atk'); + assert.equal(battle.field.weather, 'sunnyday'); + }); });