import { BattlerIndex } from "#app/battle"; import { Stat } from "#enums/stat"; import { allMoves, TeraMoveCategoryAttr } from "#app/data/move"; import { Type } from "#enums/type"; import { Abilities } from "#app/enums/abilities"; import { HitResult } from "#app/field/pokemon"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import GameManager from "#test/testUtils/gameManager"; import Phaser from "phaser"; import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; describe("Moves - Tera Blast", () => { let phaserGame: Phaser.Game; let game: GameManager; const moveToCheck = allMoves[Moves.TERA_BLAST]; const teraBlastAttr = moveToCheck.getAttrs(TeraMoveCategoryAttr)[0]; beforeAll(() => { phaserGame = new Phaser.Game({ type: Phaser.HEADLESS, }); }); afterEach(() => { game.phaseInterceptor.restoreOg(); }); beforeEach(() => { game = new GameManager(phaserGame); game.override .battleType("single") .disableCrits() .starterSpecies(Species.FEEBAS) .moveset([ Moves.TERA_BLAST ]) .ability(Abilities.BALL_FETCH) .enemySpecies(Species.MAGIKARP) .enemyMoveset(Moves.SPLASH) .enemyAbility(Abilities.STURDY) .enemyLevel(50); vi.spyOn(moveToCheck, "calculateBattlePower"); }); it("changes type to match user's tera type", async () => { game.override.enemySpecies(Species.FURRET); await game.startBattle(); const enemyPokemon = game.scene.getEnemyPokemon()!; vi.spyOn(enemyPokemon, "apply"); const playerPokemon = game.scene.getPlayerPokemon()!; playerPokemon.teraType = Type.FIGHTING; playerPokemon.isTerastallized = true; game.move.select(Moves.TERA_BLAST); await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]); await game.phaseInterceptor.to("MoveEffectPhase"); expect(enemyPokemon.apply).toHaveReturnedWith(HitResult.SUPER_EFFECTIVE); }, 20000); it("increases power if user is Stellar tera type", async () => { await game.startBattle(); const playerPokemon = game.scene.getPlayerPokemon()!; playerPokemon.teraType = Type.STELLAR; playerPokemon.isTerastallized = true; game.move.select(Moves.TERA_BLAST); await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]); await game.phaseInterceptor.to("MoveEffectPhase"); expect(moveToCheck.calculateBattlePower).toHaveReturnedWith(100); }, 20000); it("is super effective against terastallized targets if user is Stellar tera type", async () => { await game.startBattle(); const playerPokemon = game.scene.getPlayerPokemon()!; playerPokemon.teraType = Type.STELLAR; playerPokemon.isTerastallized = true; const enemyPokemon = game.scene.getEnemyPokemon()!; vi.spyOn(enemyPokemon, "apply"); enemyPokemon.isTerastallized = true; game.move.select(Moves.TERA_BLAST); await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]); await game.phaseInterceptor.to("MoveEffectPhase"); expect(enemyPokemon.apply).toHaveReturnedWith(HitResult.SUPER_EFFECTIVE); }); it("uses the higher ATK for damage calculation", async () => { await game.startBattle(); const playerPokemon = game.scene.getPlayerPokemon()!; playerPokemon.stats[Stat.ATK] = 100; playerPokemon.stats[Stat.SPATK] = 1; playerPokemon.isTerastallized = true; vi.spyOn(teraBlastAttr, "apply"); game.move.select(Moves.TERA_BLAST); await game.toNextTurn(); expect(teraBlastAttr.apply).toHaveLastReturnedWith(true); }); it("uses the higher SPATK for damage calculation", async () => { await game.startBattle(); const playerPokemon = game.scene.getPlayerPokemon()!; playerPokemon.stats[Stat.ATK] = 1; playerPokemon.stats[Stat.SPATK] = 100; vi.spyOn(teraBlastAttr, "apply"); game.move.select(Moves.TERA_BLAST); await game.toNextTurn(); expect(teraBlastAttr.apply).toHaveLastReturnedWith(false); }); it("should stay as a special move if ATK turns lower than SPATK mid-turn", async () => { game.override.enemyMoveset([ Moves.CHARM ]); await game.startBattle(); const playerPokemon = game.scene.getPlayerPokemon()!; playerPokemon.stats[Stat.ATK] = 51; playerPokemon.stats[Stat.SPATK] = 50; vi.spyOn(teraBlastAttr, "apply"); game.move.select(Moves.TERA_BLAST); await game.setTurnOrder([ BattlerIndex.ENEMY, BattlerIndex.PLAYER ]); await game.toNextTurn(); expect(teraBlastAttr.apply).toHaveLastReturnedWith(false); }); it("does not change its move category from stat changes due to held items", async () => { game.override .startingHeldItems([{ name: "SPECIES_STAT_BOOSTER", type: "THICK_CLUB" }]) .starterSpecies(Species.CUBONE); await game.startBattle(); const playerPokemon = game.scene.getPlayerPokemon()!; playerPokemon.stats[Stat.ATK] = 50; playerPokemon.stats[Stat.SPATK] = 51; vi.spyOn(teraBlastAttr, "apply"); game.move.select(Moves.TERA_BLAST); await game.setTurnOrder([ BattlerIndex.ENEMY, BattlerIndex.PLAYER ]); await game.toNextTurn(); expect(teraBlastAttr.apply).toHaveLastReturnedWith(false); }); it("does not change its move category from stat changes due to abilities", async () => { game.override.ability(Abilities.HUGE_POWER); await game.startBattle(); const playerPokemon = game.scene.getPlayerPokemon()!; playerPokemon.stats[Stat.ATK] = 50; playerPokemon.stats[Stat.SPATK] = 51; vi.spyOn(teraBlastAttr, "apply"); game.move.select(Moves.TERA_BLAST); await game.setTurnOrder([ BattlerIndex.ENEMY, BattlerIndex.PLAYER ]); await game.toNextTurn(); expect(teraBlastAttr.apply).toHaveLastReturnedWith(false); }); it("causes stat drops if user is Stellar tera type", async () => { await game.startBattle(); const playerPokemon = game.scene.getPlayerPokemon()!; playerPokemon.teraType = Type.STELLAR; playerPokemon.isTerastallized = true; game.move.select(Moves.TERA_BLAST); await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]); await game.phaseInterceptor.to("MoveEndPhase"); expect(playerPokemon.getStatStage(Stat.SPATK)).toBe(-1); expect(playerPokemon.getStatStage(Stat.ATK)).toBe(-1); }, 20000); });