From 8496255a046ec0b5aeb9c74e09ec84fbaeb099f0 Mon Sep 17 00:00:00 2001 From: Michael Li Date: Thu, 24 Oct 2024 22:53:56 -0400 Subject: [PATCH] [Beta] Stop Transform giving copied moves negative fractional `ppUp` --- src/data/ability.ts | 5 ++--- src/data/move.ts | 5 ++--- src/field/pokemon.ts | 19 +++++++++++++------ src/modifier/modifier-type.ts | 2 +- src/modifier/modifier.ts | 2 +- src/system/pokemon-data.ts | 2 +- src/test/abilities/imposter.test.ts | 15 ++++++++++++--- src/test/moves/transform.test.ts | 17 +++++++++++++---- 8 files changed, 45 insertions(+), 22 deletions(-) diff --git a/src/data/ability.ts b/src/data/ability.ts index d761657f5cd..a8b0926e1c9 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -2455,9 +2455,8 @@ export class PostSummonTransformAbAttr extends PostSummonAbAttr { pokemon.summonData.moveset = target.getMoveset().map(m => { const pp = m?.getMove().pp ?? 0; - // if PP value is less than 5, do nothing. If greater, we need to reduce the value to 5 using a negative ppUp value. - const ppUp = pp <= 5 ? 0 : (5 - pp) / Math.max(Math.floor(pp / 5), 1); - return new PokemonMove(m?.moveId ?? Moves.NONE, 0, ppUp); + // If PP value is less than 5, do nothing. If greater, we need to reduce the value to 5. + return new PokemonMove(m?.moveId!, 0, 0, false, Math.min(pp, 5)); }); pokemon.summonData.types = target.getTypes(); promises.push(pokemon.updateInfo()); diff --git a/src/data/move.ts b/src/data/move.ts index efdd4568927..f872224af8a 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -6670,9 +6670,8 @@ export class TransformAttr extends MoveEffectAttr { user.summonData.moveset = target.getMoveset().map(m => { const pp = m?.getMove().pp ?? 0; - // if PP value is less than 5, do nothing. If greater, we need to reduce the value to 5 using a negative ppUp value. - const ppUp = pp <= 5 ? 0 : (5 - pp) / Math.max(Math.floor(pp / 5), 1); - return new PokemonMove(m?.moveId!, 0, ppUp); + // If PP value is less than 5, do nothing. If greater, we need to reduce the value to 5. + return new PokemonMove(m?.moveId!, 0, 0, false, Math.min(pp, 5)); }); user.summonData.types = target.getTypes(); promises.push(user.updateInfo()); diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index d41c1f9eefa..addb0679d19 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -4453,7 +4453,7 @@ export class PlayerPokemon extends Pokemon { copyMoveset(): PokemonMove[] { const newMoveset : PokemonMove[] = []; this.moveset.forEach(move => - newMoveset.push(new PokemonMove(move!.moveId, 0, move!.ppUp, move!.virtual))); // TODO: are those bangs correct? + newMoveset.push(new PokemonMove(move!.moveId, 0, move!.ppUp, move!.virtual, move!.maxPpOverride))); // TODO: are those bangs correct? return newMoveset; } @@ -5180,15 +5180,22 @@ export interface DamageCalculationResult { **/ export class PokemonMove { public moveId: Moves; - public ppUsed: integer; - public ppUp: integer; + public ppUsed: number; + public ppUp: number; public virtual: boolean; - constructor(moveId: Moves, ppUsed?: integer, ppUp?: integer, virtual?: boolean) { + /** + * If defined and nonzero, overrides the maximum PP of the move (e.g., due to move being copied by Transform). + * This also nullifies all effects of `ppUp`. + */ + public maxPpOverride?: number; + + constructor(moveId: Moves, ppUsed?: number, ppUp?: number, virtual?: boolean, maxPpOverride?: number) { this.moveId = moveId; this.ppUsed = ppUsed || 0; this.ppUp = ppUp || 0; this.virtual = !!virtual; + this.maxPpOverride = maxPpOverride; } /** @@ -5225,7 +5232,7 @@ export class PokemonMove { } getMovePp(): integer { - return this.getMove().pp + this.ppUp * Utils.toDmgValue(this.getMove().pp / 5); + return this.maxPpOverride || (this.getMove().pp + this.ppUp * Utils.toDmgValue(this.getMove().pp / 5)); } getPpRatio(): number { @@ -5242,6 +5249,6 @@ export class PokemonMove { * @return {PokemonMove} A valid pokemonmove object */ static loadMove(source: PokemonMove | any): PokemonMove { - return new PokemonMove(source.moveId, source.ppUsed, source.ppUp, source.virtual); + return new PokemonMove(source.moveId, source.ppUsed, source.ppUp, source.virtual, source.maxPpOverride); } } diff --git a/src/modifier/modifier-type.ts b/src/modifier/modifier-type.ts index 3e475c62590..f4b59b9d882 100644 --- a/src/modifier/modifier-type.ts +++ b/src/modifier/modifier-type.ts @@ -384,7 +384,7 @@ export class PokemonPpUpModifierType extends PokemonMoveModifierType { (_pokemon: PlayerPokemon) => { return null; }, (pokemonMove: PokemonMove) => { - if (pokemonMove.getMove().pp < 5 || pokemonMove.ppUp >= 3) { + if (pokemonMove.getMove().pp < 5 || pokemonMove.ppUp >= 3 || pokemonMove.maxPpOverride) { return PartyUiHandler.NoEffectMessage; } return null; diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index 11f16f103a5..36f94b99b20 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -2166,7 +2166,7 @@ export class PokemonPpUpModifier extends ConsumablePokemonMoveModifier { override apply(playerPokemon: PlayerPokemon): boolean { const move = playerPokemon.getMoveset()[this.moveIndex]; - if (move) { + if (move && !move.maxPpOverride) { move.ppUp = Math.min(move.ppUp + this.upPoints, 3); } diff --git a/src/system/pokemon-data.ts b/src/system/pokemon-data.ts index 421739a9da1..c8756e4dd7f 100644 --- a/src/system/pokemon-data.ts +++ b/src/system/pokemon-data.ts @@ -135,7 +135,7 @@ export default class PokemonData { } } } else { - this.moveset = (source.moveset || [ new PokemonMove(Moves.TACKLE), new PokemonMove(Moves.GROWL) ]).filter(m => m).map((m: any) => new PokemonMove(m.moveId, m.ppUsed, m.ppUp)); + this.moveset = (source.moveset || [ new PokemonMove(Moves.TACKLE), new PokemonMove(Moves.GROWL) ]).filter(m => m).map((m: any) => new PokemonMove(m.moveId, m.ppUsed, m.ppUp, m.virtual, m.maxPpOverride)); if (!forHistory) { this.status = source.status ? new Status(source.status.effect, source.status.toxicTurnCount, source.status.sleepTurnsRemaining) diff --git a/src/test/abilities/imposter.test.ts b/src/test/abilities/imposter.test.ts index 7aaac5ca8c4..3445b3b322c 100644 --- a/src/test/abilities/imposter.test.ts +++ b/src/test/abilities/imposter.test.ts @@ -60,18 +60,19 @@ describe("Abilities - Imposter", () => { const playerMoveset = player.getMoveset(); const enemyMoveset = player.getMoveset(); + expect(playerMoveset.length).toBe(enemyMoveset.length); for (let i = 0; i < playerMoveset.length && i < enemyMoveset.length; i++) { - // TODO: Checks for 5 PP should be done here when that gets addressed expect(playerMoveset[i]?.moveId).toBe(enemyMoveset[i]?.moveId); } const playerTypes = player.getTypes(); const enemyTypes = enemy.getTypes(); + expect(playerTypes.length).toBe(enemyTypes.length); for (let i = 0; i < playerTypes.length && i < enemyTypes.length; i++) { expect(playerTypes[i]).toBe(enemyTypes[i]); } - }, 20000); + }); it("should copy in-battle overridden stats", async () => { game.override.enemyMoveset([ Moves.POWER_SPLIT ]); @@ -104,7 +105,15 @@ describe("Abilities - Imposter", () => { await game.phaseInterceptor.to(TurnEndPhase); player.getMoveset().forEach(move => { - expect(move!.getMovePp()).toBeLessThanOrEqual(5); + // Should set correct maximum PP without touching `ppUp` + if (move) { + if (move.moveId === Moves.SKETCH) { + expect(move.getMovePp()).toBe(1); + } else { + expect(move.getMovePp()).toBe(5); + } + expect(move.ppUp).toBe(0); + } }); }); }); diff --git a/src/test/moves/transform.test.ts b/src/test/moves/transform.test.ts index 8c0f5eda7b2..adb97b42af7 100644 --- a/src/test/moves/transform.test.ts +++ b/src/test/moves/transform.test.ts @@ -60,18 +60,19 @@ describe("Moves - Transform", () => { const playerMoveset = player.getMoveset(); const enemyMoveset = player.getMoveset(); + expect(playerMoveset.length).toBe(enemyMoveset.length); for (let i = 0; i < playerMoveset.length && i < enemyMoveset.length; i++) { - // TODO: Checks for 5 PP should be done here when that gets addressed expect(playerMoveset[i]?.moveId).toBe(enemyMoveset[i]?.moveId); } const playerTypes = player.getTypes(); const enemyTypes = enemy.getTypes(); + expect(playerTypes.length).toBe(enemyTypes.length); for (let i = 0; i < playerTypes.length && i < enemyTypes.length; i++) { expect(playerTypes[i]).toBe(enemyTypes[i]); } - }, 20000); + }); it("should copy in-battle overridden stats", async () => { game.override.enemyMoveset([ Moves.POWER_SPLIT ]); @@ -94,7 +95,7 @@ describe("Moves - Transform", () => { expect(enemy.getStat(Stat.SPATK, false)).toBe(avgSpAtk); }); - it ("should set each move's pp to a maximum of 5", async () => { + it("should set each move's pp to a maximum of 5", async () => { game.override.enemyMoveset([ Moves.SWORDS_DANCE, Moves.GROWL, Moves.SKETCH, Moves.RECOVER ]); await game.classicMode.startBattle([ Species.DITTO ]); @@ -104,7 +105,15 @@ describe("Moves - Transform", () => { await game.phaseInterceptor.to(TurnEndPhase); player.getMoveset().forEach(move => { - expect(move!.getMovePp()).toBeLessThanOrEqual(5); + // Should set correct maximum PP without touching `ppUp` + if (move) { + if (move.moveId === Moves.SKETCH) { + expect(move.getMovePp()).toBe(1); + } else { + expect(move.getMovePp()).toBe(5); + } + expect(move.ppUp).toBe(0); + } }); }); });