From f2a339fbe5a4b385579b267d24c15918917ed989 Mon Sep 17 00:00:00 2001 From: Wlowscha <54003515+Wlowscha@users.noreply.github.com> Date: Tue, 17 Jun 2025 23:08:14 +0200 Subject: [PATCH] Held item generation for enemies follows the new scheme --- src/battle-scene.ts | 25 ++++---- src/enums/modifier-pool-type.ts | 2 +- src/field/pokemon-held-item-manager.ts | 12 ++++ src/items/held-item-pool.ts | 89 +++++++++++++++++++++++++- 4 files changed, 114 insertions(+), 14 deletions(-) diff --git a/src/battle-scene.ts b/src/battle-scene.ts index ff37fcc3b30..8afceb5571a 100644 --- a/src/battle-scene.ts +++ b/src/battle-scene.ts @@ -51,13 +51,12 @@ import { allMoves } from "./data/data-lists"; import { MusicPreference } from "#app/system/settings/settings"; import { getDefaultModifierTypeForTier, - getEnemyHeldItemsForWave, getLuckString, getLuckTextTint, getPartyLuckValue, } from "#app/modifier/modifier-type"; import { getModifierPoolForType } from "./utils/modifier-utils"; -import { ModifierPoolType } from "#enums/modifier-pool-type"; +import { HeldItemPoolType, ModifierPoolType } from "#enums/modifier-pool-type"; import AbilityBar from "#app/ui/ability-bar"; import { applyAbAttrs, applyPostBattleInitAbAttrs, applyPostItemLostAbAttrs } from "./data/abilities/apply-ab-attrs"; import { allAbilities } from "./data/data-lists"; @@ -157,7 +156,8 @@ import { allHeldItems, applyHeldItems } from "./items/all-held-items"; import { ITEM_EFFECT } from "./items/held-item"; import { PhaseManager } from "./phase-manager"; import { HeldItemId } from "#enums/held-item-id"; -import type { HeldItemPropertyMap } from "./field/pokemon-held-item-manager"; +import { assignEnemyHeldItemsForWave, assignItemsFromConfiguration } from "./items/held-item-pool"; +import type { HeldItemConfiguration } from "./items/held-item-data-types"; const DEBUG_RNG = false; @@ -2758,9 +2758,12 @@ export default class BattleScene extends SceneBase { } const countTaken = Math.min(transferQuantity, itemStack, maxStackCount - matchingItemStack); - const data = source.heldItemManager[heldItemId].data; + const itemSpecs = source.heldItemManager.getItemSpecs(heldItemId); + if (!itemSpecs) { + return false; + } source.heldItemManager.remove(heldItemId, countTaken); - target.heldItemManager.add(heldItemId, countTaken, data); + target.heldItemManager.add(itemSpecs); if (source.heldItemManager.getStack(heldItemId) === 0 && itemLost) { applyPostItemLostAbAttrs("PostItemLostAbAttr", source, false); @@ -2801,7 +2804,7 @@ export default class BattleScene extends SceneBase { return countTaken > 0; } - generateEnemyModifiers(heldItemConfigs?: HeldItemPropertyMap[]): Promise { + generateEnemyModifiers(heldItemConfigs?: HeldItemConfiguration[]): Promise { return new Promise(resolve => { if (this.currentBattle.battleSpec === BattleSpec.FINAL_BOSS) { return resolve(); @@ -2824,7 +2827,7 @@ export default class BattleScene extends SceneBase { party.forEach((enemyPokemon: EnemyPokemon, i: number) => { if (heldItemConfigs && i < heldItemConfigs.length && heldItemConfigs[i]) { - enemyPokemon.heldItemManager.overrideItems(heldItemConfigs[i]); + assignItemsFromConfiguration(heldItemConfigs[i], enemyPokemon); } else { const isBoss = enemyPokemon.isBoss() || @@ -2845,13 +2848,13 @@ export default class BattleScene extends SceneBase { if (isBoss) { count = Math.max(count, Math.floor(chances / 2)); } - getEnemyHeldItemsForWave( + assignEnemyHeldItemsForWave( difficultyWaveIndex, count, - [enemyPokemon], - this.currentBattle.battleType === BattleType.TRAINER ? ModifierPoolType.TRAINER : ModifierPoolType.WILD, + enemyPokemon, + this.currentBattle.battleType === BattleType.TRAINER ? HeldItemPoolType.TRAINER : HeldItemPoolType.WILD, upgradeChance, - ).map(itemId => enemyPokemon.heldItemManager.add(itemId)); + ); } return true; }); diff --git a/src/enums/modifier-pool-type.ts b/src/enums/modifier-pool-type.ts index c4928516f71..99b698e568c 100644 --- a/src/enums/modifier-pool-type.ts +++ b/src/enums/modifier-pool-type.ts @@ -1,10 +1,10 @@ export enum ModifierPoolType { PLAYER, ENEMY_BUFF, - DAILY_STARTER } export enum HeldItemPoolType { WILD, TRAINER, + DAILY_STARTER, } diff --git a/src/field/pokemon-held-item-manager.ts b/src/field/pokemon-held-item-manager.ts index c30b660c855..71ffed6750c 100644 --- a/src/field/pokemon-held-item-manager.ts +++ b/src/field/pokemon-held-item-manager.ts @@ -20,6 +20,18 @@ export class PokemonItemManager { this.formChangeItems = {}; } + getItemSpecs(id: HeldItemId): HeldItemSpecs | undefined { + const item = this.heldItems[id]; + if (item) { + const itemSpecs: HeldItemSpecs = { + ...item, + id, + }; + return itemSpecs; + } + return undefined; + } + getHeldItems(): number[] { return Object.keys(this.heldItems).map(k => Number(k)); } diff --git a/src/items/held-item-pool.ts b/src/items/held-item-pool.ts index 676fa798765..c79936305d4 100644 --- a/src/items/held-item-pool.ts +++ b/src/items/held-item-pool.ts @@ -1,8 +1,9 @@ -import type { PlayerPokemon } from "#app/field/pokemon"; +import type { EnemyPokemon, PlayerPokemon } from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon"; import { coerceArray, getEnumValues, randSeedFloat, randSeedInt } from "#app/utils/common"; import { BerryType } from "#enums/berry-type"; import { HeldItemCategoryId, HeldItemId } from "#enums/held-item-id"; +import { HeldItemPoolType } from "#enums/modifier-pool-type"; import type { PokemonType } from "#enums/pokemon-type"; import { RewardTier } from "#enums/reward-tier"; import { PERMANENT_STATS } from "#enums/stat"; @@ -33,7 +34,7 @@ export function assignDailyRunStarterHeldItems(party: PlayerPokemon[]) { const tier = getDailyRewardTier(tierValue); - const item = getNewHeldItemFromPool(dailyStarterHeldItemPool[tier] as HeldItemPool, party); + const item = getNewHeldItemFromPool(getHeldItemPool(HeldItemPoolType.DAILY_STARTER)[tier] as HeldItemPool, party); p.heldItemManager.add(item); } } @@ -55,6 +56,90 @@ function getDailyRewardTier(tierValue: number): RewardTier { return RewardTier.MASTER; } +function getHeldItemPool(poolType: HeldItemPoolType): HeldItemTieredPool { + let pool: HeldItemTieredPool; + switch (poolType) { + case HeldItemPoolType.WILD: + pool = wildHeldItemPool; + break; + case HeldItemPoolType.TRAINER: + pool = trainerHeldItemPool; + break; + case HeldItemPoolType.DAILY_STARTER: + pool = dailyStarterHeldItemPool; + break; + } + return pool; +} + +// TODO: Add proper documentation to this function (once it fully works...) +export function assignEnemyHeldItemsForWave( + waveIndex: number, + count: number, + enemy: EnemyPokemon, + poolType: HeldItemPoolType.WILD | HeldItemPoolType.TRAINER, + upgradeChance = 0, +): void { + for (let i = 1; i <= count; i++) { + const item = getNewHeldItemFromTieredPool( + getHeldItemPool(poolType), + [enemy], + upgradeChance && !randSeedInt(upgradeChance) ? 1 : 0, + ); + enemy.heldItemManager.add(item); + } + if (!(waveIndex % 1000)) { + enemy.heldItemManager.add(HeldItemId.MINI_BLACK_HOLE); + } +} + +function getRandomTier(): RewardTier { + const tierValue = randSeedInt(1024); + + if (tierValue > 255) { + return RewardTier.COMMON; + } + if (tierValue > 60) { + return RewardTier.GREAT; + } + if (tierValue > 12) { + return RewardTier.ULTRA; + } + if (tierValue) { + return RewardTier.ROGUE; + } + return RewardTier.MASTER; +} + +function determineEnemyPoolTier(pool: HeldItemTieredPool, upgradeCount?: number): RewardTier { + let tier = getRandomTier(); + + if (!upgradeCount) { + upgradeCount = 0; + } + + tier += upgradeCount; + while (tier && !pool[tier]?.length) { + tier--; + if (upgradeCount) { + upgradeCount--; + } + } + + return tier; +} + +function getNewHeldItemFromTieredPool( + pool: HeldItemTieredPool, + pokemon: Pokemon | Pokemon[], + upgradeCount: number, +): HeldItemId | HeldItemSpecs { + const tier = determineEnemyPoolTier(pool, upgradeCount); + const tierPool = pool[tier]; + + return getNewHeldItemFromPool(tierPool!, pokemon); +} + function pickWeightedIndex(weights: number[]): number { const totalWeight = weights.reduce((sum, w) => sum + w, 0);