pokerogue/src/phases/move-charge-phase.ts
Bertie690 5efdb0dc0b
[Refactor] Fix issues with "last move selected" vs "used" (#5810)
* Added `MoveUseType` and refactored MEP

* Fixed Wimp out tests & ME code

finally i think all the booleans are gone
i hope

* Added version migration for last resort and co.

buh gumbug

* Fixed various bugs and added tests for previous bugfixes

* Reverted a couple doc changes

* WIP

* Update pokemon-species.ts

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>

* Update pokemon-phase.ts

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>

* Fixed remaining tests (I think)

* Reverted rollout test changes

* Fixed command phase bug causing metronome test timeout

* Revert early_bird.test.ts

* Fix biome.jsonc

* Made `MoveUseType` start at 1

As per @DayKev's request

* Fixed a thing

* Fixed bolt beak condition to be marginally less jank

* Applied some review suggestions

* Reverted move phase operations

* Added helper functions complete with markdown tables

* Fixed things

* Update battler-tags.ts

* Fixed random issues

* Fixed code

* Fixed comment

* Fixed import issues

* Fix disable.test.ts conflicts

* Update instruct.test.ts

* Update `biome.jsonc`

* Renamed `MoveUseType` to `MoveUseMode`; applied review comments

* Fixed space

* Fixed phasemanager bugs

* Fixed instruct test to not bork

* Fixed gorilla tactics bug

* Battler Tags doc fixes

* Fixed formatting and suttff

* Minor comment updates and remove unused imports in `move.ts`

* Re-add `public`, remove unnecessary default value in `battler-tags.ts`

* Restore `{}` in `turn-start-phase.ts`

Fixes `lint/correctness/noSwitchDeclarations`

* Remove extra space in TSDoc in `move-phase.ts`

* Use `game.field` instead of `game.scene` in `instruct.test.ts`

Also `game.toEndOfTurn()` instead of
`game.phaseInterceptor.to("BerryPhase")`

* Use `game.field` instead of `game.scene` in `metronome.test.ts`

* Use `toEndOfTurn()` instead of `to("BerryPhase")` in `powder.test.ts`

* Convert `MoveUseMode` enum to `const` object

* Update move-phase.ts

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>

* Add `enumValueToKey` utility function

* Apply Biome

---------

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
2025-06-15 10:52:44 -07:00

103 lines
3.9 KiB
TypeScript

import { globalScene } from "#app/global-scene";
import type { BattlerIndex } from "#enums/battler-index";
import { MoveChargeAnim } from "#app/data/battle-anims";
import { applyMoveChargeAttrs } from "#app/data/moves/apply-attrs";
import type { PokemonMove } from "#app/data/moves/pokemon-move";
import type Pokemon from "#app/field/pokemon";
import { MoveResult } from "#enums/move-result";
import { BooleanHolder } from "#app/utils/common";
import { PokemonPhase } from "#app/phases/pokemon-phase";
import { BattlerTagType } from "#enums/battler-tag-type";
import type { MoveUseMode } from "#enums/move-use-mode";
import type { ChargingMove } from "#app/@types/move-types";
/**
* Phase for the "charging turn" of two-turn moves (e.g. Dig).
*/
export class MoveChargePhase extends PokemonPhase {
public readonly phaseName = "MoveChargePhase";
/** The move instance that this phase applies */
public move: PokemonMove;
/** The field index targeted by the move (Charging moves assume single target) */
public targetIndex: BattlerIndex;
/** The {@linkcode MoveUseMode} of the move that triggered the charge; passed on from move phase */
private useMode: MoveUseMode;
/**
* Create a new MoveChargePhase.
* @param battlerIndex - The {@linkcode BattlerIndex} of the user.
* @param targetIndex - The {@linkcode BattlerIndex} of the target.
* @param move - The {@linkcode PokemonMove} being used
* @param useMode - The move's {@linkcode MoveUseMode}
*/
constructor(battlerIndex: BattlerIndex, targetIndex: BattlerIndex, move: PokemonMove, useMode: MoveUseMode) {
super(battlerIndex);
this.move = move;
this.targetIndex = targetIndex;
this.useMode = useMode;
}
public override start() {
super.start();
const user = this.getUserPokemon();
const target = this.getTargetPokemon();
const move = this.move.getMove();
// If the target is somehow not defined, or the move is somehow not a ChargingMove,
// immediately end this phase.
if (!target || !move.isChargingMove()) {
console.warn("Invalid parameters for MoveChargePhase");
super.end();
return;
}
new MoveChargeAnim(move.chargeAnim, move.id, user).play(false, () => {
move.showChargeText(user, target);
applyMoveChargeAttrs("MoveEffectAttr", user, target, move);
user.addTag(BattlerTagType.CHARGING, 1, move.id, user.id);
this.end();
});
}
/** Checks the move's instant charge conditions, then ends this phase. */
public override end() {
const user = this.getUserPokemon();
// Checked for `ChargingMove` in `this.start()`
const move = this.move.getMove() as ChargingMove;
const instantCharge = new BooleanHolder(false);
applyMoveChargeAttrs("InstantChargeAttr", user, null, move, instantCharge);
// If instantly charging, remove the pending MoveEndPhase and queue a new MovePhase for the "attack" portion of the move.
// Otherwise, add the attack portion to the user's move queue to execute next turn.
// TODO: This checks status twice for a single-turn usage...
if (instantCharge.value) {
globalScene.phaseManager.tryRemovePhase(phase => phase.is("MoveEndPhase") && phase.getPokemon() === user);
globalScene.phaseManager.unshiftNew("MovePhase", user, [this.targetIndex], this.move, this.useMode);
} else {
user.pushMoveQueue({ move: move.id, targets: [this.targetIndex], useMode: this.useMode });
}
// Add this move's charging phase to the user's move history
user.pushMoveHistory({
move: this.move.moveId,
targets: [this.targetIndex],
result: MoveResult.OTHER,
useMode: this.useMode,
});
super.end();
}
public getUserPokemon(): Pokemon {
return (this.player ? globalScene.getPlayerField() : globalScene.getEnemyField())[this.fieldIndex];
}
public getTargetPokemon(): Pokemon | undefined {
return globalScene.getField(true).find(p => this.targetIndex === p.getBattlerIndex());
}
}