diff --git a/src/phases/weather-effect-phase.ts b/src/phases/weather-effect-phase.ts index 71ca7f9b505..ccfc9abb64f 100644 --- a/src/phases/weather-effect-phase.ts +++ b/src/phases/weather-effect-phase.ts @@ -1,10 +1,11 @@ -import BattleScene from "#app/battle-scene.js"; +import BattleScene from "#app/battle-scene"; import { applyPreWeatherEffectAbAttrs, SuppressWeatherEffectAbAttr, PreWeatherDamageAbAttr, applyAbAttrs, BlockNonDirectDamageAbAttr, applyPostWeatherLapseAbAttrs, PostWeatherLapseAbAttr } from "#app/data/ability.js"; -import { CommonAnim } from "#app/data/battle-anims.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"; -import * as Utils from "#app/utils.js"; +import { CommonAnim } from "#app/data/battle-anims"; +import { Weather, getWeatherDamageMessage, getWeatherLapseMessage } from "#app/data/weather"; +import { BattlerTagType } from "#app/enums/battler-tag-type.js"; +import { WeatherType } from "#app/enums/weather-type"; +import Pokemon, { HitResult } from "#app/field/pokemon"; +import * as Utils from "#app/utils"; import { CommonAnimPhase } from "./common-anim-phase"; export class WeatherEffectPhase extends CommonAnimPhase { @@ -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(BattlerTagType.UNDERGROUND) || pokemon.getTag(BattlerTagType.UNDERWATER)) { 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..75125b3448c --- /dev/null +++ b/src/test/arena/weather_hail.test.ts @@ -0,0 +1,62 @@ +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"; +import { BattlerIndex } from "#app/battle"; + +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.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); + + 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 underwater (Dive) or underground (Dig)", async () => { + game.override.moveset([Moves.DIG]); + await game.classicMode.startBattle([Species.MAGIKARP]); + + game.move.select(Moves.DIG); + await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); + + 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..978774ba4c1 --- /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 underwater (Dive) or underground (Dig)", async () => { + game.override.moveset([Moves.DIVE]); + await game.classicMode.startBattle([Species.MAGIKARP]); + + game.move.select(Moves.DIVE); + + 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)); + }); +});