mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-07-15 12:52:20 +02:00
Update tests to reflect move effect phase changes
Co-authored-by: innerthunder <brandonerickson98@gmail.com>
This commit is contained in:
parent
f85e008202
commit
f29486cd4e
@ -669,10 +669,10 @@ export default class Move implements Localizable {
|
|||||||
case MoveFlags.REFLECTABLE:
|
case MoveFlags.REFLECTABLE:
|
||||||
// If the target is not semi-invulnerable and either has magic coat active or an unignored magic bounce ability
|
// If the target is not semi-invulnerable and either has magic coat active or an unignored magic bounce ability
|
||||||
if (
|
if (
|
||||||
target?.getTag(SemiInvulnerableTag) &&
|
target?.getTag(SemiInvulnerableTag) ||
|
||||||
(target.getTag(BattlerTagType.MAGIC_COAT) ||
|
!(target?.getTag(BattlerTagType.MAGIC_COAT) ||
|
||||||
(!this.doesFlagEffectApply({ flag: MoveFlags.IGNORE_ABILITIES, user, target }) &&
|
(!this.doesFlagEffectApply({ flag: MoveFlags.IGNORE_ABILITIES, user, target }) &&
|
||||||
target.hasAbilityWithAttr(ReflectStatusMoveAbAttr)))
|
target?.hasAbilityWithAttr(ReflectStatusMoveAbAttr)))
|
||||||
) {
|
) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -2733,11 +2733,11 @@ export class StealEatBerryAttr extends EatBerryAttr {
|
|||||||
}
|
}
|
||||||
/**
|
/**
|
||||||
* User steals a random berry from the target and then eats it.
|
* User steals a random berry from the target and then eats it.
|
||||||
* @param {Pokemon} user Pokemon that used the move and will eat the stolen berry
|
* @param user - Pokemon that used the move and will eat the stolen berry
|
||||||
* @param {Pokemon} target Pokemon that will have its berry stolen
|
* @param target - Pokemon that will have its berry stolen
|
||||||
* @param {Move} move Move being used
|
* @param move - Move being used
|
||||||
* @param {any[]} args Unused
|
* @param args Unused
|
||||||
* @returns {boolean} true if the function succeeds
|
* @returns true if the function succeeds
|
||||||
*/
|
*/
|
||||||
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): boolean {
|
||||||
const cancelled = new BooleanHolder(false);
|
const cancelled = new BooleanHolder(false);
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
export enum MoveEffectTrigger {
|
export enum MoveEffectTrigger {
|
||||||
PRE_APPLY,
|
PRE_APPLY,
|
||||||
POST_APPLY,
|
POST_APPLY,
|
||||||
HIT,
|
|
||||||
/** Triggers one time after all target effects have applied */
|
/** Triggers one time after all target effects have applied */
|
||||||
POST_TARGET
|
POST_TARGET
|
||||||
}
|
}
|
||||||
|
@ -151,8 +151,6 @@ export class MoveEffectPhase extends PokemonPhase {
|
|||||||
|
|
||||||
let targets = this.getTargets();
|
let targets = this.getTargets();
|
||||||
|
|
||||||
let fieldBounce = false;
|
|
||||||
|
|
||||||
// For field targeted moves, we only look for the first target that may magic bounce
|
// For field targeted moves, we only look for the first target that may magic bounce
|
||||||
|
|
||||||
for (const [i, target] of targets.entries()) {
|
for (const [i, target] of targets.entries()) {
|
||||||
@ -162,7 +160,6 @@ export class MoveEffectPhase extends PokemonPhase {
|
|||||||
if (fieldMove && hitCheck[0] === HitCheckResult.REFLECTED) {
|
if (fieldMove && hitCheck[0] === HitCheckResult.REFLECTED) {
|
||||||
targets = [target];
|
targets = [target];
|
||||||
this.hitChecks = [hitCheck];
|
this.hitChecks = [hitCheck];
|
||||||
fieldBounce = true;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (hitCheck[0] === HitCheckResult.HIT) {
|
if (hitCheck[0] === HitCheckResult.HIT) {
|
||||||
@ -173,13 +170,8 @@ export class MoveEffectPhase extends PokemonPhase {
|
|||||||
this.hitChecks[i] = hitCheck;
|
this.hitChecks[i] = hitCheck;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (anySuccess || (fieldMove && !fieldBounce)) {
|
if (anySuccess) {
|
||||||
this.moveHistoryEntry.result = MoveResult.SUCCESS;
|
this.moveHistoryEntry.result = MoveResult.SUCCESS;
|
||||||
// Unreflected field moves have no targets; they target the field
|
|
||||||
if (fieldMove) {
|
|
||||||
this.hitChecks = [];
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
user.turnData.hitCount = 1;
|
user.turnData.hitCount = 1;
|
||||||
user.turnData.hitsLeft = 1;
|
user.turnData.hitsLeft = 1;
|
||||||
@ -350,6 +342,9 @@ export class MoveEffectPhase extends PokemonPhase {
|
|||||||
|
|
||||||
const targets = this.conductHitChecks(user, fieldMove);
|
const targets = this.conductHitChecks(user, fieldMove);
|
||||||
|
|
||||||
|
this.firstHit = user.turnData.hitCount === user.turnData.hitsLeft;
|
||||||
|
this.lastHit = user.turnData.hitsLeft === 1 || !targets.some(t => t.isActive(true));
|
||||||
|
|
||||||
// only play the animation if the move had at least one successful target
|
// only play the animation if the move had at least one successful target
|
||||||
|
|
||||||
// Play the animation if the move was successful against any of its targets or it has a POST_TARGET effect (like self destruct)
|
// Play the animation if the move was successful against any of its targets or it has a POST_TARGET effect (like self destruct)
|
||||||
@ -375,6 +370,7 @@ export class MoveEffectPhase extends PokemonPhase {
|
|||||||
* Callback to be called after the move animation is played
|
* Callback to be called after the move animation is played
|
||||||
*/
|
*/
|
||||||
private postAnimCallback(user: Pokemon, targets: Pokemon[]) {
|
private postAnimCallback(user: Pokemon, targets: Pokemon[]) {
|
||||||
|
console.log("============Inside post anim callback======");
|
||||||
// Add to the move history entry
|
// Add to the move history entry
|
||||||
if (this.firstHit) {
|
if (this.firstHit) {
|
||||||
user.pushMoveHistory(this.moveHistoryEntry);
|
user.pushMoveHistory(this.moveHistoryEntry);
|
||||||
@ -387,7 +383,10 @@ export class MoveEffectPhase extends PokemonPhase {
|
|||||||
console.warn(e.message || "Unexpected error in move effect phase");
|
console.warn(e.message || "Unexpected error in move effect phase");
|
||||||
this.end();
|
this.end();
|
||||||
}
|
}
|
||||||
//
|
// Apply queued phases
|
||||||
|
if (this.queuedPhases.length) {
|
||||||
|
globalScene.appendToPhase(this.queuedPhases, MoveEndPhase);
|
||||||
|
}
|
||||||
const moveType = user.getMoveType(this.move, true);
|
const moveType = user.getMoveType(this.move, true);
|
||||||
if (this.move.category !== MoveCategory.STATUS && !user.stellarTypesBoosted.includes(moveType)) {
|
if (this.move.category !== MoveCategory.STATUS && !user.stellarTypesBoosted.includes(moveType)) {
|
||||||
user.stellarTypesBoosted.push(moveType);
|
user.stellarTypesBoosted.push(moveType);
|
||||||
@ -398,11 +397,6 @@ export class MoveEffectPhase extends PokemonPhase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.updateSubstitutes();
|
this.updateSubstitutes();
|
||||||
|
|
||||||
// Apply queued phases
|
|
||||||
if (this.queuedPhases.length) {
|
|
||||||
globalScene.appendToPhase(this.queuedPhases, MoveEndPhase);
|
|
||||||
}
|
|
||||||
this.end();
|
this.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -592,7 +586,7 @@ export class MoveEffectPhase extends PokemonPhase {
|
|||||||
* @param target - {@linkcode Pokemon} the target to check for protection
|
* @param target - {@linkcode Pokemon} the target to check for protection
|
||||||
* @param move - The {@linkcode Move} being used
|
* @param move - The {@linkcode Move} being used
|
||||||
*/
|
*/
|
||||||
private protectedCheck(user: Pokemon, target: Pokemon, move: Move) {
|
private protectedCheck(user: Pokemon, target: Pokemon) {
|
||||||
/** The {@linkcode ArenaTagSide} to which the target belongs */
|
/** The {@linkcode ArenaTagSide} to which the target belongs */
|
||||||
const targetSide = target.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY;
|
const targetSide = target.isPlayer() ? ArenaTagSide.PLAYER : ArenaTagSide.ENEMY;
|
||||||
/** Has the invoked move been cancelled by conditional protection (e.g Quick Guard)? */
|
/** Has the invoked move been cancelled by conditional protection (e.g Quick Guard)? */
|
||||||
@ -608,7 +602,7 @@ export class MoveEffectPhase extends PokemonPhase {
|
|||||||
hasConditionalProtectApplied,
|
hasConditionalProtectApplied,
|
||||||
user,
|
user,
|
||||||
target,
|
target,
|
||||||
move.id,
|
this.move.id,
|
||||||
bypassIgnoreProtect,
|
bypassIgnoreProtect,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -648,18 +642,21 @@ export class MoveEffectPhase extends PokemonPhase {
|
|||||||
return [HitCheckResult.ERROR, 0];
|
return [HitCheckResult.ERROR, 0];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Moves targeting the user or field bypass accuracy and effectiveness checks
|
// Moves targeting the user bypass all checks
|
||||||
if (move.moveTarget === MoveTarget.USER) {
|
if (move.moveTarget === MoveTarget.USER) {
|
||||||
return [HitCheckResult.HIT, 1];
|
return [HitCheckResult.HIT, 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const fieldTargeted = isFieldTargeted(move);
|
||||||
|
|
||||||
// If the target is not on the field, cancel the hit check
|
// If the target is not on the field, cancel the hit check
|
||||||
if (!target.isActive(true)) {
|
if (!target.isActive(true) && !fieldTargeted) {
|
||||||
return [HitCheckResult.TARGET_NOT_ON_FIELD, 0];
|
return [HitCheckResult.TARGET_NOT_ON_FIELD, 0];
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the target of the move is hidden by the effects of its commander ability, then this misses
|
// If the target of the move is hidden by the effects of its commander ability, then this misses
|
||||||
if (
|
if (
|
||||||
|
!fieldTargeted &&
|
||||||
globalScene.currentBattle.double &&
|
globalScene.currentBattle.double &&
|
||||||
target.getAlly()?.getTag(BattlerTagType.COMMANDED)?.getSourcePokemon() === target
|
target.getAlly()?.getTag(BattlerTagType.COMMANDED)?.getSourcePokemon() === target
|
||||||
) {
|
) {
|
||||||
@ -667,14 +664,15 @@ export class MoveEffectPhase extends PokemonPhase {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Whether both accuracy and invulnerability checks can be skipped */
|
/** Whether both accuracy and invulnerability checks can be skipped */
|
||||||
const bypassAccAndInvuln = this.checkBypassAccAndInvuln(target);
|
const bypassAccAndInvuln = fieldTargeted || this.checkBypassAccAndInvuln(target);
|
||||||
const semiInvulnerableTag = target.getTag(SemiInvulnerableTag);
|
const semiInvulnerableTag = target.getTag(SemiInvulnerableTag);
|
||||||
|
|
||||||
if (semiInvulnerableTag && !bypassAccAndInvuln && !this.checkBypassSemiInvuln(semiInvulnerableTag)) {
|
if (semiInvulnerableTag && !bypassAccAndInvuln && !this.checkBypassSemiInvuln(semiInvulnerableTag)) {
|
||||||
return [HitCheckResult.MISS, 0];
|
return [HitCheckResult.MISS, 0];
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.protectedCheck(user, target, move)) {
|
if (!fieldTargeted && this.protectedCheck(user, target)) {
|
||||||
|
console.log("====== Protected ========");
|
||||||
return [HitCheckResult.PROTECTED, 0];
|
return [HitCheckResult.PROTECTED, 0];
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -682,6 +680,12 @@ export class MoveEffectPhase extends PokemonPhase {
|
|||||||
return [HitCheckResult.REFLECTED, 0];
|
return [HitCheckResult.REFLECTED, 0];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// After the magic bounce check, field targeted moves are always successful
|
||||||
|
if (fieldTargeted) {
|
||||||
|
console.log("====== Field targeted moves overriding hit check ========");
|
||||||
|
return [HitCheckResult.HIT, 1];
|
||||||
|
}
|
||||||
|
|
||||||
const cancelNoEffectMessage = new BooleanHolder(false);
|
const cancelNoEffectMessage = new BooleanHolder(false);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -4,7 +4,6 @@ import { PokemonType } from "#enums/pokemon-type";
|
|||||||
import { Abilities } from "#app/enums/abilities";
|
import { Abilities } from "#app/enums/abilities";
|
||||||
import { Moves } from "#app/enums/moves";
|
import { Moves } from "#app/enums/moves";
|
||||||
import { Species } from "#app/enums/species";
|
import { Species } from "#app/enums/species";
|
||||||
import { HitResult } from "#app/field/pokemon";
|
|
||||||
import GameManager from "#test/testUtils/gameManager";
|
import GameManager from "#test/testUtils/gameManager";
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
@ -38,13 +37,13 @@ describe("Abilities - Galvanize", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("should change Normal-type attacks to Electric type and boost their power", async () => {
|
it("should change Normal-type attacks to Electric type and boost their power", async () => {
|
||||||
await game.startBattle();
|
await game.classicMode.startBattle();
|
||||||
|
|
||||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||||
vi.spyOn(playerPokemon, "getMoveType");
|
vi.spyOn(playerPokemon, "getMoveType");
|
||||||
|
|
||||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||||
vi.spyOn(enemyPokemon, "apply");
|
const spy = vi.spyOn(enemyPokemon, "getMoveEffectiveness");
|
||||||
|
|
||||||
const move = allMoves[Moves.TACKLE];
|
const move = allMoves[Moves.TACKLE];
|
||||||
vi.spyOn(move, "calculateBattlePower");
|
vi.spyOn(move, "calculateBattlePower");
|
||||||
@ -54,21 +53,23 @@ describe("Abilities - Galvanize", () => {
|
|||||||
await game.phaseInterceptor.to("BerryPhase", false);
|
await game.phaseInterceptor.to("BerryPhase", false);
|
||||||
|
|
||||||
expect(playerPokemon.getMoveType).toHaveLastReturnedWith(PokemonType.ELECTRIC);
|
expect(playerPokemon.getMoveType).toHaveLastReturnedWith(PokemonType.ELECTRIC);
|
||||||
expect(enemyPokemon.apply).toHaveReturnedWith(HitResult.EFFECTIVE);
|
expect(spy).toHaveReturnedWith(1);
|
||||||
expect(move.calculateBattlePower).toHaveReturnedWith(48);
|
expect(move.calculateBattlePower).toHaveReturnedWith(48);
|
||||||
expect(enemyPokemon.hp).toBeLessThan(enemyPokemon.getMaxHp());
|
expect(enemyPokemon.hp).toBeLessThan(enemyPokemon.getMaxHp());
|
||||||
|
|
||||||
|
spy.mockRestore();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should cause Normal-type attacks to activate Volt Absorb", async () => {
|
it("should cause Normal-type attacks to activate Volt Absorb", async () => {
|
||||||
game.override.enemyAbility(Abilities.VOLT_ABSORB);
|
game.override.enemyAbility(Abilities.VOLT_ABSORB);
|
||||||
|
|
||||||
await game.startBattle();
|
await game.classicMode.startBattle();
|
||||||
|
|
||||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||||
vi.spyOn(playerPokemon, "getMoveType");
|
vi.spyOn(playerPokemon, "getMoveType");
|
||||||
|
|
||||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||||
vi.spyOn(enemyPokemon, "apply");
|
const spy = vi.spyOn(enemyPokemon, "getMoveEffectiveness");
|
||||||
|
|
||||||
enemyPokemon.hp = Math.floor(enemyPokemon.getMaxHp() * 0.8);
|
enemyPokemon.hp = Math.floor(enemyPokemon.getMaxHp() * 0.8);
|
||||||
|
|
||||||
@ -77,37 +78,37 @@ describe("Abilities - Galvanize", () => {
|
|||||||
await game.phaseInterceptor.to("BerryPhase", false);
|
await game.phaseInterceptor.to("BerryPhase", false);
|
||||||
|
|
||||||
expect(playerPokemon.getMoveType).toHaveLastReturnedWith(PokemonType.ELECTRIC);
|
expect(playerPokemon.getMoveType).toHaveLastReturnedWith(PokemonType.ELECTRIC);
|
||||||
expect(enemyPokemon.apply).toHaveReturnedWith(HitResult.NO_EFFECT);
|
expect(spy).toHaveReturnedWith(0);
|
||||||
expect(enemyPokemon.hp).toBe(enemyPokemon.getMaxHp());
|
expect(enemyPokemon.hp).toBe(enemyPokemon.getMaxHp());
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should not change the type of variable-type moves", async () => {
|
it("should not change the type of variable-type moves", async () => {
|
||||||
game.override.enemySpecies(Species.MIGHTYENA);
|
game.override.enemySpecies(Species.MIGHTYENA);
|
||||||
|
|
||||||
await game.startBattle([Species.ESPEON]);
|
await game.classicMode.startBattle([Species.ESPEON]);
|
||||||
|
|
||||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||||
vi.spyOn(playerPokemon, "getMoveType");
|
vi.spyOn(playerPokemon, "getMoveType");
|
||||||
|
|
||||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||||
vi.spyOn(enemyPokemon, "apply");
|
const spy = vi.spyOn(enemyPokemon, "getMoveEffectiveness");
|
||||||
|
|
||||||
game.move.select(Moves.REVELATION_DANCE);
|
game.move.select(Moves.REVELATION_DANCE);
|
||||||
await game.phaseInterceptor.to("BerryPhase", false);
|
await game.phaseInterceptor.to("BerryPhase", false);
|
||||||
|
|
||||||
expect(playerPokemon.getMoveType).not.toHaveLastReturnedWith(PokemonType.ELECTRIC);
|
expect(playerPokemon.getMoveType).not.toHaveLastReturnedWith(PokemonType.ELECTRIC);
|
||||||
expect(enemyPokemon.apply).toHaveReturnedWith(HitResult.NO_EFFECT);
|
expect(spy).toHaveReturnedWith(0);
|
||||||
expect(enemyPokemon.hp).toBe(enemyPokemon.getMaxHp());
|
expect(enemyPokemon.hp).toBe(enemyPokemon.getMaxHp());
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should affect all hits of a Normal-type multi-hit move", async () => {
|
it("should affect all hits of a Normal-type multi-hit move", async () => {
|
||||||
await game.startBattle();
|
await game.classicMode.startBattle();
|
||||||
|
|
||||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||||
vi.spyOn(playerPokemon, "getMoveType");
|
vi.spyOn(playerPokemon, "getMoveType");
|
||||||
|
|
||||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||||
vi.spyOn(enemyPokemon, "apply");
|
const spy = vi.spyOn(enemyPokemon, "getMoveEffectiveness");
|
||||||
|
|
||||||
game.move.select(Moves.FURY_SWIPES);
|
game.move.select(Moves.FURY_SWIPES);
|
||||||
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
|
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
|
||||||
@ -125,6 +126,6 @@ describe("Abilities - Galvanize", () => {
|
|||||||
expect(enemyPokemon.hp).toBeLessThan(enemyStartingHp);
|
expect(enemyPokemon.hp).toBeLessThan(enemyStartingHp);
|
||||||
}
|
}
|
||||||
|
|
||||||
expect(enemyPokemon.apply).not.toHaveReturnedWith(HitResult.NO_EFFECT);
|
expect(spy).not.toHaveReturnedWith(0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -4,6 +4,7 @@ import { MoveEndPhase } from "#app/phases/move-end-phase";
|
|||||||
import { Abilities } from "#enums/abilities";
|
import { Abilities } from "#enums/abilities";
|
||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
|
import { HitCheckResult } from "#enums/hit-check-result";
|
||||||
import GameManager from "#test/testUtils/gameManager";
|
import GameManager from "#test/testUtils/gameManager";
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, it, expect, vi } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, it, expect, vi } from "vitest";
|
||||||
@ -28,6 +29,7 @@ describe("Abilities - No Guard", () => {
|
|||||||
.moveset(Moves.ZAP_CANNON)
|
.moveset(Moves.ZAP_CANNON)
|
||||||
.ability(Abilities.NO_GUARD)
|
.ability(Abilities.NO_GUARD)
|
||||||
.enemyLevel(200)
|
.enemyLevel(200)
|
||||||
|
.enemySpecies(Species.SNORLAX)
|
||||||
.enemyAbility(Abilities.BALL_FETCH)
|
.enemyAbility(Abilities.BALL_FETCH)
|
||||||
.enemyMoveset(Moves.SPLASH);
|
.enemyMoveset(Moves.SPLASH);
|
||||||
});
|
});
|
||||||
@ -48,7 +50,7 @@ describe("Abilities - No Guard", () => {
|
|||||||
|
|
||||||
await game.phaseInterceptor.to(MoveEndPhase);
|
await game.phaseInterceptor.to(MoveEndPhase);
|
||||||
|
|
||||||
expect(moveEffectPhase.hitCheck).toHaveReturnedWith(true);
|
expect(moveEffectPhase.hitCheck).toHaveReturnedWith([HitCheckResult.HIT, 1]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should guarantee double battle with any one LURE", async () => {
|
it("should guarantee double battle with any one LURE", async () => {
|
||||||
|
@ -52,7 +52,7 @@ describe("Abilities - Shield Dust", () => {
|
|||||||
|
|
||||||
// Shield Dust negates secondary effect
|
// Shield Dust negates secondary effect
|
||||||
const phase = game.scene.getCurrentPhase() as MoveEffectPhase;
|
const phase = game.scene.getCurrentPhase() as MoveEffectPhase;
|
||||||
const move = phase.move.getMove();
|
const move = phase.move;
|
||||||
expect(move.id).toBe(Moves.AIR_SLASH);
|
expect(move.id).toBe(Moves.AIR_SLASH);
|
||||||
|
|
||||||
const chance = new NumberHolder(move.chance);
|
const chance = new NumberHolder(move.chance);
|
||||||
|
@ -25,7 +25,6 @@ describe("Abilities - Super Luck", () => {
|
|||||||
.moveset([Moves.TACKLE])
|
.moveset([Moves.TACKLE])
|
||||||
.ability(Abilities.SUPER_LUCK)
|
.ability(Abilities.SUPER_LUCK)
|
||||||
.battleStyle("single")
|
.battleStyle("single")
|
||||||
.disableCrits()
|
|
||||||
.enemySpecies(Species.MAGIKARP)
|
.enemySpecies(Species.MAGIKARP)
|
||||||
.enemyAbility(Abilities.BALL_FETCH)
|
.enemyAbility(Abilities.BALL_FETCH)
|
||||||
.enemyMoveset(Moves.SPLASH);
|
.enemyMoveset(Moves.SPLASH);
|
||||||
|
@ -2,7 +2,6 @@ import { BattlerIndex } from "#app/battle";
|
|||||||
import { Abilities } from "#app/enums/abilities";
|
import { Abilities } from "#app/enums/abilities";
|
||||||
import { Moves } from "#app/enums/moves";
|
import { Moves } from "#app/enums/moves";
|
||||||
import { Species } from "#app/enums/species";
|
import { Species } from "#app/enums/species";
|
||||||
import { HitResult } from "#app/field/pokemon";
|
|
||||||
import GameManager from "#test/testUtils/gameManager";
|
import GameManager from "#test/testUtils/gameManager";
|
||||||
import Phaser from "phaser";
|
import Phaser from "phaser";
|
||||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
@ -87,13 +86,15 @@ describe("Abilities - Tera Shell", () => {
|
|||||||
await game.classicMode.startBattle([Species.CHARIZARD]);
|
await game.classicMode.startBattle([Species.CHARIZARD]);
|
||||||
|
|
||||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||||
vi.spyOn(playerPokemon, "apply");
|
const spy = vi.spyOn(playerPokemon, "getMoveEffectiveness");
|
||||||
|
|
||||||
game.move.select(Moves.SPLASH);
|
game.move.select(Moves.SPLASH);
|
||||||
|
|
||||||
await game.phaseInterceptor.to("BerryPhase", false);
|
await game.phaseInterceptor.to("BerryPhase", false);
|
||||||
expect(playerPokemon.apply).toHaveLastReturnedWith(HitResult.EFFECTIVE);
|
expect(spy).toHaveLastReturnedWith(1);
|
||||||
expect(playerPokemon.hp).toBe(playerPokemon.getMaxHp() - 40);
|
expect(playerPokemon.hp).toBe(playerPokemon.getMaxHp() - 40);
|
||||||
|
|
||||||
|
spy.mockRestore();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("should change the effectiveness of all strikes of a multi-strike move", async () => {
|
it("should change the effectiveness of all strikes of a multi-strike move", async () => {
|
||||||
@ -102,7 +103,7 @@ describe("Abilities - Tera Shell", () => {
|
|||||||
await game.classicMode.startBattle([Species.SNORLAX]);
|
await game.classicMode.startBattle([Species.SNORLAX]);
|
||||||
|
|
||||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||||
vi.spyOn(playerPokemon, "apply");
|
const spy = vi.spyOn(playerPokemon, "getMoveEffectiveness");
|
||||||
|
|
||||||
game.move.select(Moves.SPLASH);
|
game.move.select(Moves.SPLASH);
|
||||||
|
|
||||||
@ -110,8 +111,9 @@ describe("Abilities - Tera Shell", () => {
|
|||||||
await game.move.forceHit();
|
await game.move.forceHit();
|
||||||
for (let i = 0; i < 2; i++) {
|
for (let i = 0; i < 2; i++) {
|
||||||
await game.phaseInterceptor.to("MoveEffectPhase");
|
await game.phaseInterceptor.to("MoveEffectPhase");
|
||||||
expect(playerPokemon.apply).toHaveLastReturnedWith(HitResult.NOT_VERY_EFFECTIVE);
|
expect(spy).toHaveLastReturnedWith(0.5);
|
||||||
}
|
}
|
||||||
expect(playerPokemon.apply).toHaveReturnedTimes(2);
|
expect(spy).toHaveReturnedTimes(2);
|
||||||
|
spy.mockRestore();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -36,8 +36,7 @@ describe("Items - Dire Hit", () => {
|
|||||||
.enemyMoveset(Moves.SPLASH)
|
.enemyMoveset(Moves.SPLASH)
|
||||||
.moveset([Moves.POUND])
|
.moveset([Moves.POUND])
|
||||||
.startingHeldItems([{ name: "DIRE_HIT" }])
|
.startingHeldItems([{ name: "DIRE_HIT" }])
|
||||||
.battleStyle("single")
|
.battleStyle("single");
|
||||||
.disableCrits();
|
|
||||||
}, 20000);
|
}, 20000);
|
||||||
|
|
||||||
it("should raise CRIT stage by 1", async () => {
|
it("should raise CRIT stage by 1", async () => {
|
||||||
|
@ -28,7 +28,6 @@ describe("Items - Leek", () => {
|
|||||||
.enemyMoveset([Moves.SPLASH, Moves.SPLASH, Moves.SPLASH, Moves.SPLASH])
|
.enemyMoveset([Moves.SPLASH, Moves.SPLASH, Moves.SPLASH, Moves.SPLASH])
|
||||||
.startingHeldItems([{ name: "LEEK" }])
|
.startingHeldItems([{ name: "LEEK" }])
|
||||||
.moveset([Moves.TACKLE])
|
.moveset([Moves.TACKLE])
|
||||||
.disableCrits()
|
|
||||||
.battleStyle("single");
|
.battleStyle("single");
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -27,8 +27,7 @@ describe("Items - Scope Lens", () => {
|
|||||||
.enemyMoveset(Moves.SPLASH)
|
.enemyMoveset(Moves.SPLASH)
|
||||||
.moveset([Moves.POUND])
|
.moveset([Moves.POUND])
|
||||||
.startingHeldItems([{ name: "SCOPE_LENS" }])
|
.startingHeldItems([{ name: "SCOPE_LENS" }])
|
||||||
.battleStyle("single")
|
.battleStyle("single");
|
||||||
.disableCrits();
|
|
||||||
}, 20000);
|
}, 20000);
|
||||||
|
|
||||||
it("should raise CRIT stage by 1", async () => {
|
it("should raise CRIT stage by 1", async () => {
|
||||||
|
@ -57,12 +57,12 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => {
|
|||||||
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2]);
|
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2]);
|
||||||
|
|
||||||
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
||||||
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id);
|
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.id).toBe(fusionFlare.id);
|
||||||
await game.phaseInterceptor.to(DamageAnimPhase, false);
|
await game.phaseInterceptor.to(DamageAnimPhase, false);
|
||||||
expect(fusionFlare.calculateBattlePower).toHaveLastReturnedWith(100);
|
expect(fusionFlare.calculateBattlePower).toHaveLastReturnedWith(100);
|
||||||
|
|
||||||
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
||||||
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id);
|
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.id).toBe(fusionBolt.id);
|
||||||
await game.phaseInterceptor.to(DamageAnimPhase, false);
|
await game.phaseInterceptor.to(DamageAnimPhase, false);
|
||||||
expect(fusionBolt.calculateBattlePower).toHaveLastReturnedWith(200);
|
expect(fusionBolt.calculateBattlePower).toHaveLastReturnedWith(200);
|
||||||
}, 20000);
|
}, 20000);
|
||||||
@ -77,12 +77,12 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => {
|
|||||||
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2]);
|
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2]);
|
||||||
|
|
||||||
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
||||||
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id);
|
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.id).toBe(fusionBolt.id);
|
||||||
await game.phaseInterceptor.to(DamageAnimPhase, false);
|
await game.phaseInterceptor.to(DamageAnimPhase, false);
|
||||||
expect(fusionBolt.calculateBattlePower).toHaveLastReturnedWith(100);
|
expect(fusionBolt.calculateBattlePower).toHaveLastReturnedWith(100);
|
||||||
|
|
||||||
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
||||||
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id);
|
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.id).toBe(fusionFlare.id);
|
||||||
await game.phaseInterceptor.to(DamageAnimPhase, false);
|
await game.phaseInterceptor.to(DamageAnimPhase, false);
|
||||||
expect(fusionFlare.calculateBattlePower).toHaveLastReturnedWith(200);
|
expect(fusionFlare.calculateBattlePower).toHaveLastReturnedWith(200);
|
||||||
}, 20000);
|
}, 20000);
|
||||||
@ -97,7 +97,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => {
|
|||||||
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY]);
|
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY]);
|
||||||
|
|
||||||
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
||||||
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id);
|
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.id).toBe(fusionFlare.id);
|
||||||
await game.phaseInterceptor.to(DamageAnimPhase, false);
|
await game.phaseInterceptor.to(DamageAnimPhase, false);
|
||||||
expect(fusionFlare.calculateBattlePower).toHaveLastReturnedWith(100);
|
expect(fusionFlare.calculateBattlePower).toHaveLastReturnedWith(100);
|
||||||
|
|
||||||
@ -107,7 +107,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => {
|
|||||||
await game.phaseInterceptor.runFrom(MovePhase).to(MoveEndPhase);
|
await game.phaseInterceptor.runFrom(MovePhase).to(MoveEndPhase);
|
||||||
|
|
||||||
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
||||||
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id);
|
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.id).toBe(fusionBolt.id);
|
||||||
await game.phaseInterceptor.to(DamageAnimPhase, false);
|
await game.phaseInterceptor.to(DamageAnimPhase, false);
|
||||||
expect(fusionBolt.calculateBattlePower).toHaveLastReturnedWith(200);
|
expect(fusionBolt.calculateBattlePower).toHaveLastReturnedWith(200);
|
||||||
}, 20000);
|
}, 20000);
|
||||||
@ -123,7 +123,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => {
|
|||||||
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY]);
|
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY]);
|
||||||
|
|
||||||
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
||||||
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id);
|
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.id).toBe(fusionFlare.id);
|
||||||
await game.phaseInterceptor.to(DamageAnimPhase, false);
|
await game.phaseInterceptor.to(DamageAnimPhase, false);
|
||||||
expect(fusionFlare.calculateBattlePower).toHaveLastReturnedWith(100);
|
expect(fusionFlare.calculateBattlePower).toHaveLastReturnedWith(100);
|
||||||
|
|
||||||
@ -132,7 +132,7 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => {
|
|||||||
await game.phaseInterceptor.runFrom(MovePhase).to(MoveEndPhase);
|
await game.phaseInterceptor.runFrom(MovePhase).to(MoveEndPhase);
|
||||||
|
|
||||||
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
||||||
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id);
|
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.id).toBe(fusionBolt.id);
|
||||||
await game.phaseInterceptor.to(DamageAnimPhase, false);
|
await game.phaseInterceptor.to(DamageAnimPhase, false);
|
||||||
expect(fusionBolt.calculateBattlePower).toHaveLastReturnedWith(100);
|
expect(fusionBolt.calculateBattlePower).toHaveLastReturnedWith(100);
|
||||||
}, 20000);
|
}, 20000);
|
||||||
@ -147,12 +147,12 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => {
|
|||||||
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2]);
|
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2]);
|
||||||
|
|
||||||
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
||||||
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id);
|
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.id).toBe(fusionBolt.id);
|
||||||
await game.phaseInterceptor.to(DamageAnimPhase, false);
|
await game.phaseInterceptor.to(DamageAnimPhase, false);
|
||||||
expect(fusionBolt.calculateBattlePower).toHaveLastReturnedWith(100);
|
expect(fusionBolt.calculateBattlePower).toHaveLastReturnedWith(100);
|
||||||
|
|
||||||
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
||||||
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id);
|
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.id).toBe(fusionFlare.id);
|
||||||
await game.phaseInterceptor.to(DamageAnimPhase, false);
|
await game.phaseInterceptor.to(DamageAnimPhase, false);
|
||||||
expect(fusionFlare.calculateBattlePower).toHaveLastReturnedWith(200);
|
expect(fusionFlare.calculateBattlePower).toHaveLastReturnedWith(200);
|
||||||
}, 20000);
|
}, 20000);
|
||||||
@ -191,22 +191,22 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => {
|
|||||||
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY]);
|
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY]);
|
||||||
|
|
||||||
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
||||||
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id);
|
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.id).toBe(fusionBolt.id);
|
||||||
await game.phaseInterceptor.to(DamageAnimPhase, false);
|
await game.phaseInterceptor.to(DamageAnimPhase, false);
|
||||||
expect(fusionBolt.calculateBattlePower).toHaveLastReturnedWith(100);
|
expect(fusionBolt.calculateBattlePower).toHaveLastReturnedWith(100);
|
||||||
|
|
||||||
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
||||||
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id);
|
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.id).toBe(fusionFlare.id);
|
||||||
await game.phaseInterceptor.to(DamageAnimPhase, false);
|
await game.phaseInterceptor.to(DamageAnimPhase, false);
|
||||||
expect(fusionFlare.calculateBattlePower).toHaveLastReturnedWith(200);
|
expect(fusionFlare.calculateBattlePower).toHaveLastReturnedWith(200);
|
||||||
|
|
||||||
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
||||||
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id);
|
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.id).toBe(fusionBolt.id);
|
||||||
await game.phaseInterceptor.to(DamageAnimPhase, false);
|
await game.phaseInterceptor.to(DamageAnimPhase, false);
|
||||||
expect(fusionBolt.calculateBattlePower).toHaveLastReturnedWith(200);
|
expect(fusionBolt.calculateBattlePower).toHaveLastReturnedWith(200);
|
||||||
|
|
||||||
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
||||||
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id);
|
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.id).toBe(fusionFlare.id);
|
||||||
await game.phaseInterceptor.to(DamageAnimPhase, false);
|
await game.phaseInterceptor.to(DamageAnimPhase, false);
|
||||||
expect(fusionFlare.calculateBattlePower).toHaveLastReturnedWith(200);
|
expect(fusionFlare.calculateBattlePower).toHaveLastReturnedWith(200);
|
||||||
}, 20000);
|
}, 20000);
|
||||||
@ -245,22 +245,22 @@ describe("Moves - Fusion Flare and Fusion Bolt", () => {
|
|||||||
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY]);
|
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY_2, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY]);
|
||||||
|
|
||||||
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
||||||
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id);
|
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.id).toBe(fusionBolt.id);
|
||||||
await game.phaseInterceptor.to(DamageAnimPhase, false);
|
await game.phaseInterceptor.to(DamageAnimPhase, false);
|
||||||
expect(fusionBolt.calculateBattlePower).toHaveLastReturnedWith(100);
|
expect(fusionBolt.calculateBattlePower).toHaveLastReturnedWith(100);
|
||||||
|
|
||||||
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
||||||
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id);
|
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.id).toBe(fusionFlare.id);
|
||||||
await game.phaseInterceptor.to(DamageAnimPhase, false);
|
await game.phaseInterceptor.to(DamageAnimPhase, false);
|
||||||
expect(fusionFlare.calculateBattlePower).toHaveLastReturnedWith(200);
|
expect(fusionFlare.calculateBattlePower).toHaveLastReturnedWith(200);
|
||||||
|
|
||||||
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
||||||
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionBolt.id);
|
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.id).toBe(fusionBolt.id);
|
||||||
await game.phaseInterceptor.to(DamageAnimPhase, false);
|
await game.phaseInterceptor.to(DamageAnimPhase, false);
|
||||||
expect(fusionBolt.calculateBattlePower).toHaveLastReturnedWith(200);
|
expect(fusionBolt.calculateBattlePower).toHaveLastReturnedWith(200);
|
||||||
|
|
||||||
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
await game.phaseInterceptor.to(MoveEffectPhase, false);
|
||||||
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.moveId).toBe(fusionFlare.id);
|
expect((game.scene.getCurrentPhase() as MoveEffectPhase).move.id).toBe(fusionFlare.id);
|
||||||
await game.phaseInterceptor.to(DamageAnimPhase, false);
|
await game.phaseInterceptor.to(DamageAnimPhase, false);
|
||||||
expect(fusionFlare.calculateBattlePower).toHaveLastReturnedWith(200);
|
expect(fusionFlare.calculateBattlePower).toHaveLastReturnedWith(200);
|
||||||
}, 20000);
|
}, 20000);
|
||||||
|
@ -4,7 +4,6 @@ import { allMoves, TeraMoveCategoryAttr } from "#app/data/moves/move";
|
|||||||
import type Move from "#app/data/moves/move";
|
import type Move from "#app/data/moves/move";
|
||||||
import { PokemonType } from "#enums/pokemon-type";
|
import { PokemonType } from "#enums/pokemon-type";
|
||||||
import { Abilities } from "#app/enums/abilities";
|
import { Abilities } from "#app/enums/abilities";
|
||||||
import { HitResult } from "#app/field/pokemon";
|
|
||||||
import { Moves } from "#enums/moves";
|
import { Moves } from "#enums/moves";
|
||||||
import { Species } from "#enums/species";
|
import { Species } from "#enums/species";
|
||||||
import GameManager from "#test/testUtils/gameManager";
|
import GameManager from "#test/testUtils/gameManager";
|
||||||
@ -49,9 +48,9 @@ describe("Moves - Tera Blast", () => {
|
|||||||
|
|
||||||
it("changes type to match user's tera type", async () => {
|
it("changes type to match user's tera type", async () => {
|
||||||
game.override.enemySpecies(Species.FURRET);
|
game.override.enemySpecies(Species.FURRET);
|
||||||
await game.startBattle();
|
await game.classicMode.startBattle();
|
||||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||||
vi.spyOn(enemyPokemon, "apply");
|
const spy = vi.spyOn(enemyPokemon, "getMoveEffectiveness");
|
||||||
|
|
||||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||||
playerPokemon.teraType = PokemonType.FIGHTING;
|
playerPokemon.teraType = PokemonType.FIGHTING;
|
||||||
@ -61,11 +60,11 @@ describe("Moves - Tera Blast", () => {
|
|||||||
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
|
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
|
||||||
await game.phaseInterceptor.to("MoveEffectPhase");
|
await game.phaseInterceptor.to("MoveEffectPhase");
|
||||||
|
|
||||||
expect(enemyPokemon.apply).toHaveReturnedWith(HitResult.SUPER_EFFECTIVE);
|
expect(spy).toHaveReturnedWith(2);
|
||||||
}, 20000);
|
}, 20000);
|
||||||
|
|
||||||
it("increases power if user is Stellar tera type", async () => {
|
it("increases power if user is Stellar tera type", async () => {
|
||||||
await game.startBattle();
|
await game.classicMode.startBattle();
|
||||||
|
|
||||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||||
playerPokemon.teraType = PokemonType.STELLAR;
|
playerPokemon.teraType = PokemonType.STELLAR;
|
||||||
@ -79,25 +78,25 @@ describe("Moves - Tera Blast", () => {
|
|||||||
}, 20000);
|
}, 20000);
|
||||||
|
|
||||||
it("is super effective against terastallized targets if user is Stellar tera type", async () => {
|
it("is super effective against terastallized targets if user is Stellar tera type", async () => {
|
||||||
await game.startBattle();
|
await game.classicMode.startBattle();
|
||||||
|
|
||||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||||
playerPokemon.teraType = PokemonType.STELLAR;
|
playerPokemon.teraType = PokemonType.STELLAR;
|
||||||
playerPokemon.isTerastallized = true;
|
playerPokemon.isTerastallized = true;
|
||||||
|
|
||||||
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||||
vi.spyOn(enemyPokemon, "apply");
|
const spy = vi.spyOn(enemyPokemon, "getMoveEffectiveness");
|
||||||
enemyPokemon.isTerastallized = true;
|
enemyPokemon.isTerastallized = true;
|
||||||
|
|
||||||
game.move.select(Moves.TERA_BLAST);
|
game.move.select(Moves.TERA_BLAST);
|
||||||
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
|
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
|
||||||
await game.phaseInterceptor.to("MoveEffectPhase");
|
await game.phaseInterceptor.to("MoveEffectPhase");
|
||||||
|
|
||||||
expect(enemyPokemon.apply).toHaveReturnedWith(HitResult.SUPER_EFFECTIVE);
|
expect(spy).toHaveReturnedWith(2);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("uses the higher ATK for damage calculation", async () => {
|
it("uses the higher ATK for damage calculation", async () => {
|
||||||
await game.startBattle();
|
await game.classicMode.startBattle();
|
||||||
|
|
||||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||||
playerPokemon.stats[Stat.ATK] = 100;
|
playerPokemon.stats[Stat.ATK] = 100;
|
||||||
@ -112,7 +111,7 @@ describe("Moves - Tera Blast", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("uses the higher SPATK for damage calculation", async () => {
|
it("uses the higher SPATK for damage calculation", async () => {
|
||||||
await game.startBattle();
|
await game.classicMode.startBattle();
|
||||||
|
|
||||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||||
playerPokemon.stats[Stat.ATK] = 1;
|
playerPokemon.stats[Stat.ATK] = 1;
|
||||||
@ -127,7 +126,7 @@ describe("Moves - Tera Blast", () => {
|
|||||||
|
|
||||||
it("should stay as a special move if ATK turns lower than SPATK mid-turn", async () => {
|
it("should stay as a special move if ATK turns lower than SPATK mid-turn", async () => {
|
||||||
game.override.enemyMoveset([Moves.CHARM]);
|
game.override.enemyMoveset([Moves.CHARM]);
|
||||||
await game.startBattle();
|
await game.classicMode.startBattle();
|
||||||
|
|
||||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||||
playerPokemon.stats[Stat.ATK] = 51;
|
playerPokemon.stats[Stat.ATK] = 51;
|
||||||
@ -145,7 +144,7 @@ describe("Moves - Tera Blast", () => {
|
|||||||
game.override
|
game.override
|
||||||
.startingHeldItems([{ name: "SPECIES_STAT_BOOSTER", type: "THICK_CLUB" }])
|
.startingHeldItems([{ name: "SPECIES_STAT_BOOSTER", type: "THICK_CLUB" }])
|
||||||
.starterSpecies(Species.CUBONE);
|
.starterSpecies(Species.CUBONE);
|
||||||
await game.startBattle();
|
await game.classicMode.startBattle();
|
||||||
|
|
||||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||||
|
|
||||||
@ -163,7 +162,7 @@ describe("Moves - Tera Blast", () => {
|
|||||||
|
|
||||||
it("does not change its move category from stat changes due to abilities", async () => {
|
it("does not change its move category from stat changes due to abilities", async () => {
|
||||||
game.override.ability(Abilities.HUGE_POWER);
|
game.override.ability(Abilities.HUGE_POWER);
|
||||||
await game.startBattle();
|
await game.classicMode.startBattle();
|
||||||
|
|
||||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||||
playerPokemon.stats[Stat.ATK] = 50;
|
playerPokemon.stats[Stat.ATK] = 50;
|
||||||
@ -178,7 +177,7 @@ describe("Moves - Tera Blast", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it("causes stat drops if user is Stellar tera type", async () => {
|
it("causes stat drops if user is Stellar tera type", async () => {
|
||||||
await game.startBattle();
|
await game.classicMode.startBattle();
|
||||||
|
|
||||||
const playerPokemon = game.scene.getPlayerPokemon()!;
|
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||||
playerPokemon.teraType = PokemonType.STELLAR;
|
playerPokemon.teraType = PokemonType.STELLAR;
|
||||||
|
@ -18,29 +18,29 @@ import { vi } from "vitest";
|
|||||||
*/
|
*/
|
||||||
export class MoveHelper extends GameManagerHelper {
|
export class MoveHelper extends GameManagerHelper {
|
||||||
/**
|
/**
|
||||||
* Intercepts {@linkcode MoveEffectPhase} and mocks the
|
* Intercepts {@linkcode MoveEffectPhase} and mocks the phase's move's
|
||||||
* {@linkcode MoveEffectPhase.hitCheck | hitCheck}'s return value to `true`.
|
* accuracy to -1, guaranteeing a hit.
|
||||||
* Used to force a move to hit.
|
|
||||||
*/
|
*/
|
||||||
public async forceHit(): Promise<void> {
|
public async forceHit(): Promise<void> {
|
||||||
await this.game.phaseInterceptor.to(MoveEffectPhase, false);
|
await this.game.phaseInterceptor.to(MoveEffectPhase, false);
|
||||||
vi.spyOn(this.game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck").mockReturnValue(true);
|
const moveEffectPhase = this.game.scene.getCurrentPhase() as MoveEffectPhase;
|
||||||
|
vi.spyOn(moveEffectPhase.move, "calculateBattleAccuracy").mockReturnValue(-1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Intercepts {@linkcode MoveEffectPhase} and mocks the
|
* Intercepts {@linkcode MoveEffectPhase} and mocks the phase's move's accuracy
|
||||||
* {@linkcode MoveEffectPhase.hitCheck | hitCheck}'s return value to `false`.
|
* to 0, guaranteeing a miss.
|
||||||
* 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-target moves.
|
* @param firstTargetOnly - Whether the move should force miss on the first target only, in the case of multi-target moves.
|
||||||
*/
|
*/
|
||||||
public async forceMiss(firstTargetOnly = false): Promise<void> {
|
public async forceMiss(firstTargetOnly = false): Promise<void> {
|
||||||
await this.game.phaseInterceptor.to(MoveEffectPhase, false);
|
await this.game.phaseInterceptor.to(MoveEffectPhase, false);
|
||||||
const hitCheck = vi.spyOn(this.game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck");
|
const moveEffectPhase = this.game.scene.getCurrentPhase() as MoveEffectPhase;
|
||||||
|
const accuracy = vi.spyOn(moveEffectPhase.move, "calculateBattleAccuracy");
|
||||||
|
|
||||||
if (firstTargetOnly) {
|
if (firstTargetOnly) {
|
||||||
hitCheck.mockReturnValueOnce(false);
|
accuracy.mockReturnValueOnce(0);
|
||||||
} else {
|
} else {
|
||||||
hitCheck.mockReturnValue(false);
|
accuracy.mockReturnValue(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user