From f895d1561761102c7d72461ae30c38a5aa2c922f Mon Sep 17 00:00:00 2001 From: innerthunder <168692175+innerthunder@users.noreply.github.com> Date: Mon, 17 Feb 2025 18:03:55 -0800 Subject: [PATCH 1/6] Fully Implement Uproar --- src/data/battler-tags.ts | 84 +++++++++++- src/data/init-moves.ts | 11 +- src/data/move-attrs/message-header-attr.ts | 4 +- src/enums/battler-tag-type.ts | 1 + src/field/pokemon.ts | 10 +- src/utils/battler-tag-type-utils.ts | 2 +- test/moves/uproar.test.ts | 142 +++++++++++++++++++++ 7 files changed, 243 insertions(+), 11 deletions(-) create mode 100644 test/moves/uproar.test.ts diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index 4bbeee9c82..cc6c099ceb 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -41,6 +41,7 @@ import { BattlerTagLapseType } from "#enums/battler-tag-lapse-type"; import { AbilityApplyMode } from "#enums/ability-apply-mode"; import { GulpMissileBattlerTagTypes, + MoveLockTagTypes, RemoveTypeBattlerTagTypes, SemiInvulnerableBattlerTagTypes, TrappedBattlerTagTypes, @@ -1180,6 +1181,78 @@ export class FrenzyTag extends MoveLockTag { } } +/** + * Puts the source {@linkcode Pokemon} into an uproar, locking them into using + * Uproar for 2 turns after the initial usage and preventing all + * Pokemon on the field from sleeping. All Pokemon on the field also + * wake up when this tag is added. + * @extends MoveLockTag + * @see {@link https://bulbapedia.bulbagarden.net/wiki/Uproar_(move) Uproar} + */ +export class UproarTag extends MoveLockTag { + constructor() { + super(BattlerTagType.UPROAR, 3, MoveId.UPROAR); + } + + /** + * Plays a "started an uproar" message, then wakes up all active Pokemon + * @param pokemon the {@linkcode Pokemon} with this tag + */ + override onAdd(pokemon: Pokemon): void { + // "{pokemonNameWithAffix} caused an uproar!" + globalScene.queueMessage( + i18next.t("battlerTags:uproarOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }), + ); + + // Wake up all sleeping Pokemon on the field + globalScene.getField(true).forEach((p) => { + if (p.status?.effect === StatusEffect.SLEEP) { + p.resetStatus(); + // "The uproar woke {pokemonNameWithAffix}!" + globalScene.queueMessage( + i18next.t("battlerTags:uproarOnCureSleep", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }), + ); + } + }); + } + + override onRemove(pokemon: Pokemon): void { + // "{pokemonNameWithAffix} calmed down." + globalScene.queueMessage( + i18next.t("battlerTags:uproarOnRemove", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }), + ); + + super.onRemove(pokemon); + } + + /** + * Prevents Pokemon on the field from falling asleep + * @param pokemon the {@linkcode Pokemon} with this tag + * @param simulated if `true`, suppresses changes to game state + * @param affectedPokemon the {@linkcode Pokemon} to be afflicted with sleep + * @param preventSleep a {@linkcode BooleanHolder} which, if `true`, cancels attempts to afflict sleep + * @returns `true` + */ + override apply( + _pokemon: Pokemon, + simulated: boolean, + affectedPokemon: Pokemon, + preventSleep: BooleanHolder, + ): boolean { + if (!simulated) { + // "But the uproar kept {pokemonNameWithAffix} awake!" + globalScene.queueMessage( + i18next.t("battlerTags:uproarOnPreventSleep", { + pokemonNameWithAffix: getPokemonNameWithAffix(affectedPokemon), + }), + ); + } + + preventSleep.value = true; + return true; + } +} + /** * Applies the effects of the move Encore onto the target Pokemon * Encore forces the target Pokemon to use its most-recent move for 3 turns @@ -3191,10 +3264,13 @@ export class TormentTag extends MoveRestrictionBattlerTag { if (!lastMoveTurn) { return false; } - // This checks for locking / momentum moves like Rollout and Hydro Cannon + if the user is under the influence of BattlerTagType.FRENZY - // Because Uproar's unique behavior is not implemented, it does not check for Uproar. Torment has been marked as partial in moves.ts + const moveObj = allMoves[lastMoveTurn.move.id]; - const isUnaffected = moveObj.hasAttr(ConsecutiveUseDoublePowerAttr) || user.getTag(BattlerTagType.FRENZY); + /** + * Consecutively-executed moves are not interrupted by Torment + * @todo remove the additional attribute check once Rollout/Ice Ball are reimplemented + */ + const isUnaffected = moveObj.hasAttr(ConsecutiveUseDoublePowerAttr) || user.getTag(...MoveLockTagTypes); const validLastMoveResult = lastMoveTurn.result === MoveResult.SUCCESS || lastMoveTurn.result === MoveResult.MISS; if ( lastMoveTurn.move.id === moveId @@ -3531,6 +3607,8 @@ export function getBattlerTag( return new NightmareTag(); case BattlerTagType.FRENZY: return new FrenzyTag(turnCount, sourceMoveId); + case BattlerTagType.UPROAR: + return new UproarTag(); case BattlerTagType.CHARGING: return new BattlerTag(tagType, BattlerTagLapseType.CUSTOM, 1, sourceMoveId, sourceId); case BattlerTagType.ENCORE: diff --git a/src/data/init-moves.ts b/src/data/init-moves.ts index 7a869624d7..e364401a5a 100644 --- a/src/data/init-moves.ts +++ b/src/data/init-moves.ts @@ -1129,10 +1129,16 @@ export function initMoves() { .attr(FlinchAttr) .condition(new FirstMoveCondition()), new AttackMove(MoveId.UPROAR, ElementalType.NORMAL, MoveCategory.SPECIAL, 90, 100, 10, -1, 0, 3) + .attr(AddBattlerTagAttr, BattlerTagType.UPROAR, true) + .attr(MessageHeaderAttr, (user, _move) => + !!user.getTag(BattlerTagType.UPROAR) + ? // "{pokemonNameWithAffix} is making an uproar!" + i18next.t("moveTriggers:isMakingAnUproar", { pokemonNameWithAffix: getPokemonNameWithAffix(user) }) + : undefined, + ) .ignoresVirtual() .soundMove() - .target(MoveTarget.RANDOM_NEAR_ENEMY) - .partial(), // Does not lock the user, does not stop Pokemon from sleeping + .target(MoveTarget.RANDOM_NEAR_ENEMY), new SelfStatusMove(MoveId.STOCKPILE, ElementalType.NORMAL, -1, 20, -1, 0, 3) .condition((user) => (user.getTag(BattlerTagType.STOCKPILING)?.stockpiledCount ?? 0) < 3) .attr(AddBattlerTagAttr, BattlerTagType.STOCKPILING, true), @@ -1155,7 +1161,6 @@ export function initMoves() { .target(MoveTarget.BOTH_SIDES), new StatusMove(MoveId.TORMENT, ElementalType.DARK, 100, 15, -1, 0, 3) .ignoresSubstitute() - .edgeCase() // Incomplete implementation because of Uproar's partial implementation .attr(AddBattlerTagAttr, BattlerTagType.TORMENT, false, { failOnOverlap: true }), new StatusMove(MoveId.FLATTER, ElementalType.DARK, 100, 15, -1, 0, 3) .attr(StatStageChangeAttr, [Stat.SPATK], 1) diff --git a/src/data/move-attrs/message-header-attr.ts b/src/data/move-attrs/message-header-attr.ts index 07d013f3eb..d41eae53fb 100644 --- a/src/data/move-attrs/message-header-attr.ts +++ b/src/data/move-attrs/message-header-attr.ts @@ -8,9 +8,9 @@ import { MoveHeaderAttr } from "#app/data/move-attrs/move-header-attr"; * @extends MoveHeaderAttr */ export class MessageHeaderAttr extends MoveHeaderAttr { - private message: string | ((user: Pokemon, move: Move) => string); + private message: string | ((user: Pokemon, move: Move) => string | undefined); - constructor(message: string | ((user: Pokemon, move: Move) => string)) { + constructor(message: string | ((user: Pokemon, move: Move) => string | undefined)) { super(); this.message = message; } diff --git a/src/enums/battler-tag-type.ts b/src/enums/battler-tag-type.ts index 62ebd877a1..2013769d86 100644 --- a/src/enums/battler-tag-type.ts +++ b/src/enums/battler-tag-type.ts @@ -105,4 +105,5 @@ export enum BattlerTagType { SKY_DROP, CRIT_BOOST_STACKABLE, RAGE, + UPROAR, } diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 8d238fd5df..a5ab687a82 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -112,6 +112,7 @@ import { getBattlerTag, type AutotomizedTag, type CritBoostStackableTag, + type UproarTag, } from "../data/battler-tags"; import { BattlerTagLapseType } from "#enums/battler-tag-lapse-type"; import { WeatherType } from "#enums/weather-type"; @@ -4056,7 +4057,12 @@ export abstract class Pokemon extends Phaser.GameObjects.Container { } break; case StatusEffect.SLEEP: - if (this.isGrounded() && globalScene.arena.hasTerrain(TerrainType.ELECTRIC)) { + const preventSleep = new BooleanHolder(false); + globalScene + .getField(true) + .forEach((p) => p.getTag(BattlerTagType.UPROAR)?.apply(p, quiet, this, preventSleep)); + + if (preventSleep.value || (this.isGrounded() && globalScene.arena.hasTerrain(TerrainType.ELECTRIC))) { return false; } break; @@ -4099,7 +4105,7 @@ export abstract class Pokemon extends Phaser.GameObjects.Container { turnsRemaining: number = 0, sourceText: string | null = null, ): boolean { - if (!this.canSetStatus(effect, asPhase, false, sourcePokemon)) { + if (!this.canSetStatus(effect, !asPhase, false, sourcePokemon)) { return false; } if (this.isFainted() && effect !== StatusEffect.FAINT) { diff --git a/src/utils/battler-tag-type-utils.ts b/src/utils/battler-tag-type-utils.ts index b4d62dd17f..adfbdd7f21 100644 --- a/src/utils/battler-tag-type-utils.ts +++ b/src/utils/battler-tag-type-utils.ts @@ -7,7 +7,7 @@ export const SemiInvulnerableBattlerTagTypes = Object.freeze([ BattlerTagType.HIDDEN, ]); -export const MoveLockTagTypes = Object.freeze([BattlerTagType.FRENZY]); +export const MoveLockTagTypes = Object.freeze([BattlerTagType.FRENZY, BattlerTagType.UPROAR]); export const CritBoostBattlerTagTypes = Object.freeze([BattlerTagType.CRIT_BOOST, BattlerTagType.DRAGON_CHEER]); diff --git a/test/moves/uproar.test.ts b/test/moves/uproar.test.ts new file mode 100644 index 0000000000..b4bf0ac4a8 --- /dev/null +++ b/test/moves/uproar.test.ts @@ -0,0 +1,142 @@ +import { allMoves } from "#app/data/data-lists"; +import { Abilities } from "#enums/abilities"; +import { BattlerIndex } from "#enums/battler-index"; +import { BattlerTagType } from "#enums/battler-tag-type"; +import { MoveId } from "#enums/move-id"; +import { MoveResult } from "#enums/move-result"; +import { Species } from "#enums/species"; +import { StatusEffect } from "#enums/status-effect"; +import { GameManager } from "#test/testUtils/gameManager"; +import Phaser from "phaser"; +import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest"; + +describe("Moves - Uproar", () => { + 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 + .ability(Abilities.BALL_FETCH) + .battleType("single") + .disableCrits() + .enemySpecies(Species.BLISSEY) + .enemyAbility(Abilities.BALL_FETCH) + .enemyMoveset(MoveId.SPLASH) + .startingLevel(100) + .enemyLevel(100); + }); + + it("should lock the user into using Uproar for the following 2 turns", async () => { + await game.classicMode.startBattle([Species.FEEBAS]); + + const player = game.field.getPlayerPokemon(); + + game.move.use(MoveId.UPROAR); + await game.toNextTurn(); + + expect(player.getTag(BattlerTagType.UPROAR)?.turnCount).toBe(2); + expect(player.getMoveQueue()[0]).toMatchObject({ + moveId: MoveId.UPROAR, + ignorePP: true, + }); + + await game.toNextTurn(); + await game.toNextTurn(); + + expect(player.getTag(BattlerTagType.UPROAR)).toBeUndefined(); + expect(player.getMoveQueue()).toHaveLength(0); + }); + + it("should stop execution after using Uproar has no effect", async () => { + await game.classicMode.startBattle([Species.FEEBAS]); + + const player = game.field.getPlayerPokemon(); + + game.move.use(MoveId.UPROAR); + await game.toNextTurn(); + + expect(player.getTag(BattlerTagType.UPROAR)?.turnCount).toBe(2); + expect(player.getMoveQueue()[0]).toMatchObject({ + moveId: MoveId.UPROAR, + ignorePP: true, + }); + + game.override.enemyAbility(Abilities.SOUNDPROOF); + + await game.toNextTurn(); + expect(player.getTag(BattlerTagType.UPROAR)).toBeUndefined(); + expect(player.getMoveQueue()).toHaveLength(0); + }); + + it("should wake up all active Pokemon on its initial use", async () => { + game.override.enemyStatusEffect(StatusEffect.SLEEP).battleType("double"); + + await game.classicMode.startBattle([Species.FEEBAS]); + + const enemyPokemon = game.scene.getEnemyField(); + + game.move.use(MoveId.UPROAR, 0); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2]); + + await game.phaseInterceptor.to("MoveEndPhase"); + enemyPokemon.forEach((p) => expect(p.status?.effect).toBeOneOf([StatusEffect.NONE, undefined])); + }); + + it("should prevent active Pokemon from falling asleep during its execution", async () => { + game.override.battleType("double"); + await game.classicMode.startBattle([Species.FEEBAS, Species.MAGIKARP]); + + const enemyPokemon = game.scene.getEnemyField(); + + game.move.use(MoveId.UPROAR, 0); + game.move.use(MoveId.SPORE, 1, BattlerIndex.ENEMY_2); + await game.move.forceEnemyMove(MoveId.REST); + await game.move.forceEnemyMove(MoveId.SPLASH); + await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY_2]); + + await game.phaseInterceptor.to("BerryPhase", false); + enemyPokemon.forEach((p) => expect(p.status?.effect).toBeOneOf([StatusEffect.NONE, undefined])); + }); + + it("should not have its execution interrupted by Torment", async () => { + await game.classicMode.startBattle([Species.FEEBAS]); + + const player = game.field.getPlayerPokemon(); + + game.move.use(MoveId.UPROAR); + await game.move.forceEnemyMove(MoveId.TORMENT); + await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]); + + await game.toNextTurn(); + + expect(player.getTag(BattlerTagType.UPROAR)?.turnCount).toBe(2); + expect(player.getMoveQueue()[0]).toMatchObject({ + moveId: MoveId.UPROAR, + ignorePP: true, + }); + + await game.toNextTurn(); + await game.toNextTurn(); + + expect(player.getTag(BattlerTagType.UPROAR)).toBeUndefined(); + expect(player.getMoveQueue()).toHaveLength(0); + expect(player.getMoveHistory()).toHaveLength(3); + player.getMoveHistory().forEach((turnMove) => + expect(turnMove).toMatchObject({ + move: allMoves[MoveId.UPROAR], + result: MoveResult.SUCCESS, + }), + ); + }); +}); From 3812132864be2b8a1a1ac0a5c39e57295b1a536d Mon Sep 17 00:00:00 2001 From: innerthunder <168692175+innerthunder@users.noreply.github.com> Date: Mon, 17 Feb 2025 18:51:13 -0800 Subject: [PATCH 2/6] Another FRENZY replaced Co-Authored-By: PigeonBar <56974298+PigeonBar@users.noreply.github.com> --- src/phases/check-switch-phase.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/phases/check-switch-phase.ts b/src/phases/check-switch-phase.ts index 26fb72a7a4..bd18fb4697 100644 --- a/src/phases/check-switch-phase.ts +++ b/src/phases/check-switch-phase.ts @@ -11,6 +11,7 @@ import { SwitchType } from "#enums/switch-type"; import { settings } from "#app/system/settings/settings-manager"; import i18next from "i18next"; import { PhaseId } from "#enums/phase-id"; +import { MoveLockTagTypes } from "#app/utils/battler-tag-type-utils"; /** * Handles the prompt to switch pokemon at the start of a battle when the player is playing in Switch mode @@ -60,7 +61,7 @@ export class CheckSwitchPhase extends BattlePhase { // ...or if any player Pokemon has an effect that prevents the checked Pokemon from switching if ( - pokemon.getTag(BattlerTagType.FRENZY) + pokemon.getTag(...MoveLockTagTypes) || pokemon.isTrapped() || globalScene.getPlayerField().some((p) => p.getTag(BattlerTagType.COMMANDED)) ) { From c89b9f4d001045954a631e86183993ddbddfd531 Mon Sep 17 00:00:00 2001 From: innerthunder <168692175+innerthunder@users.noreply.github.com> Date: Mon, 17 Feb 2025 18:54:48 -0800 Subject: [PATCH 3/6] Add Uproar's tag to benefit score func --- src/data/move-attrs/add-battler-tag-attr.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/src/data/move-attrs/add-battler-tag-attr.ts b/src/data/move-attrs/add-battler-tag-attr.ts index 72d575c3d9..352c840626 100644 --- a/src/data/move-attrs/add-battler-tag-attr.ts +++ b/src/data/move-attrs/add-battler-tag-attr.ts @@ -85,6 +85,7 @@ export class AddBattlerTagAttr extends ChanceBasedMoveEffectAttr { case BattlerTagType.SALT_CURED: case BattlerTagType.CURSED: case BattlerTagType.FRENZY: + case BattlerTagType.UPROAR: case BattlerTagType.TRAPPED: case BattlerTagType.BIND: case BattlerTagType.WRAP: From 8d443e36a00ef2013e09fbb9acc77bb34eea1855 Mon Sep 17 00:00:00 2001 From: innerthunder <168692175+innerthunder@users.noreply.github.com> Date: Sat, 22 Feb 2025 01:51:02 -0800 Subject: [PATCH 4/6] Update locales --- public/locales | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/public/locales b/public/locales index b3c2629d28..5fbc8d34cf 160000 --- a/public/locales +++ b/public/locales @@ -1 +1 @@ -Subproject commit b3c2629d2875f703eac0f50ee07c9734eabb4fac +Subproject commit 5fbc8d34cf7774ded43433c86b855d3ce03f171b From d84f535cb370775d768c9a657132ffe1f1c0203d Mon Sep 17 00:00:00 2001 From: innerthunder <168692175+innerthunder@users.noreply.github.com> Date: Sat, 22 Feb 2025 01:59:43 -0800 Subject: [PATCH 5/6] Fix status effect checks + test for PP used --- src/data/battler-tags.ts | 2 +- test/moves/uproar.test.ts | 8 ++++++-- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/data/battler-tags.ts b/src/data/battler-tags.ts index a9bd30daae..ef7c86010e 100644 --- a/src/data/battler-tags.ts +++ b/src/data/battler-tags.ts @@ -1206,7 +1206,7 @@ export class UproarTag extends MoveLockTag { // Wake up all sleeping Pokemon on the field globalScene.getField(true).forEach((p) => { - if (p.status?.effect === StatusEffect.SLEEP) { + if (p.hasStatusEffect(StatusEffect.SLEEP, false, true)) { p.resetStatus(); // "The uproar woke {pokemonNameWithAffix}!" globalScene.queueMessage( diff --git a/test/moves/uproar.test.ts b/test/moves/uproar.test.ts index b4bf0ac4a8..896f7fdf98 100644 --- a/test/moves/uproar.test.ts +++ b/test/moves/uproar.test.ts @@ -51,11 +51,15 @@ describe("Moves - Uproar", () => { ignorePP: true, }); + const playerUproar = player.getMoveset().find((mv) => mv.moveId === MoveId.UPROAR); + expect(playerUproar?.ppUsed).toBe(1); + await game.toNextTurn(); await game.toNextTurn(); expect(player.getTag(BattlerTagType.UPROAR)).toBeUndefined(); expect(player.getMoveQueue()).toHaveLength(0); + expect(playerUproar?.ppUsed).toBe(1); }); it("should stop execution after using Uproar has no effect", async () => { @@ -90,7 +94,7 @@ describe("Moves - Uproar", () => { await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2]); await game.phaseInterceptor.to("MoveEndPhase"); - enemyPokemon.forEach((p) => expect(p.status?.effect).toBeOneOf([StatusEffect.NONE, undefined])); + enemyPokemon.forEach((p) => expect(p.getStatusEffect()).toBe(StatusEffect.NONE)); }); it("should prevent active Pokemon from falling asleep during its execution", async () => { @@ -106,7 +110,7 @@ describe("Moves - Uproar", () => { await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY_2]); await game.phaseInterceptor.to("BerryPhase", false); - enemyPokemon.forEach((p) => expect(p.status?.effect).toBeOneOf([StatusEffect.NONE, undefined])); + enemyPokemon.forEach((p) => expect(p.getStatusEffect()).toBe(StatusEffect.NONE)); }); it("should not have its execution interrupted by Torment", async () => { From 5e978f3fe7cc4cee4cbcd0c0e68b474f9785de66 Mon Sep 17 00:00:00 2001 From: innerthunder <168692175+innerthunder@users.noreply.github.com> Date: Mon, 24 Feb 2025 22:50:57 -0800 Subject: [PATCH 6/6] Fix uproar tests --- test/moves/uproar.test.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/test/moves/uproar.test.ts b/test/moves/uproar.test.ts index 896f7fdf98..69229da792 100644 --- a/test/moves/uproar.test.ts +++ b/test/moves/uproar.test.ts @@ -1,4 +1,3 @@ -import { allMoves } from "#app/data/data-lists"; import { Abilities } from "#enums/abilities"; import { BattlerIndex } from "#enums/battler-index"; import { BattlerTagType } from "#enums/battler-tag-type"; @@ -47,7 +46,7 @@ describe("Moves - Uproar", () => { expect(player.getTag(BattlerTagType.UPROAR)?.turnCount).toBe(2); expect(player.getMoveQueue()[0]).toMatchObject({ - moveId: MoveId.UPROAR, + move: expect.objectContaining({ id: MoveId.UPROAR }), ignorePP: true, }); @@ -72,7 +71,7 @@ describe("Moves - Uproar", () => { expect(player.getTag(BattlerTagType.UPROAR)?.turnCount).toBe(2); expect(player.getMoveQueue()[0]).toMatchObject({ - moveId: MoveId.UPROAR, + move: expect.objectContaining({ id: MoveId.UPROAR }), ignorePP: true, }); @@ -126,7 +125,7 @@ describe("Moves - Uproar", () => { expect(player.getTag(BattlerTagType.UPROAR)?.turnCount).toBe(2); expect(player.getMoveQueue()[0]).toMatchObject({ - moveId: MoveId.UPROAR, + move: expect.objectContaining({ id: MoveId.UPROAR }), ignorePP: true, }); @@ -138,7 +137,7 @@ describe("Moves - Uproar", () => { expect(player.getMoveHistory()).toHaveLength(3); player.getMoveHistory().forEach((turnMove) => expect(turnMove).toMatchObject({ - move: allMoves[MoveId.UPROAR], + move: expect.objectContaining({ id: MoveId.UPROAR }), result: MoveResult.SUCCESS, }), );