[Refactor] [Docs] Minor refactor of move.checkFlags into move.doesFlagEffectApply (#5264)

* Refactor Move.checkFlags

* Improve jsdoc clarity

* Fix improper recursive call for the IGNORE_PROTECT check

* Fix improper placement of followUp check

* Get rid of unnecssary break

* Fix last import

* Remove latent checkFlag call in move-effect-phase

* Remedy perish body oversight

* Apply kev's suggestions from code review

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>

---------

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
This commit is contained in:
Sirz Benjie 2025-04-04 19:43:46 -05:00 committed by GitHub
parent 9e4162d429
commit 5318d717b3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 40 additions and 20 deletions

View File

@ -998,7 +998,7 @@ export class PostDefendContactApplyStatusEffectAbAttr extends PostDefendAbAttr {
override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean {
const effect = this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randSeedInt(this.effects.length)];
return move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon) && !attacker.status
return move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon}) && !attacker.status
&& (this.chance === -1 || pokemon.randSeedInt(100) < this.chance) && !move.hitsSubstitute(attacker, pokemon)
&& attacker.canSetStatus(effect, true, false, pokemon);
}
@ -1038,7 +1038,7 @@ export class PostDefendContactApplyTagChanceAbAttr extends PostDefendAbAttr {
}
override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean {
return move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon) && pokemon.randSeedInt(100) < this.chance
return move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon}) && pokemon.randSeedInt(100) < this.chance
&& !move.hitsSubstitute(attacker, pokemon) && attacker.canAddTag(this.tagType);
}
@ -1085,7 +1085,7 @@ export class PostDefendContactDamageAbAttr extends PostDefendAbAttr {
}
override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean {
return !simulated && move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon)
return !simulated && move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon})
&& !attacker.hasAbilityWithAttr(BlockNonDirectDamageAbAttr) && !move.hitsSubstitute(attacker, pokemon);
}
@ -1118,8 +1118,7 @@ export class PostDefendPerishSongAbAttr extends PostDefendAbAttr {
}
override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean {
return (move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon) && !move.hitsSubstitute(attacker, pokemon))
&& !attacker.getTag(BattlerTagType.PERISH_SONG);
return move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon}) && !attacker.getTag(BattlerTagType.PERISH_SONG);
}
override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, _args: any[]): void {
@ -1163,7 +1162,7 @@ export class PostDefendAbilitySwapAbAttr extends PostDefendAbAttr {
}
override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean {
return move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon)
return move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon})
&& attacker.getAbility().isSwappable && !move.hitsSubstitute(attacker, pokemon);
}
@ -1189,7 +1188,7 @@ export class PostDefendAbilityGiveAbAttr extends PostDefendAbAttr {
}
override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean {
return move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon) && attacker.getAbility().isSuppressable
return move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon}) && attacker.getAbility().isSuppressable
&& !attacker.getAbility().hasAttr(PostDefendAbilityGiveAbAttr) && !move.hitsSubstitute(attacker, pokemon);
}
@ -1220,7 +1219,7 @@ export class PostDefendMoveDisableAbAttr extends PostDefendAbAttr {
override canApplyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult | null, args: any[]): boolean {
return attacker.getTag(BattlerTagType.DISABLED) === null && !move.hitsSubstitute(attacker, pokemon)
&& move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon) && (this.chance === -1 || pokemon.randSeedInt(100) < this.chance);
&& move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon}) && (this.chance === -1 || pokemon.randSeedInt(100) < this.chance);
}
override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, _args: any[]): void {
@ -1925,7 +1924,7 @@ export class PostAttackApplyStatusEffectAbAttr extends PostAttackAbAttr {
super.canApplyPostAttack(pokemon, passive, simulated, attacker, move, hitResult, args)
&& !(pokemon !== attacker && move.hitsSubstitute(attacker, pokemon))
&& (simulated || !attacker.hasAbilityWithAttr(IgnoreMoveEffectsAbAttr) && pokemon !== attacker
&& (!this.contactRequired || move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon)) && pokemon.randSeedInt(100) < this.chance && !pokemon.status)
&& (!this.contactRequired || move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon})) && pokemon.randSeedInt(100) < this.chance && !pokemon.status)
) {
const effect = this.effects.length === 1 ? this.effects[0] : this.effects[pokemon.randSeedInt(this.effects.length)];
return simulated || attacker.canSetStatus(effect, true, false, pokemon);
@ -1964,7 +1963,7 @@ export class PostAttackApplyBattlerTagAbAttr extends PostAttackAbAttr {
/**Battler tags inflicted by abilities post attacking are also considered additional effects.*/
return super.canApplyPostAttack(pokemon, passive, simulated, attacker, move, hitResult, args) &&
!attacker.hasAbilityWithAttr(IgnoreMoveEffectsAbAttr) && pokemon !== attacker &&
(!this.contactRequired || move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon)) &&
(!this.contactRequired || move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon})) &&
pokemon.randSeedInt(100) < this.chance(attacker, pokemon, move) && !pokemon.status;
}
@ -4761,7 +4760,7 @@ export class PostFaintContactDamageAbAttr extends PostFaintAbAttr {
}
override canApplyPostFaint(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker?: Pokemon, move?: Move, hitResult?: HitResult, ...args: any[]): boolean {
const diedToDirectDamage = move !== undefined && attacker !== undefined && move.checkFlag(MoveFlags.MAKES_CONTACT, attacker, pokemon);
const diedToDirectDamage = move !== undefined && attacker !== undefined && move.doesFlagEffectApply({flag: MoveFlags.MAKES_CONTACT, user: attacker, target: pokemon});
const cancelled = new Utils.BooleanHolder(false);
globalScene.getField(true).map(p => applyAbAttrs(FieldPreventExplosiveMovesAbAttr, p, cancelled, simulated));
if (!diedToDirectDamage || cancelled.value || attacker!.hasAbilityWithAttr(BlockNonDirectDamageAbAttr)) {

View File

@ -346,7 +346,7 @@ export default class Move implements Localizable {
* @param target The {@linkcode Pokemon} targeted by this move
* @returns `true` if the move can bypass the target's Substitute; `false` otherwise.
*/
hitsSubstitute(user: Pokemon, target: Pokemon | null): boolean {
hitsSubstitute(user: Pokemon, target?: Pokemon): boolean {
if ([ MoveTarget.USER, MoveTarget.USER_SIDE, MoveTarget.ENEMY_SIDE, MoveTarget.BOTH_SIDES ].includes(this.moveTarget)
|| !target?.getTag(BattlerTagType.SUBSTITUTE)) {
return false;
@ -618,12 +618,30 @@ export default class Move implements Localizable {
/**
* Checks if the move flag applies to the pokemon(s) using/receiving the move
*
* This method will take the `user`'s ability into account when reporting flags, e.g.
* calling this method for {@linkcode MoveFlags.MAKES_CONTACT | MAKES_CONTACT}
* will return `false` if the user has a {@linkcode Abilities.LONG_REACH} that is not being suppressed.
*
* **Note:** This method only checks if the move should have effectively have the flag applied to its use.
* It does *not* check whether the flag will trigger related effects.
* For example using this method to check {@linkcode MoveFlags.WIND_MOVE}
* will not consider {@linkcode Abilities.WIND_RIDER | Wind Rider }.
*
* To simply check whether the move has a flag, use {@linkcode hasFlag}.
* @param flag {@linkcode MoveFlags} MoveFlag to check on user and/or target
* @param user {@linkcode Pokemon} the Pokemon using the move
* @param target {@linkcode Pokemon} the Pokemon receiving the move
* @param isFollowUp (defaults to `false`) `true` if the move was used as a follow up
* @returns boolean
* @see {@linkcode hasFlag}
*/
checkFlag(flag: MoveFlags, user: Pokemon, target: Pokemon | null): boolean {
doesFlagEffectApply({ flag, user, target, isFollowUp = false }: {
flag: MoveFlags;
user: Pokemon;
target?: Pokemon;
isFollowUp?: boolean;
}): boolean {
// special cases below, eg: if the move flag is MAKES_CONTACT, and the user pokemon has an ability that ignores contact (like "Long Reach"), then overrides and move does not make contact
switch (flag) {
case MoveFlags.MAKES_CONTACT:
@ -633,16 +651,18 @@ export default class Move implements Localizable {
break;
case MoveFlags.IGNORE_ABILITIES:
if (user.hasAbilityWithAttr(MoveAbilityBypassAbAttr)) {
const abilityEffectsIgnored = new Utils.BooleanHolder(false);
const abilityEffectsIgnored = new Utils.BooleanHolder(false);
applyAbAttrs(MoveAbilityBypassAbAttr, user, abilityEffectsIgnored, false, this);
if (abilityEffectsIgnored.value) {
return true;
}
// Sunsteel strike, Moongeist beam, and photon geyser will not ignore abilities if invoked
// by another move, such as via metronome.
}
break;
return this.hasFlag(MoveFlags.IGNORE_ABILITIES) && !isFollowUp;
case MoveFlags.IGNORE_PROTECT:
if (user.hasAbilityWithAttr(IgnoreProtectOnContactAbAttr)
&& this.checkFlag(MoveFlags.MAKES_CONTACT, user, null)) {
&& this.doesFlagEffectApply({ flag: MoveFlags.MAKES_CONTACT, user })) {
return true;
}
break;
@ -1214,7 +1234,7 @@ export class MoveEffectAttr extends MoveAttr {
canApply(user: Pokemon, target: Pokemon, move: Move, args?: any[]) {
return !! (this.selfTarget ? user.hp && !user.getTag(BattlerTagType.FRENZY) : target.hp)
&& (this.selfTarget || !target.getTag(BattlerTagType.PROTECTED) ||
move.checkFlag(MoveFlags.IGNORE_PROTECT, user, target));
move.doesFlagEffectApply({ flag: MoveFlags.IGNORE_PROTECT, user, target }));
}
/** Applies move effects so long as they are able based on {@linkcode canApply} */

View File

@ -289,7 +289,8 @@ export class MoveEffectPhase extends PokemonPhase {
/** Is the target protected by Protect, etc. or a relevant conditional protection effect? */
const isProtected =
![MoveTarget.ENEMY_SIDE, MoveTarget.BOTH_SIDES].includes(this.move.getMove().moveTarget) &&
(bypassIgnoreProtect.value || !this.move.getMove().checkFlag(MoveFlags.IGNORE_PROTECT, user, target)) &&
(bypassIgnoreProtect.value ||
!this.move.getMove().doesFlagEffectApply({ flag: MoveFlags.IGNORE_PROTECT, user, target })) &&
(hasConditionalProtectApplied.value ||
(!target.findTags(t => t instanceof DamageProtectedTag).length &&
target.findTags(t => t instanceof ProtectedTag).find(t => target.lapseTag(t.tagType))) ||
@ -307,7 +308,7 @@ export class MoveEffectPhase extends PokemonPhase {
/** Is the target's magic bounce ability not ignored and able to reflect this move? */
const canMagicBounce =
!isReflecting &&
!move.checkFlag(MoveFlags.IGNORE_ABILITIES, user, target) &&
!move.doesFlagEffectApply({ flag: MoveFlags.IGNORE_ABILITIES, user, target }) &&
target.hasAbilityWithAttr(ReflectStatusMoveAbAttr);
const semiInvulnerableTag = target.getTag(SemiInvulnerableTag);

View File

@ -168,7 +168,7 @@ export class MovePhase extends BattlePhase {
// Check move to see if arena.ignoreAbilities should be true.
if (!this.followUp || this.reflected) {
if (this.move.getMove().checkFlag(MoveFlags.IGNORE_ABILITIES, this.pokemon, null)) {
if (this.move.getMove().doesFlagEffectApply({ flag: MoveFlags.IGNORE_ABILITIES, user: this.pokemon, isFollowUp: this.followUp })) {
globalScene.arena.setIgnoreAbilities(true, this.pokemon.getBattlerIndex());
}
}