UNPKG

@nekooftheabyss/fortuna

Version:

A Gacha-like system to roll random items with weights.

113 lines (110 loc) 3.51 kB
/** * Roll one item from a pool using linear search. Simple and great for one-time use pools. * Use `GachaMachine` if you will be picking multiple items from the same pool. * ```ts * const items = [ * { result: "SSR cool character", chance: 1 }, * { result: "Kinda rare character", chance: 3 }, * { result: "Mob character", chance: 5 }, * { result: "Mob character", chance: 5 }, * { result: "Mob character", chance: 5 }, * ] * roll(items) // Rolls one item from the list of items * ``` * * ```ts * const items = [ * { result: "SSR cool character", chance: 1 }, * { result: "Kinda rare character", chance: 3 }, * { result: "Mob character", chance: 5 }, * { result: "Mob character", chance: 5 }, * { result: "Mob character", chance: 5 }, * ] * roll(items, 19) // Rolls one item from the list of items, faster because the total chance is known. * ``` * @module */ /** One item from a gacha pool */ export type GachaChoice<ItemType> = { result: ItemType; chance: number; } /** * Roll one item from a pool using linear search. Simple and great for one-time use pools. * Use `GachaMachine` if you will be picking multiple items from the same pool. * @param items List of items to roll from, each having a `result` and `chance`. * @param totalChance Total weight of the pool. * ```ts * const items = [ * { result: "SSR cool character", chance: 1 }, * { result: "Kinda rare character", chance: 3 }, * { result: "Mob character", chance: 5 }, * { result: "Mob character", chance: 5 }, * { result: "Mob character", chance: 5 }, * ] * roll(items) // Rolls one item from the list of items * ``` * * ```ts * const items = [ * { result: "SSR cool character", chance: 1 }, * { result: "Kinda rare character", chance: 3 }, * { result: "Mob character", chance: 5 }, * { result: "Mob character", chance: 5 }, * { result: "Mob character", chance: 5 }, * ] * roll(items, 19) // Rolls one item from the list of items, faster because the total chance is known. * ``` */ export function roll<ItemType>( choices: ItemType[], chances: number[], totalChance?: number ): ItemType; export function roll<ItemType>( choices: GachaChoice<ItemType>[], totalChance?: number ): ItemType; export function roll<ItemType>( choices: ItemType[] | GachaChoice<ItemType>[], chanceArrOrTotalChance: number | number[] = 0, totalChance = 0 ): ItemType { const asArray = Array.isArray(chanceArrOrTotalChance); let total = asArray ? totalChance : chanceArrOrTotalChance || 0; if (typeof total !== "number") { throw new TypeError( `Invalid type for total chance. Expected 'undefined' or 'number', got '${typeof total}'` ); } let i = 0; if (total === 0) { while (i < choices.length) { total += asArray ? chanceArrOrTotalChance[i] : (choices[i] as GachaChoice<ItemType>).chance; i += 1; } } const result = Math.random() * total; let going = 0.0; i = 0; while (i < choices.length) { going += asArray ? chanceArrOrTotalChance[i] : (choices[i] as GachaChoice<ItemType>).chance; if (result < going) { return asArray ? (choices[i] as ItemType) : (choices[i] as GachaChoice<ItemType>).result; } i += 1; } return asArray ? (choices[Math.floor(Math.random() * choices.length)] as ItemType) : ( choices[ Math.floor(Math.random() * choices.length) ] as GachaChoice<ItemType> ).result; }