diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 8110bf96bfd..f12fc14b17f 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -3206,6 +3206,14 @@ export class PokemonMove { return allMoves[this.moveId]; } + /** + * Sets {@link ppUsed} for this move and ensures the value does not exceed {@link getMovePp} + * @param {number} count Amount of PP to use + */ + usePp(count: number = 1) { + this.ppUsed = Math.min(this.ppUsed + count, this.getMovePp()); + } + getMovePp(): integer { return this.getMove().pp + this.ppUp * Math.max(Math.floor(this.getMove().pp / 5), 1); } diff --git a/src/phases.ts b/src/phases.ts index e5d67de28af..9595ab9c395 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -2158,6 +2158,7 @@ export class MovePhase extends BattlePhase { public targets: BattlerIndex[]; protected followUp: boolean; protected ignorePp: boolean; + protected failed: boolean; protected cancelled: boolean; constructor(scene: BattleScene, pokemon: Pokemon, targets: BattlerIndex[], move: PokemonMove, followUp?: boolean, ignorePp?: boolean) { @@ -2168,6 +2169,7 @@ export class MovePhase extends BattlePhase { this.move = move; this.followUp = !!followUp; this.ignorePp = !!ignorePp; + this.failed = false; this.cancelled = false; } @@ -2175,6 +2177,12 @@ export class MovePhase extends BattlePhase { return this.pokemon.isActive(true) && this.move.isUsable(this.pokemon, this.ignorePp) && !!this.targets.length; } + /**Signifies the current move should fail but still use PP */ + fail(): void { + this.failed = true; + } + + /**Signifies the current move should cancel and retain PP */ cancel(): void { this.cancelled = true; } @@ -2214,7 +2222,7 @@ export class MovePhase extends BattlePhase { this.targets[0] = attacker.getBattlerIndex(); } if (this.targets[0] === BattlerIndex.ATTACKER) { - this.cancel(); + this.fail(); // Marks the move as failed for later in doMove this.showMoveText(); this.showFailedText(); } @@ -2234,11 +2242,24 @@ export class MovePhase extends BattlePhase { this.pokemon.turnData.acted = true; // Record that the move was attempted, even if it fails this.pokemon.lapseTags(BattlerTagLapseType.PRE_MOVE); + + let ppUsed = 1; + // Filter all opponents to include only those this move is targeting + const targetedOpponents = this.pokemon.getOpponents().filter(o => this.targets.includes(o.getBattlerIndex())); + for (let opponent of targetedOpponents) { + if (this.move.ppUsed + ppUsed >= this.move.getMovePp()) // If we're already at max PP usage, stop checking + break; + if (opponent.hasAbilityWithAttr(IncreasePpAbAttr)) // Accounting for abilities like Pressure + ppUsed++; + } if (!this.followUp && this.canMove() && !this.cancelled) { this.pokemon.lapseTags(BattlerTagLapseType.MOVE); } - if (this.cancelled) { + if (this.cancelled || this.failed) { + if (this.failed) + this.move.usePp(ppUsed); // Only use PP if the move failed + this.pokemon.pushMoveHistory({ move: Moves.NONE, result: MoveResult.FAIL }); return this.end(); } @@ -2253,23 +2274,12 @@ export class MovePhase extends BattlePhase { if ((moveQueue.length && moveQueue[0].move === Moves.NONE) || !targets.length) { moveQueue.shift(); this.cancel(); - } - - if (this.cancelled) { this.pokemon.pushMoveHistory({ move: Moves.NONE, result: MoveResult.FAIL }); return this.end(); } - if (!moveQueue.length || !moveQueue.shift().ignorePP) { - this.move.ppUsed++; - const targetedOpponents = this.pokemon.getOpponents().filter(o => this.targets.includes(o.getBattlerIndex())); - for (let opponent of targetedOpponents) { - if (this.move.ppUsed === this.move.getMove().pp) - break; - if (opponent.hasAbilityWithAttr(IncreasePpAbAttr)) - this.move.ppUsed = Math.min(this.move.ppUsed + 1, this.move.getMovePp()); - } - } + if (!moveQueue.length || !moveQueue.shift().ignorePP) // using .shift here clears out two turn moves once they've been used + this.move.usePp(ppUsed); if (!allMoves[this.move.moveId].getAttrs(CopyMoveAttr).length) this.scene.currentBattle.lastMove = this.move.moveId;