[Bug] Moves copied by Dancer should not consume PP (#3623)
* Moves copied by Dancer should not consume PP * Add test for Dancer (unfinished) * Delete src/test/abilities/dancer.test.ts This test is not finished lol * Add test
This commit is contained in:
parent
4553c1c34f
commit
69a9916b4c
|
@ -3695,10 +3695,10 @@ export class PostDancingMoveAbAttr extends PostMoveUsedAbAttr {
|
||||||
// If the move is an AttackMove or a StatusMove the Dancer must replicate the move on the source of the Dance
|
// If the move is an AttackMove or a StatusMove the Dancer must replicate the move on the source of the Dance
|
||||||
if (move.getMove() instanceof AttackMove || move.getMove() instanceof StatusMove) {
|
if (move.getMove() instanceof AttackMove || move.getMove() instanceof StatusMove) {
|
||||||
const target = this.getTarget(dancer, source, targets);
|
const target = this.getTarget(dancer, source, targets);
|
||||||
dancer.scene.unshiftPhase(new MovePhase(dancer.scene, dancer, target, move, true));
|
dancer.scene.unshiftPhase(new MovePhase(dancer.scene, dancer, target, move, true, true));
|
||||||
} else if (move.getMove() instanceof SelfStatusMove) {
|
} else if (move.getMove() instanceof SelfStatusMove) {
|
||||||
// If the move is a SelfStatusMove (ie. Swords Dance) the Dancer should replicate it on itself
|
// If the move is a SelfStatusMove (ie. Swords Dance) the Dancer should replicate it on itself
|
||||||
dancer.scene.unshiftPhase(new MovePhase(dancer.scene, dancer, [dancer.getBattlerIndex()], move, true));
|
dancer.scene.unshiftPhase(new MovePhase(dancer.scene, dancer, [dancer.getBattlerIndex()], move, true, true));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -1,9 +1,9 @@
|
||||||
import BattleScene from "#app/battle-scene.js";
|
import BattleScene from "#app/battle-scene.js";
|
||||||
import { BattlerIndex } from "#app/battle.js";
|
import { BattlerIndex } from "#app/battle.js";
|
||||||
import { applyAbAttrs, RedirectMoveAbAttr, BlockRedirectAbAttr, IncreasePpAbAttr, applyPreAttackAbAttrs, PokemonTypeChangeAbAttr, applyPostMoveUsedAbAttrs, PostMoveUsedAbAttr } from "#app/data/ability.js";
|
import { applyAbAttrs, applyPostMoveUsedAbAttrs, applyPreAttackAbAttrs, BlockRedirectAbAttr, IncreasePpAbAttr, PokemonTypeChangeAbAttr, PostMoveUsedAbAttr, RedirectMoveAbAttr } from "#app/data/ability.js";
|
||||||
import { CommonAnim } from "#app/data/battle-anims.js";
|
import { CommonAnim } from "#app/data/battle-anims.js";
|
||||||
import { CenterOfAttentionTag, BattlerTagLapseType } from "#app/data/battler-tags.js";
|
import { BattlerTagLapseType, CenterOfAttentionTag } from "#app/data/battler-tags.js";
|
||||||
import { MoveFlags, BypassRedirectAttr, allMoves, CopyMoveAttr, applyMoveAttrs, BypassSleepAttr, HealStatusEffectAttr, ChargeAttr, PreMoveMessageAttr } from "#app/data/move.js";
|
import { allMoves, applyMoveAttrs, BypassRedirectAttr, BypassSleepAttr, ChargeAttr, CopyMoveAttr, HealStatusEffectAttr, MoveFlags, PreMoveMessageAttr } from "#app/data/move.js";
|
||||||
import { SpeciesFormChangePreMoveTrigger } from "#app/data/pokemon-forms.js";
|
import { SpeciesFormChangePreMoveTrigger } from "#app/data/pokemon-forms.js";
|
||||||
import { getStatusEffectActivationText, getStatusEffectHealText } from "#app/data/status-effect.js";
|
import { getStatusEffectActivationText, getStatusEffectHealText } from "#app/data/status-effect.js";
|
||||||
import { Type } from "#app/data/type.js";
|
import { Type } from "#app/data/type.js";
|
||||||
|
@ -13,10 +13,10 @@ import { BattlerTagType } from "#app/enums/battler-tag-type.js";
|
||||||
import { Moves } from "#app/enums/moves.js";
|
import { Moves } from "#app/enums/moves.js";
|
||||||
import { StatusEffect } from "#app/enums/status-effect.js";
|
import { StatusEffect } from "#app/enums/status-effect.js";
|
||||||
import { MoveUsedEvent } from "#app/events/battle-scene.js";
|
import { MoveUsedEvent } from "#app/events/battle-scene.js";
|
||||||
import Pokemon, { PokemonMove, MoveResult, TurnMove } from "#app/field/pokemon.js";
|
import Pokemon, { MoveResult, PokemonMove, TurnMove } from "#app/field/pokemon.js";
|
||||||
import { getPokemonNameWithAffix } from "#app/messages.js";
|
import { getPokemonNameWithAffix } from "#app/messages.js";
|
||||||
import i18next from "i18next";
|
|
||||||
import * as Utils from "#app/utils.js";
|
import * as Utils from "#app/utils.js";
|
||||||
|
import i18next from "i18next";
|
||||||
import { BattlePhase } from "./battle-phase";
|
import { BattlePhase } from "./battle-phase";
|
||||||
import { CommonAnimPhase } from "./common-anim-phase";
|
import { CommonAnimPhase } from "./common-anim-phase";
|
||||||
import { MoveEffectPhase } from "./move-effect-phase";
|
import { MoveEffectPhase } from "./move-effect-phase";
|
||||||
|
@ -38,8 +38,8 @@ export class MovePhase extends BattlePhase {
|
||||||
this.pokemon = pokemon;
|
this.pokemon = pokemon;
|
||||||
this.targets = targets;
|
this.targets = targets;
|
||||||
this.move = move;
|
this.move = move;
|
||||||
this.followUp = !!followUp;
|
this.followUp = followUp ?? false;
|
||||||
this.ignorePp = !!ignorePp;
|
this.ignorePp = ignorePp ?? false;
|
||||||
this.failed = false;
|
this.failed = false;
|
||||||
this.cancelled = false;
|
this.cancelled = false;
|
||||||
}
|
}
|
||||||
|
@ -194,7 +194,7 @@ export class MovePhase extends BattlePhase {
|
||||||
return this.end();
|
return this.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!moveQueue.length || !moveQueue.shift()?.ignorePP) { // using .shift here clears out two turn moves once they've been used
|
if ((!moveQueue.length || !moveQueue.shift()?.ignorePP) && !this.ignorePp) { // using .shift here clears out two turn moves once they've been used
|
||||||
this.move.usePp(ppUsed);
|
this.move.usePp(ppUsed);
|
||||||
this.scene.eventTarget.dispatchEvent(new MoveUsedEvent(this.pokemon?.id, this.move.getMove(), this.move.ppUsed));
|
this.scene.eventTarget.dispatchEvent(new MoveUsedEvent(this.pokemon?.id, this.move.getMove(), this.move.ppUsed));
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,64 @@
|
||||||
|
import { BattlerIndex } from "#app/battle";
|
||||||
|
import { MovePhase } from "#app/phases/move-phase";
|
||||||
|
import { Abilities } from "#enums/abilities";
|
||||||
|
import { Moves } from "#enums/moves";
|
||||||
|
import { Species } from "#enums/species";
|
||||||
|
import GameManager from "#test/utils/gameManager";
|
||||||
|
import Phaser from "phaser";
|
||||||
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
|
|
||||||
|
const TIMEOUT = 20 * 1000;
|
||||||
|
|
||||||
|
describe("Abilities - Dancer", () => {
|
||||||
|
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("double")
|
||||||
|
.moveset([Moves.SWORDS_DANCE, Moves.SPLASH])
|
||||||
|
.enemySpecies(Species.MAGIKARP)
|
||||||
|
.enemyAbility(Abilities.DANCER)
|
||||||
|
.enemyMoveset(Array(4).fill(Moves.VICTORY_DANCE));
|
||||||
|
});
|
||||||
|
|
||||||
|
// Reference Link: https://bulbapedia.bulbagarden.net/wiki/Dancer_(Ability)
|
||||||
|
|
||||||
|
it("triggers when dance moves are used, doesn't consume extra PP", async () => {
|
||||||
|
await game.classicMode.startBattle([Species.ORICORIO, Species.FEEBAS]);
|
||||||
|
|
||||||
|
const [oricorio] = game.scene.getPlayerField();
|
||||||
|
|
||||||
|
game.move.select(Moves.SPLASH);
|
||||||
|
game.move.select(Moves.SWORDS_DANCE, 1);
|
||||||
|
await game.setTurnOrder([BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.PLAYER, BattlerIndex.ENEMY_2]);
|
||||||
|
await game.phaseInterceptor.to("MovePhase");
|
||||||
|
// immediately copies ally move
|
||||||
|
await game.phaseInterceptor.to("MovePhase", false);
|
||||||
|
let currentPhase = game.scene.getCurrentPhase() as MovePhase;
|
||||||
|
expect(currentPhase.pokemon).toBe(oricorio);
|
||||||
|
expect(currentPhase.move.moveId).toBe(Moves.SWORDS_DANCE);
|
||||||
|
await game.phaseInterceptor.to("MoveEndPhase");
|
||||||
|
await game.phaseInterceptor.to("MovePhase");
|
||||||
|
// immediately copies enemy move
|
||||||
|
await game.phaseInterceptor.to("MovePhase", false);
|
||||||
|
currentPhase = game.scene.getCurrentPhase() as MovePhase;
|
||||||
|
expect(currentPhase.pokemon).toBe(oricorio);
|
||||||
|
expect(currentPhase.move.moveId).toBe(Moves.VICTORY_DANCE);
|
||||||
|
await game.phaseInterceptor.to("BerryPhase");
|
||||||
|
|
||||||
|
// doesn't use PP if copied move is also in moveset
|
||||||
|
expect(oricorio.moveset[0]?.ppUsed).toBe(0);
|
||||||
|
}, TIMEOUT);
|
||||||
|
});
|
Loading…
Reference in New Issue