From 0fd7e2eed5c780d81506b1fa198c3035f767153a Mon Sep 17 00:00:00 2001 From: frutescens Date: Sun, 17 Nov 2024 23:18:42 -0800 Subject: [PATCH] Rewrote old Sheer Force tests in accordance to current testing standards. --- src/test/abilities/sheer_force.test.ts | 203 +++++++++---------------- 1 file changed, 74 insertions(+), 129 deletions(-) diff --git a/src/test/abilities/sheer_force.test.ts b/src/test/abilities/sheer_force.test.ts index cf05323f67c..e8908fc0586 100644 --- a/src/test/abilities/sheer_force.test.ts +++ b/src/test/abilities/sheer_force.test.ts @@ -1,15 +1,13 @@ import { BattlerIndex } from "#app/battle"; -import { applyAbAttrs, applyPostDefendAbAttrs, applyPreAttackAbAttrs, MoveEffectChanceMultiplierAbAttr, MovePowerBoostAbAttr, PostDefendTypeChangeAbAttr } from "#app/data/ability"; -import { MoveEffectPhase } from "#app/phases/move-effect-phase"; -import { NumberHolder } from "#app/utils"; +import { Type } from "#app/enums/type"; import { Abilities } from "#enums/abilities"; import { Moves } from "#enums/moves"; import { Species } from "#enums/species"; import { Stat } from "#enums/stat"; import GameManager from "#test/utils/gameManager"; import Phaser from "phaser"; -import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; -import { allMoves } from "#app/data/move"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; +import { allMoves, FlinchAttr } from "#app/data/move"; describe("Abilities - Sheer Force", () => { let phaserGame: Phaser.Game; @@ -27,143 +25,91 @@ describe("Abilities - Sheer Force", () => { beforeEach(() => { game = new GameManager(phaserGame); - const movesToUse = [ Moves.AIR_SLASH, Moves.BIND, Moves.CRUSH_CLAW, Moves.TACKLE ]; - game.override.battleType("single"); - game.override.enemySpecies(Species.ONIX); - game.override.startingLevel(100); - game.override.moveset(movesToUse); - game.override.enemyMoveset([ Moves.TACKLE, Moves.TACKLE, Moves.TACKLE, Moves.TACKLE ]); + game.override + .battleType("single") + .ability(Abilities.SHEER_FORCE) + .enemySpecies(Species.ONIX) + .enemyAbility(Abilities.BALL_FETCH) + .enemyMoveset([ Moves.SPLASH ]) + .disableCrits(); }); - it("Sheer Force", async () => { - const moveToUse = Moves.AIR_SLASH; - game.override.ability(Abilities.SHEER_FORCE); + const SHEER_FORCE_MULT = 5461 / 4096; + + it("Sheer Force should boost the power of the move but disable secondary effects", async () => { + game.override.moveset([ Moves.AIR_SLASH ]); + await game.classicMode.startBattle([ Species.SHUCKLE ]); + + const airSlashMove = allMoves[Moves.AIR_SLASH]; + vi.spyOn(airSlashMove, "calculateBattlePower"); + const airSlashFlinchAttr = airSlashMove.getAttrs(FlinchAttr)[0]; + vi.spyOn(airSlashFlinchAttr, "getMoveChance"); + + game.move.select(Moves.AIR_SLASH); + + await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]); + await game.move.forceHit(); + await game.phaseInterceptor.to("BerryPhase", false); + + expect(airSlashMove.calculateBattlePower).toHaveLastReturnedWith(airSlashMove.power * SHEER_FORCE_MULT); + expect(airSlashFlinchAttr.getMoveChance).toHaveLastReturnedWith(0); + }); + + it("Sheer Force does not affect the base damage or secondary effects of binding moves", async () => { + game.override.moveset([ Moves.BIND ]); + await game.classicMode.startBattle([ Species.SHUCKLE ]); + + const bindMove = allMoves[Moves.BIND]; + vi.spyOn(bindMove, "calculateBattlePower"); + + game.move.select(Moves.BIND); + + await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]); + await game.move.forceHit(); + await game.phaseInterceptor.to("BerryPhase", false); + + expect(bindMove.calculateBattlePower).toHaveLastReturnedWith(bindMove.power); + }, 20000); + + it("Sheer Force does not boost the base damage of moves with no secondary effect", async () => { + game.override.moveset([ Moves.TACKLE ]); await game.classicMode.startBattle([ Species.PIDGEOT ]); - game.scene.getEnemyPokemon()!.stats[Stat.SPDEF] = 10000; - expect(game.scene.getPlayerPokemon()!.formIndex).toBe(0); - - game.move.select(moveToUse); + const tackleMove = allMoves[Moves.TACKLE]; + vi.spyOn(tackleMove, "calculateBattlePower"); + game.move.select(Moves.TACKLE); await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]); - await game.phaseInterceptor.to(MoveEffectPhase, false); + await game.move.forceHit(); + await game.phaseInterceptor.to("BerryPhase", false); - const phase = game.scene.getCurrentPhase() as MoveEffectPhase; - const move = phase.move.getMove(); - expect(move.id).toBe(Moves.AIR_SLASH); + expect(tackleMove.calculateBattlePower).toHaveLastReturnedWith(tackleMove.power); + }); - //Verify the move is boosted and has no chance of secondary effects - const power = new NumberHolder(move.power); - const chance = new NumberHolder(move.chance); + it("Sheer Force can disable the on-hit activation of specific abilities", async () => { + game.override + .moveset([ Moves.HEADBUTT ]) + .enemySpecies(Species.SQUIRTLE) + .enemyLevel(10) + .enemyAbility(Abilities.COLOR_CHANGE); - applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, false, chance, move, phase.getFirstTarget(), false); - applyPreAttackAbAttrs(MovePowerBoostAbAttr, phase.getUserPokemon()!, phase.getFirstTarget()!, move, false, power); - - expect(chance.value).toBe(0); - expect(power.value).toBe(move.power * 5461 / 4096); - - - }, 20000); - - it("Sheer Force with exceptions including binding moves", async () => { - const moveToUse = Moves.BIND; - game.override.ability(Abilities.SHEER_FORCE); await game.classicMode.startBattle([ Species.PIDGEOT ]); + const enemyPokemon = game.scene.getEnemyPokemon(); + const headbuttMove = allMoves[Moves.HEADBUTT]; + vi.spyOn(headbuttMove, "calculateBattlePower"); + const headbuttFlinchAttr = headbuttMove.getAttrs(FlinchAttr)[0]; + vi.spyOn(headbuttFlinchAttr, "getMoveChance"); - - game.scene.getEnemyPokemon()!.stats[Stat.DEF] = 10000; - expect(game.scene.getPlayerPokemon()!.formIndex).toBe(0); - - game.move.select(moveToUse); + game.move.select(Moves.HEADBUTT); await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]); - await game.phaseInterceptor.to(MoveEffectPhase, false); + await game.move.forceHit(); + await game.phaseInterceptor.to("BerryPhase", false); - const phase = game.scene.getCurrentPhase() as MoveEffectPhase; - const move = phase.move.getMove(); - expect(move.id).toBe(Moves.BIND); - - //Binding moves and other exceptions are not affected by Sheer Force and have a chance.value of -1 - const power = new NumberHolder(move.power); - const chance = new NumberHolder(move.chance); - - applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, false, chance, move, phase.getFirstTarget(), false); - applyPreAttackAbAttrs(MovePowerBoostAbAttr, phase.getUserPokemon()!, phase.getFirstTarget()!, move, false, power); - - expect(chance.value).toBe(-1); - expect(power.value).toBe(move.power); - - - }, 20000); - - it("Sheer Force with moves with no secondary effect", async () => { - const moveToUse = Moves.TACKLE; - game.override.ability(Abilities.SHEER_FORCE); - await game.classicMode.startBattle([ Species.PIDGEOT ]); - - - game.scene.getEnemyPokemon()!.stats[Stat.DEF] = 10000; - expect(game.scene.getPlayerPokemon()!.formIndex).toBe(0); - - game.move.select(moveToUse); - - await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]); - await game.phaseInterceptor.to(MoveEffectPhase, false); - - const phase = game.scene.getCurrentPhase() as MoveEffectPhase; - const move = phase.move.getMove(); - expect(move.id).toBe(Moves.TACKLE); - - //Binding moves and other exceptions are not affected by Sheer Force and have a chance.value of -1 - const power = new NumberHolder(move.power); - const chance = new NumberHolder(move.chance); - - applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, false, chance, move, phase.getFirstTarget(), false); - applyPreAttackAbAttrs(MovePowerBoostAbAttr, phase.getUserPokemon()!, phase.getFirstTarget()!, move, false, power); - - expect(chance.value).toBe(-1); - expect(power.value).toBe(move.power); - - - }, 20000); - - it("Sheer Force Disabling Specific Abilities", async () => { - const moveToUse = Moves.CRUSH_CLAW; - game.override.enemyAbility(Abilities.COLOR_CHANGE); - game.override.startingHeldItems([{ name: "KINGS_ROCK", count: 1 }]); - game.override.ability(Abilities.SHEER_FORCE); - await game.startBattle([ Species.PIDGEOT ]); - - - game.scene.getEnemyPokemon()!.stats[Stat.DEF] = 10000; - expect(game.scene.getPlayerPokemon()!.formIndex).toBe(0); - - game.move.select(moveToUse); - - await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]); - await game.phaseInterceptor.to(MoveEffectPhase, false); - - const phase = game.scene.getCurrentPhase() as MoveEffectPhase; - const move = phase.move.getMove(); - expect(move.id).toBe(Moves.CRUSH_CLAW); - - //Disable color change due to being hit by Sheer Force - const power = new NumberHolder(move.power); - const chance = new NumberHolder(move.chance); - const user = phase.getUserPokemon()!; - const target = phase.getFirstTarget()!; - const opponentType = target.getTypes()[0]; - - applyAbAttrs(MoveEffectChanceMultiplierAbAttr, user, null, false, chance, move, target, false); - applyPreAttackAbAttrs(MovePowerBoostAbAttr, user, target, move, false, power); - applyPostDefendAbAttrs(PostDefendTypeChangeAbAttr, target, user, move, target.apply(user, move)); - - expect(chance.value).toBe(0); - expect(power.value).toBe(move.power * 5461 / 4096); - expect(target.getTypes().length).toBe(2); - expect(target.getTypes()[0]).toBe(opponentType); - - }, 20000); + expect(enemyPokemon?.getTypes()[0]).toBe(Type.WATER); + expect(headbuttMove.calculateBattlePower).toHaveLastReturnedWith(headbuttMove.power * SHEER_FORCE_MULT); + expect(headbuttFlinchAttr.getMoveChance).toHaveLastReturnedWith(0); + }); it("Two Pokemon with abilities disabled by Sheer Force hitting each other should not cause a crash", async () => { const moveToUse = Moves.CRUNCH; @@ -213,7 +159,6 @@ describe("Abilities - Sheer Force", () => { .moveset([ Moves.TACKLE ]) .enemySpecies(Species.GEODUDE) .enemyMoveset([ Moves.TACKLE ]) - .enemyLevel(100) .startingHeldItems([{ name: "SHELL_BELL", count: 1 }]); await game.classicMode.startBattle([ Species.SHUCKLE ]);