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 { LoadingScene } from "#app/loading-scene";
import { LevelCapPhase } from "#app/phases/level-cap-phase"; import { LevelCapPhase } from "#app/phases/level-cap-phase";
import { LoginPhase } from "#app/phases/login-phase"; import { LoginPhase } from "#app/phases/login-phase";
import { MessagePhase } from "#app/phases/message-phase";
import type { MovePhase } from "#app/phases/move-phase"; import type { MovePhase } from "#app/phases/move-phase";
import { NewBiomeEncounterPhase } from "#app/phases/new-biome-encounter-phase"; import { NewBiomeEncounterPhase } from "#app/phases/new-biome-encounter-phase";
import { NextEncounterPhase } from "#app/phases/next-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 { SummonPhase } from "#app/phases/summon-phase";
import { TitlePhase } from "#app/phases/title-phase"; import { TitlePhase } from "#app/phases/title-phase";
import { ToggleDoublePositionPhase } from "#app/phases/toggle-double-position-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 { ShopCursorTarget } from "#app/enums/shop-cursor-target";
import MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter"; import MysteryEncounter from "#app/data/mystery-encounters/mystery-encounter";
import { import {
@ -178,13 +176,12 @@ import { BattlerTagType } from "#enums/battler-tag-type";
import { FRIENDSHIP_GAIN_FROM_BATTLE } from "#app/data/balance/starters"; import { FRIENDSHIP_GAIN_FROM_BATTLE } from "#app/data/balance/starters";
import { StatusEffect } from "#enums/status-effect"; import { StatusEffect } from "#enums/status-effect";
import { initGlobalScene } from "#app/global-scene"; 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 { expSpriteKeys } from "./sprites/sprite-keys";
import { hasExpSprite } from "./sprites/sprite-utils"; import { hasExpSprite } from "./sprites/sprite-utils";
import { timedEventManager } from "./global-event-manager"; import { timedEventManager } from "./global-event-manager";
import { starterColors } from "./global-vars/starter-colors"; import { starterColors } from "./global-vars/starter-colors";
import { startingWave } from "./starting-wave"; import { startingWave } from "./starting-wave";
import { PhaseManager } from "./phase-manager";
const DEBUG_RNG = false; const DEBUG_RNG = false;
@ -297,18 +294,8 @@ export default class BattleScene extends SceneBase {
public gameData: GameData; public gameData: GameData;
public sessionSlotId: number; public sessionSlotId: number;
/** PhaseQueue: dequeue/remove the first element to get the next phase */ /** Manager for the phases active in the battle scene */
public phaseQueue: Phase[]; public readonly phaseManager: PhaseManager;
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;
public field: Phaser.GameObjects.Container; public field: Phaser.GameObjects.Container;
public fieldUI: Phaser.GameObjects.Container; public fieldUI: Phaser.GameObjects.Container;
public charSprite: CharSprite; public charSprite: CharSprite;
@ -396,11 +383,7 @@ export default class BattleScene extends SceneBase {
constructor() { constructor() {
super("battle"); super("battle");
this.phaseQueue = []; this.phaseManager = new PhaseManager();
this.phaseQueuePrepend = [];
this.conditionalQueue = [];
this.phaseQueuePrependSpliceIndex = -1;
this.nextCommandPhaseQueue = [];
this.eventManager = new TimedEventManager(); this.eventManager = new TimedEventManager();
this.updateGameInfo(); this.updateGameInfo();
initGlobalScene(this); initGlobalScene(this);
@ -716,10 +699,10 @@ export default class BattleScene extends SceneBase {
).then(() => loadMoveAnimAssets(defaultMoves, true)), ).then(() => loadMoveAnimAssets(defaultMoves, true)),
this.initStarterColors(), this.initStarterColors(),
]).then(() => { ]).then(() => {
this.pushPhase(new LoginPhase()); this.phaseManager.pushPhase(new LoginPhase());
this.pushPhase(new TitlePhase()); this.phaseManager.pushPhase(new TitlePhase());
this.shiftPhase(); this.phaseManager.shiftPhase();
}); });
} }
@ -899,7 +882,7 @@ export default class BattleScene extends SceneBase {
if (allyPokemon?.isActive(true)) { if (allyPokemon?.isActive(true)) {
let targetingMovePhase: MovePhase; let targetingMovePhase: MovePhase;
do { do {
targetingMovePhase = this.findPhase( targetingMovePhase = this.phaseManager.findPhase(
mp => mp =>
mp.is("MovePhase") && mp.is("MovePhase") &&
mp.targets.length === 1 && mp.targets.length === 1 &&
@ -1277,7 +1260,7 @@ export default class BattleScene extends SceneBase {
duration: 250, duration: 250,
ease: "Sine.easeInOut", ease: "Sine.easeInOut",
onComplete: () => { onComplete: () => {
this.clearPhaseQueue(); this.phaseManager.clearPhaseQueue();
this.ui.freeUIData(); this.ui.freeUIData();
this.uiContainer.remove(this.ui, true); this.uiContainer.remove(this.ui, true);
@ -1450,7 +1433,7 @@ export default class BattleScene extends SceneBase {
} }
if (lastBattle?.double && !newDouble) { 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()) { for (const p of this.getPlayerField()) {
p.lapseTag(BattlerTagType.COMMANDED); p.lapseTag(BattlerTagType.COMMANDED);
} }
@ -1492,7 +1475,7 @@ export default class BattleScene extends SceneBase {
playerField.forEach((pokemon, p) => { playerField.forEach((pokemon, p) => {
if (pokemon.isOnField()) { 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) { 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) { if (!this.gameMode.hasRandomBiomes && !isNewBiome) {
this.pushPhase(new NextEncounterPhase()); this.phaseManager.pushPhase(new NextEncounterPhase());
} else { } else {
this.pushPhase(new NewBiomeEncounterPhase()); this.phaseManager.pushPhase(new NewBiomeEncounterPhase());
const newMaxExpLevel = this.getMaxExpLevel(); const newMaxExpLevel = this.getMaxExpLevel();
if (newMaxExpLevel > maxExpLevel) { if (newMaxExpLevel > maxExpLevel) {
this.pushPhase(new LevelCapPhase()); this.phaseManager.pushPhase(new LevelCapPhase());
} }
} }
} }
@ -1588,7 +1571,9 @@ export default class BattleScene extends SceneBase {
return 0; return 0;
} }
const isEggPhase: boolean = ["EggLapsePhase", "EggHatchPhase"].includes(this.getCurrentPhase()?.phaseName ?? ""); const isEggPhase: boolean = ["EggLapsePhase", "EggHatchPhase"].includes(
this.phaseManager.getCurrentPhase()?.phaseName ?? "",
);
if ( if (
// Give trainers with specialty types an appropriately-typed form for Wormadam, Rotom, Arceus, Oricorio, Silvally, or Paldean Tauros. // 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 { addMoney(amount: number): void {
this.money = Math.min(this.money + amount, Number.MAX_SAFE_INTEGER); this.money = Math.min(this.money + amount, Number.MAX_SAFE_INTEGER);
this.updateMoneyText(); this.updateMoneyText();
@ -2942,7 +2647,7 @@ export default class BattleScene extends SceneBase {
} }
} else if (!virtual) { } else if (!virtual) {
const defaultModifierType = getDefaultModifierTypeForTier(modifier.type.tier); const defaultModifierType = getDefaultModifierTypeForTier(modifier.type.tier);
this.queueMessage( this.phaseManager.queueMessage(
i18next.t("battle:itemStackFull", { i18next.t("battle:itemStackFull", {
fullItemName: modifier.type.name, fullItemName: modifier.type.name,
itemName: defaultModifierType.name, itemName: defaultModifierType.name,
@ -3499,11 +3204,11 @@ export default class BattleScene extends SceneBase {
phase = new QuietFormChangePhase(pokemon, matchingFormChange); phase = new QuietFormChangePhase(pokemon, matchingFormChange);
} }
if (pokemon.isPlayer() && !matchingFormChange.quiet && modal) { if (pokemon.isPlayer() && !matchingFormChange.quiet && modal) {
this.overridePhase(phase); this.phaseManager.overridePhase(phase);
} else if (delayed) { } else if (delayed) {
this.pushPhase(phase); this.phaseManager.pushPhase(phase);
} else { } else {
this.unshiftPhase(phase); this.phaseManager.unshiftPhase(phase);
} }
return true; return true;
} }
@ -3520,9 +3225,9 @@ export default class BattleScene extends SceneBase {
): boolean { ): boolean {
const phase: Phase = new PokemonAnimPhase(battleAnimType, pokemon, fieldAssets); const phase: Phase = new PokemonAnimPhase(battleAnimType, pokemon, fieldAssets);
if (delayed) { if (delayed) {
this.pushPhase(phase); this.phaseManager.pushPhase(phase);
} else { } else {
this.unshiftPhase(phase); this.phaseManager.unshiftPhase(phase);
} }
return true; return true;
} }
@ -3630,19 +3335,19 @@ export default class BattleScene extends SceneBase {
this.currentBattle.double = true; this.currentBattle.double = true;
const availablePartyMembers = this.getPlayerParty().filter(p => p.isAllowedInBattle()); const availablePartyMembers = this.getPlayerParty().filter(p => p.isAllowedInBattle());
if (availablePartyMembers.length > 1) { if (availablePartyMembers.length > 1) {
this.pushPhase(new ToggleDoublePositionPhase(true)); this.phaseManager.pushPhase(new ToggleDoublePositionPhase(true));
if (!availablePartyMembers[1].isOnField()) { if (!availablePartyMembers[1].isOnField()) {
this.pushPhase(new SummonPhase(1)); this.phaseManager.pushPhase(new SummonPhase(1));
} }
} }
this.shiftPhase(); this.phaseManager.shiftPhase();
}, },
); );
return; return;
} }
this.shiftPhase(); this.phaseManager.shiftPhase();
} }
/** /**
@ -3754,7 +3459,7 @@ export default class BattleScene extends SceneBase {
if (exp) { if (exp) {
const partyMemberIndex = party.indexOf(expPartyMembers[pm]); const partyMemberIndex = party.indexOf(expPartyMembers[pm]);
this.unshiftPhase( this.phaseManager.unshiftPhase(
expPartyMembers[pm].isOnField() expPartyMembers[pm].isOnField()
? new ExpPhase(partyMemberIndex, exp) ? new ExpPhase(partyMemberIndex, exp)
: new ShowPartyExpBarPhase(partyMemberIndex, exp), : new ShowPartyExpBarPhase(partyMemberIndex, exp),

View File

@ -205,7 +205,7 @@ export default class Battle {
const message = i18next.t("battle:moneyPickedUp", { const message = i18next.t("battle:moneyPickedUp", {
moneyAmount: formattedMoneyAmount, moneyAmount: formattedMoneyAmount,
}); });
globalScene.queueMessage(message, undefined, true); globalScene.phaseManager.queueMessage(message, undefined, true);
globalScene.currentBattle.moneyScattered = 0; 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)); statStageChangePhases.push(new StatStageChangePhase(pokemon.getBattlerIndex(), true, this.stats, this.stages));
for (const statStageChangePhase of statStageChangePhases) { 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); super.applyPreDefend(pokemon, passive, simulated, attacker, move, cancelled, args);
if (!pokemon.isFullHp() && !simulated) { if (!pokemon.isFullHp() && !simulated) {
const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name; 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)); toDmgValue(pokemon.getMaxHp() / 4), i18next.t("abilityTriggers:typeImmunityHeal", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), abilityName }), true));
cancelled.value = true; // Suppresses "No Effect" message cancelled.value = true; // Suppresses "No Effect" message
} }
@ -436,7 +436,7 @@ class TypeImmunityStatStageChangeAbAttr extends TypeImmunityAbAttr {
super.applyPreDefend(pokemon, passive, simulated, attacker, move, cancelled, args); super.applyPreDefend(pokemon, passive, simulated, attacker, move, cancelled, args);
cancelled.value = true; // Suppresses "No Effect" message cancelled.value = true; // Suppresses "No Effect" message
if (!simulated) { 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 { 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); 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 { override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, _args: any[]): void {
if (!simulated) { 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 ally = pokemon.getAlly();
const otherPokemon = !isNullOrUndefined(ally) ? pokemon.getOpponents().concat([ ally ]) : pokemon.getOpponents(); const otherPokemon = !isNullOrUndefined(ally) ? pokemon.getOpponents().concat([ ally ]) : pokemon.getOpponents();
for (const other of otherPokemon) { 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 { } 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 { override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, _args: any[]): void {
if (!simulated) { 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 { override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, _args: any[]): void {
if (!pokemon.getTag(this.tagType) && !simulated) { if (!pokemon.getTag(this.tagType) && !simulated) {
pokemon.addTag(this.tagType, undefined, undefined, pokemon.id); 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 { override applyPostDefend(pokemon: Pokemon, _passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, _hitResult: HitResult, _args: any[]): void {
if (!simulated) { 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 { override applyPostStatStageChange(pokemon: Pokemon, simulated: boolean, statStagesChanged: BattleStat[], stagesChanged: number, selfTarget: boolean, args: any[]): void {
if (!simulated) { 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)]; this.stolenItem = heldItems[pokemon.randBattleSeedInt(heldItems.length)];
} }
if (globalScene.tryTransferHeldItemModifier(this.stolenItem, pokemon, false)) { if (globalScene.tryTransferHeldItemModifier(this.stolenItem, pokemon, false)) {
globalScene.queueMessage( globalScene.phaseManager.queueMessage(
i18next.t("abilityTriggers:postAttackStealHeldItem", { i18next.t("abilityTriggers:postAttackStealHeldItem", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
defenderName: defender.name, defenderName: defender.name,
@ -1892,7 +1892,7 @@ export class PostDefendStealHeldItemAbAttr extends PostDefendAbAttr {
this.stolenItem = heldItems[pokemon.randBattleSeedInt(heldItems.length)]; this.stolenItem = heldItems[pokemon.randBattleSeedInt(heldItems.length)];
} }
if (globalScene.tryTransferHeldItemModifier(this.stolenItem, pokemon, false)) { if (globalScene.tryTransferHeldItemModifier(this.stolenItem, pokemon, false)) {
globalScene.queueMessage( globalScene.phaseManager.queueMessage(
i18next.t("abilityTriggers:postDefendStealHeldItem", { i18next.t("abilityTriggers:postDefendStealHeldItem", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
attackerName: attacker.name, attackerName: attacker.name,
@ -1999,7 +1999,7 @@ class PostVictoryStatStageChangeAbAttr extends PostVictoryAbAttr {
override applyPostVictory(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): void { override applyPostVictory(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): void {
const stat = typeof this.stat === "function" ? this.stat(pokemon) : this.stat; const stat = typeof this.stat === "function" ? this.stat(pokemon) : this.stat;
if (!simulated) { 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 { override applyPostKnockOut(pokemon: Pokemon, passive: boolean, simulated: boolean, knockedOut: Pokemon, args: any[]): void {
const stat = typeof this.stat === "function" ? this.stat(pokemon) : this.stat; const stat = typeof this.stat === "function" ? this.stat(pokemon) : this.stat;
if (!simulated) { 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 { override applyPostKnockOut(pokemon: Pokemon, passive: boolean, simulated: boolean, knockedOut: Pokemon, args: any[]): void {
if (!simulated) { if (!simulated) {
pokemon.setTempAbility(knockedOut.getAbility()); 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 { override apply(pokemon: Pokemon, passive: boolean, simulated:boolean, cancelled: BooleanHolder, args: any[]): void {
if (!simulated) { 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; cancelled.value = this.overwrites;
} }
@ -2240,7 +2240,7 @@ export class PostSummonMessageAbAttr extends PostSummonAbAttr {
override applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): void { override applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): void {
if (!simulated) { 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 { override applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): void {
if (!simulated) { if (!simulated) {
globalScene.queueMessage(this.message); globalScene.phaseManager.queueMessage(this.message);
} }
} }
} }
@ -2332,7 +2332,7 @@ export class PostSummonStatStageChangeAbAttr extends PostSummonAbAttr {
if (this.selfTarget) { if (this.selfTarget) {
// we unshift the StatStageChangePhase to put it right after the showAbility and not at the end of the // 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) // 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 { } else {
for (const opponent of pokemon.getOpponents()) { for (const opponent of pokemon.getOpponents()) {
const cancelled = new BooleanHolder(false); const cancelled = new BooleanHolder(false);
@ -2345,7 +2345,7 @@ export class PostSummonStatStageChangeAbAttr extends PostSummonAbAttr {
} }
} }
if (!cancelled.value) { 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 { override applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): void {
const target = pokemon.getAlly(); const target = pokemon.getAlly();
if (!simulated && !isNullOrUndefined(target)) { 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)); 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); 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) { 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) { if (!simulated) {
for (const pokemon of allowedParty) { for (const pokemon of allowedParty) {
if (pokemon.status && this.statusEffect.includes(pokemon.status.effect)) { 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.resetStatus(false);
pokemon.updateInfo(); pokemon.updateInfo();
} }
@ -2725,7 +2725,7 @@ export class PostSummonTransformAbAttr extends PostSummonAbAttr {
override applyPostSummon(pokemon: Pokemon, _passive: boolean, simulated: boolean, _args: any[]): void { override applyPostSummon(pokemon: Pokemon, _passive: boolean, simulated: boolean, _args: any[]): void {
const target = this.getTarget(pokemon.getOpponents()); 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 // Apply boosts from this effect to the ally Dondozo
pokemon.getAlly()?.addTag(BattlerTagType.COMMANDED, 0, MoveId.NONE, pokemon.id); pokemon.getAlly()?.addTag(BattlerTagType.COMMANDED, 0, MoveId.NONE, pokemon.id);
// Cancel the source Pokemon's next move (if a move is queued) // 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]; const stages = args[1];
this.reflectedStat = stat; this.reflectedStat = stat;
if (!simulated) { 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; cancelled.value = true;
} }
@ -3768,7 +3768,7 @@ export class ForewarnAbAttr extends PostSummonAbAttr {
} }
} }
if (!simulated) { 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 { override applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): void {
if (!simulated) { if (!simulated) {
for (const opponent of pokemon.getOpponents()) { 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); setAbilityRevealed(opponent);
} }
} }
@ -3913,7 +3913,7 @@ export class PostWeatherLapseHealAbAttr extends PostWeatherLapseAbAttr {
override applyPostWeatherLapse(pokemon: Pokemon, passive: boolean, simulated: boolean, weather: Weather, args: any[]): void { override applyPostWeatherLapse(pokemon: Pokemon, passive: boolean, simulated: boolean, weather: Weather, args: any[]): void {
const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name; const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name;
if (!simulated) { 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)); 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 { override applyPostWeatherLapse(pokemon: Pokemon, passive: boolean, simulated: boolean, weather: Weather, args: any[]): void {
if (!simulated) { if (!simulated) {
const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name; 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 }); 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 { override applyPostTurn(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): void {
if (!simulated) { if (!simulated) {
const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name; 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)); 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 { override applyPostTurn(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): void {
if (!simulated && this.target?.status) { 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.resetStatus(false);
this.target.updateInfo(); this.target.updateInfo();
} }
@ -4132,7 +4132,7 @@ export class PostTurnRestoreBerryAbAttr extends PostTurnAbAttr {
} }
globalScene.updateModifiers(pokemon.isPlayer()); 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; return true;
} }
} }
@ -4162,7 +4162,7 @@ export class RepeatBerryNextTurnAbAttr extends PostTurnAbAttr {
* @param _args - N/A * @param _args - N/A
*/ */
override apply(pokemon: Pokemon, _passive: boolean, _simulated: boolean, _cancelled: BooleanHolder | null, _args: any[]): void { 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), new CommonAnimPhase(pokemon.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.USE_ITEM),
); );
@ -4226,11 +4226,11 @@ export class MoodyAbAttr extends PostTurnAbAttr {
if (canRaise.length > 0) { if (canRaise.length > 0) {
const raisedStat = canRaise[pokemon.randBattleSeedInt(canRaise.length)]; const raisedStat = canRaise[pokemon.randBattleSeedInt(canRaise.length)];
canLower = canRaise.filter(s => s !== raisedStat); 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) { if (canLower.length > 0) {
const loweredStat = canLower[pokemon.randBattleSeedInt(canLower.length)]; 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 { 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 { override applyPostTurn(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): void {
if (!simulated) { if (!simulated) {
const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name; 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)); 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 ((opp.status?.effect === StatusEffect.SLEEP || opp.hasAbility(AbilityId.COMATOSE)) && !opp.hasAbilityWithAttr(BlockNonDirectDamageAbAttr) && !opp.switchOutStatus) {
if (!simulated) { if (!simulated) {
opp.damageAndUpdate(toDmgValue(opp.getMaxHp() / 8), { result: HitResult.INDIRECT }); 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; const lastUsed = globalScene.currentBattle.lastUsedPokeball;
globalScene.pokeballCounts[lastUsed!]++; globalScene.pokeballCounts[lastUsed!]++;
globalScene.currentBattle.lastUsedPokeball = null; 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 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) { if (move.getMove() instanceof AttackMove || move.getMove() instanceof StatusMove) {
const target = this.getTarget(dancer, source, targets); 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) { } else if (move.getMove() instanceof SelfStatusMove) {
// If the move is a SelfStatusMove (ie. Swords Dance) the Dancer should replicate it on itself // 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[], args: any[],
): void { ): void {
if (!simulated) { 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(); const { name: abilityName } = passive ? pokemon.getPassiveAbility() : pokemon.getAbility();
globalScene.unshiftPhase( globalScene.phaseManager.unshiftPhase(
new PokemonHealPhase( new PokemonHealPhase(
pokemon.getBattlerIndex(), pokemon.getBattlerIndex(),
toDmgValue(pokemon.getMaxHp() * this.healPercent), 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)) { if (globalScene.tryTransferHeldItemModifier(this.randItem, pokemon, true, 1, true, undefined, false)) {
postBattleLoot.splice(postBattleLoot.indexOf(this.randItem), 1); 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; 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 { override apply(pokemon: Pokemon, passive: boolean, simulated: boolean, cancelled: BooleanHolder, args: any[]): void {
if (!simulated) { 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; continue;
} }
globalScene.setPhaseQueueSplice(); globalScene.phaseManager.setPhaseQueueSplice();
if (attr.showAbility && !simulated) { if (attr.showAbility && !simulated) {
globalScene.queueAbilityDisplay(pokemon, passive, true); globalScene.phaseManager.queueAbilityDisplay(pokemon, passive, true);
abShown = true; abShown = true;
} }
const message = attr.getTriggerMessage(pokemon, ability.name, args); const message = attr.getTriggerMessage(pokemon, ability.name, args);
if (message) { if (message) {
if (!simulated) { if (!simulated) {
globalScene.queueMessage(message); globalScene.phaseManager.queueMessage(message);
} }
messages.push(message); messages.push(message);
} }
@ -5512,14 +5512,14 @@ function applySingleAbAttrs<TAttr extends AbAttr>(
applyFunc(attr, passive); applyFunc(attr, passive);
if (abShown) { if (abShown) {
globalScene.queueAbilityDisplay(pokemon, passive, false); globalScene.phaseManager.queueAbilityDisplay(pokemon, passive, false);
} }
if (!simulated) { if (!simulated) {
pokemon.waveData.abilitiesApplied.add(ability.id); pokemon.waveData.abilitiesApplied.add(ability.id);
} }
globalScene.clearPhaseQueueSplice(); globalScene.phaseManager.clearPhaseQueueSplice();
} }
} }
@ -5546,7 +5546,7 @@ class ForceSwitchOutHelper {
if (switchOutTarget.hp > 0) { if (switchOutTarget.hp > 0) {
switchOutTarget.leaveField(this.switchType === SwitchType.SWITCH); 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; return true;
} }
/** /**
@ -5560,7 +5560,7 @@ class ForceSwitchOutHelper {
if (switchOutTarget.hp > 0) { if (switchOutTarget.hp > 0) {
switchOutTarget.leaveField(this.switchType === SwitchType.SWITCH); switchOutTarget.leaveField(this.switchType === SwitchType.SWITCH);
const summonIndex = (globalScene.currentBattle.trainer ? globalScene.currentBattle.trainer.getNextSummonIndex((switchOutTarget as EnemyPokemon).trainerSlot) : 0); 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; return true;
} }
/** /**
@ -5576,7 +5576,7 @@ class ForceSwitchOutHelper {
if (switchOutTarget.hp > 0) { if (switchOutTarget.hp > 0) {
switchOutTarget.leaveField(false); 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)) { if (globalScene.currentBattle.double && !isNullOrUndefined(allyPokemon)) {
globalScene.redirectPokemonMoves(switchOutTarget, allyPokemon); globalScene.redirectPokemonMoves(switchOutTarget, allyPokemon);
} }
@ -5586,13 +5586,13 @@ class ForceSwitchOutHelper {
globalScene.clearEnemyHeldItemModifiers(); globalScene.clearEnemyHeldItemModifiers();
if (switchOutTarget.hp) { if (switchOutTarget.hp) {
globalScene.pushPhase(new BattleEndPhase(false)); globalScene.phaseManager.pushPhase(new BattleEndPhase(false));
if (globalScene.gameMode.hasRandomBiomes || globalScene.isNewBiome()) { 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 ]) { for (const passive of [ false, true ]) {
if (pokemon) { if (pokemon) {
applySingleAbAttrs(pokemon, passive, attrType, applyFunc, successFunc, args, gainedMidTurn, simulated, messages); applySingleAbAttrs(pokemon, passive, attrType, applyFunc, successFunc, args, gainedMidTurn, simulated, messages);
globalScene.clearPhaseQueueSplice(); globalScene.phaseManager.clearPhaseQueueSplice();
} }
} }
} }
@ -6870,7 +6870,7 @@ export function initAbilities() {
.ignorable(), .ignorable(),
new Ability(AbilityId.ANALYTIC, 5) new Ability(AbilityId.ANALYTIC, 5)
.attr(MovePowerBoostAbAttr, (user, target, move) => { .attr(MovePowerBoostAbAttr, (user, target, move) => {
const movePhase = globalScene.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); return isNullOrUndefined(movePhase);
}, 1.3), }, 1.3),
new Ability(AbilityId.ILLUSION, 5) new Ability(AbilityId.ILLUSION, 5)

View File

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

View File

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

View File

@ -3,11 +3,7 @@ import type Pokemon from "../field/pokemon";
import { HitResult } from "../field/pokemon"; import { HitResult } from "../field/pokemon";
import { getStatusEffectHealText } from "./status-effect"; import { getStatusEffectHealText } from "./status-effect";
import { NumberHolder, toDmgValue, randSeedInt } from "#app/utils/common"; import { NumberHolder, toDmgValue, randSeedInt } from "#app/utils/common";
import { import { DoubleBerryEffectAbAttr, ReduceBerryUseThresholdAbAttr, applyAbAttrs } from "./abilities/ability";
DoubleBerryEffectAbAttr,
ReduceBerryUseThresholdAbAttr,
applyAbAttrs,
} from "./abilities/ability";
import i18next from "i18next"; import i18next from "i18next";
import { BattlerTagType } from "#enums/battler-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type";
import { BerryType } from "#enums/berry-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)); const hpHealed = new NumberHolder(toDmgValue(consumer.getMaxHp() / 4));
applyAbAttrs(DoubleBerryEffectAbAttr, consumer, null, false, hpHealed); applyAbAttrs(DoubleBerryEffectAbAttr, consumer, null, false, hpHealed);
globalScene.unshiftPhase( globalScene.phaseManager.unshiftPhase(
new PokemonHealPhase( new PokemonHealPhase(
consumer.getBattlerIndex(), consumer.getBattlerIndex(),
hpHealed.value, hpHealed.value,
@ -95,7 +91,7 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
case BerryType.LUM: case BerryType.LUM:
{ {
if (consumer.status) { if (consumer.status) {
globalScene.queueMessage( globalScene.phaseManager.queueMessage(
getStatusEffectHealText(consumer.status.effect, getPokemonNameWithAffix(consumer)), getStatusEffectHealText(consumer.status.effect, getPokemonNameWithAffix(consumer)),
); );
} }
@ -113,7 +109,7 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
const stat: BattleStat = berryType - BerryType.ENIGMA; const stat: BattleStat = berryType - BerryType.ENIGMA;
const statStages = new NumberHolder(1); const statStages = new NumberHolder(1);
applyAbAttrs(DoubleBerryEffectAbAttr, consumer, null, false, statStages); applyAbAttrs(DoubleBerryEffectAbAttr, consumer, null, false, statStages);
globalScene.unshiftPhase( globalScene.phaseManager.unshiftPhase(
new StatStageChangePhase(consumer.getBattlerIndex(), true, [stat], statStages.value), 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 randStat = randSeedInt(Stat.SPD, Stat.ATK);
const stages = new NumberHolder(2); const stages = new NumberHolder(2);
applyAbAttrs(DoubleBerryEffectAbAttr, consumer, null, false, stages); applyAbAttrs(DoubleBerryEffectAbAttr, consumer, null, false, stages);
globalScene.unshiftPhase( globalScene.phaseManager.unshiftPhase(
new StatStageChangePhase(consumer.getBattlerIndex(), true, [randStat], stages.value), 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()); consumer.getMoveset().find(m => m.ppUsed < m.getMovePp());
if (ppRestoreMove) { if (ppRestoreMove) {
ppRestoreMove.ppUsed = Math.max(ppRestoreMove.ppUsed - 10, 0); ppRestoreMove.ppUsed = Math.max(ppRestoreMove.ppUsed - 10, 0);
globalScene.queueMessage( globalScene.phaseManager.queueMessage(
i18next.t("battle:ppHealBerry", { i18next.t("battle:ppHealBerry", {
pokemonNameWithAffix: getPokemonNameWithAffix(consumer), pokemonNameWithAffix: getPokemonNameWithAffix(consumer),
moveName: ppRestoreMove.getName(), 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) * @param target the {@linkcode Pokemon} targeted by this move (optional)
*/ */
showChargeText(user: Pokemon, target?: Pokemon): void { showChargeText(user: Pokemon, target?: Pokemon): void {
globalScene.queueMessage(this._chargeText globalScene.phaseManager.queueMessage(this._chargeText
.replace("{USER}", getPokemonNameWithAffix(user)) .replace("{USER}", getPokemonNameWithAffix(user))
.replace("{TARGET}", getPokemonNameWithAffix(target)) .replace("{TARGET}", getPokemonNameWithAffix(target))
); );
@ -1310,7 +1310,7 @@ export class MessageHeaderAttr extends MoveHeaderAttr {
: this.message(user, move); : this.message(user, move);
if (message) { if (message) {
globalScene.queueMessage(message); globalScene.phaseManager.queueMessage(message);
return true; return true;
} }
return false; return false;
@ -1363,7 +1363,7 @@ export class PreMoveMessageAttr extends MoveAttr {
? this.message as string ? this.message as string
: this.message(user, target, move); : this.message(user, target, move);
if (message) { if (message) {
globalScene.queueMessage(message, 500); globalScene.phaseManager.queueMessage(message, 500);
return true; return true;
} }
return false; return false;
@ -1620,14 +1620,14 @@ export class SurviveDamageAttr extends ModifiedDamageAttr {
export class SplashAttr extends MoveEffectAttr { export class SplashAttr extends MoveEffectAttr {
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { 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; return true;
} }
} }
export class CelebrateAttr extends MoveEffectAttr { export class CelebrateAttr extends MoveEffectAttr {
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { 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; return true;
} }
} }
@ -1677,7 +1677,7 @@ export class RecoilAttr extends MoveEffectAttr {
} }
user.damageAndUpdate(recoilDamage, { result: HitResult.INDIRECT, ignoreSegments: true }); 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; user.turnData.damageTaken += recoilDamage;
return true; return true;
@ -1789,7 +1789,7 @@ export class HalfSacrificialAttr extends MoveEffectAttr {
applyAbAttrs(BlockNonDirectDamageAbAttr, user, cancelled); applyAbAttrs(BlockNonDirectDamageAbAttr, user, cancelled);
if (!cancelled.value) { if (!cancelled.value) {
user.damageAndUpdate(toDmgValue(user.getMaxHp() / 2), { result: HitResult.INDIRECT, ignoreSegments: true }); 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; return true;
} }
@ -1890,7 +1890,7 @@ export class HealAttr extends MoveEffectAttr {
* This heals the target and shows the appropriate message. * This heals the target and shows the appropriate message.
*/ */
addHealPhase(target: Pokemon, healRatio: number) { 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)); 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)); partyPokemon.forEach(p => this.cureStatus(p, user.id));
if (this.message) { if (this.message) {
globalScene.queueMessage(this.message); globalScene.phaseManager.queueMessage(this.message);
} }
return true; return true;
@ -1954,8 +1954,8 @@ export class PartyStatusCureAttr extends MoveEffectAttr {
pokemon.updateInfo(); pokemon.updateInfo();
} else { } else {
// TODO: Ability displays should be handled by the ability // TODO: Ability displays should be handled by the ability
globalScene.queueAbilityDisplay(pokemon, pokemon.getPassiveAbility()?.id === this.abilityCondition, true); globalScene.phaseManager.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, false);
} }
} }
} }
@ -2021,7 +2021,7 @@ export class SacrificialFullRestoreAttr extends SacrificialAttr {
const party = user.isPlayer() ? globalScene.getPlayerParty() : globalScene.getEnemyParty(); 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); const maxPartyMemberHp = party.map(p => p.getMaxHp()).reduce((maxHp: number, hp: number) => Math.max(hp, maxHp), 0);
globalScene.pushPhase( globalScene.phaseManager.pushPhase(
new PokemonHealPhase( new PokemonHealPhase(
user.getBattlerIndex(), user.getBattlerIndex(),
maxPartyMemberHp, maxPartyMemberHp,
@ -2233,7 +2233,7 @@ export class HitHealAttr extends MoveEffectAttr {
message = ""; message = "";
} }
} }
globalScene.unshiftPhase(new PokemonHealPhase(user.getBattlerIndex(), healAmount, message, false, true)); globalScene.phaseManager.unshiftPhase(new PokemonHealPhase(user.getBattlerIndex(), healAmount, message, false, true));
return true; return true;
} }
@ -2565,7 +2565,7 @@ export class StealHeldItemChanceAttr extends MoveEffectAttr {
return false; 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; return true;
} }
@ -2643,9 +2643,9 @@ export class RemoveHeldItemAttr extends MoveEffectAttr {
globalScene.updateModifiers(target.isPlayer()); globalScene.updateModifiers(target.isPlayer());
if (this.berriesOnly) { 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 { } 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; return true;
@ -2777,7 +2777,7 @@ export class StealEatBerryAttr extends EatBerryAttr {
this.chosenBerry = heldBerries[user.randBattleSeedInt(heldBerries.length)]; this.chosenBerry = heldBerries[user.randBattleSeedInt(heldBerries.length)];
applyPostItemLostAbAttrs(PostItemLostAbAttr, target, false); applyPostItemLostAbAttrs(PostItemLostAbAttr, target, false);
const message = i18next.t("battle:stealEatBerry", { pokemonName: user.name, targetName: target.name, berryName: this.chosenBerry.type.name }); 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.reduceBerryModifier(target);
this.eatBerry(user, target); this.eatBerry(user, target);
@ -2822,7 +2822,7 @@ export class HealStatusEffectAttr extends MoveEffectAttr {
const pokemon = this.selfTarget ? user : target; const pokemon = this.selfTarget ? user : target;
if (pokemon.status && this.effects.includes(pokemon.status.effect)) { 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.resetStatus();
pokemon.updateInfo(); pokemon.updateInfo();
@ -3067,13 +3067,13 @@ export class DelayedAttackAttr extends OverrideMoveEffectAttr {
if (!virtual) { if (!virtual) {
overridden.value = true; overridden.value = true;
globalScene.unshiftPhase(new MoveAnimPhase(new MoveChargeAnim(this.chargeAnim, move.id, user))); globalScene.phaseManager.unshiftPhase(new MoveAnimPhase(new MoveChargeAnim(this.chargeAnim, move.id, user)));
globalScene.queueMessage(this.chargeText.replace("{TARGET}", getPokemonNameWithAffix(target)).replace("{USER}", getPokemonNameWithAffix(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 }); user.pushMoveHistory({ move: move.id, targets: [ target.getBattlerIndex() ], result: MoveResult.OTHER });
const side = target.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY; const side = target.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY;
globalScene.arena.addTag(this.tagType, 3, move.id, user.id, side, false, target.getBattlerIndex()); globalScene.arena.addTag(this.tagType, 3, move.id, user.id, side, false, target.getBattlerIndex());
} else { } 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; return true;
@ -3103,29 +3103,29 @@ export class AwaitCombinedPledgeAttr extends OverrideMoveEffectAttr {
override apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { override apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
if (user.turnData.combiningPledge) { if (user.turnData.combiningPledge) {
// "The two moves have become one!\nIt's a combined move!" // "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; return false;
} }
const overridden = args[0] as BooleanHolder; 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) { if (allyMovePhase) {
const allyMove = allyMovePhase.move.getMove(); const allyMove = allyMovePhase.move.getMove();
if (allyMove !== move && allyMove.hasAttr(AwaitCombinedPledgeAttr)) { if (allyMove !== move && allyMove.hasAttr(AwaitCombinedPledgeAttr)) {
[ user, allyMovePhase.pokemon ].forEach((p) => p.turnData.combiningPledge = move.id); [ user, allyMovePhase.pokemon ].forEach((p) => p.turnData.combiningPledge = move.id);
// "{userPokemonName} is waiting for {allyPokemonName}'s move..." // "{userPokemonName} is waiting for {allyPokemonName}'s move..."
globalScene.queueMessage(i18next.t("moveTriggers:awaitingPledge", { globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:awaitingPledge", {
userPokemonName: getPokemonNameWithAffix(user), userPokemonName: getPokemonNameWithAffix(user),
allyPokemonName: getPokemonNameWithAffix(allyMovePhase.pokemon) allyPokemonName: getPokemonNameWithAffix(allyMovePhase.pokemon)
})); }));
// Move the ally's MovePhase (if needed) so that the ally moves next // Move the ally's MovePhase (if needed) so that the ally moves next
const allyMovePhaseIndex = globalScene.phaseQueue.indexOf(allyMovePhase); const allyMovePhaseIndex = globalScene.phaseManager.phaseQueue.indexOf(allyMovePhase);
const firstMovePhaseIndex = globalScene.phaseQueue.findIndex((phase) => phase.is("MovePhase")); const firstMovePhaseIndex = globalScene.phaseManager.phaseQueue.findIndex((phase) => phase.is("MovePhase"));
if (allyMovePhaseIndex !== firstMovePhaseIndex) { 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; overridden.value = true;
@ -3207,7 +3207,7 @@ export class StatStageChangeAttr extends MoveEffectAttr {
const moveChance = this.getMoveChance(user, target, move, this.selfTarget, true); const moveChance = this.getMoveChance(user, target, move, this.selfTarget, true);
if (moveChance < 0 || moveChance === 100 || user.randBattleSeedInt(100) < moveChance) { if (moveChance < 0 || moveChance === 100 || user.randBattleSeedInt(100) < moveChance) {
const stages = this.getLevels(user); 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; return true;
} }
@ -3432,7 +3432,7 @@ export class AcupressureStatStageChangeAttr extends MoveEffectAttr {
const randStats = BATTLE_STATS.filter((s) => target.getStatStage(s) < 6); const randStats = BATTLE_STATS.filter((s) => target.getStatStage(s) < 6);
if (randStats.length > 0) { if (randStats.length > 0) {
const boostStat = [ randStats[user.randBattleSeedInt(randStats.length)] ]; 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 true;
} }
return false; return false;
@ -3510,7 +3510,7 @@ export class OrderUpStatBoostAttr extends MoveEffectAttr {
break; break;
} }
globalScene.unshiftPhase(new StatStageChangePhase(user.getBattlerIndex(), this.selfTarget, [ increasedStat ], 1)); globalScene.phaseManager.unshiftPhase(new StatStageChangePhase(user.getBattlerIndex(), this.selfTarget, [ increasedStat ], 1));
return true; return true;
} }
} }
@ -3533,7 +3533,7 @@ export class CopyStatsAttr extends MoveEffectAttr {
} }
target.updateInfo(); target.updateInfo();
user.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; return true;
} }
@ -3552,7 +3552,7 @@ export class InvertStatsAttr extends MoveEffectAttr {
target.updateInfo(); target.updateInfo();
user.updateInfo(); user.updateInfo();
globalScene.queueMessage(i18next.t("moveTriggers:invertStats", { pokemonName: getPokemonNameWithAffix(target) })); globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:invertStats", { pokemonName: getPokemonNameWithAffix(target) }));
return true; return true;
} }
@ -3570,10 +3570,10 @@ export class ResetStatsAttr extends MoveEffectAttr {
// Target all pokemon on the field when Freezy Frost or Haze are used // Target all pokemon on the field when Freezy Frost or Haze are used
const activePokemon = globalScene.getField(true); const activePokemon = globalScene.getField(true);
activePokemon.forEach((p) => this.resetStats(p)); 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 } else { // Affects only the single target when Clear Smog is used
this.resetStats(target); this.resetStats(target);
globalScene.queueMessage(i18next.t("moveTriggers:resetStats", { pokemonName: getPokemonNameWithAffix(target) })); globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:resetStats", { pokemonName: getPokemonNameWithAffix(target) }));
} }
return true; return true;
} }
@ -3623,9 +3623,9 @@ export class SwapStatStagesAttr extends MoveEffectAttr {
user.updateInfo(); user.updateInfo();
if (this.stats.length === 7) { 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) { } else if (this.stats.length === 2) {
globalScene.queueMessage(i18next.t("moveTriggers:switchedTwoStatChanges", { globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:switchedTwoStatChanges", {
pokemonName: getPokemonNameWithAffix(user), pokemonName: getPokemonNameWithAffix(user),
firstStat: i18next.t(getStatKey(this.stats[0])), firstStat: i18next.t(getStatKey(this.stats[0])),
secondStat: i18next.t(getStatKey(this.stats[1])) 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 // If this move is multi-hit, disable all other hits
user.turnData.hitCount = 1; user.turnData.hitCount = 1;
user.turnData.hitsLeft = 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)); 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 { 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 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 // Update the phase queue so that the next Pokemon using Round moves next
const nextRoundIndex = globalScene.phaseQueue.indexOf(nextRoundPhase); const nextRoundIndex = globalScene.phaseManager.phaseQueue.indexOf(nextRoundPhase);
const nextMoveIndex = globalScene.phaseQueue.findIndex(phase => phase.is("MovePhase")); const nextMoveIndex = globalScene.phaseManager.phaseQueue.findIndex(phase => phase.is("MovePhase"));
if (nextRoundIndex !== nextMoveIndex) { 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) // 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); 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.setStatStage(s, statStageValueTarget - availableToSteal);
} }
} }
target.updateInfo(); target.updateInfo();
user.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; return true;
} }
@ -5368,7 +5368,7 @@ const crashDamageFunc = (user: Pokemon, move: Move) => {
} }
user.damageAndUpdate(toDmgValue(user.getMaxHp() / 2), { result: HitResult.INDIRECT }); 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); user.turnData.damageTaken += toDmgValue(user.getMaxHp() / 2);
return true; return true;
@ -5581,7 +5581,7 @@ export class FallDownAttr extends AddBattlerTagAttr {
*/ */
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
if (!target.isGrounded()) { 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); 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 { apply(user: Pokemon, target: Pokemon, move:Move, args: any[]): boolean {
if (user.getTypes(true).includes(PokemonType.GHOST)) { if (user.getTypes(true).includes(PokemonType.GHOST)) {
if (target.getTag(BattlerTagType.CURSED)) { if (target.getTag(BattlerTagType.CURSED)) {
globalScene.queueMessage(i18next.t("battle:attackFailed")); globalScene.phaseManager.queueMessage(i18next.t("battle:attackFailed"));
return false; return false;
} }
const curseRecoilDamage = Math.max(1, Math.floor(user.getMaxHp() / 2)); const curseRecoilDamage = Math.max(1, Math.floor(user.getMaxHp() / 2));
user.damageAndUpdate(curseRecoilDamage, { result: HitResult.INDIRECT, ignoreSegments: true }); user.damageAndUpdate(curseRecoilDamage, { result: HitResult.INDIRECT, ignoreSegments: true });
globalScene.queueMessage( globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:cursedOnAdd", { i18next.t("battlerTags:cursedOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(user), pokemonNameWithAffix: getPokemonNameWithAffix(user),
pokemonName: getPokemonNameWithAffix(target) pokemonName: getPokemonNameWithAffix(target)
@ -5680,8 +5680,8 @@ export class CurseAttr extends MoveEffectAttr {
target.addTag(BattlerTagType.CURSED, 0, move.id, user.id); target.addTag(BattlerTagType.CURSED, 0, move.id, user.id);
return true; return true;
} else { } else {
globalScene.unshiftPhase(new StatStageChangePhase(user.getBattlerIndex(), true, [ Stat.ATK, Stat.DEF ], 1)); globalScene.phaseManager.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.SPD ], -1));
return true; return true;
} }
} }
@ -5745,7 +5745,7 @@ export class ConfuseAttr extends AddBattlerTagAttr {
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
if (!this.selfTarget && target.isSafeguarded(user)) { if (!this.selfTarget && target.isSafeguarded(user)) {
if (move.category === MoveCategory.STATUS) { 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; return false;
} }
@ -5802,7 +5802,7 @@ export class IgnoreAccuracyAttr extends AddBattlerTagAttr {
return false; 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; return true;
} }
@ -5818,7 +5818,7 @@ export class FaintCountdownAttr extends AddBattlerTagAttr {
return false; 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; 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; return true;
} }
} }
@ -6154,7 +6154,7 @@ export class RevivalBlessingAttr extends MoveEffectAttr {
override apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { override apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
// If user is player, checks if the user has fainted pokemon // If user is player, checks if the user has fainted pokemon
if (user.isPlayer()) { if (user.isPlayer()) {
globalScene.unshiftPhase(new RevivalBlessingPhase(user)); globalScene.phaseManager.unshiftPhase(new RevivalBlessingPhase(user));
return true; return true;
} else if (user.isEnemy() && user.hasTrainer() && globalScene.getEnemyParty().findIndex((p) => p.isFainted() && !p.isBoss()) > -1) { } 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 // 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); const slotIndex = globalScene.getEnemyParty().findIndex((p) => pokemon.id === p.id);
pokemon.resetStatus(true, false, false, true); pokemon.resetStatus(true, false, false, true);
pokemon.heal(Math.min(toDmgValue(0.5 * pokemon.getMaxHp()), pokemon.getMaxHp())); 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(); const allyPokemon = user.getAlly();
if (globalScene.currentBattle.double && globalScene.getEnemyParty().length > 1 && !isNullOrUndefined(allyPokemon)) { if (globalScene.currentBattle.double && globalScene.getEnemyParty().length > 1 && !isNullOrUndefined(allyPokemon)) {
// Handle cases where revived pokemon needs to get switched in on same turn // Handle cases where revived pokemon needs to get switched in on same turn
if (allyPokemon.isFainted() || allyPokemon === pokemon) { if (allyPokemon.isFainted() || allyPokemon === pokemon) {
// Enemy switch phase should be removed and replaced with the revived pkmn switching in // 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 // If the pokemon being revived was alive earlier in the turn, cancel its move
// (revived pokemon can't move in the turn they're brought back) // (revived pokemon can't move in the turn they're brought back)
globalScene.findPhase((phase: MovePhase) => phase.pokemon === pokemon)?.cancel(); globalScene.phaseManager.findPhase((phase: MovePhase) => phase.pokemon === pokemon)?.cancel();
if (user.fieldPosition === FieldPosition.CENTER) { if (user.fieldPosition === FieldPosition.CENTER) {
user.setFieldPosition(FieldPosition.LEFT); 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; return true;
@ -6255,7 +6255,7 @@ export class ForceSwitchOutAttr extends MoveEffectAttr {
if (this.switchType === SwitchType.FORCE_SWITCH) { if (this.switchType === SwitchType.FORCE_SWITCH) {
switchOutTarget.leaveField(true); switchOutTarget.leaveField(true);
const slotIndex = eligibleNewIndices[user.randBattleSeedInt(eligibleNewIndices.length)]; const slotIndex = eligibleNewIndices[user.randBattleSeedInt(eligibleNewIndices.length)];
globalScene.prependToPhase( globalScene.phaseManager.prependToPhase(
new SwitchSummonPhase( new SwitchSummonPhase(
this.switchType, this.switchType,
switchOutTarget.getFieldIndex(), switchOutTarget.getFieldIndex(),
@ -6267,7 +6267,7 @@ export class ForceSwitchOutAttr extends MoveEffectAttr {
); );
} else { } else {
switchOutTarget.leaveField(this.switchType === SwitchType.SWITCH); switchOutTarget.leaveField(this.switchType === SwitchType.SWITCH);
globalScene.prependToPhase( globalScene.phaseManager.prependToPhase(
new SwitchPhase( new SwitchPhase(
this.switchType, this.switchType,
switchOutTarget.getFieldIndex(), switchOutTarget.getFieldIndex(),
@ -6298,7 +6298,7 @@ export class ForceSwitchOutAttr extends MoveEffectAttr {
if (this.switchType === SwitchType.FORCE_SWITCH) { if (this.switchType === SwitchType.FORCE_SWITCH) {
switchOutTarget.leaveField(true); switchOutTarget.leaveField(true);
const slotIndex = eligibleNewIndices[user.randBattleSeedInt(eligibleNewIndices.length)]; const slotIndex = eligibleNewIndices[user.randBattleSeedInt(eligibleNewIndices.length)];
globalScene.prependToPhase( globalScene.phaseManager.prependToPhase(
new SwitchSummonPhase( new SwitchSummonPhase(
this.switchType, this.switchType,
switchOutTarget.getFieldIndex(), switchOutTarget.getFieldIndex(),
@ -6310,7 +6310,7 @@ export class ForceSwitchOutAttr extends MoveEffectAttr {
); );
} else { } else {
switchOutTarget.leaveField(this.switchType === SwitchType.SWITCH); switchOutTarget.leaveField(this.switchType === SwitchType.SWITCH);
globalScene.prependToPhase( globalScene.phaseManager.prependToPhase(
new SwitchSummonPhase( new SwitchSummonPhase(
this.switchType, this.switchType,
switchOutTarget.getFieldIndex(), switchOutTarget.getFieldIndex(),
@ -6339,7 +6339,7 @@ export class ForceSwitchOutAttr extends MoveEffectAttr {
if (switchOutTarget.hp > 0) { if (switchOutTarget.hp > 0) {
switchOutTarget.leaveField(false); 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 // in double battles redirect potential moves off fled pokemon
if (globalScene.currentBattle.double && !isNullOrUndefined(allyPokemon)) { if (globalScene.currentBattle.double && !isNullOrUndefined(allyPokemon)) {
@ -6351,13 +6351,13 @@ export class ForceSwitchOutAttr extends MoveEffectAttr {
globalScene.clearEnemyHeldItemModifiers(switchOutTarget); globalScene.clearEnemyHeldItemModifiers(switchOutTarget);
if (!allyPokemon?.isActive(true) && switchOutTarget.hp) { if (!allyPokemon?.isActive(true) && switchOutTarget.hp) {
globalScene.pushPhase(new BattleEndPhase(false)); globalScene.phaseManager.pushPhase(new BattleEndPhase(false));
if (globalScene.gameMode.hasRandomBiomes || globalScene.isNewBiome()) { 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.summonData.types = targetTypes;
user.updateInfo(); 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; return true;
} }
@ -6556,7 +6556,7 @@ export class CopyBiomeTypeAttr extends MoveEffectAttr {
user.summonData.types = [ typeChange ]; user.summonData.types = [ typeChange ];
user.updateInfo(); 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; return true;
} }
@ -6661,7 +6661,7 @@ export class ChangeTypeAttr extends MoveEffectAttr {
target.summonData.types = [ this.type ]; target.summonData.types = [ this.type ];
target.updateInfo(); 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; return true;
} }
@ -6684,7 +6684,7 @@ export class AddTypeAttr extends MoveEffectAttr {
target.summonData.addedType = this.type; target.summonData.addedType = this.type;
target.updateInfo(); 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; return true;
} }
@ -6706,7 +6706,7 @@ export class FirstMoveTypeAttr extends MoveEffectAttr {
const firstMoveType = target.getMoveset()[0].getMove().type; const firstMoveType = target.getMoveset()[0].getMove().type;
user.summonData.types = [ firstMoveType ]; 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; return true;
} }
@ -6725,7 +6725,7 @@ class CallMoveAttr extends OverrideMoveEffectAttr {
const replaceMoveTarget = move.moveTarget === MoveTarget.NEAR_OTHER ? MoveTarget.NEAR_ENEMY : undefined; const replaceMoveTarget = move.moveTarget === MoveTarget.NEAR_OTHER ? MoveTarget.NEAR_ENEMY : undefined;
const moveTargets = getMoveTargets(user, move.id, replaceMoveTarget); const moveTargets = getMoveTargets(user, move.id, replaceMoveTarget);
if (moveTargets.targets.length === 0) { 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."); console.log("CallMoveAttr failed due to no targets.");
return false; return false;
} }
@ -6733,8 +6733,8 @@ class CallMoveAttr extends OverrideMoveEffectAttr {
? moveTargets.targets ? moveTargets.targets
: [ this.hasTarget ? target.getBattlerIndex() : moveTargets.targets[user.randBattleSeedInt(moveTargets.targets.length)] ]; // account for Mirror Move having a target already : [ 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 }); user.getMoveQueue().push({ move: move.id, targets: targets, virtual: true, ignorePP: true });
globalScene.unshiftPhase(new LoadMoveAnimPhase(move.id)); globalScene.phaseManager.unshiftPhase(new LoadMoveAnimPhase(move.id));
globalScene.unshiftPhase(new MovePhase(user, targets, new PokemonMove(move.id, 0, 0, true), true, true)); globalScene.phaseManager.unshiftPhase(new MovePhase(user, targets, new PokemonMove(move.id, 0, 0, true), true, true));
return true; return true;
} }
} }
@ -6962,8 +6962,8 @@ export class NaturePowerAttr extends OverrideMoveEffectAttr {
} }
user.getMoveQueue().push({ move: moveId, targets: [ target.getBattlerIndex() ], ignorePP: true }); user.getMoveQueue().push({ move: moveId, targets: [ target.getBattlerIndex() ], ignorePP: true });
globalScene.unshiftPhase(new LoadMoveAnimPhase(moveId)); globalScene.phaseManager.unshiftPhase(new LoadMoveAnimPhase(moveId));
globalScene.unshiftPhase(new MovePhase(user, [ target.getBattlerIndex() ], new PokemonMove(moveId, 0, 0, true), true)); globalScene.phaseManager.unshiftPhase(new MovePhase(user, [ target.getBattlerIndex() ], new PokemonMove(moveId, 0, 0, true), true));
return 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), userPokemonName: getPokemonNameWithAffix(user),
targetPokemonName: getPokemonNameWithAffix(target) targetPokemonName: getPokemonNameWithAffix(target)
})); }));
target.getMoveQueue().unshift({ move: lastMove.move, targets: moveTargets, ignorePP: false }); target.getMoveQueue().unshift({ move: lastMove.move, targets: moveTargets, ignorePP: false });
target.turnData.extraTurns++; target.turnData.extraTurns++;
globalScene.appendToPhase(new MovePhase(target, moveTargets, movesetMove), MoveEndPhase); globalScene.phaseManager.appendToPhase(new MovePhase(target, moveTargets, movesetMove), MoveEndPhase);
return true; 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 }); 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.eventTarget.dispatchEvent(new MoveUsedEvent(target.id, movesetMove.getMove(), movesetMove.ppUsed));
globalScene.queueMessage(message); globalScene.phaseManager.queueMessage(message);
return true; return true;
} }
@ -7276,7 +7276,7 @@ export class MovesetCopyMoveAttr extends OverrideMoveEffectAttr {
user.summonData.moveset = user.getMoveset().slice(0); user.summonData.moveset = user.getMoveset().slice(0);
user.summonData.moveset[thisMoveIndex] = new PokemonMove(copiedMove.id, 0, 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; return true;
} }
@ -7326,7 +7326,7 @@ export class SketchAttr extends MoveEffectAttr {
user.setMove(sketchIndex, sketchedMove.id); 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; return true;
} }
@ -7381,9 +7381,9 @@ export class AbilityChangeAttr extends MoveEffectAttr {
globalScene.triggerPokemonFormChange(moveTarget, SpeciesFormChangeRevertWeatherFormTrigger); globalScene.triggerPokemonFormChange(moveTarget, SpeciesFormChangeRevertWeatherFormTrigger);
if (moveTarget.breakIllusion()) { 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]); moveTarget.setTempAbility(allAbilities[this.ability]);
globalScene.triggerPokemonFormChange(moveTarget, SpeciesFormChangeRevertWeatherFormTrigger); globalScene.triggerPokemonFormChange(moveTarget, SpeciesFormChangeRevertWeatherFormTrigger);
return true; return true;
@ -7408,13 +7408,13 @@ export class AbilityCopyAttr extends MoveEffectAttr {
return false; 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()); user.setTempAbility(target.getAbility());
const ally = user.getAlly(); 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? 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()); ally.setTempAbility(target.getAbility());
} }
@ -7447,7 +7447,7 @@ export class AbilityGiveAttr extends MoveEffectAttr {
return false; 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()); target.setTempAbility(user.getAbility());
@ -7467,7 +7467,7 @@ export class SwitchAbilitiesAttr extends MoveEffectAttr {
const tempAbility = user.getAbility(); 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()); user.setTempAbility(target.getAbility());
target.setTempAbility(tempAbility); target.setTempAbility(tempAbility);
@ -7497,7 +7497,7 @@ export class SuppressAbilitiesAttr extends MoveEffectAttr {
return false; return false;
} }
globalScene.queueMessage(i18next.t("moveTriggers:suppressAbilities", { pokemonName: getPokemonNameWithAffix(target) })); globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:suppressAbilities", { pokemonName: getPokemonNameWithAffix(target) }));
target.suppressAbility(); target.suppressAbility();
@ -7550,9 +7550,9 @@ export class TransformAttr extends MoveEffectAttr {
return false; 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; return true;
} }
@ -7589,7 +7589,7 @@ export class SwapStatAttr extends MoveEffectAttr {
user.setStat(this.stat, target.getStat(this.stat, false), false); user.setStat(this.stat, target.getStat(this.stat, false), false);
target.setStat(this.stat, temp, false); target.setStat(this.stat, temp, false);
globalScene.queueMessage(i18next.t("moveTriggers:switchedStat", { globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:switchedStat", {
pokemonName: getPokemonNameWithAffix(user), pokemonName: getPokemonNameWithAffix(user),
stat: i18next.t(getStatKey(this.stat)), stat: i18next.t(getStatKey(this.stat)),
})); }));
@ -7635,7 +7635,7 @@ export class ShiftStatAttr extends MoveEffectAttr {
user.setStat(this.statToSwitch, secondStat, false); user.setStat(this.statToSwitch, secondStat, false);
user.setStat(this.statToSwitchWith, firstStat, false); user.setStat(this.statToSwitchWith, firstStat, false);
globalScene.queueMessage(i18next.t("moveTriggers:shiftedStats", { globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:shiftedStats", {
pokemonName: getPokemonNameWithAffix(user), pokemonName: getPokemonNameWithAffix(user),
statToSwitch: i18next.t(getStatKey(this.statToSwitch)), statToSwitch: i18next.t(getStatKey(this.statToSwitch)),
statToSwitchWith: i18next.t(getStatKey(this.statToSwitchWith)) statToSwitchWith: i18next.t(getStatKey(this.statToSwitchWith))
@ -7694,7 +7694,7 @@ export class AverageStatsAttr extends MoveEffectAttr {
target.setStat(s, avg, false); 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; return true;
} }
@ -7709,7 +7709,7 @@ export class MoneyAttr extends MoveEffectAttr {
apply(user: Pokemon, target: Pokemon, move: Move): boolean { apply(user: Pokemon, target: Pokemon, move: Move): boolean {
globalScene.currentBattle.moneyScattered += globalScene.getWaveMoneyAmount(0.2); globalScene.currentBattle.moneyScattered += globalScene.getWaveMoneyAmount(0.2);
globalScene.queueMessage(i18next.t("moveTriggers:coinsScatteredEverywhere")); globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:coinsScatteredEverywhere"));
return true; return true;
} }
} }
@ -7733,7 +7733,7 @@ export class DestinyBondAttr extends MoveEffectAttr {
* @returns true * @returns true
*/ */
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { 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); user.addTag(BattlerTagType.DESTINY_BOND, undefined, move.id, user.id);
return true; return true;
} }
@ -7847,12 +7847,12 @@ export class AfterYouAttr extends MoveEffectAttr {
* @returns true * @returns true
*/ */
override apply(user: Pokemon, target: Pokemon, _move: Move, _args: any[]): boolean { 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. //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); const nextAttackPhase = globalScene.phaseManager.findPhase<MovePhase>((phase) => phase.pokemon === target);
if (nextAttackPhase && globalScene.tryRemovePhase((phase: MovePhase) => phase.pokemon === target)) { if (nextAttackPhase && globalScene.phaseManager.tryRemovePhase((phase: MovePhase) => phase.pokemon === target)) {
globalScene.prependToPhase(new MovePhase(target, [ ...nextAttackPhase.targets ], nextAttackPhase.move), MovePhase); globalScene.phaseManager.prependToPhase(new MovePhase(target, [ ...nextAttackPhase.targets ], nextAttackPhase.move), MovePhase);
} }
return true; return true;
@ -7875,19 +7875,19 @@ export class ForceLastAttr extends MoveEffectAttr {
* @returns true * @returns true
*/ */
override apply(user: Pokemon, target: Pokemon, _move: Move, _args: any[]): boolean { 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); const targetMovePhase = globalScene.phaseManager.findPhase<MovePhase>((phase) => phase.pokemon === target);
if (targetMovePhase && !targetMovePhase.isForcedLast() && globalScene.tryRemovePhase((phase: MovePhase) => 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 - // 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 // 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)) [ MovePhase, MoveEndPhase ].every(cls => !(phase instanceof cls))
|| (phase.is("MovePhase")) && phaseForcedSlower(phase, target, !!globalScene.arena.getTag(ArenaTagType.TRICK_ROOM)) || (phase.is("MovePhase")) && phaseForcedSlower(phase, target, !!globalScene.arena.getTag(ArenaTagType.TRICK_ROOM))
); );
if (prependPhase) { if (prependPhase) {
globalScene.phaseQueue.splice( globalScene.phaseManager.phaseQueue.splice(
globalScene.phaseQueue.indexOf(prependPhase), globalScene.phaseManager.phaseQueue.indexOf(prependPhase),
0, 0,
new MovePhase(target, [ ...targetMovePhase.targets ], targetMovePhase.move, false, false, false, true) 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)); globalScene.getField(true).map(p=>applyAbAttrs(FieldPreventExplosiveMovesAbAttr, p, cancelled));
// Queue a message if an ability prevented usage of the move // Queue a message if an ability prevented usage of the move
if (cancelled.value) { 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; 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 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 failIfLastInPartyCondition: MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => {
const party: Pokemon[] = user.isPlayer() ? globalScene.getPlayerParty() : globalScene.getEnemyParty(); 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)]; const type = validTypes[user.randBattleSeedInt(validTypes.length)];
user.summonData.types = [ type ]; 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(); user.updateInfo();
return true; return true;
@ -8166,7 +8166,7 @@ export class ExposedMoveAttr extends AddBattlerTagAttr {
return false; 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; return true;
} }
@ -8802,7 +8802,7 @@ export function initMoves() {
.reflectable(), .reflectable(),
new SelfStatusMove(MoveId.BELLY_DRUM, PokemonType.NORMAL, -1, 10, -1, 0, 2) new SelfStatusMove(MoveId.BELLY_DRUM, PokemonType.NORMAL, -1, 10, -1, 0, 2)
.attr(CutHpStatStageBoostAttr, [ Stat.ATK ], 12, 2, (user) => { .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) new AttackMove(MoveId.SLUDGE_BOMB, PokemonType.POISON, MoveCategory.SPECIAL, 90, 100, 10, 30, 0, 2)
.attr(StatusEffectAttr, StatusEffect.POISON) .attr(StatusEffectAttr, StatusEffect.POISON)
@ -10370,7 +10370,7 @@ export function initMoves() {
.attr(HealStatusEffectAttr, true, StatusEffect.FREEZE) .attr(HealStatusEffectAttr, true, StatusEffect.FREEZE)
.attr(AddBattlerTagAttr, BattlerTagType.BURNED_UP, true, false) .attr(AddBattlerTagAttr, BattlerTagType.BURNED_UP, true, false)
.attr(RemoveTypeAttr, PokemonType.FIRE, (user) => { .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) new StatusMove(MoveId.SPEED_SWAP, PokemonType.PSYCHIC, -1, 10, -1, 0, 7)
.attr(SwapStatAttr, Stat.SPD) .attr(SwapStatAttr, Stat.SPD)
@ -11154,7 +11154,7 @@ export function initMoves() {
}) })
.attr(AddBattlerTagAttr, BattlerTagType.DOUBLE_SHOCKED, true, false) .attr(AddBattlerTagAttr, BattlerTagType.DOUBLE_SHOCKED, true, false)
.attr(RemoveTypeAttr, PokemonType.ELECTRIC, (user) => { .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) new AttackMove(MoveId.GIGATON_HAMMER, PokemonType.STEEL, MoveCategory.PHYSICAL, 160, 100, 5, -1, 0, 9)
.makesContact(false) .makesContact(false)

View File

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

View File

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

View File

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

View File

@ -237,7 +237,7 @@ export const BerriesAboundEncounter: MysteryEncounter = MysteryEncounterBuilder.
config.pokemonConfigs![0].tags = [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON]; config.pokemonConfigs![0].tags = [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON];
config.pokemonConfigs![0].mysteryEncounterBattleEffects = (pokemon: Pokemon) => { config.pokemonConfigs![0].mysteryEncounterBattleEffects = (pokemon: Pokemon) => {
queueEncounterMessage(`${namespace}:option.2.boss_enraged`); queueEncounterMessage(`${namespace}:option.2.boss_enraged`);
globalScene.unshiftPhase( globalScene.phaseManager.unshiftPhase(
new StatStageChangePhase(pokemon.getBattlerIndex(), true, statChangesForBattle, 1), 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 // Option select complete, handle if they are learning a move
if (result && result.selectedOptionIndex < moveOptions.length) { if (result && result.selectedOptionIndex < moveOptions.length) {
globalScene.unshiftPhase( globalScene.phaseManager.unshiftPhase(
new LearnMovePhase(result.selectedPokemonIndex, moveOptions[result.selectedOptionIndex].moveId), 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], tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON],
mysteryEncounterBattleEffects: (pokemon: Pokemon) => { mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
queueEncounterMessage(`${namespace}:option.1.boss_enraged`); queueEncounterMessage(`${namespace}:option.1.boss_enraged`);
globalScene.unshiftPhase( globalScene.phaseManager.unshiftPhase(
new StatStageChangePhase( new StatStageChangePhase(
pokemon.getBattlerIndex(), pokemon.getBattlerIndex(),
true, true,
@ -245,7 +245,7 @@ export const DancingLessonsEncounter: MysteryEncounter = MysteryEncounterBuilder
const onPokemonSelected = (pokemon: PlayerPokemon) => { const onPokemonSelected = (pokemon: PlayerPokemon) => {
encounter.setDialogueToken("selectedPokemon", pokemon.getNameToRender()); encounter.setDialogueToken("selectedPokemon", pokemon.getNameToRender());
globalScene.unshiftPhase( globalScene.phaseManager.unshiftPhase(
new LearnMovePhase(globalScene.getPlayerParty().indexOf(pokemon), MoveId.REVELATION_DANCE), new LearnMovePhase(globalScene.getPlayerParty().indexOf(pokemon), MoveId.REVELATION_DANCE),
); );

View File

@ -165,7 +165,7 @@ export const DarkDealEncounter: MysteryEncounter = MysteryEncounterBuilder.withE
.withOptionPhase(async () => { .withOptionPhase(async () => {
// Give the player 5 Rogue Balls // Give the player 5 Rogue Balls
const encounter = globalScene.currentBattle.mysteryEncounter!; 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 // 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 // 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()); return !(existingCharm && existingCharm.getStackCount() >= existingCharm.getMaxStackCount());
}); });
if (candidates.length > 0) { if (candidates.length > 0) {
globalScene.unshiftPhase(new ModifierRewardPhase(modifierTypes[randSeedItem(candidates)])); globalScene.phaseManager.unshiftPhase(new ModifierRewardPhase(modifierTypes[randSeedItem(candidates)]));
} else { } else {
// At max stacks, give a Voucher instead // 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(); doEventReward();
} else { } else {
globalScene.unshiftPhase(new ModifierRewardPhase(modifierTypes.AMULET_COIN)); globalScene.phaseManager.unshiftPhase(new ModifierRewardPhase(modifierTypes.AMULET_COIN));
doEventReward(); doEventReward();
} }
@ -266,7 +266,7 @@ export const DelibirdyEncounter: MysteryEncounter = MysteryEncounterBuilder.with
); );
doEventReward(); doEventReward();
} else { } else {
globalScene.unshiftPhase(new ModifierRewardPhase(modifierTypes.CANDY_JAR)); globalScene.phaseManager.unshiftPhase(new ModifierRewardPhase(modifierTypes.CANDY_JAR));
doEventReward(); doEventReward();
} }
} else { } else {
@ -288,7 +288,7 @@ export const DelibirdyEncounter: MysteryEncounter = MysteryEncounterBuilder.with
); );
doEventReward(); doEventReward();
} else { } else {
globalScene.unshiftPhase(new ModifierRewardPhase(modifierTypes.BERRY_POUCH)); globalScene.phaseManager.unshiftPhase(new ModifierRewardPhase(modifierTypes.BERRY_POUCH));
doEventReward(); doEventReward();
} }
} }
@ -372,7 +372,7 @@ export const DelibirdyEncounter: MysteryEncounter = MysteryEncounterBuilder.with
); );
doEventReward(); doEventReward();
} else { } else {
globalScene.unshiftPhase(new ModifierRewardPhase(modifierTypes.HEALING_CHARM)); globalScene.phaseManager.unshiftPhase(new ModifierRewardPhase(modifierTypes.HEALING_CHARM));
doEventReward(); doEventReward();
} }

View File

@ -92,7 +92,7 @@ export const FieryFalloutEncounter: MysteryEncounter = MysteryEncounterBuilder.w
gender: Gender.MALE, gender: Gender.MALE,
tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON], tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON],
mysteryEncounterBattleEffects: (pokemon: Pokemon) => { mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
globalScene.unshiftPhase( globalScene.phaseManager.unshiftPhase(
new StatStageChangePhase(pokemon.getBattlerIndex(), true, [Stat.SPDEF, Stat.SPD], 1), new StatStageChangePhase(pokemon.getBattlerIndex(), true, [Stat.SPDEF, Stat.SPD], 1),
); );
}, },
@ -103,7 +103,7 @@ export const FieryFalloutEncounter: MysteryEncounter = MysteryEncounterBuilder.w
gender: Gender.FEMALE, gender: Gender.FEMALE,
tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON], tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON],
mysteryEncounterBattleEffects: (pokemon: Pokemon) => { mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
globalScene.unshiftPhase( globalScene.phaseManager.unshiftPhase(
new StatStageChangePhase(pokemon.getBattlerIndex(), true, [Stat.SPDEF, Stat.SPD], 1), 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`); queueEncounterMessage(`${namespace}:option.1.stat_boost`);
// Randomly boost 1 stat 2 stages // Randomly boost 1 stat 2 stages
// Cannot boost Spd, Acc, or Evasion // 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(); pokemon.resetSummonData();
globalScene.time.delayedCall(1000, () => { globalScene.time.delayedCall(1000, () => {
if (pokemon.isShiny()) { if (pokemon.isShiny()) {
globalScene.unshiftPhase(new ShinySparklePhase(pokemon.getBattlerIndex())); globalScene.phaseManager.unshiftPhase(new ShinySparklePhase(pokemon.getBattlerIndex()));
} }
pokemon.resetTurnData(); pokemon.resetTurnData();
globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeActiveTrigger, true); globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeActiveTrigger, true);
globalScene.pushPhase(new PostSummonPhase(pokemon.getBattlerIndex())); globalScene.phaseManager.pushPhase(new PostSummonPhase(pokemon.getBattlerIndex()));
resolve(); resolve();
}); });
}, },

View File

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

View File

@ -276,7 +276,7 @@ async function summonSafariPokemon() {
const encounter = globalScene.currentBattle.mysteryEncounter!; const encounter = globalScene.currentBattle.mysteryEncounter!;
// Message pokemon remaining // Message pokemon remaining
encounter.setDialogueToken("remainingCount", encounter.misc.safariPokemonRemaining); 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 // 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 // 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.pokemon = pokemon;
encounter.misc.safariPokemonRemaining -= 1; encounter.misc.safariPokemonRemaining -= 1;
globalScene.unshiftPhase(new SummonPhase(0, false)); globalScene.phaseManager.unshiftPhase(new SummonPhase(0, false));
encounter.setDialogueToken("pokemonName", getPokemonNameWithAffix(pokemon)); encounter.setDialogueToken("pokemonName", getPokemonNameWithAffix(pokemon));
@ -336,7 +336,7 @@ async function summonSafariPokemon() {
const ivScannerModifier = globalScene.findModifier(m => m instanceof IvScannerModifier); const ivScannerModifier = globalScene.findModifier(m => m instanceof IvScannerModifier);
if (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); leaveEncounterWithoutBattle(true);
} }
} else { } else {
globalScene.queueMessage(getEncounterText(`${namespace}:safari.watching`) ?? "", 0, null, 1000); globalScene.phaseManager.queueMessage(getEncounterText(`${namespace}:safari.watching`) ?? "", 0, null, 1000);
initSubsequentOptionSelect({ initSubsequentOptionSelect({
overrideOptions: safariZoneGameOptions, overrideOptions: safariZoneGameOptions,
startingCursorIndex: cursorIndex, startingCursorIndex: cursorIndex,

View File

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

View File

@ -227,7 +227,9 @@ async function doBiomeTransitionDialogueAndBattleInit() {
tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON], tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON],
mysteryEncounterBattleEffects: (pokemon: Pokemon) => { mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
queueEncounterMessage(`${namespace}:boss_enraged`); 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); globalScene.playBgm(globalScene.arena.bgm);
// Clear any leftover battle phases // Clear any leftover battle phases
globalScene.clearPhaseQueue(); globalScene.phaseManager.clearPhaseQueue();
globalScene.clearPhaseQueueSplice(); globalScene.phaseManager.clearPhaseQueueSplice();
// Return enemy Pokemon // Return enemy Pokemon
const pokemon = globalScene.getEnemyPokemon(); const pokemon = globalScene.getEnemyPokemon();

View File

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

View File

@ -143,7 +143,7 @@ export const TheWinstrateChallengeEncounter: MysteryEncounter = MysteryEncounter
}, },
async () => { async () => {
// Refuse the challenge, they full heal the party and give the player a Rarer Candy // 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({ setEncounterRewards({
guaranteedModifierTypeFuncs: [modifierTypes.RARER_CANDY], guaranteedModifierTypeFuncs: [modifierTypes.RARER_CANDY],
fillRemaining: false, fillRemaining: false,
@ -209,7 +209,7 @@ function endTrainerBattleAndShowDialogue(): Promise<void> {
for (const pokemon of playerField) { for (const pokemon of playerField) {
pokemon.lapseTag(BattlerTagType.COMMANDED); 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()) { for (const pokemon of globalScene.getPlayerParty()) {
// Only trigger form change when Eiscue is in Noice form // Only trigger form change when Eiscue is in Noice form
@ -227,7 +227,7 @@ function endTrainerBattleAndShowDialogue(): Promise<void> {
applyPostBattleInitAbAttrs(PostBattleInitAbAttr, pokemon); applyPostBattleInitAbAttrs(PostBattleInitAbAttr, pokemon);
} }
globalScene.unshiftPhase(new ShowTrainerPhase()); globalScene.phaseManager.unshiftPhase(new ShowTrainerPhase());
// Hide the trainer and init next battle // Hide the trainer and init next battle
const trainer = globalScene.currentBattle.trainer; const trainer = globalScene.currentBattle.trainer;
// Unassign previous trainer from battle so it isn't destroyed before animation completes // 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], tags: [BattlerTagType.MYSTERY_ENCOUNTER_POST_SUMMON],
mysteryEncounterBattleEffects: (pokemon: Pokemon) => { mysteryEncounterBattleEffects: (pokemon: Pokemon) => {
queueEncounterMessage(`${namespace}:option.1.stat_boost`); queueEncounterMessage(`${namespace}:option.1.stat_boost`);
globalScene.unshiftPhase( globalScene.phaseManager.unshiftPhase(
new StatStageChangePhase(pokemon.getBattlerIndex(), true, statChangesForBattle, 1), 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 { export function queueEncounterMessage(contentKey: string): void {
const text: string | null = getEncounterText(contentKey); 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); console.log("Moveset:", moveset);
}); });
globalScene.pushPhase(new MysteryEncounterBattlePhase(partyConfig.disableSwitch)); globalScene.phaseManager.pushPhase(new MysteryEncounterBattlePhase(partyConfig.disableSwitch));
await Promise.all(loadEnemyAssets); await Promise.all(loadEnemyAssets);
battle.enemyParty.forEach((enemyPokemon_2, e_1) => { battle.enemyParty.forEach((enemyPokemon_2, e_1) => {
@ -480,7 +480,7 @@ export function updatePlayerMoney(changeValue: number, playSound = true, showMes
} }
if (showMessage) { if (showMessage) {
if (changeValue < 0) { if (changeValue < 0) {
globalScene.queueMessage( globalScene.phaseManager.queueMessage(
i18next.t("mysteryEncounterMessages:paid_money", { i18next.t("mysteryEncounterMessages:paid_money", {
amount: -changeValue, amount: -changeValue,
}), }),
@ -488,7 +488,7 @@ export function updatePlayerMoney(changeValue: number, playSound = true, showMes
true, true,
); );
} else { } else {
globalScene.queueMessage( globalScene.phaseManager.queueMessage(
i18next.t("mysteryEncounterMessages:receive_money", { i18next.t("mysteryEncounterMessages:receive_money", {
amount: changeValue, amount: changeValue,
}), }),
@ -767,9 +767,9 @@ export function setEncounterRewards(
} }
if (customShopRewards) { if (customShopRewards) {
globalScene.unshiftPhase(new SelectModifierPhase(0, undefined, customShopRewards)); globalScene.phaseManager.unshiftPhase(new SelectModifierPhase(0, undefined, customShopRewards));
} else { } else {
globalScene.tryRemovePhase(p => p.is("MysteryEncounterRewardsPhase")); globalScene.phaseManager.tryRemovePhase(p => p.is("MysteryEncounterRewardsPhase"));
} }
if (eggRewards) { if (eggRewards) {
@ -807,7 +807,7 @@ export function setEncounterExp(participantId: number | number[], baseExpValue:
const participantIds = Array.isArray(participantId) ? participantId : [participantId]; const participantIds = Array.isArray(participantId) ? participantId : [participantId];
globalScene.currentBattle.mysteryEncounter!.doEncounterExp = () => { 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; return true;
}; };
@ -829,7 +829,7 @@ export class OptionSelectSettings {
* @param optionSelectSettings * @param optionSelectSettings
*/ */
export function initSubsequentOptionSelect(optionSelectSettings: 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, encounterMode: MysteryEncounterMode = MysteryEncounterMode.NO_BATTLE,
) { ) {
globalScene.currentBattle.mysteryEncounter!.encounterMode = encounterMode; globalScene.currentBattle.mysteryEncounter!.encounterMode = encounterMode;
globalScene.clearPhaseQueue(); globalScene.phaseManager.clearPhaseQueue();
globalScene.clearPhaseQueueSplice(); globalScene.phaseManager.clearPhaseQueueSplice();
handleMysteryEncounterVictory(addHealPhase); handleMysteryEncounterVictory(addHealPhase);
} }
@ -857,8 +857,8 @@ export function handleMysteryEncounterVictory(addHealPhase = false, doNotContinu
const allowedPkm = globalScene.getPlayerParty().filter(pkm => pkm.isAllowedInBattle()); const allowedPkm = globalScene.getPlayerParty().filter(pkm => pkm.isAllowedInBattle());
if (allowedPkm.length === 0) { if (allowedPkm.length === 0) {
globalScene.clearPhaseQueue(); globalScene.phaseManager.clearPhaseQueue();
globalScene.unshiftPhase(new GameOverPhase()); globalScene.phaseManager.unshiftPhase(new GameOverPhase());
return; return;
} }
@ -869,8 +869,8 @@ export function handleMysteryEncounterVictory(addHealPhase = false, doNotContinu
return; return;
} }
if (encounter.encounterMode === MysteryEncounterMode.NO_BATTLE) { if (encounter.encounterMode === MysteryEncounterMode.NO_BATTLE) {
globalScene.pushPhase(new MysteryEncounterRewardsPhase(addHealPhase)); globalScene.phaseManager.pushPhase(new MysteryEncounterRewardsPhase(addHealPhase));
globalScene.pushPhase(new EggLapsePhase()); globalScene.phaseManager.pushPhase(new EggLapsePhase());
} else if ( } else if (
!globalScene !globalScene
.getEnemyParty() .getEnemyParty()
@ -878,15 +878,15 @@ export function handleMysteryEncounterVictory(addHealPhase = false, doNotContinu
encounter.encounterMode !== MysteryEncounterMode.TRAINER_BATTLE ? p.isOnField() : !p?.isFainted(true), 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) { 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)) { if (globalScene.gameMode.isEndless || !globalScene.gameMode.isWaveFinal(globalScene.currentBattle.waveIndex)) {
globalScene.pushPhase(new MysteryEncounterRewardsPhase(addHealPhase)); globalScene.phaseManager.pushPhase(new MysteryEncounterRewardsPhase(addHealPhase));
if (!encounter.doContinueEncounter) { if (!encounter.doContinueEncounter) {
// Only lapse eggs once for multi-battle encounters // 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()); const allowedPkm = globalScene.getPlayerParty().filter(pkm => pkm.isAllowedInBattle());
if (allowedPkm.length === 0) { if (allowedPkm.length === 0) {
globalScene.clearPhaseQueue(); globalScene.phaseManager.clearPhaseQueue();
globalScene.unshiftPhase(new GameOverPhase()); globalScene.phaseManager.unshiftPhase(new GameOverPhase());
return; return;
} }
@ -912,14 +912,14 @@ export function handleMysteryEncounterBattleFailed(addHealPhase = false, doNotCo
return; return;
} }
if (encounter.encounterMode !== MysteryEncounterMode.NO_BATTLE) { 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) { if (!encounter.doContinueEncounter) {
// Only lapse eggs once for multi-battle encounters // 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 { } else {
source = globalScene.getEnemyField()[0]; source = globalScene.getEnemyField()[0];
} }
globalScene.phaseManager.pushPhase(
// @ts-ignore: source cannot be undefined // @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. // Pseudo turn end phase to reset flinch states, Endure, etc.
globalScene.pushPhase(new MysteryEncounterBattleStartCleanupPhase()); globalScene.phaseManager.pushPhase(new MysteryEncounterBattleStartCleanupPhase());
encounter.startOfBattleEffectsComplete = true; encounter.startOfBattleEffectsComplete = true;
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -68,7 +68,7 @@ export class EncounterPhase extends BattlePhase {
// Failsafe if players somehow skip floor 200 in classic mode // Failsafe if players somehow skip floor 200 in classic mode
if (globalScene.gameMode.isClassic && globalScene.currentBattle.waveIndex > 200) { if (globalScene.gameMode.isClassic && globalScene.currentBattle.waveIndex > 200) {
globalScene.unshiftPhase(new GameOverPhase()); globalScene.phaseManager.unshiftPhase(new GameOverPhase());
} }
const loadEnemyAssets: Promise<void>[] = []; const loadEnemyAssets: Promise<void>[] = [];
@ -438,9 +438,9 @@ export class EncounterPhase extends BattlePhase {
const doTrainerSummon = () => { const doTrainerSummon = () => {
this.hideEnemyTrainer(); this.hideEnemyTrainer();
const availablePartyMembers = globalScene.getEnemyParty().filter(p => !p.isFainted()).length; 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) { if (globalScene.currentBattle.double && availablePartyMembers > 1) {
globalScene.unshiftPhase(new SummonPhase(1, false)); globalScene.phaseManager.unshiftPhase(new SummonPhase(1, false));
} }
this.end(); this.end();
}; };
@ -496,7 +496,7 @@ export class EncounterPhase extends BattlePhase {
globalScene.ui.clearText(); globalScene.ui.clearText();
globalScene.ui.getMessageHandler().hideNameText(); globalScene.ui.getMessageHandler().hideNameText();
globalScene.unshiftPhase(new MysteryEncounterPhase()); globalScene.phaseManager.unshiftPhase(new MysteryEncounterPhase());
this.end(); this.end();
}; };
@ -554,7 +554,7 @@ export class EncounterPhase extends BattlePhase {
enemyField.forEach((enemyPokemon, e) => { enemyField.forEach((enemyPokemon, e) => {
if (enemyPokemon.isShiny(true)) { 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 */ /** This sets Eternatus' held item to be untransferrable, preventing it from being stolen */
if ( if (
@ -576,7 +576,7 @@ export class EncounterPhase extends BattlePhase {
if (![BattleType.TRAINER, BattleType.MYSTERY_ENCOUNTER].includes(globalScene.currentBattle.battleType)) { if (![BattleType.TRAINER, BattleType.MYSTERY_ENCOUNTER].includes(globalScene.currentBattle.battleType)) {
enemyField.map(p => 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 there is not a player party, we can't continue
if (!globalScene.getPlayerParty().length) { if (!globalScene.getPlayerParty().length) {
return false; return false;
@ -594,7 +594,7 @@ export class EncounterPhase extends BattlePhase {
); );
const ivScannerModifier = globalScene.findModifier(m => m instanceof IvScannerModifier); const ivScannerModifier = globalScene.findModifier(m => m instanceof IvScannerModifier);
if (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(); const availablePartyMembers = globalScene.getPokemonAllowedInBattle();
if (!availablePartyMembers[0].isOnField()) { if (!availablePartyMembers[0].isOnField()) {
globalScene.pushPhase(new SummonPhase(0)); globalScene.phaseManager.pushPhase(new SummonPhase(0));
} }
if (globalScene.currentBattle.double) { if (globalScene.currentBattle.double) {
if (availablePartyMembers.length > 1) { if (availablePartyMembers.length > 1) {
globalScene.pushPhase(new ToggleDoublePositionPhase(true)); globalScene.phaseManager.pushPhase(new ToggleDoublePositionPhase(true));
if (!availablePartyMembers[1].isOnField()) { if (!availablePartyMembers[1].isOnField()) {
globalScene.pushPhase(new SummonPhase(1)); globalScene.phaseManager.pushPhase(new SummonPhase(1));
} }
} }
} else { } else {
if (availablePartyMembers.length > 1 && availablePartyMembers[1].isOnField()) { 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 ( if (
@ -625,9 +625,9 @@ export class EncounterPhase extends BattlePhase {
) { ) {
const minPartySize = globalScene.currentBattle.double ? 2 : 1; const minPartySize = globalScene.currentBattle.double ? 2 : 1;
if (availablePartyMembers.length > minPartySize) { 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) { 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); SoundFade.fadeOut(globalScene, this.evolutionBgm, 100);
globalScene.unshiftPhase(new EndEvolutionPhase()); globalScene.phaseManager.unshiftPhase(new EndEvolutionPhase());
globalScene.ui.showText( globalScene.ui.showText(
i18next.t("menu:stoppedEvolving", { i18next.t("menu:stoppedEvolving", {
@ -355,9 +355,11 @@ export class EvolutionPhase extends Phase {
.getLevelMoves(this.lastLevel + 1, true, false, false, learnSituation) .getLevelMoves(this.lastLevel + 1, true, false, false, learnSituation)
.filter(lm => lm[0] === EVOLVE_MOVE); .filter(lm => lm[0] === EVOLVE_MOVE);
for (const lm of levelMoves) { 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"); globalScene.playSound("se/shine");
this.doSpray(); this.doSpray();

View File

@ -34,7 +34,7 @@ export class ExpPhase extends PlayerPartyMemberPokemonPhase {
pokemon.addExp(exp.value); pokemon.addExp(exp.value);
const newLevel = pokemon.level; const newLevel = pokemon.level;
if (newLevel > lastLevel) { 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()); 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", { i18next.t("battle:fainted", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}), }),
@ -166,7 +166,7 @@ export class FaintPhase extends PokemonPhase {
const legalPlayerPartyPokemon = legalPlayerPokemon.filter(p => !p.isActive(true)); const legalPlayerPartyPokemon = legalPlayerPokemon.filter(p => !p.isActive(true));
if (!legalPlayerPokemon.length) { if (!legalPlayerPokemon.length) {
/** If the player doesn't have any legal Pokemon, end the game */ /** If the player doesn't have any legal Pokemon, end the game */
globalScene.unshiftPhase(new GameOverPhase()); globalScene.phaseManager.unshiftPhase(new GameOverPhase());
} else if ( } else if (
globalScene.currentBattle.double && globalScene.currentBattle.double &&
legalPlayerPokemon.length === 1 && 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 * 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. * 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) { } else if (legalPlayerPartyPokemon.length > 0) {
/** /**
* If previous conditions weren't met, and the player has at least 1 legal Pokemon off the field, * 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. * 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 { } else {
globalScene.unshiftPhase(new VictoryPhase(this.battlerIndex)); globalScene.phaseManager.unshiftPhase(new VictoryPhase(this.battlerIndex));
if ([BattleType.TRAINER, BattleType.MYSTERY_ENCOUNTER].includes(globalScene.currentBattle.battleType)) { if ([BattleType.TRAINER, BattleType.MYSTERY_ENCOUNTER].includes(globalScene.currentBattle.battleType)) {
const hasReservePartyMember = !!globalScene const hasReservePartyMember = !!globalScene
.getEnemyParty() .getEnemyParty()
.filter(p => p.isActive() && !p.isOnField() && p.trainerSlot === (pokemon as EnemyPokemon).trainerSlot) .filter(p => p.isActive() && !p.isOnField() && p.trainerSlot === (pokemon as EnemyPokemon).trainerSlot)
.length; .length;
if (hasReservePartyMember) { 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 { } else {
// Final boss' HP threshold has been bypassed; cancel faint and force check for 2nd phase // Final boss' HP threshold has been bypassed; cancel faint and force check for 2nd phase
enemy.hp++; enemy.hp++;
globalScene.unshiftPhase(new DamageAnimPhase(enemy.getBattlerIndex(), 0, HitResult.INDIRECT)); globalScene.phaseManager.unshiftPhase(new DamageAnimPhase(enemy.getBattlerIndex(), 0, HitResult.INDIRECT));
this.end(); this.end();
} }
return true; return true;

View File

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

View File

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

View File

@ -66,14 +66,14 @@ export class LevelUpPhase extends PlayerPartyMemberPokemonPhase {
// this feels like an unnecessary optimization // this feels like an unnecessary optimization
const levelMoves = this.getPokemon().getLevelMoves(this.lastLevel + 1); const levelMoves = this.getPokemon().getLevelMoves(this.lastLevel + 1);
for (const lm of levelMoves) { 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) { if (!this.pokemon.pauseEvolutions) {
const evolution = this.pokemon.getEvolution(); const evolution = this.pokemon.getEvolution();
if (evolution) { if (evolution) {
this.pokemon.breakIllusion(); 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(); 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(); this.end();
}, },
], ],
@ -94,7 +94,7 @@ export class LoginPhase extends Phase {
removeCookie(sessionIdKey); removeCookie(sessionIdKey);
globalScene.reset(true, true); globalScene.reset(true, true);
} else { } else {
globalScene.unshiftPhase(new UnavailablePhase()); globalScene.phaseManager.unshiftPhase(new UnavailablePhase());
super.end(); super.end();
} }
return null; return null;
@ -114,7 +114,7 @@ export class LoginPhase extends Phase {
globalScene.ui.setMode(UiMode.MESSAGE); globalScene.ui.setMode(UiMode.MESSAGE);
if (!globalScene.gameData.gender) { if (!globalScene.gameData.gender) {
globalScene.unshiftPhase(new SelectGenderPhase()); globalScene.phaseManager.unshiftPhase(new SelectGenderPhase());
} }
handleTutorial(Tutorial.Intro).then(() => super.end()); 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]); page0 = page0.split(repname[p]).join(pokename[p]);
page1 = page1.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), new MessagePhase(page1, this.callbackDelay, this.prompt, this.promptDelay, this.speaker),
); );
this.text = page0.trim(); this.text = page0.trim();

View File

@ -62,9 +62,9 @@ export class MoveChargePhase extends PokemonPhase {
if (instantCharge.value) { if (instantCharge.value) {
// this MoveEndPhase will be duplicated by the queued MovePhase if not removed // 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 // 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 { } else {
user.getMoveQueue().push({ move: move.id, targets: [this.targetIndex] }); user.getMoveQueue().push({ move: move.id, targets: [this.targetIndex] });
} }

View File

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

View File

@ -268,10 +268,10 @@ export class MovePhase extends BattlePhase {
if (activated) { if (activated) {
this.cancel(); this.cancel();
globalScene.queueMessage( globalScene.phaseManager.queueMessage(
getStatusEffectActivationText(this.pokemon.status.effect, getPokemonNameWithAffix(this.pokemon)), getStatusEffectActivationText(this.pokemon.status.effect, getPokemonNameWithAffix(this.pokemon)),
); );
globalScene.unshiftPhase( globalScene.phaseManager.unshiftPhase(
new CommonAnimPhase( new CommonAnimPhase(
this.pokemon.getBattlerIndex(), this.pokemon.getBattlerIndex(),
undefined, undefined,
@ -279,7 +279,7 @@ export class MovePhase extends BattlePhase {
), ),
); );
} else if (healed) { } else if (healed) {
globalScene.queueMessage( globalScene.phaseManager.queueMessage(
getStatusEffectHealText(this.pokemon.status.effect, getPokemonNameWithAffix(this.pokemon)), getStatusEffectHealText(this.pokemon.status.effect, getPokemonNameWithAffix(this.pokemon)),
); );
this.pokemon.resetStatus(); this.pokemon.resetStatus();
@ -407,7 +407,7 @@ export class MovePhase extends BattlePhase {
if (success) { if (success) {
const move = this.move.getMove(); const move = this.move.getMove();
applyPreAttackAbAttrs(PokemonTypeChangeAbAttr, this.pokemon, null, move); applyPreAttackAbAttrs(PokemonTypeChangeAbAttr, this.pokemon, null, move);
globalScene.unshiftPhase( globalScene.phaseManager.unshiftPhase(
new MoveEffectPhase(this.pokemon.getBattlerIndex(), this.targets, move, this.reflected, this.move.virtual), new MoveEffectPhase(this.pokemon.getBattlerIndex(), this.targets, move, this.reflected, this.move.virtual),
); );
} else { } else {
@ -457,7 +457,9 @@ export class MovePhase extends BattlePhase {
applyPreAttackAbAttrs(PokemonTypeChangeAbAttr, this.pokemon, null, this.move.getMove()); applyPreAttackAbAttrs(PokemonTypeChangeAbAttr, this.pokemon, null, this.move.getMove());
this.showMoveText(); 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 { } else {
this.pokemon.pushMoveHistory({ this.pokemon.pushMoveHistory({
move: this.move.moveId, move: this.move.moveId,
@ -479,7 +481,7 @@ export class MovePhase extends BattlePhase {
* Queues a {@linkcode MoveEndPhase} and then ends the phase * Queues a {@linkcode MoveEndPhase} and then ends the phase
*/ */
public end(): void { public end(): void {
globalScene.unshiftPhase( globalScene.phaseManager.unshiftPhase(
new MoveEndPhase(this.pokemon.getBattlerIndex(), this.getActiveTargetPokemon(), this.followUp), new MoveEndPhase(this.pokemon.getBattlerIndex(), this.getActiveTargetPokemon(), this.followUp),
); );
@ -545,12 +547,12 @@ export class MovePhase extends BattlePhase {
if (this.pokemon.hasAbilityWithAttr(BlockRedirectAbAttr)) { if (this.pokemon.hasAbilityWithAttr(BlockRedirectAbAttr)) {
redirectTarget.value = currentTarget; redirectTarget.value = currentTarget;
// TODO: Ability displays should be handled by the ability // TODO: Ability displays should be handled by the ability
globalScene.queueAbilityDisplay( globalScene.phaseManager.queueAbilityDisplay(
this.pokemon, this.pokemon,
this.pokemon.getPassiveAbility().hasAttr(BlockRedirectAbAttr), this.pokemon.getPassiveAbility().hasAttr(BlockRedirectAbAttr),
true, true,
); );
globalScene.queueAbilityDisplay( globalScene.phaseManager.queueAbilityDisplay(
this.pokemon, this.pokemon,
this.pokemon.getPassiveAbility().hasAttr(BlockRedirectAbAttr), this.pokemon.getPassiveAbility().hasAttr(BlockRedirectAbAttr),
false, false,
@ -649,7 +651,7 @@ export class MovePhase extends BattlePhase {
return; return;
} }
globalScene.queueMessage( globalScene.phaseManager.queueMessage(
i18next.t(this.reflected ? "battle:magicCoatActivated" : "battle:useMove", { i18next.t(this.reflected ? "battle:magicCoatActivated" : "battle:useMove", {
pokemonNameWithAffix: getPokemonNameWithAffix(this.pokemon), pokemonNameWithAffix: getPokemonNameWithAffix(this.pokemon),
moveName: this.move.getName(), moveName: this.move.getName(),
@ -660,6 +662,6 @@ export class MovePhase extends BattlePhase {
} }
public showFailedText(failedText: string = i18next.t("battle:attackFailed")): void { 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(); super.start();
// Clears out queued phases that are part of standard battle // Clears out queued phases that are part of standard battle
globalScene.clearPhaseQueue(); globalScene.phaseManager.clearPhaseQueue();
globalScene.clearPhaseQueueSplice(); globalScene.phaseManager.clearPhaseQueueSplice();
const encounter = globalScene.currentBattle.mysteryEncounter!; const encounter = globalScene.currentBattle.mysteryEncounter!;
encounter.updateSeedOffset(); encounter.updateSeedOffset();
@ -124,7 +124,7 @@ export class MysteryEncounterPhase extends Phase {
*/ */
continueEncounter() { continueEncounter() {
const endDialogueAndContinueEncounter = () => { const endDialogueAndContinueEncounter = () => {
globalScene.pushPhase(new MysteryEncounterOptionSelectedPhase()); globalScene.phaseManager.pushPhase(new MysteryEncounterOptionSelectedPhase());
this.end(); this.end();
}; };
@ -247,8 +247,8 @@ export class MysteryEncounterBattleStartCleanupPhase extends Phase {
}); });
// Remove any status tick phases // Remove any status tick phases
while (globalScene.findPhase(p => p.is("PostTurnStatusEffectPhase"))) { while (globalScene.phaseManager.findPhase(p => p.is("PostTurnStatusEffectPhase"))) {
globalScene.tryRemovePhase(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 // 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 // The total number of legal player Pokemon that aren't currently on the field
const legalPlayerPartyPokemon = legalPlayerPokemon.filter(p => !p.isActive(true)); const legalPlayerPartyPokemon = legalPlayerPokemon.filter(p => !p.isActive(true));
if (!legalPlayerPokemon.length) { if (!legalPlayerPokemon.length) {
globalScene.unshiftPhase(new GameOverPhase()); globalScene.phaseManager.unshiftPhase(new GameOverPhase());
return this.end(); return this.end();
} }
@ -265,13 +265,13 @@ export class MysteryEncounterBattleStartCleanupPhase extends Phase {
const playerField = globalScene.getPlayerField(); const playerField = globalScene.getPlayerField();
playerField.forEach((pokemon, i) => { playerField.forEach((pokemon, i) => {
if (!pokemon.isAllowedInBattle() && legalPlayerPartyPokemon.length > 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 // 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) { if (globalScene.currentBattle.double && legalPlayerPokemon.length === 1 && legalPlayerPartyPokemon.length === 0) {
globalScene.unshiftPhase(new ToggleDoublePositionPhase(true)); globalScene.phaseManager.unshiftPhase(new ToggleDoublePositionPhase(true));
} }
this.end(); this.end();
@ -348,9 +348,9 @@ export class MysteryEncounterBattlePhase extends Phase {
globalScene.playBgm(); globalScene.playBgm();
} }
const availablePartyMembers = globalScene.getEnemyParty().filter(p => !p.isFainted()).length; 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) { if (globalScene.currentBattle.double && availablePartyMembers > 1) {
globalScene.unshiftPhase(new SummonPhase(1, false)); globalScene.phaseManager.unshiftPhase(new SummonPhase(1, false));
} }
if (!globalScene.currentBattle.mysteryEncounter?.hideBattleIntroMessage) { if (!globalScene.currentBattle.mysteryEncounter?.hideBattleIntroMessage) {
@ -368,9 +368,9 @@ export class MysteryEncounterBattlePhase extends Phase {
const doTrainerSummon = () => { const doTrainerSummon = () => {
this.hideEnemyTrainer(); this.hideEnemyTrainer();
const availablePartyMembers = globalScene.getEnemyParty().filter(p => !p.isFainted()).length; 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) { if (globalScene.currentBattle.double && availablePartyMembers > 1) {
globalScene.unshiftPhase(new SummonPhase(1, false)); globalScene.phaseManager.unshiftPhase(new SummonPhase(1, false));
} }
this.endBattleSetup(); this.endBattleSetup();
}; };
@ -426,37 +426,37 @@ export class MysteryEncounterBattlePhase extends Phase {
if (encounterMode !== MysteryEncounterMode.TRAINER_BATTLE) { if (encounterMode !== MysteryEncounterMode.TRAINER_BATTLE) {
const ivScannerModifier = globalScene.findModifier(m => m instanceof IvScannerModifier); const ivScannerModifier = globalScene.findModifier(m => m instanceof IvScannerModifier);
if (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()); const availablePartyMembers = globalScene.getPlayerParty().filter(p => p.isAllowedInBattle());
if (!availablePartyMembers[0].isOnField()) { if (!availablePartyMembers[0].isOnField()) {
globalScene.pushPhase(new SummonPhase(0)); globalScene.phaseManager.pushPhase(new SummonPhase(0));
} }
if (globalScene.currentBattle.double) { if (globalScene.currentBattle.double) {
if (availablePartyMembers.length > 1) { if (availablePartyMembers.length > 1) {
globalScene.pushPhase(new ToggleDoublePositionPhase(true)); globalScene.phaseManager.pushPhase(new ToggleDoublePositionPhase(true));
if (!availablePartyMembers[1].isOnField()) { if (!availablePartyMembers[1].isOnField()) {
globalScene.pushPhase(new SummonPhase(1)); globalScene.phaseManager.pushPhase(new SummonPhase(1));
} }
} }
} else { } else {
if (availablePartyMembers.length > 1 && availablePartyMembers[1].isOnField()) { if (availablePartyMembers.length > 1 && availablePartyMembers[1].isOnField()) {
globalScene.getPlayerField().forEach(pokemon => pokemon.lapseTag(BattlerTagType.COMMANDED)); 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) { if (encounterMode !== MysteryEncounterMode.TRAINER_BATTLE && !this.disableSwitch) {
const minPartySize = globalScene.currentBattle.double ? 2 : 1; const minPartySize = globalScene.currentBattle.double ? 2 : 1;
if (availablePartyMembers.length > minPartySize) { 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) { 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) { if (encounter.doEncounterRewards) {
encounter.doEncounterRewards(); encounter.doEncounterRewards();
} else if (this.addHealPhase) { } else if (this.addHealPhase) {
globalScene.tryRemovePhase(p => p.is("SelectModifierPhase")); globalScene.phaseManager.tryRemovePhase(p => p.is("SelectModifierPhase"));
globalScene.unshiftPhase( globalScene.phaseManager.unshiftPhase(
new SelectModifierPhase(0, undefined, { new SelectModifierPhase(0, undefined, {
fillRemaining: false, fillRemaining: false,
rerollMultiplier: -1, rerollMultiplier: -1,
@ -571,7 +571,7 @@ export class MysteryEncounterRewardsPhase extends Phase {
); );
} }
globalScene.pushPhase(new PostMysteryEncounterPhase()); globalScene.phaseManager.pushPhase(new PostMysteryEncounterPhase());
this.end(); this.end();
} }
} }
@ -618,10 +618,10 @@ export class PostMysteryEncounterPhase extends Phase {
continueEncounter() { continueEncounter() {
const endPhase = () => { const endPhase = () => {
if (globalScene.gameMode.hasRandomBiomes || globalScene.isNewBiome()) { 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(); this.end();
}; };

View File

@ -7,9 +7,11 @@ export class NewBattlePhase extends BattlePhase {
super.start(); super.start();
// cull any extra `NewBattle` phases from the queue. // 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. // `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(); globalScene.newBattle();

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -28,12 +28,12 @@ export class SelectTargetPhase extends PokemonPhase {
const errorMessage = user const errorMessage = user
.getRestrictingTag(move!, user, fieldSide[targets[0]])! .getRestrictingTag(move!, user, fieldSide[targets[0]])!
.selectionDeniedText(user, moveObject.id); .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 = []; targets = [];
} }
if (targets.length < 1) { if (targets.length < 1) {
globalScene.currentBattle.turnCommands[this.fieldIndex] = null; globalScene.currentBattle.turnCommands[this.fieldIndex] = null;
globalScene.unshiftPhase(new CommandPhase(this.fieldIndex)); globalScene.phaseManager.unshiftPhase(new CommandPhase(this.fieldIndex));
} else { } else {
turnCommand!.targets = targets; //TODO: is the bang correct here? 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 the bar is already out, hide it before showing the new one
if (globalScene.abilityBar.isVisible()) { if (globalScene.abilityBar.isVisible()) {
globalScene.unshiftPhase(new HideAbilityPhase()); globalScene.phaseManager.unshiftPhase(new HideAbilityPhase());
globalScene.unshiftPhase(new ShowAbilityPhase(this.battlerIndex, this.passive)); globalScene.phaseManager.unshiftPhase(new ShowAbilityPhase(this.battlerIndex, this.passive));
return this.end(); return this.end();
} }

View File

@ -29,9 +29,9 @@ export class ShowPartyExpBarPhase extends PlayerPartyMemberPokemonPhase {
pokemon.addExp(exp.value); pokemon.addExp(exp.value);
const newLevel = pokemon.level; const newLevel = pokemon.level;
if (newLevel > lastLevel) { 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(); pokemon.updateInfo();
if (globalScene.expParty === ExpNotification.SKIP) { if (globalScene.expParty === ExpNotification.SKIP) {

View File

@ -72,7 +72,7 @@ export class StatStageChangePhase extends PokemonPhase {
if (this.stats.length > 1) { if (this.stats.length > 1) {
for (let i = 0; i < this.stats.length; i++) { for (let i = 0; i < this.stats.length; i++) {
const stat = [this.stats[i]]; const stat = [this.stats[i]];
globalScene.unshiftPhase( globalScene.phaseManager.unshiftPhase(
new StatStageChangePhase( new StatStageChangePhase(
this.battlerIndex, this.battlerIndex,
this.selfTarget, this.selfTarget,
@ -212,7 +212,7 @@ export class StatStageChangePhase extends PokemonPhase {
if (this.showMessage) { if (this.showMessage) {
const messages = this.getStatStageChangeMessages(filteredStats, stages.value, relLevels); const messages = this.getStatStageChangeMessages(filteredStats, stages.value, relLevels);
for (const message of messages) { 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); 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 // 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, p => p.is("StatStageChangePhase") && p.battlerIndex === this.battlerIndex,
); );
if (!existingPhase?.is("StatStageChangePhase")) { if (!existingPhase?.is("StatStageChangePhase")) {
@ -315,7 +315,7 @@ export class StatStageChangePhase extends PokemonPhase {
let existingPhase: StatStageChangePhase; let existingPhase: StatStageChangePhase;
if (this.stats.length === 1) { if (this.stats.length === 1) {
while ( while (
(existingPhase = globalScene.findPhase( (existingPhase = globalScene.phaseManager.findPhase(
p => p =>
p.is("StatStageChangePhase") && p.is("StatStageChangePhase") &&
p.battlerIndex === this.battlerIndex && p.battlerIndex === this.battlerIndex &&
@ -328,13 +328,13 @@ export class StatStageChangePhase extends PokemonPhase {
) { ) {
this.stages += existingPhase.stages; this.stages += existingPhase.stages;
if (!globalScene.tryRemovePhase(p => p === existingPhase)) { if (!globalScene.phaseManager.tryRemovePhase(p => p === existingPhase)) {
break; break;
} }
} }
} }
while ( while (
(existingPhase = globalScene.findPhase( (existingPhase = globalScene.phaseManager.findPhase(
p => p =>
p.is("StatStageChangePhase") && p.is("StatStageChangePhase") &&
p.battlerIndex === this.battlerIndex && p.battlerIndex === this.battlerIndex &&
@ -346,7 +346,7 @@ export class StatStageChangePhase extends PokemonPhase {
) as StatStageChangePhase) ) as StatStageChangePhase)
) { ) {
this.stats.push(...existingPhase.stats); this.stats.push(...existingPhase.stats);
if (!globalScene.tryRemovePhase(p => p === existingPhase)) { if (!globalScene.phaseManager.tryRemovePhase(p => p === existingPhase)) {
break; break;
} }
} }

View File

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

View File

@ -76,9 +76,13 @@ export class SwitchPhase extends BattlePhase {
if (slotIndex >= globalScene.currentBattle.getBattlerCount() && slotIndex < 6) { if (slotIndex >= globalScene.currentBattle.getBattlerCount() && slotIndex < 6) {
// Remove any pre-existing PostSummonPhase under the same field index. // 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. // 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; 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()); globalScene.ui.setMode(UiMode.MESSAGE).then(() => super.end());
}, },

View File

@ -265,6 +265,6 @@ export class SwitchSummonPhase extends SummonPhase {
} }
queuePostSummon(): void { 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() { start() {
super.start(); super.start();
globalScene.queueMessage( globalScene.phaseManager.queueMessage(
i18next.t("battle:pokemonTerastallized", { i18next.t("battle:pokemonTerastallized", {
pokemonNameWithAffix: getPokemonNameWithAffix(this.pokemon), pokemonNameWithAffix: getPokemonNameWithAffix(this.pokemon),
type: i18next.t(`pokemonInfo:Type.${PokemonType[this.pokemon.getTeraType()]}`), type: i18next.t(`pokemonInfo:Type.${PokemonType[this.pokemon.getTeraType()]}`),

View File

@ -124,8 +124,8 @@ export class TitlePhase extends Phase {
options.push({ options.push({
label: i18next.t("menu:cancel"), label: i18next.t("menu:cancel"),
handler: () => { handler: () => {
globalScene.clearPhaseQueue(); globalScene.phaseManager.clearPhaseQueue();
globalScene.pushPhase(new TitlePhase()); globalScene.phaseManager.pushPhase(new TitlePhase());
super.end(); super.end();
return true; return true;
}, },
@ -198,9 +198,9 @@ export class TitlePhase extends Phase {
initDailyRun(): void { initDailyRun(): void {
globalScene.ui.clearText(); globalScene.ui.clearText();
globalScene.ui.setMode(UiMode.SAVE_SLOT, SaveSlotUiMode.SAVE, (slotId: number) => { globalScene.ui.setMode(UiMode.SAVE_SLOT, SaveSlotUiMode.SAVE, (slotId: number) => {
globalScene.clearPhaseQueue(); globalScene.phaseManager.clearPhaseQueue();
if (slotId === -1) { if (slotId === -1) {
globalScene.pushPhase(new TitlePhase()); globalScene.phaseManager.pushPhase(new TitlePhase());
return super.end(); return super.end();
} }
globalScene.sessionSlotId = slotId; globalScene.sessionSlotId = slotId;
@ -304,23 +304,23 @@ export class TitlePhase extends Phase {
globalScene.arena.preloadBgm(); globalScene.arena.preloadBgm();
globalScene.gameMode = getGameMode(this.gameMode); globalScene.gameMode = getGameMode(this.gameMode);
if (this.gameMode === GameModes.CHALLENGE) { if (this.gameMode === GameModes.CHALLENGE) {
globalScene.pushPhase(new SelectChallengePhase()); globalScene.phaseManager.pushPhase(new SelectChallengePhase());
} else { } else {
globalScene.pushPhase(new SelectStarterPhase()); globalScene.phaseManager.pushPhase(new SelectStarterPhase());
} }
globalScene.newArena(globalScene.gameMode.getStartingBiome()); globalScene.newArena(globalScene.gameMode.getStartingBiome());
} else { } else {
globalScene.playBgm(); globalScene.playBgm();
} }
globalScene.pushPhase(new EncounterPhase(this.loaded)); globalScene.phaseManager.pushPhase(new EncounterPhase(this.loaded));
if (this.loaded) { if (this.loaded) {
const availablePartyMembers = globalScene.getPokemonAllowedInBattle().length; 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) { if (globalScene.currentBattle.double && availablePartyMembers > 1) {
globalScene.pushPhase(new SummonPhase(1, true, true)); globalScene.phaseManager.pushPhase(new SummonPhase(1, true, true));
} }
if ( if (
@ -329,9 +329,9 @@ export class TitlePhase extends Phase {
) { ) {
const minPartySize = globalScene.currentBattle.double ? 2 : 1; const minPartySize = globalScene.currentBattle.double ? 2 : 1;
if (availablePartyMembers > minPartySize) { if (availablePartyMembers > minPartySize) {
globalScene.pushPhase(new CheckSwitchPhase(0, globalScene.currentBattle.double)); globalScene.phaseManager.pushPhase(new CheckSwitchPhase(0, globalScene.currentBattle.double));
if (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.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? const modifierRewardFuncs = globalScene.currentBattle.trainer?.config.modifierRewardFuncs!; // TODO: is this bang correct?
for (const modifierRewardFunc of modifierRewardFuncs) { 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? 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 globalScene.currentBattle.trainer?.config.isBoss
) { ) {
if (timedEventManager.getUpgradeUnlockedVouchers()) { if (timedEventManager.getUpgradeUnlockedVouchers()) {
globalScene.unshiftPhase( globalScene.phaseManager.unshiftPhase(
new ModifierRewardPhase( new ModifierRewardPhase(
[ [
modifierTypes.VOUCHER_PLUS, modifierTypes.VOUCHER_PLUS,
@ -46,7 +48,7 @@ export class TrainerVictoryPhase extends BattlePhase {
), ),
); );
} else { } else {
globalScene.unshiftPhase( globalScene.phaseManager.unshiftPhase(
new ModifierRewardPhase( new ModifierRewardPhase(
[modifierTypes.VOUCHER, modifierTypes.VOUCHER, modifierTypes.VOUCHER_PLUS, modifierTypes.VOUCHER_PREMIUM][ [modifierTypes.VOUCHER, modifierTypes.VOUCHER, modifierTypes.VOUCHER_PLUS, modifierTypes.VOUCHER_PREMIUM][
vouchers[TrainerType[trainerType]].voucherType vouchers[TrainerType[trainerType]].voucherType

View File

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

View File

@ -22,14 +22,18 @@ export class TurnInitPhase extends FieldPhase {
globalScene.getPlayerField().forEach(p => { globalScene.getPlayerField().forEach(p => {
// If this pokemon is in play and evolved into something illegal under the current challenge, force a switch // If this pokemon is in play and evolved into something illegal under the current challenge, force a switch
if (p.isOnField() && !p.isAllowedInBattle()) { 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(); const allowedPokemon = globalScene.getPokemonAllowedInBattle();
if (!allowedPokemon.length) { if (!allowedPokemon.length) {
// If there are no longer any legal pokemon in the party, game over. // If there are no longer any legal pokemon in the party, game over.
globalScene.clearPhaseQueue(); globalScene.phaseManager.clearPhaseQueue();
globalScene.unshiftPhase(new GameOverPhase()); globalScene.phaseManager.unshiftPhase(new GameOverPhase());
} else if ( } else if (
allowedPokemon.length >= globalScene.currentBattle.getBattlerCount() || allowedPokemon.length >= globalScene.currentBattle.getBattlerCount() ||
(globalScene.currentBattle.double && !allowedPokemon[0].isActive(true)) (globalScene.currentBattle.double && !allowedPokemon[0].isActive(true))
@ -42,7 +46,7 @@ export class TurnInitPhase extends FieldPhase {
p.leaveField(); p.leaveField();
} }
if (allowedPokemon.length === 1 && globalScene.currentBattle.double) { 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(); 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(); this.end();
} }

View File

@ -153,7 +153,7 @@ export class TurnStartPhase extends FieldPhase {
switch (preTurnCommand?.command) { switch (preTurnCommand?.command) {
case Command.TERA: 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()) || pokemon.getMoveset().find(m => m.moveId === queuedMove.move && m.ppUsed < m.getMovePp()) ||
new PokemonMove(queuedMove.move); new PokemonMove(queuedMove.move);
if (move.getMove().hasAttr(MoveHeaderAttr)) { if (move.getMove().hasAttr(MoveHeaderAttr)) {
globalScene.unshiftPhase(new MoveHeaderPhase(pokemon, move)); globalScene.phaseManager.unshiftPhase(new MoveHeaderPhase(pokemon, move));
} }
if (pokemon.isPlayer()) { if (pokemon.isPlayer()) {
if (turnCommand.cursor === -1) { 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 { } else {
const playerPhase = new MovePhase( const playerPhase = new MovePhase(
pokemon, pokemon,
@ -189,10 +191,10 @@ export class TurnStartPhase extends FieldPhase {
false, false,
queuedMove.ignorePP, queuedMove.ignorePP,
); //TODO: is the bang correct here? ); //TODO: is the bang correct here?
globalScene.pushPhase(playerPhase); globalScene.phaseManager.pushPhase(playerPhase);
} }
} else { } else {
globalScene.pushPhase( globalScene.phaseManager.pushPhase(
new MovePhase( new MovePhase(
pokemon, pokemon,
turnCommand.targets || turnCommand.move!.targets, turnCommand.targets || turnCommand.move!.targets,
@ -204,11 +206,13 @@ export class TurnStartPhase extends FieldPhase {
} }
break; break;
case Command.BALL: 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; break;
case Command.POKEMON: case Command.POKEMON:
const switchType = turnCommand.args?.[0] ? SwitchType.BATON_PASS : SwitchType.SWITCH; 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()), new SwitchSummonPhase(switchType, pokemon.getFieldIndex(), turnCommand.cursor!, true, pokemon.isPlayer()),
); );
break; break;
@ -233,18 +237,18 @@ export class TurnStartPhase extends FieldPhase {
runningPokemon = hasRunAway !== undefined ? hasRunAway : fasterPokemon; runningPokemon = hasRunAway !== undefined ? hasRunAway : fasterPokemon;
} }
} }
globalScene.unshiftPhase(new AttemptRunPhase(runningPokemon.getFieldIndex())); globalScene.phaseManager.unshiftPhase(new AttemptRunPhase(runningPokemon.getFieldIndex()));
break; break;
} }
} }
globalScene.pushPhase(new WeatherEffectPhase()); globalScene.phaseManager.pushPhase(new WeatherEffectPhase());
globalScene.pushPhase(new BerryPhase()); globalScene.phaseManager.pushPhase(new BerryPhase());
/** Add a new phase to check who should be taking status damage */ /** 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 * 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"; public readonly phaseName = "UnavailablePhase";
start(): void { start(): void {
globalScene.ui.setMode(UiMode.UNAVAILABLE, () => { globalScene.ui.setMode(UiMode.UNAVAILABLE, () => {
globalScene.unshiftPhase(new LoginPhase(true)); globalScene.phaseManager.unshiftPhase(new LoginPhase(true));
this.end(); this.end();
}); });
} }

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -156,7 +156,9 @@ export default class MysteryEncounterUiHandler extends UiHandler {
) { ) {
success = false; success = false;
} else { } else {
if ((globalScene.getCurrentPhase() as MysteryEncounterPhase).handleOptionSelect(selected, cursor)) { if (
(globalScene.phaseManager.getCurrentPhase() as MysteryEncounterPhase).handleOptionSelect(selected, cursor)
) {
success = true; success = true;
} else { } else {
ui.playError(); 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? // TODO: This risks hitting the other options (.MOVE_i and ALL) so does it? Do we need an extra check?
if ( if (
option >= PartyOption.FORM_CHANGE_ITEM && option >= PartyOption.FORM_CHANGE_ITEM &&
globalScene.getCurrentPhase()?.is("SelectModifierPhase") && globalScene.phaseManager.getCurrentPhase()?.is("SelectModifierPhase") &&
this.partyUiMode === PartyUiMode.CHECK this.partyUiMode === PartyUiMode.CHECK
) { ) {
const formChangeItemModifiers = this.getFormChangeItemsModifiers(pokemon); const formChangeItemModifiers = this.getFormChangeItemsModifiers(pokemon);
@ -804,7 +804,7 @@ export default class PartyUiHandler extends MessageUiHandler {
this.partyUiMode === PartyUiMode.SWITCH this.partyUiMode === PartyUiMode.SWITCH
) { ) {
this.clearOptions(); this.clearOptions();
(globalScene.getCurrentPhase() as CommandPhase).handleCommand( (globalScene.phaseManager.getCurrentPhase() as CommandPhase).handleCommand(
Command.POKEMON, Command.POKEMON,
this.cursor, this.cursor,
option === PartyOption.PASS_BATON, option === PartyOption.PASS_BATON,
@ -1337,7 +1337,7 @@ export default class PartyUiHandler extends MessageUiHandler {
this.addCommonOptions(pokemon); this.addCommonOptions(pokemon);
break; break;
case PartyUiMode.CHECK: case PartyUiMode.CHECK:
if (globalScene.getCurrentPhase()?.is("SelectModifierPhase")) { if (globalScene.phaseManager.getCurrentPhase()?.is("SelectModifierPhase")) {
const formChangeItemModifiers = this.getFormChangeItemsModifiers(pokemon); const formChangeItemModifiers = this.getFormChangeItemsModifiers(pokemon);
for (let i = 0; i < formChangeItemModifiers.length; i++) { for (let i = 0; i < formChangeItemModifiers.length; i++) {
this.options.push(PartyOption.FORM_CHANGE_ITEM + 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 { show(args: any[]): boolean {
// Allow the use of candies if we are in one of the whitelisted phases // Allow the use of candies if we are in one of the whitelisted phases
this.canUseCandies = ["TitlePhase", "SelectStarterPhase", "CommandPhase"].includes( this.canUseCandies = ["TitlePhase", "SelectStarterPhase", "CommandPhase"].includes(
globalScene.getCurrentPhase()?.phaseName ?? "", globalScene.phaseManager.getCurrentPhase()?.phaseName ?? "",
); );
if (args.length >= 1 && args[0] === "refresh") { if (args.length >= 1 && args[0] === "refresh") {

View File

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

View File

@ -67,7 +67,7 @@ describe("Abilities - Cud Chew", () => {
}); });
it("shows ability popup for eating berry, even if berry is useless", async () => { 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]); game.override.enemyMoveset([MoveId.SPLASH, MoveId.HEAL_PULSE]);
await game.classicMode.startBattle([SpeciesId.FARIGIRAF]); await game.classicMode.startBattle([SpeciesId.FARIGIRAF]);
@ -89,7 +89,7 @@ describe("Abilities - Cud Chew", () => {
await game.move.selectEnemyMove(MoveId.HEAL_PULSE); await game.move.selectEnemyMove(MoveId.HEAL_PULSE);
await game.phaseInterceptor.to("TurnEndPhase"); 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 show cud chew text before regurgitating berries,
// once to hide ability text after finishing. // once to hide ability text after finishing.
expect(abDisplaySpy).toBeCalledTimes(2); 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"); // feebas uses swords dance
await game.phaseInterceptor.to("MovePhase", false); // oricorio copies 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.pokemon).toBe(oricorio);
expect(currentPhase.move.moveId).toBe(MoveId.SWORDS_DANCE); 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"); // magikarp (left) uses victory dance
await game.phaseInterceptor.to("MovePhase", false); // oricorio copies magikarp's 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.pokemon).toBe(oricorio);
expect(currentPhase.move.moveId).toBe(MoveId.VICTORY_DANCE); 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"); // shuckle 2 mirror moves oricorio
await game.phaseInterceptor.to("MovePhase"); // calls instructed rev dance 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.pokemon).toBe(shuckle2);
expect(currentPhase.move.moveId).toBe(MoveId.REVELATION_DANCE); expect(currentPhase.move.moveId).toBe(MoveId.REVELATION_DANCE);
await game.phaseInterceptor.to("MovePhase"); // shuckle 1 instructs oricorio await game.phaseInterceptor.to("MovePhase"); // shuckle 1 instructs oricorio
await game.phaseInterceptor.to("MovePhase"); 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.pokemon).toBe(oricorio);
expect(currentPhase.move.moveId).toBe(MoveId.REVELATION_DANCE); 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); 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); commandPhase.handleCommand(Command.RUN, 0);
await game.phaseInterceptor.to("BerryPhase"); await game.phaseInterceptor.to("BerryPhase");

View File

@ -201,7 +201,7 @@ describe("Abilities - Disguise", () => {
game.move.select(MoveId.SHADOW_SNEAK); game.move.select(MoveId.SHADOW_SNEAK);
await game.toNextWave(); 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); expect(game.scene.currentBattle.waveIndex).toBe(2);
}); });

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