pokerogue/src/phases/move-charge-phase.ts
Dean 87e6095a00
[Misc/Feature] Add dynamic turn order (#6036)
* Add new priority queues

* Add dynamic queue manager

* Add timing modifier and fix post speed ordering

* Make `phaseQueue` private

* Fix `gameManager.setTurnOrder`

* Update `findPhase` to also check dynamic queues

* Modify existing phase manager methods to check dynamic queues

* Fix move order persisting through tests

* Fix magic coat/bounce

* Use append for magic coat/bounce

* Remove `getSpeedOrder` from `TurnStartPhase`, fix references to `getCommandOrder` in tests

* Fix round queuing last instead of next

* Add quick draw application

* Add quick claw activation

* Fix turn order tracking

* Add move header queue to fix ordering

* Fix abilities activating immediately on summon

* Fix `postsummonphases` being shuffled (need to handle speed ties differently here)

* Update speed order function

* Add `StaticSwitchSummonPhase`

* Fix magic coat/bounce error from conflict resolution

* Remove conditional queue

* Fix dancer and baton pass tests

* Automatically queue consecutive Pokémon phases as dynamic

* Move turn end phases queuing back to `TurnStartPhase`

* Fix `LearnMovePhase`

* Remove `PrependSplice`

* Move DQM to phase manager

* Fix various phases being pushed instead of unshifted

* Remove `StaticSwitchSummonPhase`

* Ensure the top queue is always at length - 1

* Fix encounter `PostSummonPhase`s and Revival Blessing

* Fix move headers

* Remove implicit ordering from DQM

* Fix `PostSummonPhase`s in encounters running too early

* Fix `tryRemovePhase` usages

* Add `MovePhase` after `MoveEndPhase` automatically

* Implement an `inSpeedOrder` function

* Merge fixes

* Fix encounter rewards

* Defer `FaintPhase`s where splice was used previously

* Separate speed order utils to avoid circular imports

* Temporarily disable lunar dance test

* Simplify deferral

* Remove move priority modifier

* Fix TS errors in code files

* Fix ts errors in tests

* Fix more test files

* Fix postsummon + checkswitch ability activations

* Fix `removeAll`

* Reposition `positionalTagPhase`

* Re-add `startCurrentPhase`

* Avoid overwriting `currentPhase` after `turnStart`

* Delete `switchSummonPhasePriorityQueue`

* Update `phase-manager.ts`

* Remove uses of `isNullOrUndefined`

* Rename deferral methods

* Update docs and use `getPlayerField(true)` in turn start phase

* Use `.getEnemyField(true)`

* Update docs for post summon phase priority queue (psppq)

* Update speed order utils

* Remove null from `nextPhase`

* Update move phase timing modifier docs

* Remove mention of phases from base priority queue class

* Remove and replace `applyInSpeedOrder`

* Don't sort weather effect phases

* Order priority queues before removing

- Add some `readonly` and `public` modifiers

- Remove unused `queuedPhases` field from `MoveEffectPhase`

* Fix linting in `phase-manager.ts`

* Remove unnecessary turn order modification in Rage Fist test

---------

Co-authored-by: Bertie690 <136088738+Bertie690@users.noreply.github.com>
Co-authored-by: Sirz Benjie <142067137+SirzBenjie@users.noreply.github.com>
Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
2025-09-20 17:49:40 -05:00

103 lines
3.9 KiB
TypeScript

import { globalScene } from "#app/global-scene";
import { MoveChargeAnim } from "#data/battle-anims";
import type { BattlerIndex } from "#enums/battler-index";
import { BattlerTagType } from "#enums/battler-tag-type";
import { MoveResult } from "#enums/move-result";
import type { MoveUseMode } from "#enums/move-use-mode";
import type { Pokemon } from "#field/pokemon";
import { applyMoveChargeAttrs } from "#moves/apply-attrs";
import type { PokemonMove } from "#moves/pokemon-move";
import { PokemonPhase } from "#phases/pokemon-phase";
import type { ChargingMove } from "#types/move-types";
import { BooleanHolder } from "#utils/common";
/**
* 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("MoveEndPhase", phase => 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());
}
}