diff --git a/src/battle.ts b/src/battle.ts index b80caa9e679..a3e7b0a4336 100644 --- a/src/battle.ts +++ b/src/battle.ts @@ -1,5 +1,4 @@ import BattleScene from "./battle-scene"; -import { EnemyPokemon, PlayerPokemon, QueuedMove } from "./field/pokemon"; import { Command } from "./ui/command-ui-handler"; import * as Utils from "./utils"; import Trainer, { TrainerVariant } from "./field/trainer"; @@ -7,6 +6,7 @@ import { GameMode } from "./game-mode"; import { MoneyMultiplierModifier, PokemonHeldItemModifier } from "./modifier/modifier"; import { PokeballType } from "./data/pokeball"; import { trainerConfigs } from "#app/data/trainer-config"; +import Pokemon, { EnemyPokemon, PlayerPokemon, QueuedMove } from "#app/field/pokemon"; import { ArenaTagType } from "#enums/arena-tag-type"; import { BattleSpec } from "#enums/battle-spec"; import { Moves } from "#enums/moves"; @@ -38,6 +38,11 @@ export interface TurnCommand { args?: any[]; } +export interface FaintLogEntry { + pokemon: Pokemon, + turn: number +} + interface TurnCommands { [key: number]: TurnCommand | null } @@ -69,6 +74,8 @@ export default class Battle { public playerFaints: number = 0; /** The number of times a Pokemon on the enemy's side has fainted this battle */ public enemyFaints: number = 0; + public playerFaintsHistory: FaintLogEntry[] = []; + public enemyFaintsHistory: FaintLogEntry[] = []; private rngCounter: number = 0; diff --git a/src/data/move.ts b/src/data/move.ts index 135122311ff..9916ccc1c9f 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -8024,7 +8024,15 @@ export function initMoves() { new StatusMove(Moves.REFLECT_TYPE, Type.NORMAL, -1, 15, -1, 0, 5) .attr(CopyTypeAttr), new AttackMove(Moves.RETALIATE, Type.NORMAL, MoveCategory.PHYSICAL, 70, 100, 5, -1, 0, 5) - .partial(), + .attr(MovePowerMultiplierAttr, (user, target, move) => { + const turn = user.scene.currentBattle.turn; + const lastPlayerFaint = user.scene.currentBattle.playerFaintsHistory[user.scene.currentBattle.playerFaintsHistory.length - 1]; + const lastEnemyFaint = user.scene.currentBattle.enemyFaintsHistory[user.scene.currentBattle.enemyFaintsHistory.length - 1]; + return ( + (lastPlayerFaint !== undefined && turn - lastPlayerFaint.turn === 1 && user.isPlayer()) || + (lastEnemyFaint !== undefined && turn - lastEnemyFaint.turn === 1 && !user.isPlayer()) + ) ? 2 : 1; + }), new AttackMove(Moves.FINAL_GAMBIT, Type.FIGHTING, MoveCategory.SPECIAL, -1, 100, 5, -1, 0, 5) .attr(UserHpDamageAttr) .attr(SacrificialAttrOnHit), diff --git a/src/phases/faint-phase.ts b/src/phases/faint-phase.ts index c30003b79aa..169d667113a 100644 --- a/src/phases/faint-phase.ts +++ b/src/phases/faint-phase.ts @@ -55,8 +55,10 @@ export class FaintPhase extends PokemonPhase { // Track total times pokemon have been KO'd for supreme overlord/last respects if (pokemon.isPlayer()) { this.scene.currentBattle.playerFaints += 1; + this.scene.currentBattle.playerFaintsHistory.push({ pokemon: pokemon, turn: this.scene.currentBattle.turn }); } else { this.scene.currentBattle.enemyFaints += 1; + this.scene.currentBattle.enemyFaintsHistory.push({ pokemon: pokemon, turn: this.scene.currentBattle.turn }); } this.scene.queueMessage(i18next.t("battle:fainted", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }), null, true); diff --git a/src/test/moves/retaliate.test.ts b/src/test/moves/retaliate.test.ts new file mode 100644 index 00000000000..62965fffba6 --- /dev/null +++ b/src/test/moves/retaliate.test.ts @@ -0,0 +1,49 @@ +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; +import Phaser from "phaser"; +import GameManager from "#app/test/utils/gameManager"; +import { Species } from "#enums/species"; +import { Moves } from "#enums/moves"; +import { allMoves } from "#app/data/move"; + +describe("Moves - Retaliate", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + const retaliate = allMoves[Moves.RETALIATE]; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .battleType("single") + .enemySpecies(Species.SNORLAX) + .enemyMoveset([Moves.RETALIATE, Moves.RETALIATE, Moves.RETALIATE, Moves.RETALIATE]) + .enemyLevel(100) + .moveset([Moves.RETALIATE, Moves.SPLASH]) + .startingLevel(80) + .disableCrits(); + }); + + it("increases power if ally died previous turn", async () => { + vi.spyOn(retaliate, "calculateBattlePower"); + await game.startBattle([Species.ABRA, Species.COBALION]); + game.move.select(Moves.RETALIATE); + await game.phaseInterceptor.to("TurnEndPhase"); + expect(retaliate.calculateBattlePower).toHaveLastReturnedWith(70); + game.doSelectPartyPokemon(1); + + await game.toNextTurn(); + game.move.select(Moves.RETALIATE); + await game.phaseInterceptor.to("MoveEffectPhase"); + expect(retaliate.calculateBattlePower).toHaveReturnedWith(140); + }); +});