From 5c2922c22bf3ac87b05e148ab42c9736ae06ae3e Mon Sep 17 00:00:00 2001 From: frutescens Date: Tue, 19 Nov 2024 09:56:35 -0800 Subject: [PATCH] Moved getSecondaryChanceMultiplier to FlinchChanceModifier and revised Serene Grace tests --- src/modifier/modifier.ts | 35 +++++----- src/test/abilities/serene_grace.test.ts | 85 +++++++++---------------- src/test/abilities/sheer_force.test.ts | 2 - 3 files changed, 48 insertions(+), 74 deletions(-) diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index 5e5246269a3..a92105f1b94 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -726,22 +726,6 @@ export abstract class PokemonHeldItemModifier extends PersistentModifier { return 1; } - //Applies to items with chance of activating secondary effects ie Kings Rock - getSecondaryChanceMultiplier(pokemon: Pokemon): number { - // Temporary quickfix to stop game from freezing when the opponet uses u-turn while holding on to king's rock - if (!pokemon.getLastXMoves()[0]) { - return 1; - } - const sheerForceAffected = allMoves[pokemon.getLastXMoves()[0].move].chance >= 0 && pokemon.hasAbility(Abilities.SHEER_FORCE); - - if (sheerForceAffected) { - return 0; - } else if (pokemon.hasAbility(Abilities.SERENE_GRACE)) { - return 2; - } - return 1; - } - getMaxStackCount(scene: BattleScene, forThreshold?: boolean): number { const pokemon = this.getPokemon(scene); if (!pokemon) { @@ -1615,8 +1599,11 @@ export class BypassSpeedChanceModifier extends PokemonHeldItemModifier { } export class FlinchChanceModifier extends PokemonHeldItemModifier { + private chance: number; constructor(type: ModifierType, pokemonId: number, stackCount?: number) { super(type, pokemonId, stackCount); + + this.chance = 10; } matchType(modifier: Modifier) { @@ -1637,6 +1624,18 @@ export class FlinchChanceModifier extends PokemonHeldItemModifier { return super.shouldApply(pokemon, flinched) && !!flinched; } + /** + * Checks for any chance modifying abilities + * @param pokemon + * @returns `2` if the pokemon involved has a Serene Grace-like ability | `1` if it does not + */ + getSecondaryChanceMultiplier(pokemon: Pokemon): number { + if (pokemon.hasAbility(Abilities.SERENE_GRACE)) { + return 2; + } + return 1; + } + /** * Applies {@linkcode FlinchChanceModifier} * @param pokemon the {@linkcode Pokemon} that holds the item @@ -1644,7 +1643,9 @@ export class FlinchChanceModifier extends PokemonHeldItemModifier { * @returns `true` if {@linkcode FlinchChanceModifier} has been applied */ override apply(pokemon: Pokemon, flinched: BooleanHolder): boolean { - if (!flinched.value && pokemon.randSeedInt(10) < (this.getStackCount() * this.getSecondaryChanceMultiplier(pokemon))) { + // The check for pokemon.battleSummonData is to ensure that a crash doesn't occur when a Pokemon with King's Rock procs a flinch + const secondaryChanceMultiplier = pokemon.battleSummonData ? this.getSecondaryChanceMultiplier(pokemon) : 1; + if (!flinched.value && pokemon.randSeedInt(100) < (this.getStackCount() * secondaryChanceMultiplier * this.chance)) { flinched.value = true; return true; } diff --git a/src/test/abilities/serene_grace.test.ts b/src/test/abilities/serene_grace.test.ts index 3318c7fc27a..15548a2ccc7 100644 --- a/src/test/abilities/serene_grace.test.ts +++ b/src/test/abilities/serene_grace.test.ts @@ -1,14 +1,13 @@ import { BattlerIndex } from "#app/battle"; -import { applyAbAttrs, MoveEffectChanceMultiplierAbAttr } from "#app/data/ability"; -import { Stat } from "#enums/stat"; -import { MoveEffectPhase } from "#app/phases/move-effect-phase"; -import * as Utils from "#app/utils"; import { Abilities } from "#enums/abilities"; 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 { allMoves } from "#app/data/move"; +import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest"; +import { FlinchAttr } from "#app/data/move"; +import { FlinchChanceModifier } from "#app/modifier/modifier"; describe("Abilities - Serene Grace", () => { @@ -27,66 +26,42 @@ describe("Abilities - Serene Grace", () => { beforeEach(() => { game = new GameManager(phaserGame); - const movesToUse = [ Moves.AIR_SLASH, 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 + .ability(Abilities.SERENE_GRACE) + .moveset([ Moves.AIR_SLASH, Moves.TACKLE ]) + .enemyLevel(10) + .enemyMoveset([ Moves.SPLASH ]); }); - it("Move chance without Serene Grace", async () => { - const moveToUse = Moves.AIR_SLASH; - await game.startBattle([ - Species.PIDGEOT - ]); + it("Serene Grace should double the secondary effect chance of a move", async () => { + await game.classicMode.startBattle([ Species.SHUCKLE ]); + const airSlashMove = allMoves[Moves.AIR_SLASH]; + const airSlashFlinchAttr = airSlashMove.getAttrs(FlinchAttr)[0]; + vi.spyOn(airSlashFlinchAttr, "getMoveChance"); - game.scene.getEnemyParty()[0].stats[Stat.SPDEF] = 10000; - expect(game.scene.getPlayerParty()[0].formIndex).toBe(0); - - game.move.select(moveToUse); - + game.move.select(Moves.AIR_SLASH); await game.setTurnOrder([ BattlerIndex.PLAYER, BattlerIndex.ENEMY ]); - await game.phaseInterceptor.to(MoveEffectPhase, false); + await game.move.forceHit(); + await game.phaseInterceptor.to("BerryPhase"); - // Check chance of Air Slash without Serene Grace - const phase = game.scene.getCurrentPhase() as MoveEffectPhase; - const move = phase.move.getMove(); - expect(move.id).toBe(Moves.AIR_SLASH); + expect(airSlashFlinchAttr.getMoveChance).toHaveLastReturnedWith(60); + }); - const chance = new Utils.IntegerHolder(move.chance); - console.log(move.chance + " Their ability is " + phase.getUserPokemon()!.getAbility().name); - applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, false, chance, move, phase.getFirstTarget(), false); - expect(chance.value).toBe(30); + it("Serene Grace should double the chance of King Rock's activating", async () => { + game.override + .startingHeldItems([{ name: "KINGS_ROCK", count: 1 }]); - }, 20000); + await game.classicMode.startBattle([ Species.SHUCKLE ]); - it("Move chance with Serene Grace", async () => { - const moveToUse = Moves.AIR_SLASH; - game.override.ability(Abilities.SERENE_GRACE); - await game.startBattle([ - Species.TOGEKISS - ]); - - game.scene.getEnemyParty()[0].stats[Stat.SPDEF] = 10000; - expect(game.scene.getPlayerParty()[0].formIndex).toBe(0); - - game.move.select(moveToUse); + const kingsRockInstance = game.scene.findModifier(m => m instanceof FlinchChanceModifier) as FlinchChanceModifier; + vi.spyOn(kingsRockInstance, "getSecondaryChanceMultiplier"); + 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"); - // Check chance of Air Slash with Serene Grace - const phase = game.scene.getCurrentPhase() as MoveEffectPhase; - const move = phase.move.getMove(); - expect(move.id).toBe(Moves.AIR_SLASH); - - const chance = new Utils.IntegerHolder(move.chance); - applyAbAttrs(MoveEffectChanceMultiplierAbAttr, phase.getUserPokemon()!, null, false, chance, move, phase.getFirstTarget(), false); - expect(chance.value).toBe(60); - - }, 20000); - - //TODO King's Rock Interaction Unit Test + expect(kingsRockInstance.getSecondaryChanceMultiplier).toHaveLastReturnedWith(2); + }); }); diff --git a/src/test/abilities/sheer_force.test.ts b/src/test/abilities/sheer_force.test.ts index 51824d21fbe..a0ddf5bb9c6 100644 --- a/src/test/abilities/sheer_force.test.ts +++ b/src/test/abilities/sheer_force.test.ts @@ -152,6 +152,4 @@ describe("Abilities - Sheer Force", () => { await game.phaseInterceptor.to("TurnEndPhase"); expect(formKeyStart).toBe(playerPokemon?.getFormKey()); }); - - //TODO King's Rock Interaction Unit Test });