Remove APQP

This commit is contained in:
Dean 2025-06-15 20:12:26 -07:00
parent acbcd3e308
commit 3aa1940a8d
13 changed files with 69 additions and 105 deletions

View File

@ -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,
);
}
}
}

View File

@ -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;
}

View File

@ -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<T extends PhaseString>(phase: T, ...args: ConstructorParameters<PhaseConstructorMap[T]>): void {
public unshiftNew<T extends StaticPhaseString>(
phase: T,
...args: ConstructorParameters<PhaseConstructorMap[T]>
): 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<T extends PhaseString>(
targetPhase: PhaseString,
targetPhase: StaticPhaseString,
phase: T,
...args: ConstructorParameters<PhaseConstructorMap[T]>
): boolean {
@ -660,13 +637,6 @@ export class PhaseManager {
return this.appendToPhase(this.create(phase, ...args), targetPhase);
}
public startNewDynamicPhase<T extends DynamicPhaseString>(
phase: T,
...args: ConstructorParameters<PhaseConstructorMap[T]>
): void {
this.startDynamicPhase(this.create(phase, ...args));
}
public forceMoveNext(phaseCondition: PhaseConditionFunc) {
this.dynamicQueueManager.setMoveTimingModifier(phaseCondition, MovePhaseTimingModifier.FIRST);
}

View File

@ -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;
}
}

View File

@ -175,8 +175,7 @@ export class MoveEffectPhase extends PokemonPhase {
globalScene.phaseManager.unshiftNew("HideAbilityPhase");
}
globalScene.phaseManager.appendNewToPhase(
"MoveEndPhase",
globalScene.phaseManager.pushNew(
"MovePhase",
target,
newTargets,

View File

@ -28,12 +28,19 @@ export class PostSummonPhase extends PokemonPhase {
const field = pokemon.isPlayer() ? globalScene.getPlayerField() : globalScene.getEnemyField();
for (const p of field) {
if (p.isActive(true)) {
applyAbAttrs("CommanderAbAttr", p, null, false);
}
}
this.end();
}
override end() {
globalScene.phaseManager.startNextDynamicPhase("PostSummonPhase");
super.end();
}
public getPriority() {
return 0;
}

View File

@ -289,6 +289,7 @@ export class SummonPhase extends PartyMemberPokemonPhase {
queuePostSummon(): void {
globalScene.phaseManager.pushNew("PostSummonPhase", this.getPokemon().getBattlerIndex());
globalScene.phaseManager.startNextDynamicPhase("PostSummonPhase");
}
end() {

View File

@ -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());
},

View File

@ -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());
}
/**

View File

@ -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(),

View File

@ -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 {

View File

@ -10,6 +10,7 @@ export class MovePhasePriorityQueue extends PokemonPhasePriorityQueue<MovePhase>
public override reorder(): void {
super.reorder();
this.sortPostSpeed();
console.log(this.queue.map(p => p.getPokemon().name));
}
public setTimingModifier(condition: PhaseConditionFunc, modifier: MovePhaseTimingModifier): void {

View File

@ -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<Post
private queueAbilityPhase(phase: PostSummonPhase): void {
const phasePokemon = phase.getPokemon();
phasePokemon.getAbilityPriorities().forEach((priority, idx) => {
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)),
);
});
}
}