[Refactor] Ensure that new phases are created through the phase manager

https://github.com/pagefaultgames/pokerogue/pull/5955

* Add newPhase method to phase-manager

* Update calls to append/prepend phase to use string phase

* Replace instantiations of new phase with phase manager
This commit is contained in:
Sirz Benjie 2025-06-08 01:55:30 -05:00 committed by GitHub
parent 75beec12a8
commit 1c4edabd1d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
76 changed files with 1302 additions and 1294 deletions

View File

@ -1,286 +1,25 @@
import type { MoveAnim } from "#app/data/battle-anims"; import type { PhaseConstructorMap } from "#app/phase-manager";
import type { AddEnemyBuffModifierPhase } from "#app/phases/add-enemy-buff-modifier-phase";
import type { AttemptCapturePhase } from "#app/phases/attempt-capture-phase";
import type { AttemptRunPhase } from "#app/phases/attempt-run-phase";
import type { BattleEndPhase } from "#app/phases/battle-end-phase";
import type { BerryPhase } from "#app/phases/berry-phase";
import type { CheckStatusEffectPhase } from "#app/phases/check-status-effect-phase";
import type { CheckSwitchPhase } from "#app/phases/check-switch-phase";
import type { CommandPhase } from "#app/phases/command-phase";
import type { CommonAnimPhase } from "#app/phases/common-anim-phase";
import type { DamageAnimPhase } from "#app/phases/damage-anim-phase";
import type { EggHatchPhase } from "#app/phases/egg-hatch-phase";
import type { EggLapsePhase } from "#app/phases/egg-lapse-phase";
import type { EggSummaryPhase } from "#app/phases/egg-summary-phase";
import type { EncounterPhase } from "#app/phases/encounter-phase";
import type { EndCardPhase } from "#app/phases/end-card-phase";
import type { EndEvolutionPhase } from "#app/phases/end-evolution-phase";
import type { EnemyCommandPhase } from "#app/phases/enemy-command-phase";
import type { EvolutionPhase } from "#app/phases/evolution-phase";
import type { ExpPhase } from "#app/phases/exp-phase";
import type { FaintPhase } from "#app/phases/faint-phase";
import type { FormChangePhase } from "#app/phases/form-change-phase";
import type { GameOverModifierRewardPhase } from "#app/phases/game-over-modifier-reward-phase";
import type { GameOverPhase } from "#app/phases/game-over-phase";
import type { HideAbilityPhase } from "#app/phases/hide-ability-phase";
import type { HidePartyExpBarPhase } from "#app/phases/hide-party-exp-bar-phase";
import type { LearnMovePhase } from "#app/phases/learn-move-phase";
import type { LevelCapPhase } from "#app/phases/level-cap-phase";
import type { LevelUpPhase } from "#app/phases/level-up-phase";
import type { LoadMoveAnimPhase } from "#app/phases/load-move-anim-phase";
import type { LoginPhase } from "#app/phases/login-phase";
import type { MessagePhase } from "#app/phases/message-phase";
import type { ModifierRewardPhase } from "#app/phases/modifier-reward-phase";
import type { MoneyRewardPhase } from "#app/phases/money-reward-phase";
import type { MoveAnimPhase } from "#app/phases/move-anim-phase";
import type { MoveChargePhase } from "#app/phases/move-charge-phase";
import type { MoveEffectPhase } from "#app/phases/move-effect-phase";
import type { MoveEndPhase } from "#app/phases/move-end-phase";
import type { MoveHeaderPhase } from "#app/phases/move-header-phase";
import type { MovePhase } from "#app/phases/move-phase";
import type {
MysteryEncounterPhase,
MysteryEncounterOptionSelectedPhase,
MysteryEncounterBattlePhase,
MysteryEncounterRewardsPhase,
PostMysteryEncounterPhase,
MysteryEncounterBattleStartCleanupPhase,
} from "#app/phases/mystery-encounter-phases";
import type { NewBattlePhase } from "#app/phases/new-battle-phase";
import type { NewBiomeEncounterPhase } from "#app/phases/new-biome-encounter-phase";
import type { NextEncounterPhase } from "#app/phases/next-encounter-phase";
import type { ObtainStatusEffectPhase } from "#app/phases/obtain-status-effect-phase";
import type { PartyExpPhase } from "#app/phases/party-exp-phase";
import type { PartyHealPhase } from "#app/phases/party-heal-phase";
import type { PokemonAnimPhase } from "#app/phases/pokemon-anim-phase";
import type { PokemonHealPhase } from "#app/phases/pokemon-heal-phase";
import type { PokemonTransformPhase } from "#app/phases/pokemon-transform-phase";
import type { PostGameOverPhase } from "#app/phases/post-game-over-phase";
import type { PostSummonPhase } from "#app/phases/post-summon-phase";
import type { PostTurnStatusEffectPhase } from "#app/phases/post-turn-status-effect-phase";
import type { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase";
import type { ReloadSessionPhase } from "#app/phases/reload-session-phase";
import type { ResetStatusPhase } from "#app/phases/reset-status-phase";
import type { ReturnPhase } from "#app/phases/return-phase";
import type { RevivalBlessingPhase } from "#app/phases/revival-blessing-phase";
import type { RibbonModifierRewardPhase } from "#app/phases/ribbon-modifier-reward-phase";
import type { ScanIvsPhase } from "#app/phases/scan-ivs-phase";
import type { SelectBiomePhase } from "#app/phases/select-biome-phase";
import type { SelectChallengePhase } from "#app/phases/select-challenge-phase";
import type { SelectGenderPhase } from "#app/phases/select-gender-phase";
import type { SelectModifierPhase } from "#app/phases/select-modifier-phase";
import type { SelectStarterPhase } from "#app/phases/select-starter-phase";
import type { SelectTargetPhase } from "#app/phases/select-target-phase";
import type { ShinySparklePhase } from "#app/phases/shiny-sparkle-phase";
import type { ShowAbilityPhase } from "#app/phases/show-ability-phase";
import type { ShowPartyExpBarPhase } from "#app/phases/show-party-exp-bar-phase";
import type { ShowTrainerPhase } from "#app/phases/show-trainer-phase";
import type { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
import type { SummonMissingPhase } from "#app/phases/summon-missing-phase";
import type { SummonPhase } from "#app/phases/summon-phase";
import type { SwitchBiomePhase } from "#app/phases/switch-biome-phase";
import type { SwitchPhase } from "#app/phases/switch-phase";
import type { SwitchSummonPhase } from "#app/phases/switch-summon-phase";
import type { TeraPhase } from "#app/phases/tera-phase";
import type { TitlePhase } from "#app/phases/title-phase";
import type { ToggleDoublePositionPhase } from "#app/phases/toggle-double-position-phase";
import type { TrainerVictoryPhase } from "#app/phases/trainer-victory-phase";
import type { TurnEndPhase } from "#app/phases/turn-end-phase";
import type { TurnInitPhase } from "#app/phases/turn-init-phase";
import type { TurnStartPhase } from "#app/phases/turn-start-phase";
import type { UnavailablePhase } from "#app/phases/unavailable-phase";
import type { UnlockPhase } from "#app/phases/unlock-phase";
import type { VictoryPhase } from "#app/phases/victory-phase";
import type { WeatherEffectPhase } from "#app/phases/weather-effect-phase";
export type PhaseClass = // Intentionally export the types of everything in phase-manager, as this file is meant to be
| typeof AddEnemyBuffModifierPhase // the centralized place for type definitions for the phase system.
| typeof AttemptCapturePhase export type * from "#app/phase-manager";
| typeof AttemptRunPhase
| typeof BattleEndPhase
| typeof BerryPhase
| typeof CheckStatusEffectPhase
| typeof CheckSwitchPhase
| typeof CommandPhase
| typeof CommonAnimPhase
| typeof DamageAnimPhase
| typeof EggHatchPhase
| typeof EggLapsePhase
| typeof EggSummaryPhase
| typeof EncounterPhase
| typeof EndCardPhase
| typeof EndEvolutionPhase
| typeof EnemyCommandPhase
| typeof EvolutionPhase
| typeof FormChangePhase
| typeof ExpPhase
| typeof FaintPhase
| typeof FormChangePhase
| typeof GameOverPhase
| typeof GameOverModifierRewardPhase
| typeof HideAbilityPhase
| typeof HidePartyExpBarPhase
| typeof LearnMovePhase
| typeof LevelUpPhase
| typeof LevelCapPhase
| typeof LoadMoveAnimPhase
| typeof LoginPhase
| typeof MessagePhase
| typeof ModifierRewardPhase
| typeof MoneyRewardPhase
| typeof MoveAnimPhase
| typeof MoveChargePhase
| typeof MoveEffectPhase
| typeof MoveEndPhase
| typeof MoveHeaderPhase
| typeof MovePhase
| typeof MysteryEncounterPhase
| typeof MysteryEncounterOptionSelectedPhase
| typeof MysteryEncounterBattlePhase
| typeof MysteryEncounterRewardsPhase
| typeof MysteryEncounterBattleStartCleanupPhase
| typeof MysteryEncounterRewardsPhase
| typeof PostMysteryEncounterPhase
| typeof NewBattlePhase
| typeof NewBiomeEncounterPhase
| typeof NextEncounterPhase
| typeof ObtainStatusEffectPhase
| typeof PartyExpPhase
| typeof PartyHealPhase
| typeof PokemonAnimPhase
| typeof PokemonHealPhase
| typeof PokemonTransformPhase
| typeof PostGameOverPhase
| typeof PostSummonPhase
| typeof PostTurnStatusEffectPhase
| typeof QuietFormChangePhase
| typeof ReloadSessionPhase
| typeof ResetStatusPhase
| typeof ReturnPhase
| typeof RevivalBlessingPhase
| typeof RibbonModifierRewardPhase
| typeof ScanIvsPhase
| typeof SelectBiomePhase
| typeof SelectChallengePhase
| typeof SelectGenderPhase
| typeof SelectModifierPhase
| typeof SelectStarterPhase
| typeof SelectTargetPhase
| typeof ShinySparklePhase
| typeof ShowAbilityPhase
| typeof ShowTrainerPhase
| typeof ShowPartyExpBarPhase
| typeof StatStageChangePhase
| typeof SummonMissingPhase
| typeof SummonPhase
| typeof SwitchBiomePhase
| typeof SwitchPhase
| typeof SwitchSummonPhase
| typeof TeraPhase
| typeof TitlePhase
| typeof ToggleDoublePositionPhase
| typeof TrainerVictoryPhase
| typeof TurnEndPhase
| typeof TurnInitPhase
| typeof TurnStartPhase
| typeof UnavailablePhase
| typeof UnlockPhase
| typeof VictoryPhase
| typeof WeatherEffectPhase;
/** Typescript map used to map a string phase to the actual phase type */ // This file includes helpful types for the phase system.
// It intentionally imports the phase constructor map from the phase manager (and re-exports it)
/**
* Map of phase names to constructors for said phase
*/
export type PhaseMap = { export type PhaseMap = {
AddEnemyBuffModifierPhase: AddEnemyBuffModifierPhase; [K in keyof PhaseConstructorMap]: InstanceType<PhaseConstructorMap[K]>;
AttemptCapturePhase: AttemptCapturePhase;
AttemptRunPhase: AttemptRunPhase;
BattleEndPhase: BattleEndPhase;
BerryPhase: BerryPhase;
CheckStatusEffectPhase: CheckStatusEffectPhase;
CheckSwitchPhase: CheckSwitchPhase;
CommandPhase: CommandPhase;
CommonAnimPhase: CommonAnimPhase;
DamageAnimPhase: DamageAnimPhase;
EggHatchPhase: EggHatchPhase;
EggLapsePhase: EggLapsePhase;
EggSummaryPhase: EggSummaryPhase;
EncounterPhase: EncounterPhase;
EndCardPhase: EndCardPhase;
EndEvolutionPhase: EndEvolutionPhase;
EnemyCommandPhase: EnemyCommandPhase;
EvolutionPhase: EvolutionPhase;
ExpPhase: ExpPhase;
FaintPhase: FaintPhase;
FormChangePhase: FormChangePhase;
GameOverPhase: GameOverPhase;
GameOverModifierRewardPhase: GameOverModifierRewardPhase;
HideAbilityPhase: HideAbilityPhase;
HidePartyExpBarPhase: HidePartyExpBarPhase;
LearnMovePhase: LearnMovePhase;
LevelCapPhase: LevelCapPhase;
LevelUpPhase: LevelUpPhase;
LoadMoveAnimPhase: LoadMoveAnimPhase;
LoginPhase: LoginPhase;
MessagePhase: MessagePhase;
ModifierRewardPhase: ModifierRewardPhase;
MoneyRewardPhase: MoneyRewardPhase;
MoveAnimPhase: MoveAnimPhase<MoveAnim>;
MoveChargePhase: MoveChargePhase;
MoveEffectPhase: MoveEffectPhase;
MoveEndPhase: MoveEndPhase;
MoveHeaderPhase: MoveHeaderPhase;
MovePhase: MovePhase;
MysteryEncounterPhase: MysteryEncounterPhase;
MysteryEncounterOptionSelectedPhase: MysteryEncounterOptionSelectedPhase;
MysteryEncounterBattlePhase: MysteryEncounterBattlePhase;
MysteryEncounterBattleStartCleanupPhase: MysteryEncounterBattleStartCleanupPhase;
MysteryEncounterRewardsPhase: MysteryEncounterRewardsPhase;
PostMysteryEncounterPhase: PostMysteryEncounterPhase;
NewBattlePhase: NewBattlePhase;
NewBiomeEncounterPhase: NewBiomeEncounterPhase;
NextEncounterPhase: NextEncounterPhase;
ObtainStatusEffectPhase: ObtainStatusEffectPhase;
PartyExpPhase: PartyExpPhase;
PartyHealPhase: PartyHealPhase;
PokemonAnimPhase: PokemonAnimPhase;
PokemonHealPhase: PokemonHealPhase;
PokemonTransformPhase: PokemonTransformPhase;
PostGameOverPhase: PostGameOverPhase;
PostSummonPhase: PostSummonPhase;
PostTurnStatusEffectPhase: PostTurnStatusEffectPhase;
QuietFormChangePhase: QuietFormChangePhase;
ReloadSessionPhase: ReloadSessionPhase;
ResetStatusPhase: ResetStatusPhase;
ReturnPhase: ReturnPhase;
RevivalBlessingPhase: RevivalBlessingPhase;
RibbonModifierRewardPhase: RibbonModifierRewardPhase;
ScanIvsPhase: ScanIvsPhase;
SelectBiomePhase: SelectBiomePhase;
SelectChallengePhase: SelectChallengePhase;
SelectGenderPhase: SelectGenderPhase;
SelectModifierPhase: SelectModifierPhase;
SelectStarterPhase: SelectStarterPhase;
SelectTargetPhase: SelectTargetPhase;
ShinySparklePhase: ShinySparklePhase;
ShowAbilityPhase: ShowAbilityPhase;
ShowPartyExpBarPhase: ShowPartyExpBarPhase;
ShowTrainerPhase: ShowTrainerPhase;
StatStageChangePhase: StatStageChangePhase;
SummonMissingPhase: SummonMissingPhase;
SummonPhase: SummonPhase;
SwitchBiomePhase: SwitchBiomePhase;
SwitchPhase: SwitchPhase;
SwitchSummonPhase: SwitchSummonPhase;
TeraPhase: TeraPhase;
TitlePhase: TitlePhase;
ToggleDoublePositionPhase: ToggleDoublePositionPhase;
TrainerVictoryPhase: TrainerVictoryPhase;
TurnEndPhase: TurnEndPhase;
TurnInitPhase: TurnInitPhase;
TurnStartPhase: TurnStartPhase;
UnavailablePhase: UnavailablePhase;
UnlockPhase: UnlockPhase;
VictoryPhase: VictoryPhase;
WeatherEffectPhase: WeatherEffectPhase;
}; };
/**
* Union type of all phase constructors.
*/
export type PhaseClass = PhaseConstructorMap[keyof PhaseConstructorMap];
/**
* Union type of all phase names as strings.
*/
export type PhaseString = keyof PhaseMap; export type PhaseString = keyof PhaseMap;

View File

@ -108,7 +108,6 @@ import {
SpeciesFormChangeManualTrigger, SpeciesFormChangeManualTrigger,
SpeciesFormChangeTimeOfDayTrigger, SpeciesFormChangeTimeOfDayTrigger,
} from "#app/data/pokemon-forms"; } from "#app/data/pokemon-forms";
import { FormChangePhase } from "#app/phases/form-change-phase";
import { getTypeRgb } from "#app/data/type"; import { getTypeRgb } from "#app/data/type";
import { PokemonType } from "#enums/pokemon-type"; import { PokemonType } from "#enums/pokemon-type";
import PokemonSpriteSparkleHandler from "#app/field/pokemon-sprite-sparkle-handler"; import PokemonSpriteSparkleHandler from "#app/field/pokemon-sprite-sparkle-handler";
@ -142,18 +141,7 @@ import i18next from "i18next";
import { TrainerType } from "#enums/trainer-type"; import { TrainerType } from "#enums/trainer-type";
import { battleSpecDialogue } from "#app/data/dialogue"; 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 { LoginPhase } from "#app/phases/login-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 { NextEncounterPhase } from "#app/phases/next-encounter-phase";
import { PokemonAnimPhase } from "#app/phases/pokemon-anim-phase";
import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase";
import { ReturnPhase } from "#app/phases/return-phase";
import { ShowTrainerPhase } from "#app/phases/show-trainer-phase";
import { SummonPhase } from "#app/phases/summon-phase";
import { TitlePhase } from "#app/phases/title-phase";
import { ToggleDoublePositionPhase } from "#app/phases/toggle-double-position-phase";
import { 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 {
@ -168,8 +156,6 @@ import { MysteryEncounterSaveData } from "#app/data/mystery-encounters/mystery-e
import { MysteryEncounterType } from "#enums/mystery-encounter-type"; import { MysteryEncounterType } from "#enums/mystery-encounter-type";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import type HeldModifierConfig from "#app/@types/held-modifier-config"; import type HeldModifierConfig from "#app/@types/held-modifier-config";
import { ExpPhase } from "#app/phases/exp-phase";
import { ShowPartyExpBarPhase } from "#app/phases/show-party-exp-bar-phase";
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode"; import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
import { ExpGainsSpeed } from "#enums/exp-gains-speed"; import { ExpGainsSpeed } from "#enums/exp-gains-speed";
import { BattlerTagType } from "#enums/battler-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type";
@ -699,8 +685,8 @@ export default class BattleScene extends SceneBase {
).then(() => loadMoveAnimAssets(defaultMoves, true)), ).then(() => loadMoveAnimAssets(defaultMoves, true)),
this.initStarterColors(), this.initStarterColors(),
]).then(() => { ]).then(() => {
this.phaseManager.pushPhase(new LoginPhase()); this.phaseManager.pushNew("LoginPhase");
this.phaseManager.pushPhase(new TitlePhase()); this.phaseManager.pushNew("TitlePhase");
this.phaseManager.shiftPhase(); this.phaseManager.shiftPhase();
}); });
@ -1475,7 +1461,7 @@ export default class BattleScene extends SceneBase {
playerField.forEach((pokemon, p) => { playerField.forEach((pokemon, p) => {
if (pokemon.isOnField()) { if (pokemon.isOnField()) {
this.phaseManager.pushPhase(new ReturnPhase(p)); this.phaseManager.pushNew("ReturnPhase", p);
} }
}); });
@ -1492,7 +1478,7 @@ export default class BattleScene extends SceneBase {
} }
if (!this.trainer.visible) { if (!this.trainer.visible) {
this.phaseManager.pushPhase(new ShowTrainerPhase()); this.phaseManager.pushNew("ShowTrainerPhase");
} }
} }
@ -1501,13 +1487,13 @@ export default class BattleScene extends SceneBase {
} }
if (!this.gameMode.hasRandomBiomes && !isNewBiome) { if (!this.gameMode.hasRandomBiomes && !isNewBiome) {
this.phaseManager.pushPhase(new NextEncounterPhase()); this.phaseManager.pushNew("NextEncounterPhase");
} else { } else {
this.phaseManager.pushPhase(new NewBiomeEncounterPhase()); this.phaseManager.pushNew("NewBiomeEncounterPhase");
const newMaxExpLevel = this.getMaxExpLevel(); const newMaxExpLevel = this.getMaxExpLevel();
if (newMaxExpLevel > maxExpLevel) { if (newMaxExpLevel > maxExpLevel) {
this.phaseManager.pushPhase(new LevelCapPhase()); this.phaseManager.pushNew("LevelCapPhase");
} }
} }
} }
@ -3199,9 +3185,9 @@ export default class BattleScene extends SceneBase {
if (matchingFormChange) { if (matchingFormChange) {
let phase: Phase; let phase: Phase;
if (pokemon.isPlayer() && !matchingFormChange.quiet) { if (pokemon.isPlayer() && !matchingFormChange.quiet) {
phase = new FormChangePhase(pokemon, matchingFormChange, modal); phase = this.phaseManager.create("FormChangePhase", pokemon, matchingFormChange, modal);
} else { } else {
phase = new QuietFormChangePhase(pokemon, matchingFormChange); phase = this.phaseManager.create("QuietFormChangePhase", pokemon, matchingFormChange);
} }
if (pokemon.isPlayer() && !matchingFormChange.quiet && modal) { if (pokemon.isPlayer() && !matchingFormChange.quiet && modal) {
this.phaseManager.overridePhase(phase); this.phaseManager.overridePhase(phase);
@ -3223,11 +3209,12 @@ export default class BattleScene extends SceneBase {
fieldAssets?: Phaser.GameObjects.Sprite[], fieldAssets?: Phaser.GameObjects.Sprite[],
delayed = false, delayed = false,
): boolean { ): boolean {
const phase: Phase = new PokemonAnimPhase(battleAnimType, pokemon, fieldAssets); const phaseManager = this.phaseManager;
const phase: Phase = phaseManager.create("PokemonAnimPhase", battleAnimType, pokemon, fieldAssets);
if (delayed) { if (delayed) {
this.phaseManager.pushPhase(phase); phaseManager.pushPhase(phase);
} else { } else {
this.phaseManager.unshiftPhase(phase); phaseManager.unshiftPhase(phase);
} }
return true; return true;
} }
@ -3335,9 +3322,9 @@ 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.phaseManager.pushPhase(new ToggleDoublePositionPhase(true)); this.phaseManager.pushNew("ToggleDoublePositionPhase", true);
if (!availablePartyMembers[1].isOnField()) { if (!availablePartyMembers[1].isOnField()) {
this.phaseManager.pushPhase(new SummonPhase(1)); this.phaseManager.pushNew("SummonPhase", 1);
} }
} }
@ -3461,8 +3448,8 @@ export default class BattleScene extends SceneBase {
const partyMemberIndex = party.indexOf(expPartyMembers[pm]); const partyMemberIndex = party.indexOf(expPartyMembers[pm]);
this.phaseManager.unshiftPhase( this.phaseManager.unshiftPhase(
expPartyMembers[pm].isOnField() expPartyMembers[pm].isOnField()
? new ExpPhase(partyMemberIndex, exp) ? this.phaseManager.create("ExpPhase", partyMemberIndex, exp)
: new ShowPartyExpBarPhase(partyMemberIndex, exp), : this.phaseManager.create("ShowPartyExpBarPhase", partyMemberIndex, exp),
); );
} }
} }

View File

@ -47,16 +47,8 @@ import { Command } from "#app/ui/command-ui-handler";
import { BerryModifierType } from "#app/modifier/modifier-type"; import { BerryModifierType } from "#app/modifier/modifier-type";
import { getPokeballName } from "#app/data/pokeball"; import { getPokeballName } from "#app/data/pokeball";
import { BattleType } from "#enums/battle-type"; import { BattleType } from "#enums/battle-type";
import { MovePhase } from "#app/phases/move-phase"; import type { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase";
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import { SwitchPhase } from "#app/phases/switch-phase";
import { SwitchSummonPhase } from "#app/phases/switch-summon-phase";
import { BattleEndPhase } from "#app/phases/battle-end-phase";
import { NewBattlePhase } from "#app/phases/new-battle-phase";
import { MoveEndPhase } from "#app/phases/move-end-phase";
import { PokemonTransformPhase } from "#app/phases/pokemon-transform-phase";
import { allAbilities } from "#app/data/data-lists"; import { allAbilities } from "#app/data/data-lists";
import { AbAttr } from "#app/data/abilities/ab-attrs/ab-attr"; import { AbAttr } from "#app/data/abilities/ab-attrs/ab-attr";
import { Ability } from "#app/data/abilities/ability-class"; import { Ability } from "#app/data/abilities/ability-class";
@ -77,7 +69,6 @@ import { MoveFlags } from "#enums/MoveFlags";
import { MoveTarget } from "#enums/MoveTarget"; import { MoveTarget } from "#enums/MoveTarget";
import { MoveCategory } from "#enums/MoveCategory"; import { MoveCategory } from "#enums/MoveCategory";
import type { BerryType } from "#enums/berry-type"; import type { BerryType } from "#enums/berry-type";
import { CommonAnimPhase } from "#app/phases/common-anim-phase";
import { CommonAnim } from "../battle-anims"; import { CommonAnim } from "../battle-anims";
import { getBerryEffectFunc } from "../berry"; import { getBerryEffectFunc } from "../berry";
import { BerryUsedEvent } from "#app/events/battle-scene"; import { BerryUsedEvent } from "#app/events/battle-scene";
@ -98,7 +89,6 @@ import type {
import type { BattlerIndex } from "#app/battle"; import type { BattlerIndex } from "#app/battle";
import type Move from "#app/data/moves/move"; import type Move from "#app/data/moves/move";
import type { ArenaTrapTag, SuppressAbilitiesTag } from "#app/data/arena-tag"; import type { ArenaTrapTag, SuppressAbilitiesTag } from "#app/data/arena-tag";
import { SelectBiomePhase } from "#app/phases/select-biome-phase";
import { noAbilityTypeOverrideMoves } from "../moves/invalid-moves"; import { noAbilityTypeOverrideMoves } from "../moves/invalid-moves";
export class BlockRecoilDamageAttr extends AbAttr { export class BlockRecoilDamageAttr extends AbAttr {
@ -200,10 +190,13 @@ export class PostTeraFormChangeStatChangeAbAttr extends AbAttr {
const statStageChangePhases: StatStageChangePhase[] = []; const statStageChangePhases: StatStageChangePhase[] = [];
if (!simulated) { if (!simulated) {
statStageChangePhases.push(new StatStageChangePhase(pokemon.getBattlerIndex(), true, this.stats, this.stages)); const phaseManager = globalScene.phaseManager;
statStageChangePhases.push(
phaseManager.create("StatStageChangePhase", pokemon.getBattlerIndex(), true, this.stats, this.stages),
);
for (const statStageChangePhase of statStageChangePhases) { for (const statStageChangePhase of statStageChangePhases) {
globalScene.phaseManager.unshiftPhase(statStageChangePhase); phaseManager.unshiftPhase(statStageChangePhase);
} }
} }
} }
@ -581,8 +574,8 @@ 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new PokemonHealPhase( "PokemonHealPhase",
pokemon.getBattlerIndex(), pokemon.getBattlerIndex(),
toDmgValue(pokemon.getMaxHp() / 4), toDmgValue(pokemon.getMaxHp() / 4),
i18next.t("abilityTriggers:typeImmunityHeal", { i18next.t("abilityTriggers:typeImmunityHeal", {
@ -590,7 +583,6 @@ export class TypeImmunityHealAbAttr extends TypeImmunityAbAttr {
abilityName, abilityName,
}), }),
true, true,
),
); );
cancelled.value = true; // Suppresses "No Effect" message cancelled.value = true; // Suppresses "No Effect" message
} }
@ -632,8 +624,12 @@ 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new StatStageChangePhase(pokemon.getBattlerIndex(), true, [this.stat], this.stages), "StatStageChangePhase",
pokemon.getBattlerIndex(),
true,
[this.stat],
this.stages,
); );
} }
} }
@ -960,8 +956,12 @@ export class MoveImmunityStatStageChangeAbAttr extends MoveImmunityAbAttr {
args: any[], args: any[],
): void { ): void {
super.applyPreDefend(pokemon, passive, simulated, attacker, move, cancelled, args); super.applyPreDefend(pokemon, passive, simulated, attacker, move, cancelled, args);
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new StatStageChangePhase(pokemon.getBattlerIndex(), true, [this.stat], this.stages), "StatStageChangePhase",
pokemon.getBattlerIndex(),
true,
[this.stat],
this.stages,
); );
} }
} }
@ -1063,18 +1063,21 @@ 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new StatStageChangePhase(other.getBattlerIndex(), false, [this.stat], this.stages), "StatStageChangePhase",
other.getBattlerIndex(),
false,
[this.stat],
this.stages,
); );
} }
} else { } else {
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new StatStageChangePhase( "StatStageChangePhase",
(this.selfTarget ? pokemon : attacker).getBattlerIndex(), (this.selfTarget ? pokemon : attacker).getBattlerIndex(),
this.selfTarget, this.selfTarget,
[this.stat], [this.stat],
this.stages, this.stages,
),
); );
} }
} }
@ -1130,13 +1133,12 @@ export class PostDefendHpGatedStatStageChangeAbAttr extends PostDefendAbAttr {
_args: any[], _args: any[],
): void { ): void {
if (!simulated) { if (!simulated) {
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new StatStageChangePhase( "StatStageChangePhase",
(this.selfTarget ? pokemon : attacker).getBattlerIndex(), (this.selfTarget ? pokemon : attacker).getBattlerIndex(),
true, true,
this.stats, this.stats,
this.stages, this.stages,
),
); );
} }
} }
@ -1450,8 +1452,12 @@ export class PostDefendCritStatStageChangeAbAttr extends PostDefendAbAttr {
_args: any[], _args: any[],
): void { ): void {
if (!simulated) { if (!simulated) {
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new StatStageChangePhase(pokemon.getBattlerIndex(), true, [this.stat], this.stages), "StatStageChangePhase",
pokemon.getBattlerIndex(),
true,
[this.stat],
this.stages,
); );
} }
} }
@ -1766,8 +1772,12 @@ export class PostStatStageChangeStatStageChangeAbAttr extends PostStatStageChang
_args: any[], _args: any[],
): void { ): void {
if (!simulated) { if (!simulated) {
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new StatStageChangePhase(pokemon.getBattlerIndex(), true, this.statsToChange, this.stages), "StatStageChangePhase",
pokemon.getBattlerIndex(),
true,
this.statsToChange,
this.stages,
); );
} }
} }
@ -2928,9 +2938,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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew("StatStageChangePhase", pokemon.getBattlerIndex(), true, [stat], this.stages);
new StatStageChangePhase(pokemon.getBattlerIndex(), true, [stat], this.stages),
);
} }
} }
} }
@ -2996,9 +3004,7 @@ export class PostKnockOutStatStageChangeAbAttr extends PostKnockOutAbAttr {
): void { ): 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew("StatStageChangePhase", pokemon.getBattlerIndex(), true, [stat], this.stages);
new StatStageChangePhase(pokemon.getBattlerIndex(), true, [stat], this.stages),
);
} }
} }
} }
@ -3112,8 +3118,12 @@ export class PostIntimidateStatStageChangeAbAttr extends AbAttr {
_args: any[], _args: any[],
): void { ): void {
if (!simulated) { if (!simulated) {
globalScene.phaseManager.pushPhase( globalScene.phaseManager.pushNew(
new StatStageChangePhase(pokemon.getBattlerIndex(), false, this.stats, this.stages), "StatStageChangePhase",
pokemon.getBattlerIndex(),
false,
this.stats,
this.stages,
); );
} }
cancelled.value = this.overwrites; cancelled.value = this.overwrites;
@ -3315,8 +3325,12 @@ 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new StatStageChangePhase(pokemon.getBattlerIndex(), true, this.stats, this.stages), "StatStageChangePhase",
pokemon.getBattlerIndex(),
true,
this.stats,
this.stages,
); );
} else { } else {
for (const opponent of pokemon.getOpponents()) { for (const opponent of pokemon.getOpponents()) {
@ -3330,8 +3344,12 @@ export class PostSummonStatStageChangeAbAttr extends PostSummonAbAttr {
} }
} }
if (!cancelled.value) { if (!cancelled.value) {
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new StatStageChangePhase(opponent.getBattlerIndex(), false, this.stats, this.stages), "StatStageChangePhase",
opponent.getBattlerIndex(),
false,
this.stats,
this.stages,
); );
} }
} }
@ -3357,8 +3375,8 @@ 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new PokemonHealPhase( "PokemonHealPhase",
target.getBattlerIndex(), target.getBattlerIndex(),
toDmgValue(pokemon.getMaxHp() / this.healRatio), toDmgValue(pokemon.getMaxHp() / this.healRatio),
i18next.t("abilityTriggers:postSummonAllyHeal", { i18next.t("abilityTriggers:postSummonAllyHeal", {
@ -3367,7 +3385,6 @@ export class PostSummonAllyHealAbAttr extends PostSummonAbAttr {
}), }),
true, true,
!this.showAnim, !this.showAnim,
),
); );
} }
} }
@ -3445,7 +3462,7 @@ export class DownloadAbAttr extends PostSummonAbAttr {
} }
if (!simulated) { if (!simulated) {
globalScene.phaseManager.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), false, this.stats, 1)); globalScene.phaseManager.unshiftNew("StatStageChangePhase", pokemon.getBattlerIndex(), false, this.stats, 1);
} }
} }
} }
@ -3726,8 +3743,11 @@ 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new PokemonTransformPhase(pokemon.getBattlerIndex(), target.getBattlerIndex(), true), "PokemonTransformPhase",
pokemon.getBattlerIndex(),
target.getBattlerIndex(),
true,
); );
} }
} }
@ -4110,8 +4130,17 @@ export class ReflectStatStageChangeAbAttr extends PreStatStageChangeAbAttr {
const stages = args[1]; const stages = args[1];
this.reflectedStat = stat; this.reflectedStat = stat;
if (!simulated) { if (!simulated) {
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new StatStageChangePhase(attacker.getBattlerIndex(), false, [stat], stages, true, false, true, null, true), "StatStageChangePhase",
attacker.getBattlerIndex(),
false,
[stat],
stages,
true,
false,
true,
null,
true,
); );
} }
cancelled.value = true; cancelled.value = true;
@ -5212,8 +5241,8 @@ export class PostWeatherLapseHealAbAttr extends PostWeatherLapseAbAttr {
): void { ): void {
const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name; const abilityName = (!passive ? pokemon.getAbility() : pokemon.getPassiveAbility()).name;
if (!simulated) { if (!simulated) {
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new PokemonHealPhase( "PokemonHealPhase",
pokemon.getBattlerIndex(), pokemon.getBattlerIndex(),
toDmgValue(pokemon.getMaxHp() / (16 / this.healFactor)), toDmgValue(pokemon.getMaxHp() / (16 / this.healFactor)),
i18next.t("abilityTriggers:postWeatherLapseHeal", { i18next.t("abilityTriggers:postWeatherLapseHeal", {
@ -5221,7 +5250,6 @@ export class PostWeatherLapseHealAbAttr extends PostWeatherLapseAbAttr {
abilityName, abilityName,
}), }),
true, true,
),
); );
} }
} }
@ -5366,13 +5394,12 @@ 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new PokemonHealPhase( "PokemonHealPhase",
pokemon.getBattlerIndex(), pokemon.getBattlerIndex(),
toDmgValue(pokemon.getMaxHp() / 8), toDmgValue(pokemon.getMaxHp() / 8),
i18next.t("abilityTriggers:poisonHeal", { pokemonName: getPokemonNameWithAffix(pokemon), abilityName }), i18next.t("abilityTriggers:poisonHeal", { pokemonName: getPokemonNameWithAffix(pokemon), abilityName }),
true, true,
),
); );
} }
} }
@ -5529,8 +5556,11 @@ export class RepeatBerryNextTurnAbAttr extends PostTurnAbAttr {
_cancelled: BooleanHolder | null, _cancelled: BooleanHolder | null,
_args: any[], _args: any[],
): void { ): void {
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new CommonAnimPhase(pokemon.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.USE_ITEM), "CommonAnimPhase",
pokemon.getBattlerIndex(),
pokemon.getBattlerIndex(),
CommonAnim.USE_ITEM,
); );
// Re-apply effects of all berries previously scarfed. // Re-apply effects of all berries previously scarfed.
@ -5593,15 +5623,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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew("StatStageChangePhase", pokemon.getBattlerIndex(), true, [raisedStat], 2);
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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew("StatStageChangePhase", pokemon.getBattlerIndex(), true, [loweredStat], -1);
new StatStageChangePhase(pokemon.getBattlerIndex(), true, [loweredStat], -1),
);
} }
} }
} }
@ -5617,7 +5643,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.phaseManager.unshiftPhase(new StatStageChangePhase(pokemon.getBattlerIndex(), true, [Stat.SPD], 1)); globalScene.phaseManager.unshiftNew("StatStageChangePhase", pokemon.getBattlerIndex(), true, [Stat.SPD], 1);
} }
} }
@ -5629,8 +5655,8 @@ 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new PokemonHealPhase( "PokemonHealPhase",
pokemon.getBattlerIndex(), pokemon.getBattlerIndex(),
toDmgValue(pokemon.getMaxHp() / 16), toDmgValue(pokemon.getMaxHp() / 16),
i18next.t("abilityTriggers:postTurnHeal", { i18next.t("abilityTriggers:postTurnHeal", {
@ -5638,7 +5664,6 @@ export class PostTurnHealAbAttr extends PostTurnAbAttr {
abilityName, abilityName,
}), }),
true, true,
),
); );
} }
} }
@ -5857,13 +5882,14 @@ export class PostDancingMoveAbAttr extends PostMoveUsedAbAttr {
): void { ): void {
if (!simulated) { if (!simulated) {
dancer.turnData.extraTurns++; dancer.turnData.extraTurns++;
const phaseManager = globalScene.phaseManager;
// 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.phaseManager.unshiftPhase(new MovePhase(dancer, target, move, true, true)); phaseManager.unshiftNew("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.phaseManager.unshiftPhase(new MovePhase(dancer, [dancer.getBattlerIndex()], move, true, true)); phaseManager.unshiftNew("MovePhase", dancer, [dancer.getBattlerIndex()], move, true, true);
} }
} }
} }
@ -5949,8 +5975,8 @@ export class StatStageChangeCopyAbAttr extends AbAttr {
args: any[], args: any[],
): void { ): void {
if (!simulated) { if (!simulated) {
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new StatStageChangePhase( "StatStageChangePhase",
pokemon.getBattlerIndex(), pokemon.getBattlerIndex(),
true, true,
args[0] as BattleStat[], args[0] as BattleStat[],
@ -5958,7 +5984,6 @@ export class StatStageChangeCopyAbAttr extends AbAttr {
true, true,
false, false,
false, false,
),
); );
} }
} }
@ -6058,8 +6083,8 @@ export class HealFromBerryUseAbAttr extends AbAttr {
} }
const { name: abilityName } = passive ? pokemon.getPassiveAbility() : pokemon.getAbility(); const { name: abilityName } = passive ? pokemon.getPassiveAbility() : pokemon.getAbility();
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new PokemonHealPhase( "PokemonHealPhase",
pokemon.getBattlerIndex(), pokemon.getBattlerIndex(),
toDmgValue(pokemon.getMaxHp() * this.healPercent), toDmgValue(pokemon.getMaxHp() * this.healPercent),
i18next.t("abilityTriggers:healFromBerryUse", { i18next.t("abilityTriggers:healFromBerryUse", {
@ -6067,7 +6092,6 @@ export class HealFromBerryUseAbAttr extends AbAttr {
abilityName, abilityName,
}), }),
true, true,
),
); );
} }
} }
@ -6502,8 +6526,12 @@ export class FlinchStatStageChangeAbAttr extends FlinchEffectAbAttr {
_args: any[], _args: any[],
): void { ): void {
if (!simulated) { if (!simulated) {
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new StatStageChangePhase(pokemon.getBattlerIndex(), true, this.stats, this.stages), "StatStageChangePhase",
pokemon.getBattlerIndex(),
true,
this.stats,
this.stages,
); );
} }
} }
@ -7241,9 +7269,13 @@ class ForceSwitchOutHelper {
if (switchOutTarget.hp > 0) { if (switchOutTarget.hp > 0) {
switchOutTarget.leaveField(this.switchType === SwitchType.SWITCH); switchOutTarget.leaveField(this.switchType === SwitchType.SWITCH);
globalScene.phaseManager.prependToPhase( globalScene.phaseManager.prependNewToPhase(
new SwitchPhase(this.switchType, switchOutTarget.getFieldIndex(), true, true), "MoveEndPhase",
MoveEndPhase, "SwitchPhase",
this.switchType,
switchOutTarget.getFieldIndex(),
true,
true,
); );
return true; return true;
} }
@ -7260,9 +7292,14 @@ class ForceSwitchOutHelper {
const summonIndex = globalScene.currentBattle.trainer const summonIndex = globalScene.currentBattle.trainer
? globalScene.currentBattle.trainer.getNextSummonIndex((switchOutTarget as EnemyPokemon).trainerSlot) ? globalScene.currentBattle.trainer.getNextSummonIndex((switchOutTarget as EnemyPokemon).trainerSlot)
: 0; : 0;
globalScene.phaseManager.prependToPhase( globalScene.phaseManager.prependNewToPhase(
new SwitchSummonPhase(this.switchType, switchOutTarget.getFieldIndex(), summonIndex, false, false), "MoveEndPhase",
MoveEndPhase, "SwitchSummonPhase",
this.switchType,
switchOutTarget.getFieldIndex(),
summonIndex,
false,
false,
); );
return true; return true;
} }
@ -7294,13 +7331,13 @@ class ForceSwitchOutHelper {
globalScene.clearEnemyHeldItemModifiers(); globalScene.clearEnemyHeldItemModifiers();
if (switchOutTarget.hp) { if (switchOutTarget.hp) {
globalScene.phaseManager.pushPhase(new BattleEndPhase(false)); globalScene.phaseManager.pushNew("BattleEndPhase", false);
if (globalScene.gameMode.hasRandomBiomes || globalScene.isNewBiome()) { if (globalScene.gameMode.hasRandomBiomes || globalScene.isNewBiome()) {
globalScene.phaseManager.pushPhase(new SelectBiomePhase()); globalScene.phaseManager.pushNew("SelectBiomePhase");
} }
globalScene.phaseManager.pushPhase(new NewBattlePhase()); globalScene.phaseManager.pushNew("NewBattlePhase");
} }
} }
} }

View File

@ -26,10 +26,6 @@ import { AbilityId } from "#enums/ability-id";
import { ArenaTagType } from "#enums/arena-tag-type"; import { ArenaTagType } from "#enums/arena-tag-type";
import { BattlerTagType } from "#enums/battler-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type";
import { MoveId } from "#enums/move-id"; import { MoveId } from "#enums/move-id";
import { MoveEffectPhase } from "#app/phases/move-effect-phase";
import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase";
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
import { CommonAnimPhase } from "#app/phases/common-anim-phase";
export enum ArenaTagSide { export enum ArenaTagSide {
BOTH, BOTH,
@ -568,9 +564,7 @@ class WishTag extends ArenaTag {
const target = globalScene.getField()[this.battlerIndex]; const target = globalScene.getField()[this.battlerIndex];
if (target?.isActive(true)) { if (target?.isActive(true)) {
globalScene.phaseManager.queueMessage(this.triggerMessage); globalScene.phaseManager.queueMessage(this.triggerMessage);
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew("PokemonHealPhase", target.getBattlerIndex(), this.healHp, null, true, false);
new PokemonHealPhase(target.getBattlerIndex(), this.healHp, null, true, false),
);
} }
} }
} }
@ -893,8 +887,13 @@ export class DelayedAttackTag extends ArenaTag {
const ret = super.lapse(arena); const ret = super.lapse(arena);
if (!ret) { if (!ret) {
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new MoveEffectPhase(this.sourceId!, [this.targetIndex], allMoves[this.sourceMove!], false, true), "MoveEffectPhase",
this.sourceId!,
[this.targetIndex],
allMoves[this.sourceMove!],
false,
true,
); // TODO: are those bangs correct? ); // TODO: are those bangs correct?
} }
@ -1028,8 +1027,8 @@ class StickyWebTag extends ArenaTrapTag {
}), }),
); );
const stages = new NumberHolder(-1); const stages = new NumberHolder(-1);
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new StatStageChangePhase( "StatStageChangePhase",
pokemon.getBattlerIndex(), pokemon.getBattlerIndex(),
false, false,
[Stat.SPD], [Stat.SPD],
@ -1040,7 +1039,6 @@ class StickyWebTag extends ArenaTrapTag {
null, null,
false, false,
true, true,
),
); );
return true; return true;
} }
@ -1138,26 +1136,26 @@ class TailwindTag extends ArenaTag {
const source = globalScene.getPokemonById(this.sourceId!); //TODO: this bang is questionable! const source = globalScene.getPokemonById(this.sourceId!); //TODO: this bang is questionable!
const party = (source?.isPlayer() ? globalScene.getPlayerField() : globalScene.getEnemyField()) ?? []; const party = (source?.isPlayer() ? globalScene.getPlayerField() : globalScene.getEnemyField()) ?? [];
const phaseManager = globalScene.phaseManager;
for (const pokemon of party) { for (const pokemon of party) {
// 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.phaseManager.queueMessage( phaseManager.queueMessage(
i18next.t("abilityTriggers:windPowerCharged", { i18next.t("abilityTriggers:windPowerCharged", {
pokemonName: getPokemonNameWithAffix(pokemon), pokemonName: getPokemonNameWithAffix(pokemon),
moveName: this.getMoveName(), moveName: this.getMoveName(),
}), }),
); );
} }
// 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.phaseManager.queueAbilityDisplay(pokemon, false, true); phaseManager.queueAbilityDisplay(pokemon, false, true);
globalScene.phaseManager.unshiftPhase( phaseManager.unshiftNew("StatStageChangePhase", pokemon.getBattlerIndex(), true, [Stat.ATK], 1, true);
new StatStageChangePhase(pokemon.getBattlerIndex(), true, [Stat.ATK], 1, true), phaseManager.queueAbilityDisplay(pokemon, false, false);
);
globalScene.phaseManager.queueAbilityDisplay(pokemon, false, false);
} }
} }
} }
@ -1319,8 +1317,11 @@ class FireGrassPledgeTag extends ArenaTag {
}), }),
); );
// TODO: Replace this with a proper animation // TODO: Replace this with a proper animation
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new CommonAnimPhase(pokemon.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.MAGMA_STORM), "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 });
}); });

View File

@ -27,12 +27,9 @@ import { PokemonType } from "#enums/pokemon-type";
import type Pokemon from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon";
import { HitResult, MoveResult } from "#app/field/pokemon"; import { HitResult, MoveResult } from "#app/field/pokemon";
import { getPokemonNameWithAffix } from "#app/messages"; import { getPokemonNameWithAffix } from "#app/messages";
import { CommonAnimPhase } from "#app/phases/common-anim-phase";
import type { MoveEffectPhase } from "#app/phases/move-effect-phase"; import type { MoveEffectPhase } from "#app/phases/move-effect-phase";
import { MovePhase } from "#app/phases/move-phase"; import type { MovePhase } from "#app/phases/move-phase";
import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase";
import type { StatStageChangeCallback } from "#app/phases/stat-stage-change-phase"; import type { StatStageChangeCallback } from "#app/phases/stat-stage-change-phase";
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
import i18next from "#app/plugins/i18n"; import i18next from "#app/plugins/i18n";
import { BooleanHolder, getFrameMs, NumberHolder, toDmgValue } from "#app/utils/common"; import { BooleanHolder, getFrameMs, NumberHolder, toDmgValue } from "#app/utils/common";
import { AbilityId } from "#enums/ability-id"; import { AbilityId } from "#enums/ability-id";
@ -560,7 +557,7 @@ export class ShellTrapTag extends BattlerTag {
// 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.phaseManager.phaseQueue.splice(shellTrapPhaseIndex, 1)[0]; const shellTrapMovePhase = globalScene.phaseManager.phaseQueue.splice(shellTrapPhaseIndex, 1)[0];
globalScene.phaseManager.prependToPhase(shellTrapMovePhase, MovePhase); globalScene.phaseManager.prependToPhase(shellTrapMovePhase, "MovePhase");
} }
this.activated = true; this.activated = true;
@ -719,9 +716,7 @@ export class ConfusedTag extends BattlerTag {
onAdd(pokemon: Pokemon): void { onAdd(pokemon: Pokemon): void {
super.onAdd(pokemon); super.onAdd(pokemon);
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew("CommonAnimPhase", pokemon.getBattlerIndex(), undefined, CommonAnim.CONFUSION);
new CommonAnimPhase(pokemon.getBattlerIndex(), undefined, CommonAnim.CONFUSION),
);
globalScene.phaseManager.queueMessage( globalScene.phaseManager.queueMessage(
i18next.t("battlerTags:confusedOnAdd", { i18next.t("battlerTags:confusedOnAdd", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
@ -756,14 +751,14 @@ export class ConfusedTag extends BattlerTag {
return false; return false;
} }
globalScene.phaseManager.queueMessage( const phaseManager = globalScene.phaseManager;
phaseManager.queueMessage(
i18next.t("battlerTags:confusedLapse", { i18next.t("battlerTags:confusedLapse", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}), }),
); );
globalScene.phaseManager.unshiftPhase( phaseManager.unshiftNew("CommonAnimPhase", pokemon.getBattlerIndex(), undefined, CommonAnim.CONFUSION);
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) {
@ -773,9 +768,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.phaseManager.queueMessage(i18next.t("battlerTags:confusedLapseHurtItself")); phaseManager.queueMessage(i18next.t("battlerTags:confusedLapseHurtItself"));
pokemon.damageAndUpdate(damage, { result: HitResult.CONFUSION }); pokemon.damageAndUpdate(damage, { result: HitResult.CONFUSION });
(globalScene.phaseManager.getCurrentPhase() as MovePhase).cancel(); (phaseManager.getCurrentPhase() as MovePhase).cancel();
} }
return true; return true;
@ -881,24 +876,24 @@ export class InfatuatedTag extends BattlerTag {
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean { lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
const ret = lapseType !== BattlerTagLapseType.CUSTOM || super.lapse(pokemon, lapseType); const ret = lapseType !== BattlerTagLapseType.CUSTOM || super.lapse(pokemon, lapseType);
const phaseManager = globalScene.phaseManager;
if (ret) { if (ret) {
globalScene.phaseManager.queueMessage( 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.phaseManager.unshiftPhase( phaseManager.unshiftNew("CommonAnimPhase", pokemon.getBattlerIndex(), undefined, CommonAnim.ATTRACT);
new CommonAnimPhase(pokemon.getBattlerIndex(), undefined, CommonAnim.ATTRACT),
);
if (pokemon.randBattleSeedInt(2)) { if (pokemon.randBattleSeedInt(2)) {
globalScene.phaseManager.queueMessage( phaseManager.queueMessage(
i18next.t("battlerTags:infatuatedLapseImmobilize", { i18next.t("battlerTags:infatuatedLapseImmobilize", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}), }),
); );
(globalScene.phaseManager.getCurrentPhase() as MovePhase).cancel(); (phaseManager.getCurrentPhase() as MovePhase).cancel();
} }
} }
@ -965,14 +960,17 @@ export class SeedTag extends BattlerTag {
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled); applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled);
if (!cancelled.value) { if (!cancelled.value) {
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new CommonAnimPhase(source.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.LEECH_SEED), "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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new PokemonHealPhase( "PokemonHealPhase",
source.getBattlerIndex(), source.getBattlerIndex(),
!reverseDrain ? damage : damage * -1, !reverseDrain ? damage : damage * -1,
!reverseDrain !reverseDrain
@ -984,7 +982,6 @@ export class SeedTag extends BattlerTag {
}), }),
false, false,
true, true,
),
); );
} }
} }
@ -1039,9 +1036,9 @@ export class PowderTag extends BattlerTag {
movePhase.fail(); movePhase.fail();
movePhase.showMoveText(); movePhase.showMoveText();
globalScene.phaseManager.unshiftPhase( const idx = pokemon.getBattlerIndex();
new CommonAnimPhase(pokemon.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.POWDER),
); globalScene.phaseManager.unshiftNew("CommonAnimPhase", idx, idx, CommonAnim.POWDER);
const cancelDamage = new BooleanHolder(false); const cancelDamage = new BooleanHolder(false);
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelDamage); applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelDamage);
@ -1088,14 +1085,13 @@ 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.phaseManager.queueMessage( const phaseManager = globalScene.phaseManager;
phaseManager.queueMessage(
i18next.t("battlerTags:nightmareLapse", { i18next.t("battlerTags:nightmareLapse", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}), }),
); );
globalScene.phaseManager.unshiftPhase( phaseManager.unshiftNew("CommonAnimPhase", pokemon.getBattlerIndex(), undefined, CommonAnim.CURSE); // TODO: Update animation type
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);
@ -1194,7 +1190,7 @@ export class EncoreTag extends MoveRestrictionBattlerTag {
const lastMove = pokemon.getLastXMoves(1)[0]; const lastMove = pokemon.getLastXMoves(1)[0];
globalScene.phaseManager.tryReplacePhase( globalScene.phaseManager.tryReplacePhase(
m => m.is("MovePhase") && m.pokemon === pokemon, m => m.is("MovePhase") && m.pokemon === pokemon,
new MovePhase(pokemon, lastMove.targets ?? [], movesetMove), globalScene.phaseManager.create("MovePhase", pokemon, lastMove.targets ?? [], movesetMove),
); );
} }
} }
@ -1276,15 +1272,14 @@ 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new PokemonHealPhase( "PokemonHealPhase",
pokemon.getBattlerIndex(), pokemon.getBattlerIndex(),
toDmgValue(pokemon.getMaxHp() / 16), toDmgValue(pokemon.getMaxHp() / 16),
i18next.t("battlerTags:ingrainLapse", { i18next.t("battlerTags:ingrainLapse", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}), }),
true, true,
),
); );
} }
@ -1315,8 +1310,12 @@ 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new StatStageChangePhase(pokemon.getBattlerIndex(), false, [Stat.DEF, Stat.SPDEF], -1), "StatStageChangePhase",
pokemon.getBattlerIndex(),
false,
[Stat.DEF, Stat.SPDEF],
-1,
); );
return true; return true;
} }
@ -1344,8 +1343,8 @@ 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new PokemonHealPhase( "PokemonHealPhase",
pokemon.getBattlerIndex(), pokemon.getBattlerIndex(),
toDmgValue(pokemon.getMaxHp() / 16), toDmgValue(pokemon.getMaxHp() / 16),
i18next.t("battlerTags:aquaRingLapse", { i18next.t("battlerTags:aquaRingLapse", {
@ -1353,7 +1352,6 @@ export class AquaRingTag extends BattlerTag {
pokemonName: getPokemonNameWithAffix(pokemon), pokemonName: getPokemonNameWithAffix(pokemon),
}), }),
true, true,
),
); );
} }
@ -1445,13 +1443,14 @@ export abstract class DamagingTrapTag extends TrappedTag {
const ret = super.lapse(pokemon, lapseType); const ret = super.lapse(pokemon, lapseType);
if (ret) { if (ret) {
globalScene.phaseManager.queueMessage( const phaseManager = globalScene.phaseManager;
phaseManager.queueMessage(
i18next.t("battlerTags:damagingTrapLapse", { i18next.t("battlerTags:damagingTrapLapse", {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
moveName: this.getMoveName(), moveName: this.getMoveName(),
}), }),
); );
globalScene.phaseManager.unshiftPhase(new CommonAnimPhase(pokemon.getBattlerIndex(), undefined, this.commonAnim)); phaseManager.unshiftNew("CommonAnimPhase", pokemon.getBattlerIndex(), undefined, this.commonAnim);
const cancelled = new BooleanHolder(false); const cancelled = new BooleanHolder(false);
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled); applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled);
@ -1764,8 +1763,12 @@ 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new StatStageChangePhase(attacker.getBattlerIndex(), false, [this.stat], this.levels), "StatStageChangePhase",
attacker.getBattlerIndex(),
false,
[this.stat],
this.levels,
); );
} }
} }
@ -2281,8 +2284,11 @@ 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new CommonAnimPhase(pokemon.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.SALT_CURE), "CommonAnimPhase",
pokemon.getBattlerIndex(),
pokemon.getBattlerIndex(),
CommonAnim.SALT_CURE,
); );
const cancelled = new BooleanHolder(false); const cancelled = new BooleanHolder(false);
@ -2332,8 +2338,11 @@ 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new CommonAnimPhase(pokemon.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.SALT_CURE), "CommonAnimPhase",
pokemon.getBattlerIndex(),
pokemon.getBattlerIndex(),
CommonAnim.SALT_CURE,
); );
const cancelled = new BooleanHolder(false); const cancelled = new BooleanHolder(false);
@ -2509,13 +2518,12 @@ 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new StatStageChangePhase( "StatStageChangePhase",
pokemon.getBattlerIndex(), pokemon.getBattlerIndex(),
true, true,
[Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD], [Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF, Stat.SPD],
2, 2,
),
); );
} }
@ -2592,8 +2600,8 @@ 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new StatStageChangePhase( "StatStageChangePhase",
pokemon.getBattlerIndex(), pokemon.getBattlerIndex(),
true, true,
[Stat.SPDEF, Stat.DEF], [Stat.SPDEF, Stat.DEF],
@ -2602,7 +2610,6 @@ export class StockpilingTag extends BattlerTag {
false, false,
true, true,
this.onStatStagesChanged, this.onStatStagesChanged,
),
); );
} }
} }
@ -2620,14 +2627,28 @@ export class StockpilingTag extends BattlerTag {
const spDefChange = this.statChangeCounts[Stat.SPDEF]; const spDefChange = this.statChangeCounts[Stat.SPDEF];
if (defChange) { if (defChange) {
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new StatStageChangePhase(pokemon.getBattlerIndex(), true, [Stat.DEF], -defChange, true, false, true), "StatStageChangePhase",
pokemon.getBattlerIndex(),
true,
[Stat.DEF],
-defChange,
true,
false,
true,
); );
} }
if (spDefChange) { if (spDefChange) {
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new StatStageChangePhase(pokemon.getBattlerIndex(), true, [Stat.SPDEF], -spDefChange, true, false, true), "StatStageChangePhase",
pokemon.getBattlerIndex(),
true,
[Stat.SPDEF],
-spDefChange,
true,
false,
true,
); );
} }
} }
@ -2667,9 +2688,7 @@ export class GulpMissileTag extends BattlerTag {
} }
if (this.tagType === BattlerTagType.GULP_MISSILE_ARROKUDA) { if (this.tagType === BattlerTagType.GULP_MISSILE_ARROKUDA) {
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew("StatStageChangePhase", attacker.getBattlerIndex(), false, [Stat.DEF], -1);
new StatStageChangePhase(attacker.getBattlerIndex(), false, [Stat.DEF], -1),
);
} else { } else {
attacker.trySetStatus(StatusEffect.PARALYSIS, true, pokemon); attacker.trySetStatus(StatusEffect.PARALYSIS, true, pokemon);
} }
@ -3290,8 +3309,15 @@ export class SyrupBombTag extends BattlerTag {
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
}), }),
); );
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new StatStageChangePhase(pokemon.getBattlerIndex(), true, [Stat.SPD], -1, true, false, true), "StatStageChangePhase",
pokemon.getBattlerIndex(),
true,
[Stat.SPD],
-1,
true,
false,
true,
); );
return --this.turnCount > 0; return --this.turnCount > 0;
} }

View File

@ -8,8 +8,6 @@ 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";
import { Stat, type BattleStat } from "#app/enums/stat"; import { Stat, type BattleStat } from "#app/enums/stat";
import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase";
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
export function getBerryName(berryType: BerryType): string { export function getBerryName(berryType: BerryType): string {
@ -75,8 +73,8 @@ 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new PokemonHealPhase( "PokemonHealPhase",
consumer.getBattlerIndex(), consumer.getBattlerIndex(),
hpHealed.value, hpHealed.value,
i18next.t("battle:hpHealBerry", { i18next.t("battle:hpHealBerry", {
@ -84,7 +82,6 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc {
berryName: getBerryName(berryType), berryName: getBerryName(berryType),
}), }),
true, true,
),
); );
} }
break; break;
@ -109,8 +106,12 @@ 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new StatStageChangePhase(consumer.getBattlerIndex(), true, [stat], statStages.value), "StatStageChangePhase",
consumer.getBattlerIndex(),
true,
[stat],
statStages.value,
); );
} }
break; break;
@ -126,8 +127,12 @@ 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new StatStageChangePhase(consumer.getBattlerIndex(), true, [randStat], stages.value), "StatStageChangePhase",
consumer.getBattlerIndex(),
true,
[randStat],
stages.value,
); );
} }
break; break;

View File

@ -1890,8 +1890,8 @@ 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.phaseManager.unshiftPhase(new PokemonHealPhase(target.getBattlerIndex(), globalScene.phaseManager.unshiftNew("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);
} }
getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): number { getTargetBenefitScore(user: Pokemon, target: Pokemon, move: Move): number {
@ -2021,8 +2021,10 @@ 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.phaseManager.pushPhase( const pm = globalScene.phaseManager;
new PokemonHealPhase(
pm.pushPhase(
pm.create("PokemonHealPhase",
user.getBattlerIndex(), user.getBattlerIndex(),
maxPartyMemberHp, maxPartyMemberHp,
i18next.t(this.moveMessage, { pokemonName: getPokemonNameWithAffix(user) }), i18next.t(this.moveMessage, { pokemonName: getPokemonNameWithAffix(user) }),
@ -2233,7 +2235,7 @@ export class HitHealAttr extends MoveEffectAttr {
message = ""; message = "";
} }
} }
globalScene.phaseManager.unshiftPhase(new PokemonHealPhase(user.getBattlerIndex(), healAmount, message, false, true)); globalScene.phaseManager.unshiftNew("PokemonHealPhase", user.getBattlerIndex(), healAmount, message, false, true);
return true; return true;
} }
@ -3067,7 +3069,7 @@ export class DelayedAttackAttr extends OverrideMoveEffectAttr {
if (!virtual) { if (!virtual) {
overridden.value = true; overridden.value = true;
globalScene.phaseManager.unshiftPhase(new MoveAnimPhase(new MoveChargeAnim(this.chargeAnim, move.id, user))); globalScene.phaseManager.unshiftNew("MoveAnimPhase", new MoveChargeAnim(this.chargeAnim, move.id, user));
globalScene.phaseManager.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;
@ -3125,7 +3127,7 @@ export class AwaitCombinedPledgeAttr extends OverrideMoveEffectAttr {
const allyMovePhaseIndex = globalScene.phaseManager.phaseQueue.indexOf(allyMovePhase); const allyMovePhaseIndex = globalScene.phaseManager.phaseQueue.indexOf(allyMovePhase);
const firstMovePhaseIndex = globalScene.phaseManager.phaseQueue.findIndex((phase) => phase.is("MovePhase")); const firstMovePhaseIndex = globalScene.phaseManager.phaseQueue.findIndex((phase) => phase.is("MovePhase"));
if (allyMovePhaseIndex !== firstMovePhaseIndex) { if (allyMovePhaseIndex !== firstMovePhaseIndex) {
globalScene.phaseManager.prependToPhase(globalScene.phaseManager.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 +3209,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.phaseManager.unshiftPhase(new StatStageChangePhase((this.selfTarget ? user : target).getBattlerIndex(), this.selfTarget, this.stats, stages, this.showMessage)); globalScene.phaseManager.unshiftNew("StatStageChangePhase", (this.selfTarget ? user : target).getBattlerIndex(), this.selfTarget, this.stats, stages, this.showMessage);
return true; return true;
} }
@ -3432,7 +3434,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.phaseManager.unshiftPhase(new StatStageChangePhase(target.getBattlerIndex(), this.selfTarget, boostStat, 2)); globalScene.phaseManager.unshiftNew("StatStageChangePhase", target.getBattlerIndex(), this.selfTarget, boostStat, 2);
return true; return true;
} }
return false; return false;
@ -3510,7 +3512,7 @@ export class OrderUpStatBoostAttr extends MoveEffectAttr {
break; break;
} }
globalScene.phaseManager.unshiftPhase(new StatStageChangePhase(user.getBattlerIndex(), this.selfTarget, [ increasedStat ], 1)); globalScene.phaseManager.unshiftNew("StatStageChangePhase", user.getBattlerIndex(), this.selfTarget, [ increasedStat ], 1);
return true; return true;
} }
} }
@ -4227,8 +4229,8 @@ 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.phaseManager.unshiftPhase(new PokemonHealPhase(target.getBattlerIndex(), globalScene.phaseManager.unshiftNew("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);
} }
return true; return true;
@ -4488,7 +4490,7 @@ export class CueNextRoundAttr extends MoveEffectAttr {
const nextRoundIndex = globalScene.phaseManager.phaseQueue.indexOf(nextRoundPhase); const nextRoundIndex = globalScene.phaseManager.phaseQueue.indexOf(nextRoundPhase);
const nextMoveIndex = globalScene.phaseManager.phaseQueue.findIndex(phase => phase.is("MovePhase")); const nextMoveIndex = globalScene.phaseManager.phaseQueue.findIndex(phase => phase.is("MovePhase"));
if (nextRoundIndex !== nextMoveIndex) { if (nextRoundIndex !== nextMoveIndex) {
globalScene.phaseManager.prependToPhase(globalScene.phaseManager.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,7 +4548,7 @@ export class SpectralThiefAttr extends StatChangeBeforeDmgCalcAttr {
*/ */
const availableToSteal = Math.min(statStageValueTarget, 6 - statStageValueUser); const availableToSteal = Math.min(statStageValueTarget, 6 - statStageValueUser);
globalScene.phaseManager.unshiftPhase(new StatStageChangePhase(user.getBattlerIndex(), this.selfTarget, [ s ], availableToSteal)); globalScene.phaseManager.unshiftNew("StatStageChangePhase", user.getBattlerIndex(), this.selfTarget, [ s ], availableToSteal);
target.setStatStage(s, statStageValueTarget - availableToSteal); target.setStatStage(s, statStageValueTarget - availableToSteal);
} }
} }
@ -5680,8 +5682,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.phaseManager.unshiftPhase(new StatStageChangePhase(user.getBattlerIndex(), true, [ Stat.ATK, Stat.DEF ], 1)); globalScene.phaseManager.unshiftNew("StatStageChangePhase", user.getBattlerIndex(), true, [ Stat.ATK, Stat.DEF ], 1);
globalScene.phaseManager.unshiftPhase(new StatStageChangePhase(user.getBattlerIndex(), true, [ Stat.SPD ], -1)); globalScene.phaseManager.unshiftNew("StatStageChangePhase", user.getBattlerIndex(), true, [ Stat.SPD ], -1);
return true; return true;
} }
} }
@ -6154,7 +6156,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.phaseManager.unshiftPhase(new RevivalBlessingPhase(user)); globalScene.phaseManager.unshiftNew("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
@ -6177,7 +6179,7 @@ export class RevivalBlessingAttr extends MoveEffectAttr {
if (user.fieldPosition === FieldPosition.CENTER) { if (user.fieldPosition === FieldPosition.CENTER) {
user.setFieldPosition(FieldPosition.LEFT); user.setFieldPosition(FieldPosition.LEFT);
} }
globalScene.phaseManager.unshiftPhase(new SwitchSummonPhase(SwitchType.SWITCH, allyPokemon.getFieldIndex(), slotIndex, false, false)); globalScene.phaseManager.unshiftNew("SwitchSummonPhase", SwitchType.SWITCH, allyPokemon.getFieldIndex(), slotIndex, false, false);
} }
} }
return true; return true;
@ -6255,26 +6257,23 @@ 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.phaseManager.prependToPhase( globalScene.phaseManager.prependNewToPhase(
new SwitchSummonPhase( "MoveEndPhase",
"SwitchSummonPhase",
this.switchType, this.switchType,
switchOutTarget.getFieldIndex(), switchOutTarget.getFieldIndex(),
slotIndex, slotIndex,
false, false,
true true
),
MoveEndPhase
); );
} else { } else {
switchOutTarget.leaveField(this.switchType === SwitchType.SWITCH); switchOutTarget.leaveField(this.switchType === SwitchType.SWITCH);
globalScene.phaseManager.prependToPhase( globalScene.phaseManager.prependNewToPhase("MoveEndPhase",
new SwitchPhase( "SwitchPhase",
this.switchType, this.switchType,
switchOutTarget.getFieldIndex(), switchOutTarget.getFieldIndex(),
true, true,
true true
),
MoveEndPhase
); );
return true; return true;
} }
@ -6298,27 +6297,23 @@ 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.phaseManager.prependToPhase( globalScene.phaseManager.prependNewToPhase("MoveEndPhase",
new SwitchSummonPhase( "SwitchSummonPhase",
this.switchType, this.switchType,
switchOutTarget.getFieldIndex(), switchOutTarget.getFieldIndex(),
slotIndex, slotIndex,
false, false,
false false
),
MoveEndPhase
); );
} else { } else {
switchOutTarget.leaveField(this.switchType === SwitchType.SWITCH); switchOutTarget.leaveField(this.switchType === SwitchType.SWITCH);
globalScene.phaseManager.prependToPhase( globalScene.phaseManager.prependNewToPhase("MoveEndPhase",
new SwitchSummonPhase( "SwitchSummonPhase",
this.switchType, this.switchType,
switchOutTarget.getFieldIndex(), switchOutTarget.getFieldIndex(),
(globalScene.currentBattle.trainer ? globalScene.currentBattle.trainer.getNextSummonIndex((switchOutTarget as EnemyPokemon).trainerSlot) : 0), (globalScene.currentBattle.trainer ? globalScene.currentBattle.trainer.getNextSummonIndex((switchOutTarget as EnemyPokemon).trainerSlot) : 0),
false, false,
false false
),
MoveEndPhase
); );
} }
} }
@ -6351,13 +6346,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.phaseManager.pushPhase(new BattleEndPhase(false)); globalScene.phaseManager.pushNew("BattleEndPhase", false);
if (globalScene.gameMode.hasRandomBiomes || globalScene.isNewBiome()) { if (globalScene.gameMode.hasRandomBiomes || globalScene.isNewBiome()) {
globalScene.phaseManager.pushPhase(new SelectBiomePhase()); globalScene.phaseManager.pushNew("SelectBiomePhase");
} }
globalScene.phaseManager.pushPhase(new NewBattlePhase()); globalScene.phaseManager.pushNew("NewBattlePhase");
} }
} }
@ -6733,8 +6728,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.phaseManager.unshiftPhase(new LoadMoveAnimPhase(move.id)); globalScene.phaseManager.unshiftNew("LoadMoveAnimPhase", move.id);
globalScene.phaseManager.unshiftPhase(new MovePhase(user, targets, new PokemonMove(move.id, 0, 0, true), true, true)); globalScene.phaseManager.unshiftNew("MovePhase", user, targets, new PokemonMove(move.id, 0, 0, true), true, true);
return true; return true;
} }
} }
@ -6962,8 +6957,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.phaseManager.unshiftPhase(new LoadMoveAnimPhase(moveId)); globalScene.phaseManager.unshiftNew("LoadMoveAnimPhase", moveId);
globalScene.phaseManager.unshiftPhase(new MovePhase(user, [ target.getBattlerIndex() ], new PokemonMove(moveId, 0, 0, true), true)); globalScene.phaseManager.unshiftNew("MovePhase", user, [ target.getBattlerIndex() ], new PokemonMove(moveId, 0, 0, true), true);
return true; return true;
} }
} }
@ -7050,7 +7045,7 @@ export class RepeatMoveAttr extends MoveEffectAttr {
})); }));
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.phaseManager.appendToPhase(new MovePhase(target, moveTargets, movesetMove), MoveEndPhase); globalScene.phaseManager.appendNewToPhase("MoveEndPhase", "MovePhase", target, moveTargets, movesetMove);
return true; return true;
} }
@ -7550,7 +7545,7 @@ export class TransformAttr extends MoveEffectAttr {
return false; return false;
} }
globalScene.phaseManager.unshiftPhase(new PokemonTransformPhase(user.getBattlerIndex(), target.getBattlerIndex())); globalScene.phaseManager.unshiftNew("PokemonTransformPhase", user.getBattlerIndex(), target.getBattlerIndex());
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:transformedIntoTarget", { pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target) })); globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:transformedIntoTarget", { pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target) }));
@ -7852,7 +7847,7 @@ export class AfterYouAttr extends MoveEffectAttr {
//Will find next acting phase of the targeted pokémon, delete it and queue it next on successful delete. //Will find next acting phase of the targeted pokémon, delete it and queue it next on successful delete.
const nextAttackPhase = globalScene.phaseManager.findPhase<MovePhase>((phase) => phase.pokemon === target); const nextAttackPhase = globalScene.phaseManager.findPhase<MovePhase>((phase) => phase.pokemon === target);
if (nextAttackPhase && globalScene.phaseManager.tryRemovePhase((phase: MovePhase) => phase.pokemon === target)) { if (nextAttackPhase && globalScene.phaseManager.tryRemovePhase((phase: MovePhase) => phase.pokemon === target)) {
globalScene.phaseManager.prependToPhase(new MovePhase(target, [ ...nextAttackPhase.targets ], nextAttackPhase.move), MovePhase); globalScene.phaseManager.prependNewToPhase("MovePhase", "MovePhase", target, [ ...nextAttackPhase.targets ], nextAttackPhase.move);
} }
return true; return true;
@ -7889,7 +7884,7 @@ export class ForceLastAttr extends MoveEffectAttr {
globalScene.phaseManager.phaseQueue.splice( globalScene.phaseManager.phaseQueue.splice(
globalScene.phaseManager.phaseQueue.indexOf(prependPhase), globalScene.phaseManager.phaseQueue.indexOf(prependPhase),
0, 0,
new MovePhase(target, [ ...targetMovePhase.targets ], targetMovePhase.move, false, false, false, true) globalScene.phaseManager.create("MovePhase", target, [ ...targetMovePhase.targets ], targetMovePhase.move, false, false, false, true)
); );
} }
} }

View File

@ -19,7 +19,6 @@ import i18next from "i18next";
import type { IEggOptions } from "#app/data/egg"; import type { IEggOptions } from "#app/data/egg";
import { EggSourceType } from "#enums/egg-source-types"; import { EggSourceType } from "#enums/egg-source-types";
import { EggTier } from "#enums/egg-type"; import { EggTier } from "#enums/egg-type";
import { PartyHealPhase } from "#app/phases/party-heal-phase";
import { ModifierTier } from "#app/modifier/modifier-tier"; import { ModifierTier } from "#app/modifier/modifier-tier";
import { modifierTypes } from "#app/modifier/modifier-type"; import { modifierTypes } from "#app/modifier/modifier-type";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
@ -182,7 +181,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.phaseManager.unshiftPhase(new PartyHealPhase(true)); globalScene.phaseManager.unshiftNew("PartyHealPhase", true);
const eggOptions: IEggOptions = { const eggOptions: IEggOptions = {
pulled: false, pulled: false,

View File

@ -35,7 +35,6 @@ import { TrainerSlot } from "#enums/trainer-slot";
import { PokeballType } from "#enums/pokeball"; import { PokeballType } from "#enums/pokeball";
import type HeldModifierConfig from "#app/@types/held-modifier-config"; import type HeldModifierConfig from "#app/@types/held-modifier-config";
import type { BerryType } from "#enums/berry-type"; import type { BerryType } from "#enums/berry-type";
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
import { Stat } from "#enums/stat"; import { Stat } from "#enums/stat";
import i18next from "i18next"; import i18next from "i18next";
@ -237,8 +236,12 @@ 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new StatStageChangePhase(pokemon.getBattlerIndex(), true, statChangesForBattle, 1), "StatStageChangePhase",
pokemon.getBattlerIndex(),
true,
statChangesForBattle,
1,
); );
}, },
}, },

View File

@ -22,7 +22,6 @@ import { getPokemonSpecies } from "#app/data/pokemon-species";
import { speciesStarterCosts } from "#app/data/balance/starters"; import { speciesStarterCosts } from "#app/data/balance/starters";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import { ModifierRewardPhase } from "#app/phases/modifier-reward-phase";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import i18next from "i18next"; import i18next from "i18next";
@ -137,7 +136,7 @@ export const AnOfferYouCantRefuseEncounter: MysteryEncounter = MysteryEncounterB
}) })
.withOptionPhase(async () => { .withOptionPhase(async () => {
// Give the player a Shiny Charm // Give the player a Shiny Charm
globalScene.phaseManager.unshiftPhase(new ModifierRewardPhase(modifierTypes.SHINY_CHARM)); globalScene.phaseManager.unshiftNew("ModifierRewardPhase", modifierTypes.SHINY_CHARM);
leaveEncounterWithoutBattle(true); leaveEncounterWithoutBattle(true);
}) })
.build(), .build(),

View File

@ -35,7 +35,6 @@ import { BerryModifier } from "#app/modifier/modifier";
import i18next from "#app/plugins/i18n"; import i18next from "#app/plugins/i18n";
import { BerryType } from "#enums/berry-type"; import { BerryType } from "#enums/berry-type";
import { PERMANENT_STATS, Stat } from "#enums/stat"; import { PERMANENT_STATS, Stat } from "#enums/stat";
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
/** the i18n namespace for the encounter */ /** the i18n namespace for the encounter */
@ -237,8 +236,12 @@ 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new StatStageChangePhase(pokemon.getBattlerIndex(), true, statChangesForBattle, 1), "StatStageChangePhase",
pokemon.getBattlerIndex(),
true,
statChangesForBattle,
1,
); );
}; };
setEncounterRewards( setEncounterRewards(

View File

@ -26,7 +26,6 @@ import type { PlayerPokemon } from "#app/field/pokemon";
import type Pokemon from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon";
import { PokemonMove } from "#app/field/pokemon"; import { PokemonMove } from "#app/field/pokemon";
import { getEncounterText, showEncounterDialogue } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; import { getEncounterText, showEncounterDialogue } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
import { LearnMovePhase } from "#app/phases/learn-move-phase";
import { MoveId } from "#enums/move-id"; import { MoveId } from "#enums/move-id";
import type { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler"; import type { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option"; import { MysteryEncounterOptionBuilder } from "#app/data/mystery-encounters/mystery-encounter-option";
@ -766,8 +765,10 @@ 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new LearnMovePhase(result.selectedPokemonIndex, moveOptions[result.selectedOptionIndex].moveId), "LearnMovePhase",
result.selectedPokemonIndex,
moveOptions[result.selectedOptionIndex].moveId,
); );
} }

View File

@ -26,8 +26,6 @@ import type Pokemon from "#app/field/pokemon";
import { EnemyPokemon, PokemonMove } from "#app/field/pokemon"; import { EnemyPokemon, PokemonMove } from "#app/field/pokemon";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { modifierTypes } from "#app/modifier/modifier-type"; import { modifierTypes } from "#app/modifier/modifier-type";
import { LearnMovePhase } from "#app/phases/learn-move-phase";
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
import PokemonData from "#app/system/pokemon-data"; import PokemonData from "#app/system/pokemon-data";
import type { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler"; import type { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
import { BattlerTagType } from "#enums/battler-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type";
@ -176,13 +174,12 @@ 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new StatStageChangePhase( "StatStageChangePhase",
pokemon.getBattlerIndex(), pokemon.getBattlerIndex(),
true, true,
[Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF], [Stat.ATK, Stat.DEF, Stat.SPATK, Stat.SPDEF],
1, 1,
),
); );
}, },
}, },
@ -245,8 +242,10 @@ export const DancingLessonsEncounter: MysteryEncounter = MysteryEncounterBuilder
const onPokemonSelected = (pokemon: PlayerPokemon) => { const onPokemonSelected = (pokemon: PlayerPokemon) => {
encounter.setDialogueToken("selectedPokemon", pokemon.getNameToRender()); encounter.setDialogueToken("selectedPokemon", pokemon.getNameToRender());
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new LearnMovePhase(globalScene.getPlayerParty().indexOf(pokemon), MoveId.REVELATION_DANCE), "LearnMovePhase",
globalScene.getPlayerParty().indexOf(pokemon),
MoveId.REVELATION_DANCE,
); );
// Play animation again to "learn" the dance // Play animation again to "learn" the dance

View File

@ -16,7 +16,6 @@ import {
} from "#app/data/mystery-encounters/utils/encounter-pokemon-utils"; } from "#app/data/mystery-encounters/utils/encounter-pokemon-utils";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import { ModifierRewardPhase } from "#app/phases/modifier-reward-phase";
import type { PokemonHeldItemModifier } from "#app/modifier/modifier"; import type { PokemonHeldItemModifier } from "#app/modifier/modifier";
import { PokemonFormChangeItemModifier } from "#app/modifier/modifier"; import { PokemonFormChangeItemModifier } from "#app/modifier/modifier";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
@ -165,7 +164,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.phaseManager.unshiftPhase(new ModifierRewardPhase(modifierTypes.ROGUE_BALL)); globalScene.phaseManager.unshiftNew("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

@ -29,7 +29,6 @@ import {
} from "#app/modifier/modifier"; } from "#app/modifier/modifier";
import type { PokemonHeldItemModifierType } from "#app/modifier/modifier-type"; import type { PokemonHeldItemModifierType } from "#app/modifier/modifier-type";
import { modifierTypes } from "#app/modifier/modifier-type"; import { modifierTypes } from "#app/modifier/modifier-type";
import { ModifierRewardPhase } from "#app/phases/modifier-reward-phase";
import i18next from "#app/plugins/i18n"; import i18next from "#app/plugins/i18n";
import type { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler"; import type { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
import { randSeedItem } from "#app/utils/common"; import { randSeedItem } from "#app/utils/common";
@ -65,10 +64,10 @@ const doEventReward = () => {
return !(existingCharm && existingCharm.getStackCount() >= existingCharm.getMaxStackCount()); return !(existingCharm && existingCharm.getStackCount() >= existingCharm.getMaxStackCount());
}); });
if (candidates.length > 0) { if (candidates.length > 0) {
globalScene.phaseManager.unshiftPhase(new ModifierRewardPhase(modifierTypes[randSeedItem(candidates)])); globalScene.phaseManager.unshiftNew("ModifierRewardPhase", modifierTypes[randSeedItem(candidates)]);
} else { } else {
// At max stacks, give a Voucher instead // At max stacks, give a Voucher instead
globalScene.phaseManager.unshiftPhase(new ModifierRewardPhase(modifierTypes.VOUCHER)); globalScene.phaseManager.unshiftNew("ModifierRewardPhase", modifierTypes.VOUCHER);
} }
} }
}; };
@ -181,7 +180,7 @@ export const DelibirdyEncounter: MysteryEncounter = MysteryEncounterBuilder.with
); );
doEventReward(); doEventReward();
} else { } else {
globalScene.phaseManager.unshiftPhase(new ModifierRewardPhase(modifierTypes.AMULET_COIN)); globalScene.phaseManager.unshiftNew("ModifierRewardPhase", modifierTypes.AMULET_COIN);
doEventReward(); doEventReward();
} }
@ -266,7 +265,7 @@ export const DelibirdyEncounter: MysteryEncounter = MysteryEncounterBuilder.with
); );
doEventReward(); doEventReward();
} else { } else {
globalScene.phaseManager.unshiftPhase(new ModifierRewardPhase(modifierTypes.CANDY_JAR)); globalScene.phaseManager.unshiftNew("ModifierRewardPhase", modifierTypes.CANDY_JAR);
doEventReward(); doEventReward();
} }
} else { } else {
@ -288,7 +287,7 @@ export const DelibirdyEncounter: MysteryEncounter = MysteryEncounterBuilder.with
); );
doEventReward(); doEventReward();
} else { } else {
globalScene.phaseManager.unshiftPhase(new ModifierRewardPhase(modifierTypes.BERRY_POUCH)); globalScene.phaseManager.unshiftNew("ModifierRewardPhase", modifierTypes.BERRY_POUCH);
doEventReward(); doEventReward();
} }
} }
@ -372,7 +371,7 @@ export const DelibirdyEncounter: MysteryEncounter = MysteryEncounterBuilder.with
); );
doEventReward(); doEventReward();
} else { } else {
globalScene.phaseManager.unshiftPhase(new ModifierRewardPhase(modifierTypes.HEALING_CHARM)); globalScene.phaseManager.unshiftNew("ModifierRewardPhase", modifierTypes.HEALING_CHARM);
doEventReward(); doEventReward();
} }

View File

@ -44,7 +44,6 @@ import { EncounterAnim } from "#enums/encounter-anims";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { AbilityId } from "#enums/ability-id"; import { AbilityId } from "#enums/ability-id";
import { BattlerTagType } from "#enums/battler-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type";
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
import { Stat } from "#enums/stat"; import { Stat } from "#enums/stat";
import { Ability } from "#app/data/abilities/ability-class"; import { Ability } from "#app/data/abilities/ability-class";
import { FIRE_RESISTANT_ABILITIES } from "#app/data/mystery-encounters/requirements/requirement-groups"; import { FIRE_RESISTANT_ABILITIES } from "#app/data/mystery-encounters/requirements/requirement-groups";
@ -92,8 +91,12 @@ 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new StatStageChangePhase(pokemon.getBattlerIndex(), true, [Stat.SPDEF, Stat.SPD], 1), "StatStageChangePhase",
pokemon.getBattlerIndex(),
true,
[Stat.SPDEF, Stat.SPD],
1,
); );
}, },
}, },
@ -103,8 +106,12 @@ 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new StatStageChangePhase(pokemon.getBattlerIndex(), true, [Stat.SPDEF, Stat.SPD], 1), "StatStageChangePhase",
pokemon.getBattlerIndex(),
true,
[Stat.SPDEF, Stat.SPD],
1,
); );
}, },
}, },

View File

@ -32,7 +32,6 @@ import PokemonData from "#app/system/pokemon-data";
import { BattlerTagType } from "#enums/battler-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type";
import { queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; import { queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
import { randSeedInt } from "#app/utils/common"; import { randSeedInt } from "#app/utils/common";
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
/** the i18n namespace for the encounter */ /** the i18n namespace for the encounter */
@ -76,8 +75,12 @@ 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new StatStageChangePhase(pokemon.getBattlerIndex(), true, [randSeedInt(4, 1)], 2), "StatStageChangePhase",
pokemon.getBattlerIndex(),
true,
[randSeedInt(4, 1)],
2,
); );
}, },
}, },

View File

@ -25,9 +25,7 @@ import { getPokemonNameWithAffix } from "#app/messages";
import { PlayerGender } from "#enums/player-gender"; import { PlayerGender } from "#enums/player-gender";
import { getPokeballAtlasKey, getPokeballTintColor } from "#app/data/pokeball"; import { getPokeballAtlasKey, getPokeballTintColor } from "#app/data/pokeball";
import { addPokeballOpenParticles } from "#app/field/anims"; import { addPokeballOpenParticles } from "#app/field/anims";
import { ShinySparklePhase } from "#app/phases/shiny-sparkle-phase";
import { SpeciesFormChangeActiveTrigger } from "#app/data/pokemon-forms"; import { SpeciesFormChangeActiveTrigger } from "#app/data/pokemon-forms";
import { PostSummonPhase } from "#app/phases/post-summon-phase";
import { modifierTypes } from "#app/modifier/modifier-type"; import { modifierTypes } from "#app/modifier/modifier-type";
import { Nature } from "#enums/nature"; import { Nature } from "#enums/nature";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
@ -411,13 +409,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.phaseManager.unshiftPhase(new ShinySparklePhase(pokemon.getBattlerIndex())); globalScene.phaseManager.unshiftNew("ShinySparklePhase", pokemon.getBattlerIndex());
} }
pokemon.resetTurnData(); pokemon.resetTurnData();
globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeActiveTrigger, true); globalScene.triggerPokemonFormChange(pokemon, SpeciesFormChangeActiveTrigger, true);
globalScene.phaseManager.pushPhase(new PostSummonPhase(pokemon.getBattlerIndex())); globalScene.phaseManager.pushNew("PostSummonPhase", pokemon.getBattlerIndex());
resolve(); resolve();
}); });
}, },

View File

@ -17,7 +17,6 @@ import {
import { getPokemonSpecies } from "#app/data/pokemon-species"; import { getPokemonSpecies } from "#app/data/pokemon-species";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { ModifierTier } from "#app/modifier/modifier-tier"; import { ModifierTier } from "#app/modifier/modifier-tier";
import { GameOverPhase } from "#app/phases/game-over-phase";
import { randSeedInt } from "#app/utils/common"; import { randSeedInt } from "#app/utils/common";
import { MoveId } from "#enums/move-id"; import { MoveId } from "#enums/move-id";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
@ -190,7 +189,7 @@ export const MysteriousChestEncounter: MysteryEncounter = MysteryEncounterBuilde
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.phaseManager.clearPhaseQueue(); globalScene.phaseManager.clearPhaseQueue();
globalScene.phaseManager.unshiftPhase(new GameOverPhase()); globalScene.phaseManager.unshiftNew("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

@ -29,8 +29,6 @@ import { getEncounterText, showEncounterText } from "#app/data/mystery-encounter
import { getPokemonNameWithAffix } from "#app/messages"; import { getPokemonNameWithAffix } from "#app/messages";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import { ScanIvsPhase } from "#app/phases/scan-ivs-phase";
import { SummonPhase } from "#app/phases/summon-phase";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { NON_LEGEND_PARADOX_POKEMON } from "#app/data/balance/special-species-groups"; import { NON_LEGEND_PARADOX_POKEMON } from "#app/data/balance/special-species-groups";
@ -325,7 +323,7 @@ async function summonSafariPokemon() {
encounter.misc.pokemon = pokemon; encounter.misc.pokemon = pokemon;
encounter.misc.safariPokemonRemaining -= 1; encounter.misc.safariPokemonRemaining -= 1;
globalScene.phaseManager.unshiftPhase(new SummonPhase(0, false)); globalScene.phaseManager.unshiftNew("SummonPhase", 0, false);
encounter.setDialogueToken("pokemonName", getPokemonNameWithAffix(pokemon)); encounter.setDialogueToken("pokemonName", getPokemonNameWithAffix(pokemon));
@ -336,7 +334,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.phaseManager.pushPhase(new ScanIvsPhase(pokemon.getBattlerIndex())); globalScene.phaseManager.pushNew("ScanIvsPhase", pokemon.getBattlerIndex());
} }
} }

View File

@ -26,7 +26,6 @@ import { AiType, PokemonMove } from "#app/field/pokemon";
import { getPokemonSpecies } from "#app/data/pokemon-species"; import { getPokemonSpecies } from "#app/data/pokemon-species";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode"; import { MysteryEncounterOptionMode } from "#enums/mystery-encounter-option-mode";
import { PartyHealPhase } from "#app/phases/party-heal-phase";
import { BerryType } from "#enums/berry-type"; import { BerryType } from "#enums/berry-type";
import { Stat } from "#enums/stat"; import { Stat } from "#enums/stat";
import { CustomPokemonData } from "#app/data/custom-pokemon-data"; import { CustomPokemonData } from "#app/data/custom-pokemon-data";
@ -155,7 +154,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.phaseManager.unshiftPhase(new PartyHealPhase(true)); globalScene.phaseManager.unshiftNew("PartyHealPhase", true);
queueEncounterMessage(`${namespace}:option.2.rest_result`); queueEncounterMessage(`${namespace}:option.2.rest_result`);
leaveEncounterWithoutBattle(); leaveEncounterWithoutBattle();
}, },

View File

@ -27,7 +27,6 @@ import { getPartyLuckValue, modifierTypes } from "#app/modifier/modifier-type";
import { TrainerSlot } from "#enums/trainer-slot"; import { TrainerSlot } from "#enums/trainer-slot";
import { BattlerTagType } from "#enums/battler-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type";
import { getPokemonNameWithAffix } from "#app/messages"; import { getPokemonNameWithAffix } from "#app/messages";
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
import { Stat } from "#enums/stat"; import { Stat } from "#enums/stat";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
import { import {
@ -227,8 +226,12 @@ 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new StatStageChangePhase(pokemon.getBattlerIndex(), true, statChangesForBattle, 1), "StatStageChangePhase",
pokemon.getBattlerIndex(),
true,
statChangesForBattle,
1,
); );
}, },
}, },

View File

@ -27,7 +27,6 @@ import { BerryType } from "#enums/berry-type";
import { MysteryEncounterTier } from "#enums/mystery-encounter-tier"; import { MysteryEncounterTier } from "#enums/mystery-encounter-tier";
import { CustomPokemonData } from "#app/data/custom-pokemon-data"; import { CustomPokemonData } from "#app/data/custom-pokemon-data";
import { Stat } from "#enums/stat"; import { Stat } from "#enums/stat";
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
/** the i18n namespace for the encounter */ /** the i18n namespace for the encounter */
@ -116,8 +115,12 @@ 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new StatStageChangePhase(pokemon.getBattlerIndex(), true, [Stat.DEF, Stat.SPDEF], 1), "StatStageChangePhase",
pokemon.getBattlerIndex(),
true,
[Stat.DEF, Stat.SPDEF],
1,
); );
}, },
}, },

View File

@ -27,9 +27,6 @@ import { SpeciesFormChangeAbilityTrigger } from "#app/data/pokemon-forms";
import { applyPostBattleInitAbAttrs, PostBattleInitAbAttr } from "#app/data/abilities/ability"; import { applyPostBattleInitAbAttrs, PostBattleInitAbAttr } from "#app/data/abilities/ability";
import { showEncounterDialogue, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; import { showEncounterDialogue, showEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode"; import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
import { PartyHealPhase } from "#app/phases/party-heal-phase";
import { ShowTrainerPhase } from "#app/phases/show-trainer-phase";
import { ReturnPhase } from "#app/phases/return-phase";
import i18next from "i18next"; import i18next from "i18next";
import { ModifierTier } from "#app/modifier/modifier-tier"; import { ModifierTier } from "#app/modifier/modifier-tier";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
@ -143,7 +140,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.phaseManager.unshiftPhase(new PartyHealPhase(true)); globalScene.phaseManager.unshiftNew("PartyHealPhase", true);
setEncounterRewards({ setEncounterRewards({
guaranteedModifierTypeFuncs: [modifierTypes.RARER_CANDY], guaranteedModifierTypeFuncs: [modifierTypes.RARER_CANDY],
fillRemaining: false, fillRemaining: false,
@ -209,7 +206,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.phaseManager.unshiftPhase(new ReturnPhase(p))); playerField.forEach((_, p) => globalScene.phaseManager.unshiftNew("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 +224,7 @@ function endTrainerBattleAndShowDialogue(): Promise<void> {
applyPostBattleInitAbAttrs(PostBattleInitAbAttr, pokemon); applyPostBattleInitAbAttrs(PostBattleInitAbAttr, pokemon);
} }
globalScene.phaseManager.unshiftPhase(new ShowTrainerPhase()); globalScene.phaseManager.unshiftNew("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

@ -35,7 +35,6 @@ import { PokeballType } from "#enums/pokeball";
import { BattlerTagType } from "#enums/battler-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type";
import { queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; import { queueEncounterMessage } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
import { BerryModifier } from "#app/modifier/modifier"; import { BerryModifier } from "#app/modifier/modifier";
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
import { Stat } from "#enums/stat"; import { Stat } from "#enums/stat";
import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants"; import { CLASSIC_MODE_MYSTERY_ENCOUNTER_WAVES } from "#app/constants";
@ -103,8 +102,12 @@ 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new StatStageChangePhase(pokemon.getBattlerIndex(), true, statChangesForBattle, 1), "StatStageChangePhase",
pokemon.getBattlerIndex(),
true,
statChangesForBattle,
1,
); );
}, },
}, },

View File

@ -20,12 +20,6 @@ import {
modifierTypes, modifierTypes,
regenerateModifierPoolThresholds, regenerateModifierPoolThresholds,
} from "#app/modifier/modifier-type"; } from "#app/modifier/modifier-type";
import {
MysteryEncounterBattlePhase,
MysteryEncounterBattleStartCleanupPhase,
MysteryEncounterPhase,
MysteryEncounterRewardsPhase,
} from "#app/phases/mystery-encounter-phases";
import type PokemonData from "#app/system/pokemon-data"; import type PokemonData from "#app/system/pokemon-data";
import type { OptionSelectConfig, OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler"; import type { OptionSelectConfig, OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler";
import type { PartyOption, PokemonSelectFilter } from "#app/ui/party-ui-handler"; import type { PartyOption, PokemonSelectFilter } from "#app/ui/party-ui-handler";
@ -51,13 +45,6 @@ import type { IEggOptions } from "#app/data/egg";
import { Egg } from "#app/data/egg"; import { Egg } from "#app/data/egg";
import type { CustomPokemonData } from "#app/data/custom-pokemon-data"; import type { CustomPokemonData } from "#app/data/custom-pokemon-data";
import type HeldModifierConfig from "#app/@types/held-modifier-config"; import type HeldModifierConfig from "#app/@types/held-modifier-config";
import { MovePhase } from "#app/phases/move-phase";
import { EggLapsePhase } from "#app/phases/egg-lapse-phase";
import { TrainerVictoryPhase } from "#app/phases/trainer-victory-phase";
import { BattleEndPhase } from "#app/phases/battle-end-phase";
import { GameOverPhase } from "#app/phases/game-over-phase";
import { SelectModifierPhase } from "#app/phases/select-modifier-phase";
import { PartyExpPhase } from "#app/phases/party-exp-phase";
import type { Variant } from "#app/sprites/variant"; import type { Variant } from "#app/sprites/variant";
import { StatusEffect } from "#enums/status-effect"; import { StatusEffect } from "#enums/status-effect";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
@ -428,7 +415,7 @@ export async function initBattleWithEnemyConfig(partyConfig: EnemyPartyConfig):
console.log("Moveset:", moveset); console.log("Moveset:", moveset);
}); });
globalScene.phaseManager.pushPhase(new MysteryEncounterBattlePhase(partyConfig.disableSwitch)); globalScene.phaseManager.pushNew("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) => {
@ -767,7 +754,7 @@ export function setEncounterRewards(
} }
if (customShopRewards) { if (customShopRewards) {
globalScene.phaseManager.unshiftPhase(new SelectModifierPhase(0, undefined, customShopRewards)); globalScene.phaseManager.unshiftNew("SelectModifierPhase", 0, undefined, customShopRewards);
} else { } else {
globalScene.phaseManager.tryRemovePhase(p => p.is("MysteryEncounterRewardsPhase")); globalScene.phaseManager.tryRemovePhase(p => p.is("MysteryEncounterRewardsPhase"));
} }
@ -807,7 +794,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.phaseManager.unshiftPhase(new PartyExpPhase(baseExpValue, useWaveIndex, new Set(participantIds))); globalScene.phaseManager.unshiftNew("PartyExpPhase", baseExpValue, useWaveIndex, new Set(participantIds));
return true; return true;
}; };
@ -829,7 +816,7 @@ export class OptionSelectSettings {
* @param optionSelectSettings * @param optionSelectSettings
*/ */
export function initSubsequentOptionSelect(optionSelectSettings: OptionSelectSettings) { export function initSubsequentOptionSelect(optionSelectSettings: OptionSelectSettings) {
globalScene.phaseManager.pushPhase(new MysteryEncounterPhase(optionSelectSettings)); globalScene.phaseManager.pushNew("MysteryEncounterPhase", optionSelectSettings);
} }
/** /**
@ -858,7 +845,7 @@ export function handleMysteryEncounterVictory(addHealPhase = false, doNotContinu
if (allowedPkm.length === 0) { if (allowedPkm.length === 0) {
globalScene.phaseManager.clearPhaseQueue(); globalScene.phaseManager.clearPhaseQueue();
globalScene.phaseManager.unshiftPhase(new GameOverPhase()); globalScene.phaseManager.unshiftNew("GameOverPhase");
return; return;
} }
@ -869,8 +856,8 @@ export function handleMysteryEncounterVictory(addHealPhase = false, doNotContinu
return; return;
} }
if (encounter.encounterMode === MysteryEncounterMode.NO_BATTLE) { if (encounter.encounterMode === MysteryEncounterMode.NO_BATTLE) {
globalScene.phaseManager.pushPhase(new MysteryEncounterRewardsPhase(addHealPhase)); globalScene.phaseManager.pushNew("MysteryEncounterRewardsPhase", addHealPhase);
globalScene.phaseManager.pushPhase(new EggLapsePhase()); globalScene.phaseManager.pushNew("EggLapsePhase");
} else if ( } else if (
!globalScene !globalScene
.getEnemyParty() .getEnemyParty()
@ -878,15 +865,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.phaseManager.pushPhase(new BattleEndPhase(true)); globalScene.phaseManager.pushNew("BattleEndPhase", true);
if (encounter.encounterMode === MysteryEncounterMode.TRAINER_BATTLE) { if (encounter.encounterMode === MysteryEncounterMode.TRAINER_BATTLE) {
globalScene.phaseManager.pushPhase(new TrainerVictoryPhase()); globalScene.phaseManager.pushNew("TrainerVictoryPhase");
} }
if (globalScene.gameMode.isEndless || !globalScene.gameMode.isWaveFinal(globalScene.currentBattle.waveIndex)) { if (globalScene.gameMode.isEndless || !globalScene.gameMode.isWaveFinal(globalScene.currentBattle.waveIndex)) {
globalScene.phaseManager.pushPhase(new MysteryEncounterRewardsPhase(addHealPhase)); globalScene.phaseManager.pushNew("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.phaseManager.pushPhase(new EggLapsePhase()); globalScene.phaseManager.pushNew("EggLapsePhase");
} }
} }
} }
@ -901,7 +888,7 @@ export function handleMysteryEncounterBattleFailed(addHealPhase = false, doNotCo
if (allowedPkm.length === 0) { if (allowedPkm.length === 0) {
globalScene.phaseManager.clearPhaseQueue(); globalScene.phaseManager.clearPhaseQueue();
globalScene.phaseManager.unshiftPhase(new GameOverPhase()); globalScene.phaseManager.unshiftNew("GameOverPhase");
return; return;
} }
@ -912,14 +899,14 @@ export function handleMysteryEncounterBattleFailed(addHealPhase = false, doNotCo
return; return;
} }
if (encounter.encounterMode !== MysteryEncounterMode.NO_BATTLE) { if (encounter.encounterMode !== MysteryEncounterMode.NO_BATTLE) {
globalScene.phaseManager.pushPhase(new BattleEndPhase(false)); globalScene.phaseManager.pushNew("BattleEndPhase", false);
} }
globalScene.phaseManager.pushPhase(new MysteryEncounterRewardsPhase(addHealPhase)); globalScene.phaseManager.pushNew("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.phaseManager.pushPhase(new EggLapsePhase()); globalScene.phaseManager.pushNew("EggLapsePhase");
} }
} }
@ -1004,14 +991,19 @@ export function handleMysteryEncounterBattleStartEffects() {
} else { } else {
source = globalScene.getEnemyField()[0]; source = globalScene.getEnemyField()[0];
} }
globalScene.phaseManager.pushPhase( globalScene.phaseManager.pushNew(
// @ts-ignore: source cannot be undefined "MovePhase",
new MovePhase(source, effect.targets, effect.move, effect.followUp, effect.ignorePp), // @ts-expect-error: source is guaranteed to be defined
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.phaseManager.pushPhase(new MysteryEncounterBattleStartCleanupPhase()); globalScene.phaseManager.pushNew("MysteryEncounterBattleStartCleanupPhase");
encounter.startOfBattleEffectsComplete = true; encounter.startOfBattleEffectsComplete = true;
} }

View File

@ -32,7 +32,6 @@ import type { PokemonHeldItemModifierType } from "#app/modifier/modifier-type";
import { modifierTypes } from "#app/modifier/modifier-type"; import { modifierTypes } from "#app/modifier/modifier-type";
import { Gender } from "#app/data/gender"; import { Gender } from "#app/data/gender";
import type { PermanentStat } from "#enums/stat"; import type { PermanentStat } from "#enums/stat";
import { VictoryPhase } from "#app/phases/victory-phase";
import { SummaryUiMode } from "#app/ui/summary-ui-handler"; import { SummaryUiMode } from "#app/ui/summary-ui-handler";
import { CustomPokemonData } from "#app/data/custom-pokemon-data"; import { CustomPokemonData } from "#app/data/custom-pokemon-data";
import type { AbilityId } from "#enums/ability-id"; import type { AbilityId } from "#enums/ability-id";
@ -675,7 +674,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.phaseManager.unshiftPhase(new VictoryPhase(pokemon.id, true)); globalScene.phaseManager.unshiftNew("VictoryPhase", pokemon.id, true);
globalScene.pokemonInfoContainer.hide(); globalScene.pokemonInfoContainer.hide();
if (pokeball) { if (pokeball) {
removePb(pokeball); removePb(pokeball);

View File

@ -38,7 +38,6 @@ import { TimeOfDay } from "#enums/time-of-day";
import { TrainerType } from "#enums/trainer-type"; import { TrainerType } from "#enums/trainer-type";
import { AbilityId } from "#enums/ability-id"; import { AbilityId } from "#enums/ability-id";
import { SpeciesFormChangeRevertWeatherFormTrigger, SpeciesFormChangeWeatherTrigger } from "#app/data/pokemon-forms"; import { SpeciesFormChangeRevertWeatherFormTrigger, SpeciesFormChangeWeatherTrigger } from "#app/data/pokemon-forms";
import { CommonAnimPhase } from "#app/phases/common-anim-phase";
import { WeatherType } from "#enums/weather-type"; import { WeatherType } from "#enums/weather-type";
import { FieldEffectModifier } from "#app/modifier/modifier"; import { FieldEffectModifier } from "#app/modifier/modifier";
@ -297,7 +296,7 @@ export class Arena {
*/ */
trySetWeatherOverride(weather: WeatherType): boolean { trySetWeatherOverride(weather: WeatherType): boolean {
this.weather = new Weather(weather, 0); this.weather = new Weather(weather, 0);
globalScene.phaseManager.unshiftPhase(new CommonAnimPhase(undefined, undefined, CommonAnim.SUNNY + (weather - 1))); globalScene.phaseManager.unshiftNew("CommonAnimPhase", undefined, undefined, CommonAnim.SUNNY + (weather - 1));
globalScene.phaseManager.queueMessage(getWeatherStartMessage(weather)!); // TODO: is this bang correct? globalScene.phaseManager.queueMessage(getWeatherStartMessage(weather)!); // TODO: is this bang correct?
return true; return true;
} }
@ -328,8 +327,12 @@ 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new CommonAnimPhase(undefined, undefined, CommonAnim.SUNNY + (oldWeatherType - 1), true), "CommonAnimPhase",
undefined,
undefined,
CommonAnim.SUNNY + (oldWeatherType - 1),
true,
); );
globalScene.phaseManager.queueMessage(getLegendaryWeatherContinuesMessage(oldWeatherType)!); globalScene.phaseManager.queueMessage(getLegendaryWeatherContinuesMessage(oldWeatherType)!);
return false; return false;
@ -348,8 +351,12 @@ export class Arena {
); // TODO: is this bang correct? ); // TODO: is this bang correct?
if (this.weather) { if (this.weather) {
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new CommonAnimPhase(undefined, undefined, CommonAnim.SUNNY + (weather - 1), true), "CommonAnimPhase",
undefined,
undefined,
CommonAnim.SUNNY + (weather - 1),
true,
); );
globalScene.phaseManager.queueMessage(getWeatherStartMessage(weather)!); // TODO: is this bang correct? globalScene.phaseManager.queueMessage(getWeatherStartMessage(weather)!); // TODO: is this bang correct?
} else { } else {
@ -433,8 +440,11 @@ export class Arena {
if (this.terrain) { if (this.terrain) {
if (!ignoreAnim) { if (!ignoreAnim) {
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new CommonAnimPhase(undefined, undefined, CommonAnim.MISTY_TERRAIN + (terrain - 1)), "CommonAnimPhase",
undefined,
undefined,
CommonAnim.MISTY_TERRAIN + (terrain - 1),
); );
} }
globalScene.phaseManager.queueMessage(getTerrainStartMessage(terrain)!); // TODO: is this bang correct? globalScene.phaseManager.queueMessage(getTerrainStartMessage(terrain)!); // TODO: is this bang correct?

View File

@ -230,13 +230,6 @@ import { BiomeId } from "#enums/biome-id";
import { MoveId } from "#enums/move-id"; import { MoveId } from "#enums/move-id";
import { SpeciesId } from "#enums/species-id"; import { SpeciesId } from "#enums/species-id";
import { getPokemonNameWithAffix } from "#app/messages"; import { getPokemonNameWithAffix } from "#app/messages";
import { DamageAnimPhase } from "#app/phases/damage-anim-phase";
import { FaintPhase } from "#app/phases/faint-phase";
import { LearnMovePhase } from "#app/phases/learn-move-phase";
import { MoveEndPhase } from "#app/phases/move-end-phase";
import { ObtainStatusEffectPhase } from "#app/phases/obtain-status-effect-phase";
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
import { SwitchSummonPhase } from "#app/phases/switch-summon-phase";
import { Challenges } from "#enums/challenges"; import { Challenges } from "#enums/challenges";
import { PokemonAnimType } from "#enums/pokemon-anim-type"; import { PokemonAnimType } from "#enums/pokemon-anim-type";
import { PLAYER_PARTY_MAX_SIZE } from "#app/constants"; import { PLAYER_PARTY_MAX_SIZE } from "#app/constants";
@ -256,7 +249,6 @@ import { doShinySparkleAnim } from "#app/field/anims";
import { MoveFlags } from "#enums/MoveFlags"; import { MoveFlags } from "#enums/MoveFlags";
import { timedEventManager } from "#app/global-event-manager"; import { timedEventManager } from "#app/global-event-manager";
import { loadMoveAnimations } from "#app/sprites/pokemon-asset-loader"; import { loadMoveAnimations } from "#app/sprites/pokemon-asset-loader";
import { ResetStatusPhase } from "#app/phases/reset-status-phase";
export enum LearnMoveSituation { export enum LearnMoveSituation {
MISC, MISC,
@ -4013,7 +4005,7 @@ 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.phaseManager.setPhaseQueueSplice(); globalScene.phaseManager.setPhaseQueueSplice();
globalScene.phaseManager.unshiftPhase(new FaintPhase(this.getBattlerIndex(), preventEndure)); globalScene.phaseManager.unshiftNew("FaintPhase", this.getBattlerIndex(), preventEndure);
this.destroySubstitute(); this.destroySubstitute();
this.lapseTag(BattlerTagType.COMMANDED); this.lapseTag(BattlerTagType.COMMANDED);
} }
@ -4049,7 +4041,13 @@ 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 = globalScene.phaseManager.create(
"DamageAnimPhase",
this.getBattlerIndex(),
damage,
result as DamageResult,
isCritical,
);
globalScene.phaseManager.unshiftPhase(damagePhase); globalScene.phaseManager.unshiftPhase(damagePhase);
if (this.switchOutStatus && source) { if (this.switchOutStatus && source) {
damage = 0; damage = 0;
@ -4778,8 +4776,13 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
if (overrideStatus) { if (overrideStatus) {
this.resetStatus(false); this.resetStatus(false);
} }
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new ObtainStatusEffectPhase(this.getBattlerIndex(), effect, turnsRemaining, sourceText, sourcePokemon), "ObtainStatusEffectPhase",
this.getBattlerIndex(),
effect,
turnsRemaining,
sourceText,
sourcePokemon,
); );
return true; return true;
} }
@ -4828,7 +4831,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
} }
if (asPhase) { if (asPhase) {
globalScene.phaseManager.unshiftPhase(new ResetStatusPhase(this, confusion, reloadAssets)); globalScene.phaseManager.unshiftNew("ResetStatusPhase", this, confusion, reloadAssets);
} else { } else {
this.clearStatus(confusion, reloadAssets); this.clearStatus(confusion, reloadAssets);
} }
@ -5635,9 +5638,13 @@ 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.phaseManager.prependToPhase( globalScene.phaseManager.prependNewToPhase(
new SwitchSummonPhase(switchType, this.getFieldIndex(), slotIndex, false), "MoveEndPhase",
MoveEndPhase, "SwitchSummonPhase",
switchType,
this.getFieldIndex(),
slotIndex,
false,
); );
} }
globalScene.ui.setMode(UiMode.MESSAGE).then(resolve); globalScene.ui.setMode(UiMode.MESSAGE).then(resolve);
@ -6001,7 +6008,7 @@ export class PlayerPokemon extends Pokemon {
pokemon pokemon
.getMoveset(true) .getMoveset(true)
.map((m: PokemonMove) => .map((m: PokemonMove) =>
globalScene.phaseManager.unshiftPhase(new LearnMovePhase(newPartyMemberIndex, m.getMove().id)), globalScene.phaseManager.unshiftNew("LearnMovePhase", newPartyMemberIndex, m.getMove().id),
); );
pokemon.destroy(); pokemon.destroy();
this.updateFusionPalette(); this.updateFusionPalette();
@ -6644,8 +6651,14 @@ export class EnemyPokemon extends Pokemon {
stages++; stages++;
} }
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new StatStageChangePhase(this.getBattlerIndex(), true, [boostedStat!], stages, true, true), "StatStageChangePhase",
this.getBattlerIndex(),
true,
[boostedStat!],
stages,
true,
true,
); );
this.bossSegmentIndex--; this.bossSegmentIndex--;
} }

View File

@ -8,10 +8,7 @@ import { getStatusEffectHealText } from "#app/data/status-effect";
import Pokemon, { type PlayerPokemon } from "#app/field/pokemon"; import Pokemon, { type PlayerPokemon } from "#app/field/pokemon";
import { getPokemonNameWithAffix } from "#app/messages"; import { getPokemonNameWithAffix } from "#app/messages";
import Overrides from "#app/overrides"; import Overrides from "#app/overrides";
import { EvolutionPhase } from "#app/phases/evolution-phase"; import { LearnMoveType } from "#app/phases/learn-move-phase";
import { LearnMovePhase, LearnMoveType } from "#app/phases/learn-move-phase";
import { LevelUpPhase } from "#app/phases/level-up-phase";
import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase";
import type { VoucherType } from "#app/system/voucher"; import type { VoucherType } from "#app/system/voucher";
import { Command } from "#app/ui/command-ui-handler"; import { Command } from "#app/ui/command-ui-handler";
import { addTextObject, TextStyle } from "#app/ui/text"; import { addTextObject, TextStyle } from "#app/ui/text";
@ -1684,8 +1681,8 @@ export class TurnHealModifier extends PokemonHeldItemModifier {
*/ */
override apply(pokemon: Pokemon): boolean { override apply(pokemon: Pokemon): boolean {
if (!pokemon.isFullHp()) { if (!pokemon.isFullHp()) {
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new PokemonHealPhase( "PokemonHealPhase",
pokemon.getBattlerIndex(), pokemon.getBattlerIndex(),
toDmgValue(pokemon.getMaxHp() / 16) * this.stackCount, toDmgValue(pokemon.getMaxHp() / 16) * this.stackCount,
i18next.t("modifier:turnHealApply", { i18next.t("modifier:turnHealApply", {
@ -1693,7 +1690,6 @@ export class TurnHealModifier extends PokemonHeldItemModifier {
typeName: this.type.name, typeName: this.type.name,
}), }),
true, true,
),
); );
return true; return true;
} }
@ -1782,8 +1778,8 @@ 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new PokemonHealPhase( "PokemonHealPhase",
pokemon.getBattlerIndex(), pokemon.getBattlerIndex(),
toDmgValue(pokemon.turnData.totalDamageDealt / 8) * this.stackCount, toDmgValue(pokemon.turnData.totalDamageDealt / 8) * this.stackCount,
i18next.t("modifier:hitHealApply", { i18next.t("modifier:hitHealApply", {
@ -1791,7 +1787,6 @@ export class HitHealModifier extends PokemonHeldItemModifier {
typeName: this.type.name, typeName: this.type.name,
}), }),
true, true,
),
); );
} }
@ -1950,8 +1945,8 @@ 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new PokemonHealPhase( "PokemonHealPhase",
pokemon.getBattlerIndex(), pokemon.getBattlerIndex(),
toDmgValue(pokemon.getMaxHp() / 2), toDmgValue(pokemon.getMaxHp() / 2),
i18next.t("modifier:pokemonInstantReviveApply", { i18next.t("modifier:pokemonInstantReviveApply", {
@ -1961,7 +1956,6 @@ export class PokemonInstantReviveModifier extends PokemonHeldItemModifier {
false, false,
false, false,
true, true,
),
); );
// Remove the Pokemon's FAINT status // Remove the Pokemon's FAINT status
@ -2323,12 +2317,11 @@ export class PokemonLevelIncrementModifier extends ConsumablePokemonModifier {
playerPokemon.addFriendship(FRIENDSHIP_GAIN_FROM_RARE_CANDY); playerPokemon.addFriendship(FRIENDSHIP_GAIN_FROM_RARE_CANDY);
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new LevelUpPhase( "LevelUpPhase",
globalScene.getPlayerParty().indexOf(playerPokemon), globalScene.getPlayerParty().indexOf(playerPokemon),
playerPokemon.level - levelCount.value, playerPokemon.level - levelCount.value,
playerPokemon.level, playerPokemon.level,
),
); );
return true; return true;
@ -2344,8 +2337,11 @@ export class TmModifier extends ConsumablePokemonModifier {
* @returns always `true` * @returns always `true`
*/ */
override apply(playerPokemon: PlayerPokemon): boolean { override apply(playerPokemon: PlayerPokemon): boolean {
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new LearnMovePhase(globalScene.getPlayerParty().indexOf(playerPokemon), this.type.moveId, LearnMoveType.TM), "LearnMovePhase",
globalScene.getPlayerParty().indexOf(playerPokemon),
this.type.moveId,
LearnMoveType.TM,
); );
return true; return true;
@ -2367,13 +2363,12 @@ 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new LearnMovePhase( "LearnMovePhase",
globalScene.getPlayerParty().indexOf(playerPokemon), globalScene.getPlayerParty().indexOf(playerPokemon),
playerPokemon.getLearnableLevelMoves()[this.levelMoveIndex], playerPokemon.getLearnableLevelMoves()[this.levelMoveIndex],
LearnMoveType.MEMORY, LearnMoveType.MEMORY,
cost, cost,
),
); );
return true; return true;
@ -2410,9 +2405,7 @@ export class EvolutionItemModifier extends ConsumablePokemonModifier {
} }
if (matchingEvolution) { if (matchingEvolution) {
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew("EvolutionPhase", playerPokemon, matchingEvolution, playerPokemon.level - 1);
new EvolutionPhase(playerPokemon, matchingEvolution, playerPokemon.level - 1),
);
return true; return true;
} }
@ -3574,8 +3567,8 @@ export class EnemyTurnHealModifier extends EnemyPersistentModifier {
*/ */
override apply(enemyPokemon: Pokemon): boolean { override apply(enemyPokemon: Pokemon): boolean {
if (!enemyPokemon.isFullHp()) { if (!enemyPokemon.isFullHp()) {
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new PokemonHealPhase( "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),
i18next.t("modifier:enemyTurnHealApply", { i18next.t("modifier:enemyTurnHealApply", {
@ -3586,7 +3579,6 @@ export class EnemyTurnHealModifier extends EnemyPersistentModifier {
false, false,
false, false,
true, true,
),
); );
return true; return true;
} }

View File

@ -1,11 +1,100 @@
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 { Phase } from "#app/phase";
import type { default as Pokemon } from "#app/field/pokemon"; import type { default as Pokemon } from "#app/field/pokemon";
import type { Constructor } from "#app/utils/common"; import type { PhaseMap, PhaseString } from "./@types/phase-types";
import { MessagePhase } from "./phases/message-phase";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import { AddEnemyBuffModifierPhase } from "#app/phases/add-enemy-buff-modifier-phase";
import { AttemptCapturePhase } from "#app/phases/attempt-capture-phase";
import { AttemptRunPhase } from "#app/phases/attempt-run-phase";
import { BattleEndPhase } from "#app/phases/battle-end-phase";
import { BerryPhase } from "#app/phases/berry-phase";
import { CheckStatusEffectPhase } from "#app/phases/check-status-effect-phase";
import { CheckSwitchPhase } from "#app/phases/check-switch-phase";
import { CommandPhase } from "#app/phases/command-phase";
import { CommonAnimPhase } from "#app/phases/common-anim-phase";
import { DamageAnimPhase } from "#app/phases/damage-anim-phase";
import { EggHatchPhase } from "#app/phases/egg-hatch-phase";
import { EggLapsePhase } from "#app/phases/egg-lapse-phase";
import { EggSummaryPhase } from "#app/phases/egg-summary-phase";
import { EncounterPhase } from "#app/phases/encounter-phase";
import { EndCardPhase } from "#app/phases/end-card-phase";
import { EndEvolutionPhase } from "#app/phases/end-evolution-phase";
import { EnemyCommandPhase } from "#app/phases/enemy-command-phase";
import { EvolutionPhase } from "#app/phases/evolution-phase";
import { ExpPhase } from "#app/phases/exp-phase";
import { FaintPhase } from "#app/phases/faint-phase";
import { FormChangePhase } from "#app/phases/form-change-phase";
import { GameOverModifierRewardPhase } from "#app/phases/game-over-modifier-reward-phase";
import { GameOverPhase } from "#app/phases/game-over-phase";
import { HideAbilityPhase } from "#app/phases/hide-ability-phase";
import { HidePartyExpBarPhase } from "#app/phases/hide-party-exp-bar-phase";
import { LearnMovePhase } from "#app/phases/learn-move-phase";
import { LevelCapPhase } from "#app/phases/level-cap-phase";
import { LevelUpPhase } from "#app/phases/level-up-phase";
import { LoadMoveAnimPhase } from "#app/phases/load-move-anim-phase";
import { LoginPhase } from "#app/phases/login-phase";
import { MessagePhase } from "#app/phases/message-phase";
import { ModifierRewardPhase } from "#app/phases/modifier-reward-phase";
import { MoneyRewardPhase } from "#app/phases/money-reward-phase";
import { MoveAnimPhase } from "#app/phases/move-anim-phase";
import { MoveChargePhase } from "#app/phases/move-charge-phase";
import { MoveEffectPhase } from "#app/phases/move-effect-phase";
import { MoveEndPhase } from "#app/phases/move-end-phase";
import { MoveHeaderPhase } from "#app/phases/move-header-phase";
import { MovePhase } from "#app/phases/move-phase";
import {
MysteryEncounterPhase,
MysteryEncounterOptionSelectedPhase,
MysteryEncounterBattlePhase,
MysteryEncounterRewardsPhase,
PostMysteryEncounterPhase,
MysteryEncounterBattleStartCleanupPhase,
} from "#app/phases/mystery-encounter-phases";
import { NewBattlePhase } from "#app/phases/new-battle-phase";
import { NewBiomeEncounterPhase } from "#app/phases/new-biome-encounter-phase";
import { NextEncounterPhase } from "#app/phases/next-encounter-phase";
import { ObtainStatusEffectPhase } from "#app/phases/obtain-status-effect-phase";
import { PartyExpPhase } from "#app/phases/party-exp-phase";
import { PartyHealPhase } from "#app/phases/party-heal-phase";
import { PokemonAnimPhase } from "#app/phases/pokemon-anim-phase";
import { PokemonHealPhase } from "#app/phases/pokemon-heal-phase";
import { PokemonTransformPhase } from "#app/phases/pokemon-transform-phase";
import { PostGameOverPhase } from "#app/phases/post-game-over-phase";
import { PostSummonPhase } from "#app/phases/post-summon-phase";
import { PostTurnStatusEffectPhase } from "#app/phases/post-turn-status-effect-phase";
import { QuietFormChangePhase } from "#app/phases/quiet-form-change-phase";
import { ReloadSessionPhase } from "#app/phases/reload-session-phase";
import { ResetStatusPhase } from "#app/phases/reset-status-phase";
import { ReturnPhase } from "#app/phases/return-phase";
import { RevivalBlessingPhase } from "#app/phases/revival-blessing-phase";
import { RibbonModifierRewardPhase } from "#app/phases/ribbon-modifier-reward-phase";
import { ScanIvsPhase } from "#app/phases/scan-ivs-phase";
import { SelectBiomePhase } from "#app/phases/select-biome-phase";
import { SelectChallengePhase } from "#app/phases/select-challenge-phase";
import { SelectGenderPhase } from "#app/phases/select-gender-phase";
import { SelectModifierPhase } from "#app/phases/select-modifier-phase";
import { SelectStarterPhase } from "#app/phases/select-starter-phase";
import { SelectTargetPhase } from "#app/phases/select-target-phase";
import { ShinySparklePhase } from "#app/phases/shiny-sparkle-phase";
import { ShowAbilityPhase } from "#app/phases/show-ability-phase";
import { ShowPartyExpBarPhase } from "#app/phases/show-party-exp-bar-phase";
import { ShowTrainerPhase } from "#app/phases/show-trainer-phase";
import { StatStageChangePhase } from "#app/phases/stat-stage-change-phase";
import { SummonMissingPhase } from "#app/phases/summon-missing-phase";
import { SummonPhase } from "#app/phases/summon-phase";
import { SwitchBiomePhase } from "#app/phases/switch-biome-phase";
import { SwitchPhase } from "#app/phases/switch-phase";
import { SwitchSummonPhase } from "#app/phases/switch-summon-phase";
import { TeraPhase } from "#app/phases/tera-phase";
import { TitlePhase } from "#app/phases/title-phase";
import { ToggleDoublePositionPhase } from "#app/phases/toggle-double-position-phase";
import { TrainerVictoryPhase } from "#app/phases/trainer-victory-phase";
import { TurnEndPhase } from "#app/phases/turn-end-phase";
import { TurnInitPhase } from "#app/phases/turn-init-phase";
import { TurnStartPhase } from "#app/phases/turn-start-phase";
import { UnavailablePhase } from "#app/phases/unavailable-phase";
import { UnlockPhase } from "#app/phases/unlock-phase";
import { VictoryPhase } from "#app/phases/victory-phase";
import { WeatherEffectPhase } from "#app/phases/weather-effect-phase";
/** /**
* Manager for phases used by battle scene. * Manager for phases used by battle scene.
@ -13,6 +102,115 @@ import { globalScene } from "#app/global-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.* * *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.*
*/ */
/**
* Object that holds all of the phase constructors.
* This is used to create new phases dynamically using the `newPhase` method in the `PhaseManager`.
*
* @remarks
* The keys of this object are the names of the phases, and the values are the constructors of the phases.
* This allows for easy creation of new phases without needing to import each phase individually.
*/
const PHASES = Object.freeze({
AddEnemyBuffModifierPhase,
AttemptCapturePhase,
AttemptRunPhase,
BattleEndPhase,
BerryPhase,
CheckStatusEffectPhase,
CheckSwitchPhase,
CommandPhase,
CommonAnimPhase,
DamageAnimPhase,
EggHatchPhase,
EggLapsePhase,
EggSummaryPhase,
EncounterPhase,
EndCardPhase,
EndEvolutionPhase,
EnemyCommandPhase,
EvolutionPhase,
ExpPhase,
FaintPhase,
FormChangePhase,
GameOverPhase,
GameOverModifierRewardPhase,
HideAbilityPhase,
HidePartyExpBarPhase,
LearnMovePhase,
LevelCapPhase,
LevelUpPhase,
LoadMoveAnimPhase,
LoginPhase,
MessagePhase,
ModifierRewardPhase,
MoneyRewardPhase,
MoveAnimPhase,
MoveChargePhase,
MoveEffectPhase,
MoveEndPhase,
MoveHeaderPhase,
MovePhase,
MysteryEncounterPhase,
MysteryEncounterOptionSelectedPhase,
MysteryEncounterBattlePhase,
MysteryEncounterBattleStartCleanupPhase,
MysteryEncounterRewardsPhase,
PostMysteryEncounterPhase,
NewBattlePhase,
NewBiomeEncounterPhase,
NextEncounterPhase,
ObtainStatusEffectPhase,
PartyExpPhase,
PartyHealPhase,
PokemonAnimPhase,
PokemonHealPhase,
PokemonTransformPhase,
PostGameOverPhase,
PostSummonPhase,
PostTurnStatusEffectPhase,
QuietFormChangePhase,
ReloadSessionPhase,
ResetStatusPhase,
ReturnPhase,
RevivalBlessingPhase,
RibbonModifierRewardPhase,
ScanIvsPhase,
SelectBiomePhase,
SelectChallengePhase,
SelectGenderPhase,
SelectModifierPhase,
SelectStarterPhase,
SelectTargetPhase,
ShinySparklePhase,
ShowAbilityPhase,
ShowPartyExpBarPhase,
ShowTrainerPhase,
StatStageChangePhase,
SummonMissingPhase,
SummonPhase,
SwitchBiomePhase,
SwitchPhase,
SwitchSummonPhase,
TeraPhase,
TitlePhase,
ToggleDoublePositionPhase,
TrainerVictoryPhase,
TurnEndPhase,
TurnInitPhase,
TurnStartPhase,
UnavailablePhase,
UnlockPhase,
VictoryPhase,
WeatherEffectPhase,
});
// This type export cannot be moved to `@types`, as `Phases` is intentionally private to this file
/** Maps Phase strings to their constructors */
export type PhaseConstructorMap = typeof PHASES;
/**
* PhaseManager is responsible for managing the phases in the battle scene
*/
export class PhaseManager { export class PhaseManager {
/** PhaseQueue: dequeue/remove the first element to get the next phase */ /** PhaseQueue: dequeue/remove the first element to get the next phase */
public phaseQueue: Phase[] = []; public phaseQueue: Phase[] = [];
@ -213,15 +411,16 @@ export class PhaseManager {
/** /**
* Tries to add the input phase to index before target phase in the phaseQueue, else simply calls unshiftPhase() * 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 phase - The phase to be added
* @param targetPhase {@linkcode Phase} the type of phase to search for in phaseQueue * @param targetPhase - The phase to search for in phaseQueue
* @returns boolean if a targetPhase was found and added * @returns boolean if a targetPhase was found and added
*/ */
prependToPhase(phase: Phase | Phase[], targetPhase: Constructor<Phase>): boolean { prependToPhase(phase: Phase | Phase[], targetPhase: PhaseString): boolean {
if (!Array.isArray(phase)) { if (!Array.isArray(phase)) {
phase = [phase]; phase = [phase];
} }
const targetIndex = this.phaseQueue.findIndex(ph => ph instanceof targetPhase); const target = PHASES[targetPhase];
const targetIndex = this.phaseQueue.findIndex(ph => ph instanceof target);
if (targetIndex !== -1) { if (targetIndex !== -1) {
this.phaseQueue.splice(targetIndex, 0, ...phase); this.phaseQueue.splice(targetIndex, 0, ...phase);
@ -234,14 +433,15 @@ export class PhaseManager {
/** /**
* Attempt to add the input phase(s) to index after target phase in the {@linkcode phaseQueue}, else simply calls {@linkcode unshiftPhase()} * 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 phase - The phase(s) to be added
* @param targetPhase - The type of phase to search for in {@linkcode phaseQueue} * @param targetPhase - The phase to search for in phaseQueue
* @returns `true` if a `targetPhase` was found to append to * @returns `true` if a `targetPhase` was found to append to
*/ */
appendToPhase(phase: Phase | Phase[], targetPhase: Constructor<Phase>): boolean { appendToPhase(phase: Phase | Phase[], targetPhase: PhaseString): boolean {
if (!Array.isArray(phase)) { if (!Array.isArray(phase)) {
phase = [phase]; phase = [phase];
} }
const targetIndex = this.phaseQueue.findIndex(ph => ph instanceof targetPhase); const target = PHASES[targetPhase];
const targetIndex = this.phaseQueue.findIndex(ph => ph instanceof target);
if (targetIndex !== -1 && this.phaseQueue.length > targetIndex) { if (targetIndex !== -1 && this.phaseQueue.length > targetIndex) {
this.phaseQueue.splice(targetIndex + 1, 0, ...phase); this.phaseQueue.splice(targetIndex + 1, 0, ...phase);
@ -308,4 +508,74 @@ export class PhaseManager {
} }
this.phaseQueue.push(new TurnInitPhase()); this.phaseQueue.push(new TurnInitPhase());
} }
/**
* Dynamically create the named phase from the provided arguments
*
* @remarks
* Used to avoid importing each phase individually, allowing for dynamic creation of phases.
* @param phase - The name of the phase to create.
* @param args - The arguments to pass to the phase constructor.
* @returns The requested phase instance
*/
public create<T extends PhaseString>(phase: T, ...args: ConstructorParameters<PhaseConstructorMap[T]>): PhaseMap[T] {
const PhaseClass = PHASES[phase];
if (!PhaseClass) {
throw new Error(`Phase ${phase} does not exist in PhaseMap.`);
}
// @ts-expect-error: Typescript does not support narrowing the type of operands in generic methods (see https://stackoverflow.com/a/72891234)
return new PhaseClass(...args);
}
/**
* Create a new phase and immediately push it to the phase queue. Equivalent to calling {@linkcode create} followed by {@linkcode pushPhase}.
* @param phase - The name of the phase to create
* @param args - The arguments to pass to the phase constructor
*/
public pushNew<T extends PhaseString>(phase: T, ...args: ConstructorParameters<PhaseConstructorMap[T]>): void {
this.pushPhase(this.create(phase, ...args));
}
/**
* Create a new phase and immediately unshift it to the phase queue. Equivalent to calling {@linkcode create} followed by {@linkcode unshiftPhase}.
* @param phase - The name of the phase to create
* @param args - The arguments to pass to the phase constructor
*/
public unshiftNew<T extends PhaseString>(phase: T, ...args: ConstructorParameters<PhaseConstructorMap[T]>): void {
this.unshiftPhase(this.create(phase, ...args));
}
/**
* Create a new phase and immediately prepend it to an existing phase in the phase queue.
* Equivalent to calling {@linkcode create} followed by {@linkcode prependToPhase}.
* @param targetPhase - The phase to search for in phaseQueue
* @param phase - The name of the phase to create
* @param args - The arguments to pass to the phase constructor
* @returns `true` if a `targetPhase` was found to prepend to
*/
public prependNewToPhase<T extends PhaseString>(
targetPhase: PhaseString,
phase: T,
...args: ConstructorParameters<PhaseConstructorMap[T]>
): boolean {
return this.prependToPhase(this.create(phase, ...args), targetPhase);
}
/**
* Create a new phase and immediately append it to an existing phase the phase queue.
* Equivalent to calling {@linkcode create} followed by {@linkcode appendToPhase}.
* @param targetPhase - The phase to search for in phaseQueue
* @param phase - The name of the phase to create
* @param args - The arguments to pass to the phase constructor
* @returns `true` if a `targetPhase` was found to append to
*/
public appendNewToPhase<T extends PhaseString>(
targetPhase: PhaseString,
phase: T,
...args: ConstructorParameters<PhaseConstructorMap[T]>
): boolean {
return this.appendToPhase(this.create(phase, ...args), targetPhase);
}
} }

View File

@ -14,7 +14,6 @@ import type { EnemyPokemon } from "#app/field/pokemon";
import { getPokemonNameWithAffix } from "#app/messages"; import { getPokemonNameWithAffix } from "#app/messages";
import { PokemonHeldItemModifier } from "#app/modifier/modifier"; import { PokemonHeldItemModifier } from "#app/modifier/modifier";
import { PokemonPhase } from "#app/phases/pokemon-phase"; import { PokemonPhase } from "#app/phases/pokemon-phase";
import { VictoryPhase } from "#app/phases/victory-phase";
import { achvs } from "#app/system/achv"; import { achvs } from "#app/system/achv";
import type { PartyOption } from "#app/ui/party-ui-handler"; import type { PartyOption } from "#app/ui/party-ui-handler";
import { PartyUiMode } from "#app/ui/party-ui-handler"; import { PartyUiMode } from "#app/ui/party-ui-handler";
@ -257,7 +256,7 @@ export class AttemptCapturePhase extends PokemonPhase {
null, null,
() => { () => {
const end = () => { const end = () => {
globalScene.phaseManager.unshiftPhase(new VictoryPhase(this.battlerIndex)); globalScene.phaseManager.unshiftNew("VictoryPhase", this.battlerIndex);
globalScene.pokemonInfoContainer.hide(); globalScene.pokemonInfoContainer.hide();
this.removePb(); this.removePb();
this.end(); this.end();

View File

@ -10,11 +10,8 @@ import type { PlayerPokemon, EnemyPokemon } from "#app/field/pokemon";
import type Pokemon from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon";
import i18next from "i18next"; import i18next from "i18next";
import { NumberHolder } from "#app/utils/common"; import { NumberHolder } from "#app/utils/common";
import { BattleEndPhase } from "./battle-end-phase";
import { NewBattlePhase } from "./new-battle-phase";
import { PokemonPhase } from "./pokemon-phase"; import { PokemonPhase } from "./pokemon-phase";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import { SelectBiomePhase } from "./select-biome-phase";
export class AttemptRunPhase extends PokemonPhase { export class AttemptRunPhase extends PokemonPhase {
public readonly phaseName = "AttemptRunPhase"; public readonly phaseName = "AttemptRunPhase";
@ -60,13 +57,13 @@ export class AttemptRunPhase extends PokemonPhase {
enemyPokemon.trySetStatus(StatusEffect.FAINT); enemyPokemon.trySetStatus(StatusEffect.FAINT);
}); });
globalScene.phaseManager.pushPhase(new BattleEndPhase(false)); globalScene.phaseManager.pushNew("BattleEndPhase", false);
if (globalScene.gameMode.hasRandomBiomes || globalScene.isNewBiome()) { if (globalScene.gameMode.hasRandomBiomes || globalScene.isNewBiome()) {
globalScene.phaseManager.pushPhase(new SelectBiomePhase()); globalScene.phaseManager.pushNew("SelectBiomePhase");
} }
globalScene.phaseManager.pushPhase(new NewBattlePhase()); globalScene.phaseManager.pushNew("NewBattlePhase");
} else { } else {
playerPokemon.turnData.failedRunAway = true; playerPokemon.turnData.failedRunAway = true;
globalScene.phaseManager.queueMessage(i18next.t("battle:runAwayCannotEscape"), null, true, 500); globalScene.phaseManager.queueMessage(i18next.t("battle:runAwayCannotEscape"), null, true, 500);

View File

@ -2,7 +2,6 @@ import { globalScene } from "#app/global-scene";
import { applyPostBattleAbAttrs, PostBattleAbAttr } from "#app/data/abilities/ability"; import { applyPostBattleAbAttrs, PostBattleAbAttr } from "#app/data/abilities/ability";
import { LapsingPersistentModifier, LapsingPokemonHeldItemModifier } from "#app/modifier/modifier"; import { LapsingPersistentModifier, LapsingPokemonHeldItemModifier } from "#app/modifier/modifier";
import { BattlePhase } from "./battle-phase"; import { BattlePhase } from "./battle-phase";
import { GameOverPhase } from "./game-over-phase";
export class BattleEndPhase extends BattlePhase { export class BattleEndPhase extends BattlePhase {
public readonly phaseName = "BattleEndPhase"; public readonly phaseName = "BattleEndPhase";
@ -56,7 +55,7 @@ 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.phaseManager.clearPhaseQueue(); globalScene.phaseManager.clearPhaseQueue();
globalScene.phaseManager.unshiftPhase(new GameOverPhase(true)); globalScene.phaseManager.unshiftNew("GameOverPhase", true);
} }
for (const pokemon of globalScene.getField()) { for (const pokemon of globalScene.getField()) {

View File

@ -11,7 +11,6 @@ import { BerryModifier } from "#app/modifier/modifier";
import i18next from "i18next"; import i18next from "i18next";
import { BooleanHolder } from "#app/utils/common"; import { BooleanHolder } from "#app/utils/common";
import { FieldPhase } from "./field-phase"; import { FieldPhase } from "./field-phase";
import { CommonAnimPhase } from "./common-anim-phase";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import type Pokemon from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon";
@ -58,8 +57,11 @@ export class BerryPhase extends FieldPhase {
return; return;
} }
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new CommonAnimPhase(pokemon.getBattlerIndex(), pokemon.getBattlerIndex(), CommonAnim.USE_ITEM), "CommonAnimPhase",
pokemon.getBattlerIndex(),
pokemon.getBattlerIndex(),
CommonAnim.USE_ITEM,
); );
for (const berryModifier of globalScene.applyModifiers(BerryModifier, pokemon.isPlayer(), pokemon)) { for (const berryModifier of globalScene.applyModifiers(BerryModifier, pokemon.isPlayer(), pokemon)) {

View File

@ -1,4 +1,3 @@
import { PostTurnStatusEffectPhase } from "#app/phases/post-turn-status-effect-phase";
import { Phase } from "#app/phase"; import { Phase } from "#app/phase";
import type { BattlerIndex } from "#app/battle"; import type { BattlerIndex } from "#app/battle";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
@ -15,7 +14,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.phaseManager.unshiftPhase(new PostTurnStatusEffectPhase(o)); globalScene.phaseManager.unshiftNew("PostTurnStatusEffectPhase", o);
} }
} }
this.end(); this.end();

View File

@ -5,8 +5,6 @@ import { getPokemonNameWithAffix } from "#app/messages";
import { UiMode } from "#enums/ui-mode"; import { UiMode } from "#enums/ui-mode";
import i18next from "i18next"; import i18next from "i18next";
import { BattlePhase } from "./battle-phase"; import { BattlePhase } from "./battle-phase";
import { SummonMissingPhase } from "./summon-missing-phase";
import { SwitchPhase } from "./switch-phase";
import { SwitchType } from "#enums/switch-type"; import { SwitchType } from "#enums/switch-type";
export class CheckSwitchPhase extends BattlePhase { export class CheckSwitchPhase extends BattlePhase {
@ -35,7 +33,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.phaseManager.unshiftPhase(new SummonMissingPhase(this.fieldIndex)); globalScene.phaseManager.unshiftNew("SummonMissingPhase", this.fieldIndex);
return super.end(); return super.end();
} }
@ -68,9 +66,7 @@ export class CheckSwitchPhase extends BattlePhase {
UiMode.CONFIRM, UiMode.CONFIRM,
() => { () => {
globalScene.ui.setMode(UiMode.MESSAGE); globalScene.ui.setMode(UiMode.MESSAGE);
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew("SwitchPhase", SwitchType.INITIAL_SWITCH, this.fieldIndex, false, true);
new SwitchPhase(SwitchType.INITIAL_SWITCH, this.fieldIndex, false, true),
);
this.end(); this.end();
}, },
() => { () => {

View File

@ -18,7 +18,6 @@ import { Command } from "#app/ui/command-ui-handler";
import { UiMode } from "#enums/ui-mode"; import { UiMode } from "#enums/ui-mode";
import i18next from "i18next"; import i18next from "i18next";
import { FieldPhase } from "./field-phase"; import { FieldPhase } from "./field-phase";
import { SelectTargetPhase } from "./select-target-phase";
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode"; import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
import { isNullOrUndefined } from "#app/utils/common"; import { isNullOrUndefined } from "#app/utils/common";
import { ArenaTagSide } from "#app/data/arena-tag"; import { ArenaTagSide } from "#app/data/arena-tag";
@ -192,7 +191,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.phaseManager.unshiftPhase(new SelectTargetPhase(this.fieldIndex)); globalScene.phaseManager.unshiftNew("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 +202,7 @@ export class CommandPhase extends FieldPhase {
) { ) {
turnCommand.move.targets = playerPokemon.getMoveQueue()[0].targets; turnCommand.move.targets = playerPokemon.getMoveQueue()[0].targets;
} else { } else {
globalScene.phaseManager.unshiftPhase(new SelectTargetPhase(this.fieldIndex)); globalScene.phaseManager.unshiftNew("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 +456,8 @@ export class CommandPhase extends FieldPhase {
cancel() { cancel() {
if (this.fieldIndex) { if (this.fieldIndex) {
globalScene.phaseManager.unshiftPhase(new CommandPhase(0)); globalScene.phaseManager.unshiftNew("CommandPhase", 0);
globalScene.phaseManager.unshiftPhase(new CommandPhase(1)); globalScene.phaseManager.unshiftNew("CommandPhase", 1);
this.end(); this.end();
} }
} }

View File

@ -4,11 +4,9 @@ import { EGG_SEED } from "#app/data/egg";
import { Phase } from "#app/phase"; import { Phase } from "#app/phase";
import i18next from "i18next"; import i18next from "i18next";
import Overrides from "#app/overrides"; import Overrides from "#app/overrides";
import { EggHatchPhase } from "./egg-hatch-phase";
import { UiMode } from "#enums/ui-mode"; import { UiMode } from "#enums/ui-mode";
import { achvs } from "#app/system/achv"; import { achvs } from "#app/system/achv";
import type { PlayerPokemon } from "#app/field/pokemon"; import type { PlayerPokemon } from "#app/field/pokemon";
import { EggSummaryPhase } from "./egg-summary-phase";
import { EggHatchData } from "#app/data/egg-hatch-data"; import { EggHatchData } from "#app/data/egg-hatch-data";
/** /**
@ -83,7 +81,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.phaseManager.unshiftPhase(new EggHatchPhase(this, egg, eggsToHatchCount)); globalScene.phaseManager.unshiftNew("EggHatchPhase", this, egg, eggsToHatchCount);
eggsToHatchCount--; eggsToHatchCount--;
} }
} }
@ -99,7 +97,7 @@ export class EggLapsePhase extends Phase {
} }
showSummary() { showSummary() {
globalScene.phaseManager.unshiftPhase(new EggSummaryPhase(this.eggHatchData)); globalScene.phaseManager.unshiftNew("EggSummaryPhase", this.eggHatchData);
this.end(); this.end();
} }

View File

@ -23,15 +23,6 @@ import { BoostBugSpawnModifier, IvScannerModifier, TurnHeldItemTransferModifier
import { ModifierPoolType, regenerateModifierPoolThresholds } from "#app/modifier/modifier-type"; import { ModifierPoolType, regenerateModifierPoolThresholds } from "#app/modifier/modifier-type";
import Overrides from "#app/overrides"; import Overrides from "#app/overrides";
import { BattlePhase } from "#app/phases/battle-phase"; import { BattlePhase } from "#app/phases/battle-phase";
import { CheckSwitchPhase } from "#app/phases/check-switch-phase";
import { GameOverPhase } from "#app/phases/game-over-phase";
import { MysteryEncounterPhase } from "#app/phases/mystery-encounter-phases";
import { PostSummonPhase } from "#app/phases/post-summon-phase";
import { ReturnPhase } from "#app/phases/return-phase";
import { ScanIvsPhase } from "#app/phases/scan-ivs-phase";
import { ShinySparklePhase } from "#app/phases/shiny-sparkle-phase";
import { SummonPhase } from "#app/phases/summon-phase";
import { ToggleDoublePositionPhase } from "#app/phases/toggle-double-position-phase";
import { achvs } from "#app/system/achv"; import { achvs } from "#app/system/achv";
import { handleTutorial, Tutorial } from "#app/tutorial"; import { handleTutorial, Tutorial } from "#app/tutorial";
import { UiMode } from "#enums/ui-mode"; import { UiMode } from "#enums/ui-mode";
@ -68,7 +59,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.phaseManager.unshiftPhase(new GameOverPhase()); globalScene.phaseManager.unshiftNew("GameOverPhase");
} }
const loadEnemyAssets: Promise<void>[] = []; const loadEnemyAssets: Promise<void>[] = [];
@ -438,9 +429,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.phaseManager.unshiftPhase(new SummonPhase(0, false)); globalScene.phaseManager.unshiftNew("SummonPhase", 0, false);
if (globalScene.currentBattle.double && availablePartyMembers > 1) { if (globalScene.currentBattle.double && availablePartyMembers > 1) {
globalScene.phaseManager.unshiftPhase(new SummonPhase(1, false)); globalScene.phaseManager.unshiftNew("SummonPhase", 1, false);
} }
this.end(); this.end();
}; };
@ -496,7 +487,7 @@ export class EncounterPhase extends BattlePhase {
globalScene.ui.clearText(); globalScene.ui.clearText();
globalScene.ui.getMessageHandler().hideNameText(); globalScene.ui.getMessageHandler().hideNameText();
globalScene.phaseManager.unshiftPhase(new MysteryEncounterPhase()); globalScene.phaseManager.unshiftNew("MysteryEncounterPhase");
this.end(); this.end();
}; };
@ -554,7 +545,7 @@ export class EncounterPhase extends BattlePhase {
enemyField.forEach((enemyPokemon, e) => { enemyField.forEach((enemyPokemon, e) => {
if (enemyPokemon.isShiny(true)) { if (enemyPokemon.isShiny(true)) {
globalScene.phaseManager.unshiftPhase(new ShinySparklePhase(BattlerIndex.ENEMY + e)); globalScene.phaseManager.unshiftNew("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 +567,9 @@ 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.phaseManager.pushConditionalPhase(new PostSummonPhase(p.getBattlerIndex()), () => { globalScene.phaseManager.pushConditionalPhase(
globalScene.phaseManager.create("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;
@ -584,17 +577,21 @@ export class EncounterPhase extends BattlePhase {
// how many player pokemon are on the field ? // how many player pokemon are on the field ?
const pokemonsOnFieldCount = globalScene.getPlayerParty().filter(p => p.isOnField()).length; const pokemonsOnFieldCount = globalScene.getPlayerParty().filter(p => p.isOnField()).length;
// if it's a 2vs1, there will never be a 2nd pokemon on our field even // if it's a 2vs1, there will never be a 2nd pokemon on our field even
const requiredPokemonsOnField = Math.min(globalScene.getPlayerParty().filter(p => !p.isFainted()).length, 2); const requiredPokemonsOnField = Math.min(
globalScene.getPlayerParty().filter(p => !p.isFainted()).length,
2,
);
// if it's a double, there should be 2, otherwise 1 // if it's a double, there should be 2, otherwise 1
if (globalScene.currentBattle.double) { if (globalScene.currentBattle.double) {
return pokemonsOnFieldCount === requiredPokemonsOnField; return pokemonsOnFieldCount === requiredPokemonsOnField;
} }
return pokemonsOnFieldCount === 1; return pokemonsOnFieldCount === 1;
}), },
),
); );
const ivScannerModifier = globalScene.findModifier(m => m instanceof IvScannerModifier); const ivScannerModifier = globalScene.findModifier(m => m instanceof IvScannerModifier);
if (ivScannerModifier) { if (ivScannerModifier) {
enemyField.map(p => globalScene.phaseManager.pushPhase(new ScanIvsPhase(p.getBattlerIndex()))); enemyField.map(p => globalScene.phaseManager.pushNew("ScanIvsPhase", p.getBattlerIndex()));
} }
} }
@ -602,21 +599,21 @@ export class EncounterPhase extends BattlePhase {
const availablePartyMembers = globalScene.getPokemonAllowedInBattle(); const availablePartyMembers = globalScene.getPokemonAllowedInBattle();
if (!availablePartyMembers[0].isOnField()) { if (!availablePartyMembers[0].isOnField()) {
globalScene.phaseManager.pushPhase(new SummonPhase(0)); globalScene.phaseManager.pushNew("SummonPhase", 0);
} }
if (globalScene.currentBattle.double) { if (globalScene.currentBattle.double) {
if (availablePartyMembers.length > 1) { if (availablePartyMembers.length > 1) {
globalScene.phaseManager.pushPhase(new ToggleDoublePositionPhase(true)); globalScene.phaseManager.pushNew("ToggleDoublePositionPhase", true);
if (!availablePartyMembers[1].isOnField()) { if (!availablePartyMembers[1].isOnField()) {
globalScene.phaseManager.pushPhase(new SummonPhase(1)); globalScene.phaseManager.pushNew("SummonPhase", 1);
} }
} }
} else { } else {
if (availablePartyMembers.length > 1 && availablePartyMembers[1].isOnField()) { if (availablePartyMembers.length > 1 && availablePartyMembers[1].isOnField()) {
globalScene.phaseManager.pushPhase(new ReturnPhase(1)); globalScene.phaseManager.pushNew("ReturnPhase", 1);
} }
globalScene.phaseManager.pushPhase(new ToggleDoublePositionPhase(false)); globalScene.phaseManager.pushNew("ToggleDoublePositionPhase", false);
} }
if ( if (
@ -625,9 +622,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.phaseManager.pushPhase(new CheckSwitchPhase(0, globalScene.currentBattle.double)); globalScene.phaseManager.pushNew("CheckSwitchPhase", 0, globalScene.currentBattle.double);
if (globalScene.currentBattle.double) { if (globalScene.currentBattle.double) {
globalScene.phaseManager.pushPhase(new CheckSwitchPhase(1, globalScene.currentBattle.double)); globalScene.phaseManager.pushNew("CheckSwitchPhase", 1, globalScene.currentBattle.double);
} }
} }
} }

View File

@ -14,8 +14,6 @@ import { LearnMoveSituation } from "#app/field/pokemon";
import { getTypeRgb } from "#app/data/type"; import { getTypeRgb } from "#app/data/type";
import i18next from "i18next"; import i18next from "i18next";
import { getPokemonNameWithAffix } from "#app/messages"; import { getPokemonNameWithAffix } from "#app/messages";
import { LearnMovePhase } from "#app/phases/learn-move-phase";
import { EndEvolutionPhase } from "#app/phases/end-evolution-phase";
import { EVOLVE_MOVE } from "#app/data/balance/pokemon-level-moves"; import { EVOLVE_MOVE } from "#app/data/balance/pokemon-level-moves";
export class EvolutionPhase extends Phase { export class EvolutionPhase extends Phase {
@ -262,7 +260,7 @@ export class EvolutionPhase extends Phase {
SoundFade.fadeOut(globalScene, this.evolutionBgm, 100); SoundFade.fadeOut(globalScene, this.evolutionBgm, 100);
globalScene.phaseManager.unshiftPhase(new EndEvolutionPhase()); globalScene.phaseManager.unshiftNew("EndEvolutionPhase");
globalScene.ui.showText( globalScene.ui.showText(
i18next.t("menu:stoppedEvolving", { i18next.t("menu:stoppedEvolving", {
@ -355,11 +353,13 @@ 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new LearnMovePhase(globalScene.getPlayerParty().indexOf(this.pokemon), lm[1]), "LearnMovePhase",
globalScene.getPlayerParty().indexOf(this.pokemon),
lm[1],
); );
} }
globalScene.phaseManager.unshiftPhase(new EndEvolutionPhase()); globalScene.phaseManager.unshiftNew("EndEvolutionPhase");
globalScene.playSound("se/shine"); globalScene.playSound("se/shine");
this.doSpray(); this.doSpray();

View File

@ -4,7 +4,6 @@ import { ExpBoosterModifier } from "#app/modifier/modifier";
import i18next from "i18next"; import i18next from "i18next";
import { NumberHolder } from "#app/utils/common"; import { NumberHolder } from "#app/utils/common";
import { PlayerPartyMemberPokemonPhase } from "./player-party-member-pokemon-phase"; import { PlayerPartyMemberPokemonPhase } from "./player-party-member-pokemon-phase";
import { LevelUpPhase } from "./level-up-phase";
export class ExpPhase extends PlayerPartyMemberPokemonPhase { export class ExpPhase extends PlayerPartyMemberPokemonPhase {
public readonly phaseName = "ExpPhase"; public readonly phaseName = "ExpPhase";
@ -34,7 +33,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.phaseManager.unshiftPhase(new LevelUpPhase(this.partyMemberIndex, lastLevel, newLevel)); globalScene.phaseManager.unshiftNew("LevelUpPhase", this.partyMemberIndex, lastLevel, newLevel);
} }
pokemon.updateInfo().then(() => this.end()); pokemon.updateInfo().then(() => this.end());
}, },

View File

@ -24,13 +24,7 @@ import { getPokemonNameWithAffix } from "#app/messages";
import { PokemonInstantReviveModifier } from "#app/modifier/modifier"; import { PokemonInstantReviveModifier } from "#app/modifier/modifier";
import { SwitchType } from "#enums/switch-type"; import { SwitchType } from "#enums/switch-type";
import i18next from "i18next"; import i18next from "i18next";
import { DamageAnimPhase } from "./damage-anim-phase";
import { GameOverPhase } from "./game-over-phase";
import { PokemonPhase } from "./pokemon-phase"; import { PokemonPhase } from "./pokemon-phase";
import { SwitchPhase } from "./switch-phase";
import { SwitchSummonPhase } from "./switch-summon-phase";
import { ToggleDoublePositionPhase } from "./toggle-double-position-phase";
import { VictoryPhase } from "./victory-phase";
import { isNullOrUndefined } from "#app/utils/common"; import { isNullOrUndefined } from "#app/utils/common";
import { FRIENDSHIP_LOSS_FROM_FAINT } from "#app/data/balance/starters"; import { FRIENDSHIP_LOSS_FROM_FAINT } from "#app/data/balance/starters";
import { BattlerTagType } from "#enums/battler-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type";
@ -166,7 +160,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.phaseManager.unshiftPhase(new GameOverPhase()); globalScene.phaseManager.unshiftNew("GameOverPhase");
} else if ( } else if (
globalScene.currentBattle.double && globalScene.currentBattle.double &&
legalPlayerPokemon.length === 1 && legalPlayerPokemon.length === 1 &&
@ -176,25 +170,23 @@ 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.phaseManager.unshiftPhase(new ToggleDoublePositionPhase(true)); globalScene.phaseManager.unshiftNew("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.phaseManager.pushPhase(new SwitchPhase(SwitchType.SWITCH, this.fieldIndex, true, false)); globalScene.phaseManager.pushNew("SwitchPhase", SwitchType.SWITCH, this.fieldIndex, true, false);
} }
} else { } else {
globalScene.phaseManager.unshiftPhase(new VictoryPhase(this.battlerIndex)); globalScene.phaseManager.unshiftNew("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.phaseManager.pushPhase( globalScene.phaseManager.pushNew("SwitchSummonPhase", SwitchType.SWITCH, this.fieldIndex, -1, false, false);
new SwitchSummonPhase(SwitchType.SWITCH, this.fieldIndex, -1, false, false),
);
} }
} }
} }
@ -249,7 +241,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.phaseManager.unshiftPhase(new DamageAnimPhase(enemy.getBattlerIndex(), 0, HitResult.INDIRECT)); globalScene.phaseManager.unshiftNew("DamageAnimPhase", enemy.getBattlerIndex(), 0, HitResult.INDIRECT);
this.end(); this.end();
} }
return true; return true;

View File

@ -7,7 +7,6 @@ import type { PlayerPokemon } from "../field/pokemon";
import { UiMode } from "#enums/ui-mode"; import { UiMode } from "#enums/ui-mode";
import type PartyUiHandler from "../ui/party-ui-handler"; import type PartyUiHandler from "../ui/party-ui-handler";
import { getPokemonNameWithAffix } from "../messages"; import { getPokemonNameWithAffix } from "../messages";
import { EndEvolutionPhase } from "./end-evolution-phase";
import { EvolutionPhase } from "./evolution-phase"; import { EvolutionPhase } from "./evolution-phase";
import { BattlerTagType } from "#enums/battler-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type";
import { SpeciesFormKey } from "#enums/species-form-key"; import { SpeciesFormKey } from "#enums/species-form-key";
@ -100,7 +99,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.phaseManager.unshiftPhase(new EndEvolutionPhase()); globalScene.phaseManager.unshiftNew("EndEvolutionPhase");
} }
globalScene.playSound("se/shine"); globalScene.playSound("se/shine");

View File

@ -9,14 +9,7 @@ import { trainerConfigs } from "#app/data/trainers/trainer-config";
import type Pokemon from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon";
import { modifierTypes } from "#app/modifier/modifier-type"; import { modifierTypes } from "#app/modifier/modifier-type";
import { BattlePhase } from "#app/phases/battle-phase"; import { BattlePhase } from "#app/phases/battle-phase";
import { CheckSwitchPhase } from "#app/phases/check-switch-phase"; import type { EndCardPhase } from "#app/phases/end-card-phase";
import { EncounterPhase } from "#app/phases/encounter-phase";
import { EndCardPhase } from "#app/phases/end-card-phase";
import { GameOverModifierRewardPhase } from "#app/phases/game-over-modifier-reward-phase";
import { PostGameOverPhase } from "#app/phases/post-game-over-phase";
import { RibbonModifierRewardPhase } from "#app/phases/ribbon-modifier-reward-phase";
import { SummonPhase } from "#app/phases/summon-phase";
import { UnlockPhase } from "#app/phases/unlock-phase";
import { achvs, ChallengeAchv } from "#app/system/achv"; import { achvs, ChallengeAchv } from "#app/system/achv";
import { Unlockables } from "#app/system/unlockables"; import { Unlockables } from "#app/system/unlockables";
import { UiMode } from "#enums/ui-mode"; import { UiMode } from "#enums/ui-mode";
@ -31,7 +24,6 @@ import ChallengeData from "#app/system/challenge-data";
import TrainerData from "#app/system/trainer-data"; import TrainerData from "#app/system/trainer-data";
import ArenaData from "#app/system/arena-data"; import ArenaData from "#app/system/arena-data";
import { pokerogueApi } from "#app/plugins/api/pokerogue-api"; import { pokerogueApi } from "#app/plugins/api/pokerogue-api";
import { MessagePhase } from "./message-phase";
export class GameOverPhase extends BattlePhase { export class GameOverPhase extends BattlePhase {
public readonly phaseName = "GameOverPhase"; public readonly phaseName = "GameOverPhase";
@ -86,21 +78,21 @@ export class GameOverPhase extends BattlePhase {
globalScene.reset(); globalScene.reset();
globalScene.phaseManager.clearPhaseQueue(); globalScene.phaseManager.clearPhaseQueue();
globalScene.gameData.loadSession(globalScene.sessionSlotId).then(() => { globalScene.gameData.loadSession(globalScene.sessionSlotId).then(() => {
globalScene.phaseManager.pushPhase(new EncounterPhase(true)); globalScene.phaseManager.pushNew("EncounterPhase", true);
const availablePartyMembers = globalScene.getPokemonAllowedInBattle().length; const availablePartyMembers = globalScene.getPokemonAllowedInBattle().length;
globalScene.phaseManager.pushPhase(new SummonPhase(0)); globalScene.phaseManager.pushNew("SummonPhase", 0);
if (globalScene.currentBattle.double && availablePartyMembers > 1) { if (globalScene.currentBattle.double && availablePartyMembers > 1) {
globalScene.phaseManager.pushPhase(new SummonPhase(1)); globalScene.phaseManager.pushNew("SummonPhase", 1);
} }
if ( if (
globalScene.currentBattle.waveIndex > 1 && globalScene.currentBattle.waveIndex > 1 &&
globalScene.currentBattle.battleType !== BattleType.TRAINER globalScene.currentBattle.battleType !== BattleType.TRAINER
) { ) {
globalScene.phaseManager.pushPhase(new CheckSwitchPhase(0, globalScene.currentBattle.double)); globalScene.phaseManager.pushNew("CheckSwitchPhase", 0, globalScene.currentBattle.double);
if (globalScene.currentBattle.double && availablePartyMembers > 1) { if (globalScene.currentBattle.double && availablePartyMembers > 1) {
globalScene.phaseManager.pushPhase(new CheckSwitchPhase(1, globalScene.currentBattle.double)); globalScene.phaseManager.pushNew("CheckSwitchPhase", 1, globalScene.currentBattle.double);
} }
} }
@ -160,17 +152,15 @@ export class GameOverPhase extends BattlePhase {
this.handleUnlocks(); this.handleUnlocks();
for (const species of this.firstRibbons) { for (const species of this.firstRibbons) {
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew("RibbonModifierRewardPhase", modifierTypes.VOUCHER_PLUS, species);
new RibbonModifierRewardPhase(modifierTypes.VOUCHER_PLUS, species),
);
} }
if (!firstClear) { if (!firstClear) {
globalScene.phaseManager.unshiftPhase(new GameOverModifierRewardPhase(modifierTypes.VOUCHER_PREMIUM)); globalScene.phaseManager.unshiftNew("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.phaseManager.pushPhase(new PostGameOverPhase(endCardPhase)); globalScene.phaseManager.pushNew("PostGameOverPhase", endCardPhase);
this.end(); this.end();
}); });
}; };
@ -199,7 +189,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 = globalScene.phaseManager.create("EndCardPhase");
globalScene.phaseManager.unshiftPhase(endCardPhase); globalScene.phaseManager.unshiftPhase(endCardPhase);
clear(endCardPhase); clear(endCardPhase);
}); });
@ -209,7 +199,7 @@ export class GameOverPhase extends BattlePhase {
}); });
}); });
} else { } else {
const endCardPhase = new EndCardPhase(); const endCardPhase = globalScene.phaseManager.create("EndCardPhase");
globalScene.phaseManager.unshiftPhase(endCardPhase); globalScene.phaseManager.unshiftPhase(endCardPhase);
clear(endCardPhase); clear(endCardPhase);
} }
@ -234,7 +224,7 @@ export class GameOverPhase extends BattlePhase {
.catch(_err => { .catch(_err => {
globalScene.phaseManager.clearPhaseQueue(); globalScene.phaseManager.clearPhaseQueue();
globalScene.phaseManager.clearPhaseQueueSplice(); globalScene.phaseManager.clearPhaseQueueSplice();
globalScene.phaseManager.unshiftPhase(new MessagePhase(i18next.t("menu:serverCommunicationFailed"), 2500)); globalScene.phaseManager.unshiftNew("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();
@ -253,22 +243,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.phaseManager.unshiftPhase(new UnlockPhase(Unlockables.ENDLESS_MODE)); globalScene.phaseManager.unshiftNew("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.phaseManager.unshiftPhase(new UnlockPhase(Unlockables.SPLICED_ENDLESS_MODE)); globalScene.phaseManager.unshiftNew("UnlockPhase", Unlockables.SPLICED_ENDLESS_MODE);
} }
if (!globalScene.gameData.unlocks[Unlockables.MINI_BLACK_HOLE]) { if (!globalScene.gameData.unlocks[Unlockables.MINI_BLACK_HOLE]) {
globalScene.phaseManager.unshiftPhase(new UnlockPhase(Unlockables.MINI_BLACK_HOLE)); globalScene.phaseManager.unshiftNew("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.phaseManager.unshiftPhase(new UnlockPhase(Unlockables.EVIOLITE)); globalScene.phaseManager.unshiftNew("UnlockPhase", Unlockables.EVIOLITE);
} }
} }
} }

View File

@ -2,8 +2,6 @@ import { globalScene } from "#app/global-scene";
import { ExpNotification } from "#app/enums/exp-notification"; import { ExpNotification } from "#app/enums/exp-notification";
import type { PlayerPokemon } from "#app/field/pokemon"; import type { PlayerPokemon } from "#app/field/pokemon";
import { getPokemonNameWithAffix } from "#app/messages"; import { getPokemonNameWithAffix } from "#app/messages";
import { EvolutionPhase } from "#app/phases/evolution-phase";
import { LearnMovePhase } from "#app/phases/learn-move-phase";
import { PlayerPartyMemberPokemonPhase } from "#app/phases/player-party-member-pokemon-phase"; import { PlayerPartyMemberPokemonPhase } from "#app/phases/player-party-member-pokemon-phase";
import { LevelAchv } from "#app/system/achv"; import { LevelAchv } from "#app/system/achv";
import { NumberHolder } from "#app/utils/common"; import { NumberHolder } from "#app/utils/common";
@ -66,14 +64,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.phaseManager.unshiftPhase(new LearnMovePhase(this.partyMemberIndex, lm[1])); globalScene.phaseManager.unshiftNew("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.phaseManager.unshiftPhase(new EvolutionPhase(this.pokemon, evolution, this.lastLevel)); globalScene.phaseManager.unshiftNew("EvolutionPhase", this.pokemon, evolution, this.lastLevel);
} }
} }
return super.end(); return super.end();

View File

@ -7,8 +7,6 @@ import { UiMode } from "#enums/ui-mode";
import i18next, { t } from "i18next"; import i18next, { t } from "i18next";
import { sessionIdKey, executeIf } from "#app/utils/common"; import { sessionIdKey, executeIf } from "#app/utils/common";
import { getCookie, removeCookie } from "#app/utils/cookies"; import { getCookie, removeCookie } from "#app/utils/cookies";
import { SelectGenderPhase } from "./select-gender-phase";
import { UnavailablePhase } from "./unavailable-phase";
export class LoginPhase extends Phase { export class LoginPhase extends Phase {
public readonly phaseName = "LoginPhase"; public readonly phaseName = "LoginPhase";
@ -70,7 +68,7 @@ export class LoginPhase extends Phase {
}); });
}, },
() => { () => {
globalScene.phaseManager.unshiftPhase(new LoginPhase(false)); globalScene.phaseManager.unshiftNew("LoginPhase", false);
this.end(); this.end();
}, },
], ],
@ -94,7 +92,7 @@ export class LoginPhase extends Phase {
removeCookie(sessionIdKey); removeCookie(sessionIdKey);
globalScene.reset(true, true); globalScene.reset(true, true);
} else { } else {
globalScene.phaseManager.unshiftPhase(new UnavailablePhase()); globalScene.phaseManager.unshiftNew("UnavailablePhase");
super.end(); super.end();
} }
return null; return null;
@ -114,7 +112,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.phaseManager.unshiftPhase(new SelectGenderPhase()); globalScene.phaseManager.unshiftNew("SelectGenderPhase");
} }
handleTutorial(Tutorial.Intro).then(() => super.end()); handleTutorial(Tutorial.Intro).then(() => super.end());

View File

@ -44,8 +44,13 @@ 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new MessagePhase(page1, this.callbackDelay, this.prompt, this.promptDelay, this.speaker), "MessagePhase",
page1,
this.callbackDelay,
this.prompt,
this.promptDelay,
this.speaker,
); );
this.text = page0.trim(); this.text = page0.trim();
} else { } else {

View File

@ -6,7 +6,6 @@ import type { PokemonMove } from "#app/field/pokemon";
import type Pokemon from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon";
import { MoveResult } from "#app/field/pokemon"; import { MoveResult } from "#app/field/pokemon";
import { BooleanHolder } from "#app/utils/common"; import { BooleanHolder } from "#app/utils/common";
import { MovePhase } from "#app/phases/move-phase";
import { PokemonPhase } from "#app/phases/pokemon-phase"; import { PokemonPhase } from "#app/phases/pokemon-phase";
import { BattlerTagType } from "#enums/battler-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type";
@ -64,7 +63,7 @@ export class MoveChargePhase extends PokemonPhase {
// 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.phaseManager.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.phaseManager.unshiftPhase(new MovePhase(user, [this.targetIndex], this.move, false)); globalScene.phaseManager.unshiftNew("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

@ -68,15 +68,10 @@ import { BattlerTagType } from "#enums/battler-tag-type";
import { MoveId } from "#enums/move-id"; import { MoveId } from "#enums/move-id";
import i18next from "i18next"; import i18next from "i18next";
import type { Phase } from "#app/phase"; import type { Phase } from "#app/phase";
import { ShowAbilityPhase } from "./show-ability-phase";
import { MovePhase } from "./move-phase";
import { MoveEndPhase } from "./move-end-phase";
import { HideAbilityPhase } from "#app/phases/hide-ability-phase";
import type { TypeDamageMultiplier } from "#app/data/type"; import type { TypeDamageMultiplier } from "#app/data/type";
import { HitCheckResult } from "#enums/hit-check-result"; import { HitCheckResult } from "#enums/hit-check-result";
import type Move from "#app/data/moves/move"; import type Move from "#app/data/moves/move";
import { isFieldTargeted } from "#app/data/moves/move-utils"; import { isFieldTargeted } from "#app/data/moves/move-utils";
import { FaintPhase } from "./faint-phase";
import { DamageAchv } from "#app/system/achv"; import { DamageAchv } from "#app/system/achv";
type HitCheckEntry = [HitCheckResult, TypeDamageMultiplier]; type HitCheckEntry = [HitCheckResult, TypeDamageMultiplier];
@ -191,13 +186,25 @@ export class MoveEffectPhase extends PokemonPhase {
// TODO: ability displays should be handled by the ability // TODO: ability displays should be handled by the ability
if (!target.getTag(BattlerTagType.MAGIC_COAT)) { if (!target.getTag(BattlerTagType.MAGIC_COAT)) {
this.queuedPhases.push( this.queuedPhases.push(
new ShowAbilityPhase(target.getBattlerIndex(), target.getPassiveAbility().hasAttr(ReflectStatusMoveAbAttr)), globalScene.phaseManager.create(
"ShowAbilityPhase",
target.getBattlerIndex(),
target.getPassiveAbility().hasAttr(ReflectStatusMoveAbAttr),
),
); );
this.queuedPhases.push(new HideAbilityPhase()); this.queuedPhases.push(globalScene.phaseManager.create("HideAbilityPhase"));
} }
this.queuedPhases.push( this.queuedPhases.push(
new MovePhase(target, newTargets, new PokemonMove(this.move.id, 0, 0, true), true, true, true), globalScene.phaseManager.create(
"MovePhase",
target,
newTargets,
new PokemonMove(this.move.id, 0, 0, true),
true,
true,
true,
),
); );
} }
@ -384,7 +391,7 @@ export class MoveEffectPhase extends PokemonPhase {
} }
if (this.queuedPhases.length) { if (this.queuedPhases.length) {
globalScene.phaseManager.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)) {
@ -903,7 +910,7 @@ export class MoveEffectPhase extends PokemonPhase {
// set splice index here, so future scene queues happen before FaintedPhase // set splice index here, so future scene queues happen before FaintedPhase
globalScene.phaseManager.setPhaseQueueSplice(); globalScene.phaseManager.setPhaseQueueSplice();
globalScene.phaseManager.unshiftPhase(new FaintPhase(target.getBattlerIndex(), false, user)); globalScene.phaseManager.unshiftNew("FaintPhase", target.getBattlerIndex(), false, user);
target.destroySubstitute(); target.destroySubstitute();
target.lapseTag(BattlerTagType.COMMANDED); target.lapseTag(BattlerTagType.COMMANDED);

View File

@ -39,10 +39,6 @@ import { MoveResult } from "#app/field/pokemon";
import { getPokemonNameWithAffix } from "#app/messages"; import { getPokemonNameWithAffix } from "#app/messages";
import Overrides from "#app/overrides"; import Overrides from "#app/overrides";
import { BattlePhase } from "#app/phases/battle-phase"; import { BattlePhase } from "#app/phases/battle-phase";
import { CommonAnimPhase } from "#app/phases/common-anim-phase";
import { MoveChargePhase } from "#app/phases/move-charge-phase";
import { MoveEffectPhase } from "#app/phases/move-effect-phase";
import { MoveEndPhase } from "#app/phases/move-end-phase";
import { NumberHolder } from "#app/utils/common"; import { NumberHolder } from "#app/utils/common";
import { AbilityId } from "#enums/ability-id"; import { AbilityId } from "#enums/ability-id";
import { ArenaTagType } from "#enums/arena-tag-type"; import { ArenaTagType } from "#enums/arena-tag-type";
@ -271,12 +267,11 @@ export class MovePhase extends BattlePhase {
globalScene.phaseManager.queueMessage( globalScene.phaseManager.queueMessage(
getStatusEffectActivationText(this.pokemon.status.effect, getPokemonNameWithAffix(this.pokemon)), getStatusEffectActivationText(this.pokemon.status.effect, getPokemonNameWithAffix(this.pokemon)),
); );
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new CommonAnimPhase( "CommonAnimPhase",
this.pokemon.getBattlerIndex(), this.pokemon.getBattlerIndex(),
undefined, undefined,
CommonAnim.POISON + (this.pokemon.status.effect - 1), CommonAnim.POISON + (this.pokemon.status.effect - 1),
),
); );
} else if (healed) { } else if (healed) {
globalScene.phaseManager.queueMessage( globalScene.phaseManager.queueMessage(
@ -407,8 +402,13 @@ 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new MoveEffectPhase(this.pokemon.getBattlerIndex(), this.targets, move, this.reflected, this.move.virtual), "MoveEffectPhase",
this.pokemon.getBattlerIndex(),
this.targets,
move,
this.reflected,
this.move.virtual,
); );
} else { } else {
if ([MoveId.ROAR, MoveId.WHIRLWIND, MoveId.TRICK_OR_TREAT, MoveId.FORESTS_CURSE].includes(this.move.moveId)) { if ([MoveId.ROAR, MoveId.WHIRLWIND, MoveId.TRICK_OR_TREAT, MoveId.FORESTS_CURSE].includes(this.move.moveId)) {
@ -457,8 +457,11 @@ 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new MoveChargePhase(this.pokemon.getBattlerIndex(), this.targets[0], this.move), "MoveChargePhase",
this.pokemon.getBattlerIndex(),
this.targets[0],
this.move,
); );
} else { } else {
this.pokemon.pushMoveHistory({ this.pokemon.pushMoveHistory({
@ -481,8 +484,11 @@ 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new MoveEndPhase(this.pokemon.getBattlerIndex(), this.getActiveTargetPokemon(), this.followUp), "MoveEndPhase",
this.pokemon.getBattlerIndex(),
this.getActiveTargetPokemon(),
this.followUp,
); );
super.end(); super.end();

View File

@ -3,15 +3,6 @@ import type { OptionPhaseCallback } from "#app/data/mystery-encounters/mystery-e
import type MysteryEncounterOption from "#app/data/mystery-encounters/mystery-encounter-option"; import type MysteryEncounterOption from "#app/data/mystery-encounters/mystery-encounter-option";
import { SeenEncounterData } from "#app/data/mystery-encounters/mystery-encounter-save-data"; import { SeenEncounterData } from "#app/data/mystery-encounters/mystery-encounter-save-data";
import { getEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils"; import { getEncounterText } from "#app/data/mystery-encounters/utils/encounter-dialogue-utils";
import { CheckSwitchPhase } from "#app/phases/check-switch-phase";
import { GameOverPhase } from "#app/phases/game-over-phase";
import { NewBattlePhase } from "#app/phases/new-battle-phase";
import { ReturnPhase } from "#app/phases/return-phase";
import { ScanIvsPhase } from "#app/phases/scan-ivs-phase";
import { SelectModifierPhase } from "#app/phases/select-modifier-phase";
import { SummonPhase } from "#app/phases/summon-phase";
import { SwitchPhase } from "#app/phases/switch-phase";
import { ToggleDoublePositionPhase } from "#app/phases/toggle-double-position-phase";
import { BattleSpec } from "#enums/battle-spec"; import { BattleSpec } from "#enums/battle-spec";
import { BattlerTagType } from "#enums/battler-tag-type"; import { BattlerTagType } from "#enums/battler-tag-type";
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode"; import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
@ -26,7 +17,6 @@ import { IvScannerModifier } from "../modifier/modifier";
import { Phase } from "../phase"; import { Phase } from "../phase";
import { UiMode } from "#enums/ui-mode"; import { UiMode } from "#enums/ui-mode";
import { isNullOrUndefined, randSeedItem } from "#app/utils/common"; import { isNullOrUndefined, randSeedItem } from "#app/utils/common";
import { SelectBiomePhase } from "./select-biome-phase";
/** /**
* Will handle (in order): * Will handle (in order):
@ -124,7 +114,7 @@ export class MysteryEncounterPhase extends Phase {
*/ */
continueEncounter() { continueEncounter() {
const endDialogueAndContinueEncounter = () => { const endDialogueAndContinueEncounter = () => {
globalScene.phaseManager.pushPhase(new MysteryEncounterOptionSelectedPhase()); globalScene.phaseManager.pushNew("MysteryEncounterOptionSelectedPhase");
this.end(); this.end();
}; };
@ -256,7 +246,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.phaseManager.unshiftPhase(new GameOverPhase()); globalScene.phaseManager.unshiftNew("GameOverPhase");
return this.end(); return this.end();
} }
@ -265,13 +255,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.phaseManager.unshiftPhase(new SwitchPhase(SwitchType.SWITCH, i, true, false)); globalScene.phaseManager.unshiftNew("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.phaseManager.unshiftPhase(new ToggleDoublePositionPhase(true)); globalScene.phaseManager.unshiftNew("ToggleDoublePositionPhase", true);
} }
this.end(); this.end();
@ -348,9 +338,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.phaseManager.unshiftPhase(new SummonPhase(0, false)); globalScene.phaseManager.unshiftNew("SummonPhase", 0, false);
if (globalScene.currentBattle.double && availablePartyMembers > 1) { if (globalScene.currentBattle.double && availablePartyMembers > 1) {
globalScene.phaseManager.unshiftPhase(new SummonPhase(1, false)); globalScene.phaseManager.unshiftNew("SummonPhase", 1, false);
} }
if (!globalScene.currentBattle.mysteryEncounter?.hideBattleIntroMessage) { if (!globalScene.currentBattle.mysteryEncounter?.hideBattleIntroMessage) {
@ -368,9 +358,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.phaseManager.unshiftPhase(new SummonPhase(0, false)); globalScene.phaseManager.unshiftNew("SummonPhase", 0, false);
if (globalScene.currentBattle.double && availablePartyMembers > 1) { if (globalScene.currentBattle.double && availablePartyMembers > 1) {
globalScene.phaseManager.unshiftPhase(new SummonPhase(1, false)); globalScene.phaseManager.unshiftNew("SummonPhase", 1, false);
} }
this.endBattleSetup(); this.endBattleSetup();
}; };
@ -426,37 +416,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.phaseManager.pushPhase(new ScanIvsPhase(p.getBattlerIndex()))); enemyField.map(p => globalScene.phaseManager.pushNew("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.phaseManager.pushPhase(new SummonPhase(0)); globalScene.phaseManager.pushNew("SummonPhase", 0);
} }
if (globalScene.currentBattle.double) { if (globalScene.currentBattle.double) {
if (availablePartyMembers.length > 1) { if (availablePartyMembers.length > 1) {
globalScene.phaseManager.pushPhase(new ToggleDoublePositionPhase(true)); globalScene.phaseManager.pushNew("ToggleDoublePositionPhase", true);
if (!availablePartyMembers[1].isOnField()) { if (!availablePartyMembers[1].isOnField()) {
globalScene.phaseManager.pushPhase(new SummonPhase(1)); globalScene.phaseManager.pushNew("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.phaseManager.pushPhase(new ReturnPhase(1)); globalScene.phaseManager.pushNew("ReturnPhase", 1);
} }
globalScene.phaseManager.pushPhase(new ToggleDoublePositionPhase(false)); globalScene.phaseManager.pushNew("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.phaseManager.pushPhase(new CheckSwitchPhase(0, globalScene.currentBattle.double)); globalScene.phaseManager.pushNew("CheckSwitchPhase", 0, globalScene.currentBattle.double);
if (globalScene.currentBattle.double) { if (globalScene.currentBattle.double) {
globalScene.phaseManager.pushPhase(new CheckSwitchPhase(1, globalScene.currentBattle.double)); globalScene.phaseManager.pushNew("CheckSwitchPhase", 1, globalScene.currentBattle.double);
} }
} }
} }
@ -563,15 +553,13 @@ export class MysteryEncounterRewardsPhase extends Phase {
encounter.doEncounterRewards(); encounter.doEncounterRewards();
} else if (this.addHealPhase) { } else if (this.addHealPhase) {
globalScene.phaseManager.tryRemovePhase(p => p.is("SelectModifierPhase")); globalScene.phaseManager.tryRemovePhase(p => p.is("SelectModifierPhase"));
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew("SelectModifierPhase", 0, undefined, {
new SelectModifierPhase(0, undefined, {
fillRemaining: false, fillRemaining: false,
rerollMultiplier: -1, rerollMultiplier: -1,
}), });
);
} }
globalScene.phaseManager.pushPhase(new PostMysteryEncounterPhase()); globalScene.phaseManager.pushNew("PostMysteryEncounterPhase");
this.end(); this.end();
} }
} }
@ -618,10 +606,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.phaseManager.pushPhase(new SelectBiomePhase()); globalScene.phaseManager.pushNew("SelectBiomePhase");
} }
globalScene.phaseManager.pushPhase(new NewBattlePhase()); globalScene.phaseManager.pushNew("NewBattlePhase");
this.end(); this.end();
}; };

View File

@ -1,7 +1,6 @@
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import { Phase } from "#app/phase"; import { Phase } from "#app/phase";
import type { EndCardPhase } from "./end-card-phase"; import type { EndCardPhase } from "./end-card-phase";
import { TitlePhase } from "./title-phase";
export class PostGameOverPhase extends Phase { export class PostGameOverPhase extends Phase {
public readonly phaseName = "PostGameOverPhase"; public readonly phaseName = "PostGameOverPhase";
@ -28,7 +27,7 @@ export class PostGameOverPhase extends Phase {
return globalScene.reset(true); return globalScene.reset(true);
} }
globalScene.reset(); globalScene.reset();
globalScene.phaseManager.unshiftPhase(new TitlePhase()); globalScene.phaseManager.unshiftNew("TitlePhase");
this.end(); this.end();
}); });
}); });

View File

@ -9,7 +9,6 @@ import type Pokemon from "#app/field/pokemon";
import { getPokemonNameWithAffix } from "#app/messages"; import { getPokemonNameWithAffix } from "#app/messages";
import { BattlePhase } from "./battle-phase"; import { BattlePhase } from "./battle-phase";
import type { MovePhase } from "./move-phase"; import type { MovePhase } from "./move-phase";
import { PokemonHealPhase } from "./pokemon-heal-phase";
import { import {
applyAbAttrs, applyAbAttrs,
ClearTerrainAbAttr, ClearTerrainAbAttr,
@ -159,8 +158,15 @@ 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new PokemonHealPhase(this.pokemon.getBattlerIndex(), this.pokemon.getMaxHp(), null, false, false, false, true), "PokemonHealPhase",
this.pokemon.getBattlerIndex(),
this.pokemon.getMaxHp(),
null,
false,
false,
false,
true,
); );
this.pokemon.findAndRemoveTags(() => true); this.pokemon.findAndRemoveTags(() => true);
this.pokemon.bossSegments = 5; this.pokemon.bossSegments = 5;

View File

@ -6,8 +6,6 @@ import { UiMode } from "#enums/ui-mode";
import i18next from "i18next"; import i18next from "i18next";
import { toDmgValue, isNullOrUndefined } from "#app/utils/common"; import { toDmgValue, isNullOrUndefined } from "#app/utils/common";
import { BattlePhase } from "#app/phases/battle-phase"; import { BattlePhase } from "#app/phases/battle-phase";
import { SwitchSummonPhase } from "#app/phases/switch-summon-phase";
import { ToggleDoublePositionPhase } from "#app/phases/toggle-double-position-phase";
import type { PlayerPokemon } from "#app/field/pokemon"; import type { PlayerPokemon } from "#app/field/pokemon";
/** /**
@ -51,16 +49,26 @@ export class RevivalBlessingPhase extends BattlePhase {
) { ) {
if (slotIndex <= 1) { if (slotIndex <= 1) {
// Revived ally pokemon // Revived ally pokemon
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new SwitchSummonPhase(SwitchType.SWITCH, pokemon.getFieldIndex(), slotIndex, false, true), "SwitchSummonPhase",
SwitchType.SWITCH,
pokemon.getFieldIndex(),
slotIndex,
false,
true,
); );
globalScene.phaseManager.unshiftPhase(new ToggleDoublePositionPhase(true)); globalScene.phaseManager.unshiftNew("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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new SwitchSummonPhase(SwitchType.SWITCH, allyPokemon.getFieldIndex(), slotIndex, false, true), "SwitchSummonPhase",
SwitchType.SWITCH,
allyPokemon.getFieldIndex(),
slotIndex,
false,
true,
); );
globalScene.phaseManager.unshiftPhase(new ToggleDoublePositionPhase(true)); globalScene.phaseManager.unshiftNew("ToggleDoublePositionPhase", true);
} }
} }
} }

View File

@ -6,8 +6,6 @@ import type { OptionSelectItem } from "#app/ui/abstact-option-select-ui-handler"
import { UiMode } from "#enums/ui-mode"; import { UiMode } from "#enums/ui-mode";
import { BattlePhase } from "./battle-phase"; import { BattlePhase } from "./battle-phase";
import { randSeedInt } from "#app/utils/common"; import { randSeedInt } from "#app/utils/common";
import { PartyHealPhase } from "./party-heal-phase";
import { SwitchBiomePhase } from "./switch-biome-phase";
export class SelectBiomePhase extends BattlePhase { export class SelectBiomePhase extends BattlePhase {
public readonly phaseName = "SelectBiomePhase"; public readonly phaseName = "SelectBiomePhase";
@ -22,9 +20,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.phaseManager.unshiftPhase(new PartyHealPhase(false)); globalScene.phaseManager.unshiftNew("PartyHealPhase", false);
} }
globalScene.phaseManager.unshiftPhase(new SwitchBiomePhase(nextBiome)); globalScene.phaseManager.unshiftNew("SwitchBiomePhase", nextBiome);
this.end(); this.end();
}; };

View File

@ -123,11 +123,10 @@ export class SelectModifierPhase extends BattlePhase {
return false; return false;
} }
globalScene.reroll = true; globalScene.reroll = true;
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new SelectModifierPhase( "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[],
),
); );
globalScene.ui.clearText(); globalScene.ui.clearText();
globalScene.ui.setMode(UiMode.MESSAGE).then(() => super.end()); globalScene.ui.setMode(UiMode.MESSAGE).then(() => super.end());
@ -419,7 +418,8 @@ export class SelectModifierPhase extends BattlePhase {
} }
copy(): SelectModifierPhase { copy(): SelectModifierPhase {
return new SelectModifierPhase( return globalScene.phaseManager.create(
"SelectModifierPhase",
this.rerollCount, this.rerollCount,
this.modifierTiers, this.modifierTiers,
{ {

View File

@ -6,7 +6,6 @@ import { getPokemonSpecies } from "#app/data/pokemon-species";
import { overrideHeldItems, overrideModifiers } from "#app/modifier/modifier"; import { overrideHeldItems, overrideModifiers } from "#app/modifier/modifier";
import Overrides from "#app/overrides"; import Overrides from "#app/overrides";
import { Phase } from "#app/phase"; import { Phase } from "#app/phase";
import { TitlePhase } from "#app/phases/title-phase";
import { SaveSlotUiMode } from "#app/ui/save-slot-select-ui-handler"; import { SaveSlotUiMode } from "#app/ui/save-slot-select-ui-handler";
import type { Starter } from "#app/ui/starter-select-ui-handler"; import type { Starter } from "#app/ui/starter-select-ui-handler";
import { UiMode } from "#enums/ui-mode"; import { UiMode } from "#enums/ui-mode";
@ -26,7 +25,7 @@ export class SelectStarterPhase extends Phase {
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.phaseManager.clearPhaseQueue(); globalScene.phaseManager.clearPhaseQueue();
globalScene.phaseManager.pushPhase(new TitlePhase()); globalScene.phaseManager.pushNew("TitlePhase");
return this.end(); return this.end();
} }
globalScene.sessionSlotId = slotId; globalScene.sessionSlotId = slotId;

View File

@ -2,7 +2,6 @@ import { globalScene } from "#app/global-scene";
import type { BattlerIndex } from "#app/battle"; import type { BattlerIndex } from "#app/battle";
import { Command } from "#app/ui/command-ui-handler"; import { Command } from "#app/ui/command-ui-handler";
import { UiMode } from "#enums/ui-mode"; import { UiMode } from "#enums/ui-mode";
import { CommandPhase } from "./command-phase";
import { PokemonPhase } from "./pokemon-phase"; import { PokemonPhase } from "./pokemon-phase";
import i18next from "#app/plugins/i18n"; import i18next from "#app/plugins/i18n";
import { allMoves } from "#app/data/data-lists"; import { allMoves } from "#app/data/data-lists";
@ -33,7 +32,7 @@ export class SelectTargetPhase extends PokemonPhase {
} }
if (targets.length < 1) { if (targets.length < 1) {
globalScene.currentBattle.turnCommands[this.fieldIndex] = null; globalScene.currentBattle.turnCommands[this.fieldIndex] = null;
globalScene.phaseManager.unshiftPhase(new CommandPhase(this.fieldIndex)); globalScene.phaseManager.unshiftNew("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

@ -2,7 +2,6 @@ import { globalScene } from "#app/global-scene";
import type { BattlerIndex } from "#app/battle"; import type { BattlerIndex } from "#app/battle";
import { PokemonPhase } from "./pokemon-phase"; import { PokemonPhase } from "./pokemon-phase";
import { getPokemonNameWithAffix } from "#app/messages"; import { getPokemonNameWithAffix } from "#app/messages";
import { HideAbilityPhase } from "#app/phases/hide-ability-phase";
export class ShowAbilityPhase extends PokemonPhase { export class ShowAbilityPhase extends PokemonPhase {
public readonly phaseName = "ShowAbilityPhase"; public readonly phaseName = "ShowAbilityPhase";
@ -36,8 +35,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.phaseManager.unshiftPhase(new HideAbilityPhase()); globalScene.phaseManager.unshiftNew("HideAbilityPhase");
globalScene.phaseManager.unshiftPhase(new ShowAbilityPhase(this.battlerIndex, this.passive)); globalScene.phaseManager.unshiftNew("ShowAbilityPhase", this.battlerIndex, this.passive);
return this.end(); return this.end();
} }

View File

@ -3,8 +3,6 @@ import { ExpGainsSpeed } from "#app/enums/exp-gains-speed";
import { ExpNotification } from "#app/enums/exp-notification"; import { ExpNotification } from "#app/enums/exp-notification";
import { ExpBoosterModifier } from "#app/modifier/modifier"; import { ExpBoosterModifier } from "#app/modifier/modifier";
import { NumberHolder } from "#app/utils/common"; import { NumberHolder } from "#app/utils/common";
import { HidePartyExpBarPhase } from "./hide-party-exp-bar-phase";
import { LevelUpPhase } from "./level-up-phase";
import { PlayerPartyMemberPokemonPhase } from "./player-party-member-pokemon-phase"; import { PlayerPartyMemberPokemonPhase } from "./player-party-member-pokemon-phase";
export class ShowPartyExpBarPhase extends PlayerPartyMemberPokemonPhase { export class ShowPartyExpBarPhase extends PlayerPartyMemberPokemonPhase {
@ -29,9 +27,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.phaseManager.unshiftPhase(new LevelUpPhase(this.partyMemberIndex, lastLevel, newLevel)); globalScene.phaseManager.unshiftNew("LevelUpPhase", this.partyMemberIndex, lastLevel, newLevel);
} }
globalScene.phaseManager.unshiftPhase(new HidePartyExpBarPhase()); globalScene.phaseManager.unshiftNew("HidePartyExpBarPhase");
pokemon.updateInfo(); pokemon.updateInfo();
if (globalScene.expParty === ExpNotification.SKIP) { if (globalScene.expParty === ExpNotification.SKIP) {

View File

@ -72,8 +72,8 @@ 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new StatStageChangePhase( "StatStageChangePhase",
this.battlerIndex, this.battlerIndex,
this.selfTarget, this.selfTarget,
stat, stat,
@ -83,7 +83,6 @@ export class StatStageChangePhase extends PokemonPhase {
this.canBeCopied, this.canBeCopied,
this.onChange, this.onChange,
this.comingFromMirrorArmorUser, this.comingFromMirrorArmorUser,
),
); );
} }
return this.end(); return this.end();

View File

@ -9,9 +9,6 @@ import { FieldPosition } from "#app/field/pokemon";
import { getPokemonNameWithAffix } from "#app/messages"; import { getPokemonNameWithAffix } from "#app/messages";
import i18next from "i18next"; import i18next from "i18next";
import { PartyMemberPokemonPhase } from "./party-member-pokemon-phase"; import { PartyMemberPokemonPhase } from "./party-member-pokemon-phase";
import { PostSummonPhase } from "./post-summon-phase";
import { GameOverPhase } from "./game-over-phase";
import { ShinySparklePhase } from "./shiny-sparkle-phase";
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode"; import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
import { applyPreSummonAbAttrs, PreSummonAbAttr } from "#app/data/abilities/ability"; import { applyPreSummonAbAttrs, PreSummonAbAttr } from "#app/data/abilities/ability";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
@ -58,7 +55,7 @@ export class SummonPhase extends PartyMemberPokemonPhase {
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.phaseManager.clearPhaseQueue(); globalScene.phaseManager.clearPhaseQueue();
globalScene.phaseManager.unshiftPhase(new GameOverPhase()); globalScene.phaseManager.unshiftNew("GameOverPhase");
this.end(); this.end();
return; return;
} }
@ -275,7 +272,7 @@ export class SummonPhase extends PartyMemberPokemonPhase {
const pokemon = this.getPokemon(); const pokemon = this.getPokemon();
if (pokemon.isShiny(true)) { if (pokemon.isShiny(true)) {
globalScene.phaseManager.unshiftPhase(new ShinySparklePhase(pokemon.getBattlerIndex())); globalScene.phaseManager.unshiftNew("ShinySparklePhase", pokemon.getBattlerIndex());
} }
pokemon.resetTurnData(); pokemon.resetTurnData();
@ -291,7 +288,7 @@ export class SummonPhase extends PartyMemberPokemonPhase {
} }
queuePostSummon(): void { queuePostSummon(): void {
globalScene.phaseManager.pushPhase(new PostSummonPhase(this.getPokemon().getBattlerIndex())); globalScene.phaseManager.pushNew("PostSummonPhase", this.getPokemon().getBattlerIndex());
} }
end() { end() {

View File

@ -3,7 +3,6 @@ import PartyUiHandler, { PartyOption, PartyUiMode } from "#app/ui/party-ui-handl
import { UiMode } from "#enums/ui-mode"; import { UiMode } from "#enums/ui-mode";
import { SwitchType } from "#enums/switch-type"; import { SwitchType } from "#enums/switch-type";
import { BattlePhase } from "./battle-phase"; import { BattlePhase } from "./battle-phase";
import { SwitchSummonPhase } from "./switch-summon-phase";
/** /**
* Opens the party selector UI and transitions into a {@linkcode SwitchSummonPhase} * Opens the party selector UI and transitions into a {@linkcode SwitchSummonPhase}
@ -80,9 +79,7 @@ export class SwitchPhase extends BattlePhase {
p => p.is("PostSummonPhase") && p.player && p.fieldIndex === this.fieldIndex, 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew("SwitchSummonPhase", switchType, fieldIndex, slotIndex, this.doReturn);
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

@ -16,7 +16,6 @@ import { getPokemonNameWithAffix } from "#app/messages";
import { SwitchEffectTransferModifier } from "#app/modifier/modifier"; import { SwitchEffectTransferModifier } from "#app/modifier/modifier";
import { Command } from "#app/ui/command-ui-handler"; import { Command } from "#app/ui/command-ui-handler";
import i18next from "i18next"; import i18next from "i18next";
import { PostSummonPhase } from "./post-summon-phase";
import { SummonPhase } from "./summon-phase"; import { SummonPhase } from "./summon-phase";
import { SubstituteTag } from "#app/data/battler-tags"; import { SubstituteTag } from "#app/data/battler-tags";
import { SwitchType } from "#enums/switch-type"; import { SwitchType } from "#enums/switch-type";
@ -265,6 +264,6 @@ export class SwitchSummonPhase extends SummonPhase {
} }
queuePostSummon(): void { queuePostSummon(): void {
globalScene.phaseManager.unshiftPhase(new PostSummonPhase(this.getPokemon().getBattlerIndex())); globalScene.phaseManager.unshiftNew("PostSummonPhase", this.getPokemon().getBattlerIndex());
} }
} }

View File

@ -20,11 +20,6 @@ import { SaveSlotUiMode } from "#app/ui/save-slot-select-ui-handler";
import { UiMode } from "#enums/ui-mode"; import { UiMode } from "#enums/ui-mode";
import { isLocal, isLocalServerConnected, isNullOrUndefined } from "#app/utils/common"; import { isLocal, isLocalServerConnected, isNullOrUndefined } from "#app/utils/common";
import i18next from "i18next"; import i18next from "i18next";
import { CheckSwitchPhase } from "./check-switch-phase";
import { EncounterPhase } from "./encounter-phase";
import { SelectChallengePhase } from "./select-challenge-phase";
import { SelectStarterPhase } from "./select-starter-phase";
import { SummonPhase } from "./summon-phase";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import Overrides from "#app/overrides"; import Overrides from "#app/overrides";
@ -125,7 +120,7 @@ export class TitlePhase extends Phase {
label: i18next.t("menu:cancel"), label: i18next.t("menu:cancel"),
handler: () => { handler: () => {
globalScene.phaseManager.clearPhaseQueue(); globalScene.phaseManager.clearPhaseQueue();
globalScene.phaseManager.pushPhase(new TitlePhase()); globalScene.phaseManager.pushNew("TitlePhase");
super.end(); super.end();
return true; return true;
}, },
@ -200,7 +195,7 @@ export class TitlePhase extends Phase {
globalScene.ui.setMode(UiMode.SAVE_SLOT, SaveSlotUiMode.SAVE, (slotId: number) => { globalScene.ui.setMode(UiMode.SAVE_SLOT, SaveSlotUiMode.SAVE, (slotId: number) => {
globalScene.phaseManager.clearPhaseQueue(); globalScene.phaseManager.clearPhaseQueue();
if (slotId === -1) { if (slotId === -1) {
globalScene.phaseManager.pushPhase(new TitlePhase()); globalScene.phaseManager.pushNew("TitlePhase");
return super.end(); return super.end();
} }
globalScene.sessionSlotId = slotId; globalScene.sessionSlotId = slotId;
@ -304,23 +299,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.phaseManager.pushPhase(new SelectChallengePhase()); globalScene.phaseManager.pushNew("SelectChallengePhase");
} else { } else {
globalScene.phaseManager.pushPhase(new SelectStarterPhase()); globalScene.phaseManager.pushNew("SelectStarterPhase");
} }
globalScene.newArena(globalScene.gameMode.getStartingBiome()); globalScene.newArena(globalScene.gameMode.getStartingBiome());
} else { } else {
globalScene.playBgm(); globalScene.playBgm();
} }
globalScene.phaseManager.pushPhase(new EncounterPhase(this.loaded)); globalScene.phaseManager.pushNew("EncounterPhase", this.loaded);
if (this.loaded) { if (this.loaded) {
const availablePartyMembers = globalScene.getPokemonAllowedInBattle().length; const availablePartyMembers = globalScene.getPokemonAllowedInBattle().length;
globalScene.phaseManager.pushPhase(new SummonPhase(0, true, true)); globalScene.phaseManager.pushNew("SummonPhase", 0, true, true);
if (globalScene.currentBattle.double && availablePartyMembers > 1) { if (globalScene.currentBattle.double && availablePartyMembers > 1) {
globalScene.phaseManager.pushPhase(new SummonPhase(1, true, true)); globalScene.phaseManager.pushNew("SummonPhase", 1, true, true);
} }
if ( if (
@ -329,9 +324,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.phaseManager.pushPhase(new CheckSwitchPhase(0, globalScene.currentBattle.double)); globalScene.phaseManager.pushNew("CheckSwitchPhase", 0, globalScene.currentBattle.double);
if (globalScene.currentBattle.double) { if (globalScene.currentBattle.double) {
globalScene.phaseManager.pushPhase(new CheckSwitchPhase(1, globalScene.currentBattle.double)); globalScene.phaseManager.pushNew("CheckSwitchPhase", 1, globalScene.currentBattle.double);
} }
} }
} }

View File

@ -5,8 +5,6 @@ import { vouchers } from "#app/system/voucher";
import i18next from "i18next"; import i18next from "i18next";
import { randSeedItem } from "#app/utils/common"; import { randSeedItem } from "#app/utils/common";
import { BattlePhase } from "./battle-phase"; import { BattlePhase } from "./battle-phase";
import { ModifierRewardPhase } from "./modifier-reward-phase";
import { MoneyRewardPhase } from "./money-reward-phase";
import { TrainerSlot } from "#enums/trainer-slot"; import { TrainerSlot } from "#enums/trainer-slot";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import { BiomeId } from "#enums/biome-id"; import { BiomeId } from "#enums/biome-id";
@ -20,13 +18,11 @@ export class TrainerVictoryPhase extends BattlePhase {
globalScene.playBgm(globalScene.currentBattle.trainer?.config.victoryBgm); globalScene.playBgm(globalScene.currentBattle.trainer?.config.victoryBgm);
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew("MoneyRewardPhase", globalScene.currentBattle.trainer?.config.moneyMultiplier!); // TODO: is this bang correct?
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.phaseManager.unshiftPhase(new ModifierRewardPhase(modifierRewardFunc)); globalScene.phaseManager.unshiftNew("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?
@ -37,23 +33,21 @@ export class TrainerVictoryPhase extends BattlePhase {
globalScene.currentBattle.trainer?.config.isBoss globalScene.currentBattle.trainer?.config.isBoss
) { ) {
if (timedEventManager.getUpgradeUnlockedVouchers()) { if (timedEventManager.getUpgradeUnlockedVouchers()) {
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new ModifierRewardPhase( "ModifierRewardPhase",
[ [
modifierTypes.VOUCHER_PLUS, modifierTypes.VOUCHER_PLUS,
modifierTypes.VOUCHER_PLUS, modifierTypes.VOUCHER_PLUS,
modifierTypes.VOUCHER_PLUS, modifierTypes.VOUCHER_PLUS,
modifierTypes.VOUCHER_PREMIUM, modifierTypes.VOUCHER_PREMIUM,
][vouchers[TrainerType[trainerType]].voucherType], ][vouchers[TrainerType[trainerType]].voucherType],
),
); );
} else { } else {
globalScene.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new ModifierRewardPhase( "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

@ -14,7 +14,6 @@ import {
} from "#app/modifier/modifier"; } from "#app/modifier/modifier";
import i18next from "i18next"; import i18next from "i18next";
import { FieldPhase } from "./field-phase"; import { FieldPhase } from "./field-phase";
import { PokemonHealPhase } from "./pokemon-heal-phase";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
export class TurnEndPhase extends FieldPhase { export class TurnEndPhase extends FieldPhase {
@ -34,15 +33,14 @@ 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.phaseManager.unshiftPhase( globalScene.phaseManager.unshiftNew(
new PokemonHealPhase( "PokemonHealPhase",
pokemon.getBattlerIndex(), pokemon.getBattlerIndex(),
Math.max(pokemon.getMaxHp() >> 4, 1), Math.max(pokemon.getMaxHp() >> 4, 1),
i18next.t("battle:turnEndHpRestore", { i18next.t("battle:turnEndHpRestore", {
pokemonName: getPokemonNameWithAffix(pokemon), pokemonName: getPokemonNameWithAffix(pokemon),
}), }),
true, true,
),
); );
} }

View File

@ -6,12 +6,7 @@ import {
import { TurnInitEvent } from "#app/events/battle-scene"; import { TurnInitEvent } from "#app/events/battle-scene";
import type { PlayerPokemon } from "#app/field/pokemon"; import type { PlayerPokemon } from "#app/field/pokemon";
import i18next from "i18next"; import i18next from "i18next";
import { CommandPhase } from "./command-phase";
import { EnemyCommandPhase } from "./enemy-command-phase";
import { FieldPhase } from "./field-phase"; import { FieldPhase } from "./field-phase";
import { GameOverPhase } from "./game-over-phase";
import { ToggleDoublePositionPhase } from "./toggle-double-position-phase";
import { TurnStartPhase } from "./turn-start-phase";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
export class TurnInitPhase extends FieldPhase { export class TurnInitPhase extends FieldPhase {
@ -33,7 +28,7 @@ export class TurnInitPhase extends FieldPhase {
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.phaseManager.clearPhaseQueue(); globalScene.phaseManager.clearPhaseQueue();
globalScene.phaseManager.unshiftPhase(new GameOverPhase()); globalScene.phaseManager.unshiftNew("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))
@ -46,7 +41,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.phaseManager.unshiftPhase(new ToggleDoublePositionPhase(true)); globalScene.phaseManager.unshiftNew("ToggleDoublePositionPhase", true);
} }
} }
}); });
@ -69,13 +64,15 @@ export class TurnInitPhase extends FieldPhase {
pokemon.resetTurnData(); pokemon.resetTurnData();
globalScene.phaseManager.pushPhase( if (pokemon.isPlayer()) {
pokemon.isPlayer() ? new CommandPhase(i) : new EnemyCommandPhase(i - BattlerIndex.ENEMY), globalScene.phaseManager.pushNew("CommandPhase", i);
); } else {
globalScene.phaseManager.pushNew("EnemyCommandPhase", i - BattlerIndex.ENEMY);
}
} }
}); });
globalScene.phaseManager.pushPhase(new TurnStartPhase()); globalScene.phaseManager.pushNew("TurnStartPhase");
this.end(); this.end();
} }

View File

@ -8,21 +8,11 @@ import { PokemonMove } from "#app/field/pokemon";
import { BypassSpeedChanceModifier } from "#app/modifier/modifier"; import { BypassSpeedChanceModifier } from "#app/modifier/modifier";
import { Command } from "#app/ui/command-ui-handler"; import { Command } from "#app/ui/command-ui-handler";
import { randSeedShuffle, BooleanHolder } from "#app/utils/common"; import { randSeedShuffle, BooleanHolder } from "#app/utils/common";
import { AttemptCapturePhase } from "./attempt-capture-phase";
import { AttemptRunPhase } from "./attempt-run-phase";
import { BerryPhase } from "./berry-phase";
import { FieldPhase } from "./field-phase"; import { FieldPhase } from "./field-phase";
import { MoveHeaderPhase } from "./move-header-phase";
import { MovePhase } from "./move-phase";
import { SwitchSummonPhase } from "./switch-summon-phase";
import { TurnEndPhase } from "./turn-end-phase";
import { WeatherEffectPhase } from "./weather-effect-phase";
import { CheckStatusEffectPhase } from "#app/phases/check-status-effect-phase";
import { BattlerIndex } from "#app/battle"; import { BattlerIndex } from "#app/battle";
import { TrickRoomTag } from "#app/data/arena-tag"; import { TrickRoomTag } from "#app/data/arena-tag";
import { SwitchType } from "#enums/switch-type"; import { SwitchType } from "#enums/switch-type";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import { TeraPhase } from "./tera-phase";
export class TurnStartPhase extends FieldPhase { export class TurnStartPhase extends FieldPhase {
public readonly phaseName = "TurnStartPhase"; public readonly phaseName = "TurnStartPhase";
@ -153,10 +143,12 @@ export class TurnStartPhase extends FieldPhase {
switch (preTurnCommand?.command) { switch (preTurnCommand?.command) {
case Command.TERA: case Command.TERA:
globalScene.phaseManager.pushPhase(new TeraPhase(pokemon)); globalScene.phaseManager.pushNew("TeraPhase", pokemon);
} }
} }
const phaseManager = globalScene.phaseManager;
for (const o of moveOrder) { for (const o of moveOrder) {
const pokemon = field[o]; const pokemon = field[o];
const turnCommand = globalScene.currentBattle.turnCommands[o]; const turnCommand = globalScene.currentBattle.turnCommands[o];
@ -167,6 +159,7 @@ export class TurnStartPhase extends FieldPhase {
switch (turnCommand?.command) { switch (turnCommand?.command) {
case Command.FIGHT: case Command.FIGHT:
{
const queuedMove = turnCommand.move; const queuedMove = turnCommand.move;
pokemon.turnData.order = orderIndex++; pokemon.turnData.order = orderIndex++;
if (!queuedMove) { if (!queuedMove) {
@ -176,47 +169,51 @@ 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.phaseManager.unshiftPhase(new MoveHeaderPhase(pokemon, move)); phaseManager.unshiftNew("MoveHeaderPhase", pokemon, move);
} }
if (pokemon.isPlayer()) { if (pokemon.isPlayer()) {
if (turnCommand.cursor === -1) { if (turnCommand.cursor === -1) {
globalScene.phaseManager.pushPhase( phaseManager.pushNew("MovePhase", pokemon, turnCommand.targets || turnCommand.move!.targets, move);
new MovePhase(pokemon, turnCommand.targets || turnCommand.move!.targets, move),
); //TODO: is the bang correct here?
} else { } else {
const playerPhase = new MovePhase( phaseManager.pushNew(
"MovePhase",
pokemon, pokemon,
turnCommand.targets || turnCommand.move!.targets, turnCommand.targets || turnCommand.move!.targets, // TODO: is the bang correct here?
move, move,
false, false,
queuedMove.ignorePP, queuedMove.ignorePP,
); //TODO: is the bang correct here? );
globalScene.phaseManager.pushPhase(playerPhase);
} }
} else { } else {
globalScene.phaseManager.pushPhase( phaseManager.pushNew(
new MovePhase( "MovePhase",
pokemon, pokemon,
turnCommand.targets || turnCommand.move!.targets, turnCommand.targets || turnCommand.move!.targets,
move, move,
false, false,
queuedMove.ignorePP, queuedMove.ignorePP,
), );
); //TODO: is the bang correct here? }
} }
break; break;
case Command.BALL: case Command.BALL:
globalScene.phaseManager.unshiftPhase( phaseManager.unshiftNew("AttemptCapturePhase", turnCommand.targets![0] % 2, turnCommand.cursor!); //TODO: is the bang correct here?
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.phaseManager.unshiftPhase( phaseManager.unshiftNew(
new SwitchSummonPhase(switchType, pokemon.getFieldIndex(), turnCommand.cursor!, true, pokemon.isPlayer()), "SwitchSummonPhase",
switchType,
pokemon.getFieldIndex(),
turnCommand.cursor!,
true,
pokemon.isPlayer(),
); );
}
break; break;
case Command.RUN: case Command.RUN:
{
let runningPokemon = pokemon; let runningPokemon = pokemon;
if (globalScene.currentBattle.double) { if (globalScene.currentBattle.double) {
const playerActivePokemon = field.filter(pokemon => { const playerActivePokemon = field.filter(pokemon => {
@ -237,18 +234,19 @@ export class TurnStartPhase extends FieldPhase {
runningPokemon = hasRunAway !== undefined ? hasRunAway : fasterPokemon; runningPokemon = hasRunAway !== undefined ? hasRunAway : fasterPokemon;
} }
} }
globalScene.phaseManager.unshiftPhase(new AttemptRunPhase(runningPokemon.getFieldIndex())); phaseManager.unshiftNew("AttemptRunPhase", runningPokemon.getFieldIndex());
}
break; break;
} }
} }
globalScene.phaseManager.pushPhase(new WeatherEffectPhase()); phaseManager.pushNew("WeatherEffectPhase");
globalScene.phaseManager.pushPhase(new BerryPhase()); phaseManager.pushNew("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.phaseManager.pushPhase(new CheckStatusEffectPhase(moveOrder)); phaseManager.pushNew("CheckStatusEffectPhase", moveOrder);
globalScene.phaseManager.pushPhase(new TurnEndPhase()); phaseManager.pushNew("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

@ -1,13 +1,12 @@
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import { Phase } from "#app/phase"; import { Phase } from "#app/phase";
import { UiMode } from "#enums/ui-mode"; import { UiMode } from "#enums/ui-mode";
import { LoginPhase } from "./login-phase";
export class UnavailablePhase extends Phase { 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.phaseManager.unshiftPhase(new LoginPhase(true)); globalScene.phaseManager.unshiftNew("LoginPhase", true);
this.end(); this.end();
}); });
} }

View File

@ -3,19 +3,10 @@ import { ClassicFixedBossWaves } from "#enums/fixed-boss-waves";
import { BattleType } from "#enums/battle-type"; import { BattleType } from "#enums/battle-type";
import type { CustomModifierSettings } from "#app/modifier/modifier-type"; import type { CustomModifierSettings } from "#app/modifier/modifier-type";
import { modifierTypes } from "#app/modifier/modifier-type"; import { modifierTypes } from "#app/modifier/modifier-type";
import { BattleEndPhase } from "./battle-end-phase";
import { NewBattlePhase } from "./new-battle-phase";
import { PokemonPhase } from "./pokemon-phase"; import { PokemonPhase } from "./pokemon-phase";
import { AddEnemyBuffModifierPhase } from "./add-enemy-buff-modifier-phase";
import { EggLapsePhase } from "./egg-lapse-phase";
import { GameOverPhase } from "./game-over-phase";
import { ModifierRewardPhase } from "./modifier-reward-phase";
import { SelectModifierPhase } from "./select-modifier-phase";
import { TrainerVictoryPhase } from "./trainer-victory-phase";
import { handleMysteryEncounterVictory } from "#app/data/mystery-encounters/utils/encounter-phase-utils"; import { handleMysteryEncounterVictory } from "#app/data/mystery-encounters/utils/encounter-phase-utils";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import { timedEventManager } from "#app/global-event-manager"; import { timedEventManager } from "#app/global-event-manager";
import { SelectBiomePhase } from "./select-biome-phase";
export class VictoryPhase extends PokemonPhase { export class VictoryPhase extends PokemonPhase {
public readonly phaseName = "VictoryPhase"; public readonly phaseName = "VictoryPhase";
@ -51,12 +42,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.phaseManager.pushPhase(new BattleEndPhase(true)); globalScene.phaseManager.pushNew("BattleEndPhase", true);
if (globalScene.currentBattle.battleType === BattleType.TRAINER) { if (globalScene.currentBattle.battleType === BattleType.TRAINER) {
globalScene.phaseManager.pushPhase(new TrainerVictoryPhase()); globalScene.phaseManager.pushNew("TrainerVictoryPhase");
} }
if (globalScene.gameMode.isEndless || !globalScene.gameMode.isWaveFinal(globalScene.currentBattle.waveIndex)) { if (globalScene.gameMode.isEndless || !globalScene.gameMode.isWaveFinal(globalScene.currentBattle.waveIndex)) {
globalScene.phaseManager.pushPhase(new EggLapsePhase()); globalScene.phaseManager.pushNew("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,68 +55,67 @@ 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.phaseManager.pushPhase(new ModifierRewardPhase(modifierTypes[r]))); .map(r => globalScene.phaseManager.pushNew("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.phaseManager.pushPhase(new ModifierRewardPhase(modifierTypes.LOCK_CAPSULE)); globalScene.phaseManager.pushNew("ModifierRewardPhase", modifierTypes.LOCK_CAPSULE);
break; break;
} }
} }
if (globalScene.currentBattle.waveIndex % 10) { if (globalScene.currentBattle.waveIndex % 10) {
globalScene.phaseManager.pushPhase( globalScene.phaseManager.pushNew(
new SelectModifierPhase(undefined, undefined, this.getFixedBattleCustomModifiers()), "SelectModifierPhase",
undefined,
undefined,
this.getFixedBattleCustomModifiers(),
); );
} else if (globalScene.gameMode.isDaily) { } else if (globalScene.gameMode.isDaily) {
globalScene.phaseManager.pushPhase(new ModifierRewardPhase(modifierTypes.EXP_CHARM)); globalScene.phaseManager.pushNew("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.phaseManager.pushPhase(new ModifierRewardPhase(modifierTypes.GOLDEN_POKEBALL)); globalScene.phaseManager.pushNew("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.phaseManager.pushPhase(new ModifierRewardPhase(modifierTypes.EXP_SHARE)); globalScene.phaseManager.pushNew("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.phaseManager.pushPhase( globalScene.phaseManager.pushNew(
new ModifierRewardPhase( "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
: modifierTypes.SUPER_EXP_CHARM, : modifierTypes.SUPER_EXP_CHARM,
),
); );
} }
if (globalScene.currentBattle.waveIndex <= 150 && !(globalScene.currentBattle.waveIndex % 50)) { if (globalScene.currentBattle.waveIndex <= 150 && !(globalScene.currentBattle.waveIndex % 50)) {
globalScene.phaseManager.pushPhase(new ModifierRewardPhase(modifierTypes.GOLDEN_POKEBALL)); globalScene.phaseManager.pushNew("ModifierRewardPhase", modifierTypes.GOLDEN_POKEBALL);
} }
if (globalScene.gameMode.isEndless && !(globalScene.currentBattle.waveIndex % 50)) { if (globalScene.gameMode.isEndless && !(globalScene.currentBattle.waveIndex % 50)) {
globalScene.phaseManager.pushPhase( globalScene.phaseManager.pushNew(
new ModifierRewardPhase( "ModifierRewardPhase",
!(globalScene.currentBattle.waveIndex % 250) !(globalScene.currentBattle.waveIndex % 250) ? modifierTypes.VOUCHER_PREMIUM : modifierTypes.VOUCHER_PLUS,
? modifierTypes.VOUCHER_PREMIUM
: modifierTypes.VOUCHER_PLUS,
),
); );
globalScene.phaseManager.pushPhase(new AddEnemyBuffModifierPhase()); globalScene.phaseManager.pushNew("AddEnemyBuffModifierPhase");
} }
} }
if (globalScene.gameMode.hasRandomBiomes || globalScene.isNewBiome()) { if (globalScene.gameMode.hasRandomBiomes || globalScene.isNewBiome()) {
globalScene.phaseManager.pushPhase(new SelectBiomePhase()); globalScene.phaseManager.pushNew("SelectBiomePhase");
} }
globalScene.phaseManager.pushPhase(new NewBattlePhase()); globalScene.phaseManager.pushNew("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.phaseManager.pushPhase(new GameOverPhase(true)); globalScene.phaseManager.pushNew("GameOverPhase", true);
} }
} }

View File

@ -49,7 +49,6 @@ import { SpeciesId } from "#enums/species-id";
import { applyChallenges, ChallengeType } from "#app/data/challenge"; import { applyChallenges, ChallengeType } from "#app/data/challenge";
import { WeatherType } from "#enums/weather-type"; import { WeatherType } from "#enums/weather-type";
import { TerrainType } from "#app/data/terrain"; import { TerrainType } from "#app/data/terrain";
import { ReloadSessionPhase } from "#app/phases/reload-session-phase";
import { RUN_HISTORY_LIMIT } from "#app/ui/run-history-ui-handler"; import { RUN_HISTORY_LIMIT } from "#app/ui/run-history-ui-handler";
import { import {
applySessionVersionMigration, applySessionVersionMigration,
@ -427,7 +426,7 @@ export class GameData {
if (error) { if (error) {
if (error.startsWith("session out of date")) { if (error.startsWith("session out of date")) {
globalScene.phaseManager.clearPhaseQueue(); globalScene.phaseManager.clearPhaseQueue();
globalScene.phaseManager.unshiftPhase(new ReloadSessionPhase()); globalScene.phaseManager.unshiftNew("ReloadSessionPhase");
} }
console.error(error); console.error(error);
return resolve(false); return resolve(false);
@ -747,7 +746,7 @@ export class GameData {
if (systemData) { if (systemData) {
globalScene.phaseManager.clearPhaseQueue(); globalScene.phaseManager.clearPhaseQueue();
globalScene.phaseManager.unshiftPhase(new ReloadSessionPhase(JSON.stringify(systemData))); globalScene.phaseManager.unshiftNew("ReloadSessionPhase", JSON.stringify(systemData));
this.clearLocalData(); this.clearLocalData();
return false; return false;
} }
@ -1249,7 +1248,7 @@ export class GameData {
if (error) { if (error) {
if (error.startsWith("session out of date")) { if (error.startsWith("session out of date")) {
globalScene.phaseManager.clearPhaseQueue(); globalScene.phaseManager.clearPhaseQueue();
globalScene.phaseManager.unshiftPhase(new ReloadSessionPhase()); globalScene.phaseManager.unshiftNew("ReloadSessionPhase");
} }
console.error(error); console.error(error);
resolve(false); resolve(false);
@ -1321,7 +1320,7 @@ export class GameData {
} else { } else {
if (jsonResponse?.error?.startsWith("session out of date")) { if (jsonResponse?.error?.startsWith("session out of date")) {
globalScene.phaseManager.clearPhaseQueue(); globalScene.phaseManager.clearPhaseQueue();
globalScene.phaseManager.unshiftPhase(new ReloadSessionPhase()); globalScene.phaseManager.unshiftNew("ReloadSessionPhase");
} }
console.error(jsonResponse); console.error(jsonResponse);
@ -1459,7 +1458,7 @@ export class GameData {
if (error) { if (error) {
if (error.startsWith("session out of date")) { if (error.startsWith("session out of date")) {
globalScene.phaseManager.clearPhaseQueue(); globalScene.phaseManager.clearPhaseQueue();
globalScene.phaseManager.unshiftPhase(new ReloadSessionPhase()); globalScene.phaseManager.unshiftNew("ReloadSessionPhase");
} }
console.error(error); console.error(error);
return resolve(false); return resolve(false);

View File

@ -9,8 +9,6 @@ import { getLocalizedSpriteKey } from "#app/utils/common";
import { Challenges } from "#app/enums/challenges"; import { Challenges } from "#app/enums/challenges";
import BBCodeText from "phaser3-rex-plugins/plugins/bbcodetext"; import BBCodeText from "phaser3-rex-plugins/plugins/bbcodetext";
import { Color, ShadowColor } from "#app/enums/color"; import { Color, ShadowColor } from "#app/enums/color";
import { SelectStarterPhase } from "#app/phases/select-starter-phase";
import { TitlePhase } from "#app/phases/title-phase";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
/** /**
@ -384,14 +382,14 @@ export default class GameChallengesUiHandler extends UiHandler {
this.updateChallengeArrows(this.startCursor.visible); this.updateChallengeArrows(this.startCursor.visible);
} else { } else {
globalScene.phaseManager.clearPhaseQueue(); globalScene.phaseManager.clearPhaseQueue();
globalScene.phaseManager.pushPhase(new TitlePhase()); globalScene.phaseManager.pushNew("TitlePhase");
globalScene.phaseManager.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.phaseManager.unshiftPhase(new SelectStarterPhase()); globalScene.phaseManager.unshiftNew("SelectStarterPhase");
globalScene.phaseManager.getCurrentPhase()?.end(); globalScene.phaseManager.getCurrentPhase()?.end();
} else { } else {
this.startCursor.setVisible(true); this.startCursor.setVisible(true);

View File

@ -51,9 +51,6 @@ import { StarterContainer } from "#app/ui/starter-container";
import { FilterBar } from "#app/ui/filter-bar"; import { FilterBar } from "#app/ui/filter-bar";
import { DropDownColumn } from "#enums/drop-down-column"; import { DropDownColumn } from "#enums/drop-down-column";
import { ScrollBar } from "#app/ui/scroll-bar"; import { ScrollBar } from "#app/ui/scroll-bar";
import { SelectChallengePhase } from "#app/phases/select-challenge-phase";
import { EncounterPhase } from "#app/phases/encounter-phase";
import { TitlePhase } from "#app/phases/title-phase";
import { AbilityId } from "#enums/ability-id"; import { AbilityId } from "#enums/ability-id";
import { import {
getPassiveCandyCount, getPassiveCandyCount,
@ -4307,10 +4304,10 @@ export default class StarterSelectUiHandler extends MessageUiHandler {
ui.setMode(UiMode.STARTER_SELECT); ui.setMode(UiMode.STARTER_SELECT);
globalScene.phaseManager.clearPhaseQueue(); globalScene.phaseManager.clearPhaseQueue();
if (globalScene.gameMode.isChallenge) { if (globalScene.gameMode.isChallenge) {
globalScene.phaseManager.pushPhase(new SelectChallengePhase()); globalScene.phaseManager.pushNew("SelectChallengePhase");
globalScene.phaseManager.pushPhase(new EncounterPhase()); globalScene.phaseManager.pushNew("EncounterPhase");
} else { } else {
globalScene.phaseManager.pushPhase(new TitlePhase()); globalScene.phaseManager.pushNew("TitlePhase");
} }
this.clearText(); this.clearText();
globalScene.phaseManager.getCurrentPhase()?.end(); globalScene.phaseManager.getCurrentPhase()?.end();

View File

@ -105,8 +105,8 @@ export default class GameManager {
// Must be run after phase interceptor has been initialized. // Must be run after phase interceptor has been initialized.
this.scene.phaseManager.pushPhase(new LoginPhase()); this.scene.phaseManager.pushNew("LoginPhase");
this.scene.phaseManager.pushPhase(new TitlePhase()); this.scene.phaseManager.pushNew("TitlePhase");
this.scene.phaseManager.shiftPhase(); this.scene.phaseManager.shiftPhase();
this.gameWrapper.scene = this.scene; this.gameWrapper.scene = this.scene;