Fixed all the bug

This commit is contained in:
Bertie690 2025-06-12 18:59:55 -04:00
parent 470e7adce0
commit fa7ae9c388
3 changed files with 34 additions and 28 deletions

View File

@ -6781,7 +6781,7 @@ export abstract class CallMoveAttr extends OverrideMoveEffectAttr {
const targets = moveTargets.multiple || moveTargets.targets.length === 1
? moveTargets.targets
: [ this.selfTarget ? target.getBattlerIndex() : moveTargets.targets[user.randBattleSeedInt(moveTargets.targets.length)] ]; // account for Mirror Move having a target already
user.getMoveQueue().push({ move: copiedMove.id, targets: targets, virtual: true, ignorePP: true });
globalScene.phaseManager.unshiftNew("LoadMoveAnimPhase", copiedMove.id);
globalScene.phaseManager.unshiftNew("MovePhase", user, targets, new PokemonMove(copiedMove.id, 0, 0, true), true, true);
return true;
@ -6883,7 +6883,6 @@ export class NaturePowerAttr extends CallMoveAttr {
override getMove(user: Pokemon): MoveId {
const moveId = this.getMoveIdForTerrain(globalScene.arena.getTerrainType(), globalScene.arena.biomeType)
// Unshift a phase to load the move's animation (in case it isn't already), then use the move.
globalScene.phaseManager.unshiftNew("LoadMoveAnimPhase", moveId);
globalScene.phaseManager.queueMessage(i18next.t("moveTriggers:naturePowerUse", {
pokemonName: getPokemonNameWithAffix(user),
moveName: allMoves[moveId].name,
@ -7007,8 +7006,8 @@ export class CopyMoveAttr extends CallMoveAttr {
override getMove(_user: Pokemon, target: Pokemon): MoveId {
return this.selfTarget
? target.getLastXMoves()[0]?.move ?? MoveId.NONE
: globalScene.currentBattle.lastMove;
? globalScene.currentBattle.lastMove
: target.getLastXMoves()[0]?.move ?? MoveId.NONE
}
getCondition(): MoveConditionFunc {

View File

@ -370,13 +370,11 @@ export class MovePhase extends BattlePhase {
success = passesConditions && !failedDueToWeather && !failedDueToTerrain;
}
// Update the battle's "last move" pointer, unless we're currently mimicking a move.
if (!allMoves[this.move.moveId].hasAttr("CopyMoveAttr")) {
// The last move used is unaffected by moves that fail
if (success) {
// Update the battle's "last move" pointer, unless we're currently mimicking a move
// or the move failed.
if (!allMoves[this.move.moveId].hasAttr("CallMoveAttr") && success) {
globalScene.currentBattle.lastMove = this.move.moveId;
}
}
/**
* If the move has not failed, trigger ability-based user type changes and then execute it.

View File

@ -34,58 +34,67 @@ describe("Moves - Copycat", () => {
.ability(AbilityId.BALL_FETCH)
.battleStyle("single")
.disableCrits()
.starterSpecies(SpeciesId.FEEBAS)
.enemySpecies(SpeciesId.MAGIKARP)
.enemyAbility(AbilityId.BALL_FETCH)
.enemyMoveset(MoveId.SPLASH);
});
it("should copy the last move successfully executed", async () => {
game.override.enemyMoveset(MoveId.SUCKER_PUNCH);
await game.classicMode.startBattle();
await game.classicMode.startBattle([SpeciesId.FEEBAS]);
game.move.select(MoveId.SWORDS_DANCE);
await game.toNextTurn();
game.move.select(MoveId.COPYCAT); // Last successful move should be Swords Dance
await game.move.forceEnemyMove(MoveId.SUCKER_PUNCH);
await game.toNextTurn();
expect(game.scene.getPlayerPokemon()!.getStatStage(Stat.ATK)).toBe(4);
const player = game.field.getPlayerPokemon();
expect(player.getStatStage(Stat.ATK)).toBe(4);
expect(player.getLastXMoves()[0].move).toBe(MoveId.SWORDS_DANCE);
});
it("should fail when the last move used is not a valid Copycat move", async () => {
game.override.enemyMoveset(MoveId.PROTECT); // Protect is not a valid move for Copycat to copy
await game.classicMode.startBattle();
game.move.select(MoveId.SPIKY_SHIELD); // Spiky Shield is not a valid move for Copycat to copy
await game.toNextTurn();
it("should fail if no prior moves have been made", async () => {
await game.classicMode.startBattle([SpeciesId.FEEBAS]);
game.move.select(MoveId.COPYCAT);
await game.move.forceEnemyMove(MoveId.SPLASH);
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
await game.toNextTurn();
expect(game.scene.getPlayerPokemon()!.getLastXMoves()[0].result).toBe(MoveResult.FAIL);
expect(game.field.getPlayerPokemon().getLastXMoves()[0].result).toBe(MoveResult.FAIL);
});
it("should fail if the last move used is not a valid Copycat move", async () => {
await game.classicMode.startBattle([SpeciesId.FEEBAS]);
game.move.use(MoveId.COPYCAT);
await game.move.forceEnemyMove(MoveId.PROTECT);
await game.toNextTurn();
expect(game.field.getPlayerPokemon().getLastXMoves()[0].result).toBe(MoveResult.FAIL);
});
it("should copy the called move when the last move successfully calls another", async () => {
game.override.moveset([MoveId.SPLASH, MoveId.METRONOME]).enemyMoveset(MoveId.COPYCAT);
await game.classicMode.startBattle();
vi.spyOn(randomMoveAttr, "getMove").mockReturnValue(MoveId.SWORDS_DANCE);
await game.classicMode.startBattle([SpeciesId.FEEBAS]);
game.move.select(MoveId.METRONOME);
game.move.use(MoveId.METRONOME);
await game.move.forceEnemyMove(MoveId.COPYCAT);
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]); // Player moves first, so enemy can copy Swords Dance
await game.toNextTurn();
expect(game.scene.getEnemyPokemon()!.getStatStage(Stat.ATK)).toBe(2);
expect(game.field.getEnemyPokemon().getStatStage(Stat.ATK)).toBe(2);
});
it("should apply secondary effects of a move", async () => {
game.override.enemyMoveset(MoveId.ACID_SPRAY); // Secondary effect lowers SpDef by 2 stages
await game.classicMode.startBattle();
await game.classicMode.startBattle([SpeciesId.FEEBAS]);
game.move.select(MoveId.COPYCAT);
game.move.use(MoveId.COPYCAT);
await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
await game.toNextTurn();
expect(game.scene.getEnemyPokemon()!.getStatStage(Stat.SPDEF)).toBe(-2);
expect(game.field.getEnemyPokemon().getStatStage(Stat.SPDEF)).toBe(-2);
});
});