mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-06-21 00:52:47 +02:00
[Bug] Dancer no longer breaks "last hit only" moves, respects flinch + steadfast (#5945)
* WIP * Fixed Dancer last hit, flinch move interaction * Fixed steadfast interaction * Fixed comment + flaky test --------- Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
This commit is contained in:
parent
88e4ab978b
commit
a818c2b33f
@ -4438,6 +4438,7 @@ export class PostDancingMoveAbAttr extends PostMoveUsedAbAttr {
|
|||||||
simulated: boolean,
|
simulated: boolean,
|
||||||
args: any[]): void {
|
args: any[]): void {
|
||||||
if (!simulated) {
|
if (!simulated) {
|
||||||
|
dancer.turnData.extraTurns++;
|
||||||
// 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);
|
||||||
|
@ -649,20 +649,14 @@ class NoRetreatTag extends TrappedTag {
|
|||||||
*/
|
*/
|
||||||
export class FlinchedTag extends BattlerTag {
|
export class FlinchedTag extends BattlerTag {
|
||||||
constructor(sourceMove: MoveId) {
|
constructor(sourceMove: MoveId) {
|
||||||
super(BattlerTagType.FLINCHED, [BattlerTagLapseType.PRE_MOVE, BattlerTagLapseType.TURN_END], 0, sourceMove);
|
super(BattlerTagType.FLINCHED, [BattlerTagLapseType.PRE_MOVE, BattlerTagLapseType.TURN_END], 1, sourceMove);
|
||||||
}
|
|
||||||
|
|
||||||
onAdd(pokemon: Pokemon): void {
|
|
||||||
super.onAdd(pokemon);
|
|
||||||
|
|
||||||
applyAbAttrs(FlinchEffectAbAttr, pokemon, null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cancels the Pokemon's next Move on the turn this tag is applied
|
* Cancels the flinched Pokemon's currently used move this turn if called mid-execution, or removes the tag at end of turn.
|
||||||
* @param pokemon The {@linkcode Pokemon} with this tag
|
* @param pokemon - The {@linkcode Pokemon} with this tag.
|
||||||
* @param lapseType The {@linkcode BattlerTagLapseType lapse type} used for this function call
|
* @param lapseType - The {@linkcode BattlerTagLapseType | lapse type} used for this function call.
|
||||||
* @returns `false` (This tag is always removed after applying its effects)
|
* @returns Whether the tag should remain active.
|
||||||
*/
|
*/
|
||||||
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
lapse(pokemon: Pokemon, lapseType: BattlerTagLapseType): boolean {
|
||||||
if (lapseType === BattlerTagLapseType.PRE_MOVE) {
|
if (lapseType === BattlerTagLapseType.PRE_MOVE) {
|
||||||
@ -672,6 +666,8 @@ export class FlinchedTag extends BattlerTag {
|
|||||||
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
applyAbAttrs(FlinchEffectAbAttr, pokemon, null);
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
return super.lapse(pokemon, lapseType);
|
return super.lapse(pokemon, lapseType);
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
import { BattlerIndex } from "#app/battle";
|
import { BattlerIndex } from "#app/battle";
|
||||||
|
import { MoveResult } from "#app/field/pokemon";
|
||||||
import type { MovePhase } from "#app/phases/move-phase";
|
import type { MovePhase } from "#app/phases/move-phase";
|
||||||
import { AbilityId } from "#enums/ability-id";
|
import { AbilityId } from "#enums/ability-id";
|
||||||
import { MoveId } from "#enums/move-id";
|
import { MoveId } from "#enums/move-id";
|
||||||
import { SpeciesId } from "#enums/species-id";
|
import { SpeciesId } from "#enums/species-id";
|
||||||
|
import { Stat } from "#enums/stat";
|
||||||
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 } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||||
@ -99,4 +101,43 @@ describe("Abilities - Dancer", () => {
|
|||||||
expect(currentPhase.pokemon).toBe(oricorio);
|
expect(currentPhase.pokemon).toBe(oricorio);
|
||||||
expect(currentPhase.move.moveId).toBe(MoveId.REVELATION_DANCE);
|
expect(currentPhase.move.moveId).toBe(MoveId.REVELATION_DANCE);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should not break subsequent last hit only moves", async () => {
|
||||||
|
game.override.battleStyle("single");
|
||||||
|
await game.classicMode.startBattle([SpeciesId.ORICORIO, SpeciesId.FEEBAS]);
|
||||||
|
|
||||||
|
const [oricorio, feebas] = game.scene.getPlayerParty();
|
||||||
|
|
||||||
|
game.move.use(MoveId.BATON_PASS);
|
||||||
|
game.doSelectPartyPokemon(1);
|
||||||
|
await game.move.forceEnemyMove(MoveId.SWORDS_DANCE);
|
||||||
|
await game.setTurnOrder([BattlerIndex.ENEMY, BattlerIndex.PLAYER]);
|
||||||
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
|
|
||||||
|
expect(game.phaseInterceptor.log).toContain("SwitchSummonPhase");
|
||||||
|
expect(game.field.getPlayerPokemon()).toBe(feebas);
|
||||||
|
expect(feebas.getStatStage(Stat.ATK)).toBe(2);
|
||||||
|
expect(oricorio.isOnField()).toBe(false);
|
||||||
|
expect(oricorio.visible).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it("should not trigger while flinched", async () => {
|
||||||
|
game.override.battleStyle("double").moveset(MoveId.SPLASH).enemyMoveset([MoveId.SWORDS_DANCE, MoveId.FAKE_OUT]);
|
||||||
|
await game.classicMode.startBattle([SpeciesId.ORICORIO]);
|
||||||
|
|
||||||
|
const oricorio = game.scene.getPlayerPokemon()!;
|
||||||
|
expect(oricorio).toBeDefined();
|
||||||
|
|
||||||
|
// get faked out and copy swords dance
|
||||||
|
game.move.select(MoveId.SPLASH);
|
||||||
|
await game.move.forceEnemyMove(MoveId.SWORDS_DANCE);
|
||||||
|
await game.move.forceEnemyMove(MoveId.FAKE_OUT, BattlerIndex.PLAYER);
|
||||||
|
await game.phaseInterceptor.to("TurnEndPhase");
|
||||||
|
|
||||||
|
expect(oricorio.getLastXMoves(-1)[0]).toMatchObject({
|
||||||
|
move: MoveId.NONE,
|
||||||
|
result: MoveResult.FAIL,
|
||||||
|
});
|
||||||
|
expect(oricorio.getStatStage(Stat.ATK)).toBe(0);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,13 +1,15 @@
|
|||||||
import { BattlerIndex } from "#app/battle";
|
import { BattlerIndex } from "#app/battle";
|
||||||
|
import { allMoves } from "#app/data/data-lists";
|
||||||
import type Pokemon from "#app/field/pokemon";
|
import type Pokemon from "#app/field/pokemon";
|
||||||
import { MoveResult } from "#app/field/pokemon";
|
import { MoveResult } from "#app/field/pokemon";
|
||||||
import type { MovePhase } from "#app/phases/move-phase";
|
import type { MovePhase } from "#app/phases/move-phase";
|
||||||
import { AbilityId } from "#enums/ability-id";
|
import { AbilityId } from "#enums/ability-id";
|
||||||
import { MoveId } from "#enums/move-id";
|
import { MoveId } from "#enums/move-id";
|
||||||
import { SpeciesId } from "#enums/species-id";
|
import { SpeciesId } from "#enums/species-id";
|
||||||
|
import { Stat } from "#enums/stat";
|
||||||
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 } from "vitest";
|
import { afterEach, beforeAll, beforeEach, describe, expect, it, vi } from "vitest";
|
||||||
|
|
||||||
describe("Moves - Instruct", () => {
|
describe("Moves - Instruct", () => {
|
||||||
let phaserGame: Phaser.Game;
|
let phaserGame: Phaser.Game;
|
||||||
@ -34,7 +36,8 @@ describe("Moves - Instruct", () => {
|
|||||||
game.override
|
game.override
|
||||||
.battleStyle("single")
|
.battleStyle("single")
|
||||||
.enemySpecies(SpeciesId.SHUCKLE)
|
.enemySpecies(SpeciesId.SHUCKLE)
|
||||||
.enemyAbility(AbilityId.NO_GUARD)
|
.enemyAbility(AbilityId.BALL_FETCH)
|
||||||
|
.passiveAbility(AbilityId.NO_GUARD)
|
||||||
.enemyLevel(100)
|
.enemyLevel(100)
|
||||||
.startingLevel(100)
|
.startingLevel(100)
|
||||||
.disableCrits();
|
.disableCrits();
|
||||||
@ -536,4 +539,27 @@ describe("Moves - Instruct", () => {
|
|||||||
|
|
||||||
expect(ivysaur.turnData.attacksReceived.length).toBe(15);
|
expect(ivysaur.turnData.attacksReceived.length).toBe(15);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it("should respect prior flinches and trigger Steadfast", async () => {
|
||||||
|
game.override.battleStyle("double");
|
||||||
|
vi.spyOn(allMoves[MoveId.AIR_SLASH], "chance", "get").mockReturnValue(100);
|
||||||
|
await game.classicMode.startBattle([SpeciesId.AUDINO, SpeciesId.ABRA]);
|
||||||
|
|
||||||
|
// Fake enemy 1 having attacked prior
|
||||||
|
const [, player2, enemy1, enemy2] = game.scene.getField();
|
||||||
|
enemy1.pushMoveHistory({ move: MoveId.ABSORB, targets: [BattlerIndex.PLAYER] });
|
||||||
|
game.field.mockAbility(enemy1, AbilityId.STEADFAST);
|
||||||
|
|
||||||
|
game.move.use(MoveId.AIR_SLASH, BattlerIndex.PLAYER, BattlerIndex.ENEMY);
|
||||||
|
game.move.use(MoveId.INSTRUCT, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY);
|
||||||
|
await game.move.forceEnemyMove(MoveId.ABSORB);
|
||||||
|
await game.move.forceEnemyMove(MoveId.INSTRUCT, BattlerIndex.ENEMY);
|
||||||
|
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.ENEMY, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY_2]);
|
||||||
|
await game.toEndOfTurn();
|
||||||
|
|
||||||
|
expect(enemy1.getLastXMoves(-1).map(m => m.move)).toEqual([MoveId.NONE, MoveId.NONE, MoveId.NONE, MoveId.ABSORB]);
|
||||||
|
expect(enemy1.getStatStage(Stat.SPD)).toBe(3);
|
||||||
|
expect(player2.getLastXMoves()[0].result).toBe(MoveResult.SUCCESS);
|
||||||
|
expect(enemy2.getLastXMoves()[0].result).toBe(MoveResult.SUCCESS);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
Reference in New Issue
Block a user