From 57b5c33c4b0534ece39b797eafbc638b8721466d Mon Sep 17 00:00:00 2001 From: Adrian T <68144167+torranx@users.noreply.github.com> Date: Tue, 18 Jun 2024 03:37:11 +0800 Subject: [PATCH] [Ability] Implement Screen Cleaner (#2346) * implement screen cleaner * add documentation * add unit tests * rename arena to arenaTag --- src/data/ability.ts | 24 ++++++- src/test/abilities/screen_cleaner.test.ts | 83 +++++++++++++++++++++++ 2 files changed, 106 insertions(+), 1 deletion(-) create mode 100644 src/test/abilities/screen_cleaner.test.ts diff --git a/src/data/ability.ts b/src/data/ability.ts index 3280f81dd6d..e11c891db4b 100755 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -1632,6 +1632,28 @@ export class PostSummonAbAttr extends AbAttr { return false; } } +/** + * Removes specified arena tags when a Pokemon is summoned. + */ +export class PostSummonRemoveArenaTagAbAttr extends PostSummonAbAttr { + private arenaTags: ArenaTagType[]; + + /** + * @param arenaTags {@linkcode ArenaTagType[]} - the arena tags to be removed + */ + constructor(arenaTags: ArenaTagType[]) { + super(true); + + this.arenaTags = arenaTags; + } + + applyPostSummon(pokemon: Pokemon, passive: boolean, args: any[]): boolean | Promise { + for (const arenaTag of this.arenaTags) { + pokemon.scene.arena.removeTag(arenaTag); + } + return true; + } +} export class PostSummonMessageAbAttr extends PostSummonAbAttr { private messageFunc: (pokemon: Pokemon) => string; @@ -4642,7 +4664,7 @@ export function initAbilities() { new Ability(Abilities.MIMICRY, 8) .unimplemented(), new Ability(Abilities.SCREEN_CLEANER, 8) - .unimplemented(), + .attr(PostSummonRemoveArenaTagAbAttr, [ArenaTagType.AURORA_VEIL, ArenaTagType.LIGHT_SCREEN, ArenaTagType.REFLECT]), new Ability(Abilities.STEELY_SPIRIT, 8) .attr(MoveTypePowerBoostAbAttr, Type.STEEL) .partial(), diff --git a/src/test/abilities/screen_cleaner.test.ts b/src/test/abilities/screen_cleaner.test.ts new file mode 100644 index 00000000000..1c9943fbfc8 --- /dev/null +++ b/src/test/abilities/screen_cleaner.test.ts @@ -0,0 +1,83 @@ +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 { PostSummonPhase, TurnEndPhase, } from "#app/phases"; +import { Moves } from "#enums/moves"; +import { getMovePosition } from "#app/test/utils/gameManagerUtils"; +import { Abilities } from "#enums/abilities"; +import { ArenaTagType } from "#app/enums/arena-tag-type.js"; + +describe("Abilities - Screen Cleaner", () => { + 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, "SINGLE_BATTLE_OVERRIDE", "get").mockReturnValue(true); + vi.spyOn(overrides, "ABILITY_OVERRIDE", "get").mockReturnValue(Abilities.SCREEN_CLEANER); + }); + + it("removes Aurora Veil", async () => { + vi.spyOn(overrides, "MOVESET_OVERRIDE", "get").mockReturnValue([Moves.HAIL]); + vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.AURORA_VEIL, Moves.AURORA_VEIL, Moves.AURORA_VEIL, Moves.AURORA_VEIL]); + + await game.startBattle([Species.MAGIKARP, Species.MAGIKARP]); + + game.doAttack(getMovePosition(game.scene, 0, Moves.HAIL)); + await game.phaseInterceptor.to(TurnEndPhase); + + expect(game.scene.arena.getTag(ArenaTagType.AURORA_VEIL)).toBeDefined(); + + await game.toNextTurn(); + game.doSwitchPokemon(1); + await game.phaseInterceptor.to(PostSummonPhase); + + expect(game.scene.arena.getTag(ArenaTagType.AURORA_VEIL)).toBeUndefined(); + }); + + it("removes Light Screen", async () => { + vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.LIGHT_SCREEN, Moves.LIGHT_SCREEN, Moves.LIGHT_SCREEN, Moves.LIGHT_SCREEN]); + + await game.startBattle([Species.MAGIKARP, Species.MAGIKARP]); + + game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + await game.phaseInterceptor.to(TurnEndPhase); + + expect(game.scene.arena.getTag(ArenaTagType.LIGHT_SCREEN)).toBeDefined(); + + await game.toNextTurn(); + game.doSwitchPokemon(1); + await game.phaseInterceptor.to(PostSummonPhase); + + expect(game.scene.arena.getTag(ArenaTagType.LIGHT_SCREEN)).toBeUndefined(); + }); + + it("removes Reflect", async () => { + vi.spyOn(overrides, "OPP_MOVESET_OVERRIDE", "get").mockReturnValue([Moves.REFLECT, Moves.REFLECT, Moves.REFLECT, Moves.REFLECT]); + + await game.startBattle([Species.MAGIKARP, Species.MAGIKARP]); + + game.doAttack(getMovePosition(game.scene, 0, Moves.SPLASH)); + await game.phaseInterceptor.to(TurnEndPhase); + + expect(game.scene.arena.getTag(ArenaTagType.REFLECT)).toBeDefined(); + + await game.toNextTurn(); + game.doSwitchPokemon(1); + await game.phaseInterceptor.to(PostSummonPhase); + + expect(game.scene.arena.getTag(ArenaTagType.REFLECT)).toBeUndefined(); + }); +});