From 404199d22726d77fa8acea8772fd76ae36314543 Mon Sep 17 00:00:00 2001 From: Mason Date: Mon, 19 Aug 2024 19:36:36 -0400 Subject: [PATCH 1/6] [Refactor] Added ON_GET_HIT BattlerTagLapseType Adjusted BeakBlastChargingTag and ShellTrapTag to use new lapse type Adjusted MoveEffectPhase to now lapse all tags with the ON_GET_HIT lapse type --- src/data/battler-tags.ts | 120 ++++++++++++++++++++------------ src/field/pokemon.ts | 9 +++ src/phases/move-effect-phase.ts | 8 +-- 3 files changed, 89 insertions(+), 48 deletions(-) diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index ede8d0293271..59cdf933e6e9 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -1,28 +1,33 @@ -import { ChargeAnim, CommonAnim, CommonBattleAnim, MoveChargeAnim } from "./battle-anims"; -import { getPokemonNameWithAffix } from "../messages"; -import Pokemon, { MoveResult, HitResult } from "../field/pokemon"; -import { Stat, getStatName } from "./pokemon-stat"; -import { StatusEffect } from "./status-effect"; +import {ChargeAnim, CommonAnim, CommonBattleAnim, MoveChargeAnim} from "./battle-anims"; +import {getPokemonNameWithAffix} from "../messages"; +import Pokemon, {HitResult, MoveResult} from "../field/pokemon"; +import {getStatName, Stat} from "./pokemon-stat"; +import {StatusEffect} from "./status-effect"; import * as Utils from "../utils"; -import { ChargeAttr, MoveFlags, allMoves } from "./move"; -import { Type } from "./type"; -import { BlockNonDirectDamageAbAttr, FlinchEffectAbAttr, ReverseDrainAbAttr, applyAbAttrs } from "./ability"; -import { TerrainType } from "./terrain"; -import { WeatherType } from "./weather"; -import { BattleStat } from "./battle-stat"; -import { allAbilities } from "./ability"; -import { SpeciesFormChangeManualTrigger } from "./pokemon-forms"; -import { Abilities } from "#enums/abilities"; -import { BattlerTagType } from "#enums/battler-tag-type"; -import { Moves } from "#enums/moves"; -import { Species } from "#enums/species"; +import Move, {allMoves, ChargeAttr, MoveCategory, MoveFlags} from "./move"; +import {Type} from "./type"; +import { + allAbilities, + applyAbAttrs, + BlockNonDirectDamageAbAttr, + FlinchEffectAbAttr, + ReverseDrainAbAttr +} from "./ability"; +import {TerrainType} from "./terrain"; +import {WeatherType} from "./weather"; +import {BattleStat} from "./battle-stat"; +import {SpeciesFormChangeManualTrigger} from "./pokemon-forms"; +import {Abilities} from "#enums/abilities"; +import {BattlerTagType} from "#enums/battler-tag-type"; +import {Moves} from "#enums/moves"; +import {Species} from "#enums/species"; import i18next from "#app/plugins/i18n.js"; -import { CommonAnimPhase } from "#app/phases/common-anim-phase.js"; -import { MoveEffectPhase } from "#app/phases/move-effect-phase.js"; -import { MovePhase } from "#app/phases/move-phase.js"; -import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase.js"; -import { ShowAbilityPhase } from "#app/phases/show-ability-phase.js"; -import { StatChangePhase, StatChangeCallback } from "#app/phases/stat-change-phase.js"; +import {CommonAnimPhase} from "#app/phases/common-anim-phase.js"; +import {MoveEffectPhase} from "#app/phases/move-effect-phase.js"; +import {MovePhase} from "#app/phases/move-phase.js"; +import {PokemonHealPhase} from "#app/phases/pokemon-heal-phase.js"; +import {ShowAbilityPhase} from "#app/phases/show-ability-phase.js"; +import {StatChangeCallback, StatChangePhase} from "#app/phases/stat-change-phase.js"; export enum BattlerTagLapseType { FAINT, @@ -31,6 +36,7 @@ export enum BattlerTagLapseType { AFTER_MOVE, MOVE_EFFECT, TURN_END, + ON_GET_HIT, CUSTOM } @@ -123,6 +129,7 @@ export class RechargingTag extends BattlerTag { } } + /** * BattlerTag representing the "charge phase" of Beak Blast. * Pokemon with this tag will inflict BURN status on any attacker that makes contact. @@ -130,7 +137,7 @@ export class RechargingTag extends BattlerTag { */ export class BeakBlastChargingTag extends BattlerTag { constructor() { - super(BattlerTagType.BEAK_BLAST_CHARGING, [ BattlerTagLapseType.PRE_MOVE, BattlerTagLapseType.TURN_END ], 1, Moves.BEAK_BLAST); + super(BattlerTagType.BEAK_BLAST_CHARGING, [ BattlerTagLapseType.PRE_MOVE, BattlerTagLapseType.TURN_END, BattlerTagLapseType.ON_GET_HIT], 1, Moves.BEAK_BLAST); } onAdd(pokemon: Pokemon): void { @@ -146,14 +153,13 @@ export class BeakBlastChargingTag extends BattlerTag { * to be removed after the source makes a move (or the turn ends, whichever comes first) * @param pokemon {@linkcode Pokemon} the owner of this tag * @param lapseType {@linkcode BattlerTagLapseType} the type of functionality invoked in battle - * @returns `true` if invoked with the CUSTOM lapse type; `false` otherwise + * @returns `true` if invoked with the ON_GET_HIT lapse type; `false` otherwise */ lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { - if (lapseType === BattlerTagLapseType.CUSTOM) { - const effectPhase = pokemon.scene.getCurrentPhase(); - if (effectPhase instanceof MoveEffectPhase && effectPhase.move.getMove().hasFlag(MoveFlags.MAKES_CONTACT)) { - const attacker = effectPhase.getPokemon(); - attacker.trySetStatus(StatusEffect.BURN, true, pokemon); + if (lapseType === BattlerTagLapseType.ON_GET_HIT) { + const phaseData = getMoveEffectPhaseData(pokemon); + if (phaseData?.move.hasFlag(MoveFlags.MAKES_CONTACT)) { + phaseData.attacker.trySetStatus(StatusEffect.BURN, true, pokemon); } return true; } @@ -170,7 +176,7 @@ export class ShellTrapTag extends BattlerTag { public activated: boolean; constructor() { - super(BattlerTagType.SHELL_TRAP, BattlerTagLapseType.TURN_END, 1); + super(BattlerTagType.SHELL_TRAP, [BattlerTagLapseType.TURN_END, BattlerTagLapseType.ON_GET_HIT], 1); this.activated = false; } @@ -185,24 +191,34 @@ export class ShellTrapTag extends BattlerTag { * @returns `true` if invoked with the `CUSTOM` lapse type; `false` otherwise */ lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { - if (lapseType === BattlerTagLapseType.CUSTOM) { - const shellTrapPhaseIndex = pokemon.scene.phaseQueue.findIndex( - phase => phase instanceof MovePhase && phase.pokemon === pokemon - ); - const firstMovePhaseIndex = pokemon.scene.phaseQueue.findIndex( - phase => phase instanceof MovePhase - ); + if (lapseType === BattlerTagLapseType.ON_GET_HIT) { + const phaseData = getMoveEffectPhaseData(pokemon); - if (shellTrapPhaseIndex !== -1 && shellTrapPhaseIndex !== firstMovePhaseIndex) { - const shellTrapMovePhase = pokemon.scene.phaseQueue.splice(shellTrapPhaseIndex, 1)[0]; - pokemon.scene.prependToPhase(shellTrapMovePhase, MovePhase); + /* Trap should only be triggered by opponent's Physical moves */ + if (phaseData?.move.category === MoveCategory.PHYSICAL && pokemon.isOpponentTo(phaseData.attacker)) { + this.triggerTrap(pokemon); } - this.activated = true; return true; } return super.lapse(pokemon, lapseType); } + + private triggerTrap(pokemon: Pokemon) { + const shellTrapPhaseIndex = pokemon.scene.phaseQueue.findIndex( + phase => phase instanceof MovePhase && phase.pokemon === pokemon + ); + const firstMovePhaseIndex = pokemon.scene.phaseQueue.findIndex( + phase => phase instanceof MovePhase + ); + + if (shellTrapPhaseIndex !== -1 && shellTrapPhaseIndex !== firstMovePhaseIndex) { + const shellTrapMovePhase = pokemon.scene.phaseQueue.splice(shellTrapPhaseIndex, 1)[0]; + pokemon.scene.prependToPhase(shellTrapMovePhase, MovePhase); + } + + this.activated = true; + } } export class TrappedTag extends BattlerTag { @@ -1827,7 +1843,6 @@ export class ExposedTag extends BattlerTag { } } - export function getBattlerTag(tagType: BattlerTagType, turnCount: number, sourceMove: Moves, sourceId: number): BattlerTag { switch (tagType) { case BattlerTagType.RECHARGING: @@ -1978,3 +1993,22 @@ export function loadBattlerTag(source: BattlerTag | any): BattlerTag { tag.loadTag(source); return tag; } + +/** + * Helper function to verify that the current phase is a MoveEffectPhase and provide quick access to commonly used fields + * + * @param pokemon {@linkcode Pokemon} The Pokémon used to access the current phase + * @returns null if current phase is not MoveEffectPhase, otherwise Object containing the {@linkcode MoveEffectPhase}, and its + * corresponding {@linkcode Move} and user {@linkcode Pokemon} + */ +function getMoveEffectPhaseData(pokemon : Pokemon) : {phase : MoveEffectPhase, attacker: Pokemon, move: Move } | null { + const phase = pokemon.scene.getCurrentPhase(); + if (phase instanceof MoveEffectPhase) { + return { + phase : phase, + attacker : phase.getPokemon(), + move : phase.move.getMove() + }; + } + return null; +} diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 6a445a83b4ea..b0453192d576 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -1866,6 +1866,15 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { this.levelExp = this.exp - getLevelTotalExp(this.level, this.species.growthRate); } + /** + * Compares if 'this' and {@linkcode target} are on the same team. + * @param target the {@linkcode Pokemon} to compare against. + * @returns true if the two pokemon are both player owned or both not, false otherwise + */ + isOpponentTo(target: Pokemon) : boolean { + return this.isPlayer() !== target.isPlayer(); + } + getOpponent(targetIndex: integer): Pokemon | null { const ret = this.getOpponents()[targetIndex]; if (ret.summonData) { diff --git a/src/phases/move-effect-phase.ts b/src/phases/move-effect-phase.ts index a5ac913cc5dc..c5b9fce74a59 100644 --- a/src/phases/move-effect-phase.ts +++ b/src/phases/move-effect-phase.ts @@ -4,7 +4,7 @@ import { applyPreAttackAbAttrs, AddSecondStrikeAbAttr, IgnoreMoveEffectsAbAttr, import { ArenaTagSide, ConditionalProtectTag } from "#app/data/arena-tag.js"; import { MoveAnim } from "#app/data/battle-anims.js"; import { BattlerTagLapseType, ProtectedTag, SemiInvulnerableTag } from "#app/data/battler-tags.js"; -import { MoveTarget, applyMoveAttrs, OverrideMoveEffectAttr, MultiHitAttr, AttackMove, FixedDamageAttr, VariableTargetAttr, MissEffectAttr, MoveFlags, applyFilteredMoveAttrs, MoveAttr, MoveEffectAttr, MoveEffectTrigger, ChargeAttr, MoveCategory, NoEffectAttr, HitsTagAttr } from "#app/data/move.js"; +import { MoveTarget, applyMoveAttrs, OverrideMoveEffectAttr, MultiHitAttr, AttackMove, FixedDamageAttr, VariableTargetAttr, MissEffectAttr, MoveFlags, applyFilteredMoveAttrs, MoveAttr, MoveEffectAttr, MoveEffectTrigger, ChargeAttr, NoEffectAttr, HitsTagAttr } from "#app/data/move.js"; import { SpeciesFormChangePostMoveTrigger } from "#app/data/pokemon-forms.js"; import { BattlerTagType } from "#app/enums/battler-tag-type.js"; import { Moves } from "#app/enums/moves.js"; @@ -258,10 +258,8 @@ export class MoveEffectPhase extends PokemonPhase { // Apply the target's post-defend ability effects (as long as the target is active or can otherwise apply them) return Utils.executeIf(!target.isFainted() || target.canApplyAbility(), () => applyPostDefendAbAttrs(PostDefendAbAttr, target, user, this.move.getMove(), hitResult).then(() => { // If the invoked move is an enemy attack, apply the enemy's status effect-inflicting tags and tokens - target.lapseTag(BattlerTagType.BEAK_BLAST_CHARGING); - if (move.category === MoveCategory.PHYSICAL && user.isPlayer() !== target.isPlayer()) { - target.lapseTag(BattlerTagType.SHELL_TRAP); - } + target.lapseTags(BattlerTagLapseType.ON_GET_HIT); + if (!user.isPlayer() && this.move.getMove() instanceof AttackMove) { user.scene.applyShuffledModifiers(this.scene, EnemyAttackStatusEffectChanceModifier, false, target); } From c9ec53f945a2eb95f0406bf7127281bce87cb04a Mon Sep 17 00:00:00 2001 From: Mason Date: Mon, 19 Aug 2024 19:36:36 -0400 Subject: [PATCH 2/6] [Refactor] Added ON_GET_HIT BattlerTagLapseType Adjusted BeakBlastChargingTag and ShellTrapTag to use new lapse type Adjusted MoveEffectPhase to now lapse all tags with the ON_GET_HIT lapse type --- src/data/battler-tags.ts | 71 +++++++++++++++++++++++---------- src/field/pokemon.ts | 9 +++++ src/phases/move-effect-phase.ts | 8 ++-- 3 files changed, 62 insertions(+), 26 deletions(-) diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index ede8d0293271..69a323ce8809 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -4,7 +4,7 @@ import Pokemon, { MoveResult, HitResult } from "../field/pokemon"; import { Stat, getStatName } from "./pokemon-stat"; import { StatusEffect } from "./status-effect"; import * as Utils from "../utils"; -import { ChargeAttr, MoveFlags, allMoves } from "./move"; +import Move, { ChargeAttr, MoveFlags, allMoves, MoveCategory } from "./move"; import { Type } from "./type"; import { BlockNonDirectDamageAbAttr, FlinchEffectAbAttr, ReverseDrainAbAttr, applyAbAttrs } from "./ability"; import { TerrainType } from "./terrain"; @@ -31,6 +31,7 @@ export enum BattlerTagLapseType { AFTER_MOVE, MOVE_EFFECT, TURN_END, + ON_GET_HIT, CUSTOM } @@ -123,6 +124,7 @@ export class RechargingTag extends BattlerTag { } } + /** * BattlerTag representing the "charge phase" of Beak Blast. * Pokemon with this tag will inflict BURN status on any attacker that makes contact. @@ -130,7 +132,7 @@ export class RechargingTag extends BattlerTag { */ export class BeakBlastChargingTag extends BattlerTag { constructor() { - super(BattlerTagType.BEAK_BLAST_CHARGING, [ BattlerTagLapseType.PRE_MOVE, BattlerTagLapseType.TURN_END ], 1, Moves.BEAK_BLAST); + super(BattlerTagType.BEAK_BLAST_CHARGING, [ BattlerTagLapseType.PRE_MOVE, BattlerTagLapseType.TURN_END, BattlerTagLapseType.ON_GET_HIT], 1, Moves.BEAK_BLAST); } onAdd(pokemon: Pokemon): void { @@ -146,14 +148,13 @@ export class BeakBlastChargingTag extends BattlerTag { * to be removed after the source makes a move (or the turn ends, whichever comes first) * @param pokemon {@linkcode Pokemon} the owner of this tag * @param lapseType {@linkcode BattlerTagLapseType} the type of functionality invoked in battle - * @returns `true` if invoked with the CUSTOM lapse type; `false` otherwise + * @returns `true` if invoked with the ON_GET_HIT lapse type; `false` otherwise */ lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { - if (lapseType === BattlerTagLapseType.CUSTOM) { - const effectPhase = pokemon.scene.getCurrentPhase(); - if (effectPhase instanceof MoveEffectPhase && effectPhase.move.getMove().hasFlag(MoveFlags.MAKES_CONTACT)) { - const attacker = effectPhase.getPokemon(); - attacker.trySetStatus(StatusEffect.BURN, true, pokemon); + if (lapseType === BattlerTagLapseType.ON_GET_HIT) { + const phaseData = getMoveEffectPhaseData(pokemon); + if (phaseData?.move.hasFlag(MoveFlags.MAKES_CONTACT)) { + phaseData.attacker.trySetStatus(StatusEffect.BURN, true, pokemon); } return true; } @@ -170,7 +171,7 @@ export class ShellTrapTag extends BattlerTag { public activated: boolean; constructor() { - super(BattlerTagType.SHELL_TRAP, BattlerTagLapseType.TURN_END, 1); + super(BattlerTagType.SHELL_TRAP, [BattlerTagLapseType.TURN_END, BattlerTagLapseType.ON_GET_HIT], 1); this.activated = false; } @@ -185,24 +186,34 @@ export class ShellTrapTag extends BattlerTag { * @returns `true` if invoked with the `CUSTOM` lapse type; `false` otherwise */ lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { - if (lapseType === BattlerTagLapseType.CUSTOM) { - const shellTrapPhaseIndex = pokemon.scene.phaseQueue.findIndex( - phase => phase instanceof MovePhase && phase.pokemon === pokemon - ); - const firstMovePhaseIndex = pokemon.scene.phaseQueue.findIndex( - phase => phase instanceof MovePhase - ); + if (lapseType === BattlerTagLapseType.ON_GET_HIT) { + const phaseData = getMoveEffectPhaseData(pokemon); - if (shellTrapPhaseIndex !== -1 && shellTrapPhaseIndex !== firstMovePhaseIndex) { - const shellTrapMovePhase = pokemon.scene.phaseQueue.splice(shellTrapPhaseIndex, 1)[0]; - pokemon.scene.prependToPhase(shellTrapMovePhase, MovePhase); + /* Trap should only be triggered by opponent's Physical moves */ + if (phaseData?.move.category === MoveCategory.PHYSICAL && pokemon.isOpponentTo(phaseData.attacker)) { + this.triggerTrap(pokemon); } - this.activated = true; return true; } return super.lapse(pokemon, lapseType); } + + private triggerTrap(pokemon: Pokemon) { + const shellTrapPhaseIndex = pokemon.scene.phaseQueue.findIndex( + phase => phase instanceof MovePhase && phase.pokemon === pokemon + ); + const firstMovePhaseIndex = pokemon.scene.phaseQueue.findIndex( + phase => phase instanceof MovePhase + ); + + if (shellTrapPhaseIndex !== -1 && shellTrapPhaseIndex !== firstMovePhaseIndex) { + const shellTrapMovePhase = pokemon.scene.phaseQueue.splice(shellTrapPhaseIndex, 1)[0]; + pokemon.scene.prependToPhase(shellTrapMovePhase, MovePhase); + } + + this.activated = true; + } } export class TrappedTag extends BattlerTag { @@ -1827,7 +1838,6 @@ export class ExposedTag extends BattlerTag { } } - export function getBattlerTag(tagType: BattlerTagType, turnCount: number, sourceMove: Moves, sourceId: number): BattlerTag { switch (tagType) { case BattlerTagType.RECHARGING: @@ -1978,3 +1988,22 @@ export function loadBattlerTag(source: BattlerTag | any): BattlerTag { tag.loadTag(source); return tag; } + +/** + * Helper function to verify that the current phase is a MoveEffectPhase and provide quick access to commonly used fields + * + * @param pokemon {@linkcode Pokemon} The Pokémon used to access the current phase + * @returns null if current phase is not MoveEffectPhase, otherwise Object containing the {@linkcode MoveEffectPhase}, and its + * corresponding {@linkcode Move} and user {@linkcode Pokemon} + */ +function getMoveEffectPhaseData(pokemon : Pokemon) : {phase : MoveEffectPhase, attacker: Pokemon, move: Move } | null { + const phase = pokemon.scene.getCurrentPhase(); + if (phase instanceof MoveEffectPhase) { + return { + phase : phase, + attacker : phase.getPokemon(), + move : phase.move.getMove() + }; + } + return null; +} diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 6a445a83b4ea..b0453192d576 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -1866,6 +1866,15 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { this.levelExp = this.exp - getLevelTotalExp(this.level, this.species.growthRate); } + /** + * Compares if 'this' and {@linkcode target} are on the same team. + * @param target the {@linkcode Pokemon} to compare against. + * @returns true if the two pokemon are both player owned or both not, false otherwise + */ + isOpponentTo(target: Pokemon) : boolean { + return this.isPlayer() !== target.isPlayer(); + } + getOpponent(targetIndex: integer): Pokemon | null { const ret = this.getOpponents()[targetIndex]; if (ret.summonData) { diff --git a/src/phases/move-effect-phase.ts b/src/phases/move-effect-phase.ts index a5ac913cc5dc..c5b9fce74a59 100644 --- a/src/phases/move-effect-phase.ts +++ b/src/phases/move-effect-phase.ts @@ -4,7 +4,7 @@ import { applyPreAttackAbAttrs, AddSecondStrikeAbAttr, IgnoreMoveEffectsAbAttr, import { ArenaTagSide, ConditionalProtectTag } from "#app/data/arena-tag.js"; import { MoveAnim } from "#app/data/battle-anims.js"; import { BattlerTagLapseType, ProtectedTag, SemiInvulnerableTag } from "#app/data/battler-tags.js"; -import { MoveTarget, applyMoveAttrs, OverrideMoveEffectAttr, MultiHitAttr, AttackMove, FixedDamageAttr, VariableTargetAttr, MissEffectAttr, MoveFlags, applyFilteredMoveAttrs, MoveAttr, MoveEffectAttr, MoveEffectTrigger, ChargeAttr, MoveCategory, NoEffectAttr, HitsTagAttr } from "#app/data/move.js"; +import { MoveTarget, applyMoveAttrs, OverrideMoveEffectAttr, MultiHitAttr, AttackMove, FixedDamageAttr, VariableTargetAttr, MissEffectAttr, MoveFlags, applyFilteredMoveAttrs, MoveAttr, MoveEffectAttr, MoveEffectTrigger, ChargeAttr, NoEffectAttr, HitsTagAttr } from "#app/data/move.js"; import { SpeciesFormChangePostMoveTrigger } from "#app/data/pokemon-forms.js"; import { BattlerTagType } from "#app/enums/battler-tag-type.js"; import { Moves } from "#app/enums/moves.js"; @@ -258,10 +258,8 @@ export class MoveEffectPhase extends PokemonPhase { // Apply the target's post-defend ability effects (as long as the target is active or can otherwise apply them) return Utils.executeIf(!target.isFainted() || target.canApplyAbility(), () => applyPostDefendAbAttrs(PostDefendAbAttr, target, user, this.move.getMove(), hitResult).then(() => { // If the invoked move is an enemy attack, apply the enemy's status effect-inflicting tags and tokens - target.lapseTag(BattlerTagType.BEAK_BLAST_CHARGING); - if (move.category === MoveCategory.PHYSICAL && user.isPlayer() !== target.isPlayer()) { - target.lapseTag(BattlerTagType.SHELL_TRAP); - } + target.lapseTags(BattlerTagLapseType.ON_GET_HIT); + if (!user.isPlayer() && this.move.getMove() instanceof AttackMove) { user.scene.applyShuffledModifiers(this.scene, EnemyAttackStatusEffectChanceModifier, false, target); } From e91415b1211f9b03ee2607159ae7fc853a400459 Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Fri, 20 Sep 2024 22:40:24 -0700 Subject: [PATCH 3/6] Fix nits --- src/data/battler-tags.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index 69a323ce8809..235a03345a07 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -132,7 +132,7 @@ export class RechargingTag extends BattlerTag { */ export class BeakBlastChargingTag extends BattlerTag { constructor() { - super(BattlerTagType.BEAK_BLAST_CHARGING, [ BattlerTagLapseType.PRE_MOVE, BattlerTagLapseType.TURN_END, BattlerTagLapseType.ON_GET_HIT], 1, Moves.BEAK_BLAST); + super(BattlerTagType.BEAK_BLAST_CHARGING, [BattlerTagLapseType.PRE_MOVE, BattlerTagLapseType.TURN_END, BattlerTagLapseType.ON_GET_HIT], 1, Moves.BEAK_BLAST); } onAdd(pokemon: Pokemon): void { @@ -1996,7 +1996,7 @@ export function loadBattlerTag(source: BattlerTag | any): BattlerTag { * @returns null if current phase is not MoveEffectPhase, otherwise Object containing the {@linkcode MoveEffectPhase}, and its * corresponding {@linkcode Move} and user {@linkcode Pokemon} */ -function getMoveEffectPhaseData(pokemon : Pokemon) : {phase : MoveEffectPhase, attacker: Pokemon, move: Move } | null { +function getMoveEffectPhaseData(pokemon: Pokemon): {phase: MoveEffectPhase, attacker: Pokemon, move: Move} | null { const phase = pokemon.scene.getCurrentPhase(); if (phase instanceof MoveEffectPhase) { return { From 5de76ca9aeb3f9559a2cbe9a97e1bb1429064936 Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Sun, 13 Oct 2024 22:41:34 -0700 Subject: [PATCH 4/6] Rename `ON_GET_HIT` to `AFTER_HIT` Change `isOpponentTo` to `isOpponent` --- src/data/battler-tags.ts | 10 +++++----- src/field/pokemon.ts | 6 +++--- src/phases/move-effect-phase.ts | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index 235a03345a07..f12816f4303a 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -132,7 +132,7 @@ export class RechargingTag extends BattlerTag { */ export class BeakBlastChargingTag extends BattlerTag { constructor() { - super(BattlerTagType.BEAK_BLAST_CHARGING, [BattlerTagLapseType.PRE_MOVE, BattlerTagLapseType.TURN_END, BattlerTagLapseType.ON_GET_HIT], 1, Moves.BEAK_BLAST); + super(BattlerTagType.BEAK_BLAST_CHARGING, [BattlerTagLapseType.PRE_MOVE, BattlerTagLapseType.TURN_END, BattlerTagLapseType.AFTER_HIT], 1, Moves.BEAK_BLAST); } onAdd(pokemon: Pokemon): void { @@ -151,7 +151,7 @@ export class BeakBlastChargingTag extends BattlerTag { * @returns `true` if invoked with the ON_GET_HIT lapse type; `false` otherwise */ lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { - if (lapseType === BattlerTagLapseType.ON_GET_HIT) { + if (lapseType === BattlerTagLapseType.AFTER_HIT) { const phaseData = getMoveEffectPhaseData(pokemon); if (phaseData?.move.hasFlag(MoveFlags.MAKES_CONTACT)) { phaseData.attacker.trySetStatus(StatusEffect.BURN, true, pokemon); @@ -171,7 +171,7 @@ export class ShellTrapTag extends BattlerTag { public activated: boolean; constructor() { - super(BattlerTagType.SHELL_TRAP, [BattlerTagLapseType.TURN_END, BattlerTagLapseType.ON_GET_HIT], 1); + super(BattlerTagType.SHELL_TRAP, [BattlerTagLapseType.TURN_END, BattlerTagLapseType.AFTER_HIT], 1); this.activated = false; } @@ -186,11 +186,11 @@ export class ShellTrapTag extends BattlerTag { * @returns `true` if invoked with the `CUSTOM` lapse type; `false` otherwise */ lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { - if (lapseType === BattlerTagLapseType.ON_GET_HIT) { + if (lapseType === BattlerTagLapseType.AFTER_HIT) { const phaseData = getMoveEffectPhaseData(pokemon); /* Trap should only be triggered by opponent's Physical moves */ - if (phaseData?.move.category === MoveCategory.PHYSICAL && pokemon.isOpponentTo(phaseData.attacker)) { + if (phaseData?.move.category === MoveCategory.PHYSICAL && pokemon.isOpponent(phaseData.attacker)) { this.triggerTrap(pokemon); } diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index b0453192d576..081e58b9628a 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -1867,11 +1867,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { } /** - * Compares if 'this' and {@linkcode target} are on the same team. + * Compares if `this` and {@linkcode target} are on the same team. * @param target the {@linkcode Pokemon} to compare against. - * @returns true if the two pokemon are both player owned or both not, false otherwise + * @returns `true` if the two pokemon are allies, `false` otherwise */ - isOpponentTo(target: Pokemon) : boolean { + isOpponent(target: Pokemon): boolean { return this.isPlayer() !== target.isPlayer(); } diff --git a/src/phases/move-effect-phase.ts b/src/phases/move-effect-phase.ts index c5b9fce74a59..ae3c54d3fcdb 100644 --- a/src/phases/move-effect-phase.ts +++ b/src/phases/move-effect-phase.ts @@ -258,7 +258,7 @@ export class MoveEffectPhase extends PokemonPhase { // Apply the target's post-defend ability effects (as long as the target is active or can otherwise apply them) return Utils.executeIf(!target.isFainted() || target.canApplyAbility(), () => applyPostDefendAbAttrs(PostDefendAbAttr, target, user, this.move.getMove(), hitResult).then(() => { // If the invoked move is an enemy attack, apply the enemy's status effect-inflicting tags and tokens - target.lapseTags(BattlerTagLapseType.ON_GET_HIT); + target.lapseTags(BattlerTagLapseType.AFTER_HIT); if (!user.isPlayer() && this.move.getMove() instanceof AttackMove) { user.scene.applyShuffledModifiers(this.scene, EnemyAttackStatusEffectChanceModifier, false, target); From e04c246ab94627fb364a5a5ff064bcf1e5b09cb7 Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Sun, 20 Oct 2024 22:51:36 -0700 Subject: [PATCH 5/6] Fix a couple minor nits --- src/data/battler-tags.ts | 53 +++++++++++++++++++++++----------------- src/field/pokemon.ts | 2 +- 2 files changed, 32 insertions(+), 23 deletions(-) diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index a4dae95f8981..aba9b74c60ba 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -1,35 +1,44 @@ +import BattleScene from "#app/battle-scene"; +import { + allAbilities, + applyAbAttrs, + BlockNonDirectDamageAbAttr, + FlinchEffectAbAttr, + ProtectStatAbAttr, + ReverseDrainAbAttr +} from "#app/data/ability"; import { ChargeAnim, CommonAnim, CommonBattleAnim, MoveChargeAnim } from "#app/data/battle-anims"; -import { getPokemonNameWithAffix } from "#app/messages"; -import Pokemon, { MoveResult, HitResult } from "#app/field/pokemon"; -import { StatusEffect } from "#app/data/status-effect"; -import { toDmgValue, BooleanHolder, getFrameMs, NumberHolder } from "#app/utils"; import Move, { - ChargeAttr, MoveFlags, allMoves, MoveCategory, applyMoveAttrs, - StatusCategoryOnAllyAttr, HealOnAllyAttr, ConsecutiveUseDoublePowerAttr + allMoves, + applyMoveAttrs, + ChargeAttr, + ConsecutiveUseDoublePowerAttr, + HealOnAllyAttr, + MoveCategory, + MoveFlags, + StatusCategoryOnAllyAttr } from "#app/data/move"; -import { Type } from "#app/data/type"; -import { - BlockNonDirectDamageAbAttr, FlinchEffectAbAttr, - ReverseDrainAbAttr, applyAbAttrs, ProtectStatAbAttr -} from "#app/data/ability"; +import { SpeciesFormChangeManualTrigger } from "#app/data/pokemon-forms"; +import { StatusEffect } from "#app/data/status-effect"; import { TerrainType } from "#app/data/terrain"; +import { Type } from "#app/data/type"; import { WeatherType } from "#app/data/weather"; -import { allAbilities } from "#app/data/ability"; -import { SpeciesFormChangeManualTrigger } from "#app/data/pokemon-forms"; -import { Abilities } from "#enums/abilities"; -import { BattlerTagType } from "#enums/battler-tag-type"; -import { Moves } from "#enums/moves"; -import { Species } from "#enums/species"; -import i18next from "#app/plugins/i18n"; -import { Stat, type BattleStat, type EffectiveStat, EFFECTIVE_STATS, getStatKey } from "#enums/stat"; +import Pokemon, { HitResult, MoveResult } from "#app/field/pokemon"; +import { getPokemonNameWithAffix } from "#app/messages"; import { CommonAnimPhase } from "#app/phases/common-anim-phase"; import { MoveEffectPhase } from "#app/phases/move-effect-phase"; import { MovePhase } from "#app/phases/move-phase"; import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase"; import { ShowAbilityPhase } from "#app/phases/show-ability-phase"; -import { StatStageChangePhase, StatStageChangeCallback } from "#app/phases/stat-stage-change-phase"; +import { StatStageChangeCallback, StatStageChangePhase } from "#app/phases/stat-stage-change-phase"; +import i18next from "#app/plugins/i18n"; +import { BooleanHolder, getFrameMs, NumberHolder, toDmgValue } from "#app/utils"; +import { Abilities } from "#enums/abilities"; +import { BattlerTagType } from "#enums/battler-tag-type"; +import { Moves } from "#enums/moves"; import { PokemonAnimType } from "#enums/pokemon-anim-type"; -import BattleScene from "#app/battle-scene"; +import { Species } from "#enums/species"; +import { EFFECTIVE_STATS, getStatKey, Stat, type BattleStat, type EffectiveStat } from "#enums/stat"; export enum BattlerTagLapseType { FAINT, @@ -428,7 +437,7 @@ export class BeakBlastChargingTag extends BattlerTag { * to be removed after the source makes a move (or the turn ends, whichever comes first) * @param pokemon {@linkcode Pokemon} the owner of this tag * @param lapseType {@linkcode BattlerTagLapseType} the type of functionality invoked in battle - * @returns `true` if invoked with the ON_GET_HIT lapse type; `false` otherwise + * @returns `true` if invoked with the `AFTER_HIT` lapse type; `false` otherwise */ lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { if (lapseType === BattlerTagLapseType.AFTER_HIT) { diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 68e203b15d83..dcbedaeca3b4 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -2295,7 +2295,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { * @param target the {@linkcode Pokemon} to compare against. * @returns `true` if the two pokemon are allies, `false` otherwise */ - isOpponent(target: Pokemon): boolean { + public isOpponent(target: Pokemon): boolean { return this.isPlayer() !== target.isPlayer(); } From e68a9d46894ac9ce1088d687373e79e4faceebcd Mon Sep 17 00:00:00 2001 From: NightKev <34855794+DayKev@users.noreply.github.com> Date: Mon, 21 Oct 2024 02:45:09 -0700 Subject: [PATCH 6/6] Remove single-use function --- src/data/battler-tags.ts | 41 +++++++++++++++++++--------------------- 1 file changed, 19 insertions(+), 22 deletions(-) diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index aba9b74c60ba..75d2d7dcdc5b 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -437,7 +437,7 @@ export class BeakBlastChargingTag extends BattlerTag { * to be removed after the source makes a move (or the turn ends, whichever comes first) * @param pokemon {@linkcode Pokemon} the owner of this tag * @param lapseType {@linkcode BattlerTagLapseType} the type of functionality invoked in battle - * @returns `true` if invoked with the `AFTER_HIT` lapse type; `false` otherwise + * @returns `true` if invoked with the `AFTER_HIT` lapse type */ lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { if (lapseType === BattlerTagLapseType.AFTER_HIT) { @@ -457,11 +457,10 @@ export class BeakBlastChargingTag extends BattlerTag { * @see {@link https://bulbapedia.bulbagarden.net/wiki/Shell_Trap_(move) | Shell Trap} */ export class ShellTrapTag extends BattlerTag { - public activated: boolean; + public activated: boolean = false; constructor() { super(BattlerTagType.SHELL_TRAP, [ BattlerTagLapseType.TURN_END, BattlerTagLapseType.AFTER_HIT ], 1); - this.activated = false; } onAdd(pokemon: Pokemon): void { @@ -472,36 +471,34 @@ export class ShellTrapTag extends BattlerTag { * "Activates" the shell trap, causing the tag owner to move next. * @param pokemon {@linkcode Pokemon} the owner of this tag * @param lapseType {@linkcode BattlerTagLapseType} the type of functionality invoked in battle - * @returns `true` if invoked with the `CUSTOM` lapse type; `false` otherwise + * @returns `true` if invoked with the `AFTER_HIT` lapse type */ lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { if (lapseType === BattlerTagLapseType.AFTER_HIT) { const phaseData = getMoveEffectPhaseData(pokemon); - /* Trap should only be triggered by opponent's Physical moves */ + // Trap should only be triggered by opponent's Physical moves if (phaseData?.move.category === MoveCategory.PHYSICAL && pokemon.isOpponent(phaseData.attacker)) { - this.triggerTrap(pokemon); - } + const shellTrapPhaseIndex = pokemon.scene.phaseQueue.findIndex( + phase => phase instanceof MovePhase && phase.pokemon === pokemon + ); + const firstMovePhaseIndex = pokemon.scene.phaseQueue.findIndex( + phase => phase instanceof MovePhase + ); - return true; - } - return super.lapse(pokemon, lapseType); - } + // Only shift MovePhase timing if it's not already next up + if (shellTrapPhaseIndex !== -1 && shellTrapPhaseIndex !== firstMovePhaseIndex) { + const shellTrapMovePhase = pokemon.scene.phaseQueue.splice(shellTrapPhaseIndex, 1)[0]; + pokemon.scene.prependToPhase(shellTrapMovePhase, MovePhase); + } - private triggerTrap(pokemon: Pokemon) { - const shellTrapPhaseIndex = pokemon.scene.phaseQueue.findIndex( - phase => phase instanceof MovePhase && phase.pokemon === pokemon - ); - const firstMovePhaseIndex = pokemon.scene.phaseQueue.findIndex( - phase => phase instanceof MovePhase - ); + this.activated = true; + } - if (shellTrapPhaseIndex !== -1 && shellTrapPhaseIndex !== firstMovePhaseIndex) { - const shellTrapMovePhase = pokemon.scene.phaseQueue.splice(shellTrapPhaseIndex, 1)[0]; - pokemon.scene.prependToPhase(shellTrapMovePhase, MovePhase); + return true; } - this.activated = true; + return super.lapse(pokemon, lapseType); } }