Moved many data types for held items to a dedicated file; introduced held item pools for item generation

This commit is contained in:
Wlowscha 2025-06-15 20:51:05 +02:00
parent 89082921eb
commit 0e5499bf25
No known key found for this signature in database
GPG Key ID: 3C8F1AD330565D04
9 changed files with 313 additions and 323 deletions

View File

@ -1,22 +1,7 @@
import { allHeldItems } from "#app/items/all-held-items"; import { allHeldItems } from "#app/items/all-held-items";
import { isItemInRequested, type HeldItemCategoryId, type HeldItemId } from "#app/enums/held-item-id"; import { isItemInRequested, type HeldItemCategoryId, type HeldItemId } from "#app/enums/held-item-id";
import type { FormChangeItem } from "#enums/form-change-item"; import type { FormChangeItem } from "#enums/form-change-item";
import type { BASE_STAT_TOTAL_DATA } from "#app/items/held-items/base-stat-total"; import { isHeldItemSpecs, type HeldItemDataMap, type HeldItemSpecs } from "#app/items/held-item-data-types";
import type { BASE_STAT_FLAT_DATA } from "#app/items/held-items/base-stat-flat";
type HELD_ITEM_DATA = BASE_STAT_TOTAL_DATA | BASE_STAT_FLAT_DATA;
interface HeldItemProperties {
stack: number;
disabled?: boolean;
unstealable?: boolean; //TODO: ensure this is taken into account by stealing effects
cooldown?: number;
data?: HELD_ITEM_DATA;
}
export type HeldItemPropertyMap = {
[key in HeldItemId]?: HeldItemProperties;
};
interface FormChangeItemProperties { interface FormChangeItemProperties {
active: boolean; active: boolean;
@ -27,7 +12,7 @@ export type FormChangeItemPropertyMap = {
}; };
export class PokemonItemManager { export class PokemonItemManager {
public heldItems: HeldItemPropertyMap; public heldItems: HeldItemDataMap;
public formChangeItems: FormChangeItemPropertyMap; public formChangeItems: FormChangeItemPropertyMap;
constructor() { constructor() {
@ -61,14 +46,6 @@ export class PokemonItemManager {
return itemType in this.heldItems; return itemType in this.heldItems;
} }
/*
getItem(itemType: HeldItemId): HeldItemProperties {
if (itemType in this.heldItems) {
return this.heldItems[itemType];
}
}
*/
getStack(itemType: HeldItemId): number { getStack(itemType: HeldItemId): number {
const item = this.heldItems[itemType]; const item = this.heldItems[itemType];
return item ? item.stack : 0; return item ? item.stack : 0;
@ -79,7 +56,7 @@ export class PokemonItemManager {
return item ? item.stack >= allHeldItems[itemType].getMaxStackCount() : false; return item ? item.stack >= allHeldItems[itemType].getMaxStackCount() : false;
} }
overrideItems(newItems: HeldItemPropertyMap) { overrideItems(newItems: HeldItemDataMap) {
this.heldItems = newItems; this.heldItems = newItems;
// The following is to allow randomly generated item configs to have stack 0 // The following is to allow randomly generated item configs to have stack 0
for (const [item, properties] of Object.entries(this.heldItems)) { for (const [item, properties] of Object.entries(this.heldItems)) {
@ -89,7 +66,11 @@ export class PokemonItemManager {
} }
} }
add(itemType: HeldItemId, addStack = 1, data?: HELD_ITEM_DATA): boolean { add(itemType: HeldItemId | HeldItemSpecs, addStack = 1): boolean {
if (isHeldItemSpecs(itemType)) {
return this.addItemWithSpecs(itemType);
}
const maxStack = allHeldItems[itemType].getMaxStackCount(); const maxStack = allHeldItems[itemType].getMaxStackCount();
const item = this.heldItems[itemType]; const item = this.heldItems[itemType];
@ -100,12 +81,25 @@ export class PokemonItemManager {
return true; return true;
} }
} else { } else {
this.heldItems[itemType] = { stack: Math.min(addStack, maxStack), disabled: false, data: data }; this.heldItems[itemType] = { stack: Math.min(addStack, maxStack) };
return true; return true;
} }
return false; return false;
} }
addItemWithSpecs(itemSpecs: HeldItemSpecs): boolean {
const id = itemSpecs.id;
const maxStack = allHeldItems[id].getMaxStackCount();
const item = this.heldItems[id];
const tempStack = item?.stack ?? 0;
this.heldItems[id] = itemSpecs;
this.heldItems[id].stack = Math.min(itemSpecs.stack + tempStack, maxStack);
return true;
}
remove(itemType: HeldItemId, removeStack = 1, all = false) { remove(itemType: HeldItemId, removeStack = 1, all = false) {
const item = this.heldItems[itemType]; const item = this.heldItems[itemType];

View File

@ -0,0 +1,69 @@
import type Pokemon from "#app/field/pokemon";
import type { HeldItemCategoryId, HeldItemId } from "#enums/held-item-id";
import type { RewardTier } from "#enums/reward-tier";
import type { Stat } from "#enums/stat";
export interface BASE_STAT_TOTAL_DATA {
statModifier: number;
}
export interface BASE_STAT_FLAT_DATA {
statModifier: number;
stats: Stat[];
}
export type HeldItemExtraData = BASE_STAT_TOTAL_DATA | BASE_STAT_FLAT_DATA;
export type HeldItemData = {
stack: number;
disabled?: boolean;
unstealable?: boolean;
cooldown?: number;
data?: HeldItemExtraData;
};
export type HeldItemDataMap = {
[key in HeldItemId]?: HeldItemData;
};
export type HeldItemSpecs = HeldItemData & {
id: HeldItemId;
};
export function isHeldItemSpecs(entry: any): entry is HeldItemSpecs {
return typeof entry.id === "number" && "stack" in entry;
}
export type HeldItemWeights = {
[key in HeldItemId]?: number;
};
export type HeldItemWeightFunc = (party: Pokemon[]) => number;
export type HeldItemCategoryEntry = HeldItemData & {
id: HeldItemCategoryId;
customWeights?: HeldItemWeights;
};
export function isHeldItemCategoryEntry(entry: any): entry is HeldItemCategoryEntry {
return isHeldItemCategoryEntry(entry.id) && "customWeights" in entry;
}
type HeldItemPoolEntry = {
entry: HeldItemId | HeldItemCategoryEntry | HeldItemSpecs;
weight: number | HeldItemWeightFunc;
};
export type HeldItemPool = HeldItemPoolEntry[];
export type HeldItemTieredPool = {
[key in RewardTier]?: HeldItemPool;
};
type HeldItemConfigurationEntry = {
entry: HeldItemId | HeldItemCategoryEntry | HeldItemSpecs | HeldItemPool;
count?: number | (() => number);
excluded?: HeldItemId[];
};
export type HeldItemConfiguration = HeldItemConfigurationEntry[];

View File

@ -1,110 +1,157 @@
/*
import type { PlayerPokemon } from "#app/field/pokemon"; import type { PlayerPokemon } from "#app/field/pokemon";
import { randSeedInt } from "#app/utils/common"; import type Pokemon from "#app/field/pokemon";
import { HeldItemCategoryId, HeldItemId, isCategoryId } from "#enums/held-item-id"; import { coerceArray, getEnumValues, randSeedFloat, randSeedInt } from "#app/utils/common";
import { BerryType } from "#enums/berry-type";
import { HeldItemCategoryId, HeldItemId } from "#enums/held-item-id";
import type { PokemonType } from "#enums/pokemon-type";
import { RewardTier } from "#enums/reward-tier"; import { RewardTier } from "#enums/reward-tier";
import { PERMANENT_STATS } from "#enums/stat";
import {
type HeldItemPool,
type HeldItemSpecs,
type HeldItemTieredPool,
type HeldItemWeights,
isHeldItemCategoryEntry,
} from "./held-item-data-types";
import { attackTypeToHeldItem } from "./held-items/attack-type-booster";
import { permanentStatToHeldItem } from "./held-items/base-stat-booster";
import { berryTypeToHeldItem } from "./held-items/berry";
interface HeldItemPoolEntry { export const wildHeldItemPool: HeldItemTieredPool = {};
weight: number;
item: HeldItemId | HeldItemCategoryId;
}
export type HeldItemPool = { export const trainerHeldItemPool: HeldItemTieredPool = {};
[key in RewardTier]?: HeldItemPoolEntry[];
};
const dailyStarterHeldItemPool: HeldItemPool = { export const dailyStarterHeldItemPool: HeldItemTieredPool = {};
[RewardTier.COMMON]: [
{ item: HeldItemCategoryId.BASE_STAT_BOOST, weight: 1 },
{ item: HeldItemCategoryId.BERRY, weight: 3 },
],
[RewardTier.GREAT]: [{ item: HeldItemCategoryId.TYPE_ATTACK_BOOSTER, weight: 5 }],
[RewardTier.ULTRA]: [
{ item: HeldItemId.REVIVER_SEED, weight: 4 },
{ item: HeldItemId.SOOTHE_BELL, weight: 1 },
{ item: HeldItemId.SOUL_DEW, weight: 1 },
{ item: HeldItemId.GOLDEN_PUNCH, weight: 1 },
],
[RewardTier.ROGUE]: [
{ item: HeldItemId.GRIP_CLAW, weight: 5 },
{ item: HeldItemId.BATON, weight: 2 },
{ item: HeldItemId.FOCUS_BAND, weight: 5 },
{ item: HeldItemId.QUICK_CLAW, weight: 3 },
{ item: HeldItemId.KINGS_ROCK, weight: 3 },
],
[RewardTier.MASTER]: [
{ item: HeldItemId.LEFTOVERS, weight: 1 },
{ item: HeldItemId.SHELL_BELL, weight: 1 },
],
};
export function getDailyRunStarterHeldItems(party: PlayerPokemon[]): PokemonHeldItemModifier[] { export function getDailyRunStarterHeldItems(party: PlayerPokemon[]) {
const ret: HeldItemId[] = [];
for (const p of party) { for (const p of party) {
for (let m = 0; m < 3; m++) { for (let m = 0; m < 3; m++) {
const tierValue = randSeedInt(64); const tierValue = randSeedInt(64);
let tier: RewardTier; const tier = getDailyRewardTier(tierValue);
const item = getNewHeldItemFromPool(dailyStarterHeldItemPool[tier] as HeldItemPool, p);
p.heldItemManager.add(item);
}
}
}
function getDailyRewardTier(tierValue: number): RewardTier {
if (tierValue > 25) { if (tierValue > 25) {
tier = RewardTier.COMMON; return RewardTier.COMMON;
} else if (tierValue > 12) { }
tier = RewardTier.GREAT; if (tierValue > 12) {
} else if (tierValue > 4) { return RewardTier.GREAT;
tier = RewardTier.ULTRA; }
} else if (tierValue) { if (tierValue > 4) {
tier = RewardTier.ROGUE; return RewardTier.ULTRA;
} else { }
tier = RewardTier.MASTER; if (tierValue > 0) {
return RewardTier.ROGUE;
}
return RewardTier.MASTER;
} }
const item = getNewHeldItemFromPool(party, dailyStarterHeldItemPool, tier); function pickWeightedIndex(weights: number[]): number {
ret.push(item); const totalWeight = weights.reduce((sum, w) => sum + w, 0);
}
if (totalWeight <= 0) {
throw new Error("Total weight must be greater than 0.");
} }
return ret; let r = randSeedFloat() * totalWeight;
for (let i = 0; i < weights.length; i++) {
if (r < weights[i]) {
return i;
}
r -= weights[i];
} }
function getNewModifierTypeOption( return -1; // TODO: Change to something more appropriate
party: Pokemon[],
poolType: ModifierPoolType,
baseTier?: ModifierTier,
upgradeCount?: number,
retryCount = 0,
allowLuckUpgrades = true,
): ModifierTypeOption | null {
const player = !poolType;
const pool = getModifierPoolForType(poolType);
const thresholds = getPoolThresholds(poolType);
const tier = determineTier(party, player, baseTier, upgradeCount, retryCount, allowLuckUpgrades);
const tierThresholds = Object.keys(thresholds[tier]);
const totalWeight = Number.parseInt(tierThresholds[tierThresholds.length - 1]);
const value = randSeedInt(totalWeight);
let index: number | undefined;
for (const t of tierThresholds) {
const threshold = Number.parseInt(t);
if (value < threshold) {
index = thresholds[tier][threshold];
break;
}
} }
if (index === undefined) { export function getNewVitaminHeldItem(customWeights: HeldItemWeights = {}): HeldItemId {
const items = PERMANENT_STATS.map(s => permanentStatToHeldItem[s]);
const weights = items.map(t => customWeights[t] ?? t);
return items[pickWeightedIndex(weights)];
}
export function getNewBerryHeldItem(customWeights: HeldItemWeights = {}): HeldItemId {
const berryTypes = getEnumValues(BerryType);
const items = berryTypes.map(b => berryTypeToHeldItem[b]);
const weights = items.map(t =>
(customWeights[t] ?? (t === HeldItemId.SITRUS_BERRY || t === HeldItemId.LUM_BERRY || t === HeldItemId.LEPPA_BERRY))
? 2
: 1,
);
return items[pickWeightedIndex(weights)];
}
export function getNewAttackTypeBoosterHeldItem(
pokemon: Pokemon | Pokemon[],
customWeights: HeldItemWeights = {},
): HeldItemId | null {
const party = coerceArray(pokemon);
// TODO: make this consider moves or abilities that change types
const attackMoveTypes = party.flatMap(p =>
p
.getMoveset()
.filter(m => m.getMove().is("AttackMove"))
.map(m => m.getMove().type),
);
if (!attackMoveTypes.length) {
return null; return null;
} }
if (player) { const attackMoveTypeWeights = attackMoveTypes.reduce((map, type) => {
console.log(index, ignoredPoolIndexes[tier].filter(i => i <= index).length, ignoredPoolIndexes[tier]); const current = map.get(type) ?? 0;
if (current < 3) {
map.set(type, current + 1);
}
return map;
}, new Map<PokemonType, number>());
const types = Array.from(attackMoveTypeWeights.keys());
const weights = types.map(type => customWeights[attackTypeToHeldItem[type]] ?? attackMoveTypeWeights.get(type)!);
const type = types[pickWeightedIndex(weights)];
return attackTypeToHeldItem[type];
} }
const item = pool[tier][index].item; export function getNewHeldItemFromCategory(
if (isCategoryId(item)) { id: HeldItemCategoryId,
return getNewHeldItemCategoryOption(item); pokemon: Pokemon | Pokemon[],
customWeights: HeldItemWeights = {},
): HeldItemId | null {
if (id === HeldItemCategoryId.BERRY) {
return getNewBerryHeldItem(customWeights);
}
if (id === HeldItemCategoryId.VITAMIN) {
return getNewVitaminHeldItem(customWeights);
}
if (id === HeldItemCategoryId.TYPE_ATTACK_BOOSTER) {
return getNewAttackTypeBoosterHeldItem(pokemon, customWeights);
}
return null;
} }
return item;
// console.log(modifierType, !player ? "(enemy)" : ""); function getNewHeldItemFromPool(pool: HeldItemPool, pokemon: Pokemon): HeldItemId | HeldItemSpecs {
const weights = pool.map(p => (typeof p.weight === "function" ? p.weight(coerceArray(pokemon)) : p.weight));
const entry = pool[pickWeightedIndex(weights)].entry;
if (typeof entry === "number") {
return entry as HeldItemId;
}
if (isHeldItemCategoryEntry(entry)) {
return getNewHeldItemFromCategory(entry.id, pokemon, entry?.customWeights) as HeldItemId;
}
return entry as HeldItemSpecs;
} }
*/

View File

@ -1,7 +1,7 @@
import type Pokemon from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon";
import type { HeldItemId } from "#enums/held-item-id"; import type { HeldItemId } from "#enums/held-item-id";
import { HeldItem, ITEM_EFFECT } from "../held-item"; import { HeldItem, ITEM_EFFECT } from "../held-item";
import { getStatKey, type Stat } from "#enums/stat"; import { getStatKey } from "#enums/stat";
import i18next from "i18next"; import i18next from "i18next";
export interface BASE_STAT_FLAT_PARAMS { export interface BASE_STAT_FLAT_PARAMS {
@ -11,11 +11,6 @@ export interface BASE_STAT_FLAT_PARAMS {
baseStats: number[]; baseStats: number[];
} }
export interface BASE_STAT_FLAT_DATA {
statModifier: number;
stats: Stat[];
}
/** /**
* Currently used by Old Gateau item * Currently used by Old Gateau item
*/ */

View File

@ -1,6 +1,7 @@
import type Pokemon from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon";
import i18next from "i18next"; import i18next from "i18next";
import { HeldItem, ITEM_EFFECT } from "../held-item"; import { HeldItem, ITEM_EFFECT } from "../held-item";
import type { BASE_STAT_TOTAL_DATA } from "../held-item-data";
export interface BASE_STAT_TOTAL_PARAMS { export interface BASE_STAT_TOTAL_PARAMS {
/** The pokemon with the item */ /** The pokemon with the item */
@ -9,10 +10,6 @@ export interface BASE_STAT_TOTAL_PARAMS {
baseStats: number[]; baseStats: number[];
} }
export interface BASE_STAT_TOTAL_DATA {
statModifier: number;
}
/** /**
* Currently used by Shuckle Juice item * Currently used by Shuckle Juice item
*/ */

View File

@ -0,0 +1,80 @@
import { HeldItemCategoryId, HeldItemId } from "#enums/held-item-id";
import { RewardTier } from "#enums/reward-tier";
import { dailyStarterHeldItemPool, trainerHeldItemPool, wildHeldItemPool } from "./held-item-pool";
/**
* Initialize the wild held item pool
*/
function initWildHeldItemPool() {
wildHeldItemPool[RewardTier.COMMON] = [{ entry: HeldItemCategoryId.BERRY, weight: 1 }];
wildHeldItemPool[RewardTier.GREAT] = [{ entry: HeldItemCategoryId.BASE_STAT_BOOST, weight: 1 }];
wildHeldItemPool[RewardTier.ULTRA] = [
{ entry: HeldItemCategoryId.TYPE_ATTACK_BOOSTER, weight: 5 },
{ entry: HeldItemId.WHITE_HERB, weight: 0 },
];
wildHeldItemPool[RewardTier.ROGUE] = [{ entry: HeldItemId.LUCKY_EGG, weight: 4 }];
wildHeldItemPool[RewardTier.MASTER] = [{ entry: HeldItemId.GOLDEN_EGG, weight: 1 }];
}
/**
* Initialize the trainer pokemon held item pool
*/
function initTrainerHeldItemPool() {
trainerHeldItemPool[RewardTier.COMMON] = [
{ entry: HeldItemCategoryId.BERRY, weight: 8 },
{ entry: HeldItemCategoryId.BASE_STAT_BOOST, weight: 3 },
];
trainerHeldItemPool[RewardTier.GREAT] = [{ entry: HeldItemCategoryId.BASE_STAT_BOOST, weight: 3 }];
trainerHeldItemPool[RewardTier.ULTRA] = [
{ entry: HeldItemCategoryId.TYPE_ATTACK_BOOSTER, weight: 10 },
{ entry: HeldItemId.WHITE_HERB, weight: 0 },
];
trainerHeldItemPool[RewardTier.ROGUE] = [
{ entry: HeldItemId.FOCUS_BAND, weight: 2 },
{ entry: HeldItemId.LUCKY_EGG, weight: 4 },
{ entry: HeldItemId.QUICK_CLAW, weight: 1 },
{ entry: HeldItemId.GRIP_CLAW, weight: 1 },
{ entry: HeldItemId.WIDE_LENS, weight: 1 },
];
trainerHeldItemPool[RewardTier.MASTER] = [
{ entry: HeldItemId.KINGS_ROCK, weight: 1 },
{ entry: HeldItemId.LEFTOVERS, weight: 1 },
{ entry: HeldItemId.SHELL_BELL, weight: 1 },
{ entry: HeldItemId.SCOPE_LENS, weight: 1 },
];
}
/**
* Initialize the daily starter held item pool
*/
function initDailyStarterModifierPool() {
dailyStarterHeldItemPool[RewardTier.COMMON] = [
{ entry: HeldItemCategoryId.BASE_STAT_BOOST, weight: 1 },
{ entry: HeldItemCategoryId.BERRY, weight: 3 },
];
dailyStarterHeldItemPool[RewardTier.GREAT] = [{ entry: HeldItemCategoryId.TYPE_ATTACK_BOOSTER, weight: 5 }];
dailyStarterHeldItemPool[RewardTier.ULTRA] = [
{ entry: HeldItemId.REVIVER_SEED, weight: 4 },
{ entry: HeldItemId.SOOTHE_BELL, weight: 1 },
{ entry: HeldItemId.SOUL_DEW, weight: 1 },
{ entry: HeldItemId.GOLDEN_PUNCH, weight: 1 },
];
dailyStarterHeldItemPool[RewardTier.ROGUE] = [
{ entry: HeldItemId.GRIP_CLAW, weight: 5 },
{ entry: HeldItemId.BATON, weight: 2 },
{ entry: HeldItemId.FOCUS_BAND, weight: 5 },
{ entry: HeldItemId.QUICK_CLAW, weight: 3 },
{ entry: HeldItemId.KINGS_ROCK, weight: 3 },
];
dailyStarterHeldItemPool[RewardTier.MASTER] = [
{ entry: HeldItemId.LEFTOVERS, weight: 1 },
{ entry: HeldItemId.SHELL_BELL, weight: 1 },
];
}
export function initHeldItemPools() {
// Default held item pools for specific scenarios
initWildHeldItemPool();
initTrainerHeldItemPool();
initDailyStarterModifierPool();
}

View File

@ -1,11 +1,5 @@
import type Pokemon from "#app/field/pokemon"; import type Pokemon from "#app/field/pokemon";
import { import { enemyBuffModifierPool, modifierPool } from "#app/modifier/modifier-pools";
dailyStarterModifierPool,
enemyBuffModifierPool,
modifierPool,
trainerModifierPool,
wildModifierPool,
} from "#app/modifier/modifier-pools";
import { globalScene } from "#app/global-scene"; import { globalScene } from "#app/global-scene";
import { DoubleBattleChanceBoosterModifier, SpeciesCritBoosterModifier, TurnStatusEffectModifier } from "./modifier"; import { DoubleBattleChanceBoosterModifier, SpeciesCritBoosterModifier, TurnStatusEffectModifier } from "./modifier";
import { WeightedModifierType } from "./modifier-type"; import { WeightedModifierType } from "./modifier-type";
@ -27,35 +21,6 @@ import { MAX_PER_TYPE_POKEBALLS } from "#app/data/pokeball";
// biome-ignore lint/correctness/noUnusedImports: This is used in a tsdoc comment // biome-ignore lint/correctness/noUnusedImports: This is used in a tsdoc comment
import type { initModifierTypes } from "./modifier-type"; import type { initModifierTypes } from "./modifier-type";
/**
* Initialize the wild modifier pool
*/
function initWildModifierPool() {
wildModifierPool[ModifierTier.COMMON] = [new WeightedModifierType(modifierTypes.BERRY, 1)].map(m => {
m.setTier(ModifierTier.COMMON);
return m;
});
wildModifierPool[ModifierTier.GREAT] = [new WeightedModifierType(modifierTypes.BASE_STAT_BOOSTER, 1)].map(m => {
m.setTier(ModifierTier.GREAT);
return m;
});
wildModifierPool[ModifierTier.ULTRA] = [
new WeightedModifierType(modifierTypes.ATTACK_TYPE_BOOSTER, 10),
new WeightedModifierType(modifierTypes.WHITE_HERB, 0),
].map(m => {
m.setTier(ModifierTier.ULTRA);
return m;
});
wildModifierPool[ModifierTier.ROGUE] = [new WeightedModifierType(modifierTypes.LUCKY_EGG, 4)].map(m => {
m.setTier(ModifierTier.ROGUE);
return m;
});
wildModifierPool[ModifierTier.MASTER] = [new WeightedModifierType(modifierTypes.GOLDEN_EGG, 1)].map(m => {
m.setTier(ModifierTier.MASTER);
return m;
});
}
/** /**
* Initialize the common modifier pool * Initialize the common modifier pool
*/ */
@ -649,46 +614,6 @@ function initMasterModifierPool() {
}); });
} }
function initTrainerModifierPool() {
trainerModifierPool[ModifierTier.COMMON] = [
new WeightedModifierType(modifierTypes.BERRY, 8),
new WeightedModifierType(modifierTypes.BASE_STAT_BOOSTER, 3),
].map(m => {
m.setTier(ModifierTier.COMMON);
return m;
});
trainerModifierPool[ModifierTier.GREAT] = [new WeightedModifierType(modifierTypes.BASE_STAT_BOOSTER, 3)].map(m => {
m.setTier(ModifierTier.GREAT);
return m;
});
trainerModifierPool[ModifierTier.ULTRA] = [
new WeightedModifierType(modifierTypes.ATTACK_TYPE_BOOSTER, 10),
new WeightedModifierType(modifierTypes.WHITE_HERB, 0),
].map(m => {
m.setTier(ModifierTier.ULTRA);
return m;
});
trainerModifierPool[ModifierTier.ROGUE] = [
new WeightedModifierType(modifierTypes.FOCUS_BAND, 2),
new WeightedModifierType(modifierTypes.LUCKY_EGG, 4),
new WeightedModifierType(modifierTypes.QUICK_CLAW, 1),
new WeightedModifierType(modifierTypes.GRIP_CLAW, 1),
new WeightedModifierType(modifierTypes.WIDE_LENS, 1),
].map(m => {
m.setTier(ModifierTier.ROGUE);
return m;
});
trainerModifierPool[ModifierTier.MASTER] = [
new WeightedModifierType(modifierTypes.KINGS_ROCK, 1),
new WeightedModifierType(modifierTypes.LEFTOVERS, 1),
new WeightedModifierType(modifierTypes.SHELL_BELL, 1),
new WeightedModifierType(modifierTypes.SCOPE_LENS, 1),
].map(m => {
m.setTier(ModifierTier.MASTER);
return m;
});
}
/** /**
* Initialize the enemy buff modifier pool * Initialize the enemy buff modifier pool
*/ */
@ -737,51 +662,6 @@ function initEnemyBuffModifierPool() {
}); });
} }
/**
* Initialize the daily starter modifier pool
*/
function initDailyStarterModifierPool() {
dailyStarterModifierPool[ModifierTier.COMMON] = [
new WeightedModifierType(modifierTypes.BASE_STAT_BOOSTER, 1),
new WeightedModifierType(modifierTypes.BERRY, 3),
].map(m => {
m.setTier(ModifierTier.COMMON);
return m;
});
dailyStarterModifierPool[ModifierTier.GREAT] = [new WeightedModifierType(modifierTypes.ATTACK_TYPE_BOOSTER, 5)].map(
m => {
m.setTier(ModifierTier.GREAT);
return m;
},
);
dailyStarterModifierPool[ModifierTier.ULTRA] = [
new WeightedModifierType(modifierTypes.REVIVER_SEED, 4),
new WeightedModifierType(modifierTypes.SOOTHE_BELL, 1),
new WeightedModifierType(modifierTypes.SOUL_DEW, 1),
new WeightedModifierType(modifierTypes.GOLDEN_PUNCH, 1),
].map(m => {
m.setTier(ModifierTier.ULTRA);
return m;
});
dailyStarterModifierPool[ModifierTier.ROGUE] = [
new WeightedModifierType(modifierTypes.GRIP_CLAW, 5),
new WeightedModifierType(modifierTypes.BATON, 2),
new WeightedModifierType(modifierTypes.FOCUS_BAND, 5),
new WeightedModifierType(modifierTypes.QUICK_CLAW, 3),
new WeightedModifierType(modifierTypes.KINGS_ROCK, 3),
].map(m => {
m.setTier(ModifierTier.ROGUE);
return m;
});
dailyStarterModifierPool[ModifierTier.MASTER] = [
new WeightedModifierType(modifierTypes.LEFTOVERS, 1),
new WeightedModifierType(modifierTypes.SHELL_BELL, 1),
].map(m => {
m.setTier(ModifierTier.MASTER);
return m;
});
}
/** /**
* Initialize {@linkcode modifierPool} with the initial set of modifier types. * Initialize {@linkcode modifierPool} with the initial set of modifier types.
* {@linkcode initModifierTypes} MUST be called before this function. * {@linkcode initModifierTypes} MUST be called before this function.
@ -798,7 +678,6 @@ export function initModifierPools() {
initWildModifierPool(); initWildModifierPool();
initTrainerModifierPool(); initTrainerModifierPool();
initEnemyBuffModifierPool(); initEnemyBuffModifierPool();
initDailyStarterModifierPool();
} }
/** /**

View File

@ -7,10 +7,6 @@ import type { ModifierPool } from "#app/@types/modifier-types";
export const modifierPool: ModifierPool = {}; export const modifierPool: ModifierPool = {};
export const wildModifierPool: ModifierPool = {};
export const trainerModifierPool: ModifierPool = {};
export const enemyBuffModifierPool: ModifierPool = {}; export const enemyBuffModifierPool: ModifierPool = {};
export const dailyStarterModifierPool: ModifierPool = {}; export const dailyStarterModifierPool: ModifierPool = {};

View File

@ -46,7 +46,6 @@ import {
MoneyRewardModifier, MoneyRewardModifier,
MultipleParticipantExpBonusModifier, MultipleParticipantExpBonusModifier,
PokemonAllMovePpRestoreModifier, PokemonAllMovePpRestoreModifier,
type PokemonHeldItemModifier,
PokemonHpRestoreModifier, PokemonHpRestoreModifier,
PokemonLevelIncrementModifier, PokemonLevelIncrementModifier,
PokemonNatureChangeModifier, PokemonNatureChangeModifier,
@ -98,12 +97,12 @@ import { HeldItemId } from "#enums/held-item-id";
import { allHeldItems } from "#app/items/all-held-items"; import { allHeldItems } from "#app/items/all-held-items";
import { TYPE_BOOST_ITEM_BOOST_PERCENT } from "#app/constants"; import { TYPE_BOOST_ITEM_BOOST_PERCENT } from "#app/constants";
import { attackTypeToHeldItem } from "#app/items/held-items/attack-type-booster"; import { attackTypeToHeldItem } from "#app/items/held-items/attack-type-booster";
import { berryTypeToHeldItem } from "#app/items/held-items/berry";
import { permanentStatToHeldItem, statBoostItems } from "#app/items/held-items/base-stat-booster"; import { permanentStatToHeldItem, statBoostItems } from "#app/items/held-items/base-stat-booster";
import { SPECIES_STAT_BOOSTER_ITEMS, type SpeciesStatBoosterItemId } from "#app/items/held-items/stat-booster"; import { SPECIES_STAT_BOOSTER_ITEMS, type SpeciesStatBoosterItemId } from "#app/items/held-items/stat-booster";
import { ModifierPoolType } from "#enums/modifier-pool-type"; import { ModifierPoolType } from "#enums/modifier-pool-type";
import { getModifierPoolForType, getModifierType } from "#app/utils/modifier-utils"; import { getModifierPoolForType } from "#app/utils/modifier-utils";
import type { ModifierTypeFunc, WeightedModifierTypeWeightFunc } from "#app/@types/modifier-types"; import type { ModifierTypeFunc, WeightedModifierTypeWeightFunc } from "#app/@types/modifier-types";
import { getNewAttackTypeBoosterHeldItem, getNewBerryHeldItem, getNewVitaminHeldItem } from "#app/items/held-item-pool";
const outputModifierData = false; const outputModifierData = false;
const useMaxWeightForOutput = false; const useMaxWeightForOutput = false;
@ -767,41 +766,14 @@ export class TempStatStageBoosterModifierType extends ModifierType implements Ge
} }
} }
export class BerryReward extends HeldItemReward implements GeneratedPersistentModifierType {
private berryType: BerryType;
constructor(berryType: BerryType) {
const itemId = berryTypeToHeldItem[berryType];
super(itemId);
this.berryType = berryType;
this.id = "BERRY"; // needed to prevent harvest item deletion; remove after modifier rework
}
getPregenArgs(): any[] {
return [this.berryType];
}
}
class BerryRewardGenerator extends ModifierTypeGenerator { class BerryRewardGenerator extends ModifierTypeGenerator {
constructor() { constructor() {
super((_party: Pokemon[], pregenArgs?: any[]) => { super((_party: Pokemon[], pregenArgs?: any[]) => {
if (pregenArgs && pregenArgs.length === 1 && pregenArgs[0] in BerryType) { if (pregenArgs && pregenArgs.length === 1 && pregenArgs[0] in BerryType) {
return new BerryReward(pregenArgs[0] as BerryType); return new BerryReward(pregenArgs[0] as BerryType);
} }
const berryTypes = getEnumValues(BerryType); const item = getNewBerryHeldItem();
let randBerryType: BerryType; return new HeldItemReward(item);
const rand = randSeedInt(12);
if (rand < 2) {
randBerryType = BerryType.SITRUS;
} else if (rand < 4) {
randBerryType = BerryType.LUM;
} else if (rand < 6) {
randBerryType = BerryType.LEPPA;
} else {
randBerryType = berryTypes[randSeedInt(berryTypes.length - 3) + 2];
}
return new BerryReward(randBerryType);
}); });
} }
} }
@ -1166,47 +1138,9 @@ class AttackTypeBoosterRewardGenerator extends ModifierTypeGenerator {
return new AttackTypeBoosterReward(pregenArgs[0] as PokemonType, TYPE_BOOST_ITEM_BOOST_PERCENT); return new AttackTypeBoosterReward(pregenArgs[0] as PokemonType, TYPE_BOOST_ITEM_BOOST_PERCENT);
} }
// TODO: make this consider moves or abilities that change types const item = getNewAttackTypeBoosterHeldItem(party);
const attackMoveTypes = party.flatMap(p =>
p
.getMoveset()
.map(m => m.getMove())
.filter(m => m.is("AttackMove"))
.map(m => m.type),
);
if (!attackMoveTypes.length) {
return null;
}
const attackMoveTypeWeights = new Map<PokemonType, number>(); return item ? new HeldItemReward(item) : null;
let totalWeight = 0;
for (const t of attackMoveTypes) {
const weight = attackMoveTypeWeights.get(t) ?? 0;
if (weight < 3) {
attackMoveTypeWeights.set(t, weight + 1);
totalWeight++;
}
}
if (!totalWeight) {
return null;
}
let type: PokemonType;
const randInt = randSeedInt(totalWeight);
let weight = 0;
for (const t of attackMoveTypeWeights.keys()) {
const typeWeight = attackMoveTypeWeights.get(t)!; // guranteed to be defined
if (randInt <= weight + typeWeight) {
type = t;
break;
}
weight += typeWeight;
}
return new AttackTypeBoosterReward(type!, TYPE_BOOST_ITEM_BOOST_PERCENT);
}); });
} }
} }
@ -1217,8 +1151,7 @@ class BaseStatBoosterRewardGenerator extends ModifierTypeGenerator {
if (pregenArgs) { if (pregenArgs) {
return new BaseStatBoosterReward(pregenArgs[0]); return new BaseStatBoosterReward(pregenArgs[0]);
} }
const randStat: PermanentStat = randSeedInt(Stat.SPD + 1); return new HeldItemReward(getNewVitaminHeldItem());
return new BaseStatBoosterReward(randStat);
}); });
} }
} }