diff --git a/src/phases/weather-effect-phase.ts b/src/phases/weather-effect-phase.ts index 71ca7f9b505..a0900f4fa33 100644 --- a/src/phases/weather-effect-phase.ts +++ b/src/phases/weather-effect-phase.ts @@ -1,6 +1,7 @@ import BattleScene from "#app/battle-scene.js"; import { applyPreWeatherEffectAbAttrs, SuppressWeatherEffectAbAttr, PreWeatherDamageAbAttr, applyAbAttrs, BlockNonDirectDamageAbAttr, applyPostWeatherLapseAbAttrs, PostWeatherLapseAbAttr } from "#app/data/ability.js"; import { CommonAnim } from "#app/data/battle-anims.js"; +import { SemiInvulnerableTag } from "#app/data/battler-tags.js"; import { Weather, getWeatherDamageMessage, getWeatherLapseMessage } from "#app/data/weather.js"; import { WeatherType } from "#app/enums/weather-type.js"; import Pokemon, { HitResult } from "#app/field/pokemon.js"; @@ -39,7 +40,7 @@ export class WeatherEffectPhase extends CommonAnimPhase { applyPreWeatherEffectAbAttrs(PreWeatherDamageAbAttr, pokemon, this.weather, cancelled); applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelled); - if (cancelled.value) { + if (cancelled.value || pokemon.getTag(SemiInvulnerableTag)) { return; } diff --git a/src/test/arena/weather_hail.test.ts b/src/test/arena/weather_hail.test.ts new file mode 100644 index 00000000000..63065bdc2bb --- /dev/null +++ b/src/test/arena/weather_hail.test.ts @@ -0,0 +1,59 @@ +import { WeatherType } from "#app/data/weather"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import { SPLASH_ONLY } from "../utils/testUtils"; + +describe("Weather - Hail", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .weather(WeatherType.HAIL) + .battleType("single") + .moveset(SPLASH_ONLY) + .enemyMoveset(SPLASH_ONLY) + .enemySpecies(Species.MAGIKARP); + }); + + it("inflicts damage equal to 1/16 of Pokemon's max HP at turn end", async () => { + await game.classicMode.startBattle([Species.MAGIKARP]); + + game.move.select(Moves.SPLASH); + + await game.phaseInterceptor.to("TurnEndPhase"); + + game.scene.getField(true).forEach(pokemon => { + expect(pokemon.hp).toBeLessThan(pokemon.getMaxHp() - Math.floor(pokemon.getMaxHp() / 16)); + }); + }); + + it("does not inflict damage to a Pokemon that is in a semi-invulnerable state", async () => { + game.override.moveset([Moves.FLY]); + await game.classicMode.startBattle([Species.MAGIKARP]); + + game.move.select(Moves.FLY); + + await game.phaseInterceptor.to("TurnEndPhase"); + + const playerPokemon = game.scene.getPlayerPokemon()!; + const enemyPokemon = game.scene.getEnemyPokemon()!; + + expect(playerPokemon.hp).toBe(playerPokemon.getMaxHp()); + expect(enemyPokemon.hp).toBeLessThan(enemyPokemon.getMaxHp() - Math.floor(enemyPokemon.getMaxHp() / 16)); + }); +}); diff --git a/src/test/arena/weather_sandstorm.test.ts b/src/test/arena/weather_sandstorm.test.ts new file mode 100644 index 00000000000..475694eb45f --- /dev/null +++ b/src/test/arena/weather_sandstorm.test.ts @@ -0,0 +1,59 @@ +import { WeatherType } from "#app/data/weather"; +import { Moves } from "#enums/moves"; +import { Species } from "#enums/species"; +import GameManager from "#test/utils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; +import { SPLASH_ONLY } from "../utils/testUtils"; + +describe("Weather - Sandstorm", () => { + let phaserGame: Phaser.Game; + let game: GameManager; + + beforeAll(() => { + phaserGame = new Phaser.Game({ + type: Phaser.HEADLESS, + }); + }); + + afterEach(() => { + game.phaseInterceptor.restoreOg(); + }); + + beforeEach(() => { + game = new GameManager(phaserGame); + game.override + .weather(WeatherType.SANDSTORM) + .battleType("single") + .moveset(SPLASH_ONLY) + .enemyMoveset(SPLASH_ONLY) + .enemySpecies(Species.MAGIKARP); + }); + + it("inflicts damage equal to 1/16 of Pokemon's max HP at turn end", async () => { + await game.classicMode.startBattle([Species.MAGIKARP]); + + game.move.select(Moves.SPLASH); + + await game.phaseInterceptor.to("TurnEndPhase"); + + game.scene.getField(true).forEach(pokemon => { + expect(pokemon.hp).toBeLessThan(pokemon.getMaxHp() - Math.floor(pokemon.getMaxHp() / 16)); + }); + }); + + it("does not inflict damage to a Pokemon that is in a semi-invulnerable state", async () => { + game.override.moveset([Moves.FLY]); + await game.classicMode.startBattle([Species.MAGIKARP]); + + game.move.select(Moves.FLY); + + await game.phaseInterceptor.to("TurnEndPhase"); + + const playerPokemon = game.scene.getPlayerPokemon()!; + const enemyPokemon = game.scene.getEnemyPokemon()!; + + expect(playerPokemon.hp).toBe(playerPokemon.getMaxHp()); + expect(enemyPokemon.hp).toBeLessThan(enemyPokemon.getMaxHp() - Math.floor(enemyPokemon.getMaxHp() / 16)); + }); +});