Track Gen 3 Pressure (#2607)
Some checks failed
Node.js CI / build (22.x) (push) Has been cancelled

This commit is contained in:
André Bastos Dias 2026-03-19 20:38:47 +00:00 committed by GitHub
parent 1f8317aedd
commit 31e23b39d3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 69 additions and 23 deletions

View File

@ -8,7 +8,7 @@
* @license MIT
*/
import { Pokemon, type Battle, type ServerPokemon } from "./battle";
import { Pokemon, type Battle, type PPState, type ServerPokemon } from "./battle";
import { Dex, type ModdedDex, toID, type ID } from "./battle-dex";
import type { BattleScene } from "./battle-animations";
import { BattleLog } from "./battle-log";
@ -993,8 +993,8 @@ export class BattleTooltips {
}).length > 4) {
text += `(More than 4 moves is usually a sign of Illusion Zoroark/Zorua.) `;
}
if (this.battle.gen === 3) {
text += `(Pressure is not visible in Gen 3, so in certain situations, more PP may have been lost than shown here.) `;
if (this.battle.gen === 3 && clientPokemon.moveTrack.some(([_, pp]) => typeof pp !== 'number')) {
text += `(Pressure is not visible in Gen 3, so in certain situations, the exact amount of PP used may be unknown.) `;
}
if (this.pokemonHasClones(clientPokemon)) {
text += `(Your opponent has two indistinguishable Pokémon, making it impossible for you to tell which one has which moves/ability/item.) `;
@ -1472,7 +1472,7 @@ export class BattleTooltips {
return buf;
}
getPPUseText(moveTrackRow: [string, number], showKnown?: boolean) {
getPPUseText(moveTrackRow: [string, PPState], showKnown?: boolean) {
let [moveName, ppUsed] = moveTrackRow;
let move;
let maxpp;
@ -1490,7 +1490,11 @@ export class BattleTooltips {
return `${bullet} ${move.name} <small>(0/${maxpp})</small>`;
}
if (ppUsed || moveName.startsWith('*')) {
return `${bullet} ${move.name} <small>(${maxpp - ppUsed}/${maxpp})</small>`;
if (typeof ppUsed === 'number') {
return `${bullet} ${move.name} <small>(${maxpp - ppUsed}/${maxpp})</small>`;
} else {
return `${bullet} ${move.name} <small>(${maxpp - ppUsed[0]}/${maxpp} to ${maxpp - ppUsed[1]}/${maxpp})</small>`;
}
}
return `${bullet} ${move.name} ${showKnown ? ' <small>(revealed)</small>' : ''}`;
}
@ -1988,7 +1992,8 @@ export class BattleTooltips {
value.set(20 + 20 * boostCount);
}
if (move.id === 'trumpcard') {
const ppLeft = 5 - this.ppUsed(move, pokemon);
const pp = this.ppUsed(move, pokemon);
const ppLeft = 5 - (typeof pp === 'number' ? pp : pp[1]);
let basePower = 40;
if (ppLeft === 1) basePower = 200;
else if (ppLeft === 2) basePower = 80;

View File

@ -40,6 +40,7 @@ declare const app: { user: AnyObject, rooms: AnyObject, ignore?: AnyObject } | u
export type EffectState = any[] & { 0: ID };
export type WeatherState = [name: string, minTimeLeft: number, maxTimeLeft: number];
export type HPColor = 'r' | 'y' | 'g';
export type PPState = number | [number, number];
export class Pokemon implements PokemonDetails, PokemonHealth {
name = '';
@ -106,7 +107,7 @@ export class Pokemon implements PokemonDetails, PokemonHealth {
lastMove = '';
/** [[moveName, ppUsed]] */
moveTrack: [string, number][] = [];
moveTrack: [string, PPState][] = [];
statusData = { sleepTurns: 0, toxicTurns: 0 };
timesAttacked = 0;
@ -340,7 +341,37 @@ export class Pokemon implements PokemonDetails, PokemonHealth {
this.clearMovestatuses();
this.side.battle.scene.clearEffects(this);
}
rememberMove(moveName: string, pp = 1, recursionSource?: string) {
private mergePP(entry: [string, PPState], pp: PPState): PPState {
let ppUsed = entry[1];
if (typeof ppUsed === 'number') {
if (typeof pp === 'number') {
ppUsed += pp;
} else {
ppUsed = [ppUsed + pp[0], ppUsed + pp[1]];
}
} else {
if (typeof pp === 'number') {
ppUsed[0] += pp;
ppUsed[1] += pp;
} else {
ppUsed[0] += pp[0];
ppUsed[1] += pp[1];
}
}
if (typeof ppUsed === 'number') {
if (ppUsed < 0) ppUsed = 0;
} else {
if (ppUsed[0] < 0) ppUsed[0] = 0;
if (ppUsed[1] < 0) ppUsed[1] = 0;
const move = this.side.battle.dex.moves.get(entry[0]);
const maxpp = (move.pp === 1 || move.noPPBoosts ? move.pp : move.pp * 8 / 5);
if (ppUsed[0] > maxpp) ppUsed[0] = maxpp;
if (ppUsed[0] < ppUsed[1]) ppUsed[0] = ppUsed[1];
if (ppUsed[0] === ppUsed[1]) ppUsed = ppUsed[0];
}
return ppUsed;
}
rememberMove(moveName: string, pp: PPState = 1, recursionSource?: string) {
if (recursionSource === this.ident) return;
moveName = Dex.moves.get(moveName).name;
if (moveName.startsWith('*')) return;
@ -353,8 +384,7 @@ export class Pokemon implements PokemonDetails, PokemonHealth {
}
for (const entry of this.moveTrack) {
if (moveName === entry[0]) {
entry[1] += pp;
if (entry[1] < 0) entry[1] = 0;
entry[1] = this.mergePP(entry, pp);
return;
}
}
@ -1537,8 +1567,8 @@ export class Battle {
}
}
}
let pp = 1;
if (this.abilityActive('Pressure') && move.id !== 'stickyweb') {
let pp: PPState = callerMoveForPressure ? 0 : 1; // 1 pp was already deducted from using the move itself
if ((this.abilityActive('Pressure') || this.gen === 3) && move.id !== 'stickyweb') {
const foeTargets = [];
const moveTarget = move.pressureTarget;
@ -1559,18 +1589,9 @@ export class Battle {
} else if (target && target.side !== pokemon.side) {
foeTargets.push(target);
}
for (const foe of foeTargets) {
if (foe && !foe.fainted && foe.effectiveAbility() === 'Pressure') {
pp += 1;
}
}
}
if (!callerMoveForPressure) {
pokemon.rememberMove(moveName, pp);
} else {
pokemon.rememberMove(callerMoveForPressure.name, pp - 1); // 1 pp was already deducted from using the move itself
pp = this.getPressurePP(pp, foeTargets.filter(foe => foe && !foe.fainted) as Pokemon[]);
}
pokemon.rememberMove(callerMoveForPressure ? callerMoveForPressure.name : moveName, pp);
}
pokemon.lastMove = move.id;
this.lastMove = move.id;
@ -1578,6 +1599,26 @@ export class Battle {
pokemon.side.wisher = pokemon;
}
}
private getPressurePP(pp: PPState, foes: Pokemon[]) {
for (const foe of foes) {
const abilities = Object.values(this.dex.species.get(foe.speciesForme).abilities);
const canHavePressure = this.gen === 3 && abilities.includes('Pressure');
if (foe.effectiveAbility() === 'Pressure' || (canHavePressure && abilities.length === 1)) {
if (typeof pp === 'number') {
pp += 1;
} else {
pp[0] += 1;
pp[1] += 1;
}
} else if (canHavePressure) {
if (typeof pp === 'number') {
pp = [pp, pp];
}
pp[0] += 1;
}
}
return pp;
}
animateMove(pokemon: Pokemon, move: Dex.Move, target: Pokemon | null, kwArgs: KWArgs) {
this.activeMoveIsSpread = kwArgs.spread;
if (this.seeking !== null || kwArgs.still) return;