From e521862096cbd59d0cdfa5aec574abeee73d936b Mon Sep 17 00:00:00 2001 From: innerthunder <168692175+innerthunder@users.noreply.github.com> Date: Thu, 27 Jun 2024 12:21:24 -0700 Subject: [PATCH] [Bug] Fix Make It Rain applying effects for each target (#2664) * Fix Make It Rain applying effects for each target * Revert MoneyAttr change * Remove RNG from parental bond tests --- src/data/move.ts | 13 ++++- src/test/abilities/parental_bond.test.ts | 4 +- src/test/moves/make_it_rain.test.ts | 60 ++++++++++++++++++++++++ 3 files changed, 73 insertions(+), 4 deletions(-) create mode 100644 src/test/moves/make_it_rain.test.ts diff --git a/src/data/move.ts b/src/data/move.ts index a62a6073064..07490290bea 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -1,5 +1,5 @@ import { ChargeAnim, MoveChargeAnim, initMoveAnim, loadMoveAnimAssets } from "./battle-anims"; -import { BattleEndPhase, MovePhase, NewBattlePhase, PartyStatusCurePhase, PokemonHealPhase, StatChangePhase, SwitchSummonPhase } from "../phases"; +import { BattleEndPhase, MoveEffectPhase, MovePhase, NewBattlePhase, PartyStatusCurePhase, PokemonHealPhase, StatChangePhase, SwitchSummonPhase } from "../phases"; import { BattleStat, getBattleStatName } from "./battle-stat"; import { EncoreTag, SemiInvulnerableTag } from "./battler-tags"; import { getPokemonMessage, getPokemonNameWithAffix } from "../messages"; @@ -5513,6 +5513,15 @@ const userSleptOrComatoseCondition: MoveConditionFunc = (user: Pokemon, target: const targetSleptOrComatoseCondition: MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => target.status?.effect === StatusEffect.SLEEP || target.hasAbility(Abilities.COMATOSE); +const lastTargetOnlyCondition: MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => { + const effectPhase = user.scene.getCurrentPhase(); + + if (effectPhase instanceof MoveEffectPhase) { + return target === effectPhase.getTargets().at(-1); + } + return false; +}; + export type MoveAttrFilter = (attr: MoveAttr) => boolean; function applyMoveAttrsInternal(attrFilter: MoveAttrFilter, user: Pokemon, target: Pokemon, move: Move, args: any[]): Promise { @@ -8260,7 +8269,7 @@ export function initMoves() { .attr(RemoveScreensAttr), new AttackMove(Moves.MAKE_IT_RAIN, Type.STEEL, MoveCategory.SPECIAL, 120, 100, 5, -1, 0, 9) .attr(MoneyAttr) - .attr(StatChangeAttr, BattleStat.SPATK, -1, true, null, true, false) + .attr(StatChangeAttr, BattleStat.SPATK, -1, true, lastTargetOnlyCondition, true, false) .target(MoveTarget.ALL_NEAR_ENEMIES), new AttackMove(Moves.PSYBLADE, Type.PSYCHIC, MoveCategory.PHYSICAL, 80, 100, 15, -1, 0, 9) .attr(MovePowerMultiplierAttr, (user, target, move) => user.scene.arena.getTerrainType() === TerrainType.ELECTRIC && user.isGrounded() ? 1.5 : 1) diff --git a/src/test/abilities/parental_bond.test.ts b/src/test/abilities/parental_bond.test.ts index 4e9a0573505..c4f8126d7a0 100644 --- a/src/test/abilities/parental_bond.test.ts +++ b/src/test/abilities/parental_bond.test.ts @@ -382,7 +382,7 @@ describe("Abilities - Parental Bond", () => { expect(leadPokemon.turnData.hitCount).toBe(2); - await game.phaseInterceptor.to(TurnEndPhase); + await game.phaseInterceptor.to(MoveEndPhase, false); expect(enemyPokemon.hp).toBe(Math.ceil(enemyStartingHp * 0.25)); }, TIMEOUT @@ -413,7 +413,7 @@ describe("Abilities - Parental Bond", () => { expect(leadPokemon.turnData.hitCount).toBe(2); - await game.phaseInterceptor.to(TurnEndPhase); + await game.phaseInterceptor.to(MoveEndPhase, false); expect(enemyPokemon.hp).toBe(enemyStartingHp - 200); }, TIMEOUT diff --git a/src/test/moves/make_it_rain.test.ts b/src/test/moves/make_it_rain.test.ts new file mode 100644 index 00000000000..1fe1bb4008b --- /dev/null +++ b/src/test/moves/make_it_rain.test.ts @@ -0,0 +1,60 @@ +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; +import Phaser from "phaser"; +import GameManager from "#app/test/utils/gameManager"; +import * as overrides from "#app/overrides"; +import { Species } from "#enums/species"; +import { + CommandPhase, + MoveEndPhase, +} from "#app/phases"; +import { Moves } from "#enums/moves"; +import { getMovePosition } from "#app/test/utils/gameManagerUtils"; +import { Abilities } from "#enums/abilities"; +import { BattleStat } from "#app/data/battle-stat.js"; + +describe("Moves - Make It Rain", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + vi.spyOn(overrides, "DOUBLE_BATTLE_OVERRIDE", "get").mockReturnValue(true); + vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.MAKE_IT_RAIN, Moves.SPLASH]); + vi.spyOn(overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.SNORLAX); + vi.spyOn(overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.INSOMNIA); + vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.SPLASH, Moves.SPLASH, Moves.SPLASH, Moves.SPLASH]); + vi.spyOn(overrides, "STARTING_LEVEL_OVERRIDE", "get").mockReturnValue(100); + vi.spyOn(overrides, "OPP_LEVEL_OVERRIDE", "get").mockReturnValue(100); + }); + + it("should only reduce Sp. Atk. once in a double battle", async () => { + await game.startBattle([Species.CHARIZARD, Species.BLASTOISE]); + + const playerPokemon = game.scene.getPlayerField(); + expect(playerPokemon.length).toBe(2); + playerPokemon.forEach(p => expect(p).toBeDefined()); + + const enemyPokemon = game.scene.getEnemyField(); + expect(enemyPokemon.length).toBe(2); + enemyPokemon.forEach(p => expect(p).toBeDefined()); + + game.doAttack(getMovePosition(game.scene, 0, Moves.MAKE_IT_RAIN)); + + await game.phaseInterceptor.to(CommandPhase); + game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + + await game.phaseInterceptor.to(MoveEndPhase); + + expect(playerPokemon[0].summonData.battleStats[BattleStat.SPATK]).toBe(-1); + }); +});