mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-06-27 20:13:00 +02:00
605 lines
20 KiB
TypeScript
605 lines
20 KiB
TypeScript
import { globalScene } from "#app/global-scene";
|
|
import type { TurnCommand } from "#app/battle";
|
|
import { BattleType } from "#enums/battle-type";
|
|
import { TrappedTag } from "#app/data/battler-tags";
|
|
import type { MoveTargetSet } from "#app/data/moves/move";
|
|
import { getMoveTargets } from "#app/data/moves/move-utils";
|
|
import { speciesStarterCosts } from "#app/data/balance/starters";
|
|
import { AbilityId } from "#enums/ability-id";
|
|
import { BattlerTagType } from "#app/enums/battler-tag-type";
|
|
import { BiomeId } from "#enums/biome-id";
|
|
import { MoveId } from "#enums/move-id";
|
|
import { PokeballType } from "#enums/pokeball";
|
|
import type { PlayerPokemon, TurnMove } from "#app/field/pokemon";
|
|
import { FieldPosition } from "#enums/field-position";
|
|
import { getPokemonNameWithAffix } from "#app/messages";
|
|
import { Command } from "#enums/command";
|
|
import { UiMode } from "#enums/ui-mode";
|
|
import i18next from "i18next";
|
|
import { FieldPhase } from "./field-phase";
|
|
import { MysteryEncounterMode } from "#enums/mystery-encounter-mode";
|
|
import { ArenaTagSide } from "#enums/arena-tag-side";
|
|
import { ArenaTagType } from "#app/enums/arena-tag-type";
|
|
import { isVirtual, isIgnorePP, MoveUseMode } from "#enums/move-use-mode";
|
|
|
|
export class CommandPhase extends FieldPhase {
|
|
public readonly phaseName = "CommandPhase";
|
|
protected fieldIndex: number;
|
|
|
|
/**
|
|
* Whether the command phase is handling a switch command
|
|
*/
|
|
private isSwitch = false;
|
|
|
|
constructor(fieldIndex: number) {
|
|
super();
|
|
|
|
this.fieldIndex = fieldIndex;
|
|
}
|
|
|
|
/**
|
|
* Resets the cursor to the position of {@linkcode Command.FIGHT} if any of the following are true
|
|
* - The setting to remember the last action is not enabled
|
|
* - This is the first turn of a mystery encounter, trainer battle, or the END biome
|
|
* - The cursor is currently on the POKEMON command
|
|
*/
|
|
private resetCursorIfNeeded() {
|
|
const commandUiHandler = globalScene.ui.handlers[UiMode.COMMAND];
|
|
|
|
// If one of these conditions is true, we always reset the cursor to Command.FIGHT
|
|
const cursorResetEvent =
|
|
globalScene.currentBattle.battleType === BattleType.MYSTERY_ENCOUNTER ||
|
|
globalScene.currentBattle.battleType === BattleType.TRAINER ||
|
|
globalScene.arena.biomeType === BiomeId.END;
|
|
|
|
if (
|
|
(commandUiHandler &&
|
|
globalScene.currentBattle.turn === 1 &&
|
|
(!globalScene.commandCursorMemory || cursorResetEvent)) ||
|
|
commandUiHandler.getCursor() === Command.POKEMON
|
|
) {
|
|
commandUiHandler.setCursor(Command.FIGHT);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Submethod of {@linkcode start} that validates field index logic for nonzero field indices.
|
|
* Must only be called if the field index is nonzero.
|
|
*/
|
|
private handleFieldIndexLogic() {
|
|
// If we somehow are attempting to check the right pokemon but there's only one pokemon out
|
|
// Switch back to the center pokemon. This can happen rarely in double battles with mid turn switching
|
|
// TODO: Prevent this from happening in the first place
|
|
if (globalScene.getPlayerField().filter(p => p.isActive()).length === 1) {
|
|
this.fieldIndex = FieldPosition.CENTER;
|
|
return;
|
|
}
|
|
|
|
const allyCommand = globalScene.currentBattle.turnCommands[this.fieldIndex - 1];
|
|
if (allyCommand?.command === Command.BALL || allyCommand?.command === Command.RUN) {
|
|
globalScene.currentBattle.turnCommands[this.fieldIndex] = {
|
|
command: allyCommand?.command,
|
|
skip: true,
|
|
};
|
|
}
|
|
}
|
|
|
|
/** Submethod of {@linkcode start} that sets the turn command to skip if this pokemon is commanding its ally
|
|
* via {@linkcode Abilities.COMMANDER}.
|
|
*/
|
|
private checkCommander() {
|
|
// If the Pokemon has applied Commander's effects to its ally, skip this command
|
|
if (
|
|
globalScene.currentBattle?.double &&
|
|
this.getPokemon().getAlly()?.getTag(BattlerTagType.COMMANDED)?.getSourcePokemon() === this.getPokemon()
|
|
) {
|
|
globalScene.currentBattle.turnCommands[this.fieldIndex] = {
|
|
command: Command.FIGHT,
|
|
move: { move: MoveId.NONE, targets: [], useMode: MoveUseMode.NORMAL },
|
|
skip: true,
|
|
};
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Clear out all unusable moves in front of the currently acting pokemon's move queue.
|
|
* TODO: Refactor move queue handling to ensure that this method is not necessary.
|
|
*/
|
|
private clearUnusuableMoves() {
|
|
const playerPokemon = this.getPokemon();
|
|
const moveQueue = playerPokemon.getMoveQueue();
|
|
if (moveQueue.length === 0) {
|
|
return;
|
|
}
|
|
|
|
let entriesToDelete = 0;
|
|
const moveset = playerPokemon.getMoveset();
|
|
for (const queuedMove of moveQueue) {
|
|
const movesetQueuedMove = moveset.find(m => m.moveId === queuedMove.move);
|
|
if (
|
|
queuedMove.move !== MoveId.NONE &&
|
|
!isVirtual(queuedMove.useMode) &&
|
|
!movesetQueuedMove?.isUsable(playerPokemon, isIgnorePP(queuedMove.useMode))
|
|
) {
|
|
entriesToDelete++;
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
if (entriesToDelete) {
|
|
moveQueue.splice(0, entriesToDelete);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Attempt to execute the first usable move in this Pokemon's move queue
|
|
* @returns Whether a queued move was successfully set to be executed.
|
|
*/
|
|
private tryExecuteQueuedMove(): boolean {
|
|
this.clearUnusuableMoves();
|
|
const playerPokemon = globalScene.getPlayerField()[this.fieldIndex];
|
|
const moveQueue = playerPokemon.getMoveQueue();
|
|
|
|
if (moveQueue.length === 0) {
|
|
return false;
|
|
}
|
|
|
|
const queuedMove = moveQueue[0];
|
|
if (queuedMove.move === MoveId.NONE) {
|
|
this.handleCommand(Command.FIGHT, -1);
|
|
return true;
|
|
}
|
|
const moveIndex = playerPokemon.getMoveset().findIndex(m => m.moveId === queuedMove.move);
|
|
if (!isVirtual(queuedMove.useMode) && moveIndex === -1) {
|
|
globalScene.ui.setMode(UiMode.COMMAND, this.fieldIndex);
|
|
} else {
|
|
this.handleCommand(Command.FIGHT, moveIndex, queuedMove.useMode, queuedMove);
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
start() {
|
|
super.start();
|
|
|
|
globalScene.updateGameInfo();
|
|
this.resetCursorIfNeeded();
|
|
|
|
if (this.fieldIndex) {
|
|
this.handleFieldIndexLogic();
|
|
}
|
|
|
|
this.checkCommander();
|
|
|
|
const playerPokemon = this.getPokemon();
|
|
|
|
// Note: It is OK to call this if the target is not under the effect of encore; it will simply do nothing.
|
|
playerPokemon.lapseTag(BattlerTagType.ENCORE);
|
|
|
|
if (globalScene.currentBattle.turnCommands[this.fieldIndex]?.skip) {
|
|
return this.end();
|
|
}
|
|
|
|
if (this.tryExecuteQueuedMove()) {
|
|
return;
|
|
}
|
|
|
|
if (
|
|
globalScene.currentBattle.isBattleMysteryEncounter() &&
|
|
globalScene.currentBattle.mysteryEncounter?.skipToFightInput
|
|
) {
|
|
globalScene.ui.clearText();
|
|
globalScene.ui.setMode(UiMode.FIGHT, this.fieldIndex);
|
|
} else {
|
|
globalScene.ui.setMode(UiMode.COMMAND, this.fieldIndex);
|
|
}
|
|
}
|
|
|
|
/**
|
|
*
|
|
* @param user - The pokemon using the move
|
|
* @param cursor - The index of the move in the moveset
|
|
*/
|
|
private queueFightErrorMessage(user: PlayerPokemon, cursor: number) {
|
|
const move = user.getMoveset()[cursor];
|
|
globalScene.ui.setMode(UiMode.MESSAGE);
|
|
|
|
// Decides between a Disabled, Not Implemented, or No PP translation message
|
|
const errorMessage = user.isMoveRestricted(move.moveId, user)
|
|
? user.getRestrictingTag(move.moveId, user)!.selectionDeniedText(user, move.moveId)
|
|
: move.getName().endsWith(" (N)")
|
|
? "battle:moveNotImplemented"
|
|
: "battle:moveNoPP";
|
|
const moveName = move.getName().replace(" (N)", ""); // Trims off the indicator
|
|
|
|
globalScene.ui.showText(
|
|
i18next.t(errorMessage, { moveName: moveName }),
|
|
null,
|
|
() => {
|
|
globalScene.ui.clearText();
|
|
globalScene.ui.setMode(UiMode.FIGHT, this.fieldIndex);
|
|
},
|
|
null,
|
|
true,
|
|
);
|
|
}
|
|
|
|
/** Helper method for {@linkcode handleFightCommand} that returns the moveID for the phase
|
|
* based on the move passed in or the cursor.
|
|
*
|
|
* Does not check if the move is usable or not, that should be handled by the caller.
|
|
*/
|
|
private comptueMoveId(playerPokemon: PlayerPokemon, cursor: number, move?: TurnMove): MoveId {
|
|
return move?.move ?? (cursor > -1 ? playerPokemon.getMoveset()[cursor]?.moveId : MoveId.NONE);
|
|
}
|
|
|
|
/**
|
|
* Handle fight logic
|
|
* @param command - The command to handle (FIGHT or TERA)
|
|
* @param cursor - The index that the cursor is placed on, or -1 if no move can be selected.
|
|
* @param args - Any additional arguments to pass to the command
|
|
*/
|
|
private handleFightCommand(
|
|
command: Command.FIGHT | Command.TERA,
|
|
cursor: number,
|
|
useMode: MoveUseMode = MoveUseMode.NORMAL,
|
|
move?: TurnMove,
|
|
): boolean {
|
|
const playerPokemon = this.getPokemon();
|
|
const ignorePP = isIgnorePP(useMode);
|
|
|
|
let canUse = cursor === -1 || playerPokemon.trySelectMove(cursor, ignorePP);
|
|
|
|
const useStruggle = canUse
|
|
? false
|
|
: cursor > -1 && !playerPokemon.getMoveset().some(m => m.isUsable(playerPokemon));
|
|
|
|
canUse = canUse || useStruggle;
|
|
|
|
if (!canUse) {
|
|
this.queueFightErrorMessage(playerPokemon, cursor);
|
|
return false;
|
|
}
|
|
|
|
const moveId = useStruggle ? MoveId.STRUGGLE : this.comptueMoveId(playerPokemon, cursor, move);
|
|
|
|
const turnCommand: TurnCommand = {
|
|
command: Command.FIGHT,
|
|
cursor: cursor,
|
|
move: { move: moveId, targets: [], useMode },
|
|
args: [useMode, move],
|
|
};
|
|
const preTurnCommand: TurnCommand = {
|
|
command: command,
|
|
targets: [this.fieldIndex],
|
|
skip: command === Command.FIGHT,
|
|
};
|
|
|
|
const moveTargets: MoveTargetSet =
|
|
move === undefined
|
|
? getMoveTargets(playerPokemon, moveId)
|
|
: {
|
|
targets: move.targets,
|
|
multiple: move.targets.length > 1,
|
|
};
|
|
|
|
if (!moveId) {
|
|
turnCommand.targets = [this.fieldIndex];
|
|
}
|
|
|
|
console.log(moveTargets, getPokemonNameWithAffix(playerPokemon));
|
|
|
|
if (moveTargets.targets.length > 1 && moveTargets.multiple) {
|
|
globalScene.phaseManager.unshiftNew("SelectTargetPhase", this.fieldIndex);
|
|
}
|
|
|
|
if (turnCommand.move && (moveTargets.targets.length <= 1 || moveTargets.multiple)) {
|
|
turnCommand.move.targets = moveTargets.targets;
|
|
} else if (
|
|
turnCommand.move &&
|
|
playerPokemon.getTag(BattlerTagType.CHARGING) &&
|
|
playerPokemon.getMoveQueue().length >= 1
|
|
) {
|
|
turnCommand.move.targets = playerPokemon.getMoveQueue()[0].targets;
|
|
} else {
|
|
globalScene.phaseManager.unshiftNew("SelectTargetPhase", this.fieldIndex);
|
|
}
|
|
|
|
globalScene.currentBattle.preTurnCommands[this.fieldIndex] = preTurnCommand;
|
|
globalScene.currentBattle.turnCommands[this.fieldIndex] = turnCommand;
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Set the mode in preparation to show the text, and then show the text.
|
|
* Only works for parameterless i18next keys.
|
|
* @param key - The i18next key for the text to show
|
|
*/
|
|
private queueShowText(key: string) {
|
|
globalScene.ui.setMode(UiMode.COMMAND, this.fieldIndex);
|
|
globalScene.ui.setMode(UiMode.MESSAGE);
|
|
|
|
globalScene.ui.showText(
|
|
i18next.t(key),
|
|
null,
|
|
() => {
|
|
globalScene.ui.showText("", 0);
|
|
globalScene.ui.setMode(UiMode.COMMAND, this.fieldIndex);
|
|
},
|
|
null,
|
|
true,
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Helper method for {@linkcode handleBallCommand} that checks if the pokeball can be thrown.
|
|
*
|
|
* The pokeball may not be thrown if:
|
|
* - It is a trainer battle
|
|
* - The biome is {@linkcode Biome.END} and it is not classic mode
|
|
* - The biome is {@linkcode Biome.END} and the fresh start challenge is active
|
|
* - The biome is {@linkcode Biome.END} and the player has not either caught the target before or caught all but one starter
|
|
* - The player is in a mystery encounter that disallows catching the pokemon
|
|
* @returns Whether a pokeball can be thrown
|
|
*
|
|
*/
|
|
private checkCanUseBall(): boolean {
|
|
if (
|
|
globalScene.arena.biomeType === BiomeId.END &&
|
|
(!globalScene.gameMode.isClassic ||
|
|
globalScene.gameMode.isFreshStartChallenge() ||
|
|
(globalScene
|
|
.getEnemyField()
|
|
.some(p => p.isActive() && !globalScene.gameData.dexData[p.species.speciesId].caughtAttr) &&
|
|
globalScene.gameData.getStarterCount(d => !!d.caughtAttr) < Object.keys(speciesStarterCosts).length - 1))
|
|
) {
|
|
this.queueShowText("battle:noPokeballForce");
|
|
} else if (globalScene.currentBattle.battleType === BattleType.TRAINER) {
|
|
this.queueShowText("battle:noPokeballTrainer");
|
|
} else if (
|
|
globalScene.currentBattle.isBattleMysteryEncounter() &&
|
|
!globalScene.currentBattle.mysteryEncounter!.catchAllowed
|
|
) {
|
|
this.queueShowText("battle:noPokeballMysteryEncounter");
|
|
} else {
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Helper method for {@linkcode handleCommand} that handles the logic when the selected command is to use a pokeball.
|
|
*
|
|
* @param cursor - The index of the pokeball to use
|
|
* @returns Whether the command was successfully initiated
|
|
*/
|
|
private handleBallCommand(cursor: number): boolean {
|
|
const targets = globalScene
|
|
.getEnemyField()
|
|
.filter(p => p.isActive(true))
|
|
.map(p => p.getBattlerIndex());
|
|
if (targets.length > 1) {
|
|
this.queueShowText("battle:noPokeballMulti");
|
|
return false;
|
|
}
|
|
|
|
if (!this.checkCanUseBall()) {
|
|
return false;
|
|
}
|
|
|
|
if (cursor < 5) {
|
|
const targetPokemon = globalScene.getEnemyPokemon();
|
|
if (
|
|
targetPokemon?.isBoss() &&
|
|
targetPokemon?.bossSegmentIndex >= 1 &&
|
|
// TODO: Decouple this hardcoded exception for wonder guard and just check the target...
|
|
!targetPokemon?.hasAbility(AbilityId.WONDER_GUARD, false, true) &&
|
|
cursor < PokeballType.MASTER_BALL
|
|
) {
|
|
this.queueShowText("battle:noPokeballStrong");
|
|
return false;
|
|
}
|
|
|
|
globalScene.currentBattle.turnCommands[this.fieldIndex] = {
|
|
command: Command.BALL,
|
|
cursor: cursor,
|
|
};
|
|
globalScene.currentBattle.turnCommands[this.fieldIndex]!.targets = targets;
|
|
if (this.fieldIndex) {
|
|
globalScene.currentBattle.turnCommands[this.fieldIndex - 1]!.skip = true;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Helper method to handle the logic for effects that prevent the pokemon from leaving the field
|
|
* due to trapping abilities or effects.
|
|
*
|
|
* This method queues the proper messages in the case of trapping abilities or effects
|
|
*
|
|
* @returns Whether the pokemon is currently trapped
|
|
*/
|
|
private handleTrap(): boolean {
|
|
const playerPokemon = this.getPokemon();
|
|
const trappedAbMessages: string[] = [];
|
|
const isSwitch = this.isSwitch;
|
|
if (!playerPokemon.isTrapped(trappedAbMessages)) {
|
|
return false;
|
|
}
|
|
if (trappedAbMessages.length > 0) {
|
|
if (isSwitch) {
|
|
globalScene.ui.setMode(UiMode.MESSAGE);
|
|
}
|
|
globalScene.ui.showText(
|
|
trappedAbMessages[0],
|
|
null,
|
|
() => {
|
|
globalScene.ui.showText("", 0);
|
|
if (isSwitch) {
|
|
globalScene.ui.setMode(UiMode.COMMAND, this.fieldIndex);
|
|
}
|
|
},
|
|
null,
|
|
true,
|
|
);
|
|
} else {
|
|
const trapTag = playerPokemon.getTag(TrappedTag);
|
|
const fairyLockTag = globalScene.arena.getTagOnSide(ArenaTagType.FAIRY_LOCK, ArenaTagSide.PLAYER);
|
|
|
|
if (!isSwitch) {
|
|
globalScene.ui.setMode(UiMode.COMMAND, this.fieldIndex);
|
|
globalScene.ui.setMode(UiMode.MESSAGE);
|
|
}
|
|
if (trapTag) {
|
|
this.showNoEscapeText(trapTag, false);
|
|
} else if (fairyLockTag) {
|
|
this.showNoEscapeText(fairyLockTag, false);
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Common helper method that attempts to have the pokemon leave the field.
|
|
* Checks for trapping abilities and effects.
|
|
*
|
|
* @param cursor - The index of the option that the cursor is on
|
|
* @param isBatonSwitch - Whether the switch command is switching via the Baton item
|
|
* @returns whether the pokemon is able to leave the field, indicating the command phase should end
|
|
*/
|
|
private tryLeaveField(cursor?: number, isBatonSwitch = false): boolean {
|
|
const currentBattle = globalScene.currentBattle;
|
|
|
|
if (isBatonSwitch || !this.handleTrap()) {
|
|
currentBattle.turnCommands[this.fieldIndex] = this.isSwitch
|
|
? {
|
|
command: Command.POKEMON,
|
|
cursor: cursor,
|
|
args: [isBatonSwitch],
|
|
}
|
|
: {
|
|
command: Command.RUN,
|
|
};
|
|
if (!this.isSwitch && this.fieldIndex) {
|
|
currentBattle.turnCommands[this.fieldIndex - 1]!.skip = true;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
private handleRunCommand(): boolean {
|
|
const { currentBattle, arena } = globalScene;
|
|
const mysteryEncounterFleeAllowed = currentBattle.mysteryEncounter?.fleeAllowed ?? true;
|
|
if (arena.biomeType === BiomeId.END || !mysteryEncounterFleeAllowed) {
|
|
this.queueShowText("battle:noEscapeForce");
|
|
return false;
|
|
}
|
|
if (
|
|
currentBattle.battleType === BattleType.TRAINER ||
|
|
currentBattle.mysteryEncounter?.encounterMode === MysteryEncounterMode.TRAINER_BATTLE
|
|
) {
|
|
this.queueShowText("battle:noEscapeTrainer");
|
|
return false;
|
|
}
|
|
|
|
const success = this.tryLeaveField();
|
|
|
|
return success;
|
|
}
|
|
|
|
/**
|
|
* Show a message indicating that the pokemon cannot escape, and then return to the command phase.
|
|
*/
|
|
private showNoEscapeText(tag: any, isSwitch: boolean): void {
|
|
globalScene.ui.showText(
|
|
i18next.t("battle:noEscapePokemon", {
|
|
pokemonName:
|
|
tag.sourceId && globalScene.getPokemonById(tag.sourceId)
|
|
? getPokemonNameWithAffix(globalScene.getPokemonById(tag.sourceId)!)
|
|
: "",
|
|
moveName: tag.getMoveName(),
|
|
escapeVerb: i18next.t(isSwitch ? "battle:escapeVerbSwitch" : "battle:escapeVerbFlee"),
|
|
}),
|
|
null,
|
|
() => {
|
|
globalScene.ui.showText("", 0);
|
|
if (!isSwitch) {
|
|
globalScene.ui.setMode(UiMode.COMMAND, this.fieldIndex);
|
|
}
|
|
},
|
|
null,
|
|
true,
|
|
);
|
|
}
|
|
|
|
// Overloads for handleCommand to provide a more specific signature for the different options
|
|
handleCommand(command: Command.FIGHT | Command.TERA, cursor: number, useMode?: MoveUseMode, move?: TurnMove): boolean;
|
|
handleCommand(command: Command.BALL, cursor: number): boolean;
|
|
handleCommand(command: Command.POKEMON, cursor: number, useBaton: boolean): boolean;
|
|
handleCommand(command: Command.RUN, cursor: number): boolean;
|
|
handleCommand(command: Command, cursor: number, useMode?: boolean | MoveUseMode, move?: TurnMove): boolean;
|
|
|
|
/**
|
|
* Process the command phase logic based on the selected command
|
|
*
|
|
* @param command - The kind of command to handle
|
|
* @param cursor - The index of option that the cursor is on, or -1 if no option is selected
|
|
* @param useMode - The mode to use for the move, if applicable. For switches, a boolean that specifies whether the switch is a Baton switch.
|
|
* @param move - For {@linkcode Command.FIGHT}, the move to use
|
|
*/
|
|
handleCommand(command: Command, cursor: number, useMode: boolean | MoveUseMode = false, move?: TurnMove): boolean {
|
|
let success = false;
|
|
|
|
switch (command) {
|
|
case Command.TERA:
|
|
case Command.FIGHT:
|
|
success = this.handleFightCommand(command, cursor, typeof useMode === "boolean" ? undefined : useMode, move);
|
|
break;
|
|
case Command.BALL:
|
|
success = this.handleBallCommand(cursor);
|
|
break;
|
|
case Command.POKEMON:
|
|
this.isSwitch = true;
|
|
success = this.tryLeaveField(cursor, typeof useMode === "boolean" ? useMode : undefined);
|
|
this.isSwitch = false;
|
|
break;
|
|
case Command.RUN:
|
|
success = this.handleRunCommand();
|
|
}
|
|
|
|
if (success) {
|
|
this.end();
|
|
}
|
|
|
|
return success;
|
|
}
|
|
|
|
cancel() {
|
|
if (this.fieldIndex) {
|
|
globalScene.phaseManager.unshiftNew("CommandPhase", 0);
|
|
globalScene.phaseManager.unshiftNew("CommandPhase", 1);
|
|
this.end();
|
|
}
|
|
}
|
|
|
|
getFieldIndex(): number {
|
|
return this.fieldIndex;
|
|
}
|
|
|
|
getPokemon(): PlayerPokemon {
|
|
return globalScene.getPlayerField()[this.fieldIndex];
|
|
}
|
|
|
|
end() {
|
|
globalScene.ui.setMode(UiMode.MESSAGE).then(() => super.end());
|
|
}
|
|
}
|