mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-09-23 15:03:24 +02:00
[Bug] [Move] Fix poltergeist crash when no remaining enemies (#6473)
* fix: poltergeist crash with no target * fix: adjust move phase history
This commit is contained in:
parent
9fc31350f8
commit
4a28773929
@ -8164,6 +8164,9 @@ const failIfGhostTypeCondition: MoveConditionFunc = (user: Pokemon, target: Poke
|
||||
const failIfNoTargetHeldItemsCondition: MoveConditionFunc = (user: Pokemon, target: Pokemon, move: Move) => target.getHeldItems().filter(i => i.isTransferable)?.length > 0;
|
||||
|
||||
const attackedByItemMessageFunc = (user: Pokemon, target: Pokemon, move: Move) => {
|
||||
if (isNullOrUndefined(target)) { // Fix bug when used against targets that have both fainted
|
||||
return "";
|
||||
}
|
||||
const heldItems = target.getHeldItems().filter(i => i.isTransferable);
|
||||
if (heldItems.length === 0) {
|
||||
return "";
|
||||
|
@ -24,6 +24,7 @@ import { applyMoveAttrs } from "#moves/apply-attrs";
|
||||
import { frenzyMissFunc } from "#moves/move-utils";
|
||||
import type { PokemonMove } from "#moves/pokemon-move";
|
||||
import { BattlePhase } from "#phases/battle-phase";
|
||||
import type { TurnMove } from "#types/turn-move";
|
||||
import { NumberHolder } from "#utils/common";
|
||||
import { enumValueToKey } from "#utils/enums";
|
||||
import i18next from "i18next";
|
||||
@ -41,6 +42,13 @@ export class MovePhase extends BattlePhase {
|
||||
/** Whether the current move should fail and retain PP. */
|
||||
protected cancelled = false;
|
||||
|
||||
/** The move history entry object that is pushed to the pokemon's move history
|
||||
*
|
||||
* @remarks
|
||||
* Can be edited _after_ being pushed to the history to adjust the result, targets, etc, for this move phase.
|
||||
*/
|
||||
protected moveHistoryEntry: TurnMove;
|
||||
|
||||
public get pokemon(): Pokemon {
|
||||
return this._pokemon;
|
||||
}
|
||||
@ -82,6 +90,11 @@ export class MovePhase extends BattlePhase {
|
||||
this.move = move;
|
||||
this.useMode = useMode;
|
||||
this.forcedLast = forcedLast;
|
||||
this.moveHistoryEntry = {
|
||||
move: MoveId.NONE,
|
||||
targets,
|
||||
useMode,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@ -410,13 +423,9 @@ export class MovePhase extends BattlePhase {
|
||||
if (showText) {
|
||||
this.showMoveText();
|
||||
}
|
||||
|
||||
this.pokemon.pushMoveHistory({
|
||||
move: this.move.moveId,
|
||||
targets: this.targets,
|
||||
result: MoveResult.FAIL,
|
||||
useMode: this.useMode,
|
||||
});
|
||||
const moveHistoryEntry = this.moveHistoryEntry;
|
||||
moveHistoryEntry.result = MoveResult.FAIL;
|
||||
this.pokemon.pushMoveHistory(moveHistoryEntry);
|
||||
|
||||
// Use move-specific failure messages if present before checking terrain/weather blockage
|
||||
// and falling back to the classic "But it failed!".
|
||||
@ -630,12 +639,9 @@ export class MovePhase extends BattlePhase {
|
||||
frenzyMissFunc(this.pokemon, this.move.getMove());
|
||||
}
|
||||
|
||||
this.pokemon.pushMoveHistory({
|
||||
move: MoveId.NONE,
|
||||
result: MoveResult.FAIL,
|
||||
targets: this.targets,
|
||||
useMode: this.useMode,
|
||||
});
|
||||
const moveHistoryEntry = this.moveHistoryEntry;
|
||||
moveHistoryEntry.result = MoveResult.FAIL;
|
||||
this.pokemon.pushMoveHistory(moveHistoryEntry);
|
||||
|
||||
this.pokemon.lapseTags(BattlerTagLapseType.MOVE_EFFECT);
|
||||
this.pokemon.lapseTags(BattlerTagLapseType.AFTER_MOVE);
|
||||
@ -649,13 +655,16 @@ export class MovePhase extends BattlePhase {
|
||||
* Displays the move's usage text to the player as applicable for the move being used.
|
||||
*/
|
||||
public showMoveText(): void {
|
||||
const moveId = this.move.moveId;
|
||||
if (
|
||||
this.move.moveId === MoveId.NONE ||
|
||||
moveId === MoveId.NONE ||
|
||||
this.pokemon.getTag(BattlerTagType.RECHARGING) ||
|
||||
this.pokemon.getTag(BattlerTagType.INTERRUPTED)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
// Showing move text always adjusts the move history entry's move id
|
||||
this.moveHistoryEntry.move = moveId;
|
||||
|
||||
// TODO: This should be done by the move...
|
||||
globalScene.phaseManager.queueMessage(
|
||||
@ -668,7 +677,7 @@ export class MovePhase extends BattlePhase {
|
||||
|
||||
// Moves with pre-use messages (Magnitude, Chilly Reception, Fickle Beam, etc.) always display their messages even on failure
|
||||
// TODO: This assumes single target for message funcs - is this sustainable?
|
||||
applyMoveAttrs("PreMoveMessageAttr", this.pokemon, this.pokemon.getOpponents(false)[0], this.move.getMove());
|
||||
applyMoveAttrs("PreMoveMessageAttr", this.pokemon, this.getActiveTargetPokemon()[0], this.move.getMove());
|
||||
}
|
||||
|
||||
/**
|
||||
|
50
test/moves/poltergeist.test.ts
Normal file
50
test/moves/poltergeist.test.ts
Normal file
@ -0,0 +1,50 @@
|
||||
import { AbilityId } from "#enums/ability-id";
|
||||
import { BattlerIndex } from "#enums/battler-index";
|
||||
import { MoveId } from "#enums/move-id";
|
||||
import { MoveResult } from "#enums/move-result";
|
||||
import { SpeciesId } from "#enums/species-id";
|
||||
import { GameManager } from "#test/test-utils/game-manager";
|
||||
import Phaser from "phaser";
|
||||
import { afterEach, beforeAll, beforeEach, describe, expect, it } from "vitest";
|
||||
|
||||
describe("Move - Poltergeist", () => {
|
||||
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
|
||||
.ability(AbilityId.BALL_FETCH)
|
||||
.battleStyle("single")
|
||||
.criticalHits(false)
|
||||
.enemySpecies(SpeciesId.MAGIKARP)
|
||||
.enemyAbility(AbilityId.BALL_FETCH)
|
||||
.enemyMoveset(MoveId.SPLASH)
|
||||
.startingLevel(100)
|
||||
.enemyLevel(100);
|
||||
});
|
||||
|
||||
it("should not crash when used after both opponents have fainted", async () => {
|
||||
game.override.battleStyle("double").enemyLevel(5);
|
||||
await game.classicMode.startBattle([SpeciesId.STARYU, SpeciesId.SLOWPOKE]);
|
||||
|
||||
game.move.use(MoveId.DAZZLING_GLEAM);
|
||||
game.move.use(MoveId.POLTERGEIST, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY);
|
||||
const [_, poltergeistUser] = game.scene.getPlayerField();
|
||||
await game.setTurnOrder([BattlerIndex.PLAYER, BattlerIndex.PLAYER_2, BattlerIndex.ENEMY, BattlerIndex.ENEMY_2]);
|
||||
await game.toEndOfTurn();
|
||||
// Expect poltergeist to have failed
|
||||
expect(poltergeistUser).toHaveUsedMove({ move: MoveId.POLTERGEIST, result: MoveResult.FAIL });
|
||||
// If the test makes it to the end of turn, no crash occurred. Nothing to assert
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user