Removed instant and ignoreUpdate parameters from tryTransferHeldItemModifier; fixed post-battle loot code to _not_ break type safety

This commit is contained in:
Bertie690 2025-06-07 12:08:21 -04:00
parent 5da3991e54
commit b996624b03
7 changed files with 76 additions and 65 deletions

View File

@ -2925,10 +2925,10 @@ export default class BattleScene extends SceneBase {
addModifier(
modifier: Modifier | null,
ignoreUpdate?: boolean,
playSound?: boolean,
virtual?: boolean,
instant?: boolean,
ignoreUpdate = false,
playSound = false,
virtual = false,
instant = false,
cost?: number,
): boolean {
// We check against modifier.type to stop a bug related to loading in a pokemon that has a form change item, which prior to some patch
@ -2942,7 +2942,7 @@ export default class BattleScene extends SceneBase {
this.validateAchvs(ModifierAchv, modifier);
const modifiersToRemove: PersistentModifier[] = [];
if (modifier instanceof PersistentModifier) {
if ((modifier as PersistentModifier).add(this.modifiers, !!virtual)) {
if ((modifier as PersistentModifier).add(this.modifiers, virtual)) {
if (modifier instanceof PokemonFormChangeItemModifier) {
const pokemon = this.getPokemonById(modifier.pokemonId);
if (pokemon) {
@ -3015,7 +3015,7 @@ export default class BattleScene extends SceneBase {
return success;
}
addEnemyModifier(modifier: PersistentModifier, ignoreUpdate?: boolean, instant?: boolean): Promise<void> {
addEnemyModifier(modifier: PersistentModifier, ignoreUpdate = false, instant = false): Promise<void> {
return new Promise(resolve => {
const modifiersToRemove: PersistentModifier[] = [];
if ((modifier as PersistentModifier).add(this.enemyModifiers, false)) {
@ -3046,9 +3046,7 @@ export default class BattleScene extends SceneBase {
* @param itemModifier - {@linkcode PokemonHeldItemModifier} to transfer (represents whole stack)
* @param target - Recipient {@linkcode Pokemon} recieving items
* @param playSound - Whether to play a sound when transferring the item
* @param transferQuantity - How many items of the stack to transfer. Optional, defaults to `1`
* @param instant - ??? (Optional)
* @param ignoreUpdate - ??? (Optional)
* @param transferQuantity - How many items of the stack to transfer. Optional, default `1`
* @param itemLost - Whether to treat the item's current holder as losing the item (for now, this simply enables Unburden). Default: `true`.
* @returns Whether the transfer was successful
*/
@ -3057,8 +3055,6 @@ export default class BattleScene extends SceneBase {
target: Pokemon,
playSound: boolean,
transferQuantity = 1,
instant?: boolean,
ignoreUpdate?: boolean,
itemLost = true,
): boolean {
const source = itemModifier.getPokemon();
@ -3106,8 +3102,8 @@ export default class BattleScene extends SceneBase {
}
// TODO: what does this do and why is it here
if (source.isPlayer() !== target.isPlayer() && !ignoreUpdate) {
this.updateModifiers(source.isPlayer(), instant);
if (source.isPlayer() !== target.isPlayer()) {
this.updateModifiers(source.isPlayer(), false);
}
// Add however much we took to the recieving pokemon, creating a new modifier if the target lacked one prio
@ -3118,9 +3114,9 @@ export default class BattleScene extends SceneBase {
newItemModifier.pokemonId = target.id;
newItemModifier.stackCount = countTaken;
if (target.isPlayer()) {
this.addModifier(newItemModifier, ignoreUpdate, playSound, false, instant);
this.addModifier(newItemModifier, false, playSound);
} else {
this.addEnemyModifier(newItemModifier, ignoreUpdate, instant);
this.addEnemyModifier(newItemModifier);
}
}
@ -3286,8 +3282,10 @@ export default class BattleScene extends SceneBase {
[this.modifierBar, this.enemyModifierBar].map(m => m.setVisible(visible));
}
// TODO: Document this
updateModifiers(player = true, instant?: boolean): void {
/**
* @param instant - Whether to instantly update any changes to party members' HP bars; default `false`
*/
updateModifiers(player = true, instant = false): void {
const modifiers = player ? this.modifiers : (this.enemyModifiers as PersistentModifier[]);
for (let m = 0; m < modifiers.length; m++) {
const modifier = modifiers[m];
@ -3319,7 +3317,13 @@ export default class BattleScene extends SceneBase {
}
}
updatePartyForModifiers(party: Pokemon[], instant?: boolean): Promise<void> {
/**
* Update one or more Pokemon's info containers after having recieved modifiers.
* @param party - An array of {@linkcode Pokemon} to update info.
* @param instant - Whether to instantly update any changes to the party's HP bars; default `false`
* @returns A Promise that resolves once all the info containers have been updated.
*/
updatePartyForModifiers(party: Pokemon[], instant = false): Promise<void> {
return new Promise(resolve => {
Promise.allSettled(
party.map(p => {

View File

@ -175,18 +175,11 @@ export default class Battle {
}
addPostBattleLoot(enemyPokemon: EnemyPokemon): void {
this.postBattleLoot.push(
...globalScene
.findModifiers(
m => m instanceof PokemonHeldItemModifier && m.pokemonId === enemyPokemon.id && m.isTransferable,
false,
)
.map(i => {
const ret = i as PokemonHeldItemModifier;
//@ts-ignore - this is awful to fix/change
ret.pokemonId = null;
return ret;
}),
this.postBattleLoot.concat(
globalScene.findModifiers(
m => m instanceof PokemonHeldItemModifier && m.pokemonId === enemyPokemon.id && m.isTransferable,
false,
) as PokemonHeldItemModifier[],
);
}

View File

@ -4724,31 +4724,46 @@ export class PostBattleAbAttr extends AbAttr {
}
export class PostBattleLootAbAttr extends PostBattleAbAttr {
private randItem?: PokemonHeldItemModifier;
override canApplyPostBattle(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean {
const postBattleLoot = globalScene.currentBattle.postBattleLoot;
if (!simulated && postBattleLoot.length && args[0]) {
this.randItem = randSeedItem(postBattleLoot);
return globalScene.canTransferHeldItemModifier(this.randItem, pokemon, 1);
}
return false;
}
/** The index of the random item to steal. */
private randItemIndex: number = 0;
/**
* @param args - `[0]`: boolean for if the battle ended in a victory
*/
override applyPostBattle(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): void {
override canApplyPostBattle(pokemon: Pokemon, passive: boolean, simulated: boolean, args: [boolean]): boolean {
const postBattleLoot = globalScene.currentBattle.postBattleLoot;
if (!this.randItem) {
this.randItem = randSeedItem(postBattleLoot);
const wasVictory = args[0];
if (simulated || postBattleLoot.length === 0 || !wasVictory) {
return false;
}
if (globalScene.tryTransferHeldItemModifier(this.randItem, pokemon, true, 1, true, undefined, false)) {
postBattleLoot.splice(postBattleLoot.indexOf(this.randItem), 1);
globalScene.queueMessage(i18next.t("abilityTriggers:postBattleLoot", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), itemName: this.randItem.type.name }));
// Pick a random item and check if we are capped.
this.randItemIndex = randSeedInt(postBattleLoot.length);
const item = postBattleLoot[this.randItemIndex]
// We can't use `canTransferItemModifier` as that assumes the Pokemon in question already exists (which it does not)
const existingItem = globalScene.findModifier(
(m): m is PokemonHeldItemModifier =>
m instanceof PokemonHeldItemModifier && m.matchType(item) && m.pokemonId === pokemon.id,
pokemon.isPlayer(),
) as PokemonHeldItemModifier | undefined;
return (existingItem?.getCountUnderMax() ?? Number.MAX_SAFE_INTEGER) > 1
}
/**
* Attempt to give the previously selected random item to the ability holder at battle end.
* @param args - `[0]`: boolean for if the battle ended in a victory
*/
override applyPostBattle(pokemon: Pokemon, passive: boolean, simulated: boolean, args: [boolean]): void {
const postBattleLoot = globalScene.currentBattle.postBattleLoot;
const item = postBattleLoot[this.randItemIndex]
item.pokemonId = pokemon.id;
if (globalScene.addModifier(item, false, true)) {
postBattleLoot.splice(this.randItemIndex, 1);
globalScene.queueMessage(i18next.t("abilityTriggers:postBattleLoot", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), itemName: item.type.name }));
}
this.randItem = undefined;
}
}

View File

@ -6005,9 +6005,8 @@ export class PlayerPokemon extends Pokemon {
true,
) as PokemonHeldItemModifier[];
for (const modifier of fusedPartyMemberHeldModifiers) {
globalScene.tryTransferHeldItemModifier(modifier, this, false, modifier.getStackCount(), true, true, false);
globalScene.tryTransferHeldItemModifier(modifier, this, false, modifier.getStackCount(), false);
}
globalScene.updateModifiers(true, true);
globalScene.removePartyMemberModifiers(fusedPartyMemberIndex);
globalScene.getPlayerParty().splice(fusedPartyMemberIndex, 1)[0];
const newPartyMemberIndex = globalScene.getPlayerParty().indexOf(this);

View File

@ -162,8 +162,6 @@ export class SelectModifierPhase extends BattlePhase {
party[toSlotIndex],
true,
itemQuantity,
undefined,
undefined,
false,
);
} else {

View File

@ -138,7 +138,6 @@ export class SwitchSummonPhase extends SummonPhase {
return;
}
if (this.switchType === SwitchType.BATON_PASS) {
// If switching via baton pass, update opposing tags coming from the prior pokemon
(this.player ? globalScene.getEnemyField() : globalScene.getPlayerField()).forEach((enemyPokemon: Pokemon) =>
@ -160,15 +159,7 @@ export class SwitchSummonPhase extends SummonPhase {
) as SwitchEffectTransferModifier;
if (batonPassModifier) {
globalScene.tryTransferHeldItemModifier(
batonPassModifier,
switchedInPokemon,
false,
undefined,
undefined,
undefined,
false,
);
globalScene.tryTransferHeldItemModifier(batonPassModifier, switchedInPokemon, false, 1, false);
}
}
}

View File

@ -538,9 +538,14 @@ export default abstract class BattleInfo extends Phaser.GameObjects.Container {
this.updateHpFrame();
}
/** Update the pokemonHp bar */
protected updatePokemonHp(pokemon: Pokemon, resolve: (r: void | PromiseLike<void>) => void, instant?: boolean): void {
let duration = !instant ? Phaser.Math.Clamp(Math.abs(this.lastHp - pokemon.hp) * 5, 250, 5000) : 0;
/**
* Update a Pokemon's HP bar.
* @param pokemon - The {@linkcode Pokemon} to whom the HP bar belongs.
* @param resolve - A promise to which the HP bar will be chained unto.
* @param instant - Whether to instantly update the pokemon's HP bar; default `false`
*/
protected updatePokemonHp(pokemon: Pokemon, resolve: (r: void | PromiseLike<void>) => void, instant = false): void {
let duration = instant ? 0 : Phaser.Math.Clamp(Math.abs(this.lastHp - pokemon.hp) * 5, 250, 5000);
const speed = globalScene.hpBarSpeed;
if (speed) {
duration = speed >= 3 ? 0 : duration / Math.pow(2, speed);
@ -563,7 +568,13 @@ export default abstract class BattleInfo extends Phaser.GameObjects.Container {
//#endregion
async updateInfo(pokemon: Pokemon, instant?: boolean): Promise<void> {
/**
* Update a Pokemon's battle info, HP bar and other effects.
* @param pokemon - The {@linkcode} Pokemon to whom this BattleInfo belongs.
* @param instant - Whether to instantly update any changes to this Pokemon's HP bar; default `false`
* @returns A Promise that resolves once the Pokemon's info has been successfully updated.
*/
async updateInfo(pokemon: Pokemon, instant = false): Promise<void> {
let resolve: (r: void | PromiseLike<void>) => void = () => {};
const promise = new Promise<void>(r => (resolve = r));
if (!globalScene) {