Update findPhase to also check dynamic queues

This commit is contained in:
Dean 2025-06-14 21:47:10 -07:00
parent 46c709ffad
commit 30ab803df9
11 changed files with 35 additions and 24 deletions

View File

@ -861,8 +861,8 @@ export default class BattleScene extends SceneBase {
let targetingMovePhase: MovePhase; let targetingMovePhase: MovePhase;
do { do {
targetingMovePhase = this.phaseManager.findPhase( targetingMovePhase = this.phaseManager.findPhase(
"MovePhase",
mp => mp =>
mp.is("MovePhase") &&
mp.targets.length === 1 && mp.targets.length === 1 &&
mp.targets[0] === removedPokemon.getBattlerIndex() && mp.targets[0] === removedPokemon.getBattlerIndex() &&
mp.pokemon.isPlayer() !== allyPokemon.isPlayer(), mp.pokemon.isPlayer() !== allyPokemon.isPlayer(),

View File

@ -8407,7 +8407,7 @@ export function initAbilities() {
.ignorable(), .ignorable(),
new Ability(AbilityId.ANALYTIC, 5) new Ability(AbilityId.ANALYTIC, 5)
.attr(MovePowerBoostAbAttr, (user, _target, _move) => { .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); return isNullOrUndefined(movePhase);
}, 1.3), }, 1.3),
new Ability(AbilityId.ILLUSION, 5) new Ability(AbilityId.ILLUSION, 5)

View File

@ -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) { if (movePhase) {
const movesetMove = pokemon.getMoveset().find(m => m.moveId === this.moveId); const movesetMove = pokemon.getMoveset().find(m => m.moveId === this.moveId);
if (movesetMove) { if (movesetMove) {

View File

@ -3171,7 +3171,7 @@ export class AwaitCombinedPledgeAttr extends OverrideMoveEffectAttr {
const overridden = args[0] as BooleanHolder; const overridden = args[0] as BooleanHolder;
const allyMovePhase = globalScene.phaseManager.findPhase<MovePhase>((phase) => phase.is("MovePhase") && phase.pokemon.isPlayer() === user.isPlayer()); const allyMovePhase = globalScene.phaseManager.findPhase("MovePhase", (phase) => phase.pokemon.isPlayer() === user.isPlayer());
if (allyMovePhase) { if (allyMovePhase) {
const allyMove = allyMovePhase.move.getMove(); const allyMove = allyMovePhase.move.getMove();
if (allyMove !== move && allyMove.hasAttr("AwaitCombinedPledgeAttr")) { 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 { override apply(user: Pokemon, target: Pokemon, move: Move, args?: any[]): boolean {
const nextRoundPhase = globalScene.phaseManager.findPhase<MovePhase>(phase => const nextRoundPhase = globalScene.phaseManager.findPhase("MovePhase", phase => phase.move.moveId === MoveId.ROUND
phase.is("MovePhase") && phase.move.moveId === MoveId.ROUND
); );
if (!nextRoundPhase) { if (!nextRoundPhase) {
@ -6217,7 +6216,7 @@ export class RevivalBlessingAttr extends MoveEffectAttr {
globalScene.phaseManager.tryRemovePhase((phase: SwitchSummonPhase) => phase.is("SwitchSummonPhase") && phase.getPokemon() === pokemon); 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 // 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) // (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) { if (user.fieldPosition === FieldPosition.CENTER) {
user.setFieldPosition(FieldPosition.LEFT); user.setFieldPosition(FieldPosition.LEFT);
} }
@ -7887,7 +7886,7 @@ export class AfterYouAttr extends MoveEffectAttr {
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:afterYou", { targetName: getPokemonNameWithAffix(target) })); 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. //Will find next acting phase of the targeted pokémon, delete it and queue it next on successful delete.
const nextAttackPhase = globalScene.phaseManager.findPhase<MovePhase>((phase) => phase.pokemon === target); const nextAttackPhase = globalScene.phaseManager.findPhase("MovePhase", (phase) => phase.pokemon === target);
if (nextAttackPhase && globalScene.phaseManager.tryRemovePhase((phase: MovePhase) => phase.pokemon === target)) { if (nextAttackPhase && globalScene.phaseManager.tryRemovePhase((phase: MovePhase) => phase.pokemon === target)) {
globalScene.phaseManager.prependNewToPhase("MovePhase", "MovePhase", target, [ ...nextAttackPhase.targets ], nextAttackPhase.move); globalScene.phaseManager.prependNewToPhase("MovePhase", "MovePhase", target, [ ...nextAttackPhase.targets ], nextAttackPhase.move);
} }

View File

@ -394,15 +394,21 @@ export class PhaseManager {
/** /**
* Find a specific {@linkcode Phase} in the phase queue. * 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 * @param phaseFilter filter function to use to find the wanted phase
* @returns the found phase or undefined if none found * @returns the found phase or undefined if none found
*/ */
findPhase<P extends Phase = Phase>(phaseFilter: (phase: P) => boolean): P | undefined { findPhase<P extends PhaseString>(
return this.phaseQueue.find(phaseFilter) as P; 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); const phaseIndex = this.phaseQueue.findIndex(phaseFilter);
if (phaseIndex > -1) { if (phaseIndex > -1) {
this.phaseQueue[phaseIndex] = phase; this.phaseQueue[phaseIndex] = phase;
@ -411,7 +417,7 @@ export class PhaseManager {
return false; return false;
} }
tryRemovePhase(phaseFilter: (phase: Phase) => boolean): boolean { tryRemovePhase(phaseFilter: PhaseConditionFunc): boolean {
const phaseIndex = this.phaseQueue.findIndex(phaseFilter); const phaseIndex = this.phaseQueue.findIndex(phaseFilter);
if (phaseIndex > -1) { if (phaseIndex > -1) {
this.phaseQueue.splice(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. * 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 * @param phaseFilter filter function
*/ */
tryRemoveUnshiftedPhase(phaseFilter: (phase: Phase) => boolean): boolean { tryRemoveUnshiftedPhase(phaseFilter: PhaseConditionFunc): boolean {
const phaseIndex = this.phaseQueuePrepend.findIndex(phaseFilter); const phaseIndex = this.phaseQueuePrepend.findIndex(phaseFilter);
if (phaseIndex > -1) { if (phaseIndex > -1) {
this.phaseQueuePrepend.splice(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 * @param condition Condition the target phase must meet to be appended to
* @returns `true` if a `targetPhase` was found to append 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); phase = coerceArray(phase);
const target = PHASES[targetPhase]; const target = PHASES[targetPhase];
const targetIndex = this.phaseQueue.findIndex(ph => ph instanceof target && (!condition || condition(ph))); const targetIndex = this.phaseQueue.findIndex(ph => ph instanceof target && (!condition || condition(ph)));

View File

@ -225,7 +225,7 @@ export class EggHatchPhase extends Phase {
} }
end() { end() {
if (globalScene.phaseManager.findPhase(p => p.is("EggHatchPhase"))) { if (globalScene.phaseManager.findPhase("EggHatchPhase")) {
this.eggHatchHandler.clear(); this.eggHatchHandler.clear();
} else { } else {
globalScene.time.delayedCall(250, () => globalScene.setModifiersVisible(true)); globalScene.time.delayedCall(250, () => globalScene.setModifiersVisible(true));

View File

@ -237,7 +237,7 @@ export class MysteryEncounterBattleStartCleanupPhase extends Phase {
}); });
// Remove any status tick phases // 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")); globalScene.phaseManager.tryRemovePhase(p => p.is("PostTurnStatusEffectPhase"));
} }

View File

@ -11,7 +11,6 @@ import { BattlerTagType } from "#app/enums/battler-tag-type";
import type Pokemon from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon";
import { getPokemonNameWithAffix } from "#app/messages"; import { getPokemonNameWithAffix } from "#app/messages";
import { BattlePhase } from "./battle-phase"; import { BattlePhase } from "./battle-phase";
import type { MovePhase } from "./move-phase";
import { applyAbAttrs } from "#app/data/abilities/apply-ab-attrs"; import { applyAbAttrs } from "#app/data/abilities/apply-ab-attrs";
export class QuietFormChangePhase extends BattlePhase { export class QuietFormChangePhase extends BattlePhase {
@ -172,9 +171,7 @@ export class QuietFormChangePhase extends BattlePhase {
this.pokemon.initBattleInfo(); this.pokemon.initBattleInfo();
this.pokemon.cry(); this.pokemon.cry();
const movePhase = globalScene.phaseManager.findPhase( const movePhase = globalScene.phaseManager.findPhase("MovePhase", p => p.pokemon === this.pokemon);
p => p.is("MovePhase") && p.pokemon === this.pokemon,
) as MovePhase;
if (movePhase) { if (movePhase) {
movePhase.cancel(); movePhase.cancel();
} }

View File

@ -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 // Look for any other stat change phases; if this is the last one, do White Herb check
const existingPhase = globalScene.phaseManager.findPhase( const existingPhase = globalScene.phaseManager.findPhase(
p => p.is("StatStageChangePhase") && p.battlerIndex === this.battlerIndex, "StatStageChangePhase",
p => p.battlerIndex === this.battlerIndex,
); );
if (!existingPhase?.is("StatStageChangePhase")) { if (!existingPhase?.is("StatStageChangePhase")) {
// Apply White Herb if needed // Apply White Herb if needed
@ -316,8 +317,8 @@ export class StatStageChangePhase extends PokemonPhase {
if (this.stats.length === 1) { if (this.stats.length === 1) {
while ( while (
(existingPhase = globalScene.phaseManager.findPhase( (existingPhase = globalScene.phaseManager.findPhase(
"StatStageChangePhase",
p => p =>
p.is("StatStageChangePhase") &&
p.battlerIndex === this.battlerIndex && p.battlerIndex === this.battlerIndex &&
p.stats.length === 1 && p.stats.length === 1 &&
p.stats[0] === this.stats[0] && p.stats[0] === this.stats[0] &&
@ -335,8 +336,8 @@ export class StatStageChangePhase extends PokemonPhase {
} }
while ( while (
(existingPhase = globalScene.phaseManager.findPhase( (existingPhase = globalScene.phaseManager.findPhase(
"StatStageChangePhase",
p => p =>
p.is("StatStageChangePhase") &&
p.battlerIndex === this.battlerIndex && p.battlerIndex === this.battlerIndex &&
p.selfTarget === this.selfTarget && p.selfTarget === this.selfTarget &&
accEva.some(s => p.stats.includes(s)) === isAccEva && accEva.some(s => p.stats.includes(s)) === isAccEva &&

View File

@ -36,6 +36,10 @@ export class DynamicQueueManager {
return this.dynamicPhaseMap.has(type); 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 { public exists(type: PhaseString, condition?: PhaseConditionFunc): boolean {
return !!this.dynamicPhaseMap.get(type)?.hasPhaseWithCondition(condition); return !!this.dynamicPhaseMap.get(type)?.hasPhaseWithCondition(condition);
} }

View File

@ -42,6 +42,10 @@ export abstract class PhasePriorityQueue<T extends Phase> {
return !this.queue.length; return !this.queue.length;
} }
public findPhase(condition?: PhaseConditionFunc): Phase | undefined {
return this.queue.find(phase => !condition || condition(phase));
}
public hasPhaseWithCondition(condition?: PhaseConditionFunc): boolean { public hasPhaseWithCondition(condition?: PhaseConditionFunc): boolean {
return this.queue.find(phase => !condition || condition(phase)) !== undefined; return this.queue.find(phase => !condition || condition(phase)) !== undefined;
} }