mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-12-16 06:45:24 +01:00
162 lines
5.9 KiB
TypeScript
162 lines
5.9 KiB
TypeScript
import { applyAbAttrs } from "#abilities/apply-ab-attrs";
|
|
import type { TurnCommand } from "#app/battle";
|
|
import { globalScene } from "#app/global-scene";
|
|
import { ArenaTagSide } from "#enums/arena-tag-side";
|
|
import type { BattlerIndex } from "#enums/battler-index";
|
|
import { Command } from "#enums/command";
|
|
import { SwitchType } from "#enums/switch-type";
|
|
import type { Pokemon } from "#field/pokemon";
|
|
import { BypassSpeedChanceModifier } from "#modifiers/modifier";
|
|
import { PokemonMove } from "#moves/pokemon-move";
|
|
import { FieldPhase } from "#phases/field-phase";
|
|
import { inSpeedOrder } from "#utils/speed-order-generator";
|
|
|
|
export class TurnStartPhase extends FieldPhase {
|
|
public readonly phaseName = "TurnStartPhase";
|
|
|
|
/**
|
|
* Returns an ordering of the current field based on command priority
|
|
* @returns The sequence of commands for this turn
|
|
*/
|
|
private getCommandOrder(): BattlerIndex[] {
|
|
const playerField = globalScene.getPlayerField(true).map(p => p.getBattlerIndex());
|
|
const enemyField = globalScene.getEnemyField(true).map(p => p.getBattlerIndex());
|
|
const orderedTargets: BattlerIndex[] = playerField.concat(enemyField);
|
|
|
|
// The function begins sorting orderedTargets based on command priority, move priority, and possible speed bypasses.
|
|
// Non-FIGHT commands (SWITCH, BALL, RUN) have a higher command priority and will always occur before any FIGHT commands.
|
|
orderedTargets.sort((a, b) => {
|
|
const aCommand = globalScene.currentBattle.turnCommands[a];
|
|
const bCommand = globalScene.currentBattle.turnCommands[b];
|
|
|
|
if (aCommand?.command !== bCommand?.command) {
|
|
if (aCommand?.command === Command.FIGHT) {
|
|
return 1;
|
|
}
|
|
if (bCommand?.command === Command.FIGHT) {
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
const aIndex = orderedTargets.indexOf(a);
|
|
const bIndex = orderedTargets.indexOf(b);
|
|
|
|
return aIndex < bIndex ? -1 : aIndex > bIndex ? 1 : 0;
|
|
});
|
|
return orderedTargets;
|
|
}
|
|
|
|
// TODO: Refactor this alongside `CommandPhase.handleCommand` to use SEPARATE METHODS
|
|
// Also need a clearer distinction between "turn command" and queued moves
|
|
start() {
|
|
super.start();
|
|
|
|
const field = globalScene.getField();
|
|
const moveOrder = this.getCommandOrder();
|
|
|
|
for (const pokemon of inSpeedOrder(ArenaTagSide.BOTH)) {
|
|
const preTurnCommand = globalScene.currentBattle.preTurnCommands[pokemon.getBattlerIndex()];
|
|
|
|
if (preTurnCommand?.skip) {
|
|
continue;
|
|
}
|
|
|
|
switch (preTurnCommand?.command) {
|
|
case Command.TERA:
|
|
globalScene.phaseManager.pushNew("TeraPhase", pokemon);
|
|
}
|
|
}
|
|
|
|
const phaseManager = globalScene.phaseManager;
|
|
for (const pokemon of inSpeedOrder(ArenaTagSide.BOTH)) {
|
|
if (globalScene.currentBattle.turnCommands[pokemon.getBattlerIndex()]?.command !== Command.FIGHT) {
|
|
continue;
|
|
}
|
|
|
|
applyAbAttrs("BypassSpeedChanceAbAttr", { pokemon });
|
|
globalScene.applyModifiers(BypassSpeedChanceModifier, pokemon.isPlayer(), pokemon);
|
|
}
|
|
|
|
moveOrder.forEach((o, index) => {
|
|
const pokemon = field[o];
|
|
const turnCommand = globalScene.currentBattle.turnCommands[o];
|
|
|
|
if (!turnCommand || turnCommand.skip) {
|
|
return;
|
|
}
|
|
|
|
// TODO: Remove `turnData.order` -
|
|
// it is used exclusively for Fusion Flare/Bolt
|
|
// and uses a really jank (and incorrect) implementation
|
|
if (turnCommand.command === Command.FIGHT) {
|
|
pokemon.turnData.order = index;
|
|
}
|
|
this.handleTurnCommand(turnCommand, pokemon);
|
|
});
|
|
|
|
// Queue various effects for the end of the turn.
|
|
phaseManager.pushNew("CheckInterludePhase");
|
|
|
|
// TODO: Re-order these phases to be consistent with mainline turn order:
|
|
// https://www.smogon.com/forums/threads/sword-shield-battle-mechanics-research.3655528/page-64#post-9244179
|
|
|
|
// TODO: In an ideal world, this is handled by the phase manager. The change is nontrivial due to the ordering of post-turn phases like those queued by VictoryPhase
|
|
globalScene.phaseManager.queueTurnEndPhases();
|
|
|
|
/*
|
|
* `this.end()` will call `PhaseManager#shiftPhase()`, which dumps everything from `phaseQueuePrepend`
|
|
* (aka everything that is queued via `unshift()`) to the front of the queue and dequeues to start the next phase.
|
|
* This is important since stuff like `SwitchSummonPhase`, `AttemptRunPhase`, and `AttemptCapturePhase` break the "flow" and should take precedence
|
|
*/
|
|
this.end();
|
|
}
|
|
|
|
private handleTurnCommand(turnCommand: TurnCommand, pokemon: Pokemon) {
|
|
switch (turnCommand?.command) {
|
|
case Command.FIGHT:
|
|
this.handleFightCommand(turnCommand, pokemon);
|
|
break;
|
|
case Command.BALL:
|
|
globalScene.phaseManager.unshiftNew("AttemptCapturePhase", turnCommand.targets![0] % 2, turnCommand.cursor!); //TODO: is the bang correct here?
|
|
break;
|
|
case Command.POKEMON:
|
|
globalScene.phaseManager.unshiftNew(
|
|
"SwitchSummonPhase",
|
|
turnCommand.args?.[0] ? SwitchType.BATON_PASS : SwitchType.SWITCH,
|
|
pokemon.getFieldIndex(),
|
|
turnCommand.cursor!, // TODO: Is this bang correct?
|
|
true,
|
|
pokemon.isPlayer(),
|
|
);
|
|
break;
|
|
case Command.RUN:
|
|
globalScene.phaseManager.unshiftNew("AttemptRunPhase");
|
|
break;
|
|
}
|
|
}
|
|
|
|
private handleFightCommand(turnCommand: TurnCommand, pokemon: Pokemon) {
|
|
const queuedMove = turnCommand.move;
|
|
if (!queuedMove) {
|
|
return;
|
|
}
|
|
|
|
// TODO: This seems somewhat dubious
|
|
const move =
|
|
pokemon.getMoveset().find(m => m.moveId === queuedMove.move && m.ppUsed < m.getMovePp())
|
|
?? new PokemonMove(queuedMove.move);
|
|
|
|
if (move.getMove().hasAttr("MoveHeaderAttr")) {
|
|
globalScene.phaseManager.unshiftNew("MoveHeaderPhase", pokemon, move);
|
|
}
|
|
|
|
globalScene.phaseManager.pushNew(
|
|
"MovePhase",
|
|
pokemon,
|
|
turnCommand.targets ?? queuedMove.targets,
|
|
move,
|
|
queuedMove.useMode,
|
|
);
|
|
}
|
|
}
|