diff --git a/src/data/abilities/ability.ts b/src/data/abilities/ability.ts index 2fc682954c6..faa9a8afafe 100644 --- a/src/data/abilities/ability.ts +++ b/src/data/abilities/ability.ts @@ -80,6 +80,7 @@ import { noAbilityTypeOverrideMoves } from "../moves/invalid-moves"; import type { Localizable } from "#app/@types/locales"; import { applyAbAttrs } from "./apply-ab-attrs"; import { MovePriorityModifier } from "#enums/move-priority-modifier"; +import { MovePhaseTimingModifier } from "#enums/move-phase-timing-modifier"; export class Ability implements Localizable { public id: AbilityId; @@ -4016,6 +4017,7 @@ export class CommanderAbAttr extends AbAttr { return ( globalScene.currentBattle?.double && !isNullOrUndefined(ally) && + ally.isActive(true) && ally.species.speciesId === SpeciesId.DONDOZO && !(ally.isFainted() || ally.getTag(BattlerTagType.COMMANDED)) ); @@ -6093,10 +6095,19 @@ export class PostDancingMoveAbAttr extends PostMoveUsedAbAttr { // If the move is an AttackMove or a StatusMove the Dancer must replicate the move on the source of the Dance if (move.getMove().is("AttackMove") || move.getMove().is("StatusMove")) { const target = this.getTarget(dancer, source, targets); - phaseManager.unshiftNew("MovePhase", dancer, target, move, true, true); + phaseManager.pushNew("MovePhase", dancer, target, move, true, true, false, MovePhaseTimingModifier.FIRST); } else if (move.getMove().is("SelfStatusMove")) { // If the move is a SelfStatusMove (ie. Swords Dance) the Dancer should replicate it on itself - phaseManager.unshiftNew("MovePhase", dancer, [dancer.getBattlerIndex()], move, true, true); + phaseManager.pushNew( + "MovePhase", + dancer, + [dancer.getBattlerIndex()], + move, + true, + true, + false, + MovePhaseTimingModifier.FIRST, + ); } } } diff --git a/src/data/moves/move.ts b/src/data/moves/move.ts index 8a0026a4ced..227f47e31b9 100644 --- a/src/data/moves/move.ts +++ b/src/data/moves/move.ts @@ -6219,7 +6219,7 @@ export class RevivalBlessingAttr extends MoveEffectAttr { if (user.fieldPosition === FieldPosition.CENTER) { user.setFieldPosition(FieldPosition.LEFT); } - globalScene.phaseManager.unshiftNew("SwitchSummonPhase", SwitchType.SWITCH, allyPokemon.getFieldIndex(), slotIndex, false, false); + globalScene.phaseManager.pushNew("SwitchSummonPhase", SwitchType.SWITCH, allyPokemon.getFieldIndex(), slotIndex, false, false); } } return true; @@ -6769,7 +6769,7 @@ class CallMoveAttr extends OverrideMoveEffectAttr { : [ this.hasTarget ? target.getBattlerIndex() : moveTargets.targets[user.randBattleSeedInt(moveTargets.targets.length)] ]; // account for Mirror Move having a target already user.getMoveQueue().push({ move: move.id, targets: targets, virtual: true, ignorePP: true }); globalScene.phaseManager.unshiftNew("LoadMoveAnimPhase", move.id); - globalScene.phaseManager.unshiftNew("MovePhase", user, targets, new PokemonMove(move.id, 0, 0, true), true, true); + globalScene.phaseManager.pushNew("MovePhase", user, targets, new PokemonMove(move.id, 0, 0, true), true, true, false, MovePhaseTimingModifier.FIRST); return true; } } @@ -6998,7 +6998,7 @@ export class NaturePowerAttr extends OverrideMoveEffectAttr { user.getMoveQueue().push({ move: moveId, targets: [ target.getBattlerIndex() ], ignorePP: true }); globalScene.phaseManager.unshiftNew("LoadMoveAnimPhase", moveId); - globalScene.phaseManager.unshiftNew("MovePhase", user, [ target.getBattlerIndex() ], new PokemonMove(moveId, 0, 0, true), true); + globalScene.phaseManager.pushNew("MovePhase", user, [ target.getBattlerIndex() ], new PokemonMove(moveId, 0, 0, true), true); return true; } } @@ -7085,7 +7085,7 @@ export class RepeatMoveAttr extends MoveEffectAttr { })); target.getMoveQueue().unshift({ move: lastMove.move, targets: moveTargets, ignorePP: false }); target.turnData.extraTurns++; - globalScene.phaseManager.appendNewToPhase("MoveEndPhase", "MovePhase", target, moveTargets, movesetMove, false, false, false, MovePhaseTimingModifier.FIRST); + globalScene.phaseManager.pushNew("MovePhase", target, moveTargets, movesetMove, false, false, false, MovePhaseTimingModifier.FIRST); return true; } diff --git a/src/phase-manager.ts b/src/phase-manager.ts index fb9f7914b41..cd67f144496 100644 --- a/src/phase-manager.ts +++ b/src/phase-manager.ts @@ -2,7 +2,6 @@ import type { Phase } from "#app/phase"; import type { default as Pokemon } from "#app/field/pokemon"; import type { DynamicPhaseString, PhaseMap, PhaseString, StaticPhaseString } from "./@types/phase-types"; import { globalScene } from "#app/global-scene"; -import { ActivatePriorityQueuePhase } from "#app/phases/activate-priority-queue-phase"; import { AddEnemyBuffModifierPhase } from "#app/phases/add-enemy-buff-modifier-phase"; import { AttemptCapturePhase } from "#app/phases/attempt-capture-phase"; import { AttemptRunPhase } from "#app/phases/attempt-run-phase"; @@ -116,7 +115,6 @@ import type { PokemonMove } from "#app/data/moves/pokemon-move"; * This allows for easy creation of new phases without needing to import each phase individually. */ const PHASES = Object.freeze({ - ActivatePriorityQueuePhase, AddEnemyBuffModifierPhase, AttemptCapturePhase, AttemptRunPhase, @@ -263,7 +261,7 @@ export class PhaseManager { */ pushPhase(phase: Phase, defer = false): void { if (this.dynamicQueueManager.isDynamicPhase(phase.phaseName)) { - this.pushDynamicPhase(phase); + this.dynamicQueueManager.queueDynamicPhase(phase); } else { (!defer ? this.phaseQueue : this.nextCommandPhaseQueue).push(phase); } @@ -344,6 +342,13 @@ export class PhaseManager { this.conditionalQueue = []; } + if (this.phaseQueue[0].is("WeatherEffectPhase")) { + const dynamicPhase = this.dynamicQueueManager.popNextPhase(); + if (dynamicPhase) { + this.phaseQueue.unshift(dynamicPhase); + } + } + this.currentPhase = this.phaseQueue.shift() ?? null; const unactivatedConditionalPhases: [() => boolean, Phase][] = []; @@ -418,6 +423,9 @@ export class PhaseManager { } tryRemovePhase(phaseFilter: PhaseConditionFunc): boolean { + if (this.dynamicQueueManager.removePhase(phaseFilter)) { + return true; + } const phaseIndex = this.phaseQueue.findIndex(phaseFilter); if (phaseIndex > -1) { this.phaseQueue.splice(phaseIndex, 1); @@ -450,22 +458,15 @@ export class PhaseManager { * @param targetPhase - The phase to search for in phaseQueue * @returns boolean if a targetPhase was found and added */ - prependToPhase(phase: Phase, targetPhase: PhaseString): boolean { - const insertPhase = this.dynamicQueueManager.isDynamicPhase(phase.phaseName) - ? new ActivatePriorityQueuePhase(phase.phaseName) - : phase; + prependToPhase(phase: Phase, targetPhase: StaticPhaseString): boolean { const target = PHASES[targetPhase]; const targetIndex = this.phaseQueue.findIndex(ph => ph instanceof target); - if (this.dynamicQueueManager.isDynamicPhase(phase.phaseName)) { - this.dynamicQueueManager.queueDynamicPhase(phase); - } - if (targetIndex !== -1) { - this.phaseQueue.splice(targetIndex, 0, insertPhase); + this.phaseQueue.splice(targetIndex, 0, phase); return true; } - this.unshiftPhase(insertPhase); + this.unshiftPhase(phase); return false; } @@ -478,60 +479,28 @@ export class PhaseManager { * @returns `true` if a `targetPhase` was found to append to */ appendToPhase(phase: Phase, targetPhase: StaticPhaseString, condition?: PhaseConditionFunc): boolean { - const insertPhase = this.dynamicQueueManager.isDynamicPhase(phase.phaseName) - ? new ActivatePriorityQueuePhase(phase.phaseName) - : phase; const target = PHASES[targetPhase]; const targetIndex = this.phaseQueue.findIndex(ph => ph instanceof target && (!condition || condition(ph))); - if (this.dynamicQueueManager.isDynamicPhase(phase.phaseName)) { - this.dynamicQueueManager.queueDynamicPhase(phase); - } - if (targetIndex !== -1 && this.phaseQueue.length > targetIndex) { - this.phaseQueue.splice(targetIndex + 1, 0, insertPhase); + this.phaseQueue.splice(targetIndex + 1, 0, phase); return true; } - this.unshiftPhase(insertPhase); + this.unshiftPhase(phase); return false; } - /** - * Pushes a phase onto its corresponding dynamic queue and marks the activation point in {@linkcode phaseQueue} - * - * The {@linkcode ActivatePriorityQueuePhase} will run the top phase in the dynamic queue (not necessarily {@linkcode phase}) - * @param phase The phase to push - */ - public pushDynamicPhase(phase: Phase): void { - this.pushNew("ActivatePriorityQueuePhase", phase.phaseName); - this.dynamicQueueManager.queueDynamicPhase(phase); - } - /** * Unshifts the top phase from the corresponding dynamic queue onto {@linkcode phaseQueue} * @param type {@linkcode DynamicPhaseString} The type of dynamic phase to start */ - public startNextDynamicPhase(): void { - const phase = this.dynamicQueueManager.popNextPhase(); + public startNextDynamicPhase(type?: DynamicPhaseString): void { + const phase = this.dynamicQueueManager.popNextPhase(type); if (phase) { this.unshiftPhase(phase); } } - /** - * Unshifts an {@linkcode ActivatePriorityQueuePhase} for {@linkcode phase}, then pushes {@linkcode phase} to its dynamic queue - * - * This is the same as {@linkcode pushDynamicPhase}, except the activation phase is unshifted - * - * {@linkcode phase} is not guaranteed to be the next phase from the queue to run (if the queue is not empty) - * @param phase The phase to add - * @returns - */ - public startDynamicPhase(phase: Phase): void { - this.unshiftNew("ActivatePriorityQueuePhase", phase.phaseName); - this.dynamicQueueManager.queueDynamicPhase(phase); - } - /** * Adds a MessagePhase, either to PhaseQueuePrepend or nextCommandPhaseQueue * @param message - string for MessagePhase @@ -583,6 +552,11 @@ export class PhaseManager { * Moves everything from nextCommandPhaseQueue to phaseQueue (keeping order) */ private populatePhaseQueue(): void { + const dynamicPhase = this.dynamicQueueManager.popNextPhase(); + if (dynamicPhase) { + this.phaseQueue.unshift(dynamicPhase); + return; + } if (this.nextCommandPhaseQueue.length) { this.phaseQueue.push(...this.nextCommandPhaseQueue); this.nextCommandPhaseQueue.splice(0, this.nextCommandPhaseQueue.length); @@ -624,7 +598,10 @@ export class PhaseManager { * @param phase - The name of the phase to create * @param args - The arguments to pass to the phase constructor */ - public unshiftNew(phase: T, ...args: ConstructorParameters): void { + public unshiftNew( + phase: T, + ...args: ConstructorParameters + ): void { this.unshiftPhase(this.create(phase, ...args)); } @@ -637,7 +614,7 @@ export class PhaseManager { * @returns `true` if a `targetPhase` was found to prepend to */ public prependNewToPhase( - targetPhase: PhaseString, + targetPhase: StaticPhaseString, phase: T, ...args: ConstructorParameters ): boolean { @@ -660,13 +637,6 @@ export class PhaseManager { return this.appendToPhase(this.create(phase, ...args), targetPhase); } - public startNewDynamicPhase( - phase: T, - ...args: ConstructorParameters - ): void { - this.startDynamicPhase(this.create(phase, ...args)); - } - public forceMoveNext(phaseCondition: PhaseConditionFunc) { this.dynamicQueueManager.setMoveTimingModifier(phaseCondition, MovePhaseTimingModifier.FIRST); } diff --git a/src/phases/activate-priority-queue-phase.ts b/src/phases/activate-priority-queue-phase.ts deleted file mode 100644 index 4e467446055..00000000000 --- a/src/phases/activate-priority-queue-phase.ts +++ /dev/null @@ -1,23 +0,0 @@ -import type { PhaseString } from "#app/@types/phase-types"; -import { globalScene } from "#app/global-scene"; -import { Phase } from "#app/phase"; - -export class ActivatePriorityQueuePhase extends Phase { - public readonly phaseName = "ActivatePriorityQueuePhase"; - private readonly type: PhaseString; - - constructor(type: PhaseString) { - super(); - this.type = type; - } - - override start() { - super.start(); - globalScene.phaseManager.startNextDynamicPhase(); - this.end(); - } - - public getType(): PhaseString { - return this.type; - } -} diff --git a/src/phases/move-effect-phase.ts b/src/phases/move-effect-phase.ts index 2af7e93a6ac..6a3384f99ed 100644 --- a/src/phases/move-effect-phase.ts +++ b/src/phases/move-effect-phase.ts @@ -175,8 +175,7 @@ export class MoveEffectPhase extends PokemonPhase { globalScene.phaseManager.unshiftNew("HideAbilityPhase"); } - globalScene.phaseManager.appendNewToPhase( - "MoveEndPhase", + globalScene.phaseManager.pushNew( "MovePhase", target, newTargets, diff --git a/src/phases/post-summon-phase.ts b/src/phases/post-summon-phase.ts index 26fffd1b024..4abeca9953e 100644 --- a/src/phases/post-summon-phase.ts +++ b/src/phases/post-summon-phase.ts @@ -28,12 +28,19 @@ export class PostSummonPhase extends PokemonPhase { const field = pokemon.isPlayer() ? globalScene.getPlayerField() : globalScene.getEnemyField(); for (const p of field) { - applyAbAttrs("CommanderAbAttr", p, null, false); + if (p.isActive(true)) { + applyAbAttrs("CommanderAbAttr", p, null, false); + } } this.end(); } + override end() { + globalScene.phaseManager.startNextDynamicPhase("PostSummonPhase"); + super.end(); + } + public getPriority() { return 0; } diff --git a/src/phases/summon-phase.ts b/src/phases/summon-phase.ts index 8ed33e12870..dc916a67ebe 100644 --- a/src/phases/summon-phase.ts +++ b/src/phases/summon-phase.ts @@ -289,6 +289,7 @@ export class SummonPhase extends PartyMemberPokemonPhase { queuePostSummon(): void { globalScene.phaseManager.pushNew("PostSummonPhase", this.getPokemon().getBattlerIndex()); + globalScene.phaseManager.startNextDynamicPhase("PostSummonPhase"); } end() { diff --git a/src/phases/switch-phase.ts b/src/phases/switch-phase.ts index 8d18e29e6a6..94c4800c823 100644 --- a/src/phases/switch-phase.ts +++ b/src/phases/switch-phase.ts @@ -79,7 +79,7 @@ export class SwitchPhase extends BattlePhase { p => p.is("PostSummonPhase") && p.player && p.fieldIndex === this.fieldIndex, ); const switchType = option === PartyOption.PASS_BATON ? SwitchType.BATON_PASS : this.switchType; - globalScene.phaseManager.unshiftNew("SwitchSummonPhase", switchType, fieldIndex, slotIndex, this.doReturn); + globalScene.phaseManager.pushNew("SwitchSummonPhase", switchType, fieldIndex, slotIndex, this.doReturn); } globalScene.ui.setMode(UiMode.MESSAGE).then(() => super.end()); }, diff --git a/src/phases/switch-summon-phase.ts b/src/phases/switch-summon-phase.ts index af03cc42b54..7d1403b8de9 100644 --- a/src/phases/switch-summon-phase.ts +++ b/src/phases/switch-summon-phase.ts @@ -245,7 +245,7 @@ export class SwitchSummonPhase extends SummonPhase { } queuePostSummon(): void { - globalScene.phaseManager.startNewDynamicPhase("PostSummonPhase", this.getPokemon().getBattlerIndex()); + globalScene.phaseManager.pushNew("PostSummonPhase", this.getPokemon().getBattlerIndex()); } /** diff --git a/src/phases/turn-start-phase.ts b/src/phases/turn-start-phase.ts index 887076b37a5..c9a9b2a57a4 100644 --- a/src/phases/turn-start-phase.ts +++ b/src/phases/turn-start-phase.ts @@ -132,7 +132,7 @@ export class TurnStartPhase extends FieldPhase { case Command.POKEMON: { const switchType = turnCommand.args?.[0] ? SwitchType.BATON_PASS : SwitchType.SWITCH; - phaseManager.unshiftNew( + phaseManager.pushNew( "SwitchSummonPhase", switchType, pokemon.getFieldIndex(), diff --git a/src/queues/dynamic-queue-manager.ts b/src/queues/dynamic-queue-manager.ts index edd2afa35f6..1e8972863d4 100644 --- a/src/queues/dynamic-queue-manager.ts +++ b/src/queues/dynamic-queue-manager.ts @@ -1,5 +1,5 @@ import type { PhaseConditionFunc } from "#app/@types/phase-condition"; -import type { PhaseString } from "#app/@types/phase-types"; +import type { DynamicPhaseString, PhaseString } from "#app/@types/phase-types"; import type { PokemonMove } from "#app/data/moves/pokemon-move"; import type { Phase } from "#app/phase"; import { MovePhasePriorityQueue } from "#app/queues/move-phase-priority-queue"; @@ -29,8 +29,11 @@ export class DynamicQueueManager { this.dynamicPhaseMap.get(phase.phaseName)?.push(phase); } - public popNextPhase(): Phase | undefined { - return [...this.dynamicPhaseMap.values()].find(queue => !queue.isEmpty())?.pop(); + public popNextPhase(type?: DynamicPhaseString): Phase | undefined { + const queue = type + ? this.dynamicPhaseMap.get(type) + : [...this.dynamicPhaseMap.values()].find(queue => !queue.isEmpty()); + return queue?.pop(); } public isDynamicPhase(type: PhaseString): boolean { diff --git a/src/queues/move-phase-priority-queue.ts b/src/queues/move-phase-priority-queue.ts index dd01fcbb210..eb9d834c7c0 100644 --- a/src/queues/move-phase-priority-queue.ts +++ b/src/queues/move-phase-priority-queue.ts @@ -10,6 +10,7 @@ export class MovePhasePriorityQueue extends PokemonPhasePriorityQueue public override reorder(): void { super.reorder(); this.sortPostSpeed(); + console.log(this.queue.map(p => p.getPokemon().name)); } public setTimingModifier(condition: PhaseConditionFunc, modifier: MovePhaseTimingModifier): void { diff --git a/src/queues/post-summon-phase-priority-queue.ts b/src/queues/post-summon-phase-priority-queue.ts index 8843e5514a7..39de4ce0193 100644 --- a/src/queues/post-summon-phase-priority-queue.ts +++ b/src/queues/post-summon-phase-priority-queue.ts @@ -1,5 +1,3 @@ -import { globalScene } from "#app/global-scene"; -import { ActivatePriorityQueuePhase } from "#app/phases/activate-priority-queue-phase"; import { PostSummonActivateAbilityPhase } from "#app/phases/post-summon-activate-ability-phase"; import type { PostSummonPhase } from "#app/phases/post-summon-phase"; import { PokemonPhasePriorityQueue } from "#app/queues/pokemon-phase-priority-queue"; @@ -30,13 +28,10 @@ export class PostSummonPhasePriorityQueue extends PokemonPhasePriorityQueue { - this.queue.push(new PostSummonActivateAbilityPhase(phasePokemon.getBattlerIndex(), priority, !!idx)); - globalScene.phaseManager.appendToPhase( - new ActivatePriorityQueuePhase("PostSummonPhase"), - "ActivatePriorityQueuePhase", - (p: ActivatePriorityQueuePhase) => p.getType() === "PostSummonPhase", + phasePokemon + .getAbilityPriorities() + .forEach((priority, idx) => + this.queue.push(new PostSummonActivateAbilityPhase(phasePokemon.getBattlerIndex(), priority, !!idx)), ); - }); } }