From 688bd5366d369775bb7539d72abe021b9e308bd7 Mon Sep 17 00:00:00 2001 From: Bertie690 Date: Fri, 13 Jun 2025 07:23:45 -0400 Subject: [PATCH 1/5] Reworked Turn Start Phase to be less jank --- src/phases/turn-start-phase.ts | 170 ++++++++++++++++----------------- 1 file changed, 84 insertions(+), 86 deletions(-) diff --git a/src/phases/turn-start-phase.ts b/src/phases/turn-start-phase.ts index 6f062cb5fbe..50fafa072cb 100644 --- a/src/phases/turn-start-phase.ts +++ b/src/phases/turn-start-phase.ts @@ -12,9 +12,15 @@ import { BattlerIndex } from "#enums/battler-index"; import { TrickRoomTag } from "#app/data/arena-tag"; import { SwitchType } from "#enums/switch-type"; import { globalScene } from "#app/global-scene"; +import type { TurnCommand } from "#app/battle"; export class TurnStartPhase extends FieldPhase { public readonly phaseName = "TurnStartPhase"; + + constructor() { + super(false); + } + /** * This orders the active Pokemon on the field by speed into an BattlerIndex array and returns that array. * It also checks for Trick Room and reverses the array if it is present. @@ -130,8 +136,6 @@ export class TurnStartPhase extends FieldPhase { const field = globalScene.getField(); const moveOrder = this.getCommandOrder(); - let orderIndex = 0; - for (const o of this.getSpeedOrder()) { const pokemon = field[o]; const preTurnCommand = globalScene.currentBattle.preTurnCommands[o]; @@ -148,96 +152,20 @@ export class TurnStartPhase extends FieldPhase { const phaseManager = globalScene.phaseManager; - for (const o of moveOrder) { + moveOrder.forEach((o, index) => { const pokemon = field[o]; const turnCommand = globalScene.currentBattle.turnCommands[o]; - if (turnCommand?.skip) { - continue; + if (!turnCommand || turnCommand.skip) { + return; } - switch (turnCommand?.command) { - case Command.FIGHT: - { - const queuedMove = turnCommand.move; - pokemon.turnData.order = orderIndex++; - if (!queuedMove) { - continue; - } - const move = - pokemon.getMoveset().find(m => m.moveId === queuedMove.move && m.ppUsed < m.getMovePp()) || - new PokemonMove(queuedMove.move); - if (move.getMove().hasAttr("MoveHeaderAttr")) { - phaseManager.unshiftNew("MoveHeaderPhase", pokemon, move); - } - if (pokemon.isPlayer()) { - if (turnCommand.cursor === -1) { - phaseManager.pushNew("MovePhase", pokemon, turnCommand.targets || turnCommand.move!.targets, move); - } else { - phaseManager.pushNew( - "MovePhase", - pokemon, - turnCommand.targets || turnCommand.move!.targets, // TODO: is the bang correct here? - move, - false, - queuedMove.ignorePP, - ); - } - } else { - phaseManager.pushNew( - "MovePhase", - pokemon, - turnCommand.targets || turnCommand.move!.targets, - move, - false, - queuedMove.ignorePP, - ); - } - } - break; - case Command.BALL: - phaseManager.unshiftNew("AttemptCapturePhase", turnCommand.targets![0] % 2, turnCommand.cursor!); //TODO: is the bang correct here? - break; - case Command.POKEMON: - { - const switchType = turnCommand.args?.[0] ? SwitchType.BATON_PASS : SwitchType.SWITCH; - phaseManager.unshiftNew( - "SwitchSummonPhase", - switchType, - pokemon.getFieldIndex(), - turnCommand.cursor!, - true, - pokemon.isPlayer(), - ); - } - break; - case Command.RUN: - { - let runningPokemon = pokemon; - if (globalScene.currentBattle.double) { - const playerActivePokemon = field.filter(pokemon => { - if (pokemon) { - return pokemon.isPlayer() && pokemon.isActive(); - } - return; - }); - // if only one pokemon is alive, use that one - if (playerActivePokemon.length > 1) { - // find which active pokemon has faster speed - const fasterPokemon = - playerActivePokemon[0].getStat(Stat.SPD) > playerActivePokemon[1].getStat(Stat.SPD) - ? playerActivePokemon[0] - : playerActivePokemon[1]; - // check if either active pokemon has the ability "Run Away" - const hasRunAway = playerActivePokemon.find(p => p.hasAbility(AbilityId.RUN_AWAY)); - runningPokemon = hasRunAway !== undefined ? hasRunAway : fasterPokemon; - } - } - phaseManager.unshiftNew("AttemptRunPhase", runningPokemon.getFieldIndex()); - } - break; + // TODO: This logic is questionable, especially given the fact that `order` is used for exactly 1 thing... + if (turnCommand.command === Command.FIGHT) { + pokemon.turnData.order = index; } - } + this.handleTurnCommand(turnCommand, pokemon); + }); phaseManager.pushNew("WeatherEffectPhase"); phaseManager.pushNew("BerryPhase"); @@ -254,4 +182,74 @@ export class TurnStartPhase extends FieldPhase { */ 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!, + true, + pokemon.isPlayer(), + ); + break; + case Command.RUN: + { + const playerActivePokemon = globalScene.getPokemonAllowedInBattle(); + if (!globalScene.currentBattle.double || playerActivePokemon.length === 1) { + // If not in doubles, attempt to run with the currently active Pokemon. + globalScene.phaseManager.unshiftNew("AttemptRunPhase", pokemon.getFieldIndex()); + return; + } + + // Use the fastest first pokemon we find with Run Away, or else the faster of the 2 player pokemon. + // This intentionally does not check for Trick Room. + // TODO: This phase should take a pokemon at all + const sortedPkmn = playerActivePokemon.sort((p1, p2) => p1.getStat(Stat.SPD) - p2.getStat(Stat.SPD)); + const runningPokemon = sortedPkmn.find(p => p.hasAbility(AbilityId.RUN_AWAY)) ?? sortedPkmn[0]; + + globalScene.phaseManager.unshiftNew("AttemptRunPhase", runningPokemon.getFieldIndex()); + } + break; + } + } + + private handleFightCommand(turnCommand: TurnCommand, pokemon: Pokemon) { + if (!turnCommand.move) { + return; + } + + const queuedMove = turnCommand.move; + + // 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); + } + + // TODO: Review what a `-1` cursor means + if (pokemon.isPlayer() && turnCommand.cursor === -1) { + globalScene.phaseManager.pushNew("MovePhase", pokemon, turnCommand.targets ?? queuedMove.targets, move); + } else { + globalScene.phaseManager.pushNew( + "MovePhase", + pokemon, + turnCommand.targets ?? turnCommand.move.targets, + move, + false, + queuedMove.ignorePP, + ); + } + } } From 81d3fb1eea269f9140533befbe8382efa270589b Mon Sep 17 00:00:00 2001 From: Bertie690 Date: Fri, 13 Jun 2025 07:30:42 -0400 Subject: [PATCH 2/5] Fixed sutff --- src/phases/turn-start-phase.ts | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/phases/turn-start-phase.ts b/src/phases/turn-start-phase.ts index 50fafa072cb..ac0f6d17aa6 100644 --- a/src/phases/turn-start-phase.ts +++ b/src/phases/turn-start-phase.ts @@ -17,10 +17,6 @@ import type { TurnCommand } from "#app/battle"; export class TurnStartPhase extends FieldPhase { public readonly phaseName = "TurnStartPhase"; - constructor() { - super(false); - } - /** * This orders the active Pokemon on the field by speed into an BattlerIndex array and returns that array. * It also checks for Trick Room and reverses the array if it is present. @@ -160,7 +156,8 @@ export class TurnStartPhase extends FieldPhase { return; } - // TODO: This logic is questionable, especially given the fact that `order` is used for exactly 1 thing... + // TODO: This logic is questionable and needs to be redone, + // especially given the fact that `order` is used for exactly 1 thing... if (turnCommand.command === Command.FIGHT) { pokemon.turnData.order = index; } @@ -196,7 +193,7 @@ export class TurnStartPhase extends FieldPhase { "SwitchSummonPhase", turnCommand.args?.[0] ? SwitchType.BATON_PASS : SwitchType.SWITCH, pokemon.getFieldIndex(), - turnCommand.cursor!, + turnCommand.cursor!, // TODO: Is this bang correct? true, pokemon.isPlayer(), ); From 7cf396f29610d2aa8cc174ad099ac76bdfaea7a3 Mon Sep 17 00:00:00 2001 From: Bertie690 <136088738+Bertie690@users.noreply.github.com> Date: Sat, 14 Jun 2025 20:02:12 -0400 Subject: [PATCH 3/5] Update turn-start-phase.ts --- src/phases/turn-start-phase.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/phases/turn-start-phase.ts b/src/phases/turn-start-phase.ts index ac0f6d17aa6..e1d5b808fc5 100644 --- a/src/phases/turn-start-phase.ts +++ b/src/phases/turn-start-phase.ts @@ -209,7 +209,7 @@ export class TurnStartPhase extends FieldPhase { // Use the fastest first pokemon we find with Run Away, or else the faster of the 2 player pokemon. // This intentionally does not check for Trick Room. - // TODO: This phase should take a pokemon at all + // TODO: This phase should not take a pokemon at all const sortedPkmn = playerActivePokemon.sort((p1, p2) => p1.getStat(Stat.SPD) - p2.getStat(Stat.SPD)); const runningPokemon = sortedPkmn.find(p => p.hasAbility(AbilityId.RUN_AWAY)) ?? sortedPkmn[0]; From 93740ae3a28047d04da0c7affe8c166584a01a3e Mon Sep 17 00:00:00 2001 From: Bertie690 <136088738+Bertie690@users.noreply.github.com> Date: Mon, 16 Jun 2025 08:23:44 -0400 Subject: [PATCH 4/5] Update turn-start-phase.ts --- src/phases/turn-start-phase.ts | 25 +++++++++---------------- 1 file changed, 9 insertions(+), 16 deletions(-) diff --git a/src/phases/turn-start-phase.ts b/src/phases/turn-start-phase.ts index 1efe6320fff..281100660d4 100644 --- a/src/phases/turn-start-phase.ts +++ b/src/phases/turn-start-phase.ts @@ -223,12 +223,11 @@ export class TurnStartPhase extends FieldPhase { } private handleFightCommand(turnCommand: TurnCommand, pokemon: Pokemon) { - if (!turnCommand.move) { + const queuedMove = turnCommand.move; + if (!queuedMove) { return; } - const queuedMove = turnCommand.move; - // TODO: This seems somewhat dubious const move = pokemon.getMoveset().find(m => m.moveId === queuedMove.move && m.ppUsed < m.getMovePp()) ?? @@ -238,18 +237,12 @@ export class TurnStartPhase extends FieldPhase { globalScene.phaseManager.unshiftNew("MoveHeaderPhase", pokemon, move); } - // TODO: Review what a `-1` cursor means - if (pokemon.isPlayer() && turnCommand.cursor === -1) { - globalScene.phaseManager.pushNew("MovePhase", pokemon, turnCommand.targets ?? queuedMove.targets, move); - } else { - globalScene.phaseManager.pushNew( - "MovePhase", - pokemon, - turnCommand.targets ?? turnCommand.move.targets, - move, - false, - queuedMove.useMode, - ); - } + globalScene.phaseManager.pushNew( + "MovePhase", + pokemon, + turnCommand.targets ?? queuedMove.targets, + move, + queuedMove.useMode, + ); } } From bc337f022d8b1c67568633576e647aa447f1210a Mon Sep 17 00:00:00 2001 From: Bertie690 Date: Mon, 16 Jun 2025 12:07:46 -0400 Subject: [PATCH 5/5] Ran biome --- src/phases/turn-start-phase.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/phases/turn-start-phase.ts b/src/phases/turn-start-phase.ts index 281100660d4..29fc962ae74 100644 --- a/src/phases/turn-start-phase.ts +++ b/src/phases/turn-start-phase.ts @@ -158,9 +158,9 @@ export class TurnStartPhase extends FieldPhase { return; } - // TODO: Remove `turnData.order` - + // TODO: Remove `turnData.order` - // it is used exclusively for Fusion Flare/Bolt - // and uses a really jank implementation + // and uses a really jank implementation if (turnCommand.command === Command.FIGHT) { pokemon.turnData.order = index; }