diff --git a/src/battle-scene.ts b/src/battle-scene.ts index 23b13f1f755..467886b25c2 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -57,7 +57,6 @@ import { getModifierPoolForType, getPartyLuckValue, ModifierPoolType, - PokemonHeldItemModifierType, } from "#app/modifier/modifier-type"; import AbilityBar from "#app/ui/ability-bar"; import { diff --git a/src/data/abilities/ability.ts b/src/data/abilities/ability.ts index 203a662767a..4bf6ce34762 100644 --- a/src/data/abilities/ability.ts +++ b/src/data/abilities/ability.ts @@ -88,8 +88,9 @@ import type { BattlerIndex } from "#app/battle"; import type Move from "#app/data/moves/move"; import type { ArenaTrapTag, SuppressAbilitiesTag } from "#app/data/arena-tag"; import { noAbilityTypeOverrideMoves } from "../moves/invalid-moves"; -import { HeldItemId } from "#enums/held-item-id"; +import { HeldItemCategoryId, HeldItemId, isItemInCategory } from "#enums/held-item-id"; import { allHeldItems } from "#app/items/all-held-items"; +import { berryTypeToHeldItem } from "#app/items/held-items/berry"; export class BlockRecoilDamageAttr extends AbAttr { constructor() { @@ -5432,10 +5433,14 @@ export class PostTurnRestoreBerryAbAttr extends PostTurnAbAttr { override canApplyPostTurn(pokemon: Pokemon, _passive: boolean, _simulated: boolean, _args: any[]): boolean { // Ensure we have at least 1 recoverable berry (at least 1 berry in berriesEaten is not capped) const cappedBerries = new Set( - globalScene - .getModifiers(BerryModifier, pokemon.isPlayer()) - .filter(bm => bm.pokemonId === pokemon.id && bm.getCountUnderMax() < 1) - .map(bm => bm.berryType), + pokemon + .getHeldItems() + .filter( + bm => + isItemInCategory(bm, HeldItemCategoryId.BERRY) && + pokemon.heldItemManager.getStack(bm) < allHeldItems[bm].maxStackCount, + ) + .map(bm => allHeldItems[bm].berryType), ); this.berriesUnderCap = pokemon.battleData.berriesEaten.filter(bt => !cappedBerries.has(bt)); @@ -5465,30 +5470,15 @@ export class PostTurnRestoreBerryAbAttr extends PostTurnAbAttr { const randomIdx = randSeedInt(this.berriesUnderCap.length); const chosenBerryType = this.berriesUnderCap[randomIdx]; pokemon.battleData.berriesEaten.splice(randomIdx, 1); // Remove berry from memory - const chosenBerry = new BerryModifierType(chosenBerryType); + const chosenBerry = berryTypeToHeldItem[chosenBerryType]; - // Add the randomly chosen berry or update the existing one - const berryModifier = globalScene.findModifier( - m => m instanceof BerryModifier && m.berryType === chosenBerryType && m.pokemonId === pokemon.id, - pokemon.isPlayer(), - ) as BerryModifier | undefined; - - if (berryModifier) { - berryModifier.stackCount++; - } else { - const newBerry = new BerryModifier(chosenBerry, pokemon.id, chosenBerryType, 1); - if (pokemon.isPlayer()) { - globalScene.addModifier(newBerry); - } else { - globalScene.addEnemyModifier(newBerry); - } - } + pokemon.heldItemManager.add(chosenBerry); globalScene.updateModifiers(pokemon.isPlayer()); globalScene.phaseManager.queueMessage( i18next.t("abilityTriggers:postTurnLootCreateEatenBerry", { pokemonNameWithAffix: getPokemonNameWithAffix(pokemon), - berryName: chosenBerry.name, + berryName: allHeldItems[chosenBerry].name, }), ); return true; @@ -5537,8 +5527,7 @@ export class RepeatBerryNextTurnAbAttr extends PostTurnAbAttr { // This doesn't count as "eating" a berry (for unnerve/stuff cheeks/unburden) as no item is consumed. for (const berryType of pokemon.summonData.berriesEatenLast) { getBerryEffectFunc(berryType)(pokemon); - const bMod = new BerryModifier(new BerryModifierType(berryType), pokemon.id, berryType, 1); - globalScene.eventTarget.dispatchEvent(new BerryUsedEvent(bMod)); // trigger message + globalScene.eventTarget.dispatchEvent(new BerryUsedEvent(pokemon, berryType)); // trigger message } // uncomment to make cheek pouch work with cud chew diff --git a/src/enums/held-item-id.ts b/src/enums/held-item-id.ts index cff6151ada7..9991e0fe15a 100644 --- a/src/enums/held-item-id.ts +++ b/src/enums/held-item-id.ts @@ -87,7 +87,7 @@ export const HeldItemId = { MACHO_BRACE: 0x0909, // Evo trackers - GIMMIGHOUL_EVO_TRACKER: 0x0a01, + GIMMIGHOUL_EVO_TRACKER: 0x0A01, }; export type HeldItemId = (typeof HeldItemId)[keyof typeof HeldItemId]; @@ -102,4 +102,28 @@ export const HeldItemNames: Record = Object.entries return acc; }, {} as Record -); \ No newline at end of file +); + + +export const HeldItemCategoryId = { + NONE: 0x0000, + BERRY: 0x0100, + CONSUMABLE: 0x0200, + TYPE_ATTACK_BOOSTER: 0x0300, + STAT_BOOSTER: 0x0400, + CRIT_BOOSTER: 0x0500, + GAIN_INCREASE: 0x0600, + UNIQUE: 0x0700, + BASE_STAT_BOOST: 0x0900, + EVO_TRACKER: 0x0A00, +}; + +export type HeldItemCategoryId = (typeof HeldItemCategoryId)[keyof typeof HeldItemCategoryId]; + +function getHeldItemCategory(itemId: HeldItemId): HeldItemCategoryId { + return itemId & 0xFF00; +} + +export function isItemInCategory(itemId: HeldItemId, category: HeldItemCategoryId): boolean { + return getHeldItemCategory(itemId) === category; +} \ No newline at end of file diff --git a/src/events/battle-scene.ts b/src/events/battle-scene.ts index 83d260bd7d2..7e454d813e2 100644 --- a/src/events/battle-scene.ts +++ b/src/events/battle-scene.ts @@ -1,5 +1,6 @@ +import type Pokemon from "#app/field/pokemon"; +import type { BerryType } from "#enums/berry-type"; import type Move from "../data/moves/move"; -import type { BerryModifier } from "../modifier/modifier"; /** Alias for all {@linkcode BattleScene} events */ export enum BattleSceneEventType { @@ -81,12 +82,13 @@ export class MoveUsedEvent extends Event { * @extends Event */ export class BerryUsedEvent extends Event { - /** The {@linkcode BerryModifier} being used */ - public berryModifier: BerryModifier; - constructor(berry: BerryModifier) { + /** The {@linkcode BerryType} being used */ + public pokemon: Pokemon; + public berryType: BerryType; + constructor(pokemon: Pokemon, berryType: BerryType) { super(BattleSceneEventType.BERRY_USED); - - this.berryModifier = berry; + this.pokemon = pokemon; + this.berryType = berryType; } } diff --git a/src/items/all-held-items.ts b/src/items/all-held-items.ts index fab4c4bb5cc..5cbc2a8e344 100644 --- a/src/items/all-held-items.ts +++ b/src/items/all-held-items.ts @@ -153,11 +153,7 @@ export function initHeldItems() { .unstealable() .untransferable() .unsuppressable(); - allHeldItems[HeldItemId.OLD_GATEAU] = new BaseStatFlatHeldItem(HeldItemId.OLD_GATEAU, 1, [ - Stat.HP, - Stat.ATK, - Stat.DEF, - ]) + allHeldItems[HeldItemId.OLD_GATEAU] = new BaseStatFlatHeldItem(HeldItemId.OLD_GATEAU, 1) .unstealable() .untransferable() .unsuppressable(); diff --git a/src/items/held-items/berry.ts b/src/items/held-items/berry.ts index eb6da1092bd..e3f6dfd0962 100644 --- a/src/items/held-items/berry.ts +++ b/src/items/held-items/berry.ts @@ -1,4 +1,5 @@ import { getBerryEffectDescription, getBerryEffectFunc, getBerryName } from "#app/data/berry"; +import { BerryUsedEvent } from "#app/events/battle-scene"; import type Pokemon from "#app/field/pokemon"; import { globalScene } from "#app/global-scene"; import { ConsumableHeldItem, ITEM_EFFECT } from "#app/items/held-item"; @@ -26,10 +27,8 @@ export const berryTypeToHeldItem: BerryTypeToHeldItemMap = { }; export interface BERRY_PARAMS { - /** The pokemon with the item */ + /** The pokemon with the berry */ pokemon: Pokemon; - /** Whether the move was used by a player pokemon */ - isPlayer: boolean; } // TODO: Maybe split up into subclasses? @@ -72,7 +71,6 @@ export class BerryHeldItem extends ConsumableHeldItem { */ apply(params: BERRY_PARAMS): boolean { const pokemon = params.pokemon; - const isPlayer = params.isPlayer; const preserve = new BooleanHolder(false); globalScene.applyModifiers(PreserveBerryModifier, pokemon.isPlayer(), pokemon, preserve); @@ -80,20 +78,15 @@ export class BerryHeldItem extends ConsumableHeldItem { // munch the berry and trigger unburden-like effects getBerryEffectFunc(this.berryType)(pokemon); - this.consume(pokemon, isPlayer, consumed); + this.consume(pokemon, pokemon.isPlayer(), consumed); // TODO: Update this method to work with held items // Update berry eaten trackers for Belch, Harvest, Cud Chew, etc. // Don't recover it if we proc berry pouch (no item duplication) pokemon.recordEatenBerry(this.berryType, consumed); + globalScene.eventTarget.dispatchEvent(new BerryUsedEvent(pokemon, this.berryType)); + return true; } - - getMaxHeldItemCount(_pokemon: Pokemon): number { - if ([BerryType.LUM, BerryType.LEPPA, BerryType.SITRUS, BerryType.ENIGMA].includes(this.berryType)) { - return 2; - } - return 3; - } } diff --git a/src/phases/berry-phase.ts b/src/phases/berry-phase.ts index 6e40e299e7c..3d9e87e3dda 100644 --- a/src/phases/berry-phase.ts +++ b/src/phases/berry-phase.ts @@ -5,14 +5,15 @@ import { RepeatBerryNextTurnAbAttr, } from "#app/data/abilities/ability"; import { CommonAnim } from "#app/data/battle-anims"; -import { BerryUsedEvent } from "#app/events/battle-scene"; import { getPokemonNameWithAffix } from "#app/messages"; -import { BerryModifier } from "#app/modifier/modifier"; import i18next from "i18next"; import { BooleanHolder } from "#app/utils/common"; import { FieldPhase } from "./field-phase"; import { globalScene } from "#app/global-scene"; import type Pokemon from "#app/field/pokemon"; +import { allHeldItems, applyHeldItems } from "#app/items/all-held-items"; +import { ITEM_EFFECT } from "#app/items/held-item"; +import { HeldItemCategoryId, isItemInCategory } from "#enums/held-item-id"; /** * The phase after attacks where the pokemon eat berries. @@ -36,10 +37,10 @@ export class BerryPhase extends FieldPhase { * @param pokemon - The {@linkcode Pokemon} to check */ eatBerries(pokemon: Pokemon): void { - const hasUsableBerry = !!globalScene.findModifier( - m => m instanceof BerryModifier && m.shouldApply(pokemon), - pokemon.isPlayer(), - ); + const hasUsableBerry = pokemon.getHeldItems().some(m => { + //TODO: This is bugged, must fix the .shouldApply() function + isItemInCategory(m, HeldItemCategoryId.BERRY) && allHeldItems[m].shouldApply(pokemon); + }); if (!hasUsableBerry) { return; @@ -64,14 +65,7 @@ export class BerryPhase extends FieldPhase { CommonAnim.USE_ITEM, ); - for (const berryModifier of globalScene.applyModifiers(BerryModifier, pokemon.isPlayer(), pokemon)) { - // No need to track berries being eaten; already done inside applyModifiers - if (berryModifier.consumed) { - berryModifier.consumed = false; - pokemon.loseHeldItem(berryModifier); - } - globalScene.eventTarget.dispatchEvent(new BerryUsedEvent(berryModifier)); - } + applyHeldItems(ITEM_EFFECT.BERRY, { pokemon: pokemon }); globalScene.updateModifiers(pokemon.isPlayer()); // AbilityId.CHEEK_POUCH only works once per round of nom noms diff --git a/src/ui/battle-flyout.ts b/src/ui/battle-flyout.ts index 9a2180eccee..7356666e6c5 100644 --- a/src/ui/battle-flyout.ts +++ b/src/ui/battle-flyout.ts @@ -177,8 +177,8 @@ export default class BattleFlyout extends Phaser.GameObjects.Container { const berryUsedEvent = event as BerryUsedEvent; if ( !berryUsedEvent || - berryUsedEvent.berryModifier.pokemonId !== this.pokemon?.id || - berryUsedEvent.berryModifier.berryType !== BerryType.LEPPA + berryUsedEvent.pokemon.id !== this.pokemon?.id || + berryUsedEvent.berryType !== BerryType.LEPPA ) { // We only care about Leppa berries return;