diff --git a/src/data/moves/move.ts b/src/data/moves/move.ts index 513ab3f6a74..26654fee18f 100644 --- a/src/data/moves/move.ts +++ b/src/data/moves/move.ts @@ -8183,7 +8183,7 @@ export type MoveTargetSet = { export function getMoveTargets(user: Pokemon, move: Moves, replaceTarget?: MoveTarget): MoveTargetSet { const variableTarget = new NumberHolder(0); - user.getOpponents().forEach(p => applyMoveAttrs(VariableTargetAttr, user, p, allMoves[move], variableTarget)); + user.getOpponents(false).forEach(p => applyMoveAttrs(VariableTargetAttr, user, p, allMoves[move], variableTarget)); let moveTarget: MoveTarget | undefined; if (allMoves[move].hasAttr(VariableTargetAttr)) { @@ -8195,7 +8195,7 @@ export function getMoveTargets(user: Pokemon, move: Moves, replaceTarget?: MoveT } else if (move === undefined) { moveTarget = MoveTarget.NEAR_ENEMY; } - const opponents = user.getOpponents(); + const opponents = user.getOpponents(false); let set: Pokemon[] = []; let multiple = false; diff --git a/src/data/terrain.ts b/src/data/terrain.ts index 894fb8a7955..5b6063cee68 100644 --- a/src/data/terrain.ts +++ b/src/data/terrain.ts @@ -59,7 +59,7 @@ export class Terrain { // Cancels move if the move has positive priority and targets a Pokemon grounded on the Psychic Terrain return ( move.getPriority(user) > 0 && - user.getOpponents().some(o => targets.includes(o.getBattlerIndex()) && o.isGrounded()) + user.getOpponents(true).some(o => targets.includes(o.getBattlerIndex()) && o.isGrounded()) ); } } diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 0242820dcde..f2e5fd4c2b6 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -3852,12 +3852,17 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container { return null; } - getOpponents(): Pokemon[] { + /** + * Returns the pokemon that oppose this one and are active + * + * @param onField - whether to also check if the pokemon is currently on the field (defaults to true) + */ + getOpponents(onField = true): Pokemon[] { return ( (this.isPlayer() ? globalScene.getEnemyField() : globalScene.getPlayerField()) as Pokemon[] - ).filter(p => p.isActive()); + ).filter(p => p.isActive(onField)); } getOpponentDescriptor(): string { diff --git a/src/phases/move-phase.ts b/src/phases/move-phase.ts index f42a2aefa34..7d2848a5d70 100644 --- a/src/phases/move-phase.ts +++ b/src/phases/move-phase.ts @@ -654,7 +654,7 @@ export class MovePhase extends BattlePhase { }), 500, ); - applyMoveAttrs(PreMoveMessageAttr, this.pokemon, this.pokemon.getOpponents()[0], this.move.getMove()); + applyMoveAttrs(PreMoveMessageAttr, this.pokemon, this.pokemon.getOpponents(false)[0], this.move.getMove()); } public showFailedText(failedText: string = i18next.t("battle:attackFailed")): void { diff --git a/test/ui/type-hints.test.ts b/test/ui/type-hints.test.ts index 08d9806ec7f..2051af76754 100644 --- a/test/ui/type-hints.test.ts +++ b/test/ui/type-hints.test.ts @@ -40,7 +40,7 @@ describe("UI - Type Hints", () => { .moveset([Moves.DRAGON_CLAW]); game.settings.typeHints(true); //activate type hints - await game.startBattle([Species.RAYQUAZA]); + await game.classicMode.startBattle([Species.RAYQUAZA]); game.onNextPrompt("CommandPhase", UiMode.COMMAND, () => { const { ui } = game.scene; @@ -65,7 +65,7 @@ describe("UI - Type Hints", () => { it("check status move color", async () => { game.override.enemySpecies(Species.FLORGES).moveset([Moves.GROWL]); - await game.startBattle([Species.RAYQUAZA]); + await game.classicMode.startBattle([Species.RAYQUAZA]); game.onNextPrompt("CommandPhase", UiMode.COMMAND, () => { const { ui } = game.scene; @@ -86,4 +86,41 @@ describe("UI - Type Hints", () => { }); await game.phaseInterceptor.to(CommandPhase); }); + + it("should show the proper hint for a move in doubles after one of the enemy pokemon flees", async () => { + game.override + .enemySpecies(Species.ABRA) + .moveset([Moves.SPLASH, Moves.SHADOW_BALL, Moves.SOAK]) + .enemyMoveset([Moves.SPLASH, Moves.TELEPORT]) + .battleStyle("double"); + + await game.classicMode.startBattle([Species.MAGIKARP, Species.MAGIKARP]); + game.move.select(Moves.SPLASH); + // Use soak to change type of remaining abra to water + game.move.select(Moves.SOAK, 1); + + await game.forceEnemyMove(Moves.SPLASH); + await game.forceEnemyMove(Moves.TELEPORT); + await game.toNextTurn(); + + game.onNextPrompt("CommandPhase", UiMode.COMMAND, () => { + const { ui } = game.scene; + const handler = ui.getHandler(); + handler.processInput(Button.ACTION); // select "Fight" + game.phaseInterceptor.unlock(); + }); + + game.onNextPrompt("CommandPhase", UiMode.FIGHT, () => { + const { ui } = game.scene; + const movesContainer = ui.getByName(FightUiHandler.MOVES_CONTAINER_NAME); + const shadowBallText = movesContainer + .getAll() + .find(text => text.text === i18next.t("move:shadowBall.name"))! as unknown as MockText; + expect.soft(shadowBallText).toBeDefined(); + + expect.soft(shadowBallText.color).toBe(undefined); + ui.getHandler().processInput(Button.ACTION); + }); + await game.phaseInterceptor.to(CommandPhase); + }); });