diff --git a/src/battle-scene.ts b/src/battle-scene.ts index 0171fb96c..1741379cf 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -1685,7 +1685,7 @@ export default class BattleScene extends SceneBase { }); } - tryTransferHeldItemModifier(itemModifier: PokemonHeldItemModifier, target: Pokemon, transferStack: boolean, playSound: boolean, instant?: boolean, ignoreUpdate?: boolean): Promise { + tryTransferHeldItemModifier(itemModifier: PokemonHeldItemModifier, target: Pokemon, playSound: boolean, transferQuantity: integer = 1, instant?: boolean, ignoreUpdate?: boolean): Promise { return new Promise(resolve => { const source = itemModifier.pokemonId ? itemModifier.getPokemon(target.scene) : null; const cancelled = new Utils.BooleanHolder(false); @@ -1701,14 +1701,15 @@ export default class BattleScene extends SceneBase { const maxStackCount = matchingModifier.getMaxStackCount(target.scene); if (matchingModifier.stackCount >= maxStackCount) return resolve(false); - const countTaken = transferStack ? Math.min(itemModifier.stackCount, maxStackCount - matchingModifier.stackCount) : 1; + const countTaken = Math.min(transferQuantity, itemModifier.stackCount, maxStackCount - matchingModifier.stackCount); itemModifier.stackCount -= countTaken; newItemModifier.stackCount = matchingModifier.stackCount + countTaken; - removeOld = !itemModifier.stackCount; - } else if (!transferStack) { - newItemModifier.stackCount = 1; - removeOld = !(--itemModifier.stackCount); + } else { + const countTaken = Math.min(transferQuantity, itemModifier.stackCount); + itemModifier.stackCount -= countTaken; + newItemModifier.stackCount = countTaken; } + removeOld = !itemModifier.stackCount; if (!removeOld || !source || this.removeModifier(itemModifier, !source.isPlayer())) { const addModifier = () => { if (!matchingModifier || this.removeModifier(matchingModifier, !target.isPlayer())) { diff --git a/src/data/ability.ts b/src/data/ability.ts index 8a244b85b..f89eb51b3 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -1104,7 +1104,7 @@ export class PostAttackStealHeldItemAbAttr extends PostAttackAbAttr { const heldItems = this.getTargetHeldItems(defender).filter(i => i.getTransferrable(false)); if (heldItems.length) { const stolenItem = heldItems[pokemon.randSeedInt(heldItems.length)]; - pokemon.scene.tryTransferHeldItemModifier(stolenItem, pokemon, false, false).then(success => { + pokemon.scene.tryTransferHeldItemModifier(stolenItem, pokemon, false).then(success => { if (success) pokemon.scene.queueMessage(getPokemonMessage(pokemon, ` stole\n${defender.name}'s ${stolenItem.type.name}!`)); resolve(success); @@ -1192,7 +1192,7 @@ export class PostDefendStealHeldItemAbAttr extends PostDefendAbAttr { const heldItems = this.getTargetHeldItems(attacker).filter(i => i.getTransferrable(false)); if (heldItems.length) { const stolenItem = heldItems[pokemon.randSeedInt(heldItems.length)]; - pokemon.scene.tryTransferHeldItemModifier(stolenItem, pokemon, false, false).then(success => { + pokemon.scene.tryTransferHeldItemModifier(stolenItem, pokemon, false).then(success => { if (success) pokemon.scene.queueMessage(getPokemonMessage(pokemon, ` stole\n${attacker.name}'s ${stolenItem.type.name}!`)); resolve(success); @@ -2298,7 +2298,7 @@ export class PostBattleLootAbAttr extends PostBattleAbAttr { const postBattleLoot = pokemon.scene.currentBattle.postBattleLoot; if (postBattleLoot.length) { const randItem = Utils.randSeedItem(postBattleLoot); - if (pokemon.scene.tryTransferHeldItemModifier(randItem, pokemon, false, true, true)) { + if (pokemon.scene.tryTransferHeldItemModifier(randItem, pokemon, true, 1, true)) { postBattleLoot.splice(postBattleLoot.indexOf(randItem), 1); pokemon.scene.queueMessage(getPokemonMessage(pokemon, ` picked up\n${randItem.type.name}!`)); return true; diff --git a/src/data/move.ts b/src/data/move.ts index 978f51091..7882cdc28 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -1197,7 +1197,7 @@ export class StealHeldItemChanceAttr extends MoveEffectAttr { const highestItemTier = heldItems.map(m => m.type.getOrInferTier(poolType)).reduce((highestTier, tier) => Math.max(tier, highestTier), 0); const tierHeldItems = heldItems.filter(m => m.type.getOrInferTier(poolType) === highestItemTier); const stolenItem = tierHeldItems[user.randSeedInt(tierHeldItems.length)]; - user.scene.tryTransferHeldItemModifier(stolenItem, user, false, false).then(success => { + user.scene.tryTransferHeldItemModifier(stolenItem, user, false).then(success => { if (success) user.scene.queueMessage(getPokemonMessage(user, ` stole\n${target.name}'s ${stolenItem.type.name}!`)); resolve(success); @@ -1244,7 +1244,7 @@ export class RemoveHeldItemAttr extends MoveEffectAttr { const highestItemTier = heldItems.map(m => m.type.getOrInferTier(poolType)).reduce((highestTier, tier) => Math.max(tier, highestTier), 0); const tierHeldItems = heldItems.filter(m => m.type.getOrInferTier(poolType) === highestItemTier); const stolenItem = tierHeldItems[user.randSeedInt(tierHeldItems.length)]; - user.scene.tryTransferHeldItemModifier(stolenItem, user, false, false).then(success => { + user.scene.tryTransferHeldItemModifier(stolenItem, user, false).then(success => { if (success) user.scene.queueMessage(getPokemonMessage(user, ` knocked off\n${target.name}'s ${stolenItem.type.name}!`)); resolve(success); diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 8afff1b27..1cb558799 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -2652,7 +2652,7 @@ export class PlayerPokemon extends Pokemon { && (m as PokemonHeldItemModifier).pokemonId === pokemon.id, true) as PokemonHeldItemModifier[]; const transferModifiers: Promise[] = []; for (let modifier of fusedPartyMemberHeldModifiers) - transferModifiers.push(this.scene.tryTransferHeldItemModifier(modifier, this, true, false, true, true)); + transferModifiers.push(this.scene.tryTransferHeldItemModifier(modifier, this, false, modifier.getStackCount(), true, true)); Promise.allSettled(transferModifiers).then(() => { this.scene.updateModifiers(true, true).then(() => { this.scene.removePartyMemberModifiers(fusedPartyMemberIndex); diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index ba009cb7a..11fae6d3b 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -1791,7 +1791,7 @@ export abstract class HeldItemTransferModifier extends PokemonHeldItemModifier { } const randItemIndex = pokemon.randSeedInt(itemModifiers.length); const randItem = itemModifiers[randItemIndex]; - heldItemTransferPromises.push(pokemon.scene.tryTransferHeldItemModifier(randItem, pokemon, false, false).then(success => { + heldItemTransferPromises.push(pokemon.scene.tryTransferHeldItemModifier(randItem, pokemon, false).then(success => { if (success) { transferredModifierTypes.push(randItem.type); itemModifiers.splice(randItemIndex, 1); diff --git a/src/phases.ts b/src/phases.ts index 828261965..8b13a3dbb 100644 --- a/src/phases.ts +++ b/src/phases.ts @@ -1407,7 +1407,7 @@ export class SwitchSummonPhase extends SummonPhase { const batonPassModifier = this.scene.findModifier(m => m instanceof SwitchEffectTransferModifier && (m as SwitchEffectTransferModifier).pokemonId === this.lastPokemon.id) as SwitchEffectTransferModifier; if (batonPassModifier && !this.scene.findModifier(m => m instanceof SwitchEffectTransferModifier && (m as SwitchEffectTransferModifier).pokemonId === switchedPokemon.id)) - this.scene.tryTransferHeldItemModifier(batonPassModifier, switchedPokemon, false, false); + this.scene.tryTransferHeldItemModifier(batonPassModifier, switchedPokemon, false); } } if (switchedPokemon) { @@ -4392,12 +4392,12 @@ export class SelectModifierPhase extends BattlePhase { this.scene.playSound('buy'); } } else if (cursor === 1) { - this.scene.ui.setModeWithoutClear(Mode.PARTY, PartyUiMode.MODIFIER_TRANSFER, -1, (fromSlotIndex: integer, itemIndex: integer, toSlotIndex: integer) => { + this.scene.ui.setModeWithoutClear(Mode.PARTY, PartyUiMode.MODIFIER_TRANSFER, -1, (fromSlotIndex: integer, itemIndex: integer, itemQuantity: integer, toSlotIndex: integer) => { if (toSlotIndex !== undefined && fromSlotIndex < 6 && toSlotIndex < 6 && fromSlotIndex !== toSlotIndex && itemIndex > -1) { const itemModifiers = this.scene.findModifiers(m => m instanceof PokemonHeldItemModifier && (m as PokemonHeldItemModifier).getTransferrable(true) && (m as PokemonHeldItemModifier).pokemonId === party[fromSlotIndex].id) as PokemonHeldItemModifier[]; const itemModifier = itemModifiers[itemIndex]; - this.scene.tryTransferHeldItemModifier(itemModifier, party[toSlotIndex], true, true); + this.scene.tryTransferHeldItemModifier(itemModifier, party[toSlotIndex], true, itemQuantity); } else this.scene.ui.setMode(Mode.MODIFIER_SELECT, this.isPlayer(), typeOptions, modifierSelectCallback, this.getRerollCost(typeOptions, this.scene.lockModifierTiers)); }, PartyUiHandler.FilterItemMaxStacks); diff --git a/src/ui/party-ui-handler.ts b/src/ui/party-ui-handler.ts index 8b497655a..fb305f606 100644 --- a/src/ui/party-ui-handler.ts +++ b/src/ui/party-ui-handler.ts @@ -29,6 +29,7 @@ export enum PartyUiMode { TM_MODIFIER, REMEMBER_MOVE_MODIFIER, MODIFIER_TRANSFER, + MODIFIER_TRANSFER_QUANTITY, SPLICE, RELEASE } @@ -40,6 +41,7 @@ export enum PartyOption { APPLY, TEACH, TRANSFER, + TRANSFER_QUANTITY, SUMMARY, UNPAUSE_EVOLUTION, SPLICE, @@ -55,7 +57,7 @@ export enum PartyOption { } export type PartySelectCallback = (cursor: integer, option: PartyOption) => void; -export type PartyModifierTransferSelectCallback = (fromCursor: integer, index: integer, toCursor?: integer) => void; +export type PartyModifierTransferSelectCallback = (fromCursor: integer, index: integer, itemQuantity?: integer, toCursor?: integer) => void; export type PartyModifierSpliceSelectCallback = (fromCursor: integer, toCursor?: integer) => void; export type PokemonSelectFilter = (pokemon: PlayerPokemon) => string; export type PokemonModifierTransferSelectFilter = (pokemon: PlayerPokemon, modifier: PokemonHeldItemModifier) => string; @@ -85,6 +87,8 @@ export default class PartyUiHandler extends MessageUiHandler { private transferMode: boolean; private transferOptionCursor: integer; private transferCursor: integer; + private transferQuantity: integer; + private transferQuantityMax: integer; private lastCursor: integer = 0; private selectCallback: PartySelectCallback | PartyModifierTransferSelectCallback; @@ -222,11 +226,35 @@ export default class PartyUiHandler extends MessageUiHandler { const option = this.options[this.optionsCursor]; const pokemon = this.scene.getParty()[this.cursor]; if (this.partyUiMode === PartyUiMode.MODIFIER_TRANSFER && !this.transferMode && option !== PartyOption.CANCEL) { + const pokemon = this.scene.getParty()[this.cursor]; + const itemModifiers = this.scene.findModifiers(m => m instanceof PokemonHeldItemModifier + && (m as PokemonHeldItemModifier).getTransferrable(true) && (m as PokemonHeldItemModifier).pokemonId === pokemon.id) as PokemonHeldItemModifier[]; + this.transferQuantityMax = itemModifiers[this.getOptionsCursorWithScroll()].stackCount + this.transferQuantity = this.transferQuantityMax + this.transferOptionCursor = this.getOptionsCursorWithScroll(); + + if (this.transferQuantityMax > 1) { + this.partyUiMode = PartyUiMode.MODIFIER_TRANSFER_QUANTITY; + this.showOptions(); + this.eraseOptionsCursor(); + ui.playSelect(); + return true; + } else { + this.transferOptionCursor = this.getOptionsCursorWithScroll(); + this.startTransfer(); + this.clearOptions(); + ui.playSelect(); + return true; + } + + } else if (this.partyUiMode === PartyUiMode.MODIFIER_TRANSFER_QUANTITY && option !== PartyOption.CANCEL) { + this.partyUiMode = PartyUiMode.MODIFIER_TRANSFER this.startTransfer(); this.clearOptions(); ui.playSelect(); return true; - } else if (this.partyUiMode === PartyUiMode.REMEMBER_MOVE_MODIFIER && option !== PartyOption.CANCEL) { + } + else if (this.partyUiMode === PartyUiMode.REMEMBER_MOVE_MODIFIER && option !== PartyOption.CANCEL) { let filterResult = (this.selectFilter as PokemonSelectFilter)(pokemon); if (filterResult === null) { this.selectCallback(this.cursor, option); @@ -255,13 +283,16 @@ export default class PartyUiHandler extends MessageUiHandler { this.clearOptions(); if (this.selectCallback) { if (option === PartyOption.TRANSFER) { - (this.selectCallback as PartyModifierTransferSelectCallback)(this.transferCursor, this.transferOptionCursor, this.cursor); + if (this.transferCursor !== this.cursor) { + (this.selectCallback as PartyModifierTransferSelectCallback)(this.transferCursor, this.transferOptionCursor, this.transferQuantity, this.cursor); + } this.clearTransfer(); } else if (this.partyUiMode === PartyUiMode.SPLICE) { if (option === PartyOption.SPLICE) { (this.selectCallback as PartyModifierSpliceSelectCallback)(this.transferCursor, this.cursor); this.clearTransfer(); } else + this.transferOptionCursor = this.getOptionsCursorWithScroll(); this.startTransfer(); this.clearOptions(); } else if (option === PartyOption.RELEASE) @@ -343,9 +374,23 @@ export default class PartyUiHandler extends MessageUiHandler { } else if (option === PartyOption.CANCEL) return this.processInput(Button.CANCEL); } else if (button === Button.CANCEL) { + if (this.partyUiMode === PartyUiMode.MODIFIER_TRANSFER_QUANTITY) { + this.partyUiMode = PartyUiMode.MODIFIER_TRANSFER + } this.clearOptions(); ui.playSelect(); return true; + } else if (this.partyUiMode === PartyUiMode.MODIFIER_TRANSFER_QUANTITY) { + switch (button) { + case Button.LEFT: + this.transferQuantity = this.transferQuantity == 1 ? this.transferQuantityMax : this.transferQuantity - 1 + this.updateOptions() + break; + case Button.RIGHT: + this.transferQuantity = this.transferQuantity == this.transferQuantityMax ? 1 : this.transferQuantity + 1 + this.updateOptions() + break; + } } else { switch (button) { case Button.UP: @@ -525,6 +570,10 @@ export default class PartyUiHandler extends MessageUiHandler { if (!this.transferMode) optionsMessage = 'Select a held item to transfer.'; break; + case PartyUiMode.MODIFIER_TRANSFER_QUANTITY: + if (!this.transferMode) + optionsMessage = 'Select the quantity to transfer.'; + break; case PartyUiMode.SPLICE: if (!this.transferMode) optionsMessage = 'Select another Pokémon to splice.'; @@ -560,7 +609,7 @@ export default class PartyUiHandler extends MessageUiHandler { let formChangeItemModifiers: PokemonFormChangeItemModifier[]; - if (this.partyUiMode !== PartyUiMode.MOVE_MODIFIER && this.partyUiMode !== PartyUiMode.REMEMBER_MOVE_MODIFIER && (this.transferMode || this.partyUiMode !== PartyUiMode.MODIFIER_TRANSFER)) { + if (this.partyUiMode !== PartyUiMode.MOVE_MODIFIER && this.partyUiMode !== PartyUiMode.REMEMBER_MOVE_MODIFIER && this.partyUiMode !== PartyUiMode.MODIFIER_TRANSFER_QUANTITY && (this.transferMode || this.partyUiMode !== PartyUiMode.MODIFIER_TRANSFER)) { switch (this.partyUiMode) { case PartyUiMode.SWITCH: case PartyUiMode.FAINT_SWITCH: @@ -619,6 +668,8 @@ export default class PartyUiHandler extends MessageUiHandler { const learnableMoves = pokemon.getLearnableLevelMoves(); for (let m = 0; m < learnableMoves.length; m++) this.options.push(m); + } else if (this.partyUiMode === PartyUiMode.MODIFIER_TRANSFER_QUANTITY) { + this.options.push(PartyOption.TRANSFER_QUANTITY) } else { for (let im = 0; im < itemModifiers.length; im++) this.options.push(im); @@ -639,7 +690,9 @@ export default class PartyUiHandler extends MessageUiHandler { this.options.push(PartyOption.SCROLL_DOWN); } - this.options.push(PartyOption.CANCEL); + if (this.partyUiMode !== PartyUiMode.MODIFIER_TRANSFER_QUANTITY) { + this.options.push(PartyOption.CANCEL); + } this.optionsBg = addWindow(this.scene, 0, 0, 0, 16 * this.options.length + 13); this.optionsBg.setOrigin(1, 1); @@ -660,7 +713,7 @@ export default class PartyUiHandler extends MessageUiHandler { optionName = '↑'; else if (option === PartyOption.SCROLL_DOWN) optionName = '↓'; - else if ((this.partyUiMode !== PartyUiMode.REMEMBER_MOVE_MODIFIER && (this.partyUiMode !== PartyUiMode.MODIFIER_TRANSFER || this.transferMode)) || option === PartyOption.CANCEL) { + else if ((this.partyUiMode !== PartyUiMode.REMEMBER_MOVE_MODIFIER && this.partyUiMode !== PartyUiMode.MODIFIER_TRANSFER_QUANTITY && (this.partyUiMode !== PartyUiMode.MODIFIER_TRANSFER || this.transferMode)) || option === PartyOption.CANCEL) { switch (option) { case PartyOption.MOVE_1: case PartyOption.MOVE_2: @@ -687,6 +740,8 @@ export default class PartyUiHandler extends MessageUiHandler { const move = learnableLevelMoves[option]; optionName = allMoves[move].name; altText = !pokemon.getSpeciesForm().getLevelMoves().find(plm => plm[1] === move); + } else if (this.partyUiMode === PartyUiMode.MODIFIER_TRANSFER_QUANTITY) { + optionName = `< ${this.transferQuantity} >` } else { const itemModifier = itemModifiers[option]; optionName = itemModifier.type.name; @@ -717,7 +772,6 @@ export default class PartyUiHandler extends MessageUiHandler { startTransfer(): void { this.transferMode = true; this.transferCursor = this.cursor; - this.transferOptionCursor = this.getOptionsCursorWithScroll(); this.partySlots[this.transferCursor].setTransfer(true); }