@randsum/dice
Version:
A flexible, type-safe dice roller
91 lines • 3.99 kB
JavaScript
import { CapModifier, DropModifier, ExplodeModifier, MinusModifier, PlusModifier, ReplaceModifier, RerollModifier, UniqueModifier } from '@randsum/core';
import { isNumericRollOptions } from '../guards/isNumericRollOptions';
import { calculateTotal } from './calculateTotal';
import { coreRandom } from './coreRandom';
import { coreSpreadRolls } from './coreSpreadRolls';
export function rollResultFromDicePools(dicePools) {
const rawRolls = generateRawRolls(dicePools.dicePools);
const modifiedRolls = generateModifiedRolls(dicePools, rawRolls);
const modifiedValues = Object.values(modifiedRolls);
return {
...dicePools,
rawRolls,
modifiedRolls,
rawResult: Object.values(rawRolls).flat(),
result: modifiedValues.map((pool) => pool.rolls).flat(),
type: calculateDicePoolType(dicePools.dicePools),
total: calculateTotal(modifiedValues.map((pool) => pool.total))
};
}
function calculateDicePoolType(dicePools) {
const pools = Object.values(dicePools);
if (pools.every((pool) => typeof pool.options.sides === 'number')) {
return 'numerical';
}
if (pools.every((pool) => Array.isArray(pool.options.sides))) {
return 'custom';
}
return 'mixed';
}
function isCustomParameters(poolParameters) {
return Array.isArray(poolParameters.options.sides);
}
function applyModifier(key, modifiers, currentBonuses, rollParams) {
const modifierMap = {
reroll: () => new RerollModifier(modifiers.reroll).apply(currentBonuses, undefined, rollParams.rollOne),
unique: () => new UniqueModifier(modifiers.unique).apply(currentBonuses, { sides: rollParams.sides, quantity: rollParams.quantity }, rollParams.rollOne),
replace: () => new ReplaceModifier(modifiers.replace).apply(currentBonuses),
cap: () => new CapModifier(modifiers.cap).apply(currentBonuses),
drop: () => new DropModifier(modifiers.drop).apply(currentBonuses),
explode: () => new ExplodeModifier(modifiers.explode).apply(currentBonuses, { sides: rollParams.sides, quantity: rollParams.quantity }, rollParams.rollOne),
plus: () => new PlusModifier(modifiers.plus).apply(currentBonuses),
minus: () => new MinusModifier(modifiers.minus).apply(currentBonuses)
};
const modifier = modifierMap[key];
//eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (!modifier) {
throw new Error(`Unknown modifier: ${key}`);
}
return modifier();
}
function generateModifiedRolls(dicePools, rawRolls) {
return Object.fromEntries(Object.entries(dicePools.dicePools).map(([key, params]) => {
const rolls = rawRolls[key] ?? [];
if (isCustomParameters(params)) {
return [
key,
{
total: calculateTotal(rolls),
rolls
}
];
}
const { options: { sides, quantity = 1, modifiers = {} } } = params;
const rollOne = () => coreRandom(sides);
const modified = Object.keys(modifiers).reduce((bonuses, modifierKey) => applyModifier(modifierKey, modifiers, bonuses, { sides, quantity, rollOne }), {
simpleMathModifier: 0,
rolls: rolls
});
return [
key,
{
rolls: modified.rolls,
total: calculateTotal(modified.rolls, modified.simpleMathModifier)
}
];
}));
}
function generateRawRolls(dicePools) {
return Object.fromEntries(Object.entries(dicePools).map(([key, pool]) => {
const { options } = pool;
const quantity = options.quantity ?? 1;
if (isNumericRollOptions(options)) {
return [key, coreSpreadRolls(quantity, options.sides)];
}
return [
key,
coreSpreadRolls(quantity, options.sides.length, options.sides)
];
}));
}
//# sourceMappingURL=rollResultFromDicePools.js.map