Skip to main content
Glama

Dice Rolling MCP Server

by jimmcq
dice-roller.ts4.19 kB
import { DiceExpression, RollResult, DieRoll } from '../types.js'; import { randomInt } from 'crypto'; export class DiceRoller { roll(notation: string, expression: DiceExpression): RollResult { let total = expression.modifier; const allRolls: DieRoll[] = []; let breakdown = ''; for (const term of expression.dice) { const termRolls: DieRoll[] = []; const isNegative = term.count < 0; const count = Math.abs(term.count); for (let i = 0; i < count; i++) { let roll: number; if (term.fudge) { // Fudge dice: uniform -1, 0, 1 roll = randomInt(0, 3) - 1; } else { roll = randomInt(1, term.size + 1); } const die: DieRoll = { size: term.size, result: roll }; // Reroll mechanic: if the die shows a value in the reroll list, reroll it once if (term.reroll && term.reroll.includes(roll)) { die.rerolled = true; roll = randomInt(1, term.size + 1); die.modified = roll; } termRolls.push(die); if (term.explode && roll === term.size) { let explodedRoll; do { explodedRoll = randomInt(1, term.size + 1); termRolls.push({ size: term.size, result: explodedRoll, exploded: true, }); } while (explodedRoll === term.size); } } if (term.keep) { // Sort highest to lowest first termRolls.sort( (a, b) => (b.modified !== undefined ? b.modified : b.result) - (a.modified !== undefined ? a.modified : a.result) ); let toKeep: DieRoll[]; if (term.keep.type === 'h') { // Keep highest: take from the beginning (already sorted high to low) toKeep = termRolls.slice(0, term.keep.count); } else { // Keep lowest: take from the end (lowest values) toKeep = termRolls.slice(-term.keep.count); } for (const die of termRolls) { if (!toKeep.includes(die)) { die.dropped = true; } } } else if (term.drop) { // Sort highest to lowest first termRolls.sort( (a, b) => (b.modified !== undefined ? b.modified : b.result) - (a.modified !== undefined ? a.modified : a.result) ); let toDrop: DieRoll[]; if (term.drop.type === 'h') { // Drop highest: take from the beginning (highest values) toDrop = termRolls.slice(0, term.drop.count); } else { // Drop lowest: take from the end (lowest values) toDrop = termRolls.slice(-term.drop.count); } for (const die of toDrop) { die.dropped = true; } } let termTotal = 0; const termBreakdown: string[] = []; let successes = 0; for (const die of termRolls) { const finalResult = die.modified !== undefined ? die.modified : die.result; if (!die.dropped) { if (term.success) { if (finalResult >= term.success) { successes++; } } else { termTotal += finalResult; } } termBreakdown.push( `${die.result}` + `${die.rerolled ? `(r${die.modified})` : ''}` + `${die.exploded ? '!' : ''}` + `${die.dropped ? 'd' : ''}` ); } if (term.success) { termTotal = successes; } if (breakdown) breakdown += isNegative ? ' - ' : ' + '; breakdown += `${count}d${term.size}:[${termBreakdown.join(',')}]`; if (term.success) { breakdown += ` successes: ${termTotal}`; } total += isNegative ? -termTotal : termTotal; allRolls.push(...termRolls); } if (expression.modifier) { breakdown += expression.modifier > 0 ? ` + ${expression.modifier}` : ` - ${Math.abs(expression.modifier)}`; } return { notation, total, rolls: allRolls, timestamp: new Date().toISOString(), breakdown, }; } }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/jimmcq/dice-rolling-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server