From 4c4e2bc792f1744582227af18f6a57ddec06b543 Mon Sep 17 00:00:00 2001 From: innerthunder <168692175+innerthunder@users.noreply.github.com> Date: Wed, 3 Jul 2024 09:49:12 -0700 Subject: [PATCH] [Bug] Fix evasion multiplier in hit check (#2765) * Fix evasion multiplier in hit check * Make Sand Veil test more future-proof --- src/phases.ts | 2 +- src/test/abilities/sand_veil.test.ts | 83 +++++++++++++++++++++ src/test/lokalisation/status-effect.test.ts | 3 +- 3 files changed, 85 insertions(+), 3 deletions(-) create mode 100644 src/test/abilities/sand_veil.test.ts diff --git a/src/phases.ts b/src/phases.ts index 9f069a60dc5..dd400c22076 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -3095,7 +3095,7 @@ export class MoveEffectPhase extends PokemonPhase { applyBattleStatMultiplierAbAttrs(BattleStatMultiplierAbAttr, user, BattleStat.ACC, accuracyMultiplier, this.move.getMove()); const evasionMultiplier = new Utils.NumberHolder(1); - applyBattleStatMultiplierAbAttrs(BattleStatMultiplierAbAttr, this.getTarget(), BattleStat.EVA, evasionMultiplier); + applyBattleStatMultiplierAbAttrs(BattleStatMultiplierAbAttr, target, BattleStat.EVA, evasionMultiplier); accuracyMultiplier.value /= evasionMultiplier.value; diff --git a/src/test/abilities/sand_veil.test.ts b/src/test/abilities/sand_veil.test.ts new file mode 100644 index 00000000000..221d48d3ca1 --- /dev/null +++ b/src/test/abilities/sand_veil.test.ts @@ -0,0 +1,83 @@ +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest"; +import GameManager from "../utils/gameManager"; +import * as Overrides from "#app/overrides"; +import { Species } from "#enums/species"; +import { Abilities } from "#enums/abilities"; +import { Moves } from "#enums/moves"; +import { getMovePosition } from "../utils/gameManagerUtils"; +import { CommandPhase, MoveEffectPhase, MoveEndPhase } from "#app/phases.js"; +import { BattleStat } from "#app/data/battle-stat.js"; +import { WeatherType } from "#app/data/weather.js"; +import { BattleStatMultiplierAbAttr, allAbilities } from "#app/data/ability.js"; + +const TIMEOUT = 20 * 1000; + +describe("Abilities - Sand Veil", () => { + 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.SPLASH]); + vi.spyOn(Overrides, "OPP_SPECIES_OVERRIDE", "get").mockReturnValue(Species.MEOWSCARADA); + vi.spyOn(Overrides, "OPP_ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.INSOMNIA); + vi.spyOn(Overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.TWISTER, Moves.TWISTER, Moves.TWISTER, Moves.TWISTER]); + vi.spyOn(Overrides, "STARTING_LEVEL_OVERRIDE", "get").mockReturnValue(100); + vi.spyOn(Overrides, "OPP_LEVEL_OVERRIDE", "get").mockReturnValue(100); + vi.spyOn(Overrides, "WEATHER_OVERRIDE", "get").mockReturnValue(WeatherType.SANDSTORM); + }); + + test( + "ability should increase the evasiveness of the source", + async () => { + await game.startBattle([Species.SNORLAX, Species.BLISSEY]); + + const leadPokemon = game.scene.getPlayerField(); + leadPokemon.forEach(p => expect(p).toBeDefined()); + + const enemyPokemon = game.scene.getEnemyField(); + enemyPokemon.forEach(p => expect(p).toBeDefined()); + + vi.spyOn(leadPokemon[0], "getAbility").mockReturnValue(allAbilities[Abilities.SAND_VEIL]); + + const sandVeilAttr = allAbilities[Abilities.SAND_VEIL].getAttrs(BattleStatMultiplierAbAttr)[0]; + vi.spyOn(sandVeilAttr, "applyBattleStat").mockImplementation( + (pokemon, passive, battleStat, statValue, args) => { + if (battleStat === BattleStat.EVA && game.scene.arena.weather?.weatherType === WeatherType.SANDSTORM) { + statValue.value *= -1; // will make all attacks miss + return true; + } + return false; + } + ); + + expect(leadPokemon[0].hasAbility(Abilities.SAND_VEIL)).toBe(true); + expect(leadPokemon[1].hasAbility(Abilities.SAND_VEIL)).toBe(false); + + game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + + await game.phaseInterceptor.to(CommandPhase); + + game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH)); + + await game.phaseInterceptor.to(MoveEffectPhase, false); + + await game.phaseInterceptor.to(MoveEndPhase, false); + + expect(leadPokemon[0].hp).toBe(leadPokemon[0].getMaxHp()); + expect(leadPokemon[1].hp).toBeLessThan(leadPokemon[1].getMaxHp()); + }, TIMEOUT + ); +}); diff --git a/src/test/lokalisation/status-effect.test.ts b/src/test/lokalisation/status-effect.test.ts index 4c79dacbff7..b4267ea7b8b 100644 --- a/src/test/lokalisation/status-effect.test.ts +++ b/src/test/lokalisation/status-effect.test.ts @@ -1,4 +1,4 @@ -import { beforeAll, describe, expect, it, vi } from "vitest"; +import { beforeAll, describe, afterEach, expect, it, vi } from "vitest"; import { StatusEffect, getStatusEffectActivationText, @@ -8,7 +8,6 @@ import { getStatusEffectOverlapText, } from "#app/data/status-effect"; import i18next, { ParseKeys } from "i18next"; -import { afterEach } from "node:test"; const tMock = (key: ParseKeys) => key; const pokemonName = "PKM";