mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-06-21 00:52:47 +02:00
Fixed groundedness checks in code
This commit is contained in:
parent
4e9655e129
commit
e59bf5254f
@ -9910,7 +9910,9 @@ export function initMoves() {
|
||||
.attr(AddBattlerTagAttr, BattlerTagType.INTERRUPTED)
|
||||
.attr(RemoveBattlerTagAttr, [ BattlerTagType.FLYING, BattlerTagType.FLOATING, BattlerTagType.TELEKINESIS ])
|
||||
.attr(HitsTagAttr, BattlerTagType.FLYING)
|
||||
.makesContact(false),
|
||||
.makesContact(false)
|
||||
// TODO: Confirm if Smack Down & Thousand Arrows will ground semi-invulnerable Pokemon with No Guard, etc.
|
||||
.edgeCase(),
|
||||
new AttackMove(MoveId.STORM_THROW, PokemonType.FIGHTING, MoveCategory.PHYSICAL, 60, 100, 10, -1, 0, 5)
|
||||
.attr(CritOnlyAttr),
|
||||
new AttackMove(MoveId.FLAME_BURST, PokemonType.FIRE, MoveCategory.SPECIAL, 70, 100, 15, -1, 0, 5)
|
||||
@ -10365,7 +10367,9 @@ export function initMoves() {
|
||||
.attr(AddBattlerTagAttr, BattlerTagType.INTERRUPTED)
|
||||
.attr(RemoveBattlerTagAttr, [ BattlerTagType.FLYING, BattlerTagType.FLOATING, BattlerTagType.TELEKINESIS ])
|
||||
.makesContact(false)
|
||||
.target(MoveTarget.ALL_NEAR_ENEMIES),
|
||||
.target(MoveTarget.ALL_NEAR_ENEMIES)
|
||||
// TODO: Confirm if Smack Down & Thousand Arrows will ground semi-invulnerable Pokemon with No Guard, etc.
|
||||
.edgeCase(),
|
||||
new AttackMove(MoveId.THOUSAND_WAVES, PokemonType.GROUND, MoveCategory.PHYSICAL, 90, 100, 10, -1, 0, 6)
|
||||
.attr(AddBattlerTagAttr, BattlerTagType.TRAPPED, false, false, 1, 1, true)
|
||||
.makesContact(false)
|
||||
|
@ -2268,6 +2268,7 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
*
|
||||
* To be considered grounded, a Pokemon must either:
|
||||
* * Be {@linkcode GroundedTag | forcibly grounded} from an effect like Smack Down or Ingrain
|
||||
* * Be under the effects of {@linkcode ArenaTagType.GRAVITY | harsh gravity}
|
||||
* * **Not** be any of the following things:
|
||||
* * {@linkcode PokemonType.FLYING | Flying-type}
|
||||
* * {@linkcode Abilities.LEVITATE | Levitating}
|
||||
@ -2280,11 +2281,11 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
public isGrounded(ignoreSemiInvulnerable = false): boolean {
|
||||
return (
|
||||
!!this.getTag(GroundedTag) ||
|
||||
!!globalScene.arena.hasTag(ArenaTagType.GRAVITY) ||
|
||||
(!this.isOfType(PokemonType.FLYING, true, true) &&
|
||||
!this.hasAbility(AbilityId.LEVITATE) &&
|
||||
!this.getTag(BattlerTagType.FLOATING) &&
|
||||
ignoreSemiInvulnerable || !this.getTag(SemiInvulnerableTag)
|
||||
)
|
||||
(ignoreSemiInvulnerable || !this.getTag(SemiInvulnerableTag)))
|
||||
);
|
||||
}
|
||||
|
||||
@ -2462,7 +2463,8 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
|
||||
|
||||
// Handle flying v ground type immunity without removing flying type so effective types are still effective
|
||||
// Related to https://github.com/pagefaultgames/pokerogue/issues/524
|
||||
if (moveType === PokemonType.GROUND && (this.isGrounded() || arena.hasTag(ArenaTagType.GRAVITY))) {
|
||||
//
|
||||
if (moveType === PokemonType.GROUND && this.isGrounded(true)) {
|
||||
const flyingIndex = types.indexOf(PokemonType.FLYING);
|
||||
if (flyingIndex > -1) {
|
||||
types.splice(flyingIndex, 1);
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { BattlerIndex } from "#enums/battler-index";
|
||||
import { AbilityId } from "#enums/ability-id";
|
||||
import { BattlerTagType } from "#app/enums/battler-tag-type";
|
||||
import { MoveResult } from "#app/field/pokemon";
|
||||
import { MoveResult } from "#enums/move-result";
|
||||
import { MoveId } from "#enums/move-id";
|
||||
import { SpeciesId } from "#enums/species-id";
|
||||
import { StatusEffect } from "#enums/status-effect";
|
||||
|
@ -8,6 +8,8 @@ import { SpeciesId } from "#enums/species-id";
|
||||
import GameManager from "#test/testUtils/gameManager";
|
||||
import Phaser from "phaser";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||
import { StatusEffect } from "#enums/status-effect";
|
||||
import { MoveResult } from "#enums/move-result";
|
||||
|
||||
describe("Arena - Gravity", () => {
|
||||
let phaserGame: Phaser.Game;
|
||||
@ -27,130 +29,129 @@ describe("Arena - Gravity", () => {
|
||||
game = new GameManager(phaserGame);
|
||||
game.override
|
||||
.battleStyle("single")
|
||||
.moveset([MoveId.TACKLE, MoveId.GRAVITY, MoveId.FISSURE])
|
||||
.ability(AbilityId.UNNERVE)
|
||||
.enemyAbility(AbilityId.BALL_FETCH)
|
||||
.enemySpecies(SpeciesId.SHUCKLE)
|
||||
.enemyMoveset(MoveId.SPLASH)
|
||||
.enemySpecies(SpeciesId.MAGIKARP)
|
||||
.enemyLevel(5);
|
||||
});
|
||||
|
||||
// Reference: https://bulbapedia.bulbagarden.net/wiki/Gravity_(move)
|
||||
|
||||
it("non-OHKO move accuracy is multiplied by 1.67", async () => {
|
||||
const moveToCheck = allMoves[MoveId.TACKLE];
|
||||
|
||||
vi.spyOn(moveToCheck, "calculateBattleAccuracy");
|
||||
|
||||
// Setup Gravity on first turn
|
||||
it("should multiply all non-OHKO move accuracy by 1.67x", async () => {
|
||||
const accSpy = vi.spyOn(allMoves[MoveId.TACKLE], "calculateBattleAccuracy");
|
||||
await game.classicMode.startBattle([SpeciesId.PIKACHU]);
|
||||
game.move.select(MoveId.GRAVITY);
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
game.move.use(MoveId.GRAVITY);
|
||||
await game.move.forceEnemyMove(MoveId.TACKLE);
|
||||
await game.toEndOfTurn();
|
||||
|
||||
expect(game.scene.arena.getTag(ArenaTagType.GRAVITY)).toBeDefined();
|
||||
|
||||
// Use non-OHKO move on second turn
|
||||
await game.toNextTurn();
|
||||
game.move.select(MoveId.TACKLE);
|
||||
await game.phaseInterceptor.to("MoveEffectPhase");
|
||||
|
||||
expect(moveToCheck.calculateBattleAccuracy).toHaveLastReturnedWith(100 * 1.67);
|
||||
expect(accSpy).toHaveLastReturnedWith(allMoves[MoveId.TACKLE].accuracy * 1.67);
|
||||
});
|
||||
|
||||
it("OHKO move accuracy is not affected", async () => {
|
||||
/** See Fissure {@link https://bulbapedia.bulbagarden.net/wiki/Fissure_(move)} */
|
||||
const moveToCheck = allMoves[MoveId.FISSURE];
|
||||
|
||||
vi.spyOn(moveToCheck, "calculateBattleAccuracy");
|
||||
|
||||
// Setup Gravity on first turn
|
||||
it("should not affect OHKO move accuracy", async () => {
|
||||
const accSpy = vi.spyOn(allMoves[MoveId.FISSURE], "calculateBattleAccuracy");
|
||||
await game.classicMode.startBattle([SpeciesId.PIKACHU]);
|
||||
game.move.select(MoveId.GRAVITY);
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
game.move.use(MoveId.GRAVITY);
|
||||
await game.move.forceEnemyMove(MoveId.FISSURE);
|
||||
await game.toEndOfTurn();
|
||||
|
||||
expect(game.scene.arena.getTag(ArenaTagType.GRAVITY)).toBeDefined();
|
||||
|
||||
// Use OHKO move on second turn
|
||||
await game.toNextTurn();
|
||||
game.move.select(MoveId.FISSURE);
|
||||
await game.phaseInterceptor.to("MoveEffectPhase");
|
||||
|
||||
expect(moveToCheck.calculateBattleAccuracy).toHaveLastReturnedWith(30);
|
||||
expect(accSpy).toHaveLastReturnedWith(allMoves[MoveId.FISSURE].accuracy);
|
||||
});
|
||||
|
||||
describe("Against flying types", () => {
|
||||
it("can be hit by ground-type moves now", async () => {
|
||||
game.override.enemySpecies(SpeciesId.PIDGEOT).moveset([MoveId.GRAVITY, MoveId.EARTHQUAKE]);
|
||||
describe.each<{ name: string; overrides: () => unknown }>([
|
||||
{ name: "Flying-type", overrides: () => game.override.enemySpecies(SpeciesId.MOLTRES) },
|
||||
{ name: "Levitating", overrides: () => game.override.enemyAbility(AbilityId.LEVITATE) },
|
||||
])("should ground $name Pokemon", ({ overrides }) => {
|
||||
beforeEach(overrides);
|
||||
|
||||
it("should remove immunity to Ground-type moves", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.PIKACHU]);
|
||||
|
||||
const pidgeot = game.scene.getEnemyPokemon()!;
|
||||
vi.spyOn(pidgeot, "getAttackTypeEffectiveness");
|
||||
const enemy = game.field.getEnemyPokemon();
|
||||
const effectivenessSpy = vi.spyOn(enemy, "getAttackTypeEffectiveness");
|
||||
|
||||
// Try earthquake on 1st turn (fails!);
|
||||
game.move.select(MoveId.EARTHQUAKE);
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
expect(pidgeot.getAttackTypeEffectiveness).toHaveLastReturnedWith(0);
|
||||
|
||||
// Setup Gravity on 2nd turn
|
||||
game.move.use(MoveId.EARTHQUAKE);
|
||||
await game.move.forceEnemyMove(MoveId.GRAVITY);
|
||||
await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
|
||||
await game.toNextTurn();
|
||||
game.move.select(MoveId.GRAVITY);
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
expect(game.scene.arena.getTag(ArenaTagType.GRAVITY)).toBeDefined();
|
||||
|
||||
// Use ground move on 3rd turn
|
||||
await game.toNextTurn();
|
||||
game.move.select(MoveId.EARTHQUAKE);
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
expect(pidgeot.getAttackTypeEffectiveness).toHaveLastReturnedWith(1);
|
||||
expect(effectivenessSpy).toHaveLastReturnedWith(2);
|
||||
expect(enemy.isGrounded()).toBe(true);
|
||||
});
|
||||
|
||||
it("keeps super-effective moves super-effective after using gravity", async () => {
|
||||
game.override.enemySpecies(SpeciesId.PIDGEOT).moveset([MoveId.GRAVITY, MoveId.THUNDERBOLT]);
|
||||
|
||||
it("should preserve normal move effectiveness for secondary type", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.PIKACHU]);
|
||||
|
||||
const pidgeot = game.scene.getEnemyPokemon()!;
|
||||
vi.spyOn(pidgeot, "getAttackTypeEffectiveness");
|
||||
const enemy = game.field.getEnemyPokemon();
|
||||
const effectivenessSpy = vi.spyOn(enemy, "getAttackTypeEffectiveness");
|
||||
|
||||
// Setup Gravity on 1st turn
|
||||
game.move.select(MoveId.GRAVITY);
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
game.move.use(MoveId.THUNDERBOLT);
|
||||
await game.move.forceEnemyMove(MoveId.GRAVITY);
|
||||
await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
|
||||
await game.toEndOfTurn();
|
||||
|
||||
expect(game.scene.arena.getTag(ArenaTagType.GRAVITY)).toBeDefined();
|
||||
expect(effectivenessSpy).toHaveLastReturnedWith(2);
|
||||
});
|
||||
|
||||
// Use electric move on 2nd turn
|
||||
it("causes terrain to come into effect", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.PIKACHU]);
|
||||
|
||||
const enemy = game.field.getEnemyPokemon();
|
||||
enemy.hp = 1;
|
||||
const statusSpy = vi.spyOn(enemy, "canSetStatus");
|
||||
|
||||
// Turn 1: set up electric terrain; spore works due to being ungrounded
|
||||
game.move.use(MoveId.SPORE);
|
||||
await game.move.forceEnemyMove(MoveId.ELECTRIC_TERRAIN);
|
||||
await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
|
||||
await game.toNextTurn();
|
||||
game.move.select(MoveId.THUNDERBOLT);
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
|
||||
expect(pidgeot.getAttackTypeEffectiveness).toHaveLastReturnedWith(2);
|
||||
expect(statusSpy).toHaveLastReturnedWith(true);
|
||||
expect(enemy.status?.effect).toBe(StatusEffect.SLEEP);
|
||||
|
||||
enemy.resetStatus();
|
||||
|
||||
// Turn 2: gravity grounds enemy; makes spore fail
|
||||
game.move.use(MoveId.SPORE);
|
||||
await game.move.forceEnemyMove(MoveId.GRAVITY);
|
||||
await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
|
||||
await game.toNextTurn();
|
||||
|
||||
expect(statusSpy).toHaveLastReturnedWith(true);
|
||||
expect(enemy.status?.effect).toBeUndefined();
|
||||
});
|
||||
});
|
||||
|
||||
it("cancels Fly if its user is semi-invulnerable", async () => {
|
||||
game.override.enemySpecies(SpeciesId.SNORLAX).enemyMoveset(MoveId.FLY).moveset([MoveId.GRAVITY, MoveId.SPLASH]);
|
||||
|
||||
it.each<{ name: string; move: MoveId }>([
|
||||
{ name: "Fly", move: MoveId.FLY },
|
||||
{ name: "Bounce", move: MoveId.BOUNCE },
|
||||
{ name: "Sky Drop", move: MoveId.SKY_DROP },
|
||||
])("cancels $name if its user is semi-invulnerable", async ({ move }) => {
|
||||
await game.classicMode.startBattle([SpeciesId.CHARIZARD]);
|
||||
|
||||
const charizard = game.scene.getPlayerPokemon()!;
|
||||
const snorlax = game.scene.getEnemyPokemon()!;
|
||||
|
||||
game.move.select(MoveId.SPLASH);
|
||||
const charizard = game.field.getPlayerPokemon();
|
||||
const snorlax = game.field.getEnemyPokemon();
|
||||
|
||||
game.move.use(MoveId.SPLASH);
|
||||
await game.move.forceEnemyMove(move);
|
||||
await game.toNextTurn();
|
||||
|
||||
expect(snorlax.getTag(BattlerTagType.FLYING)).toBeDefined();
|
||||
|
||||
game.move.select(MoveId.GRAVITY);
|
||||
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY]);
|
||||
|
||||
await game.phaseInterceptor.to("MoveEffectPhase");
|
||||
|
||||
expect(snorlax.getTag(BattlerTagType.INTERRUPTED)).toBeDefined();
|
||||
|
||||
await game.phaseInterceptor.to("TurnEndPhase");
|
||||
await game.toEndOfTurn();
|
||||
|
||||
expect(charizard.hp).toBe(charizard.getMaxHp());
|
||||
expect(snorlax.getTag(BattlerTagType.FLYING)).toBeUndefined();
|
||||
expect(snorlax.getLastXMoves()[0].result).toBe(MoveResult.FAIL);
|
||||
});
|
||||
});
|
||||
|
@ -1,7 +1,7 @@
|
||||
import { BattlerIndex } from "#app/battle";
|
||||
import { BattlerIndex } from "#enums/battler-index";
|
||||
import { allMoves } from "#app/data/data-lists";
|
||||
import { getTerrainName, TerrainType } from "#app/data/terrain";
|
||||
import { MoveResult } from "#app/field/pokemon";
|
||||
import { MoveResult } from "#enums/move-result";
|
||||
import { getPokemonNameWithAffix } from "#app/messages";
|
||||
import { capitalizeFirstLetter, randSeedInt, toDmgValue } from "#app/utils/common";
|
||||
import { AbilityId } from "#enums/ability-id";
|
||||
@ -99,6 +99,7 @@ describe("Terrain -", () => {
|
||||
it("should heal all grounded, non-semi-invulnerable pokemon for 1/16th max HP at end of turn", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.BLISSEY]);
|
||||
|
||||
// shuckle is grounded, pidgeot isn't
|
||||
const blissey = game.field.getPlayerPokemon();
|
||||
blissey.hp = toDmgValue(blissey.getMaxHp() / 2);
|
||||
expect(blissey.getHpRatio()).toBeCloseTo(0.5, 1);
|
||||
@ -114,7 +115,6 @@ describe("Terrain -", () => {
|
||||
expect(game.phaseInterceptor.log).toContain("PokemonHealPhase");
|
||||
expect(blissey.getHpRatio()).toBeCloseTo(0.5625, 1);
|
||||
expect(shuckle.getHpRatio()).toBeCloseTo(0.5, 1);
|
||||
game.phaseInterceptor.clearLogs();
|
||||
|
||||
game.move.use(MoveId.DIG);
|
||||
await game.toNextTurn();
|
||||
@ -169,7 +169,7 @@ describe("Terrain -", () => {
|
||||
);
|
||||
});
|
||||
|
||||
// TODO: Enable after terrain block PR is added
|
||||
// TODO: Enable tests after terrain-msg branch is merged
|
||||
describe.skip("Electric Terrain", () => {
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
@ -183,24 +183,23 @@ describe("Terrain -", () => {
|
||||
.enemyLevel(100)
|
||||
.enemySpecies(SpeciesId.SHUCKLE)
|
||||
.enemyAbility(AbilityId.ELECTRIC_SURGE)
|
||||
.enemyPassiveAbility(AbilityId.LEVITATE)
|
||||
.ability(AbilityId.NO_GUARD);
|
||||
});
|
||||
|
||||
it("should prevent all grounded pokemon from being put to sleep", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.BLISSEY]);
|
||||
await game.classicMode.startBattle([SpeciesId.PIDGEOT]);
|
||||
|
||||
game.move.use(MoveId.SPORE);
|
||||
await game.move.forceEnemyMove(MoveId.SPORE);
|
||||
await game.toEndOfTurn();
|
||||
|
||||
const blissey = game.field.getPlayerPokemon();
|
||||
const pidgeot = game.field.getPlayerPokemon();
|
||||
const shuckle = game.field.getEnemyPokemon();
|
||||
expect(blissey.status?.effect).toBeUndefined();
|
||||
expect(pidgeot.status?.effect).toBeUndefined();
|
||||
expect(shuckle.status?.effect).toBe(StatusEffect.SLEEP);
|
||||
// TODO: These don't work due to how move failures are propagated
|
||||
expect(blissey.getLastXMoves()[0].result).toBe(MoveResult.SUCCESS);
|
||||
expect(shuckle.getLastXMoves()[0].result).toBe(MoveResult.FAIL);
|
||||
expect(pidgeot.getLastXMoves()[0].result).toBe(MoveResult.FAIL);
|
||||
expect(shuckle.getLastXMoves()[0].result).toBe(MoveResult.SUCCESS);
|
||||
|
||||
expect(game.textInterceptor.logs).not.toContain(
|
||||
i18next.t("terrain:defaultBlockMessage", {
|
||||
@ -211,16 +210,19 @@ describe("Terrain -", () => {
|
||||
});
|
||||
|
||||
it("should prevent attack moves from applying sleep without showing text/failing move", async () => {
|
||||
await game.classicMode.startBattle([SpeciesId.BLISSEY]);
|
||||
vi.spyOn(allMoves[MoveId.RELIC_SONG], "chance", "get").mockReturnValue(100);
|
||||
await game.classicMode.startBattle([SpeciesId.BLISSEY]);
|
||||
|
||||
const shuckle = game.field.getEnemyPokemon();
|
||||
const statusSpy = vi.spyOn(shuckle, "canSetStatus");
|
||||
|
||||
game.move.use(MoveId.RELIC_SONG);
|
||||
await game.move.forceEnemyMove(MoveId.SPLASH);
|
||||
await game.toEndOfTurn();
|
||||
|
||||
const blissey = game.field.getPlayerPokemon();
|
||||
const shuckle = game.field.getEnemyPokemon();
|
||||
expect(shuckle.status?.effect).toBeUndefined();
|
||||
expect(statusSpy).toHaveLastReturnedWith(false);
|
||||
expect(blissey.getLastXMoves()[0].result).toBe(MoveResult.SUCCESS);
|
||||
|
||||
expect(game.textInterceptor.logs).not.toContain(
|
||||
@ -232,6 +234,7 @@ describe("Terrain -", () => {
|
||||
});
|
||||
});
|
||||
|
||||
// TODO: Enable tests after terrain-msg branch is merged
|
||||
describe("Misty Terrain", () => {
|
||||
afterEach(() => {
|
||||
game.phaseInterceptor.restoreOg();
|
||||
@ -245,26 +248,25 @@ describe("Terrain -", () => {
|
||||
.enemyLevel(100)
|
||||
.enemySpecies(SpeciesId.SHUCKLE)
|
||||
.enemyAbility(AbilityId.MISTY_SURGE)
|
||||
.enemyPassiveAbility(AbilityId.LEVITATE)
|
||||
.ability(AbilityId.NO_GUARD);
|
||||
});
|
||||
|
||||
it("should prevent all grounded pokemon from being statused or confused", async () => {
|
||||
game.override.confusionActivation(false); // prevent self hits from ruining things
|
||||
await game.classicMode.startBattle([SpeciesId.BLISSEY]);
|
||||
await game.classicMode.startBattle([SpeciesId.PIDGEOT]);
|
||||
|
||||
// blissey is grounded, shuckle isn't
|
||||
// shuckle is grounded, pidgeot isn't
|
||||
game.move.use(MoveId.TOXIC);
|
||||
await game.move.forceEnemyMove(MoveId.TOXIC);
|
||||
await game.toNextTurn();
|
||||
|
||||
const blissey = game.field.getPlayerPokemon();
|
||||
const pidgeot = game.field.getPlayerPokemon();
|
||||
const shuckle = game.field.getEnemyPokemon();
|
||||
expect(blissey.status?.effect).toBeUndefined();
|
||||
expect(pidgeot.status?.effect).toBeUndefined();
|
||||
expect(shuckle.status?.effect).toBe(StatusEffect.TOXIC);
|
||||
// TODO: These don't work due to how move failures are propagated
|
||||
expect(blissey.getLastXMoves()[0].result).toBe(MoveResult.SUCCESS);
|
||||
expect(shuckle.getLastXMoves()[0].result).toBe(MoveResult.FAIL);
|
||||
expect(pidgeot.getLastXMoves()[0].result).toBe(MoveResult.FAIL);
|
||||
expect(shuckle.getLastXMoves()[0].result).toBe(MoveResult.SUCCESS);
|
||||
|
||||
expect(game.textInterceptor.logs).toContain(
|
||||
i18next.t("terrain:mistyBlockMessage", {
|
||||
@ -277,21 +279,30 @@ describe("Terrain -", () => {
|
||||
await game.move.forceEnemyMove(MoveId.CONFUSE_RAY);
|
||||
await game.toNextTurn();
|
||||
|
||||
expect(blissey.getTag(BattlerTagType.CONFUSED)).toBeUndefined();
|
||||
expect(shuckle.getTag(BattlerTagType.CONFUSED)).toBeUndefined();
|
||||
expect(pidgeot.getTag(BattlerTagType.CONFUSED)).toBeUndefined();
|
||||
expect(shuckle.getTag(BattlerTagType.CONFUSED)).toBeDefined();
|
||||
});
|
||||
|
||||
it("should prevent attack moves from applying status without showing text/failing move", async () => {
|
||||
it.each<{ status: string; move: MoveId }>([
|
||||
{ status: "Sleep", move: MoveId.RELIC_SONG },
|
||||
{ status: "Burn", move: MoveId.SACRED_FIRE },
|
||||
{ status: "Freeze", move: MoveId.ICE_BEAM },
|
||||
{ status: "Paralysis", move: MoveId.NUZZLE },
|
||||
{ status: "Poison", move: MoveId.SLUDGE_BOMB },
|
||||
{ status: "Toxic", move: MoveId.MALIGNANT_CHAIN },
|
||||
{ status: "Confusion", move: MoveId.MAGICAL_TORQUE },
|
||||
])("should prevent attack moves from applying $name without showing text/failing move", async ({ move }) => {
|
||||
await game.classicMode.startBattle([SpeciesId.BLISSEY]);
|
||||
vi.spyOn(allMoves[MoveId.SACRED_FIRE], "chance", "get").mockReturnValue(100);
|
||||
vi.spyOn(allMoves[move], "chance", "get").mockReturnValue(100);
|
||||
|
||||
game.move.use(MoveId.SACRED_FIRE);
|
||||
game.move.use(move);
|
||||
await game.move.forceEnemyMove(MoveId.SPLASH);
|
||||
await game.toEndOfTurn();
|
||||
|
||||
const blissey = game.field.getPlayerPokemon();
|
||||
const shuckle = game.field.getEnemyPokemon();
|
||||
expect(shuckle.status?.effect).toBeUndefined();
|
||||
expect(shuckle.getTag(BattlerTagType.CONFUSED)).toBeUndefined();
|
||||
expect(blissey.getLastXMoves()[0].result).toBe(MoveResult.SUCCESS);
|
||||
|
||||
expect(game.textInterceptor.logs).not.toContain(
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { BattlerIndex } from "#app/battle";
|
||||
import { BattlerIndex } from "#enums/battler-index";
|
||||
import { AbilityId } from "#app/enums/ability-id";
|
||||
import { BattlerTagType } from "#app/enums/battler-tag-type";
|
||||
import type { MoveEffectPhase } from "#app/phases/move-effect-phase";
|
||||
@ -44,7 +44,7 @@ describe("Moves - Thousand Arrows", () => {
|
||||
|
||||
game.move.select(MoveId.THOUSAND_ARROWS);
|
||||
await game.phaseInterceptor.to("MoveEffectPhase", false);
|
||||
const hitSpy = vi.spyOn(game.scene.getCurrentPhase() as MoveEffectPhase, "hitCheck");
|
||||
const hitSpy = vi.spyOn(game.scene.phaseManager.getCurrentPhase() as MoveEffectPhase, "hitCheck");
|
||||
|
||||
await game.toEndOfTurn();
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user