Add Powder integration tests
This commit is contained in:
parent
55974903ae
commit
f149e31ce5
|
@ -558,6 +558,13 @@ export class PowderTag extends BattlerTag {
|
||||||
pokemon.scene.queueMessage(i18next.t("battlerTags:powderOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
pokemon.scene.queueMessage(i18next.t("battlerTags:powderOnAdd", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon) }));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Applies Powder's effects before the tag owner uses a Fire-type move.
|
||||||
|
* Also causes the tag to expire at the end of turn.
|
||||||
|
* @param pokemon {@linkcode Pokemon} the owner of this tag
|
||||||
|
* @param lapseType {@linkcode BattlerTagLapseType} the type of lapse functionality to carry out
|
||||||
|
* @returns `true` if the tag should not expire after this lapse; `false` otherwise.
|
||||||
|
*/
|
||||||
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
||||||
if (lapseType === BattlerTagLapseType.PRE_MOVE) {
|
if (lapseType === BattlerTagLapseType.PRE_MOVE) {
|
||||||
const movePhase = pokemon.scene.getCurrentPhase();
|
const movePhase = pokemon.scene.getCurrentPhase();
|
||||||
|
@ -565,7 +572,12 @@ export class PowderTag extends BattlerTag {
|
||||||
const move = movePhase.move.getMove();
|
const move = movePhase.move.getMove();
|
||||||
if (move.type === Type.FIRE) {
|
if (move.type === Type.FIRE) {
|
||||||
movePhase.cancel();
|
movePhase.cancel();
|
||||||
pokemon.damageAndUpdate(Math.floor(pokemon.getMaxHp() / 4), HitResult.OTHER);
|
|
||||||
|
const cancelDamage = new Utils.BooleanHolder(false);
|
||||||
|
applyAbAttrs(BlockNonDirectDamageAbAttr, pokemon, cancelDamage);
|
||||||
|
if (!cancelDamage.value) {
|
||||||
|
pokemon.damageAndUpdate(Math.floor(pokemon.getMaxHp() / 4), HitResult.OTHER);
|
||||||
|
}
|
||||||
|
|
||||||
pokemon.scene.queueMessage(i18next.t("battlerTags:powderLapse"));
|
pokemon.scene.queueMessage(i18next.t("battlerTags:powderLapse"));
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,145 @@
|
||||||
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
import Phaser from "phaser";
|
||||||
|
import GameManager from "#test/utils/gameManager";
|
||||||
|
import { Abilities } from "#app/enums/abilities";
|
||||||
|
import { Moves } from "#app/enums/moves";
|
||||||
|
import { Species } from "#app/enums/species";
|
||||||
|
import { getMovePosition } from "#app/test/utils/gameManagerUtils";
|
||||||
|
import { BerryPhase } from "#app/phases/berry-phase";
|
||||||
|
import { MoveResult } from "#app/field/pokemon";
|
||||||
|
import { Type } from "#app/data/type";
|
||||||
|
import { MoveEffectPhase } from "#app/phases/move-effect-phase";
|
||||||
|
import { StatusEffect } from "#app/enums/status-effect";
|
||||||
|
|
||||||
|
const TIMEOUT = 20 * 1000;
|
||||||
|
|
||||||
|
describe("Moves - Powder", () => {
|
||||||
|
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.battleType("single");
|
||||||
|
|
||||||
|
game.override.enemySpecies(Species.SNORLAX);
|
||||||
|
game.override.enemyLevel(100);
|
||||||
|
game.override.enemyMoveset(Array(4).fill(Moves.EMBER));
|
||||||
|
game.override.enemyAbility(Abilities.INSOMNIA);
|
||||||
|
|
||||||
|
game.override.startingLevel(100);
|
||||||
|
game.override.moveset([Moves.POWDER, Moves.SPLASH, Moves.FIERY_DANCE]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it(
|
||||||
|
"should cancel the target's Fire-type move and damage the target",
|
||||||
|
async () => {
|
||||||
|
await game.startBattle([Species.CHARIZARD]);
|
||||||
|
|
||||||
|
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||||
|
|
||||||
|
game.doAttack(getMovePosition(game.scene, 0, Moves.POWDER));
|
||||||
|
|
||||||
|
await game.phaseInterceptor.to(BerryPhase, false);
|
||||||
|
expect(enemyPokemon.getLastXMoves()[0].result).toBe(MoveResult.FAIL);
|
||||||
|
expect(enemyPokemon.hp).toBe(Math.ceil(3 * enemyPokemon.getMaxHp() / 4));
|
||||||
|
}, TIMEOUT
|
||||||
|
);
|
||||||
|
|
||||||
|
it.todo("should not cancel Fire-type moves after the turn it's used");
|
||||||
|
|
||||||
|
it.todo("should have no effect against Grass-type Pokemon");
|
||||||
|
|
||||||
|
it.todo("should have no effect against Pokemon with Overcoat");
|
||||||
|
|
||||||
|
it(
|
||||||
|
"should not damage the target if the target has Magic Guard",
|
||||||
|
async () => {
|
||||||
|
game.override.enemyAbility(Abilities.MAGIC_GUARD);
|
||||||
|
|
||||||
|
await game.startBattle([Species.CHARIZARD]);
|
||||||
|
|
||||||
|
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||||
|
|
||||||
|
game.doAttack(getMovePosition(game.scene, 0, Moves.POWDER));
|
||||||
|
|
||||||
|
await game.phaseInterceptor.to(BerryPhase, false);
|
||||||
|
expect(enemyPokemon.getLastXMoves()[0].result).toBe(MoveResult.FAIL);
|
||||||
|
expect(enemyPokemon.hp).toBe(enemyPokemon.getMaxHp());
|
||||||
|
}, TIMEOUT
|
||||||
|
);
|
||||||
|
|
||||||
|
it(
|
||||||
|
"should not prevent the target from thawing out with its Fire-type move",
|
||||||
|
async () => {
|
||||||
|
game.override.enemyStatusEffect(StatusEffect.FREEZE);
|
||||||
|
|
||||||
|
await game.startBattle([Species.CHARIZARD]);
|
||||||
|
|
||||||
|
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||||
|
|
||||||
|
game.doAttack(getMovePosition(game.scene, 0, Moves.POWDER));
|
||||||
|
|
||||||
|
await game.phaseInterceptor.to(BerryPhase, false);
|
||||||
|
expect(enemyPokemon.status?.effect).not.toBe(StatusEffect.FREEZE);
|
||||||
|
expect(enemyPokemon.getLastXMoves()[0].result).toBe(MoveResult.FAIL);
|
||||||
|
expect(enemyPokemon.hp).toBe(Math.ceil(3 * enemyPokemon.getMaxHp() / 4));
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
it(
|
||||||
|
"should not allow a target with Protean to change to Fire type",
|
||||||
|
async () => {
|
||||||
|
game.override.enemyAbility(Abilities.PROTEAN);
|
||||||
|
|
||||||
|
await game.startBattle([Species.CHARIZARD]);
|
||||||
|
|
||||||
|
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||||
|
|
||||||
|
game.doAttack(getMovePosition(game.scene, 0, Moves.POWDER));
|
||||||
|
|
||||||
|
await game.phaseInterceptor.to(BerryPhase, false);
|
||||||
|
expect(enemyPokemon.getLastXMoves()[0].result).toBe(MoveResult.FAIL);
|
||||||
|
expect(enemyPokemon.hp).toBeLessThan(enemyPokemon.getMaxHp());
|
||||||
|
expect(enemyPokemon.summonData?.types).not.toBe(Type.FIRE);
|
||||||
|
}, TIMEOUT
|
||||||
|
);
|
||||||
|
|
||||||
|
it.skip(
|
||||||
|
"should cancel Fire-type moves generated by the target's Dancer ability",
|
||||||
|
async () => {
|
||||||
|
game.override
|
||||||
|
.enemySpecies(Species.BLASTOISE)
|
||||||
|
.enemyAbility(Abilities.DANCER);
|
||||||
|
|
||||||
|
await game.startBattle([Species.CHARIZARD]);
|
||||||
|
|
||||||
|
const playerPokemon = game.scene.getPlayerPokemon()!;
|
||||||
|
const enemyPokemon = game.scene.getEnemyPokemon()!;
|
||||||
|
|
||||||
|
game.doAttack(getMovePosition(game.scene, 0, Moves.FIERY_DANCE));
|
||||||
|
|
||||||
|
await game.phaseInterceptor.to(MoveEffectPhase);
|
||||||
|
const enemyStartingHp = enemyPokemon.hp;
|
||||||
|
|
||||||
|
await game.phaseInterceptor.to(BerryPhase, false);
|
||||||
|
// player should not take damage
|
||||||
|
expect(playerPokemon.hp).toBe(playerPokemon.getMaxHp());
|
||||||
|
// enemy should have taken damage from player's Fiery Dance + 2 Powder procs
|
||||||
|
expect(enemyPokemon.hp).toBe(enemyStartingHp - 2*Math.floor(enemyPokemon.getMaxHp() / 4));
|
||||||
|
}, TIMEOUT
|
||||||
|
);
|
||||||
|
|
||||||
|
it.todo("should cancel Hidden Power if it becomes a Fire-type move");
|
||||||
|
|
||||||
|
it.todo("should cancel Shell Trap and damage the target, even if the move would fail");
|
||||||
|
});
|
Loading…
Reference in New Issue