mirror of
https://github.com/pagefaultgames/pokerogue.git
synced 2025-06-21 17:12:44 +02:00
Moved many data types for held items to a dedicated file; introduced held item pools for item generation
This commit is contained in:
parent
89082921eb
commit
0e5499bf25
@ -1,22 +1,7 @@
|
||||
import { allHeldItems } from "#app/items/all-held-items";
|
||||
import { isItemInRequested, type HeldItemCategoryId, type HeldItemId } from "#app/enums/held-item-id";
|
||||
import type { FormChangeItem } from "#enums/form-change-item";
|
||||
import type { BASE_STAT_TOTAL_DATA } from "#app/items/held-items/base-stat-total";
|
||||
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;
|
||||
};
|
||||
import { isHeldItemSpecs, type HeldItemDataMap, type HeldItemSpecs } from "#app/items/held-item-data-types";
|
||||
|
||||
interface FormChangeItemProperties {
|
||||
active: boolean;
|
||||
@ -27,7 +12,7 @@ export type FormChangeItemPropertyMap = {
|
||||
};
|
||||
|
||||
export class PokemonItemManager {
|
||||
public heldItems: HeldItemPropertyMap;
|
||||
public heldItems: HeldItemDataMap;
|
||||
public formChangeItems: FormChangeItemPropertyMap;
|
||||
|
||||
constructor() {
|
||||
@ -61,14 +46,6 @@ export class PokemonItemManager {
|
||||
return itemType in this.heldItems;
|
||||
}
|
||||
|
||||
/*
|
||||
getItem(itemType: HeldItemId): HeldItemProperties {
|
||||
if (itemType in this.heldItems) {
|
||||
return this.heldItems[itemType];
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
getStack(itemType: HeldItemId): number {
|
||||
const item = this.heldItems[itemType];
|
||||
return item ? item.stack : 0;
|
||||
@ -79,7 +56,7 @@ export class PokemonItemManager {
|
||||
return item ? item.stack >= allHeldItems[itemType].getMaxStackCount() : false;
|
||||
}
|
||||
|
||||
overrideItems(newItems: HeldItemPropertyMap) {
|
||||
overrideItems(newItems: HeldItemDataMap) {
|
||||
this.heldItems = newItems;
|
||||
// The following is to allow randomly generated item configs to have stack 0
|
||||
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 item = this.heldItems[itemType];
|
||||
|
||||
@ -100,12 +81,25 @@ export class PokemonItemManager {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
this.heldItems[itemType] = { stack: Math.min(addStack, maxStack), disabled: false, data: data };
|
||||
this.heldItems[itemType] = { stack: Math.min(addStack, maxStack) };
|
||||
return true;
|
||||
}
|
||||
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) {
|
||||
const item = this.heldItems[itemType];
|
||||
|
||||
|
69
src/items/held-item-data-types.ts
Normal file
69
src/items/held-item-data-types.ts
Normal 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[];
|
@ -1,110 +1,157 @@
|
||||
/*
|
||||
import type { PlayerPokemon } from "#app/field/pokemon";
|
||||
import { randSeedInt } from "#app/utils/common";
|
||||
import { HeldItemCategoryId, HeldItemId, isCategoryId } from "#enums/held-item-id";
|
||||
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 type { PokemonType } from "#enums/pokemon-type";
|
||||
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 {
|
||||
weight: number;
|
||||
item: HeldItemId | HeldItemCategoryId;
|
||||
}
|
||||
export const wildHeldItemPool: HeldItemTieredPool = {};
|
||||
|
||||
export type HeldItemPool = {
|
||||
[key in RewardTier]?: HeldItemPoolEntry[];
|
||||
};
|
||||
export const trainerHeldItemPool: HeldItemTieredPool = {};
|
||||
|
||||
const dailyStarterHeldItemPool: HeldItemPool = {
|
||||
[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 const dailyStarterHeldItemPool: HeldItemTieredPool = {};
|
||||
|
||||
export function getDailyRunStarterHeldItems(party: PlayerPokemon[]): PokemonHeldItemModifier[] {
|
||||
const ret: HeldItemId[] = [];
|
||||
export function getDailyRunStarterHeldItems(party: PlayerPokemon[]) {
|
||||
for (const p of party) {
|
||||
for (let m = 0; m < 3; m++) {
|
||||
const tierValue = randSeedInt(64);
|
||||
|
||||
let tier: RewardTier;
|
||||
if (tierValue > 25) {
|
||||
tier = RewardTier.COMMON;
|
||||
} else if (tierValue > 12) {
|
||||
tier = RewardTier.GREAT;
|
||||
} else if (tierValue > 4) {
|
||||
tier = RewardTier.ULTRA;
|
||||
} else if (tierValue) {
|
||||
tier = RewardTier.ROGUE;
|
||||
} else {
|
||||
tier = RewardTier.MASTER;
|
||||
}
|
||||
const tier = getDailyRewardTier(tierValue);
|
||||
|
||||
const item = getNewHeldItemFromPool(party, dailyStarterHeldItemPool, tier);
|
||||
ret.push(item);
|
||||
const item = getNewHeldItemFromPool(dailyStarterHeldItemPool[tier] as HeldItemPool, p);
|
||||
p.heldItemManager.add(item);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
function getNewModifierTypeOption(
|
||||
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);
|
||||
function getDailyRewardTier(tierValue: number): RewardTier {
|
||||
if (tierValue > 25) {
|
||||
return RewardTier.COMMON;
|
||||
}
|
||||
if (tierValue > 12) {
|
||||
return RewardTier.GREAT;
|
||||
}
|
||||
if (tierValue > 4) {
|
||||
return RewardTier.ULTRA;
|
||||
}
|
||||
if (tierValue > 0) {
|
||||
return RewardTier.ROGUE;
|
||||
}
|
||||
return RewardTier.MASTER;
|
||||
}
|
||||
|
||||
const tier = determineTier(party, player, baseTier, upgradeCount, retryCount, allowLuckUpgrades);
|
||||
function pickWeightedIndex(weights: number[]): number {
|
||||
const totalWeight = weights.reduce((sum, w) => sum + w, 0);
|
||||
|
||||
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 (totalWeight <= 0) {
|
||||
throw new Error("Total weight must be greater than 0.");
|
||||
}
|
||||
|
||||
if (index === undefined) {
|
||||
let r = randSeedFloat() * totalWeight;
|
||||
|
||||
for (let i = 0; i < weights.length; i++) {
|
||||
if (r < weights[i]) {
|
||||
return i;
|
||||
}
|
||||
r -= weights[i];
|
||||
}
|
||||
|
||||
return -1; // TODO: Change to something more appropriate
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
if (player) {
|
||||
console.log(index, ignoredPoolIndexes[tier].filter(i => i <= index).length, ignoredPoolIndexes[tier]);
|
||||
}
|
||||
const attackMoveTypeWeights = attackMoveTypes.reduce((map, type) => {
|
||||
const current = map.get(type) ?? 0;
|
||||
if (current < 3) {
|
||||
map.set(type, current + 1);
|
||||
}
|
||||
return map;
|
||||
}, new Map<PokemonType, number>());
|
||||
|
||||
const item = pool[tier][index].item;
|
||||
if (isCategoryId(item)) {
|
||||
return getNewHeldItemCategoryOption(item);
|
||||
}
|
||||
return item;
|
||||
const types = Array.from(attackMoveTypeWeights.keys());
|
||||
|
||||
// console.log(modifierType, !player ? "(enemy)" : "");
|
||||
const weights = types.map(type => customWeights[attackTypeToHeldItem[type]] ?? attackMoveTypeWeights.get(type)!);
|
||||
|
||||
const type = types[pickWeightedIndex(weights)];
|
||||
return attackTypeToHeldItem[type];
|
||||
}
|
||||
|
||||
export function getNewHeldItemFromCategory(
|
||||
id: HeldItemCategoryId,
|
||||
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;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
*/
|
||||
|
@ -1,7 +1,7 @@
|
||||
import type Pokemon from "#app/field/pokemon";
|
||||
import type { HeldItemId } from "#enums/held-item-id";
|
||||
import { HeldItem, ITEM_EFFECT } from "../held-item";
|
||||
import { getStatKey, type Stat } from "#enums/stat";
|
||||
import { getStatKey } from "#enums/stat";
|
||||
import i18next from "i18next";
|
||||
|
||||
export interface BASE_STAT_FLAT_PARAMS {
|
||||
@ -11,11 +11,6 @@ export interface BASE_STAT_FLAT_PARAMS {
|
||||
baseStats: number[];
|
||||
}
|
||||
|
||||
export interface BASE_STAT_FLAT_DATA {
|
||||
statModifier: number;
|
||||
stats: Stat[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Currently used by Old Gateau item
|
||||
*/
|
||||
|
@ -1,6 +1,7 @@
|
||||
import type Pokemon from "#app/field/pokemon";
|
||||
import i18next from "i18next";
|
||||
import { HeldItem, ITEM_EFFECT } from "../held-item";
|
||||
import type { BASE_STAT_TOTAL_DATA } from "../held-item-data";
|
||||
|
||||
export interface BASE_STAT_TOTAL_PARAMS {
|
||||
/** The pokemon with the item */
|
||||
@ -9,10 +10,6 @@ export interface BASE_STAT_TOTAL_PARAMS {
|
||||
baseStats: number[];
|
||||
}
|
||||
|
||||
export interface BASE_STAT_TOTAL_DATA {
|
||||
statModifier: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Currently used by Shuckle Juice item
|
||||
*/
|
||||
|
80
src/items/init-held-item-pools.ts
Normal file
80
src/items/init-held-item-pools.ts
Normal 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();
|
||||
}
|
@ -1,11 +1,5 @@
|
||||
import type Pokemon from "#app/field/pokemon";
|
||||
import {
|
||||
dailyStarterModifierPool,
|
||||
enemyBuffModifierPool,
|
||||
modifierPool,
|
||||
trainerModifierPool,
|
||||
wildModifierPool,
|
||||
} from "#app/modifier/modifier-pools";
|
||||
import { enemyBuffModifierPool, modifierPool } from "#app/modifier/modifier-pools";
|
||||
import { globalScene } from "#app/global-scene";
|
||||
import { DoubleBattleChanceBoosterModifier, SpeciesCritBoosterModifier, TurnStatusEffectModifier } from "./modifier";
|
||||
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
|
||||
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
|
||||
*/
|
||||
@ -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
|
||||
*/
|
||||
@ -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.
|
||||
* {@linkcode initModifierTypes} MUST be called before this function.
|
||||
@ -798,7 +678,6 @@ export function initModifierPools() {
|
||||
initWildModifierPool();
|
||||
initTrainerModifierPool();
|
||||
initEnemyBuffModifierPool();
|
||||
initDailyStarterModifierPool();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -7,10 +7,6 @@ import type { ModifierPool } from "#app/@types/modifier-types";
|
||||
|
||||
export const modifierPool: ModifierPool = {};
|
||||
|
||||
export const wildModifierPool: ModifierPool = {};
|
||||
|
||||
export const trainerModifierPool: ModifierPool = {};
|
||||
|
||||
export const enemyBuffModifierPool: ModifierPool = {};
|
||||
|
||||
export const dailyStarterModifierPool: ModifierPool = {};
|
||||
|
@ -46,7 +46,6 @@ import {
|
||||
MoneyRewardModifier,
|
||||
MultipleParticipantExpBonusModifier,
|
||||
PokemonAllMovePpRestoreModifier,
|
||||
type PokemonHeldItemModifier,
|
||||
PokemonHpRestoreModifier,
|
||||
PokemonLevelIncrementModifier,
|
||||
PokemonNatureChangeModifier,
|
||||
@ -98,12 +97,12 @@ import { HeldItemId } from "#enums/held-item-id";
|
||||
import { allHeldItems } from "#app/items/all-held-items";
|
||||
import { TYPE_BOOST_ITEM_BOOST_PERCENT } from "#app/constants";
|
||||
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 { SPECIES_STAT_BOOSTER_ITEMS, type SpeciesStatBoosterItemId } from "#app/items/held-items/stat-booster";
|
||||
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 { getNewAttackTypeBoosterHeldItem, getNewBerryHeldItem, getNewVitaminHeldItem } from "#app/items/held-item-pool";
|
||||
|
||||
const outputModifierData = 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 {
|
||||
constructor() {
|
||||
super((_party: Pokemon[], pregenArgs?: any[]) => {
|
||||
if (pregenArgs && pregenArgs.length === 1 && pregenArgs[0] in BerryType) {
|
||||
return new BerryReward(pregenArgs[0] as BerryType);
|
||||
}
|
||||
const berryTypes = getEnumValues(BerryType);
|
||||
let randBerryType: BerryType;
|
||||
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);
|
||||
const item = getNewBerryHeldItem();
|
||||
return new HeldItemReward(item);
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -1166,47 +1138,9 @@ class AttackTypeBoosterRewardGenerator extends ModifierTypeGenerator {
|
||||
return new AttackTypeBoosterReward(pregenArgs[0] as PokemonType, TYPE_BOOST_ITEM_BOOST_PERCENT);
|
||||
}
|
||||
|
||||
// TODO: make this consider moves or abilities that change types
|
||||
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 item = getNewAttackTypeBoosterHeldItem(party);
|
||||
|
||||
const attackMoveTypeWeights = new Map<PokemonType, number>();
|
||||
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);
|
||||
return item ? new HeldItemReward(item) : null;
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -1217,8 +1151,7 @@ class BaseStatBoosterRewardGenerator extends ModifierTypeGenerator {
|
||||
if (pregenArgs) {
|
||||
return new BaseStatBoosterReward(pregenArgs[0]);
|
||||
}
|
||||
const randStat: PermanentStat = randSeedInt(Stat.SPD + 1);
|
||||
return new BaseStatBoosterReward(randStat);
|
||||
return new HeldItemReward(getNewVitaminHeldItem());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user