diff --git a/src/test/abilities/wimp_out.test.ts b/src/test/abilities/wimp_out.test.ts index 81290fb5b72..e2be51f2e66 100644 --- a/src/test/abilities/wimp_out.test.ts +++ b/src/test/abilities/wimp_out.test.ts @@ -1,16 +1,15 @@ import { BattlerIndex } from "#app/battle"; import { ArenaTagSide } from "#app/data/arena-tag"; import { allMoves } from "#app/data/move"; -import { Abilities } from "#app/enums/abilities"; -import { ArenaTagType } from "#app/enums/arena-tag-type"; -import { BattlerTagType } from "#app/enums/battler-tag-type"; -import { Stat } from "#app/enums/stat"; -import { StatusEffect } from "#app/enums/status-effect"; -import { WeatherType } from "#app/enums/weather-type"; -import { TurnEndPhase } from "#app/phases/turn-end-phase"; import GameManager from "#app/test/utils/gameManager"; +import { Abilities } from "#enums/abilities"; +import { ArenaTagType } from "#enums/arena-tag-type"; +import { BattlerTagType } from "#enums/battler-tag-type"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; +import { Stat } from "#enums/stat"; +import { StatusEffect } from "#enums/status-effect"; +import { WeatherType } from "#enums/weather-type"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; @@ -34,233 +33,219 @@ describe("Abilities - Wimp Out", () => { .battleType("single") .ability(Abilities.WIMP_OUT) .enemySpecies(Species.NINJASK) + .enemyPassiveAbility(Abilities.NO_GUARD) .startingLevel(90) - .startingWave(97) - .moveset([ Moves.SPLASH ]) + .enemyLevel(70) + .moveset([ Moves.SPLASH, Moves.FALSE_SWIPE, Moves.ENDURE ]) .enemyMoveset(Moves.FALSE_SWIPE) .disableCrits(); }); + function confirmSwitch(): void { + const [ pokemon1, pokemon2 ] = game.scene.getParty(); + + expect(game.phaseInterceptor.log).toContain("SwitchSummonPhase"); + + expect(pokemon1.species.speciesId).not.toBe(Species.WIMPOD); + + expect(pokemon2.species.speciesId).toBe(Species.WIMPOD); + expect(pokemon2.isFainted()).toBe(false); + expect(pokemon2.getHpRatio()).toBeLessThan(0.5); + } + + function confirmNoSwitch(): void { + const [ pokemon1, pokemon2 ] = game.scene.getParty(); + + expect(game.phaseInterceptor.log).not.toContain("SwitchSummonPhase"); + + expect(pokemon2.species.speciesId).not.toBe(Species.WIMPOD); + + expect(pokemon1.species.speciesId).toBe(Species.WIMPOD); + expect(pokemon1.isFainted()).toBe(false); + expect(pokemon1.getHpRatio()).toBeLessThan(0.5); + } + it("triggers regenerator passive single time when switching out with wimp out", async () => { - // arrange game.override .passiveAbility(Abilities.REGENERATOR) .startingLevel(5) .enemyLevel(100); - await game.startBattle([ + await game.classicMode.startBattle([ Species.WIMPOD, Species.TYRUNT ]); - // act - game.move.select(Moves.FALSE_SWIPE); - game.doSelectPartyPokemon(1); - await game.phaseInterceptor.to(TurnEndPhase); + const wimpod = game.scene.getPlayerPokemon()!; - // assert - expect(game.scene.getParty()[1].hp).toEqual(Math.floor(game.scene.getParty()[1].getMaxHp() * 0.33 + 1)); - expect(game.phaseInterceptor.log).toContain("SwitchSummonPhase"); - expect(game.scene.getPlayerPokemon()!.species.speciesId).toBe(Species.TYRUNT); + game.move.select(Moves.SPLASH); + game.doSelectPartyPokemon(1); + await game.phaseInterceptor.to("TurnEndPhase"); + + expect(wimpod.hp).toEqual(Math.floor(wimpod.getMaxHp() * 0.33 + 1)); + confirmSwitch(); }); + it("It makes wild pokemon flee if triggered", async () => { - // arrange - game.override - .enemyAbility(Abilities.WIMP_OUT) - .startingLevel(150) - .moveset([ Moves.FALSE_SWIPE ]); - await game.startBattle([ + game.override.enemyAbility(Abilities.WIMP_OUT); + await game.classicMode.startBattle([ Species.GOLISOPOD, Species.TYRUNT ]); - // act + const enemyPokemon = game.scene.getEnemyPokemon()!; + game.move.select(Moves.FALSE_SWIPE); await game.phaseInterceptor.to("BerryPhase"); - // assert - const enemyPokemon = game.scene.getEnemyPokemon()!; const isVisible = enemyPokemon.visible; const hasFled = enemyPokemon.switchOutStatus; expect(!isVisible && hasFled).toBe(true); }); it("Does not trigger when HP already below half", async () => { - // arrange - game.override.moveset([ Moves.SPLASH ]); - const playerHp = 5; - await game.startBattle([ + await game.classicMode.startBattle([ Species.WIMPOD, Species.TYRUNT ]); - game.scene.getPlayerPokemon()!.hp = playerHp; + const wimpod = game.scene.getPlayerPokemon()!; + wimpod.hp = 5; - - // act - game.move.select(Moves.FALSE_SWIPE); game.move.select(Moves.SPLASH); - await game.phaseInterceptor.to(TurnEndPhase); + await game.phaseInterceptor.to("TurnEndPhase"); - // assert - expect(game.scene.getParty()[0].hp).toEqual(1); - expect(game.phaseInterceptor.log).not.toContain("SwitchSummonPhase"); - expect(game.scene.getPlayerPokemon()!.species.speciesId).toBe(Species.WIMPOD); + expect(wimpod.hp).toEqual(1); + confirmNoSwitch(); }); + it("Trapping moves do not prevent Wimp Out from activating.", async () => { - // arrange game.override .enemyMoveset([ Moves.SPIRIT_SHACKLE ]) .startingLevel(53) .enemyLevel(45); - await game.startBattle([ + await game.classicMode.startBattle([ Species.WIMPOD, Species.TYRUNT ]); - // act - game.move.select(Moves.SPIRIT_SHACKLE); + game.move.select(Moves.SPLASH); game.doSelectPartyPokemon(1); + await game.phaseInterceptor.to("TurnEndPhase"); - await game.phaseInterceptor.to(TurnEndPhase); - - // assert expect(game.phaseInterceptor.log).toContain("SwitchSummonPhase"); expect(game.scene.getPlayerPokemon()!.getTag(BattlerTagType.TRAPPED)).toBeUndefined(); - expect(game.scene.getPlayerPokemon()!.species.speciesId).toBe(Species.TYRUNT); + expect(game.scene.getParty()[1].getTag(BattlerTagType.TRAPPED)).toBeUndefined(); + confirmSwitch(); }); it("If this Ability activates due to being hit by U-turn or Volt Switch, the user of that move will not be switched out.", async () => { - // arrange game.override .startingLevel(95) .enemyMoveset([ Moves.U_TURN ]); - await game.startBattle([ + await game.classicMode.startBattle([ Species.WIMPOD, Species.TYRUNT ]); - // act - game.move.select(Moves.U_TURN); + game.move.select(Moves.SPLASH); game.doSelectPartyPokemon(1); - await game.phaseInterceptor.to(TurnEndPhase); + await game.phaseInterceptor.to("TurnEndPhase"); - // assert const enemyPokemon = game.scene.getEnemyPokemon()!; const hasFled = enemyPokemon.switchOutStatus; expect(hasFled).toBe(false); - expect(game.scene.getParty()[1].getHpRatio()).toBeLessThan(0.5); - expect(game.phaseInterceptor.log).toContain("SwitchSummonPhase"); - expect(game.scene.getPlayerPokemon()!.species.speciesId).toBe(Species.TYRUNT); + confirmSwitch(); }); it("If this Ability does not activate due to being hit by U-turn or Volt Switch, the user of that move will be switched out.", async () => { - // arrange game.override .startingLevel(190) - .moveset([ Moves.SPLASH ]) .enemyMoveset([ Moves.U_TURN ]); - await game.startBattle([ + await game.classicMode.startBattle([ Species.GOLISOPOD, Species.TYRUNT ]); - // act game.move.select(Moves.SPLASH); - game.move.select(Moves.U_TURN); - await game.phaseInterceptor.to(TurnEndPhase); + await game.phaseInterceptor.to("TurnEndPhase"); - // assert const enemyPokemon = game.scene.getEnemyPokemon()!; const hasFled = enemyPokemon.switchOutStatus; expect(hasFled).toBe(true); }); + it("Dragon Tail and Circle Throw switch out Pokémon before the Ability activates.", async () => { - // arrange game.override .startingLevel(69) - .moveset([ Moves.SPLASH ]) .enemyMoveset([ Moves.DRAGON_TAIL ]); - await game.startBattle([ + await game.classicMode.startBattle([ Species.WIMPOD, Species.TYRUNT ]); - vi.spyOn(allMoves[Moves.DRAGON_TAIL], "accuracy", "get").mockReturnValue(100); + const wimpod = game.scene.getPlayerPokemon()!; - // act - game.move.select(Moves.DRAGON_TAIL); + game.move.select(Moves.SPLASH); game.doSelectPartyPokemon(1); - await game.phaseInterceptor.to(TurnEndPhase); - // assert - expect(game.scene.getParty()[1].getHpRatio()).toBeLessThan(0.5); + await game.phaseInterceptor.to("SwitchSummonPhase", false); + + expect(wimpod.summonData.abilitiesApplied).not.toContain(Abilities.WIMP_OUT); + + await game.phaseInterceptor.to("TurnEndPhase"); + + expect(game.scene.getPlayerPokemon()!.species.speciesId).not.toBe(Species.WIMPOD); }); + it("triggers when recoil damage is taken", async () => { - // arrange game.override .moveset([ Moves.HEAD_SMASH ]) .enemyMoveset([ Moves.SPLASH ]); - await game.startBattle([ + await game.classicMode.startBattle([ Species.WIMPOD, Species.TYRUNT ]); - vi.spyOn(allMoves[Moves.HEAD_SMASH], "accuracy", "get").mockReturnValue(100); - - // act game.move.select(Moves.HEAD_SMASH); game.doSelectPartyPokemon(1); - await game.phaseInterceptor.to(TurnEndPhase); + await game.phaseInterceptor.to("TurnEndPhase"); - // assert - expect(game.scene.getParty()[1].getHpRatio()).toBeLessThan(0.5); - expect(game.phaseInterceptor.log).toContain("SwitchSummonPhase"); - expect(game.scene.getPlayerPokemon()!.species.speciesId).toBe(Species.TYRUNT); + confirmSwitch(); }); + it("It does not activate when the Pokémon cuts its own HP", async () => { - // arrange game.override .moveset([ Moves.SUBSTITUTE ]) .enemyMoveset([ Moves.SPLASH ]); - await game.startBattle([ + await game.classicMode.startBattle([ Species.WIMPOD, Species.TYRUNT ]); - const playerHp = game.scene.getPlayerPokemon()!.hp; - game.scene.getPlayerPokemon()!.hp = playerHp * 0.52; + const wimpod = game.scene.getPlayerPokemon()!; + wimpod.hp *= 0.52; - // act game.move.select(Moves.SUBSTITUTE); - game.move.select(Moves.SPLASH); - await game.phaseInterceptor.to(TurnEndPhase); + await game.phaseInterceptor.to("TurnEndPhase"); - // assert - expect(game.scene.getParty()[0].getHpRatio()).toBeLessThan(0.5); - expect(game.phaseInterceptor.log).not.toContain("SwitchSummonPhase"); - expect(game.scene.getPlayerPokemon()!.species.speciesId).toBe(Species.WIMPOD); + confirmNoSwitch(); }); + it("Does not trigger when neutralized", async () => { - // arrange game.override .enemyAbility(Abilities.NEUTRALIZING_GAS) .startingLevel(5); - await game.startBattle([ + await game.classicMode.startBattle([ Species.WIMPOD, Species.TYRUNT ]); - // act - game.move.select(Moves.FALSE_SWIPE); - await game.phaseInterceptor.to(TurnEndPhase); + game.move.select(Moves.SPLASH); + await game.phaseInterceptor.to("TurnEndPhase"); - // assert - const playerPkm = game.scene.getPlayerPokemon()!; - expect(playerPkm.species.speciesId).toEqual(Species.WIMPOD); - expect(playerPkm.getHpRatio()).toBeLessThan(0.5); - expect(game.phaseInterceptor.log).not.toContain("SwitchSummonPhase"); + confirmNoSwitch(); }); + it("If it falls below half and recovers back above half from a Shell Bell, Wimp Out will activate even after the Shell Bell recovery", async () => { - // arrange game.override .moveset([ Moves.DOUBLE_EDGE ]) .enemyMoveset([ Moves.SPLASH ]) @@ -268,261 +253,198 @@ describe("Abilities - Wimp Out", () => { { name: "SHELL_BELL", count: 3 }, { name: "HEALING_CHARM", count: 5 }, ]); - await game.startBattle([ + await game.classicMode.startBattle([ Species.WIMPOD, Species.TYRUNT ]); - const playerHp = game.scene.getPlayerPokemon()!.hp; - game.scene.getPlayerPokemon()!.hp = playerHp * 0.75; - // act + game.scene.getPlayerPokemon()!.hp *= 0.75; + game.move.select(Moves.DOUBLE_EDGE); game.doSelectPartyPokemon(1); - await game.phaseInterceptor.to(TurnEndPhase); + await game.phaseInterceptor.to("TurnEndPhase"); - // assert expect(game.scene.getParty()[1].getHpRatio()).toBeGreaterThan(0.5); expect(game.phaseInterceptor.log).toContain("SwitchSummonPhase"); expect(game.scene.getPlayerPokemon()!.species.speciesId).toBe(Species.TYRUNT); }); + it("Wimp Out will activate due to weather damage", async () => { - // arrange game.override - .moveset([ Moves.SPLASH ]) .weather(WeatherType.HAIL) .enemyMoveset([ Moves.SPLASH ]); - await game.startBattle([ + await game.classicMode.startBattle([ Species.WIMPOD, Species.TYRUNT ]); - const playerHp = game.scene.getPlayerPokemon()!.hp; - game.scene.getPlayerPokemon()!.hp = playerHp * 0.51; - // act + game.scene.getPlayerPokemon()!.hp *= 0.51; + game.move.select(Moves.SPLASH); game.doSelectPartyPokemon(1); - await game.phaseInterceptor.to(TurnEndPhase); + await game.phaseInterceptor.to("TurnEndPhase"); - // assert - expect(game.scene.getParty()[1].getHpRatio()).toBeLessThan(0.5); - expect(game.phaseInterceptor.log).toContain("SwitchSummonPhase"); - expect(game.scene.getPlayerPokemon()!.species.speciesId).toBe(Species.TYRUNT); + confirmSwitch(); }); + it("Does not trigger when enemy has sheer force", async () => { - // arrange game.override .enemyAbility(Abilities.SHEER_FORCE) .enemyMoveset(Moves.SLUDGE_BOMB) .startingLevel(95); - await game.startBattle([ + await game.classicMode.startBattle([ Species.WIMPOD, Species.TYRUNT ]); - // act - game.move.select(Moves.SLUDGE_BOMB); game.move.select(Moves.SPLASH); - await game.phaseInterceptor.to(TurnEndPhase); + await game.phaseInterceptor.to("TurnEndPhase"); - // assert - const playerPkm = game.scene.getPlayerPokemon()!; - expect(playerPkm.species.speciesId).toEqual(Species.WIMPOD); - expect(playerPkm.getHpRatio()).toBeLessThan(0.5); - expect(game.phaseInterceptor.log).not.toContain("SwitchSummonPhase"); + confirmNoSwitch(); }); + it("Wimp Out will activate due to post turn status damage", async () => { - // arrange game.override - .moveset([ Moves.SPLASH ]) .statusEffect(StatusEffect.POISON) .enemyMoveset([ Moves.SPLASH ]); - await game.startBattle([ + await game.classicMode.startBattle([ Species.WIMPOD, Species.TYRUNT ]); - const playerHp = game.scene.getPlayerPokemon()!.hp; - game.scene.getPlayerPokemon()!.hp = playerHp * 0.51; - // act + game.scene.getPlayerPokemon()!.hp *= 0.51; + game.move.select(Moves.SPLASH); game.doSelectPartyPokemon(1); await game.toNextTurn(); - - // assert - expect(game.scene.getParty()[1].getHpRatio()).toBeLessThan(0.5); - expect(game.phaseInterceptor.log).toContain("SwitchSummonPhase"); - expect(game.scene.getPlayerPokemon()!.species.speciesId).toBe(Species.TYRUNT); + confirmSwitch(); }); + it("Wimp Out will activate due to bad dreams", async () => { - // arrange game.override - .moveset([ Moves.SPLASH ]) .statusEffect(StatusEffect.SLEEP) .enemyAbility(Abilities.BAD_DREAMS); - await game.startBattle([ + await game.classicMode.startBattle([ Species.WIMPOD, Species.TYRUNT ]); - const playerHp = game.scene.getPlayerPokemon()!.hp; - game.scene.getPlayerPokemon()!.hp = playerHp * 0.52; - // act + game.scene.getPlayerPokemon()!.hp *= 0.52; + game.move.select(Moves.SPLASH); game.doSelectPartyPokemon(1); await game.toNextTurn(); - // assert - expect(game.scene.getParty()[1].getHpRatio()).toBeGreaterThan(0); - expect(game.scene.getParty()[1].getHpRatio()).toBeLessThan(0.5); - expect(game.phaseInterceptor.log).toContain("SwitchSummonPhase"); - expect(game.scene.getPlayerPokemon()!.species.speciesId).toBe(Species.TYRUNT); + confirmSwitch(); }); + it("Wimp Out will activate due to leech seed", async () => { - // arrange game.override - .moveset([ Moves.SPLASH ]) .enemyMoveset([ Moves.LEECH_SEED ]); - await game.startBattle([ + await game.classicMode.startBattle([ Species.WIMPOD, Species.TYRUNT ]); - vi.spyOn(allMoves[Moves.LEECH_SEED], "accuracy", "get").mockReturnValue(100); - const playerHp = game.scene.getPlayerPokemon()!.hp; - game.scene.getPlayerPokemon()!.hp = playerHp * 0.52; + game.scene.getPlayerPokemon()!.hp *= 0.52; - // act - game.move.select(Moves.LEECH_SEED); + game.move.select(Moves.SPLASH); game.doSelectPartyPokemon(1); await game.toNextTurn(); - // assert - expect(game.scene.getParty()[1].getHpRatio()).toBeGreaterThan(0); - expect(game.scene.getParty()[1].getHpRatio()).toBeLessThan(0.5); - expect(game.phaseInterceptor.log).toContain("SwitchSummonPhase"); - expect(game.scene.getPlayerPokemon()!.species.speciesId).toBe(Species.TYRUNT); + confirmSwitch(); }); + it("Wimp Out will activate due to curse damage", async () => { - // arrange game.override - .moveset([ Moves.SPLASH ]) .enemySpecies(Species.DUSKNOIR) .enemyMoveset([ Moves.CURSE ]); - await game.startBattle([ + await game.classicMode.startBattle([ Species.WIMPOD, Species.TYRUNT ]); - const playerHp = game.scene.getPlayerPokemon()!.hp; - game.scene.getPlayerPokemon()!.hp = playerHp * 0.52; + game.scene.getPlayerPokemon()!.hp *= 0.52; - // act - game.move.select(Moves.CURSE); + game.move.select(Moves.SPLASH); game.doSelectPartyPokemon(1); await game.toNextTurn(); - // assert - expect(game.scene.getParty()[1].getHpRatio()).toBeGreaterThan(0); - expect(game.scene.getParty()[1].getHpRatio()).toBeLessThan(0.5); - expect(game.phaseInterceptor.log).toContain("SwitchSummonPhase"); - expect(game.scene.getPlayerPokemon()!.species.speciesId).toBe(Species.TYRUNT); + confirmSwitch(); }); + it("Wimp Out will activate due to salt cure damage", async () => { - // arrange game.override - .moveset([ Moves.SPLASH ]) .enemySpecies(Species.NACLI) .enemyMoveset([ Moves.SALT_CURE ]) .enemyLevel(1); - await game.startBattle([ + await game.classicMode.startBattle([ Species.WIMPOD, Species.TYRUNT ]); - const playerHp = game.scene.getPlayerPokemon()!.hp; - game.scene.getPlayerPokemon()!.hp = playerHp * 0.70; + game.scene.getPlayerPokemon()!.hp *= 0.70; - // act - game.move.select(Moves.SALT_CURE); + game.move.select(Moves.SPLASH); game.doSelectPartyPokemon(1); await game.toNextTurn(); - // assert - expect(game.scene.getParty()[1].getHpRatio()).toBeGreaterThan(0); - expect(game.scene.getParty()[1].getHpRatio()).toBeLessThan(0.5); - expect(game.phaseInterceptor.log).toContain("SwitchSummonPhase"); - expect(game.scene.getPlayerPokemon()!.species.speciesId).toBe(Species.TYRUNT); + confirmSwitch(); }); + it("Wimp Out will activate due to damaging trap damage", async () => { - // arrange game.override - .moveset([ Moves.SPLASH ]) .enemySpecies(Species.MAGIKARP) .enemyMoveset([ Moves.WHIRLPOOL ]) .enemyLevel(1); - await game.startBattle([ + await game.classicMode.startBattle([ Species.WIMPOD, Species.TYRUNT ]); - vi.spyOn(allMoves[Moves.WHIRLPOOL], "accuracy", "get").mockReturnValue(100); - const playerHp = game.scene.getPlayerPokemon()!.hp; - game.scene.getPlayerPokemon()!.hp = playerHp * 0.55; + game.scene.getPlayerPokemon()!.hp *= 0.55; - // act - game.move.select(Moves.WHIRLPOOL); + game.move.select(Moves.SPLASH); game.doSelectPartyPokemon(1); await game.toNextTurn(); - // assert - expect(game.scene.getParty()[1].getHpRatio()).toBeGreaterThan(0); - expect(game.scene.getParty()[1].getHpRatio()).toBeLessThan(0.5); - expect(game.phaseInterceptor.log).toContain("SwitchSummonPhase"); - expect(game.scene.getPlayerPokemon()!.species.speciesId).toBe(Species.TYRUNT); + confirmSwitch(); }); + it("Magic Guard passive should not allow indirect damage to trigger Wimp Out", async () => { - // arrange game.scene.arena.addTag(ArenaTagType.STEALTH_ROCK, 1, Moves.STEALTH_ROCK, 0, ArenaTagSide.ENEMY); game.scene.arena.addTag(ArenaTagType.SPIKES, 1, Moves.SPIKES, 0, ArenaTagSide.ENEMY); game.override .passiveAbility(Abilities.MAGIC_GUARD) - .moveset([ Moves.SPLASH ]) .enemyMoveset([ Moves.LEECH_SEED ]) .weather(WeatherType.HAIL) .statusEffect(StatusEffect.POISON); - await game.startBattle([ + await game.classicMode.startBattle([ Species.WIMPOD, Species.TYRUNT ]); - vi.spyOn(allMoves[Moves.LEECH_SEED], "accuracy", "get").mockReturnValue(100); - const playerHp = game.scene.getPlayerPokemon()!.hp; - game.scene.getPlayerPokemon()!.hp = playerHp * 0.51; + game.scene.getPlayerPokemon()!.hp *= 0.51; - - // act game.move.select(Moves.SPLASH); - game.move.select(Moves.LEECH_SEED); - await game.phaseInterceptor.to(TurnEndPhase); + await game.phaseInterceptor.to("TurnEndPhase"); - // assert expect(game.scene.getParty()[0].getHpRatio()).toEqual(0.51); expect(game.phaseInterceptor.log).not.toContain("SwitchSummonPhase"); expect(game.scene.getPlayerPokemon()!.species.speciesId).toBe(Species.WIMPOD); }); + it("Wimp Out activating should not cancel a double battle", async () => { - // arrange game.override .battleType("double") - .moveset([ Moves.FALSE_SWIPE, Moves.SPLASH ]) .enemyAbility(Abilities.WIMP_OUT) .enemyMoveset([ Moves.SPLASH ]) .enemyLevel(1); - await game.startBattle([ + await game.classicMode.startBattle([ Species.WIMPOD, Species.TYRUNT ]); - const enemyLeadPokemon = game.scene.getEnemyParty()[0]!; - const enemySecPokemon = game.scene.getEnemyParty()[1]!; + const enemyLeadPokemon = game.scene.getEnemyParty()[0]; + const enemySecPokemon = game.scene.getEnemyParty()[1]; game.move.select(Moves.FALSE_SWIPE, 0, BattlerIndex.ENEMY); - game.move.select(Moves.SPLASH, 1, BattlerIndex.ENEMY); + game.move.select(Moves.SPLASH, 1); await game.phaseInterceptor.to("BerryPhase"); @@ -534,142 +456,119 @@ describe("Abilities - Wimp Out", () => { expect(enemyLeadPokemon.hp).toBeLessThan(enemyLeadPokemon.getMaxHp()); expect(enemySecPokemon.hp).toEqual(enemySecPokemon.getMaxHp()); }); + it("Wimp Out will activate due to aftermath", async () => { - // arrange game.override .moveset([ Moves.THUNDER_PUNCH ]) .enemySpecies(Species.MAGIKARP) .enemyAbility(Abilities.AFTERMATH) .enemyMoveset([ Moves.SPLASH ]) .enemyLevel(1); - await game.startBattle([ + await game.classicMode.startBattle([ Species.WIMPOD, Species.TYRUNT ]); - const playerHp = game.scene.getPlayerPokemon()!.hp; - game.scene.getPlayerPokemon()!.hp = playerHp * 0.51; + game.scene.getPlayerPokemon()!.hp *= 0.51; - // act game.move.select(Moves.THUNDER_PUNCH); game.doSelectPartyPokemon(1); - await game.phaseInterceptor.to(TurnEndPhase); + await game.phaseInterceptor.to("TurnEndPhase"); - // assert - expect(game.scene.getParty()[1].getHpRatio()).toBeGreaterThan(0); - expect(game.scene.getParty()[1].getHpRatio()).toBeLessThan(0.5); - expect(game.phaseInterceptor.log).toContain("SwitchSummonPhase"); - expect(game.scene.getPlayerPokemon()!.species.speciesId).toBe(Species.TYRUNT); + confirmSwitch(); }); + it("Activates due to entry hazards", async () => { - // arrange game.scene.arena.addTag(ArenaTagType.STEALTH_ROCK, 1, Moves.STEALTH_ROCK, 0, ArenaTagSide.ENEMY); game.scene.arena.addTag(ArenaTagType.SPIKES, 1, Moves.SPIKES, 0, ArenaTagSide.ENEMY); game.override .enemySpecies(Species.CENTISKORCH) - .enemyAbility(Abilities.WIMP_OUT); - await game.startBattle([ + .enemyAbility(Abilities.WIMP_OUT) + .startingWave(4); + await game.classicMode.startBattle([ Species.TYRUNT ]); - // assert expect(game.phaseInterceptor.log).not.toContain("MovePhase"); expect(game.phaseInterceptor.log).toContain("BattleEndPhase"); }); + it("Wimp Out will activate due to Nightmare", async () => { - // arrange game.override - .moveset([ Moves.SPLASH ]) .enemyMoveset([ Moves.NIGHTMARE ]) .statusEffect(StatusEffect.SLEEP); - await game.startBattle([ + await game.classicMode.startBattle([ Species.WIMPOD, Species.TYRUNT ]); - const playerHp = game.scene.getPlayerPokemon()!.hp; - game.scene.getPlayerPokemon()!.hp = playerHp * 0.65; + game.scene.getPlayerPokemon()!.hp *= 0.65; - // act - game.move.select(Moves.NIGHTMARE); + game.move.select(Moves.SPLASH); game.doSelectPartyPokemon(1); await game.toNextTurn(); - // assert - expect(game.scene.getParty()[1].getHpRatio()).toBeGreaterThan(0); - expect(game.scene.getParty()[1].getHpRatio()).toBeLessThan(0.5); - expect(game.phaseInterceptor.log).toContain("SwitchSummonPhase"); - expect(game.scene.getPlayerPokemon()!.species.speciesId).toBe(Species.TYRUNT); + confirmSwitch(); }); + it("triggers status on the wimp out user before a new pokemon is switched in", async () => { - // arrange game.override .enemyMoveset(Moves.SLUDGE_BOMB) .startingLevel(80); - await game.startBattle([ + await game.classicMode.startBattle([ Species.WIMPOD, Species.TYRUNT ]); - vi.spyOn(game.scene.getEnemyPokemon()!, "randSeedInt").mockReturnValue(0); + vi.spyOn(allMoves[Moves.SLUDGE_BOMB], "chance", "get").mockReturnValue(100); - // act - game.move.select(Moves.SLUDGE_BOMB); + game.move.select(Moves.SPLASH); game.doSelectPartyPokemon(1); - await game.phaseInterceptor.to(TurnEndPhase); + await game.phaseInterceptor.to("TurnEndPhase"); - // assert - const playerPkm = game.scene.getPlayerPokemon()!; expect(game.scene.getParty()[1].status?.effect).toEqual(StatusEffect.POISON); - expect(playerPkm.species.speciesId).toEqual(Species.TYRUNT); - expect(game.phaseInterceptor.log).toContain("SwitchSummonPhase"); + confirmSwitch(); }); + it("triggers after last hit of multi hit move", async () => { - // arrange game.override .enemyMoveset(Moves.BULLET_SEED) - .enemyAbility(Abilities.SKILL_LINK) - .startingLevel(110) - .enemyLevel(80); - await game.startBattle([ + .enemyAbility(Abilities.SKILL_LINK); + await game.classicMode.startBattle([ Species.WIMPOD, Species.TYRUNT ]); - // act - game.move.select(Moves.BULLET_SEED); - game.doSelectPartyPokemon(1); - await game.phaseInterceptor.to(TurnEndPhase); + game.scene.getPlayerPokemon()!.hp *= 0.51; + + game.move.select(Moves.ENDURE); + game.doSelectPartyPokemon(1); + await game.phaseInterceptor.to("TurnEndPhase"); - // assert const enemyPokemon = game.scene.getEnemyPokemon()!; expect(enemyPokemon.turnData.hitsLeft).toBe(0); expect(enemyPokemon.turnData.hitCount).toBe(5); + confirmSwitch(); }); - it.skip("Wimp Out will not activate if the Pokémon's HP falls below half due to hurting itself in confusion", async () => { // This interaction is not implemented yet - // arrange + + // TODO: This interaction is not implemented yet + it.todo("Wimp Out will not activate if the Pokémon's HP falls below half due to hurting itself in confusion", async () => { game.override .moveset([ Moves.SWORDS_DANCE ]) .enemyMoveset([ Moves.SWAGGER ]); - await game.startBattle([ + await game.classicMode.startBattle([ Species.WIMPOD, Species.TYRUNT ]); const playerPokemon = game.scene.getPlayerPokemon()!; - const playerHp = playerPokemon.hp; - playerPokemon.hp = playerHp * 0.51; + playerPokemon.hp *= 0.51; playerPokemon.setStatStage(Stat.ATK, 6); playerPokemon.addTag(BattlerTagType.CONFUSED); - vi.spyOn(playerPokemon, "randSeedInt").mockReturnValue(0); - vi.spyOn(allMoves[Moves.SWAGGER], "accuracy", "get").mockReturnValue(100); - // act + // TODO: add helper function to force confusion self-hits + while (playerPokemon.getHpRatio() > 0.49) { game.move.select(Moves.SWORDS_DANCE); - game.move.select(Moves.SWAGGER); - await game.phaseInterceptor.to(TurnEndPhase); + await game.phaseInterceptor.to("TurnEndPhase"); } - // assert - expect(playerPokemon.getHpRatio()).toBeLessThan(0.5); - expect(game.phaseInterceptor.log).not.toContain("SwitchSummonPhase"); - expect(playerPokemon.species.speciesId).toBe(Species.WIMPOD); + confirmNoSwitch(); }); });