From ae40d89c413f1b00e5a14927ad66b1164588ffed Mon Sep 17 00:00:00 2001 From: muscode13 Date: Sun, 27 Oct 2024 23:59:26 -0600 Subject: [PATCH] refactor unburden --- src/battle-scene.ts | 18 +++- src/data/ability.ts | 132 ++++++---------------------- src/data/berry.ts | 8 +- src/data/move.ts | 9 +- src/field/pokemon.ts | 1 - src/modifier/modifier.ts | 1 - src/test/abilities/unburden.test.ts | 2 +- 7 files changed, 57 insertions(+), 114 deletions(-) diff --git a/src/battle-scene.ts b/src/battle-scene.ts index 850d0baab5d..bb24c37f4b2 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -15,7 +15,7 @@ import { addTextObject, getTextColor, TextStyle } from "#app/ui/text"; import { allMoves } from "#app/data/move"; import { getDefaultModifierTypeForTier, getEnemyModifierTypesForWave, getLuckString, getLuckTextTint, getModifierPoolForType, getModifierType, getPartyLuckValue, ModifierPoolType, modifierTypes, PokemonHeldItemModifierType } from "#app/modifier/modifier-type"; import AbilityBar from "#app/ui/ability-bar"; -import { allAbilities, applyAbAttrs, applyPostBattleInitAbAttrs, BlockItemTheftAbAttr, DoubleBattleChanceAbAttr, PostBattleInitAbAttr } from "#app/data/ability"; +import { allAbilities, applyAbAttrs, applyPostBattleInitAbAttrs, applyPostItemLostAbAttrs, BlockItemTheftAbAttr, DoubleBattleChanceAbAttr, PostBattleInitAbAttr, PostItemLostAbAttr } from "#app/data/ability"; import Battle, { BattleType, FixedBattleConfig } from "#app/battle"; import { GameMode, GameModes, getGameMode } from "#app/game-mode"; import FieldSpritePipeline from "#app/pipelines/field-sprite"; @@ -2582,9 +2582,21 @@ export default class BattleScene extends SceneBase { const addModifier = () => { if (!matchingModifier || this.removeModifier(matchingModifier, !target.isPlayer())) { if (target.isPlayer()) { - this.addModifier(newItemModifier, ignoreUpdate, playSound, false, instant).then(() => resolve(true)); + this.addModifier(newItemModifier, ignoreUpdate, playSound, false, instant).then(() => { + if (source) { + console.log("Add Modifier, Player", source.name); + applyPostItemLostAbAttrs(PostItemLostAbAttr, source, source.hasPassive(), false, []); + } + resolve(true); + }); } else { - this.addEnemyModifier(newItemModifier, ignoreUpdate, instant).then(() => resolve(true)); + this.addEnemyModifier(newItemModifier, ignoreUpdate, instant).then(() => { + if (source) { + console.log("Add Modifier, ENEMY", source.name); + applyPostItemLostAbAttrs(PostItemLostAbAttr, source, source.hasPassive(), false, []); + } + resolve(true); + }); } } else { resolve(false); diff --git a/src/data/ability.ts b/src/data/ability.ts index 14f1eb2481b..771a7efc301 100644 --- a/src/data/ability.ts +++ b/src/data/ability.ts @@ -1663,7 +1663,6 @@ export class PostAttackStealHeldItemAbAttr extends PostAttackAbAttr { const stolenItem = heldItems[pokemon.randSeedInt(heldItems.length)]; pokemon.scene.tryTransferHeldItemModifier(stolenItem, pokemon, false).then(success => { if (success) { - defender.turnData.itemsLost += 1; pokemon.scene.queueMessage(i18next.t("abilityTriggers:postAttackStealHeldItem", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), defenderName: defender.name, stolenItemType: stolenItem.type.name })); } resolve(success); @@ -1757,7 +1756,6 @@ export class PostDefendStealHeldItemAbAttr extends PostDefendAbAttr { const stolenItem = heldItems[pokemon.randSeedInt(heldItems.length)]; pokemon.scene.tryTransferHeldItemModifier(stolenItem, pokemon, false).then(success => { if (success) { - attacker.turnData.itemsLost += 1; pokemon.scene.queueMessage(i18next.t("abilityTriggers:postDefendStealHeldItem", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), attackerName: attacker.name, stolenItemType: stolenItem.type.name })); } resolve(success); @@ -3809,114 +3807,39 @@ export class PostDancingMoveAbAttr extends PostMoveUsedAbAttr { } /** - * Ability attribute for Unburden, triggers when a Pokemon consumes a berry they are holding - * @extends PostTurnAbAttr - * @see {@linkcode applyPostTurn} - * @see {@linkcode getCondition} + * Triggers after the Pokemon loses or consumes an item + * @extends AbAttr */ -export class UnburdenBerryRemovedAbAttr extends PostTurnAbAttr { - - /** - * - * @param {Pokemon} pokemon the {@linkcode Pokemon} with this ability - * @param passive n/a - * @param simulated whether the ability is being simulated - * @param args n/a - * @returns `true` if the ability is applied - */ - applyPostTurn(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean { - if (simulated) { - return simulated; - } - - if (pokemon.getTag(BattlerTagType.UNBURDEN)) { - return false; - } - - pokemon.addTag(BattlerTagType.UNBURDEN); - return true; +export class PostItemLostAbAttr extends AbAttr { + applyPostItemLost(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean | Promise { + return false; } - - getCondition(): AbAttrCondition { - return (pokemon: Pokemon) => pokemon.battleData.berriesEaten.length !== 0; - } - } /** - * Ability attribute for Unburden, triggers upon an item being lost while defending (Knock Off, Thief, Pluck) - * @extends PostDefendAbAttr - * @see {@linkcode applyPostDefend} - * @see {@linkcode getCondition} + * Applies a Battler Tag to the Pokemon after it loses or consumes item + * @extends PostItemLostAbAttr */ -export class UnburdenDefendingItemRemovedAbAttr extends PostDefendAbAttr { - +export class PostItemLostApplyBattlerTagAbAttr extends PostItemLostAbAttr { + private tagType: BattlerTagType; + constructor(tagType: BattlerTagType) { + super(true); + this.tagType = tagType; + } /** - * - * @param {Pokemon} pokemon the {@linkcode Pokemon} with this ability - * @param passive n/a - * @param simulated whether the ability is being simulated - * @param attacker n/a - * @param move n/a - * @param hitResult n/a - * @param args n/a - * @returns `true` if the ability is applied + * Adds the last used Pokeball back into the player's inventory + * @param pokemon {@linkcode Pokemon} with this ability + * @param passive N/A + * @param args N/A + * @returns true if BattlerTag was applied */ - applyPostDefend(pokemon: Pokemon, passive: boolean, simulated: boolean, attacker: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { - if (simulated) { - return simulated; + applyPostItemLost(pokemon: Pokemon, passive: boolean, simulated: boolean, args: any[]): boolean | Promise { + if (!pokemon.getTag(this.tagType) && !simulated) { + pokemon.addTag(this.tagType); + return true; } - - if (pokemon.getTag(BattlerTagType.UNBURDEN)) { - return false; - } - - pokemon.addTag(BattlerTagType.UNBURDEN); - return true; + return false; } - - getCondition(): AbAttrCondition { - return (pokemon: Pokemon) => pokemon.turnData.itemsLost > 0; - } - -} - -/** - * Ability attribute for Unburden, triggers upon an item being lost while attacking (Pickpocket) - * @extends PostAttackAbAttr - * @see {@linkcode applyPostAttackAfterMoveTypeCheck} - * @see {@linkcode getCondition} - */ -export class UnburdenAttackingItemRemovedAbAttr extends PostAttackAbAttr { - - /** - * - * @param {Pokemon} pokemon the {@linkcode Pokemon} with this ability - * @param passive n/a - * @param simulated whether the ability is being simulated - * @param defender n/a - * @param move n/a - * @param hitResult n/a - * @param args n/a - * @returns `true` if the ability is applied - */ - applyPostAttackAfterMoveTypeCheck(pokemon: Pokemon, passive: boolean, simulated: boolean, defender: Pokemon, move: Move, hitResult: HitResult, args: any[]): boolean { - if (simulated) { - return simulated; - } - - if (pokemon.getTag(BattlerTagType.UNBURDEN)) { - return false; - } - - pokemon.addTag(BattlerTagType.UNBURDEN); - return true; - } - - getCondition(): AbAttrCondition { - return (pokemon: Pokemon) => pokemon.turnData.itemsLost > 0; - } - } export class StatStageChangeMultiplierAbAttr extends AbAttr { @@ -4935,6 +4858,11 @@ export function applyPostFaintAbAttrs(attrType: Constructor, return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostFaint(pokemon, passive, simulated, attacker, move, hitResult, args), args, false, simulated); } +export function applyPostItemLostAbAttrs(attrType: Constructor, + pokemon: Pokemon, passive: boolean, simulated: boolean = false, args: any[]): Promise { + return applyAbAttrsInternal(attrType, pokemon, (attr, passive) => attr.applyPostItemLost(pokemon, passive, simulated, args), args); +} + function queueShowAbility(pokemon: Pokemon, passive: boolean): void { pokemon.scene.unshiftPhase(new ShowAbilityPhase(pokemon.scene, pokemon.id, passive)); pokemon.scene.clearPhaseQueueSplice(); @@ -5230,9 +5158,7 @@ export function initAbilities() { new Ability(Abilities.ANGER_POINT, 4) .attr(PostDefendCritStatStageChangeAbAttr, Stat.ATK, 6), new Ability(Abilities.UNBURDEN, 4) - .attr(UnburdenBerryRemovedAbAttr) - .attr(UnburdenAttackingItemRemovedAbAttr) - .attr(UnburdenDefendingItemRemovedAbAttr), + .attr(PostItemLostApplyBattlerTagAbAttr, BattlerTagType.UNBURDEN), new Ability(Abilities.HEATPROOF, 4) .attr(ReceivedTypeDamageMultiplierAbAttr, Type.FIRE, 0.5) .attr(ReduceBurnDamageAbAttr, 0.5) diff --git a/src/data/berry.ts b/src/data/berry.ts index 01325ee39dd..e950b515162 100644 --- a/src/data/berry.ts +++ b/src/data/berry.ts @@ -2,7 +2,7 @@ import { getPokemonNameWithAffix } from "../messages"; import Pokemon, { HitResult } from "../field/pokemon"; import { getStatusEffectHealText } from "./status-effect"; import * as Utils from "../utils"; -import { DoubleBerryEffectAbAttr, ReduceBerryUseThresholdAbAttr, applyAbAttrs } from "./ability"; +import { DoubleBerryEffectAbAttr, PostItemLostAbAttr, ReduceBerryUseThresholdAbAttr, applyAbAttrs, applyPostItemLostAbAttrs } from "./ability"; import i18next from "i18next"; import { BattlerTagType } from "#enums/battler-tag-type"; import { BerryType } from "#enums/berry-type"; @@ -75,6 +75,7 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc { applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, hpHealed); pokemon.scene.unshiftPhase(new PokemonHealPhase(pokemon.scene, pokemon.getBattlerIndex(), hpHealed.value, i18next.t("battle:hpHealBerry", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), berryName: getBerryName(berryType) }), true)); + applyPostItemLostAbAttrs(PostItemLostAbAttr, pokemon, pokemon.hasPassive(), false, []); }; case BerryType.LUM: return (pokemon: Pokemon) => { @@ -86,6 +87,7 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc { } pokemon.resetStatus(true, true); pokemon.updateInfo(); + applyPostItemLostAbAttrs(PostItemLostAbAttr, pokemon, pokemon.hasPassive(), false, []); }; case BerryType.LIECHI: case BerryType.GANLON: @@ -101,6 +103,7 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc { const statStages = new Utils.NumberHolder(1); applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, statStages); pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ stat ], statStages.value)); + applyPostItemLostAbAttrs(PostItemLostAbAttr, pokemon, pokemon.hasPassive(), false, []); }; case BerryType.LANSAT: return (pokemon: Pokemon) => { @@ -108,6 +111,7 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc { pokemon.battleData.berriesEaten.push(berryType); } pokemon.addTag(BattlerTagType.CRIT_BOOST); + applyPostItemLostAbAttrs(PostItemLostAbAttr, pokemon, pokemon.hasPassive(), false, []); }; case BerryType.STARF: return (pokemon: Pokemon) => { @@ -118,6 +122,7 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc { const stages = new Utils.NumberHolder(2); applyAbAttrs(DoubleBerryEffectAbAttr, pokemon, null, false, stages); pokemon.scene.unshiftPhase(new StatStageChangePhase(pokemon.scene, pokemon.getBattlerIndex(), true, [ randStat ], stages.value)); + applyPostItemLostAbAttrs(PostItemLostAbAttr, pokemon, pokemon.hasPassive(), false, []); }; case BerryType.LEPPA: return (pokemon: Pokemon) => { @@ -128,6 +133,7 @@ export function getBerryEffectFunc(berryType: BerryType): BerryEffectFunc { if (ppRestoreMove !== undefined) { ppRestoreMove!.ppUsed = Math.max(ppRestoreMove!.ppUsed - 10, 0); pokemon.scene.queueMessage(i18next.t("battle:ppHealBerry", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), moveName: ppRestoreMove!.getName(), berryName: getBerryName(berryType) })); + applyPostItemLostAbAttrs(PostItemLostAbAttr, pokemon, pokemon.hasPassive(), false, []); } }; } diff --git a/src/data/move.ts b/src/data/move.ts index 69997ccf32f..fedf56aeca7 100644 --- a/src/data/move.ts +++ b/src/data/move.ts @@ -8,7 +8,7 @@ import { Constructor, NumberHolder } from "#app/utils"; import * as Utils from "../utils"; import { WeatherType } from "./weather"; import { ArenaTagSide, ArenaTrapTag, WeakenMoveTypeTag } from "./arena-tag"; -import { allAbilities, AllyMoveCategoryPowerBoostAbAttr, applyAbAttrs, applyPostAttackAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, BlockItemTheftAbAttr, BlockNonDirectDamageAbAttr, BlockOneHitKOAbAttr, BlockRecoilDamageAttr, ConfusionOnStatusEffectAbAttr, FieldMoveTypePowerBoostAbAttr, FieldPreventExplosiveMovesAbAttr, ForceSwitchOutImmunityAbAttr, HealFromBerryUseAbAttr, IgnoreContactAbAttr, IgnoreMoveEffectsAbAttr, IgnoreProtectOnContactAbAttr, MaxMultiHitAbAttr, MoveAbilityBypassAbAttr, MoveEffectChanceMultiplierAbAttr, MoveTypeChangeAbAttr, ReverseDrainAbAttr, UncopiableAbilityAbAttr, UnsuppressableAbilityAbAttr, UnswappableAbilityAbAttr, UserFieldMoveTypePowerBoostAbAttr, VariableMovePowerAbAttr, WonderSkinAbAttr } from "./ability"; +import { allAbilities, AllyMoveCategoryPowerBoostAbAttr, applyAbAttrs, applyPostAttackAbAttrs, applyPostItemLostAbAttrs, applyPreAttackAbAttrs, applyPreDefendAbAttrs, BlockItemTheftAbAttr, BlockNonDirectDamageAbAttr, BlockOneHitKOAbAttr, BlockRecoilDamageAttr, ConfusionOnStatusEffectAbAttr, FieldMoveTypePowerBoostAbAttr, FieldPreventExplosiveMovesAbAttr, ForceSwitchOutImmunityAbAttr, HealFromBerryUseAbAttr, IgnoreContactAbAttr, IgnoreMoveEffectsAbAttr, IgnoreProtectOnContactAbAttr, MaxMultiHitAbAttr, MoveAbilityBypassAbAttr, MoveEffectChanceMultiplierAbAttr, MoveTypeChangeAbAttr, PostItemLostAbAttr, ReverseDrainAbAttr, UncopiableAbilityAbAttr, UnsuppressableAbilityAbAttr, UnswappableAbilityAbAttr, UserFieldMoveTypePowerBoostAbAttr, VariableMovePowerAbAttr, WonderSkinAbAttr } from "./ability"; import { AttackTypeBoosterModifier, BerryModifier, PokemonHeldItemModifier, PokemonMoveAccuracyBoosterModifier, PokemonMultiHitModifier, PreserveBerryModifier } from "../modifier/modifier"; import { BattlerIndex, BattleType } from "../battle"; import { TerrainType } from "./terrain"; @@ -2175,7 +2175,6 @@ export class StealHeldItemChanceAttr extends MoveEffectAttr { const stolenItem = tierHeldItems[user.randSeedInt(tierHeldItems.length)]; user.scene.tryTransferHeldItemModifier(stolenItem, user, false).then(success => { if (success) { - target.turnData.itemsLost += 1; user.scene.queueMessage(i18next.t("moveTriggers:stoleItem", { pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target), itemName: stolenItem.type.name })); } resolve(success); @@ -2257,7 +2256,8 @@ export class RemoveHeldItemAttr extends MoveEffectAttr { // Decrease item amount and update icon !--removedItem.stackCount; target.scene.updateModifiers(target.isPlayer()); - target.turnData.itemsLost += 1; + applyPostItemLostAbAttrs(PostItemLostAbAttr, target, target.hasPassive(), false, []); + if (this.berriesOnly) { user.scene.queueMessage(i18next.t("moveTriggers:incineratedItem", { pokemonName: getPokemonNameWithAffix(user), targetName: getPokemonNameWithAffix(target), itemName: removedItem.type.name })); @@ -2337,6 +2337,7 @@ export class EatBerryAttr extends MoveEffectAttr { eatBerry(consumer: Pokemon) { getBerryEffectFunc(this.chosenBerry!.berryType)(consumer); // consumer eats the berry applyAbAttrs(HealFromBerryUseAbAttr, consumer, new Utils.BooleanHolder(false)); + applyPostItemLostAbAttrs(PostItemLostAbAttr, consumer, consumer.hasPassive(), false, []); } } @@ -2372,7 +2373,7 @@ export class StealEatBerryAttr extends EatBerryAttr { } // if the target has berries, pick a random berry and steal it this.chosenBerry = heldBerries[user.randSeedInt(heldBerries.length)]; - target.turnData.itemsLost += 1; + applyPostItemLostAbAttrs(PostItemLostAbAttr, target, target.hasPassive(), false, []); const message = i18next.t("battle:stealEatBerry", { pokemonName: user.name, targetName: target.name, berryName: this.chosenBerry.type.name }); user.scene.queueMessage(message); this.reduceBerryModifier(target); diff --git a/src/field/pokemon.ts b/src/field/pokemon.ts index 5b9df94631d..e4a3e7aed7b 100644 --- a/src/field/pokemon.ts +++ b/src/field/pokemon.ts @@ -5063,7 +5063,6 @@ export class PokemonTurnData { public statStagesIncreased: boolean = false; public statStagesDecreased: boolean = false; public moveEffectiveness: TypeDamageMultiplier | null = null; - public itemsLost: number = 0; public combiningPledge?: Moves; } diff --git a/src/modifier/modifier.ts b/src/modifier/modifier.ts index f04146b4868..dd8c82357a7 100644 --- a/src/modifier/modifier.ts +++ b/src/modifier/modifier.ts @@ -3125,7 +3125,6 @@ export abstract class HeldItemTransferModifier extends PokemonHeldItemModifier { const randItem = itemModifiers[randItemIndex]; heldItemTransferPromises.push(pokemon.scene.tryTransferHeldItemModifier(randItem, pokemon, false).then(success => { if (success) { - targetPokemon.turnData.itemsLost += 1; transferredModifierTypes.push(randItem.type); itemModifiers.splice(randItemIndex, 1); } diff --git a/src/test/abilities/unburden.test.ts b/src/test/abilities/unburden.test.ts index c467c2495fe..2adc2fe0d53 100644 --- a/src/test/abilities/unburden.test.ts +++ b/src/test/abilities/unburden.test.ts @@ -95,7 +95,7 @@ describe("Abilities - Unburden", () => { }); it("should activate when an item is stolen via defending ability", async () => { game.override - .startingLevel(50) + .startingLevel(45) .enemyAbility(Abilities.PICKPOCKET) .startingHeldItems([ { name: "MULTI_LENS", count: 3 },