diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index 20946c784..a45522b5e 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -799,7 +799,7 @@ export class TruantTag extends AbilityBattlerTag { } lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { - if ((!pokemon.canApplyAbility() || pokemon.getAbility().id !== Abilities.TRUANT) && (!pokemon.canApplyAbility(true) || pokemon.getPassiveAbility().id !== Abilities.TRUANT)) + if (!pokemon.hasAbility(Abilities.TRUANT)) return super.lapse(pokemon, lapseType); const passive = pokemon.getAbility().id !== Abilities.TRUANT; @@ -827,7 +827,7 @@ export class SlowStartTag extends AbilityBattlerTag { } lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { - if ((!pokemon.canApplyAbility() || pokemon.getAbility().id !== this.ability) && (!pokemon.canApplyAbility(true) || pokemon.getPassiveAbility().id !== this.ability)) + if (!pokemon.hasAbility(this.ability)) this.turnCount = 1; return super.lapse(pokemon, lapseType); diff --git a/src/data/move.ts b/src/data/move.ts index 841327b42..de749ba3a 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -275,7 +275,7 @@ export default class Move { checkFlag(flag: MoveFlags, user: Pokemon, target: Pokemon): boolean { switch (flag) { case MoveFlags.MAKES_CONTACT: - if ((user.canApplyAbility() && user.getAbility().hasAttr(IgnoreContactAbAttr)) || (user.canApplyAbility(true) && user.getPassiveAbility().hasAttr(IgnoreContactAbAttr))) + if (user.hasAbilityWithAttr(IgnoreContactAbAttr)) return false; break; } @@ -4849,9 +4849,9 @@ export function initMoves() { .attr(StatChangeAttr, [ BattleStat.SPATK, BattleStat.SPDEF, BattleStat.SPD ], 2, true) .ignoresVirtual(), new StatusMove(Moves.MAGNETIC_FLUX, "Magnetic Flux", Type.ELECTRIC, -1, 20, "The user manipulates magnetic fields, which raises the Defense and Sp. Def stats of ally Pokémon with the Plus or Minus Ability.", -1, 0, 6) - .attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF ], 1, false, (user, target, move) => !![ Abilities.PLUS, Abilities.MINUS].find(a => a === user.getAbility().id || (user.canApplyPassive() && a === user.getPassiveAbility().id))) + .attr(StatChangeAttr, [ BattleStat.DEF, BattleStat.SPDEF ], 1, false, (user, target, move) => !![ Abilities.PLUS, Abilities.MINUS].find(a => target.hasAbility(a, false))) .target(MoveTarget.USER_AND_ALLIES) - .condition((user, target, move) => !![ user, user.getAlly() ].filter(p => p?.isActive()).find(p => !![ Abilities.PLUS, Abilities.MINUS].find(a => a === p.getAbility().id || (user.canApplyPassive() && a === user.getPassiveAbility().id)))), + .condition((user, target, move) => !![ user, user.getAlly() ].filter(p => p?.isActive()).find(p => !![ Abilities.PLUS, Abilities.MINUS].find(a => p.hasAbility(a, false)))), new StatusMove(Moves.HAPPY_HOUR, "Happy Hour (N)", Type.NORMAL, -1, 30, "Using Happy Hour doubles the amount of prize money received after battle.", -1, 0, 6) // No animation .target(MoveTarget.USER_SIDE), new StatusMove(Moves.ELECTRIC_TERRAIN, "Electric Terrain", Type.ELECTRIC, -1, 10, "The user electrifies the ground for five turns, powering up Electric-type moves. Pokémon on the ground no longer fall asleep.", -1, 0, 6) @@ -4979,9 +4979,9 @@ export function initMoves() { new SelfStatusMove(Moves.LASER_FOCUS, "Laser Focus", Type.NORMAL, -1, 30, "The user concentrates intensely. The attack on the next turn always results in a critical hit.", -1, 0, 7) .attr(AddBattlerTagAttr, BattlerTagType.ALWAYS_CRIT, true, false), new StatusMove(Moves.GEAR_UP, "Gear Up", Type.STEEL, -1, 20, "The user engages its gears to raise the Attack and Sp. Atk stats of ally Pokémon with the Plus or Minus Ability.", -1, 0, 7) - .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK ], 1, false, (user, target, move) => [ Abilities.PLUS, Abilities.MINUS ].includes(target.getAbility().id) || (target.canApplyPassive() && [ Abilities.PLUS, Abilities.MINUS ].includes(target.getPassiveAbility().id))) + .attr(StatChangeAttr, [ BattleStat.ATK, BattleStat.SPATK ], 1, false, (user, target, move) => !![ Abilities.PLUS, Abilities.MINUS].find(a => target.hasAbility(a, false))) .target(MoveTarget.USER_AND_ALLIES) - .condition((user, target, move) => !![ user, user.getAlly() ].find(p => p && [ Abilities.PLUS, Abilities.MINUS ].includes(p.getAbility().id) || (target.canApplyPassive() && [ Abilities.PLUS, Abilities.MINUS ].includes(target.getPassiveAbility().id)))), + .condition((user, target, move) => !![ user, user.getAlly() ].filter(p => p?.isActive()).find(p => !![ Abilities.PLUS, Abilities.MINUS].find(a => p.hasAbility(a, false)))), new AttackMove(Moves.THROAT_CHOP, "Throat Chop (P)", Type.DARK, MoveCategory.PHYSICAL, 80, 100, 15, "The user attacks the target's throat, and the resultant suffering prevents the target from using moves that emit sound for two turns.", 100, 0, 7), new AttackMove(Moves.POLLEN_PUFF, "Pollen Puff (P)", Type.BUG, MoveCategory.SPECIAL, 90, 100, 15, "The user attacks the enemy with a pollen puff that explodes. If the target is an ally, it gives the ally a pollen puff that restores its HP instead.", -1, 0, 7) .ballBombMove(), diff --git a/src/data/pokemon-forms.ts b/src/data/pokemon-forms.ts index 2d2d491bf..bb22f9859 100644 --- a/src/data/pokemon-forms.ts +++ b/src/data/pokemon-forms.ts @@ -535,8 +535,8 @@ export const pokemonFormChanges: PokemonFormChanges = { new SpeciesFormChange(Species.MELOETTA, 'pirouette', 'aria', new SpeciesFormChangeActiveTrigger(false), true) ], [Species.AEGISLASH]: [ - new SpeciesFormChange(Species.AEGISLASH, 'blade', 'shield', new SpeciesFormChangePreMoveTrigger(Moves.KINGS_SHIELD), true, new SpeciesFormChangeCondition(p => p.getAbility().id === Abilities.STANCE_CHANGE)), - new SpeciesFormChange(Species.AEGISLASH, 'shield', 'blade', new SpeciesFormChangePreMoveTrigger(m => allMoves[m].category !== MoveCategory.STATUS), true, new SpeciesFormChangeCondition(p => p.getAbility().id === Abilities.STANCE_CHANGE)), + new SpeciesFormChange(Species.AEGISLASH, 'blade', 'shield', new SpeciesFormChangePreMoveTrigger(Moves.KINGS_SHIELD), true, new SpeciesFormChangeCondition(p => p.hasAbility(Abilities.STANCE_CHANGE))), + new SpeciesFormChange(Species.AEGISLASH, 'shield', 'blade', new SpeciesFormChangePreMoveTrigger(m => allMoves[m].category !== MoveCategory.STATUS), true, new SpeciesFormChangeCondition(p => p.hasAbility(Abilities.STANCE_CHANGE))), new SpeciesFormChange(Species.AEGISLASH, 'blade', 'shield', new SpeciesFormChangeActiveTrigger(false), true) ], [Species.DIANCIE]: [ diff --git a/src/data/weather.ts b/src/data/weather.ts index b3a59f34b..b28815984 100644 --- a/src/data/weather.ts +++ b/src/data/weather.ts @@ -108,7 +108,7 @@ export class Weather { for (let pokemon of field) { let suppressWeatherEffectAbAttr = pokemon.getAbility().getAttrs(SuppressWeatherEffectAbAttr).find(() => true) as SuppressWeatherEffectAbAttr; if (!suppressWeatherEffectAbAttr) - suppressWeatherEffectAbAttr = pokemon.canApplyPassive() ? pokemon.getPassiveAbility().getAttrs(SuppressWeatherEffectAbAttr).find(() => true) as SuppressWeatherEffectAbAttr : null; + suppressWeatherEffectAbAttr = pokemon.hasPassive() ? pokemon.getPassiveAbility().getAttrs(SuppressWeatherEffectAbAttr).find(() => true) as SuppressWeatherEffectAbAttr : null; if (suppressWeatherEffectAbAttr && (!this.isImmutable() || suppressWeatherEffectAbAttr.affectsImmutable)) return true; } diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 16e695769..9181be78e 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -25,7 +25,7 @@ import { TempBattleStat } from '../data/temp-battle-stat'; import { ArenaTagSide, WeakenMoveScreenTag, WeakenMoveTypeTag } from '../data/arena-tag'; import { ArenaTagType } from "../data/enums/arena-tag-type"; import { Biome } from "../data/enums/biome"; -import { Ability, BattleStatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldVariableMovePowerAbAttr, IgnoreOpponentStatChangesAbAttr, MoveImmunityAbAttr, MoveTypeChangeAttr, NonSuperEffectiveImmunityAbAttr, PreApplyBattlerTagAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, VariableMovePowerAbAttr, VariableMoveTypeAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPostDefendAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs } from '../data/ability'; +import { Ability, AbAttr, BattleStatMultiplierAbAttr, BlockCritAbAttr, BonusCritAbAttr, BypassBurnDamageReductionAbAttr, FieldVariableMovePowerAbAttr, IgnoreOpponentStatChangesAbAttr, MoveImmunityAbAttr, MoveTypeChangeAttr, NonSuperEffectiveImmunityAbAttr, PreApplyBattlerTagAbAttr, PreDefendFullHpEndureAbAttr, ReceivedMoveDamageMultiplierAbAttr, ReduceStatusEffectDurationAbAttr, StabBoostAbAttr, StatusEffectImmunityAbAttr, TypeImmunityAbAttr, VariableMovePowerAbAttr, VariableMoveTypeAbAttr, WeightMultiplierAbAttr, allAbilities, applyAbAttrs, applyBattleStatMultiplierAbAttrs, applyPostDefendAbAttrs, applyPreApplyBattlerTagAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, applyPreSetStatusAbAttrs } from '../data/ability'; import { Abilities } from "#app/data/enums/abilities"; import PokemonData from '../system/pokemon-data'; import { BattlerIndex } from '../battle'; @@ -561,7 +561,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { let value = Math.floor(((2 * baseStat + this.ivs[s]) * this.level) * 0.01); if (isHp) { value = value + this.level + 10; - if ((this.canApplyAbility() && this.getAbility().hasAttr(NonSuperEffectiveImmunityAbAttr)) || (this.canApplyAbility(true) && this.getPassiveAbility().hasAttr(NonSuperEffectiveImmunityAbAttr))) + if (this.hasAbility(Abilities.WONDER_GUARD, false, true)) value = 1; if (this.hp > value || this.hp === undefined) this.hp = value; @@ -730,12 +730,12 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return allAbilities[starterPassiveAbilities[starterSpeciesId]]; } - canApplyPassive(): boolean { + hasPassive(): boolean { return this.passive || this.isBoss(); } canApplyAbility(passive: boolean = false): boolean { - if (passive && !this.canApplyPassive()) + if (passive && !this.hasPassive()) return false; const ability = (!passive ? this.getAbility() : this.getPassiveAbility()); if (ability.isIgnorable && this.scene.arena.ignoreAbilities) @@ -743,6 +743,22 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return (this.hp || ability.isBypassFaint) && !ability.conditions.find(condition => !condition(this)); } + hasAbility(ability: Abilities, canApply: boolean = true, ignoreOverride?: boolean): boolean { + if ((!canApply || this.canApplyAbility()) && this.getAbility(ignoreOverride).id === ability) + return true; + if (this.hasPassive() && (!canApply || this.canApplyAbility(true)) && this.getPassiveAbility().id === ability) + return true; + return false; + } + + hasAbilityWithAttr(attrType: { new(...args: any[]): AbAttr }, canApply: boolean = true, ignoreOverride?: boolean): boolean { + if ((!canApply || this.canApplyAbility()) && this.getAbility(ignoreOverride).hasAttr(attrType)) + return true; + if (this.hasPassive() && (!canApply || this.canApplyAbility(true)) && this.getPassiveAbility().hasAttr(attrType)) + return true; + return false; + } + getWeight(): number { const weight = new Utils.NumberHolder(this.species.weight); // This will trigger the ability overlay so only call this function when necessary diff --git a/src/phases.ts b/src/phases.ts index ff2f62c3e..58490e24c 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -2190,7 +2190,7 @@ export class MovePhase extends BattlePhase { for (let opponent of targetedOpponents) { if (this.move.ppUsed === this.move.getMove().pp) break; - if ((opponent.canApplyAbility() && opponent.getAbility().hasAttr(IncreasePpAbAttr)) || (opponent.canApplyAbility(true) && opponent.getPassiveAbility().hasAttr(IncreasePpAbAttr))) + if (opponent.hasAbilityWithAttr(IncreasePpAbAttr)) this.move.ppUsed = Math.min(this.move.ppUsed + 1, this.move.getMovePp()); } }