diff --git a/src/data/move.ts b/src/data/move.ts index 77fc3e30f65..df92c023df5 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -3,7 +3,7 @@ import { BattleStat, getBattleStatName } from "./battle-stat"; import { EncoreTag, GulpMissileTag, HelpingHandTag, SemiInvulnerableTag, ShellTrapTag, StockpilingTag, TrappedTag, TypeBoostTag } from "./battler-tags"; import { getPokemonNameWithAffix } from "../messages"; import Pokemon, { AttackMoveResult, EnemyPokemon, HitResult, MoveResult, PlayerPokemon, PokemonMove, TurnMove } from "../field/pokemon"; -import { StatusEffect, getStatusEffectHealText, isNonVolatileStatusEffect, getNonVolatileStatusEffects} from "./status-effect"; +import { StatusEffect, getStatusEffectHealText, isNonVolatileStatusEffect, getNonVolatileStatusEffects } from "./status-effect"; import { getTypeResistances, Type } from "./type"; import { Constructor } from "#app/utils"; import * as Utils from "../utils"; @@ -6026,12 +6026,6 @@ export class VariableTargetAttr extends MoveAttr { } export class AfterYouAttr extends MoveEffectAttr { - private afterYouText:string; - - constructor() { - super(); - } - /** * Allows the target of this move to act right after the user. * @param user {@linkcode Pokemon} that is using the move. @@ -6041,13 +6035,13 @@ export class AfterYouAttr extends MoveEffectAttr { * @returns true */ apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean { - user.scene.queueMessage(getPokemonMessage(target," took the kind offer!")); + user.scene.queueMessage(i18next.t("moveTriggers:afterYou", {pokemonName: getPokemonNameWithAffix(target)})); /* Will find next acting phase of the targeted pokémon, delete it and queue it next on successful delete. */ - const nextAttackPhase:MovePhase = target.scene.findPhase((phase:MovePhase) => phase.pokemon === target) as MovePhase; - if (target.scene.tryRemovePhase((phase:MovePhase) => phase.pokemon === target)) { + const nextAttackPhase: MovePhase = target.scene.findPhase((phase: MovePhase) => phase.pokemon === target) as MovePhase; + if (target.scene.tryRemovePhase((phase: MovePhase) => phase.pokemon === target)) { target.scene.unshiftPhase(new MovePhase(target.scene, target, [...nextAttackPhase.targets], nextAttackPhase.move)); } diff --git a/src/locales/en/move-trigger.json b/src/locales/en/move-trigger.json index baddbaa34bf..746b903d8dc 100644 --- a/src/locales/en/move-trigger.json +++ b/src/locales/en/move-trigger.json @@ -61,5 +61,6 @@ "suppressAbilities": "{{pokemonName}}'s ability\nwas suppressed!", "revivalBlessing": "{{pokemonName}} was revived!", "swapArenaTags": "{{pokemonName}} swapped the battle effects affecting each side of the field!", - "exposedMove": "{{pokemonName}} identified\n{{targetPokemonName}}!" + "exposedMove": "{{pokemonName}} identified\n{{targetPokemonName}}!", + "afterYou": "{{pokemonName}} took the kind offer!" } diff --git a/src/test/moves/after_you.test.ts b/src/test/moves/after_you.test.ts new file mode 100644 index 00000000000..24a117c07cb --- /dev/null +++ b/src/test/moves/after_you.test.ts @@ -0,0 +1,65 @@ +import { BattlerIndex } from "#app/battle"; +import { Abilities } from "#app/enums/abilities"; +import { MoveResult } from "#app/field/pokemon"; +import { MovePhase } from "#app/phases/move-phase"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import { SPLASH_ONLY } from "../utils/testUtils"; + +const TIMEOUT = 20 * 1000; + +describe("Moves - After You", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .battleType("double") + .enemyLevel(5) + .enemySpecies(Species.PIKACHU) + .enemyAbility(Abilities.BALL_FETCH) + .enemyMoveset(SPLASH_ONLY) + .ability(Abilities.BALL_FETCH) + .moveset([Moves.AFTER_YOU, Moves.SPLASH]); + }); + + it("makes the target move immediately after the user", async () => { + await game.startBattle([Species.REGIELEKI, Species.SHUCKLE]); + + game.move.select(Moves.AFTER_YOU, 0, BattlerIndex.PLAYER_2); + game.move.select(Moves.SPLASH, 1); + + await game.phaseInterceptor.to("MoveEffectPhase"); + await game.phaseInterceptor.to(MovePhase); + const phase = game.scene.getCurrentPhase() as MovePhase; + expect(phase.pokemon).toBe(game.scene.getPlayerField()[1]); + }, TIMEOUT); + + it("fails if target already moved", async () => { + game.override.enemySpecies(Species.SHUCKLE); + await game.startBattle([Species.REGIELEKI, Species.PIKACHU]); + + game.move.select(Moves.SPLASH); + game.move.select(Moves.AFTER_YOU, 1, BattlerIndex.PLAYER); + + await game.phaseInterceptor.to("MoveEndPhase"); + await game.phaseInterceptor.to("MoveEndPhase"); + await game.phaseInterceptor.to(MovePhase); + + expect(game.scene.getPlayerField()[1].getLastXMoves(1)[0].result).toBe(MoveResult.FAIL); + }, TIMEOUT); +});