From 30ab803df9f35c8f9925047a94a4745b3ccdf9de Mon Sep 17 00:00:00 2001 From: Dean Date: Sat, 14 Jun 2025 21:47:10 -0700 Subject: [PATCH] Update findPhase to also check dynamic queues --- src/battle-scene.ts | 2 +- src/data/abilities/ability.ts | 2 +- src/data/battler-tags.ts | 2 +- src/data/moves/move.ts | 9 ++++----- src/phase-manager.ts | 20 +++++++++++++------- src/phases/egg-hatch-phase.ts | 2 +- src/phases/mystery-encounter-phases.ts | 2 +- src/phases/quiet-form-change-phase.ts | 5 +---- src/phases/stat-stage-change-phase.ts | 7 ++++--- src/queues/dynamic-queue-manager.ts | 4 ++++ src/queues/phase-priority-queue.ts | 4 ++++ 11 files changed, 35 insertions(+), 24 deletions(-) diff --git a/src/battle-scene.ts b/src/battle-scene.ts index 81c65d85e06..a3e51a734ac 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -861,8 +861,8 @@ export default class BattleScene extends SceneBase { let targetingMovePhase: MovePhase; do { targetingMovePhase = this.phaseManager.findPhase( + "MovePhase", mp => - mp.is("MovePhase") && mp.targets.length === 1 && mp.targets[0] === removedPokemon.getBattlerIndex() && mp.pokemon.isPlayer() !== allyPokemon.isPlayer(), diff --git a/src/data/abilities/ability.ts b/src/data/abilities/ability.ts index 77aa74b90e4..066b8f538fb 100644 --- a/src/data/abilities/ability.ts +++ b/src/data/abilities/ability.ts @@ -8407,7 +8407,7 @@ export function initAbilities() { .ignorable(), new Ability(AbilityId.ANALYTIC, 5) .attr(MovePowerBoostAbAttr, (user, _target, _move) => { - const movePhase = globalScene.phaseManager.findPhase((phase) => phase.is("MovePhase") && phase.pokemon.id !== user?.id); + const movePhase = globalScene.phaseManager.findPhase("MovePhase", (phase) => phase.is("MovePhase") && phase.pokemon.id !== user?.id); return isNullOrUndefined(movePhase); }, 1.3), new Ability(AbilityId.ILLUSION, 5) diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index 630388b805b..2cbe960ddff 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -1151,7 +1151,7 @@ export class EncoreTag extends MoveRestrictionBattlerTag { }), ); - const movePhase = globalScene.phaseManager.findPhase(m => m.is("MovePhase") && m.pokemon === pokemon); + const movePhase = globalScene.phaseManager.findPhase("MovePhase", (m: MovePhase) => m.pokemon === pokemon); if (movePhase) { const movesetMove = pokemon.getMoveset().find(m => m.moveId === this.moveId); if (movesetMove) { diff --git a/src/data/moves/move.ts b/src/data/moves/move.ts index d526e7c4f8b..ec92aadb504 100644 --- a/src/data/moves/move.ts +++ b/src/data/moves/move.ts @@ -3171,7 +3171,7 @@ export class AwaitCombinedPledgeAttr extends OverrideMoveEffectAttr { const overridden = args[0] as BooleanHolder; - const allyMovePhase = globalScene.phaseManager.findPhase((phase) => phase.is("MovePhase") && phase.pokemon.isPlayer() === user.isPlayer()); + const allyMovePhase = globalScene.phaseManager.findPhase("MovePhase", (phase) => phase.pokemon.isPlayer() === user.isPlayer()); if (allyMovePhase) { const allyMove = allyMovePhase.move.getMove(); if (allyMove !== move && allyMove.hasAttr("AwaitCombinedPledgeAttr")) { @@ -4534,8 +4534,7 @@ export class CueNextRoundAttr extends MoveEffectAttr { } override apply(user: Pokemon, target: Pokemon, move: Move, args?: any[]): boolean { - const nextRoundPhase = globalScene.phaseManager.findPhase(phase => - phase.is("MovePhase") && phase.move.moveId === MoveId.ROUND + const nextRoundPhase = globalScene.phaseManager.findPhase("MovePhase", phase => phase.move.moveId === MoveId.ROUND ); if (!nextRoundPhase) { @@ -6217,7 +6216,7 @@ export class RevivalBlessingAttr extends MoveEffectAttr { globalScene.phaseManager.tryRemovePhase((phase: SwitchSummonPhase) => phase.is("SwitchSummonPhase") && phase.getPokemon() === pokemon); // If the pokemon being revived was alive earlier in the turn, cancel its move // (revived pokemon can't move in the turn they're brought back) - globalScene.phaseManager.findPhase((phase: MovePhase) => phase.pokemon === pokemon)?.cancel(); + globalScene.phaseManager.findPhase("MovePhase", (phase: MovePhase) => phase.pokemon === pokemon)?.cancel(); if (user.fieldPosition === FieldPosition.CENTER) { user.setFieldPosition(FieldPosition.LEFT); } @@ -7887,7 +7886,7 @@ export class AfterYouAttr extends MoveEffectAttr { globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:afterYou", { targetName: getPokemonNameWithAffix(target) })); //Will find next acting phase of the targeted pokémon, delete it and queue it next on successful delete. - const nextAttackPhase = globalScene.phaseManager.findPhase((phase) => phase.pokemon === target); + const nextAttackPhase = globalScene.phaseManager.findPhase("MovePhase", (phase) => phase.pokemon === target); if (nextAttackPhase && globalScene.phaseManager.tryRemovePhase((phase: MovePhase) => phase.pokemon === target)) { globalScene.phaseManager.prependNewToPhase("MovePhase", "MovePhase", target, [ ...nextAttackPhase.targets ], nextAttackPhase.move); } diff --git a/src/phase-manager.ts b/src/phase-manager.ts index 6f576c29b08..d38dd9fdbea 100644 --- a/src/phase-manager.ts +++ b/src/phase-manager.ts @@ -394,15 +394,21 @@ export class PhaseManager { /** * Find a specific {@linkcode Phase} in the phase queue. - * + * @param phaseType - A {@linkcode PhaseString} representing which type to search for * @param phaseFilter filter function to use to find the wanted phase * @returns the found phase or undefined if none found */ - findPhase

(phaseFilter: (phase: P) => boolean): P | undefined { - return this.phaseQueue.find(phaseFilter) as P; + findPhase

( + phaseType: P, + phaseFilter?: (phase: PhaseMap[P]) => boolean, + ): PhaseMap[P] | undefined { + if (this.dynamicQueueManager.isDynamicPhase(phaseType)) { + return this.dynamicQueueManager.findPhaseOfType(phaseType, phaseFilter) as PhaseMap[P]; + } + return this.phaseQueue.find(phase => phase.is(phaseType) && (!phaseFilter || phaseFilter(phase))) as PhaseMap[P]; } - tryReplacePhase(phaseFilter: (phase: Phase) => boolean, phase: Phase): boolean { + tryReplacePhase(phaseFilter: PhaseConditionFunc, phase: Phase): boolean { const phaseIndex = this.phaseQueue.findIndex(phaseFilter); if (phaseIndex > -1) { this.phaseQueue[phaseIndex] = phase; @@ -411,7 +417,7 @@ export class PhaseManager { return false; } - tryRemovePhase(phaseFilter: (phase: Phase) => boolean): boolean { + tryRemovePhase(phaseFilter: PhaseConditionFunc): boolean { const phaseIndex = this.phaseQueue.findIndex(phaseFilter); if (phaseIndex > -1) { this.phaseQueue.splice(phaseIndex, 1); @@ -424,7 +430,7 @@ export class PhaseManager { * Will search for a specific phase in {@linkcode phaseQueuePrepend} via filter, and remove the first result if a match is found. * @param phaseFilter filter function */ - tryRemoveUnshiftedPhase(phaseFilter: (phase: Phase) => boolean): boolean { + tryRemoveUnshiftedPhase(phaseFilter: PhaseConditionFunc): boolean { const phaseIndex = this.phaseQueuePrepend.findIndex(phaseFilter); if (phaseIndex > -1) { this.phaseQueuePrepend.splice(phaseIndex, 1); @@ -464,7 +470,7 @@ export class PhaseManager { * @param condition Condition the target phase must meet to be appended to * @returns `true` if a `targetPhase` was found to append to */ - appendToPhase(phase: Phase | Phase[], targetPhase: PhaseString, condition?: (p: Phase) => boolean): boolean { + appendToPhase(phase: Phase | Phase[], targetPhase: PhaseString, condition?: PhaseConditionFunc): boolean { phase = coerceArray(phase); const target = PHASES[targetPhase]; const targetIndex = this.phaseQueue.findIndex(ph => ph instanceof target && (!condition || condition(ph))); diff --git a/src/phases/egg-hatch-phase.ts b/src/phases/egg-hatch-phase.ts index d6c40a1510e..10beee1f222 100644 --- a/src/phases/egg-hatch-phase.ts +++ b/src/phases/egg-hatch-phase.ts @@ -225,7 +225,7 @@ export class EggHatchPhase extends Phase { } end() { - if (globalScene.phaseManager.findPhase(p => p.is("EggHatchPhase"))) { + if (globalScene.phaseManager.findPhase("EggHatchPhase")) { this.eggHatchHandler.clear(); } else { globalScene.time.delayedCall(250, () => globalScene.setModifiersVisible(true)); diff --git a/src/phases/mystery-encounter-phases.ts b/src/phases/mystery-encounter-phases.ts index 9aae796211f..14b961deb73 100644 --- a/src/phases/mystery-encounter-phases.ts +++ b/src/phases/mystery-encounter-phases.ts @@ -237,7 +237,7 @@ export class MysteryEncounterBattleStartCleanupPhase extends Phase { }); // Remove any status tick phases - while (globalScene.phaseManager.findPhase(p => p.is("PostTurnStatusEffectPhase"))) { + while (globalScene.phaseManager.findPhase("PostTurnStatusEffectPhase")) { globalScene.phaseManager.tryRemovePhase(p => p.is("PostTurnStatusEffectPhase")); } diff --git a/src/phases/quiet-form-change-phase.ts b/src/phases/quiet-form-change-phase.ts index e6a00c73756..388ca1fa1fd 100644 --- a/src/phases/quiet-form-change-phase.ts +++ b/src/phases/quiet-form-change-phase.ts @@ -11,7 +11,6 @@ import { BattlerTagType } from "#app/enums/battler-tag-type"; import type Pokemon from "#app/field/pokemon"; import { getPokemonNameWithAffix } from "#app/messages"; import { BattlePhase } from "./battle-phase"; -import type { MovePhase } from "./move-phase"; import { applyAbAttrs } from "#app/data/abilities/apply-ab-attrs"; export class QuietFormChangePhase extends BattlePhase { @@ -172,9 +171,7 @@ export class QuietFormChangePhase extends BattlePhase { this.pokemon.initBattleInfo(); this.pokemon.cry(); - const movePhase = globalScene.phaseManager.findPhase( - p => p.is("MovePhase") && p.pokemon === this.pokemon, - ) as MovePhase; + const movePhase = globalScene.phaseManager.findPhase("MovePhase", p => p.pokemon === this.pokemon); if (movePhase) { movePhase.cancel(); } diff --git a/src/phases/stat-stage-change-phase.ts b/src/phases/stat-stage-change-phase.ts index e73f72f7a63..7370f5f63b6 100644 --- a/src/phases/stat-stage-change-phase.ts +++ b/src/phases/stat-stage-change-phase.ts @@ -236,7 +236,8 @@ export class StatStageChangePhase extends PokemonPhase { // Look for any other stat change phases; if this is the last one, do White Herb check const existingPhase = globalScene.phaseManager.findPhase( - p => p.is("StatStageChangePhase") && p.battlerIndex === this.battlerIndex, + "StatStageChangePhase", + p => p.battlerIndex === this.battlerIndex, ); if (!existingPhase?.is("StatStageChangePhase")) { // Apply White Herb if needed @@ -316,8 +317,8 @@ export class StatStageChangePhase extends PokemonPhase { if (this.stats.length === 1) { while ( (existingPhase = globalScene.phaseManager.findPhase( + "StatStageChangePhase", p => - p.is("StatStageChangePhase") && p.battlerIndex === this.battlerIndex && p.stats.length === 1 && p.stats[0] === this.stats[0] && @@ -335,8 +336,8 @@ export class StatStageChangePhase extends PokemonPhase { } while ( (existingPhase = globalScene.phaseManager.findPhase( + "StatStageChangePhase", p => - p.is("StatStageChangePhase") && p.battlerIndex === this.battlerIndex && p.selfTarget === this.selfTarget && accEva.some(s => p.stats.includes(s)) === isAccEva && diff --git a/src/queues/dynamic-queue-manager.ts b/src/queues/dynamic-queue-manager.ts index 75680074fe1..e0b5ab3df6c 100644 --- a/src/queues/dynamic-queue-manager.ts +++ b/src/queues/dynamic-queue-manager.ts @@ -36,6 +36,10 @@ export class DynamicQueueManager { return this.dynamicPhaseMap.has(type); } + public findPhaseOfType(type: PhaseString, condition?: PhaseConditionFunc): Phase | undefined { + return this.dynamicPhaseMap.get(type)?.findPhase(condition); + } + public exists(type: PhaseString, condition?: PhaseConditionFunc): boolean { return !!this.dynamicPhaseMap.get(type)?.hasPhaseWithCondition(condition); } diff --git a/src/queues/phase-priority-queue.ts b/src/queues/phase-priority-queue.ts index 00816318fcd..2ca6a077154 100644 --- a/src/queues/phase-priority-queue.ts +++ b/src/queues/phase-priority-queue.ts @@ -42,6 +42,10 @@ export abstract class PhasePriorityQueue { return !this.queue.length; } + public findPhase(condition?: PhaseConditionFunc): Phase | undefined { + return this.queue.find(phase => !condition || condition(phase)); + } + public hasPhaseWithCondition(condition?: PhaseConditionFunc): boolean { return this.queue.find(phase => !condition || condition(phase)) !== undefined; }