[Dev] Move function from testUtils.ts to gameManager.ts (1/3) (#3430)
* move mockHitCheck to gameManager * add abstract base class and move helper class * add param for single target miss
This commit is contained in:
parent
14b3907b11
commit
2b12326280
|
@ -8,7 +8,7 @@ import { Moves } from "#enums/moves";
|
|||
import { Species } from "#enums/species";
|
||||
import Phaser from "phaser";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { mockHitCheck, SPLASH_ONLY } from "#test/utils/testUtils";
|
||||
import { SPLASH_ONLY } from "#test/utils/testUtils";
|
||||
|
||||
describe("Abilities - Hustle", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
|
@ -44,7 +44,7 @@ describe("Abilities - Hustle", () => {
|
|||
vi.spyOn(pikachu, "getBattleStat");
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE));
|
||||
await mockHitCheck(game, true);
|
||||
await game.move.forceHit();
|
||||
await game.phaseInterceptor.to(DamagePhase);
|
||||
|
||||
expect(pikachu.getBattleStat).toHaveReturnedWith(atk * 1.5);
|
||||
|
|
|
@ -12,7 +12,7 @@ import Phaser from "phaser";
|
|||
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
|
||||
import GameManager from "#test/utils/gameManager";
|
||||
import { getMovePosition } from "#test/utils/gameManagerUtils";
|
||||
import { mockHitCheck, SPLASH_ONLY } from "#test/utils/testUtils";
|
||||
import { SPLASH_ONLY } from "#test/utils/testUtils";
|
||||
|
||||
const TIMEOUT = 20 * 1000;
|
||||
|
||||
|
@ -192,7 +192,7 @@ describe("Abilities - Protean", () => {
|
|||
expect(leadPokemon).not.toBe(undefined);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE));
|
||||
await mockHitCheck(game, false);
|
||||
await game.move.forceMiss();
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
|
|
|
@ -11,7 +11,7 @@ import { Abilities } from "#enums/abilities";
|
|||
import { WeatherType } from "#app/data/weather.js";
|
||||
import { StatusEffect, getStatusEffectCatchRateMultiplier } from "#app/data/status-effect";
|
||||
import { BattlerTagType } from "#enums/battler-tag-type";
|
||||
import { mockHitCheck, SPLASH_ONLY } from "#test/utils/testUtils";
|
||||
import { SPLASH_ONLY } from "#test/utils/testUtils";
|
||||
|
||||
const TIMEOUT = 20 * 1000; // 20 sec timeout
|
||||
|
||||
|
@ -258,7 +258,7 @@ describe("Abilities - Magic Guard", () => {
|
|||
const leadPokemon = game.scene.getPlayerPokemon()!;
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.HIGH_JUMP_KICK));
|
||||
await mockHitCheck(game, false);
|
||||
await game.move.forceMiss();
|
||||
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ import Phaser from "phaser";
|
|||
import { afterEach, beforeAll, beforeEach, describe, expect, test } from "vitest";
|
||||
import GameManager from "#test/utils/gameManager";
|
||||
import { getMovePosition } from "#test/utils/gameManagerUtils";
|
||||
import { mockHitCheck, SPLASH_ONLY } from "#test/utils/testUtils";
|
||||
import { SPLASH_ONLY } from "#test/utils/testUtils";
|
||||
|
||||
const TIMEOUT = 20 * 1000;
|
||||
|
||||
|
@ -129,7 +129,7 @@ describe("Abilities - Parental Bond", () => {
|
|||
expect(enemyPokemon).not.toBe(undefined);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.DOUBLE_HIT));
|
||||
await mockHitCheck(game, true);
|
||||
await game.move.forceHit();
|
||||
|
||||
await game.phaseInterceptor.to(BerryPhase, false);
|
||||
|
||||
|
@ -172,7 +172,7 @@ describe("Abilities - Parental Bond", () => {
|
|||
expect(enemyPokemon).not.toBe(undefined);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.ROLLOUT));
|
||||
await mockHitCheck(game, true);
|
||||
await game.move.forceHit();
|
||||
|
||||
await game.phaseInterceptor.to(DamagePhase, false);
|
||||
|
||||
|
@ -368,7 +368,7 @@ describe("Abilities - Parental Bond", () => {
|
|||
const enemyStartingHp = enemyPokemon.hp;
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.SUPER_FANG));
|
||||
await mockHitCheck(game, true);
|
||||
await game.move.forceHit();
|
||||
|
||||
await game.phaseInterceptor.to(DamagePhase);
|
||||
|
||||
|
@ -397,7 +397,7 @@ describe("Abilities - Parental Bond", () => {
|
|||
const enemyStartingHp = enemyPokemon.hp;
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.SEISMIC_TOSS));
|
||||
await mockHitCheck(game, true);
|
||||
await game.move.forceHit();
|
||||
|
||||
await game.phaseInterceptor.to(DamagePhase);
|
||||
|
||||
|
@ -423,7 +423,7 @@ describe("Abilities - Parental Bond", () => {
|
|||
expect(enemyPokemon).not.toBe(undefined);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.HYPER_BEAM));
|
||||
await mockHitCheck(game, true);
|
||||
await game.move.forceHit();
|
||||
|
||||
await game.phaseInterceptor.to(DamagePhase);
|
||||
|
||||
|
@ -451,7 +451,7 @@ describe("Abilities - Parental Bond", () => {
|
|||
expect(enemyPokemon).not.toBe(undefined);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.ANCHOR_SHOT));
|
||||
await mockHitCheck(game, true);
|
||||
await game.move.forceHit();
|
||||
|
||||
await game.phaseInterceptor.to(DamagePhase);
|
||||
|
||||
|
@ -481,7 +481,7 @@ describe("Abilities - Parental Bond", () => {
|
|||
expect(enemyPokemon).not.toBe(undefined);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.SMACK_DOWN));
|
||||
await mockHitCheck(game, true);
|
||||
await game.move.forceHit();
|
||||
|
||||
await game.phaseInterceptor.to(DamagePhase);
|
||||
|
||||
|
@ -508,7 +508,7 @@ describe("Abilities - Parental Bond", () => {
|
|||
expect(enemyPokemon).not.toBe(undefined);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.U_TURN));
|
||||
await mockHitCheck(game, true);
|
||||
await game.move.forceHit();
|
||||
|
||||
await game.phaseInterceptor.to(MoveEffectPhase);
|
||||
expect(leadPokemon.turnData.hitCount).toBe(2);
|
||||
|
@ -532,7 +532,7 @@ describe("Abilities - Parental Bond", () => {
|
|||
expect(enemyPokemon).not.toBe(undefined);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.WAKE_UP_SLAP));
|
||||
await mockHitCheck(game, true);
|
||||
await game.move.forceHit();
|
||||
|
||||
await game.phaseInterceptor.to(DamagePhase);
|
||||
|
||||
|
|
|
@ -12,7 +12,7 @@ import Phaser from "phaser";
|
|||
import { afterEach, beforeAll, beforeEach, describe, expect, test, vi } from "vitest";
|
||||
import GameManager from "#test/utils/gameManager";
|
||||
import { getMovePosition } from "#test/utils/gameManagerUtils";
|
||||
import { mockHitCheck, SPLASH_ONLY } from "#test/utils/testUtils";
|
||||
import { SPLASH_ONLY } from "#test/utils/testUtils";
|
||||
|
||||
const TIMEOUT = 20 * 1000;
|
||||
|
||||
|
@ -192,7 +192,7 @@ describe("Abilities - Protean", () => {
|
|||
expect(leadPokemon).not.toBe(undefined);
|
||||
|
||||
game.doAttack(getMovePosition(game.scene, 0, Moves.TACKLE));
|
||||
await mockHitCheck(game, false);
|
||||
await game.move.forceMiss();
|
||||
await game.phaseInterceptor.to(TurnEndPhase);
|
||||
|
||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||
|
|
|
@ -8,7 +8,7 @@ import { getMovePosition } from "#test/utils/gameManagerUtils";
|
|||
import { BattlerTagType } from "#app/enums/battler-tag-type.js";
|
||||
import { Abilities } from "#app/enums/abilities.js";
|
||||
import { BattlerIndex } from "#app/battle.js";
|
||||
import { mockHitCheck, SPLASH_ONLY } from "#test/utils/testUtils";
|
||||
import { SPLASH_ONLY } from "#test/utils/testUtils";
|
||||
|
||||
describe("Abilities - Sweet Veil", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
|
@ -80,11 +80,11 @@ describe("Abilities - Sweet Veil", () => {
|
|||
game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH));
|
||||
|
||||
// First pokemon move
|
||||
await mockHitCheck(game, true);
|
||||
await game.move.forceHit();
|
||||
|
||||
// Second pokemon move
|
||||
await game.phaseInterceptor.to(MovePhase, false);
|
||||
await mockHitCheck(game, true);
|
||||
await game.move.forceHit();
|
||||
|
||||
expect(game.scene.getPlayerField().some(p => !!p.getTag(BattlerTagType.DROWSY))).toBe(true);
|
||||
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
import { BattleStat } from "#app/data/battle-stat.js";
|
||||
import { MoveEffectPhase, MoveEndPhase, StatChangePhase } from "#app/phases";
|
||||
import { MoveEndPhase, StatChangePhase } from "#app/phases";
|
||||
import GameManager from "#test/utils/gameManager";
|
||||
import { getMovePosition } from "#test/utils/gameManagerUtils";
|
||||
import { Abilities } from "#enums/abilities";
|
||||
import { Moves } from "#enums/moves";
|
||||
import { Species } from "#enums/species";
|
||||
import Phaser from "phaser";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||
import { SPLASH_ONLY } from "#test/utils/testUtils";
|
||||
|
||||
const TIMEOUT = 20 * 1000;
|
||||
|
@ -91,11 +91,8 @@ describe("Moves - Make It Rain", () => {
|
|||
game.doAttack(getMovePosition(game.scene, 0, Moves.MAKE_IT_RAIN));
|
||||
game.doAttack(getMovePosition(game.scene, 1, Moves.SPLASH));
|
||||
|
||||
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
||||
|
||||
// Make Make It Rain miss the first target
|
||||
const moveEffectPhase = game.scene.getCurrentPhase() as MoveEffectPhase;
|
||||
vi.spyOn(moveEffectPhase, "hitCheck").mockReturnValueOnce(false);
|
||||
await game.move.forceMiss(true);
|
||||
|
||||
await game.phaseInterceptor.to(MoveEndPhase);
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ import { ModifierTypeOption, modifierTypes } from "#app/modifier/modifier-type.j
|
|||
import overrides from "#app/overrides.js";
|
||||
import { removeEnemyHeldItems } from "./testUtils";
|
||||
import ModifierSelectUiHandler from "#app/ui/modifier-select-ui-handler.js";
|
||||
import { MoveHelper } from "./moveHelper";
|
||||
|
||||
/**
|
||||
* Class to manage the game state and transitions between phases.
|
||||
|
@ -39,6 +40,7 @@ export default class GameManager {
|
|||
public textInterceptor: TextInterceptor;
|
||||
public inputsHandler: InputsHandler;
|
||||
public readonly override: OverridesHelper;
|
||||
public readonly move: MoveHelper;
|
||||
|
||||
/**
|
||||
* Creates an instance of GameManager.
|
||||
|
@ -55,6 +57,7 @@ export default class GameManager {
|
|||
this.textInterceptor = new TextInterceptor(this.scene);
|
||||
this.gameWrapper.setScene(this.scene);
|
||||
this.override = new OverridesHelper(this);
|
||||
this.move = new MoveHelper(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
import GameManager from "./gameManager";
|
||||
|
||||
/**
|
||||
* Base class for defining all game helpers.
|
||||
*/
|
||||
export abstract class GameManagerHelper {
|
||||
protected readonly game: GameManager;
|
||||
|
||||
constructor(game: GameManager) {
|
||||
this.game = game;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
import { vi } from "vitest";
|
||||
import { MoveEffectPhase } from "#app/phases.js";
|
||||
import { GameManagerHelper } from "./gameManagerHelper";
|
||||
|
||||
/**
|
||||
* Helper to handle a Pokemon's move
|
||||
*/
|
||||
export class MoveHelper extends GameManagerHelper {
|
||||
/**
|
||||
* Intercepts `MoveEffectPhase` and mocks the hitCheck's
|
||||
* return value to `true` {@linkcode MoveEffectPhase.hitCheck}.
|
||||
* Used to force a move to hit.
|
||||
*/
|
||||
async forceHit(): Promise<void> {
|
||||
await this.game.phaseInterceptor.to(MoveEffectPhase, false);
|
||||
vi.spyOn(this.game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValue(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Intercepts `MoveEffectPhase` and mocks the hitCheck's
|
||||
* return value to `false` {@linkcode MoveEffectPhase.hitCheck}.
|
||||
* Used to force a move to miss.
|
||||
* @param firstTargetOnly Whether the move should force miss on the first target only, in the case of multi-hit moves.
|
||||
*/
|
||||
async forceMiss(firstTargetOnly: boolean = false): Promise<void> {
|
||||
await this.game.phaseInterceptor.to(MoveEffectPhase, false);
|
||||
const hitCheck = vi.spyOn(this.game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck");
|
||||
|
||||
if (firstTargetOnly) {
|
||||
hitCheck.mockReturnValueOnce(false);
|
||||
} else {
|
||||
hitCheck.mockReturnValue(false);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -8,19 +8,13 @@ import * as GameMode from "#app/game-mode";
|
|||
import { GameModes, getGameMode } from "#app/game-mode";
|
||||
import { ModifierOverride } from "#app/modifier/modifier-type.js";
|
||||
import Overrides from "#app/overrides";
|
||||
import GameManager from "#test/utils/gameManager";
|
||||
import { vi } from "vitest";
|
||||
import { GameManagerHelper } from "./gameManagerHelper";
|
||||
|
||||
/**
|
||||
* Helper to handle overrides in tests
|
||||
*/
|
||||
export class OverridesHelper {
|
||||
private readonly game: GameManager;
|
||||
|
||||
constructor(game: GameManager) {
|
||||
this.game = game;
|
||||
}
|
||||
|
||||
export class OverridesHelper extends GameManagerHelper {
|
||||
/**
|
||||
* Override the starting biome
|
||||
* @warning Any event listeners that are attached to [NewArenaEvent](events\battle-scene.ts) may need to be handled down the line
|
||||
|
|
|
@ -3,7 +3,7 @@ import i18next, { type ParseKeys } from "i18next";
|
|||
import { vi } from "vitest";
|
||||
import GameManager from "./gameManager";
|
||||
import { BattlerIndex } from "#app/battle.js";
|
||||
import { MoveEffectPhase, TurnStartPhase } from "#app/phases.js";
|
||||
import { TurnStartPhase } from "#app/phases.js";
|
||||
|
||||
/** Ready to use array of Moves.SPLASH x4 */
|
||||
export const SPLASH_ONLY = [Moves.SPLASH, Moves.SPLASH, Moves.SPLASH, Moves.SPLASH];
|
||||
|
@ -54,19 +54,3 @@ export async function mockTurnOrder(game: GameManager, order: BattlerIndex[]): P
|
|||
|
||||
vi.spyOn(game.scene.getCurrentPhase() as TurnStartPhase, "getOrder").mockReturnValue(order);
|
||||
}
|
||||
|
||||
/**
|
||||
* Intercepts `MoveEffectPhase` and mocks the hitCheck's return value {@linkcode MoveEffectPhase.hitCheck}.
|
||||
* Used to force a move to either hit or miss.
|
||||
* Note that this uses `mockReturnValue()`, meaning it will also apply to a
|
||||
* succeeding `MoveEffectPhase` immediately following the first one
|
||||
* (in the case of a multi-target move)
|
||||
*
|
||||
* @param {GameManager} game The GameManager instance
|
||||
* @param shouldHit Whether the move should hit
|
||||
*/
|
||||
export async function mockHitCheck(game: GameManager, shouldHit: boolean): Promise<void> {
|
||||
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
||||
|
||||
vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValue(shouldHit);
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue