Merge branch 'beta' into test-doc

This commit is contained in:
NightKev 2025-06-07 17:59:38 -07:00 committed by GitHub
commit 191b5335e0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
163 changed files with 1465 additions and 1361 deletions

View File

@ -144,7 +144,6 @@ import { battleSpecDialogue } from "#app/data/dialogue";
import { LoadingScene } from "#app/loading-scene";
import { LevelCapPhase } from "#app/phases/level-cap-phase";
import { LoginPhase } from "#app/phases/login-phase";
import { MessagePhase } from "#app/phases/message-phase";
import type { MovePhase } from "#app/phases/move-phase";
import { NewBiomeEncounterPhase } from "#app/phases/new-biome-encounter-phase";
import { NextEncounterPhase } from "#app/phases/next-encounter-phase";
@ -155,7 +154,6 @@ import { ShowTrainerPhase } from "#app/phases/show-trainer-phase";
import { SummonPhase } from "#app/phases/summon-phase";
import { TitlePhase } from "#app/phases/title-phase";
import { ToggleDoublePositionPhase } from "#app/phases/toggle-double-position-phase";
import { TurnInitPhase } from "#app/phases/turn-init-phase";
import { ShopCursorTarget } from "#app/enums/shop-cursor-target";
import MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
import {
@ -178,13 +176,12 @@ import { BattlerTagType } from "#enums/battler-tag-type";
import { FRIENDSHIP_GAIN_FROM_BATTLE } from "#app/data/balance/starters";
import { StatusEffect } from "#enums/status-effect";
import { initGlobalScene } from "#app/global-scene";
import { ShowAbilityPhase } from "#app/phases/show-ability-phase";
import { HideAbilityPhase } from "#app/phases/hide-ability-phase";
import { expSpriteKeys } from "./sprites/sprite-keys";
import { hasExpSprite } from "./sprites/sprite-utils";
import { timedEventManager } from "./global-event-manager";
import { starterColors } from "./global-vars/starter-colors";
import { startingWave } from "./starting-wave";
import { PhaseManager } from "./phase-manager";
const DEBUG_RNG = false;
@ -297,18 +294,8 @@ export default class BattleScene extends SceneBase {
public gameData: GameData;
public sessionSlotId: number;
/** PhaseQueue: dequeue/remove the first element to get the next phase */
public phaseQueue: Phase[];
public conditionalQueue: Array<[() => boolean, Phase]>;
/** PhaseQueuePrepend: is a temp storage of what will be added to PhaseQueue */
private phaseQueuePrepend: Phase[];
/** overrides default of inserting phases to end of phaseQueuePrepend array, useful or inserting Phases "out of order" */
private phaseQueuePrependSpliceIndex: number;
private nextCommandPhaseQueue: Phase[];
private currentPhase: Phase | null;
private standbyPhase: Phase | null;
/** Manager for the phases active in the battle scene */
public readonly phaseManager: PhaseManager;
public field: Phaser.GameObjects.Container;
public fieldUI: Phaser.GameObjects.Container;
public charSprite: CharSprite;
@ -396,11 +383,7 @@ export default class BattleScene extends SceneBase {
constructor() {
super("battle");
this.phaseQueue = [];
this.phaseQueuePrepend = [];
this.conditionalQueue = [];
this.phaseQueuePrependSpliceIndex = -1;
this.nextCommandPhaseQueue = [];
this.phaseManager = new PhaseManager();
this.eventManager = new TimedEventManager();
this.updateGameInfo();
initGlobalScene(this);
@ -716,10 +699,10 @@ export default class BattleScene extends SceneBase {
).then(() => loadMoveAnimAssets(defaultMoves, true)),
this.initStarterColors(),
]).then(() => {
this.pushPhase(new LoginPhase());
this.pushPhase(new TitlePhase());
this.phaseManager.pushPhase(new LoginPhase());
this.phaseManager.pushPhase(new TitlePhase());
this.shiftPhase();
this.phaseManager.shiftPhase();
});
}
@ -899,7 +882,7 @@ export default class BattleScene extends SceneBase {
if (allyPokemon?.isActive(true)) {
let targetingMovePhase: MovePhase;
do {
targetingMovePhase = this.findPhase(
targetingMovePhase = this.phaseManager.findPhase(
mp =>
mp.is("MovePhase") &&
mp.targets.length === 1 &&
@ -1277,7 +1260,7 @@ export default class BattleScene extends SceneBase {
duration: 250,
ease: "Sine.easeInOut",
onComplete: () => {
this.clearPhaseQueue();
this.phaseManager.clearPhaseQueue();
this.ui.freeUIData();
this.uiContainer.remove(this.ui, true);
@ -1450,7 +1433,7 @@ export default class BattleScene extends SceneBase {
}
if (lastBattle?.double && !newDouble) {
this.tryRemovePhase((p: Phase) => p.is("SwitchPhase"));
this.phaseManager.tryRemovePhase((p: Phase) => p.is("SwitchPhase"));
for (const p of this.getPlayerField()) {
p.lapseTag(BattlerTagType.COMMANDED);
}
@ -1492,7 +1475,7 @@ export default class BattleScene extends SceneBase {
playerField.forEach((pokemon, p) => {
if (pokemon.isOnField()) {
this.pushPhase(new ReturnPhase(p));
this.phaseManager.pushPhase(new ReturnPhase(p));
}
});
@ -1509,7 +1492,7 @@ export default class BattleScene extends SceneBase {
}
if (!this.trainer.visible) {
this.pushPhase(new ShowTrainerPhase());
this.phaseManager.pushPhase(new ShowTrainerPhase());
}
}
@ -1518,13 +1501,13 @@ export default class BattleScene extends SceneBase {
}
if (!this.gameMode.hasRandomBiomes && !isNewBiome) {
this.pushPhase(new NextEncounterPhase());
this.phaseManager.pushPhase(new NextEncounterPhase());
} else {
this.pushPhase(new NewBiomeEncounterPhase());
this.phaseManager.pushPhase(new NewBiomeEncounterPhase());
const newMaxExpLevel = this.getMaxExpLevel();
if (newMaxExpLevel > maxExpLevel) {
this.pushPhase(new LevelCapPhase());
this.phaseManager.pushPhase(new LevelCapPhase());
}
}
}
@ -1588,7 +1571,9 @@ export default class BattleScene extends SceneBase {
return 0;
}
const isEggPhase: boolean = ["EggLapsePhase", "EggHatchPhase"].includes(this.getCurrentPhase()?.phaseName ?? "");
const isEggPhase: boolean = ["EggLapsePhase", "EggHatchPhase"].includes(
this.phaseManager.getCurrentPhase()?.phaseName ?? "",
);
if (
// Give trainers with specialty types an appropriately-typed form for Wormadam, Rotom, Arceus, Oricorio, Silvally, or Paldean Tauros.
@ -2615,286 +2600,6 @@ export default class BattleScene extends SceneBase {
}
}
/* Phase Functions */
getCurrentPhase(): Phase | null {
return this.currentPhase;
}
getStandbyPhase(): Phase | null {
return this.standbyPhase;
}
/**
* Adds a phase to the conditional queue and ensures it is executed only when the specified condition is met.
*
* This method allows deferring the execution of a phase until certain conditions are met, which is useful for handling
* situations like abilities and entry hazards that depend on specific game states.
*
* @param {Phase} phase - The phase to be added to the conditional queue.
* @param {() => boolean} condition - A function that returns a boolean indicating whether the phase should be executed.
*
*/
pushConditionalPhase(phase: Phase, condition: () => boolean): void {
this.conditionalQueue.push([condition, phase]);
}
/**
* Adds a phase to nextCommandPhaseQueue, as long as boolean passed in is false
* @param phase {@linkcode Phase} the phase to add
* @param defer boolean on which queue to add to, defaults to false, and adds to phaseQueue
*/
pushPhase(phase: Phase, defer = false): void {
(!defer ? this.phaseQueue : this.nextCommandPhaseQueue).push(phase);
}
/**
* Adds Phase(s) to the end of phaseQueuePrepend, or at phaseQueuePrependSpliceIndex
* @param phases {@linkcode Phase} the phase(s) to add
*/
unshiftPhase(...phases: Phase[]): void {
if (this.phaseQueuePrependSpliceIndex === -1) {
this.phaseQueuePrepend.push(...phases);
} else {
this.phaseQueuePrepend.splice(this.phaseQueuePrependSpliceIndex, 0, ...phases);
}
}
/**
* Clears the phaseQueue
*/
clearPhaseQueue(): void {
this.phaseQueue.splice(0, this.phaseQueue.length);
}
/**
* Clears all phase-related stuff, including all phase queues, the current and standby phases, and a splice index
*/
clearAllPhases(): void {
for (const queue of [this.phaseQueue, this.phaseQueuePrepend, this.conditionalQueue, this.nextCommandPhaseQueue]) {
queue.splice(0, queue.length);
}
this.currentPhase = null;
this.standbyPhase = null;
this.clearPhaseQueueSplice();
}
/**
* Used by function unshiftPhase(), sets index to start inserting at current length instead of the end of the array, useful if phaseQueuePrepend gets longer with Phases
*/
setPhaseQueueSplice(): void {
this.phaseQueuePrependSpliceIndex = this.phaseQueuePrepend.length;
}
/**
* Resets phaseQueuePrependSpliceIndex to -1, implies that calls to unshiftPhase will insert at end of phaseQueuePrepend
*/
clearPhaseQueueSplice(): void {
this.phaseQueuePrependSpliceIndex = -1;
}
/**
* Is called by each Phase implementations "end()" by default
* We dump everything from phaseQueuePrepend to the start of of phaseQueue
* then removes first Phase and starts it
*/
shiftPhase(): void {
if (this.standbyPhase) {
this.currentPhase = this.standbyPhase;
this.standbyPhase = null;
return;
}
if (this.phaseQueuePrependSpliceIndex > -1) {
this.clearPhaseQueueSplice();
}
if (this.phaseQueuePrepend.length) {
while (this.phaseQueuePrepend.length) {
const poppedPhase = this.phaseQueuePrepend.pop();
if (poppedPhase) {
this.phaseQueue.unshift(poppedPhase);
}
}
}
if (!this.phaseQueue.length) {
this.populatePhaseQueue();
// Clear the conditionalQueue if there are no phases left in the phaseQueue
this.conditionalQueue = [];
}
this.currentPhase = this.phaseQueue.shift() ?? null;
// Check if there are any conditional phases queued
if (this.conditionalQueue?.length) {
// Retrieve the first conditional phase from the queue
const conditionalPhase = this.conditionalQueue.shift();
// Evaluate the condition associated with the phase
if (conditionalPhase?.[0]()) {
// If the condition is met, add the phase to the phase queue
this.pushPhase(conditionalPhase[1]);
} else if (conditionalPhase) {
// If the condition is not met, re-add the phase back to the front of the conditional queue
this.conditionalQueue.unshift(conditionalPhase);
} else {
console.warn("condition phase is undefined/null!", conditionalPhase);
}
}
if (this.currentPhase) {
console.log(`%cStart Phase ${this.currentPhase.constructor.name}`, "color:green;");
this.currentPhase.start();
}
}
overridePhase(phase: Phase): boolean {
if (this.standbyPhase) {
return false;
}
this.standbyPhase = this.currentPhase;
this.currentPhase = phase;
console.log(`%cStart Phase ${phase.constructor.name}`, "color:green;");
phase.start();
return true;
}
/**
* Find a specific {@linkcode Phase} in the phase queue.
*
* @param phaseFilter filter function to use to find the wanted phase
* @returns the found phase or undefined if none found
*/
findPhase<P extends Phase = Phase>(phaseFilter: (phase: P) => boolean): P | undefined {
return this.phaseQueue.find(phaseFilter) as P;
}
tryReplacePhase(phaseFilter: (phase: Phase) => boolean, phase: Phase): boolean {
const phaseIndex = this.phaseQueue.findIndex(phaseFilter);
if (phaseIndex > -1) {
this.phaseQueue[phaseIndex] = phase;
return true;
}
return false;
}
tryRemovePhase(phaseFilter: (phase: Phase) => boolean): boolean {
const phaseIndex = this.phaseQueue.findIndex(phaseFilter);
if (phaseIndex > -1) {
this.phaseQueue.splice(phaseIndex, 1);
return true;
}
return false;
}
/**
* 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 {
const phaseIndex = this.phaseQueuePrepend.findIndex(phaseFilter);
if (phaseIndex > -1) {
this.phaseQueuePrepend.splice(phaseIndex, 1);
return true;
}
return false;
}
/**
* Tries to add the input phase to index before target phase in the phaseQueue, else simply calls unshiftPhase()
* @param phase {@linkcode Phase} the phase to be added
* @param targetPhase {@linkcode Phase} the type of phase to search for in phaseQueue
* @returns boolean if a targetPhase was found and added
*/
prependToPhase(phase: Phase | Phase[], targetPhase: Constructor<Phase>): boolean {
if (!Array.isArray(phase)) {
phase = [phase];
}
const targetIndex = this.phaseQueue.findIndex(ph => ph instanceof targetPhase);
if (targetIndex !== -1) {
this.phaseQueue.splice(targetIndex, 0, ...phase);
return true;
}
this.unshiftPhase(...phase);
return false;
}
/**
* Tries to add the input phase(s) to index after target phase in the {@linkcode phaseQueue}, else simply calls {@linkcode unshiftPhase()}
* @param phase {@linkcode Phase} the phase(s) to be added
* @param targetPhase {@linkcode Phase} the type of phase to search for in {@linkcode phaseQueue}
* @returns `true` if a `targetPhase` was found to append to
*/
appendToPhase(phase: Phase | Phase[], targetPhase: Constructor<Phase>): boolean {
if (!Array.isArray(phase)) {
phase = [phase];
}
const targetIndex = this.phaseQueue.findIndex(ph => ph instanceof targetPhase);
if (targetIndex !== -1 && this.phaseQueue.length > targetIndex) {
this.phaseQueue.splice(targetIndex + 1, 0, ...phase);
return true;
}
this.unshiftPhase(...phase);
return false;
}
/**
* Adds a MessagePhase, either to PhaseQueuePrepend or nextCommandPhaseQueue
* @param message string for MessagePhase
* @param callbackDelay optional param for MessagePhase constructor
* @param prompt optional param for MessagePhase constructor
* @param promptDelay optional param for MessagePhase constructor
* @param defer boolean for which queue to add it to, false -> add to PhaseQueuePrepend, true -> nextCommandPhaseQueue
*/
queueMessage(
message: string,
callbackDelay?: number | null,
prompt?: boolean | null,
promptDelay?: number | null,
defer?: boolean | null,
) {
const phase = new MessagePhase(message, callbackDelay, prompt, promptDelay);
if (!defer) {
// adds to the end of PhaseQueuePrepend
this.unshiftPhase(phase);
} else {
//remember that pushPhase adds it to nextCommandPhaseQueue
this.pushPhase(phase);
}
}
/**
* Queues an ability bar flyout phase
* @param pokemon The pokemon who has the ability
* @param passive Whether the ability is a passive
* @param show Whether to show or hide the bar
*/
public queueAbilityDisplay(pokemon: Pokemon, passive: boolean, show: boolean): void {
this.unshiftPhase(show ? new ShowAbilityPhase(pokemon.getBattlerIndex(), passive) : new HideAbilityPhase());
this.clearPhaseQueueSplice();
}
/**
* Hides the ability bar if it is currently visible
*/
public hideAbilityBar(): void {
if (this.abilityBar.isVisible()) {
this.unshiftPhase(new HideAbilityPhase());
}
}
/**
* Moves everything from nextCommandPhaseQueue to phaseQueue (keeping order)
*/
populatePhaseQueue(): void {
if (this.nextCommandPhaseQueue.length) {
this.phaseQueue.push(...this.nextCommandPhaseQueue);
this.nextCommandPhaseQueue.splice(0, this.nextCommandPhaseQueue.length);
}
this.phaseQueue.push(new TurnInitPhase());
}
addMoney(amount: number): void {
this.money = Math.min(this.money + amount, Number.MAX_SAFE_INTEGER);
this.updateMoneyText();
@ -2942,7 +2647,7 @@ export default class BattleScene extends SceneBase {
}
} else if (!virtual) {
const defaultModifierType = getDefaultModifierTypeForTier(modifier.type.tier);
this.queueMessage(
this.phaseManager.queueMessage(
i18next.t("battle:itemStackFull", {
fullItemName: modifier.type.name,
itemName: defaultModifierType.name,
@ -3499,11 +3204,11 @@ export default class BattleScene extends SceneBase {
phase = new QuietFormChangePhase(pokemon, matchingFormChange);
}
if (pokemon.isPlayer() && !matchingFormChange.quiet && modal) {
this.overridePhase(phase);
this.phaseManager.overridePhase(phase);
} else if (delayed) {
this.pushPhase(phase);
this.phaseManager.pushPhase(phase);
} else {
this.unshiftPhase(phase);
this.phaseManager.unshiftPhase(phase);
}
return true;
}
@ -3520,9 +3225,9 @@ export default class BattleScene extends SceneBase {
): boolean {
const phase: Phase = new PokemonAnimPhase(battleAnimType, pokemon, fieldAssets);
if (delayed) {
this.pushPhase(phase);
this.phaseManager.pushPhase(phase);
} else {
this.unshiftPhase(phase);
this.phaseManager.unshiftPhase(phase);
}
return true;
}
@ -3630,19 +3335,19 @@ export default class BattleScene extends SceneBase {
this.currentBattle.double = true;
const availablePartyMembers = this.getPlayerParty().filter(p => p.isAllowedInBattle());
if (availablePartyMembers.length > 1) {
this.pushPhase(new ToggleDoublePositionPhase(true));
this.phaseManager.pushPhase(new ToggleDoublePositionPhase(true));
if (!availablePartyMembers[1].isOnField()) {
this.pushPhase(new SummonPhase(1));
this.phaseManager.pushPhase(new SummonPhase(1));
}
}
this.shiftPhase();
this.phaseManager.shiftPhase();
},
);
return;
}
this.shiftPhase();
this.phaseManager.shiftPhase();
}
/**
@ -3754,7 +3459,7 @@ export default class BattleScene extends SceneBase {
if (exp) {
const partyMemberIndex = party.indexOf(expPartyMembers[pm]);
this.unshiftPhase(
this.phaseManager.unshiftPhase(
expPartyMembers[pm].isOnField()
? new ExpPhase(partyMemberIndex, exp)
: new ShowPartyExpBarPhase(partyMemberIndex, exp),

View File

@ -205,7 +205,7 @@ export default class Battle {
const message = i18next.t("battle:moneyPickedUp", {
moneyAmount: formattedMoneyAmount,
});
globalScene.queueMessage(message, undefined, true);
globalScene.phaseManager.queueMessage(message, undefined, true);
globalScene.currentBattle.moneyScattered = 0;
}

View File

@ -159,7 +159,7 @@ export class PostTeraFormChangeStatChangeAbAttr extends AbAttr {
statStageChangePhases.push(new StatStageChangePhase(pokemon.getBattlerIndex(), true, this.stats, this.stages));
for (const statStageChangePhase of statStageChangePhases) {
globalScene.unshiftPhase(statStageChangePhase);
globalScene.phaseManager.unshiftPhase(statStageChangePhase);
}
}
}
@ -410,7 +410,7 @@ export class TypeImmunityHealAbAttr extends TypeImmunityAbAttr {
super.applyPreDefend(pokemon, passive, simulated, attacker, move, cancelled, args);
if (!pokemon.isFullHp() && !simulated) {
const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name;
globalScene.unshiftPhase(new PokemonHealPhase(pokemon.getBattlerIndex(),
globalScene.phaseManager.unshiftPhase(new PokemonHealPhase(pokemon.getBattlerIndex(),
toDmgValue(pokemon.getMaxHp() / 4), i18next.t("abilityTriggers:typeImmunityHeal", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName }), true));
cancelled.value = true; // Suppresses "No Effect" message
}
@ -436,7 +436,7 @@ class TypeImmunityStatStageChangeAbAttr extends TypeImmunityAbAttr {
super.applyPreDefend(pokemon, passive, simulated, attacker, move, cancelled, args);
cancelled.value = true; // Suppresses "No Effect" message
if (!simulated) {
globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [ this.stat ], this.stages));
globalScene.phaseManager.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [ this.stat ], this.stages));
}
}
}
@ -648,7 +648,7 @@ export class MoveImmunityStatStageChangeAbAttr extends MoveImmunityAbAttr {
override applyPreDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, cancelled: BooleanHolder, args: any[]): void {
super.applyPreDefend(pokemon, passive, simulated, attacker, move, cancelled, args);
globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [ this.stat ], this.stages));
globalScene.phaseManager.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [ this.stat ], this.stages));
}
}
/**
@ -675,7 +675,7 @@ export class ReverseDrainAbAttr extends PostDefendAbAttr {
*/
override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, _args: any[]): void {
if (!simulated) {
globalScene.queueMessage(i18next.t("abilityTriggers:reverseDrain", { pokemonNameWithAffix: getPokemonNameWithAffix(attacker) }));
globalScene.phaseManager.queueMessage(i18next.t("abilityTriggers:reverseDrain", { pokemonNameWithAffix: getPokemonNameWithAffix(attacker) }));
}
}
}
@ -710,10 +710,10 @@ export class PostDefendStatStageChangeAbAttr extends PostDefendAbAttr {
const ally = pokemon.getAlly();
const otherPokemon = !isNullOrUndefined(ally) ? pokemon.getOpponents().concat([ ally ]) : pokemon.getOpponents();
for (const other of otherPokemon) {
globalScene.unshiftPhase(new StatStageChangePhase((other).getBattlerIndex(), false, [ this.stat ], this.stages));
globalScene.phaseManager.unshiftPhase(new StatStageChangePhase((other).getBattlerIndex(), false, [ this.stat ], this.stages));
}
} else {
globalScene.unshiftPhase(new StatStageChangePhase((this.selfTarget ? pokemon : attacker).getBattlerIndex(), this.selfTarget, [ this.stat ], this.stages));
globalScene.phaseManager.unshiftPhase(new StatStageChangePhase((this.selfTarget ? pokemon : attacker).getBattlerIndex(), this.selfTarget, [ this.stat ], this.stages));
}
}
}
@ -744,7 +744,7 @@ export class PostDefendHpGatedStatStageChangeAbAttr extends PostDefendAbAttr {
override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, _args: any[]): void {
if (!simulated) {
globalScene.unshiftPhase(new StatStageChangePhase((this.selfTarget ? pokemon : attacker).getBattlerIndex(), true, this.stats, this.stages));
globalScene.phaseManager.unshiftPhase(new StatStageChangePhase((this.selfTarget ? pokemon : attacker).getBattlerIndex(), true, this.stats, this.stages));
}
}
}
@ -790,7 +790,7 @@ export class PostDefendApplyBattlerTagAbAttr extends PostDefendAbAttr {
override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, _args: any[]): void {
if (!pokemon.getTag(this.tagType) && !simulated) {
pokemon.addTag(this.tagType, undefined, undefined, pokemon.id);
globalScene.queueMessage(i18next.t("abilityTriggers:windPowerCharged", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: move.name }));
globalScene.phaseManager.queueMessage(i18next.t("abilityTriggers:windPowerCharged", { pokemonName: getPokemonNameWithAffix(pokemon), moveName: move.name }));
}
}
}
@ -915,7 +915,7 @@ export class PostDefendCritStatStageChangeAbAttr extends PostDefendAbAttr {
override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, _args: any[]): void {
if (!simulated) {
globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [ this.stat ], this.stages));
globalScene.phaseManager.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [ this.stat ], this.stages));
}
}
@ -1099,7 +1099,7 @@ export class PostStatStageChangeStatStageChangeAbAttr extends PostStatStageChang
override applyPostStatStageChange(pokemon: Pokemon, simulated: boolean, statStagesChanged: BattleStat[], stagesChanged: number, selfTarget: boolean, args: any[]): void {
if (!simulated) {
globalScene.unshiftPhase(new StatStageChangePhase((pokemon).getBattlerIndex(), true, this.statsToChange, this.stages));
globalScene.phaseManager.unshiftPhase(new StatStageChangePhase((pokemon).getBattlerIndex(), true, this.statsToChange, this.stages));
}
}
}
@ -1765,7 +1765,7 @@ export class PostAttackStealHeldItemAbAttr extends PostAttackAbAttr {
this.stolenItem = heldItems[pokemon.randBattleSeedInt(heldItems.length)];
}
if (globalScene.tryTransferHeldItemModifier(this.stolenItem, pokemon, false)) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("abilityTriggers:postAttackStealHeldItem", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
defenderName: defender.name,
@ -1892,7 +1892,7 @@ export class PostDefendStealHeldItemAbAttr extends PostDefendAbAttr {
this.stolenItem = heldItems[pokemon.randBattleSeedInt(heldItems.length)];
}
if (globalScene.tryTransferHeldItemModifier(this.stolenItem, pokemon, false)) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("abilityTriggers:postDefendStealHeldItem", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
attackerName: attacker.name,
@ -1999,7 +1999,7 @@ class PostVictoryStatStageChangeAbAttr extends PostVictoryAbAttr {
override applyPostVictory(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): void {
const stat = typeof this.stat === "function" ? this.stat(pokemon) : this.stat;
if (!simulated) {
globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [ stat ], this.stages));
globalScene.phaseManager.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [ stat ], this.stages));
}
}
}
@ -2047,7 +2047,7 @@ export class PostKnockOutStatStageChangeAbAttr extends PostKnockOutAbAttr {
override applyPostKnockOut(pokemon: Pokemon, passive: boolean, simulated: boolean, knockedOut: Pokemon, args: any[]): void {
const stat = typeof this.stat === "function" ? this.stat(pokemon) : this.stat;
if (!simulated) {
globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [ stat ], this.stages));
globalScene.phaseManager.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [ stat ], this.stages));
}
}
}
@ -2064,7 +2064,7 @@ export class CopyFaintedAllyAbilityAbAttr extends PostKnockOutAbAttr {
override applyPostKnockOut(pokemon: Pokemon, passive: boolean, simulated: boolean, knockedOut: Pokemon, args: any[]): void {
if (!simulated) {
pokemon.setTempAbility(knockedOut.getAbility());
globalScene.queueMessage(i18next.t("abilityTriggers:copyFaintedAllyAbility", { pokemonNameWithAffix: getPokemonNameWithAffix(knockedOut), abilityName: allAbilities[knockedOut.getAbility().id].name }));
globalScene.phaseManager.queueMessage(i18next.t("abilityTriggers:copyFaintedAllyAbility", { pokemonNameWithAffix: getPokemonNameWithAffix(knockedOut), abilityName: allAbilities[knockedOut.getAbility().id].name }));
}
}
}
@ -2130,7 +2130,7 @@ export class PostIntimidateStatStageChangeAbAttr extends AbAttr {
override apply(pokemon: Pokemon, passive: boolean, simulated:boolean, cancelled: BooleanHolder, args: any[]): void {
if (!simulated) {
globalScene.pushPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), false, this.stats, this.stages));
globalScene.phaseManager.pushPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), false, this.stats, this.stages));
}
cancelled.value = this.overwrites;
}
@ -2240,7 +2240,7 @@ export class PostSummonMessageAbAttr extends PostSummonAbAttr {
override applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): void {
if (!simulated) {
globalScene.queueMessage(this.messageFunc(pokemon));
globalScene.phaseManager.queueMessage(this.messageFunc(pokemon));
}
}
}
@ -2257,7 +2257,7 @@ export class PostSummonUnnamedMessageAbAttr extends PostSummonAbAttr {
override applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): void {
if (!simulated) {
globalScene.queueMessage(this.message);
globalScene.phaseManager.queueMessage(this.message);
}
}
}
@ -2332,7 +2332,7 @@ export class PostSummonStatStageChangeAbAttr extends PostSummonAbAttr {
if (this.selfTarget) {
// we unshift the StatStageChangePhase to put it right after the showAbility and not at the end of the
// phase list (which could be after CommandPhase for example)
globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, this.stats, this.stages));
globalScene.phaseManager.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, this.stats, this.stages));
} else {
for (const opponent of pokemon.getOpponents()) {
const cancelled = new BooleanHolder(false);
@ -2345,7 +2345,7 @@ export class PostSummonStatStageChangeAbAttr extends PostSummonAbAttr {
}
}
if (!cancelled.value) {
globalScene.unshiftPhase(new StatStageChangePhase(opponent.getBattlerIndex(), false, this.stats, this.stages));
globalScene.phaseManager.unshiftPhase(new StatStageChangePhase(opponent.getBattlerIndex(), false, this.stats, this.stages));
}
}
}
@ -2370,7 +2370,7 @@ export class PostSummonAllyHealAbAttr extends PostSummonAbAttr {
override applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): void {
const target = pokemon.getAlly();
if (!simulated && !isNullOrUndefined(target)) {
globalScene.unshiftPhase(new PokemonHealPhase(target.getBattlerIndex(),
globalScene.phaseManager.unshiftPhase(new PokemonHealPhase(target.getBattlerIndex(),
toDmgValue(pokemon.getMaxHp() / this.healRatio), i18next.t("abilityTriggers:postSummonAllyHeal", { pokemonNameWithAffix: getPokemonNameWithAffix(target), pokemonName: pokemon.name }), true, !this.showAnim));
}
}
@ -2400,7 +2400,7 @@ export class PostSummonClearAllyStatStagesAbAttr extends PostSummonAbAttr {
target.setStatStage(s, 0);
}
globalScene.queueMessage(i18next.t("abilityTriggers:postSummonClearAllyStats", { pokemonNameWithAffix: getPokemonNameWithAffix(target) }));
globalScene.phaseManager.queueMessage(i18next.t("abilityTriggers:postSummonClearAllyStats", { pokemonNameWithAffix: getPokemonNameWithAffix(target) }));
}
}
}
@ -2448,7 +2448,7 @@ export class DownloadAbAttr extends PostSummonAbAttr {
}
if (!simulated) {
globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), false, this.stats, 1));
globalScene.phaseManager.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), false, this.stats, 1));
}
}
}
@ -2635,7 +2635,7 @@ export class PostSummonUserFieldRemoveStatusEffectAbAttr extends PostSummonAbAtt
if (!simulated) {
for (const pokemon of allowedParty) {
if (pokemon.status && this.statusEffect.includes(pokemon.status.effect)) {
globalScene.queueMessage(getStatusEffectHealText(pokemon.status.effect, getPokemonNameWithAffix(pokemon)));
globalScene.phaseManager.queueMessage(getStatusEffectHealText(pokemon.status.effect, getPokemonNameWithAffix(pokemon)));
pokemon.resetStatus(false);
pokemon.updateInfo();
}
@ -2725,7 +2725,7 @@ export class PostSummonTransformAbAttr extends PostSummonAbAttr {
override applyPostSummon(pokemon: Pokemon, _passive: boolean, simulated: boolean, _args: any[]): void {
const target = this.getTarget(pokemon.getOpponents());
globalScene.unshiftPhase(new PokemonTransformPhase(pokemon.getBattlerIndex(), target.getBattlerIndex(), true));
globalScene.phaseManager.unshiftPhase(new PokemonTransformPhase(pokemon.getBattlerIndex(), target.getBattlerIndex(), true));
}
}
@ -2820,7 +2820,7 @@ export class CommanderAbAttr extends AbAttr {
// Apply boosts from this effect to the ally Dondozo
pokemon.getAlly()?.addTag(BattlerTagType.COMMANDED, 0, MoveId.NONE, pokemon.id);
// Cancel the source Pokemon's next move (if a move is queued)
globalScene.tryRemovePhase((phase) => phase.is("MovePhase") && phase.pokemon === pokemon);
globalScene.phaseManager.tryRemovePhase((phase) => phase.is("MovePhase") && phase.pokemon === pokemon);
}
}
}
@ -3076,7 +3076,7 @@ export class ReflectStatStageChangeAbAttr extends PreStatStageChangeAbAttr {
const stages = args[1];
this.reflectedStat = stat;
if (!simulated) {
globalScene.unshiftPhase(new StatStageChangePhase(attacker.getBattlerIndex(), false, [ stat ], stages, true, false, true, null, true));
globalScene.phaseManager.unshiftPhase(new StatStageChangePhase(attacker.getBattlerIndex(), false, [ stat ], stages, true, false, true, null, true));
}
cancelled.value = true;
}
@ -3768,7 +3768,7 @@ export class ForewarnAbAttr extends PostSummonAbAttr {
}
}
if (!simulated) {
globalScene.queueMessage(i18next.t("abilityTriggers:forewarn", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: maxMove }));
globalScene.phaseManager.queueMessage(i18next.t("abilityTriggers:forewarn", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: maxMove }));
}
}
}
@ -3781,7 +3781,7 @@ export class FriskAbAttr extends PostSummonAbAttr {
override applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): void {
if (!simulated) {
for (const opponent of pokemon.getOpponents()) {
globalScene.queueMessage(i18next.t("abilityTriggers:frisk", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), opponentName: opponent.name, opponentAbilityName: opponent.getAbility().name }));
globalScene.phaseManager.queueMessage(i18next.t("abilityTriggers:frisk", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), opponentName: opponent.name, opponentAbilityName: opponent.getAbility().name }));
setAbilityRevealed(opponent);
}
}
@ -3913,7 +3913,7 @@ export class PostWeatherLapseHealAbAttr extends PostWeatherLapseAbAttr {
override applyPostWeatherLapse(pokemon: Pokemon, passive: boolean, simulated: boolean, weather: Weather, args: any[]): void {
const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name;
if (!simulated) {
globalScene.unshiftPhase(new PokemonHealPhase(pokemon.getBattlerIndex(),
globalScene.phaseManager.unshiftPhase(new PokemonHealPhase(pokemon.getBattlerIndex(),
toDmgValue(pokemon.getMaxHp() / (16 / this.healFactor)), i18next.t("abilityTriggers:postWeatherLapseHeal", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName }), true));
}
}
@ -3935,7 +3935,7 @@ export class PostWeatherLapseDamageAbAttr extends PostWeatherLapseAbAttr {
override applyPostWeatherLapse(pokemon: Pokemon, passive: boolean, simulated: boolean, weather: Weather, args: any[]): void {
if (!simulated) {
const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name;
globalScene.queueMessage(i18next.t("abilityTriggers:postWeatherLapseDamage", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName }));
globalScene.phaseManager.queueMessage(i18next.t("abilityTriggers:postWeatherLapseDamage", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName }));
pokemon.damageAndUpdate(toDmgValue(pokemon.getMaxHp() / (16 / this.damageFactor)), { result: HitResult.INDIRECT });
}
}
@ -4015,7 +4015,7 @@ export class PostTurnStatusHealAbAttr extends PostTurnAbAttr {
override applyPostTurn(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): void {
if (!simulated) {
const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name;
globalScene.unshiftPhase(new PokemonHealPhase(pokemon.getBattlerIndex(),
globalScene.phaseManager.unshiftPhase(new PokemonHealPhase(pokemon.getBattlerIndex(),
toDmgValue(pokemon.getMaxHp() / 8), i18next.t("abilityTriggers:poisonHeal", { pokemonName: getPokemonNameWithAffix(pokemon), abilityName }), true));
}
}
@ -4047,7 +4047,7 @@ export class PostTurnResetStatusAbAttr extends PostTurnAbAttr {
override applyPostTurn(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): void {
if (!simulated && this.target?.status) {
globalScene.queueMessage(getStatusEffectHealText(this.target.status?.effect, getPokemonNameWithAffix(this.target)));
globalScene.phaseManager.queueMessage(getStatusEffectHealText(this.target.status?.effect, getPokemonNameWithAffix(this.target)));
this.target.resetStatus(false);
this.target.updateInfo();
}
@ -4132,7 +4132,7 @@ export class PostTurnRestoreBerryAbAttr extends PostTurnAbAttr {
}
globalScene.updateModifiers(pokemon.isPlayer());
globalScene.queueMessage(i18next.t("abilityTriggers:postTurnLootCreateEatenBerry", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), berryName: chosenBerry.name }));
globalScene.phaseManager.queueMessage(i18next.t("abilityTriggers:postTurnLootCreateEatenBerry", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), berryName: chosenBerry.name }));
return true;
}
}
@ -4162,7 +4162,7 @@ export class RepeatBerryNextTurnAbAttr extends PostTurnAbAttr {
* @param _args - N/A
*/
override apply(pokemon: Pokemon, _passive: boolean, _simulated: boolean, _cancelled: BooleanHolder | null, _args: any[]): void {
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new CommonAnimPhase(pokemon.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.USE_ITEM),
);
@ -4226,11 +4226,11 @@ export class MoodyAbAttr extends PostTurnAbAttr {
if (canRaise.length > 0) {
const raisedStat = canRaise[pokemon.randBattleSeedInt(canRaise.length)];
canLower = canRaise.filter(s => s !== raisedStat);
globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [ raisedStat ], 2));
globalScene.phaseManager.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [ raisedStat ], 2));
}
if (canLower.length > 0) {
const loweredStat = canLower[pokemon.randBattleSeedInt(canLower.length)];
globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [ loweredStat ], -1));
globalScene.phaseManager.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [ loweredStat ], -1));
}
}
}
@ -4247,7 +4247,7 @@ export class SpeedBoostAbAttr extends PostTurnAbAttr {
}
override applyPostTurn(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): void {
globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [ Stat.SPD ], 1));
globalScene.phaseManager.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [ Stat.SPD ], 1));
}
}
@ -4259,7 +4259,7 @@ export class PostTurnHealAbAttr extends PostTurnAbAttr {
override applyPostTurn(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): void {
if (!simulated) {
const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name;
globalScene.unshiftPhase(new PokemonHealPhase(pokemon.getBattlerIndex(),
globalScene.phaseManager.unshiftPhase(new PokemonHealPhase(pokemon.getBattlerIndex(),
toDmgValue(pokemon.getMaxHp() / 16), i18next.t("abilityTriggers:postTurnHeal", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName }), true));
}
}
@ -4305,7 +4305,7 @@ export class PostTurnHurtIfSleepingAbAttr extends PostTurnAbAttr {
if ((opp.status?.effect === StatusEffect.SLEEP || opp.hasAbility(AbilityId.COMATOSE)) && !opp.hasAbilityWithAttr(BlockNonDirectDamageAbAttr) && !opp.switchOutStatus) {
if (!simulated) {
opp.damageAndUpdate(toDmgValue(opp.getMaxHp() / 8), { result: HitResult.INDIRECT });
globalScene.queueMessage(i18next.t("abilityTriggers:badDreams", { pokemonName: getPokemonNameWithAffix(opp) }));
globalScene.phaseManager.queueMessage(i18next.t("abilityTriggers:badDreams", { pokemonName: getPokemonNameWithAffix(opp) }));
}
}
}
@ -4336,7 +4336,7 @@ export class FetchBallAbAttr extends PostTurnAbAttr {
const lastUsed = globalScene.currentBattle.lastUsedPokeball;
globalScene.pokeballCounts[lastUsed!]++;
globalScene.currentBattle.lastUsedPokeball = null;
globalScene.queueMessage(i18next.t("abilityTriggers:fetchBall", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), pokeballName: getPokeballName(lastUsed!) }));
globalScene.phaseManager.queueMessage(i18next.t("abilityTriggers:fetchBall", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), pokeballName: getPokeballName(lastUsed!) }));
}
}
@ -4442,10 +4442,10 @@ 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() instanceof AttackMove || move.getMove() instanceof StatusMove) {
const target = this.getTarget(dancer, source, targets);
globalScene.unshiftPhase(new MovePhase(dancer, target, move, true, true));
globalScene.phaseManager.unshiftPhase(new MovePhase(dancer, target, move, true, true));
} else if (move.getMove() instanceof SelfStatusMove) {
// If the move is a SelfStatusMove (ie. Swords Dance) the Dancer should replicate it on itself
globalScene.unshiftPhase(new MovePhase(dancer, [ dancer.getBattlerIndex() ], move, true, true));
globalScene.phaseManager.unshiftPhase(new MovePhase(dancer, [ dancer.getBattlerIndex() ], move, true, true));
}
}
}
@ -4525,7 +4525,7 @@ export class StatStageChangeCopyAbAttr extends AbAttr {
args: any[],
): void {
if (!simulated) {
globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, (args[0] as BattleStat[]), (args[1] as number), true, false, false));
globalScene.phaseManager.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, (args[0] as BattleStat[]), (args[1] as number), true, false, false));
}
}
}
@ -4606,7 +4606,7 @@ export class HealFromBerryUseAbAttr extends AbAttr {
}
const { name: abilityName } = passive ? pokemon.getPassiveAbility() : pokemon.getAbility();
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new PokemonHealPhase(
pokemon.getBattlerIndex(),
toDmgValue(pokemon.getMaxHp() * this.healPercent),
@ -4739,7 +4739,7 @@ export class PostBattleLootAbAttr extends PostBattleAbAttr {
if (globalScene.tryTransferHeldItemModifier(this.randItem, pokemon, true, 1, true, undefined, false)) {
postBattleLoot.splice(postBattleLoot.indexOf(this.randItem), 1);
globalScene.queueMessage(i18next.t("abilityTriggers:postBattleLoot", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), itemName: this.randItem.type.name }));
globalScene.phaseManager.queueMessage(i18next.t("abilityTriggers:postBattleLoot", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), itemName: this.randItem.type.name }));
}
this.randItem = undefined;
}
@ -4927,7 +4927,7 @@ export class FlinchStatStageChangeAbAttr extends FlinchEffectAbAttr {
override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: BooleanHolder, args: any[]): void {
if (!simulated) {
globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, this.stats, this.stages));
globalScene.phaseManager.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, this.stats, this.stages));
}
}
}
@ -5495,16 +5495,16 @@ function applySingleAbAttrs<TAttr extends AbAttr>(
continue;
}
globalScene.setPhaseQueueSplice();
globalScene.phaseManager.setPhaseQueueSplice();
if (attr.showAbility && !simulated) {
globalScene.queueAbilityDisplay(pokemon, passive, true);
globalScene.phaseManager.queueAbilityDisplay(pokemon, passive, true);
abShown = true;
}
const message = attr.getTriggerMessage(pokemon, ability.name, args);
if (message) {
if (!simulated) {
globalScene.queueMessage(message);
globalScene.phaseManager.queueMessage(message);
}
messages.push(message);
}
@ -5512,14 +5512,14 @@ function applySingleAbAttrs<TAttr extends AbAttr>(
applyFunc(attr, passive);
if (abShown) {
globalScene.queueAbilityDisplay(pokemon, passive, false);
globalScene.phaseManager.queueAbilityDisplay(pokemon, passive, false);
}
if (!simulated) {
pokemon.waveData.abilitiesApplied.add(ability.id);
}
globalScene.clearPhaseQueueSplice();
globalScene.phaseManager.clearPhaseQueueSplice();
}
}
@ -5546,7 +5546,7 @@ class ForceSwitchOutHelper {
if (switchOutTarget.hp > 0) {
switchOutTarget.leaveField(this.switchType === SwitchType.SWITCH);
globalScene.prependToPhase(new SwitchPhase(this.switchType, switchOutTarget.getFieldIndex(), true, true), MoveEndPhase);
globalScene.phaseManager.prependToPhase(new SwitchPhase(this.switchType, switchOutTarget.getFieldIndex(), true, true), MoveEndPhase);
return true;
}
/**
@ -5560,7 +5560,7 @@ class ForceSwitchOutHelper {
if (switchOutTarget.hp > 0) {
switchOutTarget.leaveField(this.switchType === SwitchType.SWITCH);
const summonIndex = (globalScene.currentBattle.trainer ? globalScene.currentBattle.trainer.getNextSummonIndex((switchOutTarget as EnemyPokemon).trainerSlot) : 0);
globalScene.prependToPhase(new SwitchSummonPhase(this.switchType, switchOutTarget.getFieldIndex(), summonIndex, false, false), MoveEndPhase);
globalScene.phaseManager.prependToPhase(new SwitchSummonPhase(this.switchType, switchOutTarget.getFieldIndex(), summonIndex, false, false), MoveEndPhase);
return true;
}
/**
@ -5576,7 +5576,7 @@ class ForceSwitchOutHelper {
if (switchOutTarget.hp > 0) {
switchOutTarget.leaveField(false);
globalScene.queueMessage(i18next.t("moveTriggers:fled", { pokemonName: getPokemonNameWithAffix(switchOutTarget) }), null, true, 500);
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:fled", { pokemonName: getPokemonNameWithAffix(switchOutTarget) }), null, true, 500);
if (globalScene.currentBattle.double && !isNullOrUndefined(allyPokemon)) {
globalScene.redirectPokemonMoves(switchOutTarget, allyPokemon);
}
@ -5586,13 +5586,13 @@ class ForceSwitchOutHelper {
globalScene.clearEnemyHeldItemModifiers();
if (switchOutTarget.hp) {
globalScene.pushPhase(new BattleEndPhase(false));
globalScene.phaseManager.pushPhase(new BattleEndPhase(false));
if (globalScene.gameMode.hasRandomBiomes || globalScene.isNewBiome()) {
globalScene.pushPhase(new SelectBiomePhase());
globalScene.phaseManager.pushPhase(new SelectBiomePhase());
}
globalScene.pushPhase(new NewBattlePhase());
globalScene.phaseManager.pushPhase(new NewBattlePhase());
}
}
}
@ -5792,7 +5792,7 @@ function applyAbAttrsInternal<TAttr extends AbAttr>(
for (const passive of [ false, true ]) {
if (pokemon) {
applySingleAbAttrs(pokemon, passive, attrType, applyFunc, successFunc, args, gainedMidTurn, simulated, messages);
globalScene.clearPhaseQueueSplice();
globalScene.phaseManager.clearPhaseQueueSplice();
}
}
}
@ -6870,7 +6870,7 @@ export function initAbilities() {
.ignorable(),
new Ability(AbilityId.ANALYTIC, 5)
.attr(MovePowerBoostAbAttr, (user, target, move) => {
const movePhase = globalScene.findPhase((phase) => phase.is("MovePhase") && phase.pokemon.id !== user?.id);
const movePhase = globalScene.phaseManager.findPhase((phase) => phase.is("MovePhase") && phase.pokemon.id !== user?.id);
return isNullOrUndefined(movePhase);
}, 1.3),
new Ability(AbilityId.ILLUSION, 5)

View File

@ -54,7 +54,7 @@ export abstract class ArenaTag {
onRemove(_arena: Arena, quiet = false): void {
if (!quiet) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t(
`arenaTag:arenaOnRemove${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`,
{ moveName: this.getMoveName() },
@ -126,7 +126,7 @@ export class MistTag extends ArenaTag {
const source = globalScene.getPokemonById(this.sourceId);
if (!quiet && source) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("arenaTag:mistOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(source),
}),
@ -161,7 +161,7 @@ export class MistTag extends ArenaTag {
cancelled.value = true;
if (!simulated) {
globalScene.queueMessage(i18next.t("arenaTag:mistApply"));
globalScene.phaseManager.queueMessage(i18next.t("arenaTag:mistApply"));
}
return true;
@ -239,7 +239,7 @@ class ReflectTag extends WeakenMoveScreenTag {
onAdd(_arena: Arena, quiet = false): void {
if (!quiet) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t(
`arenaTag:reflectOnAdd${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`,
),
@ -259,7 +259,7 @@ class LightScreenTag extends WeakenMoveScreenTag {
onAdd(_arena: Arena, quiet = false): void {
if (!quiet) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t(
`arenaTag:lightScreenOnAdd${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`,
),
@ -282,7 +282,7 @@ class AuroraVeilTag extends WeakenMoveScreenTag {
onAdd(_arena: Arena, quiet = false): void {
if (!quiet) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t(
`arenaTag:auroraVeilOnAdd${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`,
),
@ -318,7 +318,7 @@ export class ConditionalProtectTag extends ArenaTag {
}
onAdd(_arena: Arena): void {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t(
`arenaTag:conditionalProtectOnAdd${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`,
{ moveName: super.getMoveName() },
@ -355,7 +355,7 @@ export class ConditionalProtectTag extends ArenaTag {
isProtected.value = true;
if (!simulated) {
new CommonBattleAnim(CommonAnim.PROTECT, defender).play();
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("arenaTag:conditionalProtectApply", {
moveName: super.getMoveName(),
pokemonNameWithAffix: getPokemonNameWithAffix(defender),
@ -381,7 +381,7 @@ export class ConditionalProtectTag extends ArenaTag {
*/
const QuickGuardConditionFunc: ProtectConditionFunc = (_arena, moveId) => {
const move = allMoves[moveId];
const effectPhase = globalScene.getCurrentPhase();
const effectPhase = globalScene.phaseManager.getCurrentPhase();
if (effectPhase?.is("MoveEffectPhase")) {
const attacker = effectPhase.getUserPokemon();
@ -458,7 +458,7 @@ class MatBlockTag extends ConditionalProtectTag {
if (this.sourceId) {
const source = globalScene.getPokemonById(this.sourceId);
if (source) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("arenaTag:matBlockOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(source),
}),
@ -517,7 +517,7 @@ export class NoCritTag extends ArenaTag {
/** Queues a message upon adding this effect to the field */
onAdd(_arena: Arena): void {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t(`arenaTag:noCritOnAdd${this.side === ArenaTagSide.PLAYER ? "Player" : "Enemy"}`, {
moveName: this.getMoveName(),
}),
@ -527,7 +527,7 @@ export class NoCritTag extends ArenaTag {
/** Queues a message upon removing this effect from the field */
onRemove(_arena: Arena): void {
const source = globalScene.getPokemonById(this.sourceId!); // TODO: is this bang correct?
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("arenaTag:noCritOnRemove", {
pokemonNameWithAffix: getPokemonNameWithAffix(source ?? undefined),
moveName: this.getMoveName(),
@ -567,8 +567,10 @@ class WishTag extends ArenaTag {
onRemove(_arena: Arena): void {
const target = globalScene.getField()[this.battlerIndex];
if (target?.isActive(true)) {
globalScene.queueMessage(this.triggerMessage);
globalScene.unshiftPhase(new PokemonHealPhase(target.getBattlerIndex(), this.healHp, null, true, false));
globalScene.phaseManager.queueMessage(this.triggerMessage);
globalScene.phaseManager.unshiftPhase(
new PokemonHealPhase(target.getBattlerIndex(), this.healHp, null, true, false),
);
}
}
}
@ -621,11 +623,11 @@ class MudSportTag extends WeakenMoveTypeTag {
}
onAdd(_arena: Arena): void {
globalScene.queueMessage(i18next.t("arenaTag:mudSportOnAdd"));
globalScene.phaseManager.queueMessage(i18next.t("arenaTag:mudSportOnAdd"));
}
onRemove(_arena: Arena): void {
globalScene.queueMessage(i18next.t("arenaTag:mudSportOnRemove"));
globalScene.phaseManager.queueMessage(i18next.t("arenaTag:mudSportOnRemove"));
}
}
@ -639,11 +641,11 @@ class WaterSportTag extends WeakenMoveTypeTag {
}
onAdd(_arena: Arena): void {
globalScene.queueMessage(i18next.t("arenaTag:waterSportOnAdd"));
globalScene.phaseManager.queueMessage(i18next.t("arenaTag:waterSportOnAdd"));
}
onRemove(_arena: Arena): void {
globalScene.queueMessage(i18next.t("arenaTag:waterSportOnRemove"));
globalScene.phaseManager.queueMessage(i18next.t("arenaTag:waterSportOnRemove"));
}
}
@ -659,7 +661,7 @@ export class IonDelugeTag extends ArenaTag {
/** Queues an on-add message */
onAdd(_arena: Arena): void {
globalScene.queueMessage(i18next.t("arenaTag:plasmaFistsOnAdd"));
globalScene.phaseManager.queueMessage(i18next.t("arenaTag:plasmaFistsOnAdd"));
}
onRemove(_arena: Arena): void {} // Removes default on-remove message
@ -758,7 +760,7 @@ class SpikesTag extends ArenaTrapTag {
const source = this.sourceId ? globalScene.getPokemonById(this.sourceId) : null;
if (!quiet && source) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("arenaTag:spikesOnAdd", {
moveName: this.getMoveName(),
opponentDesc: source.getOpponentDescriptor(),
@ -781,7 +783,7 @@ class SpikesTag extends ArenaTrapTag {
const damageHpRatio = 1 / (10 - 2 * this.layers);
const damage = toDmgValue(pokemon.getMaxHp() * damageHpRatio);
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("arenaTag:spikesActivateTrap", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -811,7 +813,7 @@ class ToxicSpikesTag extends ArenaTrapTag {
const source = this.sourceId ? globalScene.getPokemonById(this.sourceId) : null;
if (!quiet && source) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("arenaTag:toxicSpikesOnAdd", {
moveName: this.getMoveName(),
opponentDesc: source.getOpponentDescriptor(),
@ -834,7 +836,7 @@ class ToxicSpikesTag extends ArenaTrapTag {
if (pokemon.isOfType(PokemonType.POISON)) {
this.neutralized = true;
if (globalScene.arena.removeTag(this.tagType)) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("arenaTag:toxicSpikesActivateTrapPoison", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
moveName: this.getMoveName(),
@ -891,7 +893,7 @@ export class DelayedAttackTag extends ArenaTag {
const ret = super.lapse(arena);
if (!ret) {
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new MoveEffectPhase(this.sourceId!, [this.targetIndex], allMoves[this.sourceMove!], false, true),
); // TODO: are those bangs correct?
}
@ -917,7 +919,7 @@ class StealthRockTag extends ArenaTrapTag {
const source = this.sourceId ? globalScene.getPokemonById(this.sourceId) : null;
if (!quiet && source) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("arenaTag:stealthRockOnAdd", {
opponentDesc: source.getOpponentDescriptor(),
}),
@ -971,7 +973,7 @@ class StealthRockTag extends ArenaTrapTag {
}
const damage = toDmgValue(pokemon.getMaxHp() * damageHpRatio);
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("arenaTag:stealthRockActivateTrap", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -1001,7 +1003,7 @@ class StickyWebTag extends ArenaTrapTag {
super.onAdd(arena);
const source = this.sourceId ? globalScene.getPokemonById(this.sourceId) : null;
if (!quiet && source) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("arenaTag:stickyWebOnAdd", {
moveName: this.getMoveName(),
opponentDesc: source.getOpponentDescriptor(),
@ -1020,13 +1022,13 @@ class StickyWebTag extends ArenaTrapTag {
}
if (!cancelled.value) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("arenaTag:stickyWebActivateTrap", {
pokemonName: pokemon.getNameToRender(),
}),
);
const stages = new NumberHolder(-1);
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new StatStageChangePhase(
pokemon.getBattlerIndex(),
false,
@ -1074,7 +1076,7 @@ export class TrickRoomTag extends ArenaTag {
onAdd(_arena: Arena): void {
const source = this.sourceId ? globalScene.getPokemonById(this.sourceId) : null;
if (source) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("arenaTag:trickRoomOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(source),
}),
@ -1083,7 +1085,7 @@ export class TrickRoomTag extends ArenaTag {
}
onRemove(_arena: Arena): void {
globalScene.queueMessage(i18next.t("arenaTag:trickRoomOnRemove"));
globalScene.phaseManager.queueMessage(i18next.t("arenaTag:trickRoomOnRemove"));
}
}
@ -1098,7 +1100,7 @@ export class GravityTag extends ArenaTag {
}
onAdd(_arena: Arena): void {
globalScene.queueMessage(i18next.t("arenaTag:gravityOnAdd"));
globalScene.phaseManager.queueMessage(i18next.t("arenaTag:gravityOnAdd"));
globalScene.getField(true).forEach(pokemon => {
if (pokemon !== null) {
pokemon.removeTag(BattlerTagType.FLOATING);
@ -1111,7 +1113,7 @@ export class GravityTag extends ArenaTag {
}
onRemove(_arena: Arena): void {
globalScene.queueMessage(i18next.t("arenaTag:gravityOnRemove"));
globalScene.phaseManager.queueMessage(i18next.t("arenaTag:gravityOnRemove"));
}
}
@ -1127,7 +1129,7 @@ class TailwindTag extends ArenaTag {
onAdd(_arena: Arena, quiet = false): void {
if (!quiet) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t(
`arenaTag:tailwindOnAdd${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`,
),
@ -1141,7 +1143,7 @@ class TailwindTag extends ArenaTag {
// Apply the CHARGED tag to party members with the WIND_POWER ability
if (pokemon.hasAbility(AbilityId.WIND_POWER) && !pokemon.getTag(BattlerTagType.CHARGED)) {
pokemon.addTag(BattlerTagType.CHARGED);
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("abilityTriggers:windPowerCharged", {
pokemonName: getPokemonNameWithAffix(pokemon),
moveName: this.getMoveName(),
@ -1151,16 +1153,18 @@ class TailwindTag extends ArenaTag {
// Raise attack by one stage if party member has WIND_RIDER ability
// TODO: Ability displays should be handled by the ability
if (pokemon.hasAbility(AbilityId.WIND_RIDER)) {
globalScene.queueAbilityDisplay(pokemon, false, true);
globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [Stat.ATK], 1, true));
globalScene.queueAbilityDisplay(pokemon, false, false);
globalScene.phaseManager.queueAbilityDisplay(pokemon, false, true);
globalScene.phaseManager.unshiftPhase(
new StatStageChangePhase(pokemon.getBattlerIndex(), true, [Stat.ATK], 1, true),
);
globalScene.phaseManager.queueAbilityDisplay(pokemon, false, false);
}
}
}
onRemove(_arena: Arena, quiet = false): void {
if (!quiet) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t(
`arenaTag:tailwindOnRemove${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`,
),
@ -1179,11 +1183,11 @@ class HappyHourTag extends ArenaTag {
}
onAdd(_arena: Arena): void {
globalScene.queueMessage(i18next.t("arenaTag:happyHourOnAdd"));
globalScene.phaseManager.queueMessage(i18next.t("arenaTag:happyHourOnAdd"));
}
onRemove(_arena: Arena): void {
globalScene.queueMessage(i18next.t("arenaTag:happyHourOnRemove"));
globalScene.phaseManager.queueMessage(i18next.t("arenaTag:happyHourOnRemove"));
}
}
@ -1193,7 +1197,7 @@ class SafeguardTag extends ArenaTag {
}
onAdd(_arena: Arena): void {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t(
`arenaTag:safeguardOnAdd${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`,
),
@ -1201,7 +1205,7 @@ class SafeguardTag extends ArenaTag {
}
onRemove(_arena: Arena): void {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t(
`arenaTag:safeguardOnRemove${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`,
),
@ -1237,7 +1241,7 @@ class ImprisonTag extends ArenaTrapTag {
p.addTag(BattlerTagType.IMPRISON, 1, MoveId.IMPRISON, this.sourceId);
}
});
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:imprisonOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(source),
}),
@ -1294,7 +1298,7 @@ class FireGrassPledgeTag extends ArenaTag {
override onAdd(_arena: Arena): void {
// "A sea of fire enveloped your/the opposing team!"
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t(
`arenaTag:fireGrassPledgeOnAdd${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`,
),
@ -1309,13 +1313,13 @@ class FireGrassPledgeTag extends ArenaTag {
.filter(pokemon => !pokemon.isOfType(PokemonType.FIRE) && !pokemon.switchOutStatus)
.forEach(pokemon => {
// "{pokemonNameWithAffix} was hurt by the sea of fire!"
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("arenaTag:fireGrassPledgeLapse", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
);
// TODO: Replace this with a proper animation
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new CommonAnimPhase(pokemon.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.MAGMA_STORM),
);
pokemon.damageAndUpdate(toDmgValue(pokemon.getMaxHp() / 8), { result: HitResult.INDIRECT });
@ -1339,7 +1343,7 @@ class WaterFirePledgeTag extends ArenaTag {
override onAdd(_arena: Arena): void {
// "A rainbow appeared in the sky on your/the opposing team's side!"
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t(
`arenaTag:waterFirePledgeOnAdd${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`,
),
@ -1373,7 +1377,7 @@ class GrassWaterPledgeTag extends ArenaTag {
override onAdd(_arena: Arena): void {
// "A swamp enveloped your/the opposing team!"
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t(
`arenaTag:grassWaterPledgeOnAdd${this.side === ArenaTagSide.PLAYER ? "Player" : this.side === ArenaTagSide.ENEMY ? "Enemy" : ""}`,
),
@ -1394,7 +1398,7 @@ export class FairyLockTag extends ArenaTag {
}
onAdd(_arena: Arena): void {
globalScene.queueMessage(i18next.t("arenaTag:fairyLockOnAdd"));
globalScene.phaseManager.queueMessage(i18next.t("arenaTag:fairyLockOnAdd"));
}
}
@ -1451,7 +1455,7 @@ export class SuppressAbilitiesTag extends ArenaTag {
public override onRemove(_arena: Arena, quiet = false) {
this.beingRemoved = true;
if (!quiet) {
globalScene.queueMessage(i18next.t("arenaTag:neutralizingGasOnRemove"));
globalScene.phaseManager.queueMessage(i18next.t("arenaTag:neutralizingGasOnRemove"));
}
for (const pokemon of globalScene.getField(true)) {
@ -1472,7 +1476,7 @@ export class SuppressAbilitiesTag extends ArenaTag {
private playActivationMessage(pokemon: Pokemon | null) {
if (pokemon) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("arenaTag:neutralizingGasOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),

View File

@ -164,12 +164,12 @@ export abstract class MoveRestrictionBattlerTag extends BattlerTag {
override lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
if (lapseType === BattlerTagLapseType.PRE_MOVE) {
// Cancel the affected pokemon's selected move
const phase = globalScene.getCurrentPhase() as MovePhase;
const phase = globalScene.phaseManager.getCurrentPhase() as MovePhase;
const move = phase.move;
if (this.isMoveRestricted(move.moveId, pokemon)) {
if (this.interruptedText(pokemon, move.moveId)) {
globalScene.queueMessage(this.interruptedText(pokemon, move.moveId));
globalScene.phaseManager.queueMessage(this.interruptedText(pokemon, move.moveId));
}
phase.cancel();
}
@ -315,7 +315,7 @@ export class DisabledTag extends MoveRestrictionBattlerTag {
this.moveId = move.move;
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:disabledOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
moveName: allMoves[this.moveId].name,
@ -327,7 +327,7 @@ export class DisabledTag extends MoveRestrictionBattlerTag {
override onRemove(pokemon: Pokemon): void {
super.onRemove(pokemon);
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:disabledLapse", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
moveName: allMoves[this.moveId].name,
@ -456,12 +456,12 @@ export class RechargingTag extends BattlerTag {
/** Cancels the source's move this turn and queues a "__ must recharge!" message */
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
if (lapseType === BattlerTagLapseType.PRE_MOVE) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:rechargingLapse", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
);
(globalScene.getCurrentPhase() as MovePhase).cancel();
(globalScene.phaseManager.getCurrentPhase() as MovePhase).cancel();
pokemon.getMoveQueue().shift();
}
return super.lapse(pokemon, lapseType);
@ -488,7 +488,7 @@ export class BeakBlastChargingTag extends BattlerTag {
new MoveChargeAnim(ChargeAnim.BEAK_BLAST_CHARGING, this.sourceMove, pokemon).play();
// Queue Beak Blast's header message
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("moveTriggers:startedHeatingUpBeak", {
pokemonName: getPokemonNameWithAffix(pokemon),
}),
@ -533,7 +533,7 @@ export class ShellTrapTag extends BattlerTag {
}
onAdd(pokemon: Pokemon): void {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("moveTriggers:setUpShellTrap", {
pokemonName: getPokemonNameWithAffix(pokemon),
}),
@ -552,15 +552,15 @@ export class ShellTrapTag extends BattlerTag {
// Trap should only be triggered by opponent's Physical moves
if (phaseData?.move.category === MoveCategory.PHYSICAL && pokemon.isOpponent(phaseData.attacker)) {
const shellTrapPhaseIndex = globalScene.phaseQueue.findIndex(
const shellTrapPhaseIndex = globalScene.phaseManager.phaseQueue.findIndex(
phase => phase.is("MovePhase") && phase.pokemon === pokemon,
);
const firstMovePhaseIndex = globalScene.phaseQueue.findIndex(phase => phase.is("MovePhase"));
const firstMovePhaseIndex = globalScene.phaseManager.phaseQueue.findIndex(phase => phase.is("MovePhase"));
// Only shift MovePhase timing if it's not already next up
if (shellTrapPhaseIndex !== -1 && shellTrapPhaseIndex !== firstMovePhaseIndex) {
const shellTrapMovePhase = globalScene.phaseQueue.splice(shellTrapPhaseIndex, 1)[0];
globalScene.prependToPhase(shellTrapMovePhase, MovePhase);
const shellTrapMovePhase = globalScene.phaseManager.phaseQueue.splice(shellTrapPhaseIndex, 1)[0];
globalScene.phaseManager.prependToPhase(shellTrapMovePhase, MovePhase);
}
this.activated = true;
@ -598,13 +598,13 @@ export class TrappedTag extends BattlerTag {
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
globalScene.queueMessage(this.getTrapMessage(pokemon));
globalScene.phaseManager.queueMessage(this.getTrapMessage(pokemon));
}
onRemove(pokemon: Pokemon): void {
super.onRemove(pokemon);
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:trappedOnRemove", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
moveName: this.getMoveName(),
@ -660,8 +660,8 @@ export class FlinchedTag extends BattlerTag {
*/
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
if (lapseType === BattlerTagLapseType.PRE_MOVE) {
(globalScene.getCurrentPhase() as MovePhase).cancel();
globalScene.queueMessage(
(globalScene.phaseManager.getCurrentPhase() as MovePhase).cancel();
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:flinchedLapse", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -699,7 +699,7 @@ export class InterruptedTag extends BattlerTag {
}
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
(globalScene.getCurrentPhase() as MovePhase).cancel();
(globalScene.phaseManager.getCurrentPhase() as MovePhase).cancel();
return super.lapse(pokemon, lapseType);
}
}
@ -719,8 +719,10 @@ export class ConfusedTag extends BattlerTag {
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
globalScene.unshiftPhase(new CommonAnimPhase(pokemon.getBattlerIndex(), undefined, CommonAnim.CONFUSION));
globalScene.queueMessage(
globalScene.phaseManager.unshiftPhase(
new CommonAnimPhase(pokemon.getBattlerIndex(), undefined, CommonAnim.CONFUSION),
);
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:confusedOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -730,7 +732,7 @@ export class ConfusedTag extends BattlerTag {
onRemove(pokemon: Pokemon): void {
super.onRemove(pokemon);
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:confusedOnRemove", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -740,7 +742,7 @@ export class ConfusedTag extends BattlerTag {
onOverlap(pokemon: Pokemon): void {
super.onOverlap(pokemon);
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:confusedOnOverlap", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -754,12 +756,14 @@ export class ConfusedTag extends BattlerTag {
return false;
}
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:confusedLapse", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
);
globalScene.unshiftPhase(new CommonAnimPhase(pokemon.getBattlerIndex(), undefined, CommonAnim.CONFUSION));
globalScene.phaseManager.unshiftPhase(
new CommonAnimPhase(pokemon.getBattlerIndex(), undefined, CommonAnim.CONFUSION),
);
// 1/3 chance of hitting self with a 40 base power move
if (pokemon.randBattleSeedInt(3) === 0 || Overrides.CONFUSION_ACTIVATION_OVERRIDE === true) {
@ -769,9 +773,9 @@ export class ConfusedTag extends BattlerTag {
((((2 * pokemon.level) / 5 + 2) * 40 * atk) / def / 50 + 2) * (pokemon.randBattleSeedIntRange(85, 100) / 100),
);
// Intentionally don't increment rage fist's hitCount
globalScene.queueMessage(i18next.t("battlerTags:confusedLapseHurtItself"));
globalScene.phaseManager.queueMessage(i18next.t("battlerTags:confusedLapseHurtItself"));
pokemon.damageAndUpdate(damage, { result: HitResult.CONFUSION });
(globalScene.getCurrentPhase() as MovePhase).cancel();
(globalScene.phaseManager.getCurrentPhase() as MovePhase).cancel();
}
return true;
@ -815,7 +819,7 @@ export class DestinyBondTag extends BattlerTag {
}
if (pokemon.isBossImmune()) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:destinyBondLapseIsBoss", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -823,7 +827,7 @@ export class DestinyBondTag extends BattlerTag {
return false;
}
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:destinyBondLapse", {
pokemonNameWithAffix: getPokemonNameWithAffix(source),
pokemonNameWithAffix2: getPokemonNameWithAffix(pokemon),
@ -856,7 +860,7 @@ export class InfatuatedTag extends BattlerTag {
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:infatuatedOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
sourcePokemonName: getPokemonNameWithAffix(globalScene.getPokemonById(this.sourceId!) ?? undefined), // TODO: is that bang correct?
@ -867,7 +871,7 @@ export class InfatuatedTag extends BattlerTag {
onOverlap(pokemon: Pokemon): void {
super.onOverlap(pokemon);
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:infatuatedOnOverlap", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -878,21 +882,23 @@ export class InfatuatedTag extends BattlerTag {
const ret = lapseType !== BattlerTagLapseType.CUSTOM || super.lapse(pokemon, lapseType);
if (ret) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:infatuatedLapse", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
sourcePokemonName: getPokemonNameWithAffix(globalScene.getPokemonById(this.sourceId!) ?? undefined), // TODO: is that bang correct?
}),
);
globalScene.unshiftPhase(new CommonAnimPhase(pokemon.getBattlerIndex(), undefined, CommonAnim.ATTRACT));
globalScene.phaseManager.unshiftPhase(
new CommonAnimPhase(pokemon.getBattlerIndex(), undefined, CommonAnim.ATTRACT),
);
if (pokemon.randBattleSeedInt(2)) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:infatuatedLapseImmobilize", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
);
(globalScene.getCurrentPhase() as MovePhase).cancel();
(globalScene.phaseManager.getCurrentPhase() as MovePhase).cancel();
}
}
@ -902,7 +908,7 @@ export class InfatuatedTag extends BattlerTag {
onRemove(pokemon: Pokemon): void {
super.onRemove(pokemon);
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:infatuatedOnRemove", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -941,7 +947,7 @@ export class SeedTag extends BattlerTag {
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:seededOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -959,13 +965,13 @@ export class SeedTag extends BattlerTag {
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled);
if (!cancelled.value) {
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new CommonAnimPhase(source.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.LEECH_SEED),
);
const damage = pokemon.damageAndUpdate(toDmgValue(pokemon.getMaxHp() / 8), { result: HitResult.INDIRECT });
const reverseDrain = pokemon.hasAbilityWithAttr(ReverseDrainAbAttr, false);
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new PokemonHealPhase(
source.getBattlerIndex(),
!reverseDrain ? damage : damage * -1,
@ -1006,7 +1012,7 @@ export class PowderTag extends BattlerTag {
super.onAdd(pokemon);
// "{Pokemon} is covered in powder!"
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:powderOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -1022,7 +1028,7 @@ export class PowderTag extends BattlerTag {
*/
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
if (lapseType === BattlerTagLapseType.PRE_MOVE) {
const movePhase = globalScene.getCurrentPhase();
const movePhase = globalScene.phaseManager.getCurrentPhase();
if (movePhase?.is("MovePhase")) {
const move = movePhase.move.getMove();
const weather = globalScene.arena.weather;
@ -1033,7 +1039,7 @@ export class PowderTag extends BattlerTag {
movePhase.fail();
movePhase.showMoveText();
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new CommonAnimPhase(pokemon.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.POWDER),
);
@ -1044,7 +1050,7 @@ export class PowderTag extends BattlerTag {
}
// "When the flame touched the powder\non the Pokémon, it exploded!"
globalScene.queueMessage(i18next.t("battlerTags:powderLapse", { moveName: move.name }));
globalScene.phaseManager.queueMessage(i18next.t("battlerTags:powderLapse", { moveName: move.name }));
}
}
return true;
@ -1061,7 +1067,7 @@ export class NightmareTag extends BattlerTag {
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:nightmareOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -1071,7 +1077,7 @@ export class NightmareTag extends BattlerTag {
onOverlap(pokemon: Pokemon): void {
super.onOverlap(pokemon);
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:nightmareOnOverlap", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -1082,12 +1088,14 @@ export class NightmareTag extends BattlerTag {
const ret = lapseType !== BattlerTagLapseType.CUSTOM || super.lapse(pokemon, lapseType);
if (ret) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:nightmareLapse", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
);
globalScene.unshiftPhase(new CommonAnimPhase(pokemon.getBattlerIndex(), undefined, CommonAnim.CURSE)); // TODO: Update animation type
globalScene.phaseManager.unshiftPhase(
new CommonAnimPhase(pokemon.getBattlerIndex(), undefined, CommonAnim.CURSE),
); // TODO: Update animation type
const cancelled = new BooleanHolder(false);
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled);
@ -1173,18 +1181,18 @@ export class EncoreTag extends MoveRestrictionBattlerTag {
onAdd(pokemon: Pokemon): void {
super.onRemove(pokemon);
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:encoreOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
);
const movePhase = globalScene.findPhase(m => m.is("MovePhase") && m.pokemon === pokemon);
const movePhase = globalScene.phaseManager.findPhase(m => m.is("MovePhase") && m.pokemon === pokemon);
if (movePhase) {
const movesetMove = pokemon.getMoveset().find(m => m.moveId === this.moveId);
if (movesetMove) {
const lastMove = pokemon.getLastXMoves(1)[0];
globalScene.tryReplacePhase(
globalScene.phaseManager.tryReplacePhase(
m => m.is("MovePhase") && m.pokemon === pokemon,
new MovePhase(pokemon, lastMove.targets ?? [], movesetMove),
);
@ -1221,7 +1229,7 @@ export class EncoreTag extends MoveRestrictionBattlerTag {
onRemove(pokemon: Pokemon): void {
super.onRemove(pokemon);
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:encoreOnRemove", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -1235,7 +1243,7 @@ export class HelpingHandTag extends BattlerTag {
}
onAdd(pokemon: Pokemon): void {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:helpingHandOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(globalScene.getPokemonById(this.sourceId!) ?? undefined), // TODO: is that bang correct?
pokemonName: getPokemonNameWithAffix(pokemon),
@ -1268,7 +1276,7 @@ export class IngrainTag extends TrappedTag {
const ret = lapseType !== BattlerTagLapseType.CUSTOM || super.lapse(pokemon, lapseType);
if (ret) {
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new PokemonHealPhase(
pokemon.getBattlerIndex(),
toDmgValue(pokemon.getMaxHp() / 16),
@ -1307,7 +1315,9 @@ export class OctolockTag extends TrappedTag {
const shouldLapse = lapseType !== BattlerTagLapseType.CUSTOM || super.lapse(pokemon, lapseType);
if (shouldLapse) {
globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), false, [Stat.DEF, Stat.SPDEF], -1));
globalScene.phaseManager.unshiftPhase(
new StatStageChangePhase(pokemon.getBattlerIndex(), false, [Stat.DEF, Stat.SPDEF], -1),
);
return true;
}
@ -1323,7 +1333,7 @@ export class AquaRingTag extends BattlerTag {
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:aquaRingOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -1334,7 +1344,7 @@ export class AquaRingTag extends BattlerTag {
const ret = lapseType !== BattlerTagLapseType.CUSTOM || super.lapse(pokemon, lapseType);
if (ret) {
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new PokemonHealPhase(
pokemon.getBattlerIndex(),
toDmgValue(pokemon.getMaxHp() / 16),
@ -1382,7 +1392,7 @@ export class DrowsyTag extends BattlerTag {
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:drowsyOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -1435,13 +1445,13 @@ export abstract class DamagingTrapTag extends TrappedTag {
const ret = super.lapse(pokemon, lapseType);
if (ret) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:damagingTrapLapse", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
moveName: this.getMoveName(),
}),
);
globalScene.unshiftPhase(new CommonAnimPhase(pokemon.getBattlerIndex(), undefined, this.commonAnim));
globalScene.phaseManager.unshiftPhase(new CommonAnimPhase(pokemon.getBattlerIndex(), undefined, this.commonAnim));
const cancelled = new BooleanHolder(false);
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled);
@ -1596,7 +1606,7 @@ export class ProtectedTag extends BattlerTag {
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:protectedOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -1606,14 +1616,14 @@ export class ProtectedTag extends BattlerTag {
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
if (lapseType === BattlerTagLapseType.CUSTOM) {
new CommonBattleAnim(CommonAnim.PROTECT, pokemon).play();
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:protectedLapse", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
);
// Stop multi-hit moves early
const effectPhase = globalScene.getCurrentPhase();
const effectPhase = globalScene.phaseManager.getCurrentPhase();
if (effectPhase?.is("MoveEffectPhase")) {
effectPhase.stopMultiHit(pokemon);
}
@ -1754,7 +1764,9 @@ export class ContactStatStageChangeProtectedTag extends DamageProtectedTag {
* @param user - The pokemon that is being attacked and has the tag
*/
override onContact(attacker: Pokemon, _user: Pokemon): void {
globalScene.unshiftPhase(new StatStageChangePhase(attacker.getBattlerIndex(), false, [this.stat], this.levels));
globalScene.phaseManager.unshiftPhase(
new StatStageChangePhase(attacker.getBattlerIndex(), false, [this.stat], this.levels),
);
}
}
@ -1771,7 +1783,7 @@ export class EnduringTag extends BattlerTag {
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:enduringOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -1780,7 +1792,7 @@ export class EnduringTag extends BattlerTag {
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
if (lapseType === BattlerTagLapseType.CUSTOM) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:enduringLapse", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -1799,7 +1811,7 @@ export class SturdyTag extends BattlerTag {
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
if (lapseType === BattlerTagLapseType.CUSTOM) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:sturdyLapse", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -1824,7 +1836,7 @@ export class PerishSongTag extends BattlerTag {
const ret = super.lapse(pokemon, lapseType);
if (ret) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:perishSongLapse", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
turnCount: this.turnCount,
@ -1861,7 +1873,7 @@ export class CenterOfAttentionTag extends BattlerTag {
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:centerOfAttentionOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -1918,15 +1930,15 @@ export class TruantTag extends AbilityBattlerTag {
const lastMove = pokemon.getLastXMoves().find(() => true);
if (lastMove && lastMove.move !== MoveId.NONE) {
(globalScene.getCurrentPhase() as MovePhase).cancel();
(globalScene.phaseManager.getCurrentPhase() as MovePhase).cancel();
// TODO: Ability displays should be handled by the ability
globalScene.queueAbilityDisplay(pokemon, passive, true);
globalScene.queueMessage(
globalScene.phaseManager.queueAbilityDisplay(pokemon, passive, true);
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:truantLapse", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
);
globalScene.queueAbilityDisplay(pokemon, passive, false);
globalScene.phaseManager.queueAbilityDisplay(pokemon, passive, false);
}
return true;
@ -1941,7 +1953,7 @@ export class SlowStartTag extends AbilityBattlerTag {
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:slowStartOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -1959,7 +1971,7 @@ export class SlowStartTag extends AbilityBattlerTag {
onRemove(pokemon: Pokemon): void {
super.onRemove(pokemon);
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:slowStartOnRemove", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -2006,7 +2018,7 @@ export class HighestStatBoostTag extends AbilityBattlerTag {
this.stat = highestStat;
this.multiplier = this.stat === Stat.SPD ? 1.5 : 1.3;
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:highestStatBoostOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
statName: i18next.t(getStatKey(highestStat)),
@ -2021,7 +2033,7 @@ export class HighestStatBoostTag extends AbilityBattlerTag {
onRemove(pokemon: Pokemon): void {
super.onRemove(pokemon);
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:highestStatBoostOnRemove", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
abilityName: allAbilities[this.ability].name,
@ -2119,7 +2131,7 @@ export class FloatingTag extends TypeImmuneTag {
super.onAdd(pokemon);
if (this.sourceMove === MoveId.MAGNET_RISE) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:magnetRisenOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -2130,7 +2142,7 @@ export class FloatingTag extends TypeImmuneTag {
onRemove(pokemon: Pokemon): void {
super.onRemove(pokemon);
if (this.sourceMove === MoveId.MAGNET_RISE) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:magnetRisenOnRemove", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -2174,7 +2186,7 @@ export class TypeBoostTag extends BattlerTag {
}
override onAdd(pokemon: Pokemon): void {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("abilityTriggers:typeImmunityPowerBoost", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
typeName: i18next.t(`pokemonInfo:Type.${PokemonType[this.boostedType]}`),
@ -2183,7 +2195,7 @@ export class TypeBoostTag extends BattlerTag {
}
override onOverlap(pokemon: Pokemon): void {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("abilityTriggers:moveImmunity", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }),
);
}
@ -2197,7 +2209,7 @@ export class CritBoostTag extends BattlerTag {
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:critBoostOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -2211,7 +2223,7 @@ export class CritBoostTag extends BattlerTag {
onRemove(pokemon: Pokemon): void {
super.onRemove(pokemon);
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:critBoostOnRemove", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -2257,7 +2269,7 @@ export class SaltCuredTag extends BattlerTag {
onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon);
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:saltCuredOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -2269,7 +2281,7 @@ export class SaltCuredTag extends BattlerTag {
const ret = lapseType !== BattlerTagLapseType.CUSTOM || super.lapse(pokemon, lapseType);
if (ret) {
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new CommonAnimPhase(pokemon.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.SALT_CURE),
);
@ -2282,7 +2294,7 @@ export class SaltCuredTag extends BattlerTag {
result: HitResult.INDIRECT,
});
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:saltCuredLapse", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
moveName: this.getMoveName(),
@ -2320,7 +2332,7 @@ export class CursedTag extends BattlerTag {
const ret = lapseType !== BattlerTagLapseType.CUSTOM || super.lapse(pokemon, lapseType);
if (ret) {
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new CommonAnimPhase(pokemon.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.SALT_CURE),
);
@ -2329,7 +2341,7 @@ export class CursedTag extends BattlerTag {
if (!cancelled.value) {
pokemon.damageAndUpdate(toDmgValue(pokemon.getMaxHp() / 4), { result: HitResult.INDIRECT });
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:cursedLapse", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -2497,7 +2509,7 @@ export class CommandedTag extends BattlerTag {
/** Caches the Tatsugiri's form key and sharply boosts the tagged Pokemon's stats */
override onAdd(pokemon: Pokemon): void {
this._tatsugiriFormKey = this.getSourcePokemon()?.getFormKey() ?? "curly";
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new StatStageChangePhase(
pokemon.getBattlerIndex(),
true,
@ -2572,7 +2584,7 @@ export class StockpilingTag extends BattlerTag {
if (this.stockpiledCount < 3) {
this.stockpiledCount++;
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:stockpilingOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
stockpiledCount: this.stockpiledCount,
@ -2580,7 +2592,7 @@ export class StockpilingTag extends BattlerTag {
);
// Attempt to increase DEF and SPDEF by one stage, keeping track of successful changes.
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new StatStageChangePhase(
pokemon.getBattlerIndex(),
true,
@ -2608,13 +2620,13 @@ export class StockpilingTag extends BattlerTag {
const spDefChange = this.statChangeCounts[Stat.SPDEF];
if (defChange) {
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new StatStageChangePhase(pokemon.getBattlerIndex(), true, [Stat.DEF], -defChange, true, false, true),
);
}
if (spDefChange) {
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new StatStageChangePhase(pokemon.getBattlerIndex(), true, [Stat.SPDEF], -spDefChange, true, false, true),
);
}
@ -2635,7 +2647,7 @@ export class GulpMissileTag extends BattlerTag {
return true;
}
const moveEffectPhase = globalScene.getCurrentPhase();
const moveEffectPhase = globalScene.phaseManager.getCurrentPhase();
if (moveEffectPhase?.is("MoveEffectPhase")) {
const attacker = moveEffectPhase.getUserPokemon();
@ -2655,7 +2667,9 @@ export class GulpMissileTag extends BattlerTag {
}
if (this.tagType === BattlerTagType.GULP_MISSILE_ARROKUDA) {
globalScene.unshiftPhase(new StatStageChangePhase(attacker.getBattlerIndex(), false, [Stat.DEF], -1));
globalScene.phaseManager.unshiftPhase(
new StatStageChangePhase(attacker.getBattlerIndex(), false, [Stat.DEF], -1),
);
} else {
attacker.trySetStatus(StatusEffect.PARALYSIS, true, pokemon);
}
@ -2803,7 +2817,7 @@ export class HealBlockTag extends MoveRestrictionBattlerTag {
override onRemove(pokemon: Pokemon): void {
super.onRemove(pokemon);
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battle:battlerTagsHealBlockOnRemove", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -2833,7 +2847,7 @@ export class TarShotTag extends BattlerTag {
}
override onAdd(pokemon: Pokemon): void {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:tarShotOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -2852,7 +2866,7 @@ export class ElectrifiedTag extends BattlerTag {
override onAdd(pokemon: Pokemon): void {
// "{pokemonNameWithAffix}'s moves have been electrified!"
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:electrifiedOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -2878,7 +2892,7 @@ export class AutotomizedTag extends BattlerTag {
onAdd(pokemon: Pokemon): void {
const minWeight = 0.1;
if (pokemon.getWeight() > minWeight) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:autotomizeOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -2924,14 +2938,14 @@ export class SubstituteTag extends BattlerTag {
// Queue battle animation and message
globalScene.triggerPokemonBattleAnim(pokemon, PokemonAnimType.SUBSTITUTE_ADD);
if (this.sourceMove === MoveId.SHED_TAIL) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:shedTailOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
1500,
);
} else {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:substituteOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -2951,7 +2965,7 @@ export class SubstituteTag extends BattlerTag {
} else {
this.sprite.destroy();
}
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:substituteOnRemove", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -2987,7 +3001,7 @@ export class SubstituteTag extends BattlerTag {
/** If the Substitute redirects damage, queue a message to indicate it. */
onHit(pokemon: Pokemon): void {
const moveEffectPhase = globalScene.getCurrentPhase();
const moveEffectPhase = globalScene.phaseManager.getCurrentPhase();
if (moveEffectPhase?.is("MoveEffectPhase")) {
const attacker = moveEffectPhase.getUserPokemon();
if (!attacker) {
@ -2997,7 +3011,7 @@ export class SubstituteTag extends BattlerTag {
const firstHit = attacker.turnData.hitCount === attacker.turnData.hitsLeft;
if (firstHit && move.hitsSubstitute(attacker, pokemon)) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:substituteOnHit", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -3074,7 +3088,7 @@ export class TormentTag extends MoveRestrictionBattlerTag {
*/
override onAdd(pokemon: Pokemon) {
super.onAdd(pokemon);
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:tormentOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -3132,7 +3146,7 @@ export class TauntTag extends MoveRestrictionBattlerTag {
override onAdd(pokemon: Pokemon) {
super.onAdd(pokemon);
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:tauntOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -3143,7 +3157,7 @@ export class TauntTag extends MoveRestrictionBattlerTag {
public override onRemove(pokemon: Pokemon): void {
super.onRemove(pokemon);
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:tauntOnRemove", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -3253,7 +3267,7 @@ export class SyrupBombTag extends BattlerTag {
*/
override onAdd(pokemon: Pokemon) {
super.onAdd(pokemon);
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:syrupBombOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -3271,12 +3285,12 @@ export class SyrupBombTag extends BattlerTag {
return false;
}
// Custom message in lieu of an animation in mainline
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:syrupBombLapse", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
);
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new StatStageChangePhase(pokemon.getBattlerIndex(), true, [Stat.SPD], -1, true, false, true),
);
return --this.turnCount > 0;
@ -3302,7 +3316,7 @@ export class TelekinesisTag extends BattlerTag {
}
override onAdd(pokemon: Pokemon) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:telekinesisOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -3321,7 +3335,7 @@ export class PowerTrickTag extends BattlerTag {
onAdd(pokemon: Pokemon): void {
this.swapStat(pokemon);
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:powerTrickActive", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -3330,7 +3344,7 @@ export class PowerTrickTag extends BattlerTag {
onRemove(pokemon: Pokemon): void {
this.swapStat(pokemon);
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:powerTrickActive", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -3368,7 +3382,7 @@ export class GrudgeTag extends BattlerTag {
onAdd(pokemon: Pokemon) {
super.onAdd(pokemon);
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:grudgeOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -3389,7 +3403,7 @@ export class GrudgeTag extends BattlerTag {
const lastMoveData = sourcePokemon.getMoveset().find(m => m.moveId === lastMove.move);
if (lastMoveData && lastMove.move !== MoveId.STRUGGLE) {
lastMoveData.ppUsed = lastMoveData.getMovePp();
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:grudgeLapse", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
moveName: lastMoveData.getName(),
@ -3417,7 +3431,9 @@ export class PsychoShiftTag extends BattlerTag {
*/
override lapse(pokemon: Pokemon, _lapseType: BattlerTagLapseType): boolean {
if (pokemon.status && pokemon.isActive(true)) {
globalScene.queueMessage(getStatusEffectHealText(pokemon.status.effect, getPokemonNameWithAffix(pokemon)));
globalScene.phaseManager.queueMessage(
getStatusEffectHealText(pokemon.status.effect, getPokemonNameWithAffix(pokemon)),
);
pokemon.resetStatus();
pokemon.updateInfo();
}
@ -3439,7 +3455,7 @@ export class MagicCoatTag extends BattlerTag {
*/
override onAdd(pokemon: Pokemon) {
// "{pokemonNameWithAffix} shrouded itself with Magic Coat!"
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:magicCoatOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -3673,7 +3689,7 @@ export function loadBattlerTag(source: BattlerTag | any): BattlerTag {
* corresponding {@linkcode Move} and user {@linkcode Pokemon}
*/
function getMoveEffectPhaseData(_pokemon: Pokemon): { phase: MoveEffectPhase; attacker: Pokemon; move: Move } | null {
const phase = globalScene.getCurrentPhase();
const phase = globalScene.phaseManager.getCurrentPhase();
if (phase?.is("MoveEffectPhase")) {
return {
phase: phase,

View File

@ -3,11 +3,7 @@ import type Pokemon from "../field/pokemon";
import { HitResult } from "../field/pokemon";
import { getStatusEffectHealText } from "./status-effect";
import { NumberHolder, toDmgValue, randSeedInt } from "#app/utils/common";
import {
DoubleBerryEffectAbAttr,
ReduceBerryUseThresholdAbAttr,
applyAbAttrs,
} from "./abilities/ability";
import { DoubleBerryEffectAbAttr, ReduceBerryUseThresholdAbAttr, applyAbAttrs } from "./abilities/ability";
import i18next from "i18next";
import { BattlerTagType } from "#enums/battler-tag-type";
import { BerryType } from "#enums/berry-type";
@ -79,7 +75,7 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
{
const hpHealed = new NumberHolder(toDmgValue(consumer.getMaxHp() / 4));
applyAbAttrs(DoubleBerryEffectAbAttr, consumer, null, false, hpHealed);
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new PokemonHealPhase(
consumer.getBattlerIndex(),
hpHealed.value,
@ -95,7 +91,7 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
case BerryType.LUM:
{
if (consumer.status) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
getStatusEffectHealText(consumer.status.effect, getPokemonNameWithAffix(consumer)),
);
}
@ -113,7 +109,7 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
const stat: BattleStat = berryType - BerryType.ENIGMA;
const statStages = new NumberHolder(1);
applyAbAttrs(DoubleBerryEffectAbAttr, consumer, null, false, statStages);
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new StatStageChangePhase(consumer.getBattlerIndex(), true, [stat], statStages.value),
);
}
@ -130,7 +126,7 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
const randStat = randSeedInt(Stat.SPD, Stat.ATK);
const stages = new NumberHolder(2);
applyAbAttrs(DoubleBerryEffectAbAttr, consumer, null, false, stages);
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new StatStageChangePhase(consumer.getBattlerIndex(), true, [randStat], stages.value),
);
}
@ -144,7 +140,7 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
consumer.getMoveset().find(m => m.ppUsed < m.getMovePp());
if (ppRestoreMove) {
ppRestoreMove.ppUsed = Math.max(ppRestoreMove.ppUsed - 10, 0);
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battle:ppHealBerry", {
pokemonNameWithAffix: getPokemonNameWithAffix(consumer),
moveName: ppRestoreMove.getName(),

View File

@ -1048,7 +1048,7 @@ function ChargeMove<TBase extends SubMove>(Base: TBase) {
* @param target the {@linkcode Pokemon} targeted by this move (optional)
*/
showChargeText(user: Pokemon, target?: Pokemon): void {
globalScene.queueMessage(this._chargeText
globalScene.phaseManager.queueMessage(this._chargeText
.replace("{USER}", getPokemonNameWithAffix(user))
.replace("{TARGET}", getPokemonNameWithAffix(target))
);
@ -1310,7 +1310,7 @@ export class MessageHeaderAttr extends MoveHeaderAttr {
: this.message(user, move);
if (message) {
globalScene.queueMessage(message);
globalScene.phaseManager.queueMessage(message);
return true;
}
return false;
@ -1363,7 +1363,7 @@ export class PreMoveMessageAttr extends MoveAttr {
? this.message as string
: this.message(user, target, move);
if (message) {
globalScene.queueMessage(message, 500);
globalScene.phaseManager.queueMessage(message, 500);
return true;
}
return false;
@ -1620,14 +1620,14 @@ export class SurviveDamageAttr extends ModifiedDamageAttr {
export class SplashAttr extends MoveEffectAttr {
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
globalScene.queueMessage(i18next.t("moveTriggers:splash"));
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:splash"));
return true;
}
}
export class CelebrateAttr extends MoveEffectAttr {
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
globalScene.queueMessage(i18next.t("moveTriggers:celebrate", { playerName: loggedInUser?.username }));
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:celebrate", { playerName: loggedInUser?.username }));
return true;
}
}
@ -1677,7 +1677,7 @@ export class RecoilAttr extends MoveEffectAttr {
}
user.damageAndUpdate(recoilDamage, { result: HitResult.INDIRECT, ignoreSegments: true });
globalScene.queueMessage(i18next.t("moveTriggers:hitWithRecoil", { pokemonName: getPokemonNameWithAffix(user) }));
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:hitWithRecoil", { pokemonName: getPokemonNameWithAffix(user) }));
user.turnData.damageTaken += recoilDamage;
return true;
@ -1789,7 +1789,7 @@ export class HalfSacrificialAttr extends MoveEffectAttr {
applyAbAttrs(BlockNonDirectDamageAbAttr, user, cancelled);
if (!cancelled.value) {
user.damageAndUpdate(toDmgValue(user.getMaxHp() / 2), { result: HitResult.INDIRECT, ignoreSegments: true });
globalScene.queueMessage(i18next.t("moveTriggers:cutHpPowerUpMove", { pokemonName: getPokemonNameWithAffix(user) })); // Queue recoil message
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:cutHpPowerUpMove", { pokemonName: getPokemonNameWithAffix(user) })); // Queue recoil message
}
return true;
}
@ -1890,7 +1890,7 @@ export class HealAttr extends MoveEffectAttr {
* This heals the target and shows the appropriate message.
*/
addHealPhase(target: Pokemon, healRatio: number) {
globalScene.unshiftPhase(new PokemonHealPhase(target.getBattlerIndex(),
globalScene.phaseManager.unshiftPhase(new PokemonHealPhase(target.getBattlerIndex(),
toDmgValue(target.getMaxHp() * healRatio), i18next.t("moveTriggers:healHp", { pokemonName: getPokemonNameWithAffix(target) }), true, !this.showAnim));
}
@ -1934,7 +1934,7 @@ export class PartyStatusCureAttr extends MoveEffectAttr {
partyPokemon.forEach(p => this.cureStatus(p, user.id));
if (this.message) {
globalScene.queueMessage(this.message);
globalScene.phaseManager.queueMessage(this.message);
}
return true;
@ -1954,8 +1954,8 @@ export class PartyStatusCureAttr extends MoveEffectAttr {
pokemon.updateInfo();
} else {
// TODO: Ability displays should be handled by the ability
globalScene.queueAbilityDisplay(pokemon, pokemon.getPassiveAbility()?.id === this.abilityCondition, true);
globalScene.queueAbilityDisplay(pokemon, pokemon.getPassiveAbility()?.id === this.abilityCondition, false);
globalScene.phaseManager.queueAbilityDisplay(pokemon, pokemon.getPassiveAbility()?.id === this.abilityCondition, true);
globalScene.phaseManager.queueAbilityDisplay(pokemon, pokemon.getPassiveAbility()?.id === this.abilityCondition, false);
}
}
}
@ -2021,7 +2021,7 @@ export class SacrificialFullRestoreAttr extends SacrificialAttr {
const party = user.isPlayer() ? globalScene.getPlayerParty() : globalScene.getEnemyParty();
const maxPartyMemberHp = party.map(p => p.getMaxHp()).reduce((maxHp: number, hp: number) => Math.max(hp, maxHp), 0);
globalScene.pushPhase(
globalScene.phaseManager.pushPhase(
new PokemonHealPhase(
user.getBattlerIndex(),
maxPartyMemberHp,
@ -2233,7 +2233,7 @@ export class HitHealAttr extends MoveEffectAttr {
message = "";
}
}
globalScene.unshiftPhase(new PokemonHealPhase(user.getBattlerIndex(), healAmount, message, false, true));
globalScene.phaseManager.unshiftPhase(new PokemonHealPhase(user.getBattlerIndex(), healAmount, message, false, true));
return true;
}
@ -2565,7 +2565,7 @@ export class StealHeldItemChanceAttr extends MoveEffectAttr {
return false;
}
globalScene.queueMessage(i18next.t("moveTriggers:stoleItem", { pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target), itemName: stolenItem.type.name }));
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:stoleItem", { pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target), itemName: stolenItem.type.name }));
return true;
}
@ -2643,9 +2643,9 @@ export class RemoveHeldItemAttr extends MoveEffectAttr {
globalScene.updateModifiers(target.isPlayer());
if (this.berriesOnly) {
globalScene.queueMessage(i18next.t("moveTriggers:incineratedItem", { pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target), itemName: removedItem.type.name }));
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:incineratedItem", { pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target), itemName: removedItem.type.name }));
} else {
globalScene.queueMessage(i18next.t("moveTriggers:knockedOffItem", { pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target), itemName: removedItem.type.name }));
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:knockedOffItem", { pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target), itemName: removedItem.type.name }));
}
return true;
@ -2777,7 +2777,7 @@ export class StealEatBerryAttr extends EatBerryAttr {
this.chosenBerry = heldBerries[user.randBattleSeedInt(heldBerries.length)];
applyPostItemLostAbAttrs(PostItemLostAbAttr, target, false);
const message = i18next.t("battle:stealEatBerry", { pokemonName: user.name, targetName: target.name, berryName: this.chosenBerry.type.name });
globalScene.queueMessage(message);
globalScene.phaseManager.queueMessage(message);
this.reduceBerryModifier(target);
this.eatBerry(user, target);
@ -2822,7 +2822,7 @@ export class HealStatusEffectAttr extends MoveEffectAttr {
const pokemon = this.selfTarget ? user : target;
if (pokemon.status && this.effects.includes(pokemon.status.effect)) {
globalScene.queueMessage(getStatusEffectHealText(pokemon.status.effect, getPokemonNameWithAffix(pokemon)));
globalScene.phaseManager.queueMessage(getStatusEffectHealText(pokemon.status.effect, getPokemonNameWithAffix(pokemon)));
pokemon.resetStatus();
pokemon.updateInfo();
@ -3067,13 +3067,13 @@ export class DelayedAttackAttr extends OverrideMoveEffectAttr {
if (!virtual) {
overridden.value = true;
globalScene.unshiftPhase(new MoveAnimPhase(new MoveChargeAnim(this.chargeAnim, move.id, user)));
globalScene.queueMessage(this.chargeText.replace("{TARGET}", getPokemonNameWithAffix(target)).replace("{USER}", getPokemonNameWithAffix(user)));
globalScene.phaseManager.unshiftPhase(new MoveAnimPhase(new MoveChargeAnim(this.chargeAnim, move.id, user)));
globalScene.phaseManager.queueMessage(this.chargeText.replace("{TARGET}", getPokemonNameWithAffix(target)).replace("{USER}", getPokemonNameWithAffix(user)));
user.pushMoveHistory({ move: move.id, targets: [ target.getBattlerIndex() ], result: MoveResult.OTHER });
const side = target.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY;
globalScene.arena.addTag(this.tagType, 3, move.id, user.id, side, false, target.getBattlerIndex());
} else {
globalScene.queueMessage(i18next.t("moveTriggers:tookMoveAttack", { pokemonName: getPokemonNameWithAffix(globalScene.getPokemonById(target.id) ?? undefined), moveName: move.name }));
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:tookMoveAttack", { pokemonName: getPokemonNameWithAffix(globalScene.getPokemonById(target.id) ?? undefined), moveName: move.name }));
}
return true;
@ -3103,29 +3103,29 @@ export class AwaitCombinedPledgeAttr extends OverrideMoveEffectAttr {
override apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
if (user.turnData.combiningPledge) {
// "The two moves have become one!\nIt's a combined move!"
globalScene.queueMessage(i18next.t("moveTriggers:combiningPledge"));
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:combiningPledge"));
return false;
}
const overridden = args[0] as BooleanHolder;
const allyMovePhase = globalScene.findPhase<MovePhase>((phase) => phase.is("MovePhase") && phase.pokemon.isPlayer() === user.isPlayer());
const allyMovePhase = globalScene.phaseManager.findPhase<MovePhase>((phase) => phase.is("MovePhase") && phase.pokemon.isPlayer() === user.isPlayer());
if (allyMovePhase) {
const allyMove = allyMovePhase.move.getMove();
if (allyMove !== move && allyMove.hasAttr(AwaitCombinedPledgeAttr)) {
[ user, allyMovePhase.pokemon ].forEach((p) => p.turnData.combiningPledge = move.id);
// "{userPokemonName} is waiting for {allyPokemonName}'s move..."
globalScene.queueMessage(i18next.t("moveTriggers:awaitingPledge", {
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:awaitingPledge", {
userPokemonName: getPokemonNameWithAffix(user),
allyPokemonName: getPokemonNameWithAffix(allyMovePhase.pokemon)
}));
// Move the ally's MovePhase (if needed) so that the ally moves next
const allyMovePhaseIndex = globalScene.phaseQueue.indexOf(allyMovePhase);
const firstMovePhaseIndex = globalScene.phaseQueue.findIndex((phase) => phase.is("MovePhase"));
const allyMovePhaseIndex = globalScene.phaseManager.phaseQueue.indexOf(allyMovePhase);
const firstMovePhaseIndex = globalScene.phaseManager.phaseQueue.findIndex((phase) => phase.is("MovePhase"));
if (allyMovePhaseIndex !== firstMovePhaseIndex) {
globalScene.prependToPhase(globalScene.phaseQueue.splice(allyMovePhaseIndex, 1)[0], MovePhase);
globalScene.phaseManager.prependToPhase(globalScene.phaseManager.phaseQueue.splice(allyMovePhaseIndex, 1)[0], MovePhase);
}
overridden.value = true;
@ -3207,7 +3207,7 @@ export class StatStageChangeAttr extends MoveEffectAttr {
const moveChance = this.getMoveChance(user, target, move, this.selfTarget, true);
if (moveChance < 0 || moveChance === 100 || user.randBattleSeedInt(100) < moveChance) {
const stages = this.getLevels(user);
globalScene.unshiftPhase(new StatStageChangePhase((this.selfTarget ? user : target).getBattlerIndex(), this.selfTarget, this.stats, stages, this.showMessage));
globalScene.phaseManager.unshiftPhase(new StatStageChangePhase((this.selfTarget ? user : target).getBattlerIndex(), this.selfTarget, this.stats, stages, this.showMessage));
return true;
}
@ -3432,7 +3432,7 @@ export class AcupressureStatStageChangeAttr extends MoveEffectAttr {
const randStats = BATTLE_STATS.filter((s) => target.getStatStage(s) < 6);
if (randStats.length > 0) {
const boostStat = [ randStats[user.randBattleSeedInt(randStats.length)] ];
globalScene.unshiftPhase(new StatStageChangePhase(target.getBattlerIndex(), this.selfTarget, boostStat, 2));
globalScene.phaseManager.unshiftPhase(new StatStageChangePhase(target.getBattlerIndex(), this.selfTarget, boostStat, 2));
return true;
}
return false;
@ -3510,7 +3510,7 @@ export class OrderUpStatBoostAttr extends MoveEffectAttr {
break;
}
globalScene.unshiftPhase(new StatStageChangePhase(user.getBattlerIndex(), this.selfTarget, [ increasedStat ], 1));
globalScene.phaseManager.unshiftPhase(new StatStageChangePhase(user.getBattlerIndex(), this.selfTarget, [ increasedStat ], 1));
return true;
}
}
@ -3533,7 +3533,7 @@ export class CopyStatsAttr extends MoveEffectAttr {
}
target.updateInfo();
user.updateInfo();
globalScene.queueMessage(i18next.t("moveTriggers:copiedStatChanges", { pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target) }));
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:copiedStatChanges", { pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target) }));
return true;
}
@ -3552,7 +3552,7 @@ export class InvertStatsAttr extends MoveEffectAttr {
target.updateInfo();
user.updateInfo();
globalScene.queueMessage(i18next.t("moveTriggers:invertStats", { pokemonName: getPokemonNameWithAffix(target) }));
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:invertStats", { pokemonName: getPokemonNameWithAffix(target) }));
return true;
}
@ -3570,10 +3570,10 @@ export class ResetStatsAttr extends MoveEffectAttr {
// Target all pokemon on the field when Freezy Frost or Haze are used
const activePokemon = globalScene.getField(true);
activePokemon.forEach((p) => this.resetStats(p));
globalScene.queueMessage(i18next.t("moveTriggers:statEliminated"));
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:statEliminated"));
} else { // Affects only the single target when Clear Smog is used
this.resetStats(target);
globalScene.queueMessage(i18next.t("moveTriggers:resetStats", { pokemonName: getPokemonNameWithAffix(target) }));
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:resetStats", { pokemonName: getPokemonNameWithAffix(target) }));
}
return true;
}
@ -3623,9 +3623,9 @@ export class SwapStatStagesAttr extends MoveEffectAttr {
user.updateInfo();
if (this.stats.length === 7) {
globalScene.queueMessage(i18next.t("moveTriggers:switchedStatChanges", { pokemonName: getPokemonNameWithAffix(user) }));
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:switchedStatChanges", { pokemonName: getPokemonNameWithAffix(user) }));
} else if (this.stats.length === 2) {
globalScene.queueMessage(i18next.t("moveTriggers:switchedTwoStatChanges", {
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:switchedTwoStatChanges", {
pokemonName: getPokemonNameWithAffix(user),
firstStat: i18next.t(getStatKey(this.stats[0])),
secondStat: i18next.t(getStatKey(this.stats[1]))
@ -4227,7 +4227,7 @@ export class PresentPowerAttr extends VariablePowerAttr {
// If this move is multi-hit, disable all other hits
user.turnData.hitCount = 1;
user.turnData.hitsLeft = 1;
globalScene.unshiftPhase(new PokemonHealPhase(target.getBattlerIndex(),
globalScene.phaseManager.unshiftPhase(new PokemonHealPhase(target.getBattlerIndex(),
toDmgValue(target.getMaxHp() / 4), i18next.t("moveTriggers:regainedHealth", { pokemonName: getPokemonNameWithAffix(target) }), true));
}
@ -4476,7 +4476,7 @@ export class CueNextRoundAttr extends MoveEffectAttr {
}
override apply(user: Pokemon, target: Pokemon, move: Move, args?: any[]): boolean {
const nextRoundPhase = globalScene.findPhase<MovePhase>(phase =>
const nextRoundPhase = globalScene.phaseManager.findPhase<MovePhase>(phase =>
phase.is("MovePhase") && phase.move.moveId === MoveId.ROUND
);
@ -4485,10 +4485,10 @@ export class CueNextRoundAttr extends MoveEffectAttr {
}
// Update the phase queue so that the next Pokemon using Round moves next
const nextRoundIndex = globalScene.phaseQueue.indexOf(nextRoundPhase);
const nextMoveIndex = globalScene.phaseQueue.findIndex(phase => phase.is("MovePhase"));
const nextRoundIndex = globalScene.phaseManager.phaseQueue.indexOf(nextRoundPhase);
const nextMoveIndex = globalScene.phaseManager.phaseQueue.findIndex(phase => phase.is("MovePhase"));
if (nextRoundIndex !== nextMoveIndex) {
globalScene.prependToPhase(globalScene.phaseQueue.splice(nextRoundIndex, 1)[0], MovePhase);
globalScene.phaseManager.prependToPhase(globalScene.phaseManager.phaseQueue.splice(nextRoundIndex, 1)[0], MovePhase);
}
// Mark the corresponding Pokemon as having "joined the Round" (for doubling power later)
@ -4546,14 +4546,14 @@ export class SpectralThiefAttr extends StatChangeBeforeDmgCalcAttr {
*/
const availableToSteal = Math.min(statStageValueTarget, 6 - statStageValueUser);
globalScene.unshiftPhase(new StatStageChangePhase(user.getBattlerIndex(), this.selfTarget, [ s ], availableToSteal));
globalScene.phaseManager.unshiftPhase(new StatStageChangePhase(user.getBattlerIndex(), this.selfTarget, [ s ], availableToSteal));
target.setStatStage(s, statStageValueTarget - availableToSteal);
}
}
target.updateInfo();
user.updateInfo();
globalScene.queueMessage(i18next.t("moveTriggers:stealPositiveStats", { pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target) }));
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:stealPositiveStats", { pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target) }));
return true;
}
@ -5368,7 +5368,7 @@ const crashDamageFunc = (user: Pokemon, move: Move) => {
}
user.damageAndUpdate(toDmgValue(user.getMaxHp() / 2), { result: HitResult.INDIRECT });
globalScene.queueMessage(i18next.t("moveTriggers:keptGoingAndCrashed", { pokemonName: getPokemonNameWithAffix(user) }));
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:keptGoingAndCrashed", { pokemonName: getPokemonNameWithAffix(user) }));
user.turnData.damageTaken += toDmgValue(user.getMaxHp() / 2);
return true;
@ -5581,7 +5581,7 @@ export class FallDownAttr extends AddBattlerTagAttr {
*/
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
if (!target.isGrounded()) {
globalScene.queueMessage(i18next.t("moveTriggers:fallDown", { targetPokemonName: getPokemonNameWithAffix(target) }));
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:fallDown", { targetPokemonName: getPokemonNameWithAffix(target) }));
}
return super.apply(user, target, move, args);
}
@ -5665,12 +5665,12 @@ export class CurseAttr extends MoveEffectAttr {
apply(user: Pokemon, target: Pokemon, move:Move, args: any[]): boolean {
if (user.getTypes(true).includes(PokemonType.GHOST)) {
if (target.getTag(BattlerTagType.CURSED)) {
globalScene.queueMessage(i18next.t("battle:attackFailed"));
globalScene.phaseManager.queueMessage(i18next.t("battle:attackFailed"));
return false;
}
const curseRecoilDamage = Math.max(1, Math.floor(user.getMaxHp() / 2));
user.damageAndUpdate(curseRecoilDamage, { result: HitResult.INDIRECT, ignoreSegments: true });
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:cursedOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(user),
pokemonName: getPokemonNameWithAffix(target)
@ -5680,8 +5680,8 @@ export class CurseAttr extends MoveEffectAttr {
target.addTag(BattlerTagType.CURSED, 0, move.id, user.id);
return true;
} else {
globalScene.unshiftPhase(new StatStageChangePhase(user.getBattlerIndex(), true, [ Stat.ATK, Stat.DEF ], 1));
globalScene.unshiftPhase(new StatStageChangePhase(user.getBattlerIndex(), true, [ Stat.SPD ], -1));
globalScene.phaseManager.unshiftPhase(new StatStageChangePhase(user.getBattlerIndex(), true, [ Stat.ATK, Stat.DEF ], 1));
globalScene.phaseManager.unshiftPhase(new StatStageChangePhase(user.getBattlerIndex(), true, [ Stat.SPD ], -1));
return true;
}
}
@ -5745,7 +5745,7 @@ export class ConfuseAttr extends AddBattlerTagAttr {
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
if (!this.selfTarget && target.isSafeguarded(user)) {
if (move.category === MoveCategory.STATUS) {
globalScene.queueMessage(i18next.t("moveTriggers:safeguard", { targetName: getPokemonNameWithAffix(target) }));
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:safeguard", { targetName: getPokemonNameWithAffix(target) }));
}
return false;
}
@ -5802,7 +5802,7 @@ export class IgnoreAccuracyAttr extends AddBattlerTagAttr {
return false;
}
globalScene.queueMessage(i18next.t("moveTriggers:tookAimAtTarget", { pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target) }));
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:tookAimAtTarget", { pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target) }));
return true;
}
@ -5818,7 +5818,7 @@ export class FaintCountdownAttr extends AddBattlerTagAttr {
return false;
}
globalScene.queueMessage(i18next.t("moveTriggers:faintCountdown", { pokemonName: getPokemonNameWithAffix(target), turnCount: this.turnCountMin - 1 }));
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:faintCountdown", { pokemonName: getPokemonNameWithAffix(target), turnCount: this.turnCountMin - 1 }));
return true;
}
@ -6102,7 +6102,7 @@ export class SwapArenaTagsAttr extends MoveEffectAttr {
}
globalScene.queueMessage(i18next.t("moveTriggers:swapArenaTags", { pokemonName: getPokemonNameWithAffix(user) }));
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:swapArenaTags", { pokemonName: getPokemonNameWithAffix(user) }));
return true;
}
}
@ -6154,7 +6154,7 @@ export class RevivalBlessingAttr extends MoveEffectAttr {
override apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
// If user is player, checks if the user has fainted pokemon
if (user.isPlayer()) {
globalScene.unshiftPhase(new RevivalBlessingPhase(user));
globalScene.phaseManager.unshiftPhase(new RevivalBlessingPhase(user));
return true;
} else if (user.isEnemy() && user.hasTrainer() && globalScene.getEnemyParty().findIndex((p) => p.isFainted() && !p.isBoss()) > -1) {
// If used by an enemy trainer with at least one fainted non-boss Pokemon, this
@ -6164,20 +6164,20 @@ export class RevivalBlessingAttr extends MoveEffectAttr {
const slotIndex = globalScene.getEnemyParty().findIndex((p) => pokemon.id === p.id);
pokemon.resetStatus(true, false, false, true);
pokemon.heal(Math.min(toDmgValue(0.5 * pokemon.getMaxHp()), pokemon.getMaxHp()));
globalScene.queueMessage(i18next.t("moveTriggers:revivalBlessing", { pokemonName: getPokemonNameWithAffix(pokemon) }), 0, true);
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:revivalBlessing", { pokemonName: getPokemonNameWithAffix(pokemon) }), 0, true);
const allyPokemon = user.getAlly();
if (globalScene.currentBattle.double && globalScene.getEnemyParty().length > 1 && !isNullOrUndefined(allyPokemon)) {
// Handle cases where revived pokemon needs to get switched in on same turn
if (allyPokemon.isFainted() || allyPokemon === pokemon) {
// Enemy switch phase should be removed and replaced with the revived pkmn switching in
globalScene.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
// (revived pokemon can't move in the turn they're brought back)
globalScene.findPhase((phase: MovePhase) => phase.pokemon === pokemon)?.cancel();
globalScene.phaseManager.findPhase((phase: MovePhase) => phase.pokemon === pokemon)?.cancel();
if (user.fieldPosition === FieldPosition.CENTER) {
user.setFieldPosition(FieldPosition.LEFT);
}
globalScene.unshiftPhase(new SwitchSummonPhase(SwitchType.SWITCH, allyPokemon.getFieldIndex(), slotIndex, false, false));
globalScene.phaseManager.unshiftPhase(new SwitchSummonPhase(SwitchType.SWITCH, allyPokemon.getFieldIndex(), slotIndex, false, false));
}
}
return true;
@ -6255,7 +6255,7 @@ export class ForceSwitchOutAttr extends MoveEffectAttr {
if (this.switchType === SwitchType.FORCE_SWITCH) {
switchOutTarget.leaveField(true);
const slotIndex = eligibleNewIndices[user.randBattleSeedInt(eligibleNewIndices.length)];
globalScene.prependToPhase(
globalScene.phaseManager.prependToPhase(
new SwitchSummonPhase(
this.switchType,
switchOutTarget.getFieldIndex(),
@ -6267,7 +6267,7 @@ export class ForceSwitchOutAttr extends MoveEffectAttr {
);
} else {
switchOutTarget.leaveField(this.switchType === SwitchType.SWITCH);
globalScene.prependToPhase(
globalScene.phaseManager.prependToPhase(
new SwitchPhase(
this.switchType,
switchOutTarget.getFieldIndex(),
@ -6298,7 +6298,7 @@ export class ForceSwitchOutAttr extends MoveEffectAttr {
if (this.switchType === SwitchType.FORCE_SWITCH) {
switchOutTarget.leaveField(true);
const slotIndex = eligibleNewIndices[user.randBattleSeedInt(eligibleNewIndices.length)];
globalScene.prependToPhase(
globalScene.phaseManager.prependToPhase(
new SwitchSummonPhase(
this.switchType,
switchOutTarget.getFieldIndex(),
@ -6310,7 +6310,7 @@ export class ForceSwitchOutAttr extends MoveEffectAttr {
);
} else {
switchOutTarget.leaveField(this.switchType === SwitchType.SWITCH);
globalScene.prependToPhase(
globalScene.phaseManager.prependToPhase(
new SwitchSummonPhase(
this.switchType,
switchOutTarget.getFieldIndex(),
@ -6339,7 +6339,7 @@ export class ForceSwitchOutAttr extends MoveEffectAttr {
if (switchOutTarget.hp > 0) {
switchOutTarget.leaveField(false);
globalScene.queueMessage(i18next.t("moveTriggers:fled", { pokemonName: getPokemonNameWithAffix(switchOutTarget) }), null, true, 500);
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:fled", { pokemonName: getPokemonNameWithAffix(switchOutTarget) }), null, true, 500);
// in double battles redirect potential moves off fled pokemon
if (globalScene.currentBattle.double && !isNullOrUndefined(allyPokemon)) {
@ -6351,13 +6351,13 @@ export class ForceSwitchOutAttr extends MoveEffectAttr {
globalScene.clearEnemyHeldItemModifiers(switchOutTarget);
if (!allyPokemon?.isActive(true) && switchOutTarget.hp) {
globalScene.pushPhase(new BattleEndPhase(false));
globalScene.phaseManager.pushPhase(new BattleEndPhase(false));
if (globalScene.gameMode.hasRandomBiomes || globalScene.isNewBiome()) {
globalScene.pushPhase(new SelectBiomePhase());
globalScene.phaseManager.pushPhase(new SelectBiomePhase());
}
globalScene.pushPhase(new NewBattlePhase());
globalScene.phaseManager.pushPhase(new NewBattlePhase());
}
}
@ -6525,7 +6525,7 @@ export class CopyTypeAttr extends MoveEffectAttr {
user.summonData.types = targetTypes;
user.updateInfo();
globalScene.queueMessage(i18next.t("moveTriggers:copyType", { pokemonName: getPokemonNameWithAffix(user), targetPokemonName: getPokemonNameWithAffix(target) }));
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:copyType", { pokemonName: getPokemonNameWithAffix(user), targetPokemonName: getPokemonNameWithAffix(target) }));
return true;
}
@ -6556,7 +6556,7 @@ export class CopyBiomeTypeAttr extends MoveEffectAttr {
user.summonData.types = [ typeChange ];
user.updateInfo();
globalScene.queueMessage(i18next.t("moveTriggers:transformedIntoType", { pokemonName: getPokemonNameWithAffix(user), typeName: i18next.t(`pokemonInfo:Type.${PokemonType[typeChange]}`) }));
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:transformedIntoType", { pokemonName: getPokemonNameWithAffix(user), typeName: i18next.t(`pokemonInfo:Type.${PokemonType[typeChange]}`) }));
return true;
}
@ -6661,7 +6661,7 @@ export class ChangeTypeAttr extends MoveEffectAttr {
target.summonData.types = [ this.type ];
target.updateInfo();
globalScene.queueMessage(i18next.t("moveTriggers:transformedIntoType", { pokemonName: getPokemonNameWithAffix(target), typeName: i18next.t(`pokemonInfo:Type.${PokemonType[this.type]}`) }));
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:transformedIntoType", { pokemonName: getPokemonNameWithAffix(target), typeName: i18next.t(`pokemonInfo:Type.${PokemonType[this.type]}`) }));
return true;
}
@ -6684,7 +6684,7 @@ export class AddTypeAttr extends MoveEffectAttr {
target.summonData.addedType = this.type;
target.updateInfo();
globalScene.queueMessage(i18next.t("moveTriggers:addType", { typeName: i18next.t(`pokemonInfo:Type.${PokemonType[this.type]}`), pokemonName: getPokemonNameWithAffix(target) }));
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:addType", { typeName: i18next.t(`pokemonInfo:Type.${PokemonType[this.type]}`), pokemonName: getPokemonNameWithAffix(target) }));
return true;
}
@ -6706,7 +6706,7 @@ export class FirstMoveTypeAttr extends MoveEffectAttr {
const firstMoveType = target.getMoveset()[0].getMove().type;
user.summonData.types = [ firstMoveType ];
globalScene.queueMessage(i18next.t("battle:transformedIntoType", { pokemonName: getPokemonNameWithAffix(user), type: i18next.t(`pokemonInfo:Type.${PokemonType[firstMoveType]}`) }));
globalScene.phaseManager.queueMessage(i18next.t("battle:transformedIntoType", { pokemonName: getPokemonNameWithAffix(user), type: i18next.t(`pokemonInfo:Type.${PokemonType[firstMoveType]}`) }));
return true;
}
@ -6725,7 +6725,7 @@ class CallMoveAttr extends OverrideMoveEffectAttr {
const replaceMoveTarget = move.moveTarget === MoveTarget.NEAR_OTHER ? MoveTarget.NEAR_ENEMY : undefined;
const moveTargets = getMoveTargets(user, move.id, replaceMoveTarget);
if (moveTargets.targets.length === 0) {
globalScene.queueMessage(i18next.t("battle:attackFailed"));
globalScene.phaseManager.queueMessage(i18next.t("battle:attackFailed"));
console.log("CallMoveAttr failed due to no targets.");
return false;
}
@ -6733,8 +6733,8 @@ class CallMoveAttr extends OverrideMoveEffectAttr {
? moveTargets.targets
: [ 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.unshiftPhase(new LoadMoveAnimPhase(move.id));
globalScene.unshiftPhase(new MovePhase(user, targets, new PokemonMove(move.id, 0, 0, true), true, true));
globalScene.phaseManager.unshiftPhase(new LoadMoveAnimPhase(move.id));
globalScene.phaseManager.unshiftPhase(new MovePhase(user, targets, new PokemonMove(move.id, 0, 0, true), true, true));
return true;
}
}
@ -6962,8 +6962,8 @@ export class NaturePowerAttr extends OverrideMoveEffectAttr {
}
user.getMoveQueue().push({ move: moveId, targets: [ target.getBattlerIndex() ], ignorePP: true });
globalScene.unshiftPhase(new LoadMoveAnimPhase(moveId));
globalScene.unshiftPhase(new MovePhase(user, [ target.getBattlerIndex() ], new PokemonMove(moveId, 0, 0, true), true));
globalScene.phaseManager.unshiftPhase(new LoadMoveAnimPhase(moveId));
globalScene.phaseManager.unshiftPhase(new MovePhase(user, [ target.getBattlerIndex() ], new PokemonMove(moveId, 0, 0, true), true));
return true;
}
}
@ -7044,13 +7044,13 @@ export class RepeatMoveAttr extends MoveEffectAttr {
}
}
globalScene.queueMessage(i18next.t("moveTriggers:instructingMove", {
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:instructingMove", {
userPokemonName: getPokemonNameWithAffix(user),
targetPokemonName: getPokemonNameWithAffix(target)
}));
target.getMoveQueue().unshift({ move: lastMove.move, targets: moveTargets, ignorePP: false });
target.turnData.extraTurns++;
globalScene.appendToPhase(new MovePhase(target, moveTargets, movesetMove), MoveEndPhase);
globalScene.phaseManager.appendToPhase(new MovePhase(target, moveTargets, movesetMove), MoveEndPhase);
return true;
}
@ -7165,7 +7165,7 @@ export class ReducePpMoveAttr extends MoveEffectAttr {
const message = i18next.t("battle:ppReduced", { targetName: getPokemonNameWithAffix(target), moveName: movesetMove.getName(), reduction: (movesetMove.ppUsed) - lastPpUsed });
globalScene.eventTarget.dispatchEvent(new MoveUsedEvent(target.id, movesetMove.getMove(), movesetMove.ppUsed));
globalScene.queueMessage(message);
globalScene.phaseManager.queueMessage(message);
return true;
}
@ -7276,7 +7276,7 @@ export class MovesetCopyMoveAttr extends OverrideMoveEffectAttr {
user.summonData.moveset = user.getMoveset().slice(0);
user.summonData.moveset[thisMoveIndex] = new PokemonMove(copiedMove.id, 0, 0);
globalScene.queueMessage(i18next.t("moveTriggers:copiedMove", { pokemonName: getPokemonNameWithAffix(user), moveName: copiedMove.name }));
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:copiedMove", { pokemonName: getPokemonNameWithAffix(user), moveName: copiedMove.name }));
return true;
}
@ -7326,7 +7326,7 @@ export class SketchAttr extends MoveEffectAttr {
user.setMove(sketchIndex, sketchedMove.id);
globalScene.queueMessage(i18next.t("moveTriggers:sketchedMove", { pokemonName: getPokemonNameWithAffix(user), moveName: sketchedMove.name }));
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:sketchedMove", { pokemonName: getPokemonNameWithAffix(user), moveName: sketchedMove.name }));
return true;
}
@ -7381,9 +7381,9 @@ export class AbilityChangeAttr extends MoveEffectAttr {
globalScene.triggerPokemonFormChange(moveTarget, SpeciesFormChangeRevertWeatherFormTrigger);
if (moveTarget.breakIllusion()) {
globalScene.queueMessage(i18next.t("abilityTriggers:illusionBreak", { pokemonName: getPokemonNameWithAffix(moveTarget) }));
globalScene.phaseManager.queueMessage(i18next.t("abilityTriggers:illusionBreak", { pokemonName: getPokemonNameWithAffix(moveTarget) }));
}
globalScene.queueMessage(i18next.t("moveTriggers:acquiredAbility", { pokemonName: getPokemonNameWithAffix(moveTarget), abilityName: allAbilities[this.ability].name }));
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:acquiredAbility", { pokemonName: getPokemonNameWithAffix(moveTarget), abilityName: allAbilities[this.ability].name }));
moveTarget.setTempAbility(allAbilities[this.ability]);
globalScene.triggerPokemonFormChange(moveTarget, SpeciesFormChangeRevertWeatherFormTrigger);
return true;
@ -7408,13 +7408,13 @@ export class AbilityCopyAttr extends MoveEffectAttr {
return false;
}
globalScene.queueMessage(i18next.t("moveTriggers:copiedTargetAbility", { pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target), abilityName: allAbilities[target.getAbility().id].name }));
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:copiedTargetAbility", { pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target), abilityName: allAbilities[target.getAbility().id].name }));
user.setTempAbility(target.getAbility());
const ally = user.getAlly();
if (this.copyToPartner && globalScene.currentBattle?.double && !isNullOrUndefined(ally) && ally.hp) { // TODO is this the best way to check that the ally is active?
globalScene.queueMessage(i18next.t("moveTriggers:copiedTargetAbility", { pokemonName: getPokemonNameWithAffix(ally), targetName: getPokemonNameWithAffix(target), abilityName: allAbilities[target.getAbility().id].name }));
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:copiedTargetAbility", { pokemonName: getPokemonNameWithAffix(ally), targetName: getPokemonNameWithAffix(target), abilityName: allAbilities[target.getAbility().id].name }));
ally.setTempAbility(target.getAbility());
}
@ -7447,7 +7447,7 @@ export class AbilityGiveAttr extends MoveEffectAttr {
return false;
}
globalScene.queueMessage(i18next.t("moveTriggers:acquiredAbility", { pokemonName: getPokemonNameWithAffix(target), abilityName: allAbilities[user.getAbility().id].name }));
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:acquiredAbility", { pokemonName: getPokemonNameWithAffix(target), abilityName: allAbilities[user.getAbility().id].name }));
target.setTempAbility(user.getAbility());
@ -7467,7 +7467,7 @@ export class SwitchAbilitiesAttr extends MoveEffectAttr {
const tempAbility = user.getAbility();
globalScene.queueMessage(i18next.t("moveTriggers:swappedAbilitiesWithTarget", { pokemonName: getPokemonNameWithAffix(user) }));
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:swappedAbilitiesWithTarget", { pokemonName: getPokemonNameWithAffix(user) }));
user.setTempAbility(target.getAbility());
target.setTempAbility(tempAbility);
@ -7497,7 +7497,7 @@ export class SuppressAbilitiesAttr extends MoveEffectAttr {
return false;
}
globalScene.queueMessage(i18next.t("moveTriggers:suppressAbilities", { pokemonName: getPokemonNameWithAffix(target) }));
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:suppressAbilities", { pokemonName: getPokemonNameWithAffix(target) }));
target.suppressAbility();
@ -7550,9 +7550,9 @@ export class TransformAttr extends MoveEffectAttr {
return false;
}
globalScene.unshiftPhase(new PokemonTransformPhase(user.getBattlerIndex(), target.getBattlerIndex()));
globalScene.phaseManager.unshiftPhase(new PokemonTransformPhase(user.getBattlerIndex(), target.getBattlerIndex()));
globalScene.queueMessage(i18next.t("moveTriggers:transformedIntoTarget", { pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target) }));
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:transformedIntoTarget", { pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target) }));
return true;
}
@ -7589,7 +7589,7 @@ export class SwapStatAttr extends MoveEffectAttr {
user.setStat(this.stat, target.getStat(this.stat, false), false);
target.setStat(this.stat, temp, false);
globalScene.queueMessage(i18next.t("moveTriggers:switchedStat", {
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:switchedStat", {
pokemonName: getPokemonNameWithAffix(user),
stat: i18next.t(getStatKey(this.stat)),
}));
@ -7635,7 +7635,7 @@ export class ShiftStatAttr extends MoveEffectAttr {
user.setStat(this.statToSwitch, secondStat, false);
user.setStat(this.statToSwitchWith, firstStat, false);
globalScene.queueMessage(i18next.t("moveTriggers:shiftedStats", {
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:shiftedStats", {
pokemonName: getPokemonNameWithAffix(user),
statToSwitch: i18next.t(getStatKey(this.statToSwitch)),
statToSwitchWith: i18next.t(getStatKey(this.statToSwitchWith))
@ -7694,7 +7694,7 @@ export class AverageStatsAttr extends MoveEffectAttr {
target.setStat(s, avg, false);
}
globalScene.queueMessage(i18next.t(this.msgKey, { pokemonName: getPokemonNameWithAffix(user) }));
globalScene.phaseManager.queueMessage(i18next.t(this.msgKey, { pokemonName: getPokemonNameWithAffix(user) }));
return true;
}
@ -7709,7 +7709,7 @@ export class MoneyAttr extends MoveEffectAttr {
apply(user: Pokemon, target: Pokemon, move: Move): boolean {
globalScene.currentBattle.moneyScattered += globalScene.getWaveMoneyAmount(0.2);
globalScene.queueMessage(i18next.t("moveTriggers:coinsScatteredEverywhere"));
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:coinsScatteredEverywhere"));
return true;
}
}
@ -7733,7 +7733,7 @@ export class DestinyBondAttr extends MoveEffectAttr {
* @returns true
*/
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
globalScene.queueMessage(`${i18next.t("moveTriggers:tryingToTakeFoeDown", { pokemonName: getPokemonNameWithAffix(user) })}`);
globalScene.phaseManager.queueMessage(`${i18next.t("moveTriggers:tryingToTakeFoeDown", { pokemonName: getPokemonNameWithAffix(user) })}`);
user.addTag(BattlerTagType.DESTINY_BOND, undefined, move.id, user.id);
return true;
}
@ -7847,12 +7847,12 @@ export class AfterYouAttr extends MoveEffectAttr {
* @returns true
*/
override apply(user: Pokemon, target: Pokemon, _move: Move, _args: any[]): boolean {
globalScene.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.
const nextAttackPhase = globalScene.findPhase<MovePhase>((phase) => phase.pokemon === target);
if (nextAttackPhase && globalScene.tryRemovePhase((phase: MovePhase) => phase.pokemon === target)) {
globalScene.prependToPhase(new MovePhase(target, [ ...nextAttackPhase.targets ], nextAttackPhase.move), MovePhase);
const nextAttackPhase = globalScene.phaseManager.findPhase<MovePhase>((phase) => phase.pokemon === target);
if (nextAttackPhase && globalScene.phaseManager.tryRemovePhase((phase: MovePhase) => phase.pokemon === target)) {
globalScene.phaseManager.prependToPhase(new MovePhase(target, [ ...nextAttackPhase.targets ], nextAttackPhase.move), MovePhase);
}
return true;
@ -7875,19 +7875,19 @@ export class ForceLastAttr extends MoveEffectAttr {
* @returns true
*/
override apply(user: Pokemon, target: Pokemon, _move: Move, _args: any[]): boolean {
globalScene.queueMessage(i18next.t("moveTriggers:forceLast", { targetPokemonName: getPokemonNameWithAffix(target) }));
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:forceLast", { targetPokemonName: getPokemonNameWithAffix(target) }));
const targetMovePhase = globalScene.findPhase<MovePhase>((phase) => phase.pokemon === target);
if (targetMovePhase && !targetMovePhase.isForcedLast() && globalScene.tryRemovePhase((phase: MovePhase) => phase.pokemon === target)) {
const targetMovePhase = globalScene.phaseManager.findPhase<MovePhase>((phase) => phase.pokemon === target);
if (targetMovePhase && !targetMovePhase.isForcedLast() && globalScene.phaseManager.tryRemovePhase((phase: MovePhase) => phase.pokemon === target)) {
// Finding the phase to insert the move in front of -
// Either the end of the turn or in front of another, slower move which has also been forced last
const prependPhase = globalScene.findPhase((phase) =>
const prependPhase = globalScene.phaseManager.findPhase((phase) =>
[ MovePhase, MoveEndPhase ].every(cls => !(phase instanceof cls))
|| (phase.is("MovePhase")) && phaseForcedSlower(phase, target, !!globalScene.arena.getTag(ArenaTagType.TRICK_ROOM))
);
if (prependPhase) {
globalScene.phaseQueue.splice(
globalScene.phaseQueue.indexOf(prependPhase),
globalScene.phaseManager.phaseQueue.splice(
globalScene.phaseManager.phaseQueue.indexOf(prependPhase),
0,
new MovePhase(target, [ ...targetMovePhase.targets ], targetMovePhase.move, false, false, false, true)
);
@ -7920,7 +7920,7 @@ const failIfDampCondition: MoveConditionFunc = (user, target, move) => {
globalScene.getField(true).map(p=>applyAbAttrs(FieldPreventExplosiveMovesAbAttr, p, cancelled));
// Queue a message if an ability prevented usage of the move
if (cancelled.value) {
globalScene.queueMessage(i18next.t("moveTriggers:cannotUseMove", { pokemonName: getPokemonNameWithAffix(user), moveName: move.name }));
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:cannotUseMove", { pokemonName: getPokemonNameWithAffix(user), moveName: move.name }));
}
return !cancelled.value;
};
@ -7929,7 +7929,7 @@ const userSleptOrComatoseCondition: MoveConditionFunc = (user: Pokemon, target:
const targetSleptOrComatoseCondition: MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => target.status?.effect === StatusEffect.SLEEP || target.hasAbility(AbilityId.COMATOSE);
const failIfLastCondition: MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => globalScene.phaseQueue.find(phase => phase.is("MovePhase")) !== undefined;
const failIfLastCondition: MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => globalScene.phaseManager.phaseQueue.find(phase => phase.is("MovePhase")) !== undefined;
const failIfLastInPartyCondition: MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => {
const party: Pokemon[] = user.isPlayer() ? globalScene.getPlayerParty() : globalScene.getEnemyParty();
@ -8107,7 +8107,7 @@ export class ResistLastMoveTypeAttr extends MoveEffectAttr {
}
const type = validTypes[user.randBattleSeedInt(validTypes.length)];
user.summonData.types = [ type ];
globalScene.queueMessage(i18next.t("battle:transformedIntoType", { pokemonName: getPokemonNameWithAffix(user), type: toReadableString(PokemonType[type]) }));
globalScene.phaseManager.queueMessage(i18next.t("battle:transformedIntoType", { pokemonName: getPokemonNameWithAffix(user), type: toReadableString(PokemonType[type]) }));
user.updateInfo();
return true;
@ -8166,7 +8166,7 @@ export class ExposedMoveAttr extends AddBattlerTagAttr {
return false;
}
globalScene.queueMessage(i18next.t("moveTriggers:exposedMove", { pokemonName: getPokemonNameWithAffix(user), targetPokemonName: getPokemonNameWithAffix(target) }));
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:exposedMove", { pokemonName: getPokemonNameWithAffix(user), targetPokemonName: getPokemonNameWithAffix(target) }));
return true;
}
@ -8802,7 +8802,7 @@ export function initMoves() {
.reflectable(),
new SelfStatusMove(MoveId.BELLY_DRUM, PokemonType.NORMAL, -1, 10, -1, 0, 2)
.attr(CutHpStatStageBoostAttr, [ Stat.ATK ], 12, 2, (user) => {
globalScene.queueMessage(i18next.t("moveTriggers:cutOwnHpAndMaximizedStat", { pokemonName: getPokemonNameWithAffix(user), statName: i18next.t(getStatKey(Stat.ATK)) }));
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:cutOwnHpAndMaximizedStat", { pokemonName: getPokemonNameWithAffix(user), statName: i18next.t(getStatKey(Stat.ATK)) }));
}),
new AttackMove(MoveId.SLUDGE_BOMB, PokemonType.POISON, MoveCategory.SPECIAL, 90, 100, 10, 30, 0, 2)
.attr(StatusEffectAttr, StatusEffect.POISON)
@ -10370,7 +10370,7 @@ export function initMoves() {
.attr(HealStatusEffectAttr, true, StatusEffect.FREEZE)
.attr(AddBattlerTagAttr, BattlerTagType.BURNED_UP, true, false)
.attr(RemoveTypeAttr, PokemonType.FIRE, (user) => {
globalScene.queueMessage(i18next.t("moveTriggers:burnedItselfOut", { pokemonName: getPokemonNameWithAffix(user) }));
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:burnedItselfOut", { pokemonName: getPokemonNameWithAffix(user) }));
}),
new StatusMove(MoveId.SPEED_SWAP, PokemonType.PSYCHIC, -1, 10, -1, 0, 7)
.attr(SwapStatAttr, Stat.SPD)
@ -11154,7 +11154,7 @@ export function initMoves() {
})
.attr(AddBattlerTagAttr, BattlerTagType.DOUBLE_SHOCKED, true, false)
.attr(RemoveTypeAttr, PokemonType.ELECTRIC, (user) => {
globalScene.queueMessage(i18next.t("moveTriggers:usedUpAllElectricity", { pokemonName: getPokemonNameWithAffix(user) }));
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:usedUpAllElectricity", { pokemonName: getPokemonNameWithAffix(user) }));
}),
new AttackMove(MoveId.GIGATON_HAMMER, PokemonType.STEEL, MoveCategory.PHYSICAL, 160, 100, 5, -1, 0, 9)
.makesContact(false)

View File

@ -182,7 +182,7 @@ export const ATrainersTestEncounter: MysteryEncounter = MysteryEncounterBuilder.
async () => {
const encounter = globalScene.currentBattle.mysteryEncounter!;
// Full heal party
globalScene.unshiftPhase(new PartyHealPhase(true));
globalScene.phaseManager.unshiftPhase(new PartyHealPhase(true));
const eggOptions: IEggOptions = {
pulled: false,

View File

@ -237,7 +237,7 @@ export const AbsoluteAvariceEncounter: MysteryEncounter = MysteryEncounterBuilde
tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON],
mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
queueEncounterMessage(`${namespace}:option.1.boss_enraged`);
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new StatStageChangePhase(pokemon.getBattlerIndex(), true, statChangesForBattle, 1),
);
},

View File

@ -137,7 +137,7 @@ export const AnOfferYouCantRefuseEncounter: MysteryEncounter = MysteryEncounterB
})
.withOptionPhase(async () => {
// Give the player a Shiny Charm
globalScene.unshiftPhase(new ModifierRewardPhase(modifierTypes.SHINY_CHARM));
globalScene.phaseManager.unshiftPhase(new ModifierRewardPhase(modifierTypes.SHINY_CHARM));
leaveEncounterWithoutBattle(true);
})
.build(),

View File

@ -237,7 +237,7 @@ export const BerriesAboundEncounter: MysteryEncounter = MysteryEncounterBuilder.
config.pokemonConfigs![0].tags = [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON];
config.pokemonConfigs![0].mysteryEncounterBattleEffects = (pokemon: Pokemon) => {
queueEncounterMessage(`${namespace}:option.2.boss_enraged`);
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new StatStageChangePhase(pokemon.getBattlerIndex(), true, statChangesForBattle, 1),
);
};

View File

@ -766,7 +766,7 @@ function doBugTypeMoveTutor(): Promise<void> {
// Option select complete, handle if they are learning a move
if (result && result.selectedOptionIndex < moveOptions.length) {
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new LearnMovePhase(result.selectedPokemonIndex, moveOptions[result.selectedOptionIndex].moveId),
);
}

View File

@ -176,7 +176,7 @@ export const DancingLessonsEncounter: MysteryEncounter = MysteryEncounterBuilder
tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON],
mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
queueEncounterMessage(`${namespace}:option.1.boss_enraged`);
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new StatStageChangePhase(
pokemon.getBattlerIndex(),
true,
@ -245,7 +245,7 @@ export const DancingLessonsEncounter: MysteryEncounter = MysteryEncounterBuilder
const onPokemonSelected = (pokemon: PlayerPokemon) => {
encounter.setDialogueToken("selectedPokemon", pokemon.getNameToRender());
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new LearnMovePhase(globalScene.getPlayerParty().indexOf(pokemon), MoveId.REVELATION_DANCE),
);

View File

@ -165,7 +165,7 @@ export const DarkDealEncounter: MysteryEncounter = MysteryEncounterBuilder.withE
.withOptionPhase(async () => {
// Give the player 5 Rogue Balls
const encounter = globalScene.currentBattle.mysteryEncounter!;
globalScene.unshiftPhase(new ModifierRewardPhase(modifierTypes.ROGUE_BALL));
globalScene.phaseManager.unshiftPhase(new ModifierRewardPhase(modifierTypes.ROGUE_BALL));
// Start encounter with random legendary (7-10 starter strength) that has level additive
// If this is a mono-type challenge, always ensure the required type is filtered for

View File

@ -65,10 +65,10 @@ const doEventReward = () => {
return !(existingCharm && existingCharm.getStackCount() >= existingCharm.getMaxStackCount());
});
if (candidates.length > 0) {
globalScene.unshiftPhase(new ModifierRewardPhase(modifierTypes[randSeedItem(candidates)]));
globalScene.phaseManager.unshiftPhase(new ModifierRewardPhase(modifierTypes[randSeedItem(candidates)]));
} else {
// At max stacks, give a Voucher instead
globalScene.unshiftPhase(new ModifierRewardPhase(modifierTypes.VOUCHER));
globalScene.phaseManager.unshiftPhase(new ModifierRewardPhase(modifierTypes.VOUCHER));
}
}
};
@ -181,7 +181,7 @@ export const DelibirdyEncounter: MysteryEncounter = MysteryEncounterBuilder.with
);
doEventReward();
} else {
globalScene.unshiftPhase(new ModifierRewardPhase(modifierTypes.AMULET_COIN));
globalScene.phaseManager.unshiftPhase(new ModifierRewardPhase(modifierTypes.AMULET_COIN));
doEventReward();
}
@ -266,7 +266,7 @@ export const DelibirdyEncounter: MysteryEncounter = MysteryEncounterBuilder.with
);
doEventReward();
} else {
globalScene.unshiftPhase(new ModifierRewardPhase(modifierTypes.CANDY_JAR));
globalScene.phaseManager.unshiftPhase(new ModifierRewardPhase(modifierTypes.CANDY_JAR));
doEventReward();
}
} else {
@ -288,7 +288,7 @@ export const DelibirdyEncounter: MysteryEncounter = MysteryEncounterBuilder.with
);
doEventReward();
} else {
globalScene.unshiftPhase(new ModifierRewardPhase(modifierTypes.BERRY_POUCH));
globalScene.phaseManager.unshiftPhase(new ModifierRewardPhase(modifierTypes.BERRY_POUCH));
doEventReward();
}
}
@ -372,7 +372,7 @@ export const DelibirdyEncounter: MysteryEncounter = MysteryEncounterBuilder.with
);
doEventReward();
} else {
globalScene.unshiftPhase(new ModifierRewardPhase(modifierTypes.HEALING_CHARM));
globalScene.phaseManager.unshiftPhase(new ModifierRewardPhase(modifierTypes.HEALING_CHARM));
doEventReward();
}

View File

@ -92,7 +92,7 @@ export const FieryFalloutEncounter: MysteryEncounter = MysteryEncounterBuilder.w
gender: Gender.MALE,
tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON],
mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new StatStageChangePhase(pokemon.getBattlerIndex(), true, [Stat.SPDEF, Stat.SPD], 1),
);
},
@ -103,7 +103,7 @@ export const FieryFalloutEncounter: MysteryEncounter = MysteryEncounterBuilder.w
gender: Gender.FEMALE,
tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON],
mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new StatStageChangePhase(pokemon.getBattlerIndex(), true, [Stat.SPDEF, Stat.SPD], 1),
);
},

View File

@ -76,7 +76,9 @@ export const FightOrFlightEncounter: MysteryEncounter = MysteryEncounterBuilder.
queueEncounterMessage(`${namespace}:option.1.stat_boost`);
// Randomly boost 1 stat 2 stages
// Cannot boost Spd, Acc, or Evasion
globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [randSeedInt(4, 1)], 2));
globalScene.phaseManager.unshiftPhase(
new StatStageChangePhase(pokemon.getBattlerIndex(), true, [randSeedInt(4, 1)], 2),
);
},
},
],

View File

@ -411,13 +411,13 @@ function summonPlayerPokemonAnimation(pokemon: PlayerPokemon): Promise<void> {
pokemon.resetSummonData();
globalScene.time.delayedCall(1000, () => {
if (pokemon.isShiny()) {
globalScene.unshiftPhase(new ShinySparklePhase(pokemon.getBattlerIndex()));
globalScene.phaseManager.unshiftPhase(new ShinySparklePhase(pokemon.getBattlerIndex()));
}
pokemon.resetTurnData();
globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeActiveTrigger, true);
globalScene.pushPhase(new PostSummonPhase(pokemon.getBattlerIndex()));
globalScene.phaseManager.pushPhase(new PostSummonPhase(pokemon.getBattlerIndex()));
resolve();
});
},

View File

@ -189,8 +189,8 @@ export const MysteriousChestEncounter: MysteryEncounter = MysteryEncounterBuilde
const allowedPokemon = globalScene.getPokemonAllowedInBattle();
if (allowedPokemon.length === 0) {
// If there are no longer any legal pokemon in the party, game over.
globalScene.clearPhaseQueue();
globalScene.unshiftPhase(new GameOverPhase());
globalScene.phaseManager.clearPhaseQueue();
globalScene.phaseManager.unshiftPhase(new GameOverPhase());
} else {
// Show which Pokemon was KOed, then start battle against Gimmighoul
await transitionMysteryEncounterIntroVisuals(true, true, 500);

View File

@ -276,7 +276,7 @@ async function summonSafariPokemon() {
const encounter = globalScene.currentBattle.mysteryEncounter!;
// Message pokemon remaining
encounter.setDialogueToken("remainingCount", encounter.misc.safariPokemonRemaining);
globalScene.queueMessage(getEncounterText(`${namespace}:safari.remaining_count`) ?? "", null, true);
globalScene.phaseManager.queueMessage(getEncounterText(`${namespace}:safari.remaining_count`) ?? "", null, true);
// Generate pokemon using safariPokemonRemaining so they are always the same pokemon no matter how many turns are taken
// Safari pokemon roll twice on shiny and HA chances, but are otherwise normal
@ -325,7 +325,7 @@ async function summonSafariPokemon() {
encounter.misc.pokemon = pokemon;
encounter.misc.safariPokemonRemaining -= 1;
globalScene.unshiftPhase(new SummonPhase(0, false));
globalScene.phaseManager.unshiftPhase(new SummonPhase(0, false));
encounter.setDialogueToken("pokemonName", getPokemonNameWithAffix(pokemon));
@ -336,7 +336,7 @@ async function summonSafariPokemon() {
const ivScannerModifier = globalScene.findModifier(m => m instanceof IvScannerModifier);
if (ivScannerModifier) {
globalScene.pushPhase(new ScanIvsPhase(pokemon.getBattlerIndex()));
globalScene.phaseManager.pushPhase(new ScanIvsPhase(pokemon.getBattlerIndex()));
}
}
@ -559,7 +559,7 @@ async function doEndTurn(cursorIndex: number) {
leaveEncounterWithoutBattle(true);
}
} else {
globalScene.queueMessage(getEncounterText(`${namespace}:safari.watching`) ?? "", 0, null, 1000);
globalScene.phaseManager.queueMessage(getEncounterText(`${namespace}:safari.watching`) ?? "", 0, null, 1000);
initSubsequentOptionSelect({
overrideOptions: safariZoneGameOptions,
startingCursorIndex: cursorIndex,

View File

@ -155,7 +155,7 @@ export const SlumberingSnorlaxEncounter: MysteryEncounter = MysteryEncounterBuil
async () => {
// Fall asleep waiting for Snorlax
// Full heal party
globalScene.unshiftPhase(new PartyHealPhase(true));
globalScene.phaseManager.unshiftPhase(new PartyHealPhase(true));
queueEncounterMessage(`${namespace}:option.2.rest_result`);
leaveEncounterWithoutBattle();
},

View File

@ -227,7 +227,9 @@ async function doBiomeTransitionDialogueAndBattleInit() {
tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON],
mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
queueEncounterMessage(`${namespace}:boss_enraged`);
globalScene.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, statChangesForBattle, 1));
globalScene.phaseManager.unshiftPhase(
new StatStageChangePhase(pokemon.getBattlerIndex(), true, statChangesForBattle, 1),
);
},
},
],

View File

@ -658,8 +658,8 @@ function onGameOver() {
globalScene.playBgm(globalScene.arena.bgm);
// Clear any leftover battle phases
globalScene.clearPhaseQueue();
globalScene.clearPhaseQueueSplice();
globalScene.phaseManager.clearPhaseQueue();
globalScene.phaseManager.clearPhaseQueueSplice();
// Return enemy Pokemon
const pokemon = globalScene.getEnemyPokemon();

View File

@ -116,7 +116,7 @@ export const TheStrongStuffEncounter: MysteryEncounter = MysteryEncounterBuilder
tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON],
mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
queueEncounterMessage(`${namespace}:option.2.stat_boost`);
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new StatStageChangePhase(pokemon.getBattlerIndex(), true, [Stat.DEF, Stat.SPDEF], 1),
);
},

View File

@ -143,7 +143,7 @@ export const TheWinstrateChallengeEncounter: MysteryEncounter = MysteryEncounter
},
async () => {
// Refuse the challenge, they full heal the party and give the player a Rarer Candy
globalScene.unshiftPhase(new PartyHealPhase(true));
globalScene.phaseManager.unshiftPhase(new PartyHealPhase(true));
setEncounterRewards({
guaranteedModifierTypeFuncs: [modifierTypes.RARER_CANDY],
fillRemaining: false,
@ -209,7 +209,7 @@ function endTrainerBattleAndShowDialogue(): Promise<void> {
for (const pokemon of playerField) {
pokemon.lapseTag(BattlerTagType.COMMANDED);
}
playerField.forEach((_, p) => globalScene.unshiftPhase(new ReturnPhase(p)));
playerField.forEach((_, p) => globalScene.phaseManager.unshiftPhase(new ReturnPhase(p)));
for (const pokemon of globalScene.getPlayerParty()) {
// Only trigger form change when Eiscue is in Noice form
@ -227,7 +227,7 @@ function endTrainerBattleAndShowDialogue(): Promise<void> {
applyPostBattleInitAbAttrs(PostBattleInitAbAttr, pokemon);
}
globalScene.unshiftPhase(new ShowTrainerPhase());
globalScene.phaseManager.unshiftPhase(new ShowTrainerPhase());
// Hide the trainer and init next battle
const trainer = globalScene.currentBattle.trainer;
// Unassign previous trainer from battle so it isn't destroyed before animation completes

View File

@ -103,7 +103,7 @@ export const UncommonBreedEncounter: MysteryEncounter = MysteryEncounterBuilder.
tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON],
mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
queueEncounterMessage(`${namespace}:option.1.stat_boost`);
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new StatStageChangePhase(pokemon.getBattlerIndex(), true, statChangesForBattle, 1),
);
},

View File

@ -51,7 +51,7 @@ function getTextWithDialogueTokens(keyOrString: string): string | null {
*/
export function queueEncounterMessage(contentKey: string): void {
const text: string | null = getEncounterText(contentKey);
globalScene.queueMessage(text ?? "", null, true);
globalScene.phaseManager.queueMessage(text ?? "", null, true);
}
/**

View File

@ -428,7 +428,7 @@ export async function initBattleWithEnemyConfig(partyConfig: EnemyPartyConfig):
console.log("Moveset:", moveset);
});
globalScene.pushPhase(new MysteryEncounterBattlePhase(partyConfig.disableSwitch));
globalScene.phaseManager.pushPhase(new MysteryEncounterBattlePhase(partyConfig.disableSwitch));
await Promise.all(loadEnemyAssets);
battle.enemyParty.forEach((enemyPokemon_2, e_1) => {
@ -480,7 +480,7 @@ export function updatePlayerMoney(changeValue: number, playSound = true, showMes
}
if (showMessage) {
if (changeValue < 0) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("mysteryEncounterMessages:paid_money", {
amount: -changeValue,
}),
@ -488,7 +488,7 @@ export function updatePlayerMoney(changeValue: number, playSound = true, showMes
true,
);
} else {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("mysteryEncounterMessages:receive_money", {
amount: changeValue,
}),
@ -767,9 +767,9 @@ export function setEncounterRewards(
}
if (customShopRewards) {
globalScene.unshiftPhase(new SelectModifierPhase(0, undefined, customShopRewards));
globalScene.phaseManager.unshiftPhase(new SelectModifierPhase(0, undefined, customShopRewards));
} else {
globalScene.tryRemovePhase(p => p.is("MysteryEncounterRewardsPhase"));
globalScene.phaseManager.tryRemovePhase(p => p.is("MysteryEncounterRewardsPhase"));
}
if (eggRewards) {
@ -807,7 +807,7 @@ export function setEncounterExp(participantId: number | number[], baseExpValue:
const participantIds = Array.isArray(participantId) ? participantId : [participantId];
globalScene.currentBattle.mysteryEncounter!.doEncounterExp = () => {
globalScene.unshiftPhase(new PartyExpPhase(baseExpValue, useWaveIndex, new Set(participantIds)));
globalScene.phaseManager.unshiftPhase(new PartyExpPhase(baseExpValue, useWaveIndex, new Set(participantIds)));
return true;
};
@ -829,7 +829,7 @@ export class OptionSelectSettings {
* @param optionSelectSettings
*/
export function initSubsequentOptionSelect(optionSelectSettings: OptionSelectSettings) {
globalScene.pushPhase(new MysteryEncounterPhase(optionSelectSettings));
globalScene.phaseManager.pushPhase(new MysteryEncounterPhase(optionSelectSettings));
}
/**
@ -843,8 +843,8 @@ export function leaveEncounterWithoutBattle(
encounterMode: MysteryEncounterMode = MysteryEncounterMode.NO_BATTLE,
) {
globalScene.currentBattle.mysteryEncounter!.encounterMode = encounterMode;
globalScene.clearPhaseQueue();
globalScene.clearPhaseQueueSplice();
globalScene.phaseManager.clearPhaseQueue();
globalScene.phaseManager.clearPhaseQueueSplice();
handleMysteryEncounterVictory(addHealPhase);
}
@ -857,8 +857,8 @@ export function handleMysteryEncounterVictory(addHealPhase = false, doNotContinu
const allowedPkm = globalScene.getPlayerParty().filter(pkm => pkm.isAllowedInBattle());
if (allowedPkm.length === 0) {
globalScene.clearPhaseQueue();
globalScene.unshiftPhase(new GameOverPhase());
globalScene.phaseManager.clearPhaseQueue();
globalScene.phaseManager.unshiftPhase(new GameOverPhase());
return;
}
@ -869,8 +869,8 @@ export function handleMysteryEncounterVictory(addHealPhase = false, doNotContinu
return;
}
if (encounter.encounterMode === MysteryEncounterMode.NO_BATTLE) {
globalScene.pushPhase(new MysteryEncounterRewardsPhase(addHealPhase));
globalScene.pushPhase(new EggLapsePhase());
globalScene.phaseManager.pushPhase(new MysteryEncounterRewardsPhase(addHealPhase));
globalScene.phaseManager.pushPhase(new EggLapsePhase());
} else if (
!globalScene
.getEnemyParty()
@ -878,15 +878,15 @@ export function handleMysteryEncounterVictory(addHealPhase = false, doNotContinu
encounter.encounterMode !== MysteryEncounterMode.TRAINER_BATTLE ? p.isOnField() : !p?.isFainted(true),
)
) {
globalScene.pushPhase(new BattleEndPhase(true));
globalScene.phaseManager.pushPhase(new BattleEndPhase(true));
if (encounter.encounterMode === MysteryEncounterMode.TRAINER_BATTLE) {
globalScene.pushPhase(new TrainerVictoryPhase());
globalScene.phaseManager.pushPhase(new TrainerVictoryPhase());
}
if (globalScene.gameMode.isEndless || !globalScene.gameMode.isWaveFinal(globalScene.currentBattle.waveIndex)) {
globalScene.pushPhase(new MysteryEncounterRewardsPhase(addHealPhase));
globalScene.phaseManager.pushPhase(new MysteryEncounterRewardsPhase(addHealPhase));
if (!encounter.doContinueEncounter) {
// Only lapse eggs once for multi-battle encounters
globalScene.pushPhase(new EggLapsePhase());
globalScene.phaseManager.pushPhase(new EggLapsePhase());
}
}
}
@ -900,8 +900,8 @@ export function handleMysteryEncounterBattleFailed(addHealPhase = false, doNotCo
const allowedPkm = globalScene.getPlayerParty().filter(pkm => pkm.isAllowedInBattle());
if (allowedPkm.length === 0) {
globalScene.clearPhaseQueue();
globalScene.unshiftPhase(new GameOverPhase());
globalScene.phaseManager.clearPhaseQueue();
globalScene.phaseManager.unshiftPhase(new GameOverPhase());
return;
}
@ -912,14 +912,14 @@ export function handleMysteryEncounterBattleFailed(addHealPhase = false, doNotCo
return;
}
if (encounter.encounterMode !== MysteryEncounterMode.NO_BATTLE) {
globalScene.pushPhase(new BattleEndPhase(false));
globalScene.phaseManager.pushPhase(new BattleEndPhase(false));
}
globalScene.pushPhase(new MysteryEncounterRewardsPhase(addHealPhase));
globalScene.phaseManager.pushPhase(new MysteryEncounterRewardsPhase(addHealPhase));
if (!encounter.doContinueEncounter) {
// Only lapse eggs once for multi-battle encounters
globalScene.pushPhase(new EggLapsePhase());
globalScene.phaseManager.pushPhase(new EggLapsePhase());
}
}
@ -1004,12 +1004,14 @@ export function handleMysteryEncounterBattleStartEffects() {
} else {
source = globalScene.getEnemyField()[0];
}
globalScene.phaseManager.pushPhase(
// @ts-ignore: source cannot be undefined
globalScene.pushPhase(new MovePhase(source, effect.targets, effect.move, effect.followUp, effect.ignorePp));
new MovePhase(source, effect.targets, effect.move, effect.followUp, effect.ignorePp),
);
});
// Pseudo turn end phase to reset flinch states, Endure, etc.
globalScene.pushPhase(new MysteryEncounterBattleStartCleanupPhase());
globalScene.phaseManager.pushPhase(new MysteryEncounterBattleStartCleanupPhase());
encounter.startOfBattleEffectsComplete = true;
}

View File

@ -675,7 +675,7 @@ export async function catchPokemon(
if (!globalScene.getEnemyParty().some(p => p.id === pokemon.id)) {
globalScene.getEnemyParty().push(pokemon);
}
globalScene.unshiftPhase(new VictoryPhase(pokemon.id, true));
globalScene.phaseManager.unshiftPhase(new VictoryPhase(pokemon.id, true));
globalScene.pokemonInfoContainer.hide();
if (pokeball) {
removePb(pokeball);

View File

@ -297,8 +297,8 @@ export class Arena {
*/
trySetWeatherOverride(weather: WeatherType): boolean {
this.weather = new Weather(weather, 0);
globalScene.unshiftPhase(new CommonAnimPhase(undefined, undefined, CommonAnim.SUNNY + (weather - 1)));
globalScene.queueMessage(getWeatherStartMessage(weather)!); // TODO: is this bang correct?
globalScene.phaseManager.unshiftPhase(new CommonAnimPhase(undefined, undefined, CommonAnim.SUNNY + (weather - 1)));
globalScene.phaseManager.queueMessage(getWeatherStartMessage(weather)!); // TODO: is this bang correct?
return true;
}
@ -328,10 +328,10 @@ export class Arena {
this.weather?.isImmutable() &&
![WeatherType.HARSH_SUN, WeatherType.HEAVY_RAIN, WeatherType.STRONG_WINDS, WeatherType.NONE].includes(weather)
) {
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new CommonAnimPhase(undefined, undefined, CommonAnim.SUNNY + (oldWeatherType - 1), true),
);
globalScene.queueMessage(getLegendaryWeatherContinuesMessage(oldWeatherType)!);
globalScene.phaseManager.queueMessage(getLegendaryWeatherContinuesMessage(oldWeatherType)!);
return false;
}
@ -348,10 +348,12 @@ export class Arena {
); // TODO: is this bang correct?
if (this.weather) {
globalScene.unshiftPhase(new CommonAnimPhase(undefined, undefined, CommonAnim.SUNNY + (weather - 1), true));
globalScene.queueMessage(getWeatherStartMessage(weather)!); // TODO: is this bang correct?
globalScene.phaseManager.unshiftPhase(
new CommonAnimPhase(undefined, undefined, CommonAnim.SUNNY + (weather - 1), true),
);
globalScene.phaseManager.queueMessage(getWeatherStartMessage(weather)!); // TODO: is this bang correct?
} else {
globalScene.queueMessage(getWeatherClearMessage(oldWeatherType)!); // TODO: is this bang correct?
globalScene.phaseManager.queueMessage(getWeatherClearMessage(oldWeatherType)!); // TODO: is this bang correct?
}
globalScene
@ -431,11 +433,13 @@ export class Arena {
if (this.terrain) {
if (!ignoreAnim) {
globalScene.unshiftPhase(new CommonAnimPhase(undefined, undefined, CommonAnim.MISTY_TERRAIN + (terrain - 1)));
globalScene.phaseManager.unshiftPhase(
new CommonAnimPhase(undefined, undefined, CommonAnim.MISTY_TERRAIN + (terrain - 1)),
);
}
globalScene.queueMessage(getTerrainStartMessage(terrain)!); // TODO: is this bang correct?
globalScene.phaseManager.queueMessage(getTerrainStartMessage(terrain)!); // TODO: is this bang correct?
} else {
globalScene.queueMessage(getTerrainClearMessage(oldTerrainType)!); // TODO: is this bang correct?
globalScene.phaseManager.queueMessage(getTerrainClearMessage(oldTerrainType)!); // TODO: is this bang correct?
}
globalScene

View File

@ -1298,7 +1298,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
return false;
}
// During the Pokemon's MoveEffect phase, the offset is removed to put the Pokemon "in focus"
const currentPhase = globalScene.getCurrentPhase();
const currentPhase = globalScene.phaseManager.getCurrentPhase();
return !(currentPhase?.is("MoveEffectPhase") && currentPhase.getPokemon() === this);
}
@ -2537,7 +2537,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
) {
multiplier /= 2;
if (!simulated) {
globalScene.queueMessage(i18next.t("weather:strongWindsEffectMessage"));
globalScene.phaseManager.queueMessage(i18next.t("weather:strongWindsEffectMessage"));
}
}
return multiplier as TypeDamageMultiplier;
@ -4011,8 +4011,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
*
* Once the MoveEffectPhase is over (and calls it's .end() function, shiftPhase() will reset the PhaseQueueSplice via clearPhaseQueueSplice() )
*/
globalScene.setPhaseQueueSplice();
globalScene.unshiftPhase(new FaintPhase(this.getBattlerIndex(), preventEndure));
globalScene.phaseManager.setPhaseQueueSplice();
globalScene.phaseManager.unshiftPhase(new FaintPhase(this.getBattlerIndex(), preventEndure));
this.destroySubstitute();
this.lapseTag(BattlerTagType.COMMANDED);
}
@ -4049,7 +4049,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
): number {
const isIndirectDamage = [HitResult.INDIRECT, HitResult.INDIRECT_KO].includes(result);
const damagePhase = new DamageAnimPhase(this.getBattlerIndex(), damage, result as DamageResult, isCritical);
globalScene.unshiftPhase(damagePhase);
globalScene.phaseManager.unshiftPhase(damagePhase);
if (this.switchOutStatus && source) {
damage = 0;
}
@ -4615,7 +4615,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
: i18next.t("abilityTriggers:moveImmunity", {
pokemonNameWithAffix: getPokemonNameWithAffix(this),
});
globalScene.queueMessage(message);
globalScene.phaseManager.queueMessage(message);
}
/**
@ -4735,7 +4735,9 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (sourcePokemon && sourcePokemon !== this && this.isSafeguarded(sourcePokemon)) {
if (!quiet) {
globalScene.queueMessage(i18next.t("moveTriggers:safeguard", { targetName: getPokemonNameWithAffix(this) }));
globalScene.phaseManager.queueMessage(
i18next.t("moveTriggers:safeguard", { targetName: getPokemonNameWithAffix(this) }),
);
}
return false;
}
@ -4764,7 +4766,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
* cancel the attack's subsequent hits.
*/
if (effect === StatusEffect.SLEEP || effect === StatusEffect.FREEZE) {
const currentPhase = globalScene.getCurrentPhase();
const currentPhase = globalScene.phaseManager.getCurrentPhase();
if (currentPhase?.is("MoveEffectPhase") && currentPhase.getUserPokemon() === this) {
this.turnData.hitCount = 1;
this.turnData.hitsLeft = 1;
@ -4775,7 +4777,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (overrideStatus) {
this.resetStatus(false);
}
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new ObtainStatusEffectPhase(this.getBattlerIndex(), effect, turnsRemaining, sourceText, sourcePokemon),
);
return true;
@ -4825,7 +4827,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
}
if (asPhase) {
globalScene.unshiftPhase(new ResetStatusPhase(this, confusion, reloadAssets));
globalScene.phaseManager.unshiftPhase(new ResetStatusPhase(this, confusion, reloadAssets));
} else {
this.clearStatus(confusion, reloadAssets);
}
@ -5632,7 +5634,7 @@ export class PlayerPokemon extends Pokemon {
this.getFieldIndex(),
(slotIndex: number, _option: PartyOption) => {
if (slotIndex >= globalScene.currentBattle.getBattlerCount() && slotIndex < 6) {
globalScene.prependToPhase(
globalScene.phaseManager.prependToPhase(
new SwitchSummonPhase(switchType, this.getFieldIndex(), slotIndex, false),
MoveEndPhase,
);
@ -5997,7 +5999,9 @@ export class PlayerPokemon extends Pokemon {
const newPartyMemberIndex = globalScene.getPlayerParty().indexOf(this);
pokemon
.getMoveset(true)
.map((m: PokemonMove) => globalScene.unshiftPhase(new LearnMovePhase(newPartyMemberIndex, m.getMove().id)));
.map((m: PokemonMove) =>
globalScene.phaseManager.unshiftPhase(new LearnMovePhase(newPartyMemberIndex, m.getMove().id)),
);
pokemon.destroy();
this.updateFusionPalette();
}
@ -6639,7 +6643,7 @@ export class EnemyPokemon extends Pokemon {
stages++;
}
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new StatStageChangePhase(this.getBattlerIndex(), true, [boostedStat!], stages, true, true),
);
this.bossSegmentIndex--;

View File

@ -1548,7 +1548,7 @@ export class SurviveDamageModifier extends PokemonHeldItemModifier {
if (!surviveDamage.value && pokemon.randBattleSeedInt(10) < this.getStackCount()) {
surviveDamage.value = true;
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("modifier:surviveDamageApply", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
typeName: this.type.name,
@ -1598,7 +1598,7 @@ export class BypassSpeedChanceModifier extends PokemonHeldItemModifier {
const hasQuickClaw = this.type instanceof PokemonHeldItemModifierType && this.type.id === "QUICK_CLAW";
if (isCommandFight && hasQuickClaw) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("modifier:bypassSpeedChanceApply", {
pokemonName: getPokemonNameWithAffix(pokemon),
itemName: i18next.t("modifierType:ModifierType.QUICK_CLAW.name"),
@ -1684,7 +1684,7 @@ export class TurnHealModifier extends PokemonHeldItemModifier {
*/
override apply(pokemon: Pokemon): boolean {
if (!pokemon.isFullHp()) {
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new PokemonHealPhase(
pokemon.getBattlerIndex(),
toDmgValue(pokemon.getMaxHp() / 16) * this.stackCount,
@ -1782,7 +1782,7 @@ export class HitHealModifier extends PokemonHeldItemModifier {
override apply(pokemon: Pokemon): boolean {
if (pokemon.turnData.totalDamageDealt && !pokemon.isFullHp()) {
// TODO: this shouldn't be undefined AFAIK
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new PokemonHealPhase(
pokemon.getBattlerIndex(),
toDmgValue(pokemon.turnData.totalDamageDealt / 8) * this.stackCount,
@ -1950,7 +1950,7 @@ export class PokemonInstantReviveModifier extends PokemonHeldItemModifier {
*/
override apply(pokemon: Pokemon): boolean {
// Restore the Pokemon to half HP
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new PokemonHealPhase(
pokemon.getBattlerIndex(),
toDmgValue(pokemon.getMaxHp() / 2),
@ -2012,7 +2012,7 @@ export class ResetNegativeStatStageModifier extends PokemonHeldItemModifier {
}
if (statRestored) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("modifier:resetNegativeStatStageApply", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
typeName: this.type.name,
@ -2323,7 +2323,7 @@ export class PokemonLevelIncrementModifier extends ConsumablePokemonModifier {
playerPokemon.addFriendship(FRIENDSHIP_GAIN_FROM_RARE_CANDY);
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new LevelUpPhase(
globalScene.getPlayerParty().indexOf(playerPokemon),
playerPokemon.level - levelCount.value,
@ -2344,7 +2344,7 @@ export class TmModifier extends ConsumablePokemonModifier {
* @returns always `true`
*/
override apply(playerPokemon: PlayerPokemon): boolean {
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new LearnMovePhase(globalScene.getPlayerParty().indexOf(playerPokemon), this.type.moveId, LearnMoveType.TM),
);
@ -2367,7 +2367,7 @@ export class RememberMoveModifier extends ConsumablePokemonModifier {
* @returns always `true`
*/
override apply(playerPokemon: PlayerPokemon, cost?: number): boolean {
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new LearnMovePhase(
globalScene.getPlayerParty().indexOf(playerPokemon),
playerPokemon.getLearnableLevelMoves()[this.levelMoveIndex],
@ -2410,7 +2410,9 @@ export class EvolutionItemModifier extends ConsumablePokemonModifier {
}
if (matchingEvolution) {
globalScene.unshiftPhase(new EvolutionPhase(playerPokemon, matchingEvolution, playerPokemon.level - 1));
globalScene.phaseManager.unshiftPhase(
new EvolutionPhase(playerPokemon, matchingEvolution, playerPokemon.level - 1),
);
return true;
}
@ -3008,7 +3010,7 @@ export class MoneyInterestModifier extends PersistentModifier {
moneyAmount: formattedMoneyAmount,
typeName: this.type.name,
});
globalScene.queueMessage(message, undefined, true);
globalScene.phaseManager.queueMessage(message, undefined, true);
return true;
}
@ -3262,7 +3264,7 @@ export abstract class HeldItemTransferModifier extends PokemonHeldItemModifier {
}
for (const mt of transferredModifierTypes) {
globalScene.queueMessage(this.getTransferMessage(pokemon, targetPokemon, mt));
globalScene.phaseManager.queueMessage(this.getTransferMessage(pokemon, targetPokemon, mt));
}
return !!transferredModifierTypes.length;
@ -3572,7 +3574,7 @@ export class EnemyTurnHealModifier extends EnemyPersistentModifier {
*/
override apply(enemyPokemon: Pokemon): boolean {
if (!enemyPokemon.isFullHp()) {
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new PokemonHealPhase(
enemyPokemon.getBattlerIndex(),
Math.max(Math.floor(enemyPokemon.getMaxHp() / (100 / this.healPercent)) * this.stackCount, 1),
@ -3668,7 +3670,7 @@ export class EnemyStatusEffectHealChanceModifier extends EnemyPersistentModifier
*/
override apply(enemyPokemon: Pokemon): boolean {
if (enemyPokemon.status && Phaser.Math.RND.realInRange(0, 1) < this.chance * this.getStackCount()) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
getStatusEffectHealText(enemyPokemon.status.effect, getPokemonNameWithAffix(enemyPokemon)),
);
enemyPokemon.resetStatus();

311
src/phase-manager.ts Normal file
View File

@ -0,0 +1,311 @@
import { HideAbilityPhase } from "./phases/hide-ability-phase";
import { ShowAbilityPhase } from "./phases/show-ability-phase";
import { TurnInitPhase } from "./phases/turn-init-phase";
import type { Phase } from "#app/phase";
import type { default as Pokemon } from "#app/field/pokemon";
import type { Constructor } from "#app/utils/common";
import { MessagePhase } from "./phases/message-phase";
import { globalScene } from "#app/global-scene";
/**
* Manager for phases used by battle scene.
*
* *This file must not be imported or used directly. The manager is exclusively used by the battle scene and is not intended for external use.*
*/
export class PhaseManager {
/** PhaseQueue: dequeue/remove the first element to get the next phase */
public phaseQueue: Phase[] = [];
public conditionalQueue: Array<[() => boolean, Phase]> = [];
/** PhaseQueuePrepend: is a temp storage of what will be added to PhaseQueue */
private phaseQueuePrepend: Phase[] = [];
/** overrides default of inserting phases to end of phaseQueuePrepend array. Useful for inserting Phases "out of order" */
private phaseQueuePrependSpliceIndex = -1;
private nextCommandPhaseQueue: Phase[] = [];
private currentPhase: Phase | null = null;
private standbyPhase: Phase | null = null;
/* Phase Functions */
getCurrentPhase(): Phase | null {
return this.currentPhase;
}
getStandbyPhase(): Phase | null {
return this.standbyPhase;
}
/**
* Adds a phase to the conditional queue and ensures it is executed only when the specified condition is met.
*
* This method allows deferring the execution of a phase until certain conditions are met, which is useful for handling
* situations like abilities and entry hazards that depend on specific game states.
*
* @param phase - The phase to be added to the conditional queue.
* @param condition - A function that returns a boolean indicating whether the phase should be executed.
*
*/
pushConditionalPhase(phase: Phase, condition: () => boolean): void {
this.conditionalQueue.push([condition, phase]);
}
/**
* Adds a phase to nextCommandPhaseQueue, as long as boolean passed in is false
* @param phase {@linkcode Phase} the phase to add
* @param defer boolean on which queue to add to, defaults to false, and adds to phaseQueue
*/
pushPhase(phase: Phase, defer = false): void {
(!defer ? this.phaseQueue : this.nextCommandPhaseQueue).push(phase);
}
/**
* Adds Phase(s) to the end of phaseQueuePrepend, or at phaseQueuePrependSpliceIndex
* @param phases {@linkcode Phase} the phase(s) to add
*/
unshiftPhase(...phases: Phase[]): void {
if (this.phaseQueuePrependSpliceIndex === -1) {
this.phaseQueuePrepend.push(...phases);
} else {
this.phaseQueuePrepend.splice(this.phaseQueuePrependSpliceIndex, 0, ...phases);
}
}
/**
* Clears the phaseQueue
*/
clearPhaseQueue(): void {
this.phaseQueue.splice(0, this.phaseQueue.length);
}
/**
* Clears all phase-related stuff, including all phase queues, the current and standby phases, and a splice index
*/
clearAllPhases(): void {
for (const queue of [this.phaseQueue, this.phaseQueuePrepend, this.conditionalQueue, this.nextCommandPhaseQueue]) {
queue.splice(0, queue.length);
}
this.currentPhase = null;
this.standbyPhase = null;
this.clearPhaseQueueSplice();
}
/**
* Used by function unshiftPhase(), sets index to start inserting at current length instead of the end of the array, useful if phaseQueuePrepend gets longer with Phases
*/
setPhaseQueueSplice(): void {
this.phaseQueuePrependSpliceIndex = this.phaseQueuePrepend.length;
}
/**
* Resets phaseQueuePrependSpliceIndex to -1, implies that calls to unshiftPhase will insert at end of phaseQueuePrepend
*/
clearPhaseQueueSplice(): void {
this.phaseQueuePrependSpliceIndex = -1;
}
/**
* Is called by each Phase implementations "end()" by default
* We dump everything from phaseQueuePrepend to the start of of phaseQueue
* then removes first Phase and starts it
*/
shiftPhase(): void {
if (this.standbyPhase) {
this.currentPhase = this.standbyPhase;
this.standbyPhase = null;
return;
}
if (this.phaseQueuePrependSpliceIndex > -1) {
this.clearPhaseQueueSplice();
}
if (this.phaseQueuePrepend.length) {
while (this.phaseQueuePrepend.length) {
const poppedPhase = this.phaseQueuePrepend.pop();
if (poppedPhase) {
this.phaseQueue.unshift(poppedPhase);
}
}
}
if (!this.phaseQueue.length) {
this.populatePhaseQueue();
// Clear the conditionalQueue if there are no phases left in the phaseQueue
this.conditionalQueue = [];
}
this.currentPhase = this.phaseQueue.shift() ?? null;
// Check if there are any conditional phases queued
if (this.conditionalQueue?.length) {
// Retrieve the first conditional phase from the queue
const conditionalPhase = this.conditionalQueue.shift();
// Evaluate the condition associated with the phase
if (conditionalPhase?.[0]()) {
// If the condition is met, add the phase to the phase queue
this.pushPhase(conditionalPhase[1]);
} else if (conditionalPhase) {
// If the condition is not met, re-add the phase back to the front of the conditional queue
this.conditionalQueue.unshift(conditionalPhase);
} else {
console.warn("condition phase is undefined/null!", conditionalPhase);
}
}
if (this.currentPhase) {
console.log(`%cStart Phase ${this.currentPhase.constructor.name}`, "color:green;");
this.currentPhase.start();
}
}
overridePhase(phase: Phase): boolean {
if (this.standbyPhase) {
return false;
}
this.standbyPhase = this.currentPhase;
this.currentPhase = phase;
console.log(`%cStart Phase ${phase.constructor.name}`, "color:green;");
phase.start();
return true;
}
/**
* Find a specific {@linkcode Phase} in the phase queue.
*
* @param phaseFilter filter function to use to find the wanted phase
* @returns the found phase or undefined if none found
*/
findPhase<P extends Phase = Phase>(phaseFilter: (phase: P) => boolean): P | undefined {
return this.phaseQueue.find(phaseFilter) as P;
}
tryReplacePhase(phaseFilter: (phase: Phase) => boolean, phase: Phase): boolean {
const phaseIndex = this.phaseQueue.findIndex(phaseFilter);
if (phaseIndex > -1) {
this.phaseQueue[phaseIndex] = phase;
return true;
}
return false;
}
tryRemovePhase(phaseFilter: (phase: Phase) => boolean): boolean {
const phaseIndex = this.phaseQueue.findIndex(phaseFilter);
if (phaseIndex > -1) {
this.phaseQueue.splice(phaseIndex, 1);
return true;
}
return false;
}
/**
* 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 {
const phaseIndex = this.phaseQueuePrepend.findIndex(phaseFilter);
if (phaseIndex > -1) {
this.phaseQueuePrepend.splice(phaseIndex, 1);
return true;
}
return false;
}
/**
* Tries to add the input phase to index before target phase in the phaseQueue, else simply calls unshiftPhase()
* @param phase {@linkcode Phase} the phase to be added
* @param targetPhase {@linkcode Phase} the type of phase to search for in phaseQueue
* @returns boolean if a targetPhase was found and added
*/
prependToPhase(phase: Phase | Phase[], targetPhase: Constructor<Phase>): boolean {
if (!Array.isArray(phase)) {
phase = [phase];
}
const targetIndex = this.phaseQueue.findIndex(ph => ph instanceof targetPhase);
if (targetIndex !== -1) {
this.phaseQueue.splice(targetIndex, 0, ...phase);
return true;
}
this.unshiftPhase(...phase);
return false;
}
/**
* Attempt to add the input phase(s) to index after target phase in the {@linkcode phaseQueue}, else simply calls {@linkcode unshiftPhase()}
* @param phase - The phase(s) to be added
* @param targetPhase - The type of phase to search for in {@linkcode phaseQueue}
* @returns `true` if a `targetPhase` was found to append to
*/
appendToPhase(phase: Phase | Phase[], targetPhase: Constructor<Phase>): boolean {
if (!Array.isArray(phase)) {
phase = [phase];
}
const targetIndex = this.phaseQueue.findIndex(ph => ph instanceof targetPhase);
if (targetIndex !== -1 && this.phaseQueue.length > targetIndex) {
this.phaseQueue.splice(targetIndex + 1, 0, ...phase);
return true;
}
this.unshiftPhase(...phase);
return false;
}
/**
* Adds a MessagePhase, either to PhaseQueuePrepend or nextCommandPhaseQueue
* @param message - string for MessagePhase
* @param callbackDelay - optional param for MessagePhase constructor
* @param prompt - optional param for MessagePhase constructor
* @param promptDelay - optional param for MessagePhase constructor
* @param defer - Whether to allow the phase to be deferred
*
* @see {@linkcode MessagePhase} for more details on the parameters
*/
queueMessage(
message: string,
callbackDelay?: number | null,
prompt?: boolean | null,
promptDelay?: number | null,
defer?: boolean | null,
) {
const phase = new MessagePhase(message, callbackDelay, prompt, promptDelay);
if (!defer) {
// adds to the end of PhaseQueuePrepend
this.unshiftPhase(phase);
} else {
//remember that pushPhase adds it to nextCommandPhaseQueue
this.pushPhase(phase);
}
}
/**
* Queues an ability bar flyout phase
* @param pokemon The pokemon who has the ability
* @param passive Whether the ability is a passive
* @param show Whether to show or hide the bar
*/
public queueAbilityDisplay(pokemon: Pokemon, passive: boolean, show: boolean): void {
this.unshiftPhase(show ? new ShowAbilityPhase(pokemon.getBattlerIndex(), passive) : new HideAbilityPhase());
this.clearPhaseQueueSplice();
}
/**
* Hides the ability bar if it is currently visible
*/
public hideAbilityBar(): void {
if (globalScene.abilityBar.isVisible()) {
this.unshiftPhase(new HideAbilityPhase());
}
}
/**
* Moves everything from nextCommandPhaseQueue to phaseQueue (keeping order)
*/
private populatePhaseQueue(): void {
if (this.nextCommandPhaseQueue.length) {
this.phaseQueue.push(...this.nextCommandPhaseQueue);
this.nextCommandPhaseQueue.splice(0, this.nextCommandPhaseQueue.length);
}
this.phaseQueue.push(new TurnInitPhase());
}
}

View File

@ -5,7 +5,7 @@ export abstract class Phase {
start() {}
end() {
globalScene.shiftPhase();
globalScene.phaseManager.shiftPhase();
}
/**

View File

@ -257,7 +257,7 @@ export class AttemptCapturePhase extends PokemonPhase {
null,
() => {
const end = () => {
globalScene.unshiftPhase(new VictoryPhase(this.battlerIndex));
globalScene.phaseManager.unshiftPhase(new VictoryPhase(this.battlerIndex));
globalScene.pokemonInfoContainer.hide();
this.removePb();
this.end();

View File

@ -39,7 +39,7 @@ export class AttemptRunPhase extends PokemonPhase {
enemyField.forEach(enemyPokemon => applyPreLeaveFieldAbAttrs(PreLeaveFieldAbAttr, enemyPokemon));
globalScene.playSound("se/flee");
globalScene.queueMessage(i18next.t("battle:runAwaySuccess"), null, true, 500);
globalScene.phaseManager.queueMessage(i18next.t("battle:runAwaySuccess"), null, true, 500);
globalScene.tweens.add({
targets: [globalScene.arenaEnemy, enemyField].flat(),
@ -60,16 +60,16 @@ export class AttemptRunPhase extends PokemonPhase {
enemyPokemon.trySetStatus(StatusEffect.FAINT);
});
globalScene.pushPhase(new BattleEndPhase(false));
globalScene.phaseManager.pushPhase(new BattleEndPhase(false));
if (globalScene.gameMode.hasRandomBiomes || globalScene.isNewBiome()) {
globalScene.pushPhase(new SelectBiomePhase());
globalScene.phaseManager.pushPhase(new SelectBiomePhase());
}
globalScene.pushPhase(new NewBattlePhase());
globalScene.phaseManager.pushPhase(new NewBattlePhase());
} else {
playerPokemon.turnData.failedRunAway = true;
globalScene.queueMessage(i18next.t("battle:runAwayCannotEscape"), null, true, 500);
globalScene.phaseManager.queueMessage(i18next.t("battle:runAwayCannotEscape"), null, true, 500);
}
this.end();

View File

@ -19,7 +19,7 @@ export class BattleEndPhase extends BattlePhase {
super.start();
// cull any extra `BattleEnd` phases from the queue.
globalScene.phaseQueue = globalScene.phaseQueue.filter(phase => {
globalScene.phaseManager.phaseQueue = globalScene.phaseManager.phaseQueue.filter(phase => {
if (phase.is("BattleEndPhase")) {
this.isVictory ||= phase.isVictory;
return false;
@ -28,7 +28,7 @@ export class BattleEndPhase extends BattlePhase {
});
// `phaseQueuePrepend` is private, so we have to use this inefficient loop.
while (
globalScene.tryRemoveUnshiftedPhase(phase => {
globalScene.phaseManager.tryRemoveUnshiftedPhase(phase => {
if (phase.is("BattleEndPhase")) {
this.isVictory ||= phase.isVictory;
return true;
@ -55,8 +55,8 @@ export class BattleEndPhase extends BattlePhase {
// Endless graceful end
if (globalScene.gameMode.isEndless && globalScene.currentBattle.waveIndex >= 5850) {
globalScene.clearPhaseQueue();
globalScene.unshiftPhase(new GameOverPhase(true));
globalScene.phaseManager.clearPhaseQueue();
globalScene.phaseManager.unshiftPhase(new GameOverPhase(true));
}
for (const pokemon of globalScene.getField()) {

View File

@ -50,7 +50,7 @@ export class BerryPhase extends FieldPhase {
const cancelled = new BooleanHolder(false);
pokemon.getOpponents().forEach(opp => applyAbAttrs(PreventBerryUseAbAttr, opp, cancelled));
if (cancelled.value) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("abilityTriggers:preventBerryUse", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -58,7 +58,7 @@ export class BerryPhase extends FieldPhase {
return;
}
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new CommonAnimPhase(pokemon.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.USE_ITEM),
);

View File

@ -15,7 +15,7 @@ export class CheckStatusEffectPhase extends Phase {
const field = globalScene.getField();
for (const o of this.order) {
if (field[o].status?.isPostTurn()) {
globalScene.unshiftPhase(new PostTurnStatusEffectPhase(o));
globalScene.phaseManager.unshiftPhase(new PostTurnStatusEffectPhase(o));
}
}
this.end();

View File

@ -35,7 +35,7 @@ export class CheckSwitchPhase extends BattlePhase {
// ...if the checked Pokemon is somehow not on the field
if (globalScene.field.getAll().indexOf(pokemon) === -1) {
globalScene.unshiftPhase(new SummonMissingPhase(this.fieldIndex));
globalScene.phaseManager.unshiftPhase(new SummonMissingPhase(this.fieldIndex));
return super.end();
}
@ -68,7 +68,9 @@ export class CheckSwitchPhase extends BattlePhase {
UiMode.CONFIRM,
() => {
globalScene.ui.setMode(UiMode.MESSAGE);
globalScene.unshiftPhase(new SwitchPhase(SwitchType.INITIAL_SWITCH, this.fieldIndex, false, true));
globalScene.phaseManager.unshiftPhase(
new SwitchPhase(SwitchType.INITIAL_SWITCH, this.fieldIndex, false, true),
);
this.end();
},
() => {

View File

@ -192,7 +192,7 @@ export class CommandPhase extends FieldPhase {
}
console.log(moveTargets, getPokemonNameWithAffix(playerPokemon));
if (moveTargets.targets.length > 1 && moveTargets.multiple) {
globalScene.unshiftPhase(new SelectTargetPhase(this.fieldIndex));
globalScene.phaseManager.unshiftPhase(new SelectTargetPhase(this.fieldIndex));
}
if (turnCommand.move && (moveTargets.targets.length <= 1 || moveTargets.multiple)) {
turnCommand.move.targets = moveTargets.targets;
@ -203,7 +203,7 @@ export class CommandPhase extends FieldPhase {
) {
turnCommand.move.targets = playerPokemon.getMoveQueue()[0].targets;
} else {
globalScene.unshiftPhase(new SelectTargetPhase(this.fieldIndex));
globalScene.phaseManager.unshiftPhase(new SelectTargetPhase(this.fieldIndex));
}
globalScene.currentBattle.preTurnCommands[this.fieldIndex] = preTurnCommand;
globalScene.currentBattle.turnCommands[this.fieldIndex] = turnCommand;
@ -457,8 +457,8 @@ export class CommandPhase extends FieldPhase {
cancel() {
if (this.fieldIndex) {
globalScene.unshiftPhase(new CommandPhase(0));
globalScene.unshiftPhase(new CommandPhase(1));
globalScene.phaseManager.unshiftPhase(new CommandPhase(0));
globalScene.phaseManager.unshiftPhase(new CommandPhase(1));
this.end();
}
}

View File

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

View File

@ -62,12 +62,12 @@ export class EggLapsePhase extends Phase {
true,
);
} else if (eggsToHatchCount >= this.minEggsToSkip && globalScene.eggSkipPreference === 2) {
globalScene.queueMessage(i18next.t("battle:eggHatching"));
globalScene.phaseManager.queueMessage(i18next.t("battle:eggHatching"));
this.hatchEggsSkipped(eggsToHatch);
this.showSummary();
} else {
// regular hatches, no summary
globalScene.queueMessage(i18next.t("battle:eggHatching"));
globalScene.phaseManager.queueMessage(i18next.t("battle:eggHatching"));
this.hatchEggsRegular(eggsToHatch);
this.end();
}
@ -83,7 +83,7 @@ export class EggLapsePhase extends Phase {
hatchEggsRegular(eggsToHatch: Egg[]) {
let eggsToHatchCount: number = eggsToHatch.length;
for (const egg of eggsToHatch) {
globalScene.unshiftPhase(new EggHatchPhase(this, egg, eggsToHatchCount));
globalScene.phaseManager.unshiftPhase(new EggHatchPhase(this, egg, eggsToHatchCount));
eggsToHatchCount--;
}
}
@ -99,7 +99,7 @@ export class EggLapsePhase extends Phase {
}
showSummary() {
globalScene.unshiftPhase(new EggSummaryPhase(this.eggHatchData));
globalScene.phaseManager.unshiftPhase(new EggSummaryPhase(this.eggHatchData));
this.end();
}

View File

@ -68,7 +68,7 @@ export class EncounterPhase extends BattlePhase {
// Failsafe if players somehow skip floor 200 in classic mode
if (globalScene.gameMode.isClassic && globalScene.currentBattle.waveIndex > 200) {
globalScene.unshiftPhase(new GameOverPhase());
globalScene.phaseManager.unshiftPhase(new GameOverPhase());
}
const loadEnemyAssets: Promise<void>[] = [];
@ -438,9 +438,9 @@ export class EncounterPhase extends BattlePhase {
const doTrainerSummon = () => {
this.hideEnemyTrainer();
const availablePartyMembers = globalScene.getEnemyParty().filter(p => !p.isFainted()).length;
globalScene.unshiftPhase(new SummonPhase(0, false));
globalScene.phaseManager.unshiftPhase(new SummonPhase(0, false));
if (globalScene.currentBattle.double && availablePartyMembers > 1) {
globalScene.unshiftPhase(new SummonPhase(1, false));
globalScene.phaseManager.unshiftPhase(new SummonPhase(1, false));
}
this.end();
};
@ -496,7 +496,7 @@ export class EncounterPhase extends BattlePhase {
globalScene.ui.clearText();
globalScene.ui.getMessageHandler().hideNameText();
globalScene.unshiftPhase(new MysteryEncounterPhase());
globalScene.phaseManager.unshiftPhase(new MysteryEncounterPhase());
this.end();
};
@ -554,7 +554,7 @@ export class EncounterPhase extends BattlePhase {
enemyField.forEach((enemyPokemon, e) => {
if (enemyPokemon.isShiny(true)) {
globalScene.unshiftPhase(new ShinySparklePhase(BattlerIndex.ENEMY + e));
globalScene.phaseManager.unshiftPhase(new ShinySparklePhase(BattlerIndex.ENEMY + e));
}
/** This sets Eternatus' held item to be untransferrable, preventing it from being stolen */
if (
@ -576,7 +576,7 @@ export class EncounterPhase extends BattlePhase {
if (![BattleType.TRAINER, BattleType.MYSTERY_ENCOUNTER].includes(globalScene.currentBattle.battleType)) {
enemyField.map(p =>
globalScene.pushConditionalPhase(new PostSummonPhase(p.getBattlerIndex()), () => {
globalScene.phaseManager.pushConditionalPhase(new PostSummonPhase(p.getBattlerIndex()), () => {
// if there is not a player party, we can't continue
if (!globalScene.getPlayerParty().length) {
return false;
@ -594,7 +594,7 @@ export class EncounterPhase extends BattlePhase {
);
const ivScannerModifier = globalScene.findModifier(m => m instanceof IvScannerModifier);
if (ivScannerModifier) {
enemyField.map(p => globalScene.pushPhase(new ScanIvsPhase(p.getBattlerIndex())));
enemyField.map(p => globalScene.phaseManager.pushPhase(new ScanIvsPhase(p.getBattlerIndex())));
}
}
@ -602,21 +602,21 @@ export class EncounterPhase extends BattlePhase {
const availablePartyMembers = globalScene.getPokemonAllowedInBattle();
if (!availablePartyMembers[0].isOnField()) {
globalScene.pushPhase(new SummonPhase(0));
globalScene.phaseManager.pushPhase(new SummonPhase(0));
}
if (globalScene.currentBattle.double) {
if (availablePartyMembers.length > 1) {
globalScene.pushPhase(new ToggleDoublePositionPhase(true));
globalScene.phaseManager.pushPhase(new ToggleDoublePositionPhase(true));
if (!availablePartyMembers[1].isOnField()) {
globalScene.pushPhase(new SummonPhase(1));
globalScene.phaseManager.pushPhase(new SummonPhase(1));
}
}
} else {
if (availablePartyMembers.length > 1 && availablePartyMembers[1].isOnField()) {
globalScene.pushPhase(new ReturnPhase(1));
globalScene.phaseManager.pushPhase(new ReturnPhase(1));
}
globalScene.pushPhase(new ToggleDoublePositionPhase(false));
globalScene.phaseManager.pushPhase(new ToggleDoublePositionPhase(false));
}
if (
@ -625,9 +625,9 @@ export class EncounterPhase extends BattlePhase {
) {
const minPartySize = globalScene.currentBattle.double ? 2 : 1;
if (availablePartyMembers.length > minPartySize) {
globalScene.pushPhase(new CheckSwitchPhase(0, globalScene.currentBattle.double));
globalScene.phaseManager.pushPhase(new CheckSwitchPhase(0, globalScene.currentBattle.double));
if (globalScene.currentBattle.double) {
globalScene.pushPhase(new CheckSwitchPhase(1, globalScene.currentBattle.double));
globalScene.phaseManager.pushPhase(new CheckSwitchPhase(1, globalScene.currentBattle.double));
}
}
}

View File

@ -262,7 +262,7 @@ export class EvolutionPhase extends Phase {
SoundFade.fadeOut(globalScene, this.evolutionBgm, 100);
globalScene.unshiftPhase(new EndEvolutionPhase());
globalScene.phaseManager.unshiftPhase(new EndEvolutionPhase());
globalScene.ui.showText(
i18next.t("menu:stoppedEvolving", {
@ -355,9 +355,11 @@ export class EvolutionPhase extends Phase {
.getLevelMoves(this.lastLevel + 1, true, false, false, learnSituation)
.filter(lm => lm[0] === EVOLVE_MOVE);
for (const lm of levelMoves) {
globalScene.unshiftPhase(new LearnMovePhase(globalScene.getPlayerParty().indexOf(this.pokemon), lm[1]));
globalScene.phaseManager.unshiftPhase(
new LearnMovePhase(globalScene.getPlayerParty().indexOf(this.pokemon), lm[1]),
);
}
globalScene.unshiftPhase(new EndEvolutionPhase());
globalScene.phaseManager.unshiftPhase(new EndEvolutionPhase());
globalScene.playSound("se/shine");
this.doSpray();

View File

@ -34,7 +34,7 @@ export class ExpPhase extends PlayerPartyMemberPokemonPhase {
pokemon.addExp(exp.value);
const newLevel = pokemon.level;
if (newLevel > lastLevel) {
globalScene.unshiftPhase(new LevelUpPhase(this.partyMemberIndex, lastLevel, newLevel));
globalScene.phaseManager.unshiftPhase(new LevelUpPhase(this.partyMemberIndex, lastLevel, newLevel));
}
pokemon.updateInfo().then(() => this.end());
},

View File

@ -115,7 +115,7 @@ export class FaintPhase extends PokemonPhase {
});
}
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battle:fainted", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}),
@ -166,7 +166,7 @@ export class FaintPhase extends PokemonPhase {
const legalPlayerPartyPokemon = legalPlayerPokemon.filter(p => !p.isActive(true));
if (!legalPlayerPokemon.length) {
/** If the player doesn't have any legal Pokemon, end the game */
globalScene.unshiftPhase(new GameOverPhase());
globalScene.phaseManager.unshiftPhase(new GameOverPhase());
} else if (
globalScene.currentBattle.double &&
legalPlayerPokemon.length === 1 &&
@ -176,23 +176,25 @@ export class FaintPhase extends PokemonPhase {
* If the player has exactly one Pokemon in total at this point in a double battle, and that Pokemon
* is already on the field, unshift a phase that moves that Pokemon to center position.
*/
globalScene.unshiftPhase(new ToggleDoublePositionPhase(true));
globalScene.phaseManager.unshiftPhase(new ToggleDoublePositionPhase(true));
} else if (legalPlayerPartyPokemon.length > 0) {
/**
* If previous conditions weren't met, and the player has at least 1 legal Pokemon off the field,
* push a phase that prompts the player to summon a Pokemon from their party.
*/
globalScene.pushPhase(new SwitchPhase(SwitchType.SWITCH, this.fieldIndex, true, false));
globalScene.phaseManager.pushPhase(new SwitchPhase(SwitchType.SWITCH, this.fieldIndex, true, false));
}
} else {
globalScene.unshiftPhase(new VictoryPhase(this.battlerIndex));
globalScene.phaseManager.unshiftPhase(new VictoryPhase(this.battlerIndex));
if ([BattleType.TRAINER, BattleType.MYSTERY_ENCOUNTER].includes(globalScene.currentBattle.battleType)) {
const hasReservePartyMember = !!globalScene
.getEnemyParty()
.filter(p => p.isActive() && !p.isOnField() && p.trainerSlot === (pokemon as EnemyPokemon).trainerSlot)
.length;
if (hasReservePartyMember) {
globalScene.pushPhase(new SwitchSummonPhase(SwitchType.SWITCH, this.fieldIndex, -1, false, false));
globalScene.phaseManager.pushPhase(
new SwitchSummonPhase(SwitchType.SWITCH, this.fieldIndex, -1, false, false),
);
}
}
}
@ -247,7 +249,7 @@ export class FaintPhase extends PokemonPhase {
} else {
// Final boss' HP threshold has been bypassed; cancel faint and force check for 2nd phase
enemy.hp++;
globalScene.unshiftPhase(new DamageAnimPhase(enemy.getBattlerIndex(), 0, HitResult.INDIRECT));
globalScene.phaseManager.unshiftPhase(new DamageAnimPhase(enemy.getBattlerIndex(), 0, HitResult.INDIRECT));
this.end();
}
return true;

View File

@ -100,7 +100,7 @@ export class FormChangePhase extends EvolutionPhase {
globalScene.time.delayedCall(900, () => {
this.pokemon.changeForm(this.formChange).then(() => {
if (!this.modal) {
globalScene.unshiftPhase(new EndEvolutionPhase());
globalScene.phaseManager.unshiftPhase(new EndEvolutionPhase());
}
globalScene.playSound("se/shine");

View File

@ -47,7 +47,7 @@ export class GameOverPhase extends BattlePhase {
start() {
super.start();
globalScene.hideAbilityBar();
globalScene.phaseManager.hideAbilityBar();
// Failsafe if players somehow skip floor 200 in classic mode
if (globalScene.gameMode.isClassic && globalScene.currentBattle.waveIndex > 200) {
@ -84,23 +84,23 @@ export class GameOverPhase extends BattlePhase {
() => {
globalScene.ui.fadeOut(1250).then(() => {
globalScene.reset();
globalScene.clearPhaseQueue();
globalScene.phaseManager.clearPhaseQueue();
globalScene.gameData.loadSession(globalScene.sessionSlotId).then(() => {
globalScene.pushPhase(new EncounterPhase(true));
globalScene.phaseManager.pushPhase(new EncounterPhase(true));
const availablePartyMembers = globalScene.getPokemonAllowedInBattle().length;
globalScene.pushPhase(new SummonPhase(0));
globalScene.phaseManager.pushPhase(new SummonPhase(0));
if (globalScene.currentBattle.double && availablePartyMembers > 1) {
globalScene.pushPhase(new SummonPhase(1));
globalScene.phaseManager.pushPhase(new SummonPhase(1));
}
if (
globalScene.currentBattle.waveIndex > 1 &&
globalScene.currentBattle.battleType !== BattleType.TRAINER
) {
globalScene.pushPhase(new CheckSwitchPhase(0, globalScene.currentBattle.double));
globalScene.phaseManager.pushPhase(new CheckSwitchPhase(0, globalScene.currentBattle.double));
if (globalScene.currentBattle.double && availablePartyMembers > 1) {
globalScene.pushPhase(new CheckSwitchPhase(1, globalScene.currentBattle.double));
globalScene.phaseManager.pushPhase(new CheckSwitchPhase(1, globalScene.currentBattle.double));
}
}
@ -148,7 +148,7 @@ export class GameOverPhase extends BattlePhase {
globalScene.ui.fadeOut(fadeDuration).then(() => {
activeBattlers.map(a => a.setVisible(false));
globalScene.setFieldScale(1, true);
globalScene.clearPhaseQueue();
globalScene.phaseManager.clearPhaseQueue();
globalScene.ui.clearText();
if (this.isVictory && globalScene.gameMode.isChallenge) {
@ -160,15 +160,17 @@ export class GameOverPhase extends BattlePhase {
this.handleUnlocks();
for (const species of this.firstRibbons) {
globalScene.unshiftPhase(new RibbonModifierRewardPhase(modifierTypes.VOUCHER_PLUS, species));
globalScene.phaseManager.unshiftPhase(
new RibbonModifierRewardPhase(modifierTypes.VOUCHER_PLUS, species),
);
}
if (!firstClear) {
globalScene.unshiftPhase(new GameOverModifierRewardPhase(modifierTypes.VOUCHER_PREMIUM));
globalScene.phaseManager.unshiftPhase(new GameOverModifierRewardPhase(modifierTypes.VOUCHER_PREMIUM));
}
}
this.getRunHistoryEntry().then(runHistoryEntry => {
globalScene.gameData.saveRunHistory(runHistoryEntry, this.isVictory);
globalScene.pushPhase(new PostGameOverPhase(endCardPhase));
globalScene.phaseManager.pushPhase(new PostGameOverPhase(endCardPhase));
this.end();
});
};
@ -198,7 +200,7 @@ export class GameOverPhase extends BattlePhase {
globalScene.ui.fadeOut(500).then(() => {
globalScene.charSprite.hide().then(() => {
const endCardPhase = new EndCardPhase();
globalScene.unshiftPhase(endCardPhase);
globalScene.phaseManager.unshiftPhase(endCardPhase);
clear(endCardPhase);
});
});
@ -208,7 +210,7 @@ export class GameOverPhase extends BattlePhase {
});
} else {
const endCardPhase = new EndCardPhase();
globalScene.unshiftPhase(endCardPhase);
globalScene.phaseManager.unshiftPhase(endCardPhase);
clear(endCardPhase);
}
} else {
@ -230,9 +232,9 @@ export class GameOverPhase extends BattlePhase {
})
.then(success => doGameOver(!globalScene.gameMode.isDaily || !!success))
.catch(_err => {
globalScene.clearPhaseQueue();
globalScene.clearPhaseQueueSplice();
globalScene.unshiftPhase(new MessagePhase(i18next.t("menu:serverCommunicationFailed"), 2500));
globalScene.phaseManager.clearPhaseQueue();
globalScene.phaseManager.clearPhaseQueueSplice();
globalScene.phaseManager.unshiftPhase(new MessagePhase(i18next.t("menu:serverCommunicationFailed"), 2500));
// force the game to reload after 2 seconds.
setTimeout(() => {
window.location.reload();
@ -251,22 +253,22 @@ export class GameOverPhase extends BattlePhase {
handleUnlocks(): void {
if (this.isVictory && globalScene.gameMode.isClassic) {
if (!globalScene.gameData.unlocks[Unlockables.ENDLESS_MODE]) {
globalScene.unshiftPhase(new UnlockPhase(Unlockables.ENDLESS_MODE));
globalScene.phaseManager.unshiftPhase(new UnlockPhase(Unlockables.ENDLESS_MODE));
}
if (
globalScene.getPlayerParty().filter(p => p.fusionSpecies).length &&
!globalScene.gameData.unlocks[Unlockables.SPLICED_ENDLESS_MODE]
) {
globalScene.unshiftPhase(new UnlockPhase(Unlockables.SPLICED_ENDLESS_MODE));
globalScene.phaseManager.unshiftPhase(new UnlockPhase(Unlockables.SPLICED_ENDLESS_MODE));
}
if (!globalScene.gameData.unlocks[Unlockables.MINI_BLACK_HOLE]) {
globalScene.unshiftPhase(new UnlockPhase(Unlockables.MINI_BLACK_HOLE));
globalScene.phaseManager.unshiftPhase(new UnlockPhase(Unlockables.MINI_BLACK_HOLE));
}
if (
!globalScene.gameData.unlocks[Unlockables.EVIOLITE] &&
globalScene.getPlayerParty().some(p => p.getSpeciesForm(true).speciesId in pokemonEvolutions)
) {
globalScene.unshiftPhase(new UnlockPhase(Unlockables.EVIOLITE));
globalScene.phaseManager.unshiftPhase(new UnlockPhase(Unlockables.EVIOLITE));
}
}
}

View File

@ -195,7 +195,7 @@ export class LearnMovePhase extends PlayerPartyMemberPokemonPhase {
pokemon.usedTMs = [];
}
pokemon.usedTMs.push(this.moveId);
globalScene.tryRemovePhase(phase => phase.is("SelectModifierPhase"));
globalScene.phaseManager.tryRemovePhase(phase => phase.is("SelectModifierPhase"));
} else if (this.learnMoveType === LearnMoveType.MEMORY) {
if (this.cost !== -1) {
if (!Overrides.WAIVE_ROLL_FEE_OVERRIDE) {
@ -205,7 +205,7 @@ export class LearnMovePhase extends PlayerPartyMemberPokemonPhase {
}
globalScene.playSound("se/buy");
} else {
globalScene.tryRemovePhase(phase => phase.is("SelectModifierPhase"));
globalScene.phaseManager.tryRemovePhase(phase => phase.is("SelectModifierPhase"));
}
}
pokemon.setMove(index, this.moveId);

View File

@ -66,14 +66,14 @@ export class LevelUpPhase extends PlayerPartyMemberPokemonPhase {
// this feels like an unnecessary optimization
const levelMoves = this.getPokemon().getLevelMoves(this.lastLevel + 1);
for (const lm of levelMoves) {
globalScene.unshiftPhase(new LearnMovePhase(this.partyMemberIndex, lm[1]));
globalScene.phaseManager.unshiftPhase(new LearnMovePhase(this.partyMemberIndex, lm[1]));
}
}
if (!this.pokemon.pauseEvolutions) {
const evolution = this.pokemon.getEvolution();
if (evolution) {
this.pokemon.breakIllusion();
globalScene.unshiftPhase(new EvolutionPhase(this.pokemon, evolution, this.lastLevel));
globalScene.phaseManager.unshiftPhase(new EvolutionPhase(this.pokemon, evolution, this.lastLevel));
}
}
return super.end();

View File

@ -70,7 +70,7 @@ export class LoginPhase extends Phase {
});
},
() => {
globalScene.unshiftPhase(new LoginPhase(false));
globalScene.phaseManager.unshiftPhase(new LoginPhase(false));
this.end();
},
],
@ -94,7 +94,7 @@ export class LoginPhase extends Phase {
removeCookie(sessionIdKey);
globalScene.reset(true, true);
} else {
globalScene.unshiftPhase(new UnavailablePhase());
globalScene.phaseManager.unshiftPhase(new UnavailablePhase());
super.end();
}
return null;
@ -114,7 +114,7 @@ export class LoginPhase extends Phase {
globalScene.ui.setMode(UiMode.MESSAGE);
if (!globalScene.gameData.gender) {
globalScene.unshiftPhase(new SelectGenderPhase());
globalScene.phaseManager.unshiftPhase(new SelectGenderPhase());
}
handleTutorial(Tutorial.Intro).then(() => super.end());

View File

@ -44,7 +44,7 @@ export class MessagePhase extends Phase {
page0 = page0.split(repname[p]).join(pokename[p]);
page1 = page1.split(repname[p]).join(pokename[p]);
}
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new MessagePhase(page1, this.callbackDelay, this.prompt, this.promptDelay, this.speaker),
);
this.text = page0.trim();

View File

@ -62,9 +62,9 @@ export class MoveChargePhase extends PokemonPhase {
if (instantCharge.value) {
// this MoveEndPhase will be duplicated by the queued MovePhase if not removed
globalScene.tryRemovePhase(phase => phase.is("MoveEndPhase") && phase.getPokemon() === user);
globalScene.phaseManager.tryRemovePhase(phase => phase.is("MoveEndPhase") && phase.getPokemon() === user);
// queue a new MovePhase for this move's attack phase
globalScene.unshiftPhase(new MovePhase(user, [this.targetIndex], this.move, false));
globalScene.phaseManager.unshiftPhase(new MovePhase(user, [this.targetIndex], this.move, false));
} else {
user.getMoveQueue().push({ move: move.id, targets: [this.targetIndex] });
}

View File

@ -221,7 +221,7 @@ export class MoveEffectPhase extends PokemonPhase {
break;
// biome-ignore lint/suspicious/noFallthroughSwitchClause: The fallthrough is intentional
case HitCheckResult.NO_EFFECT:
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t(this.move.id === MoveId.SHEER_COLD ? "battle:hitResultImmune" : "battle:hitResultNoEffect", {
pokemonName: getPokemonNameWithAffix(target),
}),
@ -232,7 +232,7 @@ export class MoveEffectPhase extends PokemonPhase {
applyMoveAttrs(NoEffectAttr, user, target, this.move);
break;
case HitCheckResult.MISS:
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battle:attackMissed", { pokemonNameWithAffix: getPokemonNameWithAffix(target) }),
);
applyMoveAttrs(MissEffectAttr, user, target, this.move);
@ -384,7 +384,7 @@ export class MoveEffectPhase extends PokemonPhase {
}
if (this.queuedPhases.length) {
globalScene.appendToPhase(this.queuedPhases, MoveEndPhase);
globalScene.phaseManager.appendToPhase(this.queuedPhases, MoveEndPhase);
}
const moveType = user.getMoveType(this.move, true);
if (this.move.category !== MoveCategory.STATUS && !user.stellarTypesBoosted.includes(moveType)) {
@ -410,14 +410,14 @@ export class MoveEffectPhase extends PokemonPhase {
*/
if (user) {
if (user.turnData.hitsLeft && --user.turnData.hitsLeft >= 1 && this.getFirstTarget()?.isActive()) {
globalScene.unshiftPhase(this.getNewHitPhase());
globalScene.phaseManager.unshiftPhase(this.getNewHitPhase());
} else {
// Queue message for number of hits made by multi-move
// If multi-hit attack only hits once, still want to render a message
const hitsTotal = user.turnData.hitCount - Math.max(user.turnData.hitsLeft, 0);
if (hitsTotal > 1 || (user.turnData.hitsLeft && user.turnData.hitsLeft > 0)) {
// If there are multiple hits, or if there are hits of the multi-hit move left
globalScene.queueMessage(i18next.t("battle:attackHitsCount", { count: hitsTotal }));
globalScene.phaseManager.queueMessage(i18next.t("battle:attackHitsCount", { count: hitsTotal }));
}
globalScene.applyModifiers(HitHealModifier, this.player, user);
this.getTargets().forEach(target => (target.turnData.moveEffectiveness = null));
@ -858,7 +858,7 @@ export class MoveEffectPhase extends PokemonPhase {
});
if (isCritical) {
globalScene.queueMessage(i18next.t("battle:hitResultCriticalHit"));
globalScene.phaseManager.queueMessage(i18next.t("battle:hitResultCriticalHit"));
}
if (damage <= 0) {
@ -901,9 +901,9 @@ export class MoveEffectPhase extends PokemonPhase {
*/
protected onFaintTarget(user: Pokemon, target: Pokemon): void {
// set splice index here, so future scene queues happen before FaintedPhase
globalScene.setPhaseQueueSplice();
globalScene.phaseManager.setPhaseQueueSplice();
globalScene.unshiftPhase(new FaintPhase(target.getBattlerIndex(), false, user));
globalScene.phaseManager.unshiftPhase(new FaintPhase(target.getBattlerIndex(), false, user));
target.destroySubstitute();
target.lapseTag(BattlerTagType.COMMANDED);
@ -936,7 +936,7 @@ export class MoveEffectPhase extends PokemonPhase {
break;
}
if (msg) {
globalScene.queueMessage(msg);
globalScene.phaseManager.queueMessage(msg);
}
}

View File

@ -268,10 +268,10 @@ export class MovePhase extends BattlePhase {
if (activated) {
this.cancel();
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
getStatusEffectActivationText(this.pokemon.status.effect, getPokemonNameWithAffix(this.pokemon)),
);
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new CommonAnimPhase(
this.pokemon.getBattlerIndex(),
undefined,
@ -279,7 +279,7 @@ export class MovePhase extends BattlePhase {
),
);
} else if (healed) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
getStatusEffectHealText(this.pokemon.status.effect, getPokemonNameWithAffix(this.pokemon)),
);
this.pokemon.resetStatus();
@ -407,7 +407,7 @@ export class MovePhase extends BattlePhase {
if (success) {
const move = this.move.getMove();
applyPreAttackAbAttrs(PokemonTypeChangeAbAttr, this.pokemon, null, move);
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new MoveEffectPhase(this.pokemon.getBattlerIndex(), this.targets, move, this.reflected, this.move.virtual),
);
} else {
@ -457,7 +457,9 @@ export class MovePhase extends BattlePhase {
applyPreAttackAbAttrs(PokemonTypeChangeAbAttr, this.pokemon, null, this.move.getMove());
this.showMoveText();
globalScene.unshiftPhase(new MoveChargePhase(this.pokemon.getBattlerIndex(), this.targets[0], this.move));
globalScene.phaseManager.unshiftPhase(
new MoveChargePhase(this.pokemon.getBattlerIndex(), this.targets[0], this.move),
);
} else {
this.pokemon.pushMoveHistory({
move: this.move.moveId,
@ -479,7 +481,7 @@ export class MovePhase extends BattlePhase {
* Queues a {@linkcode MoveEndPhase} and then ends the phase
*/
public end(): void {
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new MoveEndPhase(this.pokemon.getBattlerIndex(), this.getActiveTargetPokemon(), this.followUp),
);
@ -545,12 +547,12 @@ export class MovePhase extends BattlePhase {
if (this.pokemon.hasAbilityWithAttr(BlockRedirectAbAttr)) {
redirectTarget.value = currentTarget;
// TODO: Ability displays should be handled by the ability
globalScene.queueAbilityDisplay(
globalScene.phaseManager.queueAbilityDisplay(
this.pokemon,
this.pokemon.getPassiveAbility().hasAttr(BlockRedirectAbAttr),
true,
);
globalScene.queueAbilityDisplay(
globalScene.phaseManager.queueAbilityDisplay(
this.pokemon,
this.pokemon.getPassiveAbility().hasAttr(BlockRedirectAbAttr),
false,
@ -649,7 +651,7 @@ export class MovePhase extends BattlePhase {
return;
}
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t(this.reflected ? "battle:magicCoatActivated" : "battle:useMove", {
pokemonNameWithAffix: getPokemonNameWithAffix(this.pokemon),
moveName: this.move.getName(),
@ -660,6 +662,6 @@ export class MovePhase extends BattlePhase {
}
public showFailedText(failedText: string = i18next.t("battle:attackFailed")): void {
globalScene.queueMessage(failedText);
globalScene.phaseManager.queueMessage(failedText);
}
}

View File

@ -58,8 +58,8 @@ export class MysteryEncounterPhase extends Phase {
super.start();
// Clears out queued phases that are part of standard battle
globalScene.clearPhaseQueue();
globalScene.clearPhaseQueueSplice();
globalScene.phaseManager.clearPhaseQueue();
globalScene.phaseManager.clearPhaseQueueSplice();
const encounter = globalScene.currentBattle.mysteryEncounter!;
encounter.updateSeedOffset();
@ -124,7 +124,7 @@ export class MysteryEncounterPhase extends Phase {
*/
continueEncounter() {
const endDialogueAndContinueEncounter = () => {
globalScene.pushPhase(new MysteryEncounterOptionSelectedPhase());
globalScene.phaseManager.pushPhase(new MysteryEncounterOptionSelectedPhase());
this.end();
};
@ -247,8 +247,8 @@ export class MysteryEncounterBattleStartCleanupPhase extends Phase {
});
// Remove any status tick phases
while (globalScene.findPhase(p => p.is("PostTurnStatusEffectPhase"))) {
globalScene.tryRemovePhase(p => p.is("PostTurnStatusEffectPhase"));
while (globalScene.phaseManager.findPhase(p => p.is("PostTurnStatusEffectPhase"))) {
globalScene.phaseManager.tryRemovePhase(p => p.is("PostTurnStatusEffectPhase"));
}
// The total number of Pokemon in the player's party that can legally fight
@ -256,7 +256,7 @@ export class MysteryEncounterBattleStartCleanupPhase extends Phase {
// The total number of legal player Pokemon that aren't currently on the field
const legalPlayerPartyPokemon = legalPlayerPokemon.filter(p => !p.isActive(true));
if (!legalPlayerPokemon.length) {
globalScene.unshiftPhase(new GameOverPhase());
globalScene.phaseManager.unshiftPhase(new GameOverPhase());
return this.end();
}
@ -265,13 +265,13 @@ export class MysteryEncounterBattleStartCleanupPhase extends Phase {
const playerField = globalScene.getPlayerField();
playerField.forEach((pokemon, i) => {
if (!pokemon.isAllowedInBattle() && legalPlayerPartyPokemon.length > i) {
globalScene.unshiftPhase(new SwitchPhase(SwitchType.SWITCH, i, true, false));
globalScene.phaseManager.unshiftPhase(new SwitchPhase(SwitchType.SWITCH, i, true, false));
}
});
// THEN, if is a double battle, and player only has 1 summoned pokemon, center pokemon on field
if (globalScene.currentBattle.double && legalPlayerPokemon.length === 1 && legalPlayerPartyPokemon.length === 0) {
globalScene.unshiftPhase(new ToggleDoublePositionPhase(true));
globalScene.phaseManager.unshiftPhase(new ToggleDoublePositionPhase(true));
}
this.end();
@ -348,9 +348,9 @@ export class MysteryEncounterBattlePhase extends Phase {
globalScene.playBgm();
}
const availablePartyMembers = globalScene.getEnemyParty().filter(p => !p.isFainted()).length;
globalScene.unshiftPhase(new SummonPhase(0, false));
globalScene.phaseManager.unshiftPhase(new SummonPhase(0, false));
if (globalScene.currentBattle.double && availablePartyMembers > 1) {
globalScene.unshiftPhase(new SummonPhase(1, false));
globalScene.phaseManager.unshiftPhase(new SummonPhase(1, false));
}
if (!globalScene.currentBattle.mysteryEncounter?.hideBattleIntroMessage) {
@ -368,9 +368,9 @@ export class MysteryEncounterBattlePhase extends Phase {
const doTrainerSummon = () => {
this.hideEnemyTrainer();
const availablePartyMembers = globalScene.getEnemyParty().filter(p => !p.isFainted()).length;
globalScene.unshiftPhase(new SummonPhase(0, false));
globalScene.phaseManager.unshiftPhase(new SummonPhase(0, false));
if (globalScene.currentBattle.double && availablePartyMembers > 1) {
globalScene.unshiftPhase(new SummonPhase(1, false));
globalScene.phaseManager.unshiftPhase(new SummonPhase(1, false));
}
this.endBattleSetup();
};
@ -426,37 +426,37 @@ export class MysteryEncounterBattlePhase extends Phase {
if (encounterMode !== MysteryEncounterMode.TRAINER_BATTLE) {
const ivScannerModifier = globalScene.findModifier(m => m instanceof IvScannerModifier);
if (ivScannerModifier) {
enemyField.map(p => globalScene.pushPhase(new ScanIvsPhase(p.getBattlerIndex())));
enemyField.map(p => globalScene.phaseManager.pushPhase(new ScanIvsPhase(p.getBattlerIndex())));
}
}
const availablePartyMembers = globalScene.getPlayerParty().filter(p => p.isAllowedInBattle());
if (!availablePartyMembers[0].isOnField()) {
globalScene.pushPhase(new SummonPhase(0));
globalScene.phaseManager.pushPhase(new SummonPhase(0));
}
if (globalScene.currentBattle.double) {
if (availablePartyMembers.length > 1) {
globalScene.pushPhase(new ToggleDoublePositionPhase(true));
globalScene.phaseManager.pushPhase(new ToggleDoublePositionPhase(true));
if (!availablePartyMembers[1].isOnField()) {
globalScene.pushPhase(new SummonPhase(1));
globalScene.phaseManager.pushPhase(new SummonPhase(1));
}
}
} else {
if (availablePartyMembers.length > 1 && availablePartyMembers[1].isOnField()) {
globalScene.getPlayerField().forEach(pokemon => pokemon.lapseTag(BattlerTagType.COMMANDED));
globalScene.pushPhase(new ReturnPhase(1));
globalScene.phaseManager.pushPhase(new ReturnPhase(1));
}
globalScene.pushPhase(new ToggleDoublePositionPhase(false));
globalScene.phaseManager.pushPhase(new ToggleDoublePositionPhase(false));
}
if (encounterMode !== MysteryEncounterMode.TRAINER_BATTLE && !this.disableSwitch) {
const minPartySize = globalScene.currentBattle.double ? 2 : 1;
if (availablePartyMembers.length > minPartySize) {
globalScene.pushPhase(new CheckSwitchPhase(0, globalScene.currentBattle.double));
globalScene.phaseManager.pushPhase(new CheckSwitchPhase(0, globalScene.currentBattle.double));
if (globalScene.currentBattle.double) {
globalScene.pushPhase(new CheckSwitchPhase(1, globalScene.currentBattle.double));
globalScene.phaseManager.pushPhase(new CheckSwitchPhase(1, globalScene.currentBattle.double));
}
}
}
@ -562,8 +562,8 @@ export class MysteryEncounterRewardsPhase extends Phase {
if (encounter.doEncounterRewards) {
encounter.doEncounterRewards();
} else if (this.addHealPhase) {
globalScene.tryRemovePhase(p => p.is("SelectModifierPhase"));
globalScene.unshiftPhase(
globalScene.phaseManager.tryRemovePhase(p => p.is("SelectModifierPhase"));
globalScene.phaseManager.unshiftPhase(
new SelectModifierPhase(0, undefined, {
fillRemaining: false,
rerollMultiplier: -1,
@ -571,7 +571,7 @@ export class MysteryEncounterRewardsPhase extends Phase {
);
}
globalScene.pushPhase(new PostMysteryEncounterPhase());
globalScene.phaseManager.pushPhase(new PostMysteryEncounterPhase());
this.end();
}
}
@ -618,10 +618,10 @@ export class PostMysteryEncounterPhase extends Phase {
continueEncounter() {
const endPhase = () => {
if (globalScene.gameMode.hasRandomBiomes || globalScene.isNewBiome()) {
globalScene.pushPhase(new SelectBiomePhase());
globalScene.phaseManager.pushPhase(new SelectBiomePhase());
}
globalScene.pushPhase(new NewBattlePhase());
globalScene.phaseManager.pushPhase(new NewBattlePhase());
this.end();
};

View File

@ -7,9 +7,11 @@ export class NewBattlePhase extends BattlePhase {
super.start();
// cull any extra `NewBattle` phases from the queue.
globalScene.phaseQueue = globalScene.phaseQueue.filter(phase => !phase.is("NewBattlePhase"));
globalScene.phaseManager.phaseQueue = globalScene.phaseManager.phaseQueue.filter(
phase => !phase.is("NewBattlePhase"),
);
// `phaseQueuePrepend` is private, so we have to use this inefficient loop.
while (globalScene.tryRemoveUnshiftedPhase(phase => phase.is("NewBattlePhase"))) {}
while (globalScene.phaseManager.tryRemoveUnshiftedPhase(phase => phase.is("NewBattlePhase"))) {}
globalScene.newBattle();

View File

@ -41,7 +41,7 @@ export class ObtainStatusEffectPhase extends PokemonPhase {
}
pokemon.updateInfo(true);
new CommonBattleAnim(CommonAnim.POISON + (this.statusEffect! - 1), pokemon).play(false, () => {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
getStatusEffectObtainText(
this.statusEffect,
getPokemonNameWithAffix(pokemon),
@ -59,7 +59,7 @@ export class ObtainStatusEffectPhase extends PokemonPhase {
return;
}
} else if (pokemon.status?.effect === this.statusEffect) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
getStatusEffectOverlapText(this.statusEffect ?? StatusEffect.NONE, getPokemonNameWithAffix(pokemon)),
);
}

View File

@ -68,7 +68,7 @@ export class PokemonHealPhase extends CommonAnimPhase {
let lastStatusEffect = StatusEffect.NONE;
if (healBlock && this.hpHealed > 0) {
globalScene.queueMessage(healBlock.onActivation(pokemon));
globalScene.phaseManager.queueMessage(healBlock.onActivation(pokemon));
this.message = null;
return super.end();
}
@ -119,11 +119,13 @@ export class PokemonHealPhase extends CommonAnimPhase {
}
if (this.message) {
globalScene.queueMessage(this.message);
globalScene.phaseManager.queueMessage(this.message);
}
if (this.healStatus && lastStatusEffect && !hasMessage) {
globalScene.queueMessage(getStatusEffectHealText(lastStatusEffect, getPokemonNameWithAffix(pokemon)));
globalScene.phaseManager.queueMessage(
getStatusEffectHealText(lastStatusEffect, getPokemonNameWithAffix(pokemon)),
);
}
if (!healOrDamage && !lastStatusEffect) {

View File

@ -65,7 +65,7 @@ export class PokemonTransformPhase extends PokemonPhase {
globalScene.playSound("battle_anims/PRSFX- Transform");
}
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("abilityTriggers:postSummonTransform", {
pokemonNameWithAffix: getPokemonNameWithAffix(user),
targetName: target.name,

View File

@ -28,7 +28,7 @@ export class PostGameOverPhase extends Phase {
return globalScene.reset(true);
}
globalScene.reset();
globalScene.unshiftPhase(new TitlePhase());
globalScene.phaseManager.unshiftPhase(new TitlePhase());
this.end();
});
});

View File

@ -32,7 +32,7 @@ export class PostTurnStatusEffectPhase extends PokemonPhase {
applyAbAttrs(BlockStatusDamageAbAttr, pokemon, cancelled);
if (!cancelled.value) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
getStatusEffectActivationText(pokemon.status.effect, getPokemonNameWithAffix(pokemon)),
);
const damage = new NumberHolder(0);

View File

@ -159,7 +159,7 @@ export class QuietFormChangePhase extends BattlePhase {
this.pokemon.findAndRemoveTags(t => t.tagType === BattlerTagType.AUTOTOMIZED);
if (globalScene?.currentBattle.battleSpec === BattleSpec.FINAL_BOSS && this.pokemon.isEnemy()) {
globalScene.playBgm();
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new PokemonHealPhase(this.pokemon.getBattlerIndex(), this.pokemon.getMaxHp(), null, false, false, false, true),
);
this.pokemon.findAndRemoveTags(() => true);
@ -168,7 +168,9 @@ export class QuietFormChangePhase extends BattlePhase {
this.pokemon.initBattleInfo();
this.pokemon.cry();
const movePhase = globalScene.findPhase(p => p.is("MovePhase") && p.pokemon === this.pokemon) as MovePhase;
const movePhase = globalScene.phaseManager.findPhase(
p => p.is("MovePhase") && p.pokemon === this.pokemon,
) as MovePhase;
if (movePhase) {
movePhase.cancel();
}

View File

@ -35,7 +35,7 @@ export class RevivalBlessingPhase extends BattlePhase {
pokemon.resetTurnData();
pokemon.resetStatus(true, false, false, false);
pokemon.heal(Math.min(toDmgValue(0.5 * pokemon.getMaxHp()), pokemon.getMaxHp()));
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("moveTriggers:revivalBlessing", {
pokemonName: pokemon.name,
}),
@ -51,16 +51,16 @@ export class RevivalBlessingPhase extends BattlePhase {
) {
if (slotIndex <= 1) {
// Revived ally pokemon
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new SwitchSummonPhase(SwitchType.SWITCH, pokemon.getFieldIndex(), slotIndex, false, true),
);
globalScene.unshiftPhase(new ToggleDoublePositionPhase(true));
globalScene.phaseManager.unshiftPhase(new ToggleDoublePositionPhase(true));
} else if (allyPokemon.isFainted()) {
// Revived party pokemon, and ally pokemon is fainted
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new SwitchSummonPhase(SwitchType.SWITCH, allyPokemon.getFieldIndex(), slotIndex, false, true),
);
globalScene.unshiftPhase(new ToggleDoublePositionPhase(true));
globalScene.phaseManager.unshiftPhase(new ToggleDoublePositionPhase(true));
}
}
}

View File

@ -22,9 +22,9 @@ export class SelectBiomePhase extends BattlePhase {
const setNextBiome = (nextBiome: BiomeId) => {
if (nextWaveIndex % 10 === 1) {
globalScene.applyModifiers(MoneyInterestModifier, true);
globalScene.unshiftPhase(new PartyHealPhase(false));
globalScene.phaseManager.unshiftPhase(new PartyHealPhase(false));
}
globalScene.unshiftPhase(new SwitchBiomePhase(nextBiome));
globalScene.phaseManager.unshiftPhase(new SwitchBiomePhase(nextBiome));
this.end();
};

View File

@ -123,7 +123,7 @@ export class SelectModifierPhase extends BattlePhase {
return false;
}
globalScene.reroll = true;
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new SelectModifierPhase(
this.rerollCount + 1,
this.typeOptions.map(o => o.type?.tier).filter(t => t !== undefined) as ModifierTier[],
@ -247,7 +247,7 @@ export class SelectModifierPhase extends BattlePhase {
// If the player selects either of these, then escapes out of consuming them,
// they are returned to a shop in the same state.
if (modifier.type instanceof RememberMoveModifierType || modifier.type instanceof TmModifierType) {
globalScene.unshiftPhase(this.copy());
globalScene.phaseManager.unshiftPhase(this.copy());
}
if (cost && !(modifier.type instanceof RememberMoveModifierType)) {

View File

@ -25,8 +25,8 @@ export class SelectStarterPhase extends Phase {
globalScene.ui.clearText();
globalScene.ui.setMode(UiMode.SAVE_SLOT, SaveSlotUiMode.SAVE, (slotId: number) => {
if (slotId === -1) {
globalScene.clearPhaseQueue();
globalScene.pushPhase(new TitlePhase());
globalScene.phaseManager.clearPhaseQueue();
globalScene.phaseManager.pushPhase(new TitlePhase());
return this.end();
}
globalScene.sessionSlotId = slotId;

View File

@ -28,12 +28,12 @@ export class SelectTargetPhase extends PokemonPhase {
const errorMessage = user
.getRestrictingTag(move!, user, fieldSide[targets[0]])!
.selectionDeniedText(user, moveObject.id);
globalScene.queueMessage(i18next.t(errorMessage, { moveName: moveObject.name }), 0, true);
globalScene.phaseManager.queueMessage(i18next.t(errorMessage, { moveName: moveObject.name }), 0, true);
targets = [];
}
if (targets.length < 1) {
globalScene.currentBattle.turnCommands[this.fieldIndex] = null;
globalScene.unshiftPhase(new CommandPhase(this.fieldIndex));
globalScene.phaseManager.unshiftPhase(new CommandPhase(this.fieldIndex));
} else {
turnCommand!.targets = targets; //TODO: is the bang correct here?
}

View File

@ -36,8 +36,8 @@ export class ShowAbilityPhase extends PokemonPhase {
// If the bar is already out, hide it before showing the new one
if (globalScene.abilityBar.isVisible()) {
globalScene.unshiftPhase(new HideAbilityPhase());
globalScene.unshiftPhase(new ShowAbilityPhase(this.battlerIndex, this.passive));
globalScene.phaseManager.unshiftPhase(new HideAbilityPhase());
globalScene.phaseManager.unshiftPhase(new ShowAbilityPhase(this.battlerIndex, this.passive));
return this.end();
}

View File

@ -29,9 +29,9 @@ export class ShowPartyExpBarPhase extends PlayerPartyMemberPokemonPhase {
pokemon.addExp(exp.value);
const newLevel = pokemon.level;
if (newLevel > lastLevel) {
globalScene.unshiftPhase(new LevelUpPhase(this.partyMemberIndex, lastLevel, newLevel));
globalScene.phaseManager.unshiftPhase(new LevelUpPhase(this.partyMemberIndex, lastLevel, newLevel));
}
globalScene.unshiftPhase(new HidePartyExpBarPhase());
globalScene.phaseManager.unshiftPhase(new HidePartyExpBarPhase());
pokemon.updateInfo();
if (globalScene.expParty === ExpNotification.SKIP) {

View File

@ -72,7 +72,7 @@ export class StatStageChangePhase extends PokemonPhase {
if (this.stats.length > 1) {
for (let i = 0; i < this.stats.length; i++) {
const stat = [this.stats[i]];
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new StatStageChangePhase(
this.battlerIndex,
this.selfTarget,
@ -212,7 +212,7 @@ export class StatStageChangePhase extends PokemonPhase {
if (this.showMessage) {
const messages = this.getStatStageChangeMessages(filteredStats, stages.value, relLevels);
for (const message of messages) {
globalScene.queueMessage(message);
globalScene.phaseManager.queueMessage(message);
}
}
@ -235,7 +235,7 @@ export class StatStageChangePhase extends PokemonPhase {
applyPostStatStageChangeAbAttrs(PostStatStageChangeAbAttr, pokemon, filteredStats, this.stages, this.selfTarget);
// Look for any other stat change phases; if this is the last one, do White Herb check
const existingPhase = globalScene.findPhase(
const existingPhase = globalScene.phaseManager.findPhase(
p => p.is("StatStageChangePhase") && p.battlerIndex === this.battlerIndex,
);
if (!existingPhase?.is("StatStageChangePhase")) {
@ -315,7 +315,7 @@ export class StatStageChangePhase extends PokemonPhase {
let existingPhase: StatStageChangePhase;
if (this.stats.length === 1) {
while (
(existingPhase = globalScene.findPhase(
(existingPhase = globalScene.phaseManager.findPhase(
p =>
p.is("StatStageChangePhase") &&
p.battlerIndex === this.battlerIndex &&
@ -328,13 +328,13 @@ export class StatStageChangePhase extends PokemonPhase {
) {
this.stages += existingPhase.stages;
if (!globalScene.tryRemovePhase(p => p === existingPhase)) {
if (!globalScene.phaseManager.tryRemovePhase(p => p === existingPhase)) {
break;
}
}
}
while (
(existingPhase = globalScene.findPhase(
(existingPhase = globalScene.phaseManager.findPhase(
p =>
p.is("StatStageChangePhase") &&
p.battlerIndex === this.battlerIndex &&
@ -346,7 +346,7 @@ export class StatStageChangePhase extends PokemonPhase {
) as StatStageChangePhase)
) {
this.stats.push(...existingPhase.stats);
if (!globalScene.tryRemovePhase(p => p === existingPhase)) {
if (!globalScene.phaseManager.tryRemovePhase(p => p === existingPhase)) {
break;
}
}

View File

@ -57,8 +57,8 @@ export class SummonPhase extends PartyMemberPokemonPhase {
if (legalIndex === -1) {
console.error("Party Details:\n", party);
console.error("All available Pokemon were fainted or illegal!");
globalScene.clearPhaseQueue();
globalScene.unshiftPhase(new GameOverPhase());
globalScene.phaseManager.clearPhaseQueue();
globalScene.phaseManager.unshiftPhase(new GameOverPhase());
this.end();
return;
}
@ -275,7 +275,7 @@ export class SummonPhase extends PartyMemberPokemonPhase {
const pokemon = this.getPokemon();
if (pokemon.isShiny(true)) {
globalScene.unshiftPhase(new ShinySparklePhase(pokemon.getBattlerIndex()));
globalScene.phaseManager.unshiftPhase(new ShinySparklePhase(pokemon.getBattlerIndex()));
}
pokemon.resetTurnData();
@ -291,7 +291,7 @@ export class SummonPhase extends PartyMemberPokemonPhase {
}
queuePostSummon(): void {
globalScene.pushPhase(new PostSummonPhase(this.getPokemon().getBattlerIndex()));
globalScene.phaseManager.pushPhase(new PostSummonPhase(this.getPokemon().getBattlerIndex()));
}
end() {

View File

@ -76,9 +76,13 @@ export class SwitchPhase extends BattlePhase {
if (slotIndex >= globalScene.currentBattle.getBattlerCount() && slotIndex < 6) {
// Remove any pre-existing PostSummonPhase under the same field index.
// Pre-existing PostSummonPhases may occur when this phase is invoked during a prompt to switch at the start of a wave.
globalScene.tryRemovePhase(p => p.is("PostSummonPhase") && p.player && p.fieldIndex === this.fieldIndex);
globalScene.phaseManager.tryRemovePhase(
p => p.is("PostSummonPhase") && p.player && p.fieldIndex === this.fieldIndex,
);
const switchType = option === PartyOption.PASS_BATON ? SwitchType.BATON_PASS : this.switchType;
globalScene.unshiftPhase(new SwitchSummonPhase(switchType, fieldIndex, slotIndex, this.doReturn));
globalScene.phaseManager.unshiftPhase(
new SwitchSummonPhase(switchType, fieldIndex, slotIndex, this.doReturn),
);
}
globalScene.ui.setMode(UiMode.MESSAGE).then(() => super.end());
},

View File

@ -265,6 +265,6 @@ export class SwitchSummonPhase extends SummonPhase {
}
queuePostSummon(): void {
globalScene.unshiftPhase(new PostSummonPhase(this.getPokemon().getBattlerIndex()));
globalScene.phaseManager.unshiftPhase(new PostSummonPhase(this.getPokemon().getBattlerIndex()));
}
}

View File

@ -21,7 +21,7 @@ export class TeraPhase extends BattlePhase {
start() {
super.start();
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
i18next.t("battle:pokemonTerastallized", {
pokemonNameWithAffix: getPokemonNameWithAffix(this.pokemon),
type: i18next.t(`pokemonInfo:Type.${PokemonType[this.pokemon.getTeraType()]}`),

View File

@ -124,8 +124,8 @@ export class TitlePhase extends Phase {
options.push({
label: i18next.t("menu:cancel"),
handler: () => {
globalScene.clearPhaseQueue();
globalScene.pushPhase(new TitlePhase());
globalScene.phaseManager.clearPhaseQueue();
globalScene.phaseManager.pushPhase(new TitlePhase());
super.end();
return true;
},
@ -198,9 +198,9 @@ export class TitlePhase extends Phase {
initDailyRun(): void {
globalScene.ui.clearText();
globalScene.ui.setMode(UiMode.SAVE_SLOT, SaveSlotUiMode.SAVE, (slotId: number) => {
globalScene.clearPhaseQueue();
globalScene.phaseManager.clearPhaseQueue();
if (slotId === -1) {
globalScene.pushPhase(new TitlePhase());
globalScene.phaseManager.pushPhase(new TitlePhase());
return super.end();
}
globalScene.sessionSlotId = slotId;
@ -304,23 +304,23 @@ export class TitlePhase extends Phase {
globalScene.arena.preloadBgm();
globalScene.gameMode = getGameMode(this.gameMode);
if (this.gameMode === GameModes.CHALLENGE) {
globalScene.pushPhase(new SelectChallengePhase());
globalScene.phaseManager.pushPhase(new SelectChallengePhase());
} else {
globalScene.pushPhase(new SelectStarterPhase());
globalScene.phaseManager.pushPhase(new SelectStarterPhase());
}
globalScene.newArena(globalScene.gameMode.getStartingBiome());
} else {
globalScene.playBgm();
}
globalScene.pushPhase(new EncounterPhase(this.loaded));
globalScene.phaseManager.pushPhase(new EncounterPhase(this.loaded));
if (this.loaded) {
const availablePartyMembers = globalScene.getPokemonAllowedInBattle().length;
globalScene.pushPhase(new SummonPhase(0, true, true));
globalScene.phaseManager.pushPhase(new SummonPhase(0, true, true));
if (globalScene.currentBattle.double && availablePartyMembers > 1) {
globalScene.pushPhase(new SummonPhase(1, true, true));
globalScene.phaseManager.pushPhase(new SummonPhase(1, true, true));
}
if (
@ -329,9 +329,9 @@ export class TitlePhase extends Phase {
) {
const minPartySize = globalScene.currentBattle.double ? 2 : 1;
if (availablePartyMembers > minPartySize) {
globalScene.pushPhase(new CheckSwitchPhase(0, globalScene.currentBattle.double));
globalScene.phaseManager.pushPhase(new CheckSwitchPhase(0, globalScene.currentBattle.double));
if (globalScene.currentBattle.double) {
globalScene.pushPhase(new CheckSwitchPhase(1, globalScene.currentBattle.double));
globalScene.phaseManager.pushPhase(new CheckSwitchPhase(1, globalScene.currentBattle.double));
}
}
}

View File

@ -20,11 +20,13 @@ export class TrainerVictoryPhase extends BattlePhase {
globalScene.playBgm(globalScene.currentBattle.trainer?.config.victoryBgm);
globalScene.unshiftPhase(new MoneyRewardPhase(globalScene.currentBattle.trainer?.config.moneyMultiplier!)); // TODO: is this bang correct?
globalScene.phaseManager.unshiftPhase(
new MoneyRewardPhase(globalScene.currentBattle.trainer?.config.moneyMultiplier!),
); // TODO: is this bang correct?
const modifierRewardFuncs = globalScene.currentBattle.trainer?.config.modifierRewardFuncs!; // TODO: is this bang correct?
for (const modifierRewardFunc of modifierRewardFuncs) {
globalScene.unshiftPhase(new ModifierRewardPhase(modifierRewardFunc));
globalScene.phaseManager.unshiftPhase(new ModifierRewardPhase(modifierRewardFunc));
}
const trainerType = globalScene.currentBattle.trainer?.config.trainerType!; // TODO: is this bang correct?
@ -35,7 +37,7 @@ export class TrainerVictoryPhase extends BattlePhase {
globalScene.currentBattle.trainer?.config.isBoss
) {
if (timedEventManager.getUpgradeUnlockedVouchers()) {
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new ModifierRewardPhase(
[
modifierTypes.VOUCHER_PLUS,
@ -46,7 +48,7 @@ export class TrainerVictoryPhase extends BattlePhase {
),
);
} else {
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new ModifierRewardPhase(
[modifierTypes.VOUCHER, modifierTypes.VOUCHER, modifierTypes.VOUCHER_PLUS, modifierTypes.VOUCHER_PREMIUM][
vouchers[TrainerType[trainerType]].voucherType

View File

@ -25,7 +25,7 @@ export class TurnEndPhase extends FieldPhase {
globalScene.currentBattle.incrementTurn();
globalScene.eventTarget.dispatchEvent(new TurnEndEvent(globalScene.currentBattle.turn));
globalScene.hideAbilityBar();
globalScene.phaseManager.hideAbilityBar();
const handlePokemon = (pokemon: Pokemon) => {
if (!pokemon.switchOutStatus) {
@ -34,7 +34,7 @@ export class TurnEndPhase extends FieldPhase {
globalScene.applyModifiers(TurnHealModifier, pokemon.isPlayer(), pokemon);
if (globalScene.arena.terrain?.terrainType === TerrainType.GRASSY && pokemon.isGrounded()) {
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new PokemonHealPhase(
pokemon.getBattlerIndex(),
Math.max(pokemon.getMaxHp() >> 4, 1),

View File

@ -22,14 +22,18 @@ export class TurnInitPhase extends FieldPhase {
globalScene.getPlayerField().forEach(p => {
// If this pokemon is in play and evolved into something illegal under the current challenge, force a switch
if (p.isOnField() && !p.isAllowedInBattle()) {
globalScene.queueMessage(i18next.t("challenges:illegalEvolution", { pokemon: p.name }), null, true);
globalScene.phaseManager.queueMessage(
i18next.t("challenges:illegalEvolution", { pokemon: p.name }),
null,
true,
);
const allowedPokemon = globalScene.getPokemonAllowedInBattle();
if (!allowedPokemon.length) {
// If there are no longer any legal pokemon in the party, game over.
globalScene.clearPhaseQueue();
globalScene.unshiftPhase(new GameOverPhase());
globalScene.phaseManager.clearPhaseQueue();
globalScene.phaseManager.unshiftPhase(new GameOverPhase());
} else if (
allowedPokemon.length >= globalScene.currentBattle.getBattlerCount() ||
(globalScene.currentBattle.double && !allowedPokemon[0].isActive(true))
@ -42,7 +46,7 @@ export class TurnInitPhase extends FieldPhase {
p.leaveField();
}
if (allowedPokemon.length === 1 && globalScene.currentBattle.double) {
globalScene.unshiftPhase(new ToggleDoublePositionPhase(true));
globalScene.phaseManager.unshiftPhase(new ToggleDoublePositionPhase(true));
}
}
});
@ -65,11 +69,13 @@ export class TurnInitPhase extends FieldPhase {
pokemon.resetTurnData();
globalScene.pushPhase(pokemon.isPlayer() ? new CommandPhase(i) : new EnemyCommandPhase(i - BattlerIndex.ENEMY));
globalScene.phaseManager.pushPhase(
pokemon.isPlayer() ? new CommandPhase(i) : new EnemyCommandPhase(i - BattlerIndex.ENEMY),
);
}
});
globalScene.pushPhase(new TurnStartPhase());
globalScene.phaseManager.pushPhase(new TurnStartPhase());
this.end();
}

View File

@ -153,7 +153,7 @@ export class TurnStartPhase extends FieldPhase {
switch (preTurnCommand?.command) {
case Command.TERA:
globalScene.pushPhase(new TeraPhase(pokemon));
globalScene.phaseManager.pushPhase(new TeraPhase(pokemon));
}
}
@ -176,11 +176,13 @@ export class TurnStartPhase extends FieldPhase {
pokemon.getMoveset().find(m => m.moveId === queuedMove.move && m.ppUsed < m.getMovePp()) ||
new PokemonMove(queuedMove.move);
if (move.getMove().hasAttr(MoveHeaderAttr)) {
globalScene.unshiftPhase(new MoveHeaderPhase(pokemon, move));
globalScene.phaseManager.unshiftPhase(new MoveHeaderPhase(pokemon, move));
}
if (pokemon.isPlayer()) {
if (turnCommand.cursor === -1) {
globalScene.pushPhase(new MovePhase(pokemon, turnCommand.targets || turnCommand.move!.targets, move)); //TODO: is the bang correct here?
globalScene.phaseManager.pushPhase(
new MovePhase(pokemon, turnCommand.targets || turnCommand.move!.targets, move),
); //TODO: is the bang correct here?
} else {
const playerPhase = new MovePhase(
pokemon,
@ -189,10 +191,10 @@ export class TurnStartPhase extends FieldPhase {
false,
queuedMove.ignorePP,
); //TODO: is the bang correct here?
globalScene.pushPhase(playerPhase);
globalScene.phaseManager.pushPhase(playerPhase);
}
} else {
globalScene.pushPhase(
globalScene.phaseManager.pushPhase(
new MovePhase(
pokemon,
turnCommand.targets || turnCommand.move!.targets,
@ -204,11 +206,13 @@ export class TurnStartPhase extends FieldPhase {
}
break;
case Command.BALL:
globalScene.unshiftPhase(new AttemptCapturePhase(turnCommand.targets![0] % 2, turnCommand.cursor!)); //TODO: is the bang correct here?
globalScene.phaseManager.unshiftPhase(
new AttemptCapturePhase(turnCommand.targets![0] % 2, turnCommand.cursor!),
); //TODO: is the bang correct here?
break;
case Command.POKEMON:
const switchType = turnCommand.args?.[0] ? SwitchType.BATON_PASS : SwitchType.SWITCH;
globalScene.unshiftPhase(
globalScene.phaseManager.unshiftPhase(
new SwitchSummonPhase(switchType, pokemon.getFieldIndex(), turnCommand.cursor!, true, pokemon.isPlayer()),
);
break;
@ -233,18 +237,18 @@ export class TurnStartPhase extends FieldPhase {
runningPokemon = hasRunAway !== undefined ? hasRunAway : fasterPokemon;
}
}
globalScene.unshiftPhase(new AttemptRunPhase(runningPokemon.getFieldIndex()));
globalScene.phaseManager.unshiftPhase(new AttemptRunPhase(runningPokemon.getFieldIndex()));
break;
}
}
globalScene.pushPhase(new WeatherEffectPhase());
globalScene.pushPhase(new BerryPhase());
globalScene.phaseManager.pushPhase(new WeatherEffectPhase());
globalScene.phaseManager.pushPhase(new BerryPhase());
/** Add a new phase to check who should be taking status damage */
globalScene.pushPhase(new CheckStatusEffectPhase(moveOrder));
globalScene.phaseManager.pushPhase(new CheckStatusEffectPhase(moveOrder));
globalScene.pushPhase(new TurnEndPhase());
globalScene.phaseManager.pushPhase(new TurnEndPhase());
/**
* this.end() will call shiftPhase(), which dumps everything from PrependQueue (aka everything that is unshifted()) to the front

View File

@ -7,7 +7,7 @@ export class UnavailablePhase extends Phase {
public readonly phaseName = "UnavailablePhase";
start(): void {
globalScene.ui.setMode(UiMode.UNAVAILABLE, () => {
globalScene.unshiftPhase(new LoginPhase(true));
globalScene.phaseManager.unshiftPhase(new LoginPhase(true));
this.end();
});
}

View File

@ -51,12 +51,12 @@ export class VictoryPhase extends PokemonPhase {
.getEnemyParty()
.find(p => (globalScene.currentBattle.battleType === BattleType.WILD ? p.isOnField() : !p?.isFainted(true)))
) {
globalScene.pushPhase(new BattleEndPhase(true));
globalScene.phaseManager.pushPhase(new BattleEndPhase(true));
if (globalScene.currentBattle.battleType === BattleType.TRAINER) {
globalScene.pushPhase(new TrainerVictoryPhase());
globalScene.phaseManager.pushPhase(new TrainerVictoryPhase());
}
if (globalScene.gameMode.isEndless || !globalScene.gameMode.isWaveFinal(globalScene.currentBattle.waveIndex)) {
globalScene.pushPhase(new EggLapsePhase());
globalScene.phaseManager.pushPhase(new EggLapsePhase());
if (globalScene.gameMode.isClassic) {
switch (globalScene.currentBattle.waveIndex) {
case ClassicFixedBossWaves.RIVAL_1:
@ -64,34 +64,36 @@ export class VictoryPhase extends PokemonPhase {
// Get event modifiers for this wave
timedEventManager
.getFixedBattleEventRewards(globalScene.currentBattle.waveIndex)
.map(r => globalScene.pushPhase(new ModifierRewardPhase(modifierTypes[r])));
.map(r => globalScene.phaseManager.pushPhase(new ModifierRewardPhase(modifierTypes[r])));
break;
case ClassicFixedBossWaves.EVIL_BOSS_2:
// Should get Lock Capsule on 165 before shop phase so it can be used in the rewards shop
globalScene.pushPhase(new ModifierRewardPhase(modifierTypes.LOCK_CAPSULE));
globalScene.phaseManager.pushPhase(new ModifierRewardPhase(modifierTypes.LOCK_CAPSULE));
break;
}
}
if (globalScene.currentBattle.waveIndex % 10) {
globalScene.pushPhase(new SelectModifierPhase(undefined, undefined, this.getFixedBattleCustomModifiers()));
globalScene.phaseManager.pushPhase(
new SelectModifierPhase(undefined, undefined, this.getFixedBattleCustomModifiers()),
);
} else if (globalScene.gameMode.isDaily) {
globalScene.pushPhase(new ModifierRewardPhase(modifierTypes.EXP_CHARM));
globalScene.phaseManager.pushPhase(new ModifierRewardPhase(modifierTypes.EXP_CHARM));
if (
globalScene.currentBattle.waveIndex > 10 &&
!globalScene.gameMode.isWaveFinal(globalScene.currentBattle.waveIndex)
) {
globalScene.pushPhase(new ModifierRewardPhase(modifierTypes.GOLDEN_POKEBALL));
globalScene.phaseManager.pushPhase(new ModifierRewardPhase(modifierTypes.GOLDEN_POKEBALL));
}
} else {
const superExpWave = !globalScene.gameMode.isEndless ? (globalScene.offsetGym ? 0 : 20) : 10;
if (globalScene.gameMode.isEndless && globalScene.currentBattle.waveIndex === 10) {
globalScene.pushPhase(new ModifierRewardPhase(modifierTypes.EXP_SHARE));
globalScene.phaseManager.pushPhase(new ModifierRewardPhase(modifierTypes.EXP_SHARE));
}
if (
globalScene.currentBattle.waveIndex <= 750 &&
(globalScene.currentBattle.waveIndex <= 500 || globalScene.currentBattle.waveIndex % 30 === superExpWave)
) {
globalScene.pushPhase(
globalScene.phaseManager.pushPhase(
new ModifierRewardPhase(
globalScene.currentBattle.waveIndex % 30 !== superExpWave || globalScene.currentBattle.waveIndex > 250
? modifierTypes.EXP_CHARM
@ -100,30 +102,30 @@ export class VictoryPhase extends PokemonPhase {
);
}
if (globalScene.currentBattle.waveIndex <= 150 && !(globalScene.currentBattle.waveIndex % 50)) {
globalScene.pushPhase(new ModifierRewardPhase(modifierTypes.GOLDEN_POKEBALL));
globalScene.phaseManager.pushPhase(new ModifierRewardPhase(modifierTypes.GOLDEN_POKEBALL));
}
if (globalScene.gameMode.isEndless && !(globalScene.currentBattle.waveIndex % 50)) {
globalScene.pushPhase(
globalScene.phaseManager.pushPhase(
new ModifierRewardPhase(
!(globalScene.currentBattle.waveIndex % 250)
? modifierTypes.VOUCHER_PREMIUM
: modifierTypes.VOUCHER_PLUS,
),
);
globalScene.pushPhase(new AddEnemyBuffModifierPhase());
globalScene.phaseManager.pushPhase(new AddEnemyBuffModifierPhase());
}
}
if (globalScene.gameMode.hasRandomBiomes || globalScene.isNewBiome()) {
globalScene.pushPhase(new SelectBiomePhase());
globalScene.phaseManager.pushPhase(new SelectBiomePhase());
}
globalScene.pushPhase(new NewBattlePhase());
globalScene.phaseManager.pushPhase(new NewBattlePhase());
} else {
globalScene.currentBattle.battleType = BattleType.CLEAR;
globalScene.score += globalScene.gameMode.getClearScoreBonus();
globalScene.updateScoreText();
globalScene.pushPhase(new GameOverPhase(true));
globalScene.phaseManager.pushPhase(new GameOverPhase(true));
}
}

View File

@ -65,7 +65,7 @@ export class WeatherEffectPhase extends CommonAnimPhase {
const damage = toDmgValue(pokemon.getMaxHp() / 16);
globalScene.queueMessage(getWeatherDamageMessage(this.weather!.weatherType, pokemon) ?? "");
globalScene.phaseManager.queueMessage(getWeatherDamageMessage(this.weather!.weatherType, pokemon) ?? "");
pokemon.damageAndUpdate(damage, { result: HitResult.INDIRECT, ignoreSegments: true });
};

View File

@ -426,8 +426,8 @@ export class GameData {
globalScene.ui.savingIcon.hide();
if (error) {
if (error.startsWith("session out of date")) {
globalScene.clearPhaseQueue();
globalScene.unshiftPhase(new ReloadSessionPhase());
globalScene.phaseManager.clearPhaseQueue();
globalScene.phaseManager.unshiftPhase(new ReloadSessionPhase());
}
console.error(error);
return resolve(false);
@ -459,7 +459,7 @@ export class GameData {
saveDataOrErr[0] !== "{"
) {
if (saveDataOrErr === 404) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
"Save data could not be found. If this is a new account, you can safely ignore this message.",
null,
true,
@ -467,7 +467,7 @@ export class GameData {
return resolve(true);
}
if (typeof saveDataOrErr === "string" && saveDataOrErr?.includes("Too many connections")) {
globalScene.queueMessage(
globalScene.phaseManager.queueMessage(
"Too many people are trying to connect and the server is overloaded. Please try again later.",
null,
true,
@ -746,8 +746,8 @@ export class GameData {
});
if (systemData) {
globalScene.clearPhaseQueue();
globalScene.unshiftPhase(new ReloadSessionPhase(JSON.stringify(systemData)));
globalScene.phaseManager.clearPhaseQueue();
globalScene.phaseManager.unshiftPhase(new ReloadSessionPhase(JSON.stringify(systemData)));
this.clearLocalData();
return false;
}
@ -1248,8 +1248,8 @@ export class GameData {
pokerogueApi.savedata.session.delete({ slot: slotId, clientSessionId }).then(error => {
if (error) {
if (error.startsWith("session out of date")) {
globalScene.clearPhaseQueue();
globalScene.unshiftPhase(new ReloadSessionPhase());
globalScene.phaseManager.clearPhaseQueue();
globalScene.phaseManager.unshiftPhase(new ReloadSessionPhase());
}
console.error(error);
resolve(false);
@ -1320,8 +1320,8 @@ export class GameData {
localStorage.removeItem(`sessionData${slotId ? slotId : ""}_${loggedInUser?.username}`);
} else {
if (jsonResponse?.error?.startsWith("session out of date")) {
globalScene.clearPhaseQueue();
globalScene.unshiftPhase(new ReloadSessionPhase());
globalScene.phaseManager.clearPhaseQueue();
globalScene.phaseManager.unshiftPhase(new ReloadSessionPhase());
}
console.error(jsonResponse);
@ -1458,8 +1458,8 @@ export class GameData {
}
if (error) {
if (error.startsWith("session out of date")) {
globalScene.clearPhaseQueue();
globalScene.unshiftPhase(new ReloadSessionPhase());
globalScene.phaseManager.clearPhaseQueue();
globalScene.phaseManager.unshiftPhase(new ReloadSessionPhase());
}
console.error(error);
return resolve(false);

View File

@ -78,7 +78,7 @@ export default class BallUiHandler extends UiHandler {
const pokeballTypeCount = Object.keys(globalScene.pokeballCounts).length;
if (button === Button.ACTION || button === Button.CANCEL) {
const commandPhase = globalScene.getCurrentPhase() as CommandPhase;
const commandPhase = globalScene.phaseManager.getCurrentPhase() as CommandPhase;
success = true;
if (button === Button.ACTION && this.cursor < pokeballTypeCount) {
if (globalScene.pokeballCounts[this.cursor]) {

View File

@ -383,16 +383,16 @@ export default class GameChallengesUiHandler extends UiHandler {
this.cursorObj?.setVisible(true);
this.updateChallengeArrows(this.startCursor.visible);
} else {
globalScene.clearPhaseQueue();
globalScene.pushPhase(new TitlePhase());
globalScene.getCurrentPhase()?.end();
globalScene.phaseManager.clearPhaseQueue();
globalScene.phaseManager.pushPhase(new TitlePhase());
globalScene.phaseManager.getCurrentPhase()?.end();
}
success = true;
} else if (button === Button.SUBMIT || button === Button.ACTION) {
if (this.hasSelectedChallenge) {
if (this.startCursor.visible) {
globalScene.unshiftPhase(new SelectStarterPhase());
globalScene.getCurrentPhase()?.end();
globalScene.phaseManager.unshiftPhase(new SelectStarterPhase());
globalScene.phaseManager.getCurrentPhase()?.end();
} else {
this.startCursor.setVisible(true);
this.cursorObj?.setVisible(false);

View File

@ -74,11 +74,11 @@ export default class CommandUiHandler extends UiHandler {
this.commandsContainer.setVisible(true);
let commandPhase: CommandPhase;
const currentPhase = globalScene.getCurrentPhase();
const currentPhase = globalScene.phaseManager.getCurrentPhase();
if (currentPhase?.is("CommandPhase")) {
commandPhase = currentPhase;
} else {
commandPhase = globalScene.getStandbyPhase() as CommandPhase;
commandPhase = globalScene.phaseManager.getStandbyPhase() as CommandPhase;
}
if (this.canTera()) {
@ -124,7 +124,7 @@ export default class CommandUiHandler extends UiHandler {
switch (cursor) {
// Fight
case Command.FIGHT:
ui.setMode(UiMode.FIGHT, (globalScene.getCurrentPhase() as CommandPhase).getFieldIndex());
ui.setMode(UiMode.FIGHT, (globalScene.phaseManager.getCurrentPhase() as CommandPhase).getFieldIndex());
success = true;
break;
// Ball
@ -137,7 +137,7 @@ export default class CommandUiHandler extends UiHandler {
ui.setMode(
UiMode.PARTY,
PartyUiMode.SWITCH,
(globalScene.getCurrentPhase() as CommandPhase).getPokemon().getFieldIndex(),
(globalScene.phaseManager.getCurrentPhase() as CommandPhase).getPokemon().getFieldIndex(),
null,
PartyUiHandler.FilterNonFainted,
);
@ -145,16 +145,20 @@ export default class CommandUiHandler extends UiHandler {
break;
// Run
case Command.RUN:
(globalScene.getCurrentPhase() as CommandPhase).handleCommand(Command.RUN, 0);
(globalScene.phaseManager.getCurrentPhase() as CommandPhase).handleCommand(Command.RUN, 0);
success = true;
break;
case Command.TERA:
ui.setMode(UiMode.FIGHT, (globalScene.getCurrentPhase() as CommandPhase).getFieldIndex(), Command.TERA);
ui.setMode(
UiMode.FIGHT,
(globalScene.phaseManager.getCurrentPhase() as CommandPhase).getFieldIndex(),
Command.TERA,
);
success = true;
break;
}
} else {
(globalScene.getCurrentPhase() as CommandPhase).cancel();
(globalScene.phaseManager.getCurrentPhase() as CommandPhase).cancel();
}
} else {
switch (button) {

View File

@ -44,7 +44,7 @@ export default class EggHatchSceneHandler extends UiHandler {
processInput(button: Button): boolean {
if (button === Button.ACTION || button === Button.CANCEL) {
const phase = globalScene.getCurrentPhase();
const phase = globalScene.phaseManager.getCurrentPhase();
if (phase?.is("EggHatchPhase") && phase.trySkip()) {
return true;
}

View File

@ -221,7 +221,7 @@ export default class EggSummaryUiHandler extends MessageUiHandler {
let error = false;
if (button === Button.CANCEL) {
if (!this.blockExit) {
const phase = globalScene.getCurrentPhase();
const phase = globalScene.phaseManager.getCurrentPhase();
if (phase?.is("EggSummaryPhase")) {
phase.end();
}

View File

@ -126,7 +126,7 @@ export default class FightUiHandler extends UiHandler implements InfoToggle {
messageHandler.bg.setVisible(false);
messageHandler.commandWindow.setVisible(false);
messageHandler.movesWindowContainer.setVisible(true);
const pokemon = (globalScene.getCurrentPhase() as CommandPhase).getPokemon();
const pokemon = (globalScene.phaseManager.getCurrentPhase() as CommandPhase).getPokemon();
if (pokemon.tempSummonData.turnCount <= 1) {
this.setCursor(0);
} else {
@ -147,7 +147,9 @@ export default class FightUiHandler extends UiHandler implements InfoToggle {
if (button === Button.CANCEL || button === Button.ACTION) {
if (button === Button.ACTION) {
if ((globalScene.getCurrentPhase() as CommandPhase).handleCommand(this.fromCommand, cursor, false)) {
if (
(globalScene.phaseManager.getCurrentPhase() as CommandPhase).handleCommand(this.fromCommand, cursor, false)
) {
success = true;
} else {
ui.playError();
@ -237,7 +239,7 @@ export default class FightUiHandler extends UiHandler implements InfoToggle {
ui.add(this.cursorObj);
}
const pokemon = (globalScene.getCurrentPhase() as CommandPhase).getPokemon();
const pokemon = (globalScene.phaseManager.getCurrentPhase() as CommandPhase).getPokemon();
const moveset = pokemon.getMoveset();
const hasMove = cursor < moveset.length;
@ -318,7 +320,7 @@ export default class FightUiHandler extends UiHandler implements InfoToggle {
}
displayMoves() {
const pokemon = (globalScene.getCurrentPhase() as CommandPhase).getPokemon();
const pokemon = (globalScene.phaseManager.getCurrentPhase() as CommandPhase).getPokemon();
const moveset = pokemon.getMoveset();
for (let moveIndex = 0; moveIndex < 4; moveIndex++) {
@ -389,7 +391,7 @@ export default class FightUiHandler extends UiHandler implements InfoToggle {
clearMoves() {
this.movesContainer.removeAll(true);
const opponents = (globalScene.getCurrentPhase() as CommandPhase).getPokemon().getOpponents();
const opponents = (globalScene.phaseManager.getCurrentPhase() as CommandPhase).getPokemon().getOpponents();
opponents.forEach(opponent => {
(opponent as EnemyPokemon).updateEffectiveness();
});

View File

@ -125,7 +125,7 @@ export default class MenuUiHandler extends MessageUiHandler {
const ui = this.getUi();
this.excludedMenus = () => [
{
condition: !!globalScene.getCurrentPhase()?.is("SelectModifierPhase"),
condition: !!globalScene.phaseManager.getCurrentPhase()?.is("SelectModifierPhase"),
options: [MenuOptions.EGG_GACHA],
},
{ condition: bypassLogin, options: [MenuOptions.LOG_OUT] },

View File

@ -156,7 +156,9 @@ export default class MysteryEncounterUiHandler extends UiHandler {
) {
success = false;
} else {
if ((globalScene.getCurrentPhase() as MysteryEncounterPhase).handleOptionSelect(selected, cursor)) {
if (
(globalScene.phaseManager.getCurrentPhase() as MysteryEncounterPhase).handleOptionSelect(selected, cursor)
) {
success = true;
} else {
ui.playError();

View File

@ -750,7 +750,7 @@ export default class PartyUiHandler extends MessageUiHandler {
// TODO: This risks hitting the other options (.MOVE_i and ALL) so does it? Do we need an extra check?
if (
option >= PartyOption.FORM_CHANGE_ITEM &&
globalScene.getCurrentPhase()?.is("SelectModifierPhase") &&
globalScene.phaseManager.getCurrentPhase()?.is("SelectModifierPhase") &&
this.partyUiMode === PartyUiMode.CHECK
) {
const formChangeItemModifiers = this.getFormChangeItemsModifiers(pokemon);
@ -804,7 +804,7 @@ export default class PartyUiHandler extends MessageUiHandler {
this.partyUiMode === PartyUiMode.SWITCH
) {
this.clearOptions();
(globalScene.getCurrentPhase() as CommandPhase).handleCommand(
(globalScene.phaseManager.getCurrentPhase() as CommandPhase).handleCommand(
Command.POKEMON,
this.cursor,
option === PartyOption.PASS_BATON,
@ -1337,7 +1337,7 @@ export default class PartyUiHandler extends MessageUiHandler {
this.addCommonOptions(pokemon);
break;
case PartyUiMode.CHECK:
if (globalScene.getCurrentPhase()?.is("SelectModifierPhase")) {
if (globalScene.phaseManager.getCurrentPhase()?.is("SelectModifierPhase")) {
const formChangeItemModifiers = this.getFormChangeItemsModifiers(pokemon);
for (let i = 0; i < formChangeItemModifiers.length; i++) {
this.options.push(PartyOption.FORM_CHANGE_ITEM + i);

View File

@ -666,7 +666,7 @@ export default class PokedexPageUiHandler extends MessageUiHandler {
show(args: any[]): boolean {
// Allow the use of candies if we are in one of the whitelisted phases
this.canUseCandies = ["TitlePhase", "SelectStarterPhase", "CommandPhase"].includes(
globalScene.getCurrentPhase()?.phaseName ?? "",
globalScene.phaseManager.getCurrentPhase()?.phaseName ?? "",
);
if (args.length >= 1 && args[0] === "refresh") {

View File

@ -4305,15 +4305,15 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
UiMode.CONFIRM,
() => {
ui.setMode(UiMode.STARTER_SELECT);
globalScene.clearPhaseQueue();
globalScene.phaseManager.clearPhaseQueue();
if (globalScene.gameMode.isChallenge) {
globalScene.pushPhase(new SelectChallengePhase());
globalScene.pushPhase(new EncounterPhase());
globalScene.phaseManager.pushPhase(new SelectChallengePhase());
globalScene.phaseManager.pushPhase(new EncounterPhase());
} else {
globalScene.pushPhase(new TitlePhase());
globalScene.phaseManager.pushPhase(new TitlePhase());
}
this.clearText();
globalScene.getCurrentPhase()?.end();
globalScene.phaseManager.getCurrentPhase()?.end();
},
cancel,
null,

View File

@ -67,7 +67,7 @@ describe("Abilities - Cud Chew", () => {
});
it("shows ability popup for eating berry, even if berry is useless", async () => {
const abDisplaySpy = vi.spyOn(globalScene, "queueAbilityDisplay");
const abDisplaySpy = vi.spyOn(globalScene.phaseManager, "queueAbilityDisplay");
game.override.enemyMoveset([MoveId.SPLASH, MoveId.HEAL_PULSE]);
await game.classicMode.startBattle([SpeciesId.FARIGIRAF]);
@ -89,7 +89,7 @@ describe("Abilities - Cud Chew", () => {
await game.move.selectEnemyMove(MoveId.HEAL_PULSE);
await game.phaseInterceptor.to("TurnEndPhase");
// globalScene.queueAbilityDisplay should be called twice:
// globalScene.phaseManager.queueAbilityDisplay should be called twice:
// once to show cud chew text before regurgitating berries,
// once to hide ability text after finishing.
expect(abDisplaySpy).toBeCalledTimes(2);

View File

@ -44,7 +44,7 @@ describe("Abilities - Dancer", () => {
await game.phaseInterceptor.to("MovePhase"); // feebas uses swords dance
await game.phaseInterceptor.to("MovePhase", false); // oricorio copies swords dance
let currentPhase = game.scene.getCurrentPhase() as MovePhase;
let currentPhase = game.scene.phaseManager.getCurrentPhase() as MovePhase;
expect(currentPhase.pokemon).toBe(oricorio);
expect(currentPhase.move.moveId).toBe(MoveId.SWORDS_DANCE);
@ -54,7 +54,7 @@ describe("Abilities - Dancer", () => {
await game.phaseInterceptor.to("MovePhase"); // magikarp (left) uses victory dance
await game.phaseInterceptor.to("MovePhase", false); // oricorio copies magikarp's victory dance
currentPhase = game.scene.getCurrentPhase() as MovePhase;
currentPhase = game.scene.phaseManager.getCurrentPhase() as MovePhase;
expect(currentPhase.pokemon).toBe(oricorio);
expect(currentPhase.move.moveId).toBe(MoveId.VICTORY_DANCE);
@ -91,13 +91,13 @@ describe("Abilities - Dancer", () => {
await game.phaseInterceptor.to("MovePhase"); // shuckle 2 mirror moves oricorio
await game.phaseInterceptor.to("MovePhase"); // calls instructed rev dance
let currentPhase = game.scene.getCurrentPhase() as MovePhase;
let currentPhase = game.scene.phaseManager.getCurrentPhase() as MovePhase;
expect(currentPhase.pokemon).toBe(shuckle2);
expect(currentPhase.move.moveId).toBe(MoveId.REVELATION_DANCE);
await game.phaseInterceptor.to("MovePhase"); // shuckle 1 instructs oricorio
await game.phaseInterceptor.to("MovePhase");
currentPhase = game.scene.getCurrentPhase() as MovePhase;
currentPhase = game.scene.phaseManager.getCurrentPhase() as MovePhase;
expect(currentPhase.pokemon).toBe(oricorio);
expect(currentPhase.move.moveId).toBe(MoveId.REVELATION_DANCE);
});

View File

@ -146,7 +146,7 @@ describe("Abilities - Desolate Land", () => {
vi.spyOn(game.scene.getPlayerPokemon()!, "randBattleSeedInt").mockReturnValue(0);
const commandPhase = game.scene.getCurrentPhase() as CommandPhase;
const commandPhase = game.scene.phaseManager.getCurrentPhase() as CommandPhase;
commandPhase.handleCommand(Command.RUN, 0);
await game.phaseInterceptor.to("BerryPhase");

View File

@ -201,7 +201,7 @@ describe("Abilities - Disguise", () => {
game.move.select(MoveId.SHADOW_SNEAK);
await game.toNextWave();
expect(game.scene.getCurrentPhase()?.constructor.name).toBe("CommandPhase");
expect(game.scene.phaseManager.getCurrentPhase()?.constructor.name).toBe("CommandPhase");
expect(game.scene.currentBattle.waveIndex).toBe(2);
});

Some files were not shown because too many files have changed in this diff Show More