[P2] Fixes Transform/Imposter not updating type/battle stat changes immediately; set move PP to 5 when transforming (#3462)

* Adds updateInfo to transform move/ability, mirrors Transform functionality in Imposter

* Implements functionality for reducing pp to 5 or less for each move when transforming

* Refactors to async/await pattern, adds back removed anims/sounds from last commit

* Eslint fix attempt

* Update src/data/ability.ts

per DayKev's suggestion

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

* Merge and fix conflicts

* Adds unit tests for pp-change with transform/imposter

* Updates to consistency in syntax/deprecated code

---------

Co-authored-by: NightKev <34855794+DayKev@users.noreply.github.com>
This commit is contained in:
schmidtc1 2024-10-23 11:12:53 -04:00 committed by GitHub
parent fd38ab4cb4
commit 958d79140c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 84 additions and 51 deletions

@ -1 +1 @@
Subproject commit fc4a1effd5170def3c8314208a52cd0d8e6913ef Subproject commit 3ccef8472dd7cc7c362538489954cb8fdad27e5f

View File

@ -2422,11 +2422,12 @@ export class PostSummonTransformAbAttr extends PostSummonAbAttr {
super(true); super(true);
} }
applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { async applyPostSummon(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): Promise<boolean> {
const targets = pokemon.getOpponents(); const targets = pokemon.getOpponents();
if (simulated || !targets.length) { if (simulated || !targets.length) {
return simulated; return simulated;
} }
const promises: Promise<void>[] = [];
let target: Pokemon; let target: Pokemon;
if (targets.length > 1) { if (targets.length > 1) {
@ -2435,7 +2436,7 @@ export class PostSummonTransformAbAttr extends PostSummonAbAttr {
target = targets[0]; target = targets[0];
} }
target = target!; // compiler doesn't know its guranteed to be defined target = target!;
pokemon.summonData.speciesForm = target.getSpeciesForm(); pokemon.summonData.speciesForm = target.getSpeciesForm();
pokemon.summonData.fusionSpeciesForm = target.getFusionSpeciesForm(); pokemon.summonData.fusionSpeciesForm = target.getFusionSpeciesForm();
pokemon.summonData.ability = target.getAbility().id; pokemon.summonData.ability = target.getAbility().id;
@ -2452,18 +2453,23 @@ export class PostSummonTransformAbAttr extends PostSummonAbAttr {
pokemon.setStatStage(s, target.getStatStage(s)); pokemon.setStatStage(s, target.getStatStage(s));
} }
pokemon.summonData.moveset = target.getMoveset().map(m => new PokemonMove(m?.moveId ?? Moves.NONE, m?.ppUsed, m?.ppUp)); 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);
});
pokemon.summonData.types = target.getTypes(); pokemon.summonData.types = target.getTypes();
promises.push(pokemon.updateInfo());
pokemon.scene.queueMessage(i18next.t("abilityTriggers:postSummonTransform", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), targetName: target!.name, }));
pokemon.scene.playSound("battle_anims/PRSFX- Transform"); pokemon.scene.playSound("battle_anims/PRSFX- Transform");
promises.push(pokemon.loadAssets(false).then(() => {
pokemon.loadAssets(false).then(() => {
pokemon.playAnim(); pokemon.playAnim();
pokemon.updateInfo(); pokemon.updateInfo();
}); }));
pokemon.scene.queueMessage(i18next.t("abilityTriggers:postSummonTransform", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), targetName: target.name, })); await Promise.all(promises);
return true; return true;
} }

View File

@ -6643,42 +6643,49 @@ export class SuppressAbilitiesIfActedAttr extends MoveEffectAttr {
} }
export class TransformAttr extends MoveEffectAttr { export class TransformAttr extends MoveEffectAttr {
apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): Promise<boolean> { async apply(user: Pokemon, target: Pokemon, move: Move, args: any[]): Promise<boolean> {
return new Promise(resolve => { if (!super.apply(user, target, move, args)) {
if (!super.apply(user, target, move, args)) { return false;
return resolve(false); }
}
user.summonData.speciesForm = target.getSpeciesForm(); const promises: Promise<void>[] = [];
user.summonData.fusionSpeciesForm = target.getFusionSpeciesForm(); user.summonData.speciesForm = target.getSpeciesForm();
user.summonData.ability = target.getAbility().id; user.summonData.fusionSpeciesForm = target.getFusionSpeciesForm();
user.summonData.gender = target.getGender(); user.summonData.ability = target.getAbility().id;
user.summonData.fusionGender = target.getFusionGender(); user.summonData.gender = target.getGender();
user.summonData.fusionGender = target.getFusionGender();
// Power Trick's effect will not preserved after using Transform // Power Trick's effect will not preserved after using Transform
user.removeTag(BattlerTagType.POWER_TRICK); user.removeTag(BattlerTagType.POWER_TRICK);
// Copy all stats (except HP) // Copy all stats (except HP)
for (const s of EFFECTIVE_STATS) { for (const s of EFFECTIVE_STATS) {
user.setStat(s, target.getStat(s, false), false); user.setStat(s, target.getStat(s, false), false);
} }
// Copy all stat stages // Copy all stat stages
for (const s of BATTLE_STATS) { for (const s of BATTLE_STATS) {
user.setStatStage(s, target.getStatStage(s)); user.setStatStage(s, target.getStatStage(s));
} }
user.summonData.moveset = target.getMoveset().map(m => new PokemonMove(m?.moveId!, m?.ppUsed, m?.ppUp)); // TODO: is this bang correct? user.summonData.moveset = target.getMoveset().map(m => {
user.summonData.types = target.getTypes(); 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.
user.scene.queueMessage(i18next.t("moveTriggers:transformedIntoTarget", { pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target) })); const ppUp = pp <= 5 ? 0 : (5 - pp) / Math.max(Math.floor(pp / 5), 1);
return new PokemonMove(m?.moveId!, 0, ppUp);
user.loadAssets(false).then(() => {
user.playAnim();
user.updateInfo();
resolve(true);
});
}); });
user.summonData.types = target.getTypes();
promises.push(user.updateInfo());
user.scene.queueMessage(i18next.t("moveTriggers:transformedIntoTarget", { pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target) }));
promises.push(user.loadAssets(false).then(() => {
user.playAnim();
user.updateInfo();
}));
await Promise.all(promises);
return true;
} }
} }

View File

@ -36,9 +36,7 @@ describe("Abilities - Imposter", () => {
}); });
it("should copy species, ability, gender, all stats except HP, all stat stages, moveset, and types of target", async () => { it("should copy species, ability, gender, all stats except HP, all stat stages, moveset, and types of target", async () => {
await game.startBattle([ await game.classicMode.startBattle([ Species.DITTO ]);
Species.DITTO
]);
game.move.select(Moves.SPLASH); game.move.select(Moves.SPLASH);
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
@ -78,9 +76,7 @@ describe("Abilities - Imposter", () => {
it("should copy in-battle overridden stats", async () => { it("should copy in-battle overridden stats", async () => {
game.override.enemyMoveset([ Moves.POWER_SPLIT ]); game.override.enemyMoveset([ Moves.POWER_SPLIT ]);
await game.startBattle([ await game.classicMode.startBattle([ Species.DITTO ]);
Species.DITTO
]);
const player = game.scene.getPlayerPokemon()!; const player = game.scene.getPlayerPokemon()!;
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.scene.getEnemyPokemon()!;
@ -97,4 +93,18 @@ describe("Abilities - Imposter", () => {
expect(player.getStat(Stat.SPATK, false)).toBe(avgSpAtk); expect(player.getStat(Stat.SPATK, false)).toBe(avgSpAtk);
expect(enemy.getStat(Stat.SPATK, false)).toBe(avgSpAtk); expect(enemy.getStat(Stat.SPATK, false)).toBe(avgSpAtk);
}); });
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 ]);
const player = game.scene.getPlayerPokemon()!;
game.move.select(Moves.TACKLE);
await game.phaseInterceptor.to(TurnEndPhase);
player.getMoveset().forEach(move => {
expect(move!.getMovePp()).toBeLessThanOrEqual(5);
});
});
}); });

View File

@ -36,9 +36,7 @@ describe("Moves - Transform", () => {
}); });
it("should copy species, ability, gender, all stats except HP, all stat stages, moveset, and types of target", async () => { it("should copy species, ability, gender, all stats except HP, all stat stages, moveset, and types of target", async () => {
await game.startBattle([ await game.classicMode.startBattle([ Species.DITTO ]);
Species.DITTO
]);
game.move.select(Moves.TRANSFORM); game.move.select(Moves.TRANSFORM);
await game.phaseInterceptor.to(TurnEndPhase); await game.phaseInterceptor.to(TurnEndPhase);
@ -78,9 +76,7 @@ describe("Moves - Transform", () => {
it("should copy in-battle overridden stats", async () => { it("should copy in-battle overridden stats", async () => {
game.override.enemyMoveset([ Moves.POWER_SPLIT ]); game.override.enemyMoveset([ Moves.POWER_SPLIT ]);
await game.startBattle([ await game.classicMode.startBattle([ Species.DITTO ]);
Species.DITTO
]);
const player = game.scene.getPlayerPokemon()!; const player = game.scene.getPlayerPokemon()!;
const enemy = game.scene.getEnemyPokemon()!; const enemy = game.scene.getEnemyPokemon()!;
@ -97,4 +93,18 @@ describe("Moves - Transform", () => {
expect(player.getStat(Stat.SPATK, false)).toBe(avgSpAtk); expect(player.getStat(Stat.SPATK, false)).toBe(avgSpAtk);
expect(enemy.getStat(Stat.SPATK, false)).toBe(avgSpAtk); expect(enemy.getStat(Stat.SPATK, false)).toBe(avgSpAtk);
}); });
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 ]);
const player = game.scene.getPlayerPokemon()!;
game.move.select(Moves.TRANSFORM);
await game.phaseInterceptor.to(TurnEndPhase);
player.getMoveset().forEach(move => {
expect(move!.getMovePp()).toBeLessThanOrEqual(5);
});
});
}); });