Reverted unneeded changes

This commit is contained in:
Bertie690 2025-06-09 18:29:21 -04:00
parent 5531b3c5cd
commit 69bcbdcaa1
6 changed files with 190 additions and 245 deletions

View File

@ -2614,10 +2614,10 @@ export default class BattleScene extends SceneBase {
addModifier( addModifier(
modifier: Modifier | null, modifier: Modifier | null,
ignoreUpdate = false, ignoreUpdate?: boolean,
playSound = false, playSound?: boolean,
virtual = false, virtual?: boolean,
instant = false, instant?: boolean,
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
@ -2631,7 +2631,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) {
@ -2704,7 +2704,7 @@ export default class BattleScene extends SceneBase {
return success; return success;
} }
addEnemyModifier(modifier: PersistentModifier, ignoreUpdate = false, instant = false): Promise<void> { addEnemyModifier(modifier: PersistentModifier, ignoreUpdate?: boolean, instant?: boolean): 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)) {
@ -2732,128 +2732,124 @@ export default class BattleScene extends SceneBase {
* If the recepient already has the maximum amount allowed for this item, the transfer is cancelled. * If the recepient already has the maximum amount allowed for this item, the transfer is cancelled.
* The quantity to transfer is automatically capped at how much the recepient can take before reaching the maximum stack size for the item. * The quantity to transfer is automatically capped at how much the recepient can take before reaching the maximum stack size for the item.
* A transfer that moves a quantity smaller than what is specified in the transferQuantity parameter is still considered successful. * A transfer that moves a quantity smaller than what is specified in the transferQuantity parameter is still considered successful.
* @param itemModifier - {@linkcode PokemonHeldItemModifier} to transfer (represents whole stack) * @param itemModifier {@linkcode PokemonHeldItemModifier} item to transfer (represents the whole stack)
* @param target - Recipient {@linkcode Pokemon} recieving items * @param target {@linkcode Pokemon} recepient in this transfer
* @param playSound - Whether to play a sound when transferring the item * @param playSound `true` to play a sound when transferring the item
* @param transferQuantity - How many items of the stack to transfer. Optional, default `1` * @param transferQuantity How many items of the stack to transfer. Optional, defaults to `1`
* @param itemLost - Whether to treat the item's current holder as losing the item (for now, this simply enables Unburden). Default: `true`. * @param instant ??? (Optional)
* @returns Whether the transfer was successful * @param ignoreUpdate ??? (Optional)
* @param itemLost If `true`, treat the item's current holder as losing the item (for now, this simply enables Unburden). Default is `true`.
* @returns `true` if the transfer was successful
*/ */
tryTransferHeldItemModifier( tryTransferHeldItemModifier(
itemModifier: PokemonHeldItemModifier, itemModifier: PokemonHeldItemModifier,
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.pokemonId ? itemModifier.getPokemon() : null;
// Check if source even exists and error if not.
// Almost certainly redundant due to checking inside condition, but better log twice than not at all
if (isNullOrUndefined(source)) {
console.error(
`Pokemon ${target.getNameToRender()} tried to transfer %d items from nonexistent source; item: `,
transferQuantity,
itemModifier,
);
return false;
}
// Check for effects that might block us from stealing
const cancelled = new BooleanHolder(false); const cancelled = new BooleanHolder(false);
if (source.isPlayer() !== target.isPlayer()) {
if (source && source.isPlayer() !== target.isPlayer()) {
applyAbAttrs(BlockItemTheftAbAttr, source, cancelled); applyAbAttrs(BlockItemTheftAbAttr, source, cancelled);
} }
if (cancelled.value) { if (cancelled.value) {
return false; return false;
} }
// check if we have an item already and calc how much to transfer const newItemModifier = itemModifier.clone() as PokemonHeldItemModifier;
newItemModifier.pokemonId = target.id;
const matchingModifier = this.findModifier( const matchingModifier = this.findModifier(
(m): m is PokemonHeldItemModifier => m => m instanceof PokemonHeldItemModifier && m.matchType(itemModifier) && m.pokemonId === target.id,
m instanceof PokemonHeldItemModifier && m.matchType(itemModifier) && m.pokemonId === target.id,
target.isPlayer(), target.isPlayer(),
); ) as PokemonHeldItemModifier;
if (matchingModifier) {
const maxStackCount = matchingModifier.getMaxStackCount();
if (matchingModifier.stackCount >= maxStackCount) {
return false;
}
const countTaken = Math.min( const countTaken = Math.min(
transferQuantity, transferQuantity,
itemModifier.stackCount, itemModifier.stackCount,
matchingModifier?.getCountUnderMax() ?? Number.MAX_SAFE_INTEGER, maxStackCount - matchingModifier.stackCount,
); );
if (countTaken <= 0) {
// Can't transfer negative items
return false;
}
itemModifier.stackCount -= countTaken; itemModifier.stackCount -= countTaken;
newItemModifier.stackCount = matchingModifier.stackCount + countTaken;
// If the old modifier is at 0 stacks, try to remove it
if (itemModifier.stackCount <= 0 && !this.removeModifier(itemModifier, !source.isPlayer())) {
return false;
}
// TODO: what does this do and why is it here
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
if (matchingModifier) {
matchingModifier.stackCount += countTaken;
} else { } else {
const newItemModifier = itemModifier.clone() as PokemonHeldItemModifier; const countTaken = Math.min(transferQuantity, itemModifier.stackCount);
newItemModifier.pokemonId = target.id; itemModifier.stackCount -= countTaken;
newItemModifier.stackCount = countTaken; newItemModifier.stackCount = countTaken;
if (target.isPlayer()) {
this.addModifier(newItemModifier, false, playSound);
} else {
this.addEnemyModifier(newItemModifier);
}
} }
if (itemLost) { const removeOld = itemModifier.stackCount === 0;
if (!removeOld || !source || this.removeModifier(itemModifier, source.isEnemy())) {
const addModifier = () => {
if (!matchingModifier || this.removeModifier(matchingModifier, target.isEnemy())) {
if (target.isPlayer()) {
this.addModifier(newItemModifier, ignoreUpdate, playSound, false, instant);
if (source && itemLost) {
applyPostItemLostAbAttrs(PostItemLostAbAttr, source, false); applyPostItemLostAbAttrs(PostItemLostAbAttr, source, false);
} }
return true; return true;
} }
this.addEnemyModifier(newItemModifier, ignoreUpdate, instant);
if (source && itemLost) {
applyPostItemLostAbAttrs(PostItemLostAbAttr, source, false);
}
return true;
}
return false;
};
if (source && source.isPlayer() !== target.isPlayer() && !ignoreUpdate) {
this.updateModifiers(source.isPlayer(), instant);
addModifier();
} else {
addModifier();
}
return true;
}
return false;
}
canTransferHeldItemModifier(itemModifier: PokemonHeldItemModifier, target: Pokemon, transferQuantity = 1): boolean { canTransferHeldItemModifier(itemModifier: PokemonHeldItemModifier, target: Pokemon, transferQuantity = 1): boolean {
const source = itemModifier.getPokemon(); const mod = itemModifier.clone() as PokemonHeldItemModifier;
if (isNullOrUndefined(source)) { const source = mod.pokemonId ? mod.getPokemon() : null;
console.error(
`Pokemon ${target.getNameToRender()} tried to transfer %d items from nonexistent source; item: `,
transferQuantity,
itemModifier,
);
return false;
}
// If we somehow lack the item being transferred, skip
if (!this.hasModifier(itemModifier, !source.isPlayer())) {
return false;
}
// Check enemy theft prevention
// TODO: Verify whether sticky hold procs on friendly fire ally theft
if (source.isPlayer() !== target.isPlayer()) {
const cancelled = new BooleanHolder(false); const cancelled = new BooleanHolder(false);
if (source && source.isPlayer() !== target.isPlayer()) {
applyAbAttrs(BlockItemTheftAbAttr, source, cancelled); applyAbAttrs(BlockItemTheftAbAttr, source, cancelled);
}
if (cancelled.value) { if (cancelled.value) {
return false; return false;
} }
const matchingModifier = this.findModifier(
m => m instanceof PokemonHeldItemModifier && m.matchType(mod) && m.pokemonId === target.id,
target.isPlayer(),
) as PokemonHeldItemModifier;
if (matchingModifier) {
const maxStackCount = matchingModifier.getMaxStackCount();
if (matchingModifier.stackCount >= maxStackCount) {
return false;
}
const countTaken = Math.min(transferQuantity, mod.stackCount, maxStackCount - matchingModifier.stackCount);
mod.stackCount -= countTaken;
} else {
const countTaken = Math.min(transferQuantity, mod.stackCount);
mod.stackCount -= countTaken;
} }
// Finally, ensure we can actually steal at least 1 item const removeOld = mod.stackCount === 0;
const matchingModifier = this.findModifier(
(m): m is PokemonHeldItemModifier => return !removeOld || !source || this.hasModifier(itemModifier, !source.isPlayer());
m instanceof PokemonHeldItemModifier && m.matchType(itemModifier) && m.pokemonId === target.id,
target.isPlayer(),
);
const countTaken = Math.min(
transferQuantity,
itemModifier.stackCount,
matchingModifier?.getCountUnderMax() ?? Number.MAX_SAFE_INTEGER,
);
return countTaken > 0;
} }
removePartyMemberModifiers(partyMemberIndex: number): Promise<void> { removePartyMemberModifiers(partyMemberIndex: number): Promise<void> {
@ -2971,10 +2967,8 @@ 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
* @param instant - Whether to instantly update any changes to party members' HP bars; default `false` updateModifiers(player = true, instant?: boolean): void {
*/
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];
@ -2991,7 +2985,6 @@ export default class BattleScene extends SceneBase {
} }
} }
// Why do we silently delete missing modifiers?
const modifiersClone = modifiers.slice(0); const modifiersClone = modifiers.slice(0);
for (const modifier of modifiersClone) { for (const modifier of modifiersClone) {
if (!modifier.getStackCount()) { if (!modifier.getStackCount()) {
@ -3006,13 +2999,7 @@ 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 => {
@ -3023,32 +3010,23 @@ export default class BattleScene extends SceneBase {
}); });
} }
/**
* Check whether a given {@linkcode PersistentModifier} exists on a given side of the field.
* @param modifier - The {@linkcode PersistentModifier} to check the existence of.
* @param enemy - Whether to check the enemy (`true`) or player (`false`) party. Default is `false`.
* @returns Whether the specified modifier exists on the given side of the field.
* @remarks This also compares `pokemonId`s to confirm a match (and therefore owners).
*/
hasModifier(modifier: PersistentModifier, enemy = false): boolean { hasModifier(modifier: PersistentModifier, enemy = false): boolean {
return (!enemy ? this.modifiers : this.enemyModifiers).includes(modifier); const modifiers = !enemy ? this.modifiers : this.enemyModifiers;
return modifiers.indexOf(modifier) > -1;
} }
/** /**
* Remove a currently owned item. If the item is stacked, the entire item stack * Removes a currently owned item. If the item is stacked, the entire item stack
* gets removed. This function does NOT apply in-battle effects, such as Unburden. * gets removed. This function does NOT apply in-battle effects, such as Unburden.
* If in-battle effects are needed, use {@linkcode Pokemon.loseHeldItem} instead. * If in-battle effects are needed, use {@linkcode Pokemon.loseHeldItem} instead.
* @param modifier - The item to be removed. * @param modifier The item to be removed.
* @param enemy - Whether to remove from the enemy (`true`) or player (`false`) party; default `false`. * @param enemy `true` to remove an item owned by the enemy rather than the player; default `false`.
* @returns Whether the item exists and was successfully removed * @returns `true` if the item exists and was successfully removed, `false` otherwise
*/ */
removeModifier(modifier: PersistentModifier, enemy = false): boolean { removeModifier(modifier: PersistentModifier, enemy = false): boolean {
const modifiers = !enemy ? this.modifiers : this.enemyModifiers; const modifiers = !enemy ? this.modifiers : this.enemyModifiers;
const modifierIndex = modifiers.indexOf(modifier); const modifierIndex = modifiers.indexOf(modifier);
if (modifierIndex === -1) { if (modifierIndex > -1) {
return false;
}
modifiers.splice(modifierIndex, 1); modifiers.splice(modifierIndex, 1);
if (modifier instanceof PokemonFormChangeItemModifier) { if (modifier instanceof PokemonFormChangeItemModifier) {
const pokemon = this.getPokemonById(modifier.pokemonId); const pokemon = this.getPokemonById(modifier.pokemonId);
@ -3059,35 +3037,17 @@ export default class BattleScene extends SceneBase {
return true; return true;
} }
/** return false;
* Get all modifiers of all {@linkcode Pokemon} in the given party,
* optionally filtering based on `modifierType` if provided.
* @param player Whether to search the player (`true`) or enemy (`false`) party; Defaults to `true`
* @returns An array containing all {@linkcode PersistentModifier}s on the given side of the field.
* @overload
*/
getModifiers(player?: boolean): PersistentModifier[];
/**
* Get all modifiers of all {@linkcode Pokemon} in the given party,
* optionally filtering based on `modifierType` if provided.
* @param modifierType The type of modifier to check against; must extend {@linkcode PersistentModifier}.
* If omitted, will return all {@linkcode PersistentModifier}s regardless of type.
* @param player Whether to search the player (`true`) or enemy (`false`) party; Defaults to `true`
* @returns An array containing all modifiers matching `modifierType` on the given side of the field.
* @overload
*/
getModifiers<T extends PersistentModifier>(modifierType: Constructor<T>, player?: boolean): T[];
// NOTE: Boolean typing on 1st parameter needed to satisfy "bool only" overload
getModifiers<T extends PersistentModifier>(modifierType?: Constructor<T> | boolean, player?: boolean) {
const usePlayer: boolean = player ?? (typeof modifierType !== "boolean" || modifierType); // non-bool in 1st position = true by default
const mods = usePlayer ? this.modifiers : this.enemyModifiers;
if (typeof modifierType === "undefined" || typeof modifierType === "boolean") {
return mods;
} }
return mods.filter((m): m is T => m instanceof modifierType);
/**
* Get all of the modifiers that match `modifierType`
* @param modifierType The type of modifier to apply; must extend {@linkcode PersistentModifier}
* @param player Whether to search the player (`true`) or the enemy (`false`); Defaults to `true`
* @returns the list of all modifiers that matched `modifierType`.
*/
getModifiers<T extends PersistentModifier>(modifierType: Constructor<T>, player = true): T[] {
return (player ? this.modifiers : this.enemyModifiers).filter((m): m is T => m instanceof modifierType);
} }
/** /**

View File

@ -176,12 +176,18 @@ export default class Battle {
} }
addPostBattleLoot(enemyPokemon: EnemyPokemon): void { addPostBattleLoot(enemyPokemon: EnemyPokemon): void {
// Push used instead of concat to avoid extra allocation
this.postBattleLoot.push( this.postBattleLoot.push(
...(globalScene.findModifiers( ...globalScene
.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

@ -2539,17 +2539,11 @@ export class AllyStatMultiplierAbAttr extends AbAttr {
* @extends AbAttr * @extends AbAttr
*/ */
export class ExecutedMoveAbAttr extends AbAttr { export class ExecutedMoveAbAttr extends AbAttr {
canApplyExecutedMove( canApplyExecutedMove(_pokemon: Pokemon, _simulated: boolean): boolean {
_pokemon: Pokemon,
_simulated: boolean,
): boolean {
return true; return true;
} }
applyExecutedMove( applyExecutedMove(_pokemon: Pokemon, _simulated: boolean): void {}
_pokemon: Pokemon,
_simulated: boolean,
): void {}
} }
/** /**
@ -2557,7 +2551,7 @@ export class ExecutedMoveAbAttr extends AbAttr {
* @extends ExecutedMoveAbAttr * @extends ExecutedMoveAbAttr
*/ */
export class GorillaTacticsAbAttr extends ExecutedMoveAbAttr { export class GorillaTacticsAbAttr extends ExecutedMoveAbAttr {
constructor(showAbility: boolean = false) { constructor(showAbility = false) {
super(showAbility); super(showAbility);
} }
@ -2574,7 +2568,7 @@ export class GorillaTacticsAbAttr extends ExecutedMoveAbAttr {
export class PostAttackStealHeldItemAbAttr extends PostAttackAbAttr { export class PostAttackStealHeldItemAbAttr extends PostAttackAbAttr {
private stealCondition: PokemonAttackCondition | null; private stealCondition: PokemonAttackCondition | null;
private stolenItem: PokemonHeldItemModifier; private stolenItem?: PokemonHeldItemModifier;
constructor(stealCondition?: PokemonAttackCondition) { constructor(stealCondition?: PokemonAttackCondition) {
super(); super();
@ -2591,35 +2585,38 @@ export class PostAttackStealHeldItemAbAttr extends PostAttackAbAttr {
hitResult: HitResult, hitResult: HitResult,
args: any[], args: any[],
): boolean { ): boolean {
// Check which items to steal
const heldItems = this.getTargetHeldItems(defender).filter((i) => i.isTransferable);
if ( if (
!super.canApplyPostAttack(pokemon, passive, simulated, defender, move, hitResult, args) || super.canApplyPostAttack(pokemon, passive, simulated, defender, move, hitResult, args) &&
heldItems.length === 0 || // no items to steal !simulated &&
hitResult >= HitResult.NO_EFFECT || // move was ineffective/protected against hitResult < HitResult.NO_EFFECT &&
(this.stealCondition && !this.stealCondition(pokemon, defender, move)) // no condition = pass (!this.stealCondition || this.stealCondition(pokemon, defender, move))
) { ) {
return false; const heldItems = this.getTargetHeldItems(defender).filter(i => i.isTransferable);
} if (heldItems.length) {
// Ensure that the stolen item in testing is the same as when the effect is applied
// pick random item and check if we can steal it
this.stolenItem = heldItems[pokemon.randBattleSeedInt(heldItems.length)]; this.stolenItem = heldItems[pokemon.randBattleSeedInt(heldItems.length)];
return globalScene.canTransferHeldItemModifier(this.stolenItem, pokemon) if (globalScene.canTransferHeldItemModifier(this.stolenItem, pokemon)) {
return true;
}
}
}
this.stolenItem = undefined;
return false;
} }
override applyPostAttack( override applyPostAttack(
pokemon: Pokemon, pokemon: Pokemon,
_passive: boolean, _passive: boolean,
simulated: boolean, _simulated: boolean,
defender: Pokemon, defender: Pokemon,
_move: Move, _move: Move,
_hitResult: HitResult, _hitResult: HitResult,
_args: any[], _args: any[],
): void { ): void {
if (simulated) { const heldItems = this.getTargetHeldItems(defender).filter(i => i.isTransferable);
return; if (!this.stolenItem) {
this.stolenItem = heldItems[pokemon.randBattleSeedInt(heldItems.length)];
} }
if (globalScene.tryTransferHeldItemModifier(this.stolenItem, pokemon, false)) { if (globalScene.tryTransferHeldItemModifier(this.stolenItem, pokemon, false)) {
globalScene.phaseManager.queueMessage( globalScene.phaseManager.queueMessage(
i18next.t("abilityTriggers:postAttackStealHeldItem", { i18next.t("abilityTriggers:postAttackStealHeldItem", {
@ -2629,6 +2626,7 @@ export class PostAttackStealHeldItemAbAttr extends PostAttackAbAttr {
}), }),
); );
} }
this.stolenItem = undefined;
} }
getTargetHeldItems(target: Pokemon): PokemonHeldItemModifier[] { getTargetHeldItems(target: Pokemon): PokemonHeldItemModifier[] {
@ -6217,45 +6215,36 @@ export class PostBattleAbAttr extends AbAttr {
} }
export class PostBattleLootAbAttr extends PostBattleAbAttr { export class PostBattleLootAbAttr extends PostBattleAbAttr {
/** The index of the random item to steal. */ private randItem?: PokemonHeldItemModifier;
private randItemIndex = 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 canApplyPostBattle(pokemon: Pokemon, _passive: boolean, simulated: boolean, args: [boolean]): boolean { override applyPostBattle(pokemon: Pokemon, _passive: boolean, _simulated: boolean, _args: any[]): void {
const postBattleLoot = globalScene.currentBattle.postBattleLoot; const postBattleLoot = globalScene.currentBattle.postBattleLoot;
const wasVictory = args[0]; if (!this.randItem) {
if (simulated || postBattleLoot.length === 0 || !wasVictory) { this.randItem = randSeedItem(postBattleLoot);
return false;
} }
// Pick a random item and check if we are capped. if (globalScene.tryTransferHeldItemModifier(this.randItem, pokemon, true, 1, true, undefined, false)) {
this.randItemIndex = randSeedInt(postBattleLoot.length); postBattleLoot.splice(postBattleLoot.indexOf(this.randItem), 1);
const item = postBattleLoot[this.randItemIndex] globalScene.phaseManager.queueMessage(
i18next.t("abilityTriggers:postBattleLoot", {
// We can't use `canTransferItemModifier` as that assumes the Pokemon in question already exists (which it does not) pokemonNameWithAffix: getPokemonNameWithAffix(pokemon),
const existingItem = globalScene.findModifier( itemName: this.randItem.type.name,
(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.
*/
override applyPostBattle(pokemon: Pokemon): 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.phaseManager.queueMessage(i18next.t("abilityTriggers:postBattleLoot", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), itemName: item.type.name }));
} }
this.randItem = undefined;
} }
} }
@ -7790,7 +7779,7 @@ export function applyPreAttackAbAttrs(
export function applyExecutedMoveAbAttrs( export function applyExecutedMoveAbAttrs(
attrType: Constructor<ExecutedMoveAbAttr>, attrType: Constructor<ExecutedMoveAbAttr>,
pokemon: Pokemon, pokemon: Pokemon,
simulated: boolean = false, simulated = false,
...args: any[] ...args: any[]
): void { ): void {
applyAbAttrsInternal<ExecutedMoveAbAttr>( applyAbAttrsInternal<ExecutedMoveAbAttr>(
@ -8401,8 +8390,7 @@ export function initAbilities() {
new Ability(AbilityId.STICKY_HOLD, 3) new Ability(AbilityId.STICKY_HOLD, 3)
.attr(BlockItemTheftAbAttr) .attr(BlockItemTheftAbAttr)
.bypassFaint() .bypassFaint()
.ignorable() .ignorable(),
.edgeCase(), // may or may not proc incorrectly on user's allies
new Ability(AbilityId.SHED_SKIN, 3) new Ability(AbilityId.SHED_SKIN, 3)
.conditionalAttr(_pokemon => !randSeedInt(3), PostTurnResetStatusAbAttr), .conditionalAttr(_pokemon => !randSeedInt(3), PostTurnResetStatusAbAttr),
new Ability(AbilityId.GUTS, 3) new Ability(AbilityId.GUTS, 3)

View File

@ -5131,13 +5131,6 @@ export default abstract class Pokemon extends Phaser.GameObjects.Container {
} }
}); });
globalScene.phaseManager.queueMessage(
i18next.t("battleInfo:newKey2", {
// arguments for the locale key go here;
pokemonNameWithAffix: getPokemonNameWithAffix(this),
}),
);
for (let f = 0; f < 2; f++) { for (let f = 0; f < 2; f++) {
const variantColors = variantColorCache[!f ? spriteKey : backSpriteKey]; const variantColors = variantColorCache[!f ? spriteKey : backSpriteKey];
const variantColorSet = new Map<number, number[]>(); const variantColorSet = new Map<number, number[]>();
@ -6006,8 +5999,9 @@ 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(), false); globalScene.tryTransferHeldItemModifier(modifier, this, false, modifier.getStackCount(), true, true, 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

@ -159,7 +159,15 @@ export class SwitchSummonPhase extends SummonPhase {
) as SwitchEffectTransferModifier; ) as SwitchEffectTransferModifier;
if (batonPassModifier) { if (batonPassModifier) {
globalScene.tryTransferHeldItemModifier(batonPassModifier, switchedInPokemon, false, 1, false); globalScene.tryTransferHeldItemModifier(
batonPassModifier,
switchedInPokemon,
false,
undefined,
undefined,
undefined,
false,
);
} }
} }
} }

View File

@ -538,14 +538,9 @@ export default abstract class BattleInfo extends Phaser.GameObjects.Container {
this.updateHpFrame(); this.updateHpFrame();
} }
/** /** Update the pokemonHp bar */
* Update a Pokemon's HP bar. protected updatePokemonHp(pokemon: Pokemon, resolve: (r: void | PromiseLike<void>) => void, instant?: boolean): void {
* @param pokemon - The {@linkcode Pokemon} to whom the HP bar belongs. let duration = !instant ? Phaser.Math.Clamp(Math.abs(this.lastHp - pokemon.hp) * 5, 250, 5000) : 0;
* @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);
@ -568,13 +563,7 @@ 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) {