From 468275ba233d45f2993320711d5a88fe049c87e3 Mon Sep 17 00:00:00 2001 From: Christopher Schmidt Date: Sat, 26 Oct 2024 20:34:10 -0400 Subject: [PATCH] Corrects mirror move implementation, rewrite unit test to adjust --- src/battle.ts | 2 -- src/data/move.ts | 25 +++++++--------- src/phases/move-phase.ts | 4 --- src/test/moves/mirror_move.test.ts | 46 ++++++++++++++---------------- 4 files changed, 32 insertions(+), 45 deletions(-) diff --git a/src/battle.ts b/src/battle.ts index 49bb2d9f042..f971ddbea81 100644 --- a/src/battle.ts +++ b/src/battle.ts @@ -88,8 +88,6 @@ export default class Battle { public enemyFaints: number = 0; public playerFaintsHistory: FaintLogEntry[] = []; public enemyFaintsHistory: FaintLogEntry[] = []; - /** The list of moves used since the beginning of the battle */ - public moveHistory: TurnMove[] = []; public mysteryEncounterType?: MysteryEncounterType; diff --git a/src/data/move.ts b/src/data/move.ts index 26d457c1fb7..2779957387a 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -5973,6 +5973,7 @@ export class FirstMoveTypeAttr extends MoveEffectAttr { export class CallMoveAttr extends OverrideMoveEffectAttr { protected invalidMoves: Moves[]; + protected hasTarget: boolean; async apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): Promise { const replaceMoveTarget = move.moveTarget === MoveTarget.NEAR_OTHER ? MoveTarget.NEAR_ENEMY : undefined; const moveTargets = getMoveTargets(user, move.id, replaceMoveTarget); @@ -5981,7 +5982,7 @@ export class CallMoveAttr extends OverrideMoveEffectAttr { } const targets = moveTargets.multiple || moveTargets.targets.length === 1 ? moveTargets.targets - : [ moveTargets.targets[user.randSeedInt(moveTargets.targets.length)] ]; + : [ this.hasTarget ? target.getBattlerIndex() : moveTargets.targets[user.randSeedInt(moveTargets.targets.length)] ]; // account for Mirror Move having a target already user.getMoveQueue().push({ move: move.id, targets: targets, virtual: true, ignorePP: true }); user.scene.unshiftPhase(new MovePhase(user.scene, user, targets, new PokemonMove(move.id, 0, 0, true), true, true)); @@ -6502,25 +6503,19 @@ export class CopyMoveAttr extends CallMoveAttr { } apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): Promise { - if (this.mirrorMove) { - const lastMove = user.scene.currentBattle.moveHistory.filter(m => m.targets.includes(user.getBattlerIndex()))[0].move; - return super.apply(user, target, allMoves[lastMove], args); - } else { - return super.apply(user, target, allMoves[user.scene.currentBattle.lastMove], args); - } + this.hasTarget = this.mirrorMove; + const lastMove = this.mirrorMove ? target.getLastXMoves()[0].move : user.scene.currentBattle.lastMove; + return super.apply(user, target, allMoves[lastMove], args); } getCondition(): MoveConditionFunc { return (user, target, move) => { if (this.mirrorMove) { - if (user.scene.currentBattle.moveHistory.filter(m => m.targets.includes(user.getBattlerIndex())).length === 0) { - return false; - } - } else if (user.scene.currentBattle.lastMove === undefined) { - return false; + return target.getMoveHistory().length !== 0; + } else { + const lastMove = user.scene.currentBattle.lastMove; + return lastMove !== undefined && !this.invalidMoves.includes(lastMove); } - const lastMove = this.mirrorMove ? user.turnData.attacksReceived[0]?.move : user.scene.currentBattle.lastMove; - return !this.invalidMoves.includes(lastMove); }; } } @@ -7906,7 +7901,7 @@ export function initMoves() { .unimplemented(), new SelfStatusMove(Moves.METRONOME, Type.NORMAL, -1, 10, -1, 0, 1) .attr(RandomMoveAttr, invalidMetronomeMoves), - new SelfStatusMove(Moves.MIRROR_MOVE, Type.FLYING, -1, 20, -1, 0, 1) + new StatusMove(Moves.MIRROR_MOVE, Type.FLYING, -1, 20, -1, 0, 1) .attr(CopyMoveAttr, true), new AttackMove(Moves.SELF_DESTRUCT, Type.NORMAL, MoveCategory.PHYSICAL, 200, 100, 5, -1, 0, 1) .attr(SacrificialAttr) diff --git a/src/phases/move-phase.ts b/src/phases/move-phase.ts index 2529a8f3c20..b1504882f30 100644 --- a/src/phases/move-phase.ts +++ b/src/phases/move-phase.ts @@ -274,10 +274,6 @@ export class MovePhase extends BattlePhase { // The last move used is unaffected by moves that fail if (success) { this.scene.currentBattle.lastMove = this.move.moveId; - this.scene.currentBattle.moveHistory.unshift({ - move: this.move.moveId, - targets: this.targets - }); } } diff --git a/src/test/moves/mirror_move.test.ts b/src/test/moves/mirror_move.test.ts index b12d59ef508..7b84762948a 100644 --- a/src/test/moves/mirror_move.test.ts +++ b/src/test/moves/mirror_move.test.ts @@ -34,15 +34,20 @@ describe("Moves - Mirror Move", () => { .enemyMoveset(Moves.SPLASH); }); - it("should use the last move targeted at the user", async () => { - game.override.enemyMoveset(Moves.TACKLE); - await game.classicMode.startBattle([ Species.FEEBAS ]); + it("should use the last move that the target", async () => { + game.override + .battleType("double") + .enemyMoveset([ Moves.TACKLE, Moves.GROWL ]); + await game.classicMode.startBattle([ Species.FEEBAS, Species.MAGIKARP ]); - game.move.select(Moves.MIRROR_MOVE); - await game.setTurnOrder([ BattlerIndex.ENEMY, BattlerIndex.PLAYER ]); + game.move.select(Moves.MIRROR_MOVE, 0, BattlerIndex.ENEMY); // target's last move is Tackle, enemy should receive damage from Mirror Move copying Tackle + game.move.select(Moves.SPLASH, 1); + await game.forceEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER_2); + await game.forceEnemyMove(Moves.GROWL, BattlerIndex.PLAYER_2); + await game.setTurnOrder([ BattlerIndex.ENEMY, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.PLAYER ]); await game.toNextTurn(); - expect(game.scene.getEnemyPokemon()!.isFullHp()).toBeFalsy(); + expect(game.scene.getEnemyField()[0].isFullHp()).toBeFalsy(); }); it("should apply secondary effects of a move", async () => { @@ -56,24 +61,7 @@ describe("Moves - Mirror Move", () => { expect(game.scene.getEnemyPokemon()!.getStatStage(Stat.SPDEF)).toBe(-2); }); - it("should fail if the user has never been targeted", { repeats: 10 }, async () => { - game.override - .battleType("double") - .startingLevel(100) - .enemyMoveset([ Moves.TACKLE, Moves.SPLASH ]); - await game.classicMode.startBattle([ Species.FEEBAS, Species.MAGIKARP ]); - - game.move.select(Moves.MIRROR_MOVE); - game.move.select(Moves.SPLASH, 1); - await game.forceEnemyMove(Moves.TACKLE, BattlerIndex.PLAYER_2); - await game.forceEnemyMove(Moves.SPLASH); - await game.setTurnOrder([ BattlerIndex.ENEMY, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.PLAYER ]); - await game.toNextTurn(); - - expect(game.scene.getPlayerField()![0].getLastXMoves()[0].result).toBe(MoveResult.FAIL); - }); - - it("should copy status moves that target the user", async () => { + it("should be able to copy status moves", async () => { game.override.enemyMoveset(Moves.GROWL); await game.classicMode.startBattle([ Species.FEEBAS ]); @@ -83,4 +71,14 @@ describe("Moves - Mirror Move", () => { expect(game.scene.getEnemyPokemon()!.getStatStage(Stat.ATK)).toBe(-1); }); + + it("should fail if the target has not used any moves", async () => { + await game.classicMode.startBattle([ Species.FEEBAS ]); + + game.move.select(Moves.MIRROR_MOVE); + await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]); + await game.toNextTurn(); + + expect(game.scene.getPlayerPokemon()!.getLastXMoves()[0].result).toBe(MoveResult.FAIL); + }); });