diff --git a/src/data/ability.ts b/src/data/ability.ts index 063c393ba72..f91cd685222 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -4868,55 +4868,72 @@ async function applyAbAttrsInternal( showAbilityInstant: boolean = false, simulated: boolean = false, messages: string[] = [], - gainedMidTurn: boolean = false /** Ignore passives and abilities with {@linkcode NoOnGainActivationAttr} */ + gainedMidTurn: boolean = false ) { for (const passive of [ false, true ]) { - if (!pokemon?.canApplyAbility(passive) || (passive && (pokemon.getPassiveAbility().id === pokemon.getAbility().id || gainedMidTurn)) - || (gainedMidTurn && pokemon.getAbility().getAttrs(PostSummonAbAttr).some(a => !a.shouldActivateOnGain()))) { + if (!pokemon?.canApplyAbility(passive) || (passive && (pokemon.getPassiveAbility().id === pokemon.getAbility().id))) { continue; } - const ability = passive ? pokemon.getPassiveAbility() : pokemon.getAbility(); - for (const attr of ability.getAttrs(attrType)) { - const condition = attr.getCondition(); - if (condition && !condition(pokemon)) { - continue; - } - - globalScene.setPhaseQueueSplice(); - - let result = applyFunc(attr, passive); - // TODO Remove this when promises get reworked - if (result instanceof Promise) { - result = await result; - } - if (result) { - if (pokemon.summonData && !pokemon.summonData.abilitiesApplied.includes(ability.id)) { - pokemon.summonData.abilitiesApplied.push(ability.id); - } - if (pokemon.battleData && !simulated && !pokemon.battleData.abilitiesApplied.includes(ability.id)) { - pokemon.battleData.abilitiesApplied.push(ability.id); - } - if (attr.showAbility && !simulated) { - if (showAbilityInstant) { - globalScene.abilityBar.showAbility(pokemon, passive); - } else { - queueShowAbility(pokemon, passive); - } - } - const message = attr.getTriggerMessage(pokemon, ability.name, args); - if (message) { - if (!simulated) { - globalScene.queueMessage(message); - } - } - messages.push(message!); - } - } + applySingleAbAttrs(pokemon, passive, attrType, applyFunc, args, gainedMidTurn, simulated, showAbilityInstant, messages); globalScene.clearPhaseQueueSplice(); } } +async function applySingleAbAttrs( + pokemon: Pokemon, + passive: boolean, + attrType: Constructor, + applyFunc: AbAttrApplyFunc, + args: any[], + gainedMidTurn: boolean = false, + simulated: boolean = false, + showAbilityInstant: boolean = false, + messages: string[] = [] +) { + const ability = passive ? pokemon.getPassiveAbility() : pokemon.getAbility(); + if (gainedMidTurn && ability.getAttrs(attrType).some(attr => attr instanceof PostSummonAbAttr && !attr.shouldActivateOnGain())) { + return; + } + + for (const attr of ability.getAttrs(attrType)) { + const condition = attr.getCondition(); + if ((condition && !condition(pokemon))) { + continue; + } + + globalScene.setPhaseQueueSplice(); + + let result = applyFunc(attr, passive); + // TODO Remove this when promises get reworked + if (result instanceof Promise) { + result = await result; + } + if (result) { + if (pokemon.summonData && !pokemon.summonData.abilitiesApplied.includes(ability.id)) { + pokemon.summonData.abilitiesApplied.push(ability.id); + } + if (pokemon.battleData && !simulated && !pokemon.battleData.abilitiesApplied.includes(ability.id)) { + pokemon.battleData.abilitiesApplied.push(ability.id); + } + if (attr.showAbility && !simulated) { + if (showAbilityInstant) { + globalScene.abilityBar.showAbility(pokemon, passive); + } else { + queueShowAbility(pokemon, passive); + } + } + const message = attr.getTriggerMessage(pokemon, ability.name, args); + if (message) { + if (!simulated) { + globalScene.queueMessage(message); + } + } + messages.push(message!); + } + } +} + class ForceSwitchOutHelper { constructor(private switchType: SwitchType) {} @@ -5308,15 +5325,15 @@ export function applyPostItemLostAbAttrs(attrType: Constructor { - return applyAbAttrsInternal(PostSummonAbAttr, pokemon, (attr, passive) => attr.applyPostSummon(pokemon, passive, simulated, args), args, false, simulated, [], true); +export function applyOnGainAbAttrs(pokemon: Pokemon, passive: boolean = false, simulated: boolean = false, ...args: any[]): void { + applySingleAbAttrs(pokemon, passive, PostSummonAbAttr, (attr, passive) => attr.applyPostSummon(pokemon, passive, simulated, args), args, true, simulated); } /** * Clears primal weather during the turn if {@linkcode pokemon}'s ability corresponds to one */ -export function applyOnGainClearWeatherAbAttrs(pokemon: Pokemon, simulated: boolean = false, ...args: any[]): Promise { - return applyAbAttrsInternal(PreLeaveFieldClearWeatherAbAttr, pokemon, (attr, passive) => attr.applyPreLeaveField(pokemon, passive, simulated, [ ...args, true ]), args, true, simulated, [], true); +export function applyOnLoseClearWeatherAbAttrs(pokemon: Pokemon, passive: boolean = false, simulated: boolean = false, ...args: any[]): void { + applySingleAbAttrs(pokemon, passive, PreLeaveFieldClearWeatherAbAttr, (attr, passive) => attr.applyPreLeaveField(pokemon, passive, simulated, [ ...args, true ]), args, true, simulated); } function queueShowAbility(pokemon: Pokemon, passive: boolean): void { globalScene.unshiftPhase(new ShowAbilityPhase(pokemon.id, passive)); diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 91f3ede277c..714f1ec7026 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -64,7 +64,7 @@ import { BattlerTag, BattlerTagLapseType, EncoreTag, GroundedTag, HighestStatBoo import { WeatherType } from "#enums/weather-type"; import { ArenaTagSide, NoCritTag, WeakenMoveScreenTag } from "#app/data/arena-tag"; import type { Ability, AbAttr } from "#app/data/ability"; -import { StatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, IgnoreOpponentStatStagesAbAttr, MoveImmunityAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyStatMultiplierAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr, IgnoreTypeImmunityAbAttr, DamageBoostAbAttr, IgnoreTypeStatusEffectImmunityAbAttr, ConditionalCritAbAttr, applyFieldStatMultiplierAbAttrs, FieldMultiplyStatAbAttr, AddSecondStrikeAbAttr, UserFieldStatusEffectImmunityAbAttr, UserFieldBattlerTagImmunityAbAttr, BattlerTagImmunityAbAttr, MoveTypeChangeAbAttr, FullHpResistTypeAbAttr, applyCheckTrappedAbAttrs, CheckTrappedAbAttr, PostSetStatusAbAttr, applyPostSetStatusAbAttrs, InfiltratorAbAttr, AlliedFieldDamageReductionAbAttr, PostDamageAbAttr, applyPostDamageAbAttrs, CommanderAbAttr, applyPostItemLostAbAttrs, PostItemLostAbAttr, applyOnGainAbAttrs, PreLeaveFieldAbAttr, applyPreLeaveFieldAbAttrs, applyOnGainClearWeatherAbAttrs } from "#app/data/ability"; +import { StatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldPriorityMoveImmunityAbAttr, IgnoreOpponentStatStagesAbAttr, MoveImmunityAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyStatMultiplierAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs, UnsuppressableAbilityAbAttr, SuppressFieldAbilitiesAbAttr, NoFusionAbilityAbAttr, MultCritAbAttr, IgnoreTypeImmunityAbAttr, DamageBoostAbAttr, IgnoreTypeStatusEffectImmunityAbAttr, ConditionalCritAbAttr, applyFieldStatMultiplierAbAttrs, FieldMultiplyStatAbAttr, AddSecondStrikeAbAttr, UserFieldStatusEffectImmunityAbAttr, UserFieldBattlerTagImmunityAbAttr, BattlerTagImmunityAbAttr, MoveTypeChangeAbAttr, FullHpResistTypeAbAttr, applyCheckTrappedAbAttrs, CheckTrappedAbAttr, PostSetStatusAbAttr, applyPostSetStatusAbAttrs, InfiltratorAbAttr, AlliedFieldDamageReductionAbAttr, PostDamageAbAttr, applyPostDamageAbAttrs, CommanderAbAttr, applyPostItemLostAbAttrs, PostItemLostAbAttr, applyOnGainAbAttrs, PreLeaveFieldAbAttr, applyPreLeaveFieldAbAttrs, applyOnLoseClearWeatherAbAttrs } from "#app/data/ability"; import type PokemonData from "#app/system/pokemon-data"; import { BattlerIndex } from "#app/battle"; import { Mode } from "#app/ui/ui"; @@ -1487,10 +1487,14 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * Also clears primal weather if it is from the ability being changed * @param ability New Ability */ - public setTempAbility(ability: Ability): void { - applyOnGainClearWeatherAbAttrs(this); - this.summonData.ability = ability.id; - applyOnGainAbAttrs(this); + public setTempAbility(ability: Ability, passive: boolean = false): void { + applyOnLoseClearWeatherAbAttrs(this, passive); + if (passive) { + this.summonData.passiveAbility = ability.id; + } else { + this.summonData.ability = ability.id; + } + applyOnGainAbAttrs(this, passive); } /**