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( addModifier(
modifier: Modifier | null, modifier: Modifier | null,
ignoreUpdate?: boolean, ignoreUpdate = false,
playSound?: boolean, playSound = false,
virtual?: boolean, virtual = false,
instant?: boolean, instant = false,
cost?: number, cost?: number,
): boolean { ): 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 // 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); this.validateAchvs(ModifierAchv, modifier);
const modifiersToRemove: PersistentModifier[] = []; const modifiersToRemove: PersistentModifier[] = [];
if (modifier instanceof 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) { if (modifier instanceof PokemonFormChangeItemModifier) {
const pokemon = this.getPokemonById(modifier.pokemonId); const pokemon = this.getPokemonById(modifier.pokemonId);
if (pokemon) { if (pokemon) {
@ -3015,7 +3015,7 @@ export default class BattleScene extends SceneBase {
return success; return success;
} }
addEnemyModifier(modifier: PersistentModifier, ignoreUpdate?: boolean, instant?: boolean): Promise<void> { addEnemyModifier(modifier: PersistentModifier, ignoreUpdate = false, instant = false): Promise<void> {
return new Promise(resolve => { return new Promise(resolve => {
const modifiersToRemove: PersistentModifier[] = []; const modifiersToRemove: PersistentModifier[] = [];
if ((modifier as PersistentModifier).add(this.enemyModifiers, false)) { 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 itemModifier - {@linkcode PokemonHeldItemModifier} to transfer (represents whole stack)
* @param target - Recipient {@linkcode Pokemon} recieving items * @param target - Recipient {@linkcode Pokemon} recieving items
* @param playSound - Whether to play a sound when transferring the item * @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 transferQuantity - How many items of the stack to transfer. Optional, default `1`
* @param instant - ??? (Optional)
* @param ignoreUpdate - ??? (Optional)
* @param itemLost - Whether to treat the item's current holder as losing the item (for now, this simply enables Unburden). Default: `true`. * @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 * @returns Whether the transfer was successful
*/ */
@ -3057,8 +3055,6 @@ export default class BattleScene extends SceneBase {
target: Pokemon, target: Pokemon,
playSound: boolean, playSound: boolean,
transferQuantity = 1, transferQuantity = 1,
instant?: boolean,
ignoreUpdate?: boolean,
itemLost = true, itemLost = true,
): boolean { ): boolean {
const source = itemModifier.getPokemon(); const source = itemModifier.getPokemon();
@ -3106,8 +3102,8 @@ export default class BattleScene extends SceneBase {
} }
// TODO: what does this do and why is it here // TODO: what does this do and why is it here
if (source.isPlayer() !== target.isPlayer() && !ignoreUpdate) { if (source.isPlayer() !== target.isPlayer()) {
this.updateModifiers(source.isPlayer(), instant); this.updateModifiers(source.isPlayer(), false);
} }
// Add however much we took to the recieving pokemon, creating a new modifier if the target lacked one prio // 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.pokemonId = target.id;
newItemModifier.stackCount = countTaken; newItemModifier.stackCount = countTaken;
if (target.isPlayer()) { if (target.isPlayer()) {
this.addModifier(newItemModifier, ignoreUpdate, playSound, false, instant); this.addModifier(newItemModifier, false, playSound);
} else { } 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)); [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[]); const modifiers = player ? this.modifiers : (this.enemyModifiers as PersistentModifier[]);
for (let m = 0; m < modifiers.length; m++) { for (let m = 0; m < modifiers.length; m++) {
const modifier = modifiers[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 => { return new Promise(resolve => {
Promise.allSettled( Promise.allSettled(
party.map(p => { party.map(p => {

View File

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

View File

@ -4724,31 +4724,46 @@ export class PostBattleAbAttr extends AbAttr {
} }
export class PostBattleLootAbAttr extends PostBattleAbAttr { export class PostBattleLootAbAttr extends PostBattleAbAttr {
private randItem?: PokemonHeldItemModifier; /** The index of the random item to steal. */
private randItemIndex: number = 0;
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;
}
/** /**
* @param args - `[0]`: boolean for if the battle ended in a victory * @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; const postBattleLoot = globalScene.currentBattle.postBattleLoot;
if (!this.randItem) { const wasVictory = args[0];
this.randItem = randSeedItem(postBattleLoot); if (simulated || postBattleLoot.length === 0 || !wasVictory) {
return false;
} }
if (globalScene.tryTransferHeldItemModifier(this.randItem, pokemon, true, 1, true, undefined, false)) { // Pick a random item and check if we are capped.
postBattleLoot.splice(postBattleLoot.indexOf(this.randItem), 1); this.randItemIndex = randSeedInt(postBattleLoot.length);
globalScene.queueMessage(i18next.t("abilityTriggers:postBattleLoot", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), itemName: this.randItem.type.name })); 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, true,
) as PokemonHeldItemModifier[]; ) as PokemonHeldItemModifier[];
for (const modifier of fusedPartyMemberHeldModifiers) { 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.removePartyMemberModifiers(fusedPartyMemberIndex);
globalScene.getPlayerParty().splice(fusedPartyMemberIndex, 1)[0]; globalScene.getPlayerParty().splice(fusedPartyMemberIndex, 1)[0];
const newPartyMemberIndex = globalScene.getPlayerParty().indexOf(this); const newPartyMemberIndex = globalScene.getPlayerParty().indexOf(this);

View File

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

View File

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

View File

@ -538,9 +538,14 @@ export default abstract class BattleInfo extends Phaser.GameObjects.Container {
this.updateHpFrame(); this.updateHpFrame();
} }
/** Update the pokemonHp bar */ /**
protected updatePokemonHp(pokemon: Pokemon, resolve: (r: void | PromiseLike<void>) => void, instant?: boolean): void { * Update a Pokemon's HP bar.
let duration = !instant ? Phaser.Math.Clamp(Math.abs(this.lastHp - pokemon.hp) * 5, 250, 5000) : 0; * @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; const speed = globalScene.hpBarSpeed;
if (speed) { if (speed) {
duration = speed >= 3 ? 0 : duration / Math.pow(2, speed); duration = speed >= 3 ? 0 : duration / Math.pow(2, speed);
@ -563,7 +568,13 @@ export default abstract class BattleInfo extends Phaser.GameObjects.Container {
//#endregion //#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 = () => {}; let resolve: (r: void | PromiseLike<void>) => void = () => {};
const promise = new Promise<void>(r => (resolve = r)); const promise = new Promise<void>(r => (resolve = r));
if (!globalScene) { if (!globalScene) {