Skip to content

rollDetailed()

Roll dice and get the individual results back. Never writes to chat.

Part of the Action API · Function reference

Signature

rollDetailed(expression: string): {
  total: number;
  rolls: number[];
  expression: string;
  breakdown: string;
}

Synchronous. Returns an object, not a promise.

Parameters

Parameter Type Description
expression string A dice expression, with the same grammar and property substitution as roll().

Returns

An object with four fields:

Field Type Description
total number The sum, with every modifier applied. 0 if the expression could not be parsed.
rolls number[] Every individual die face, in order, across all dice groups. Flat modifiers do not appear here. Empty for a diceless expression.
expression string The expression exactly as you passed it, before property substitution.
breakdown string A human-readable trace, e.g. 2d6(4, 2) + 3. On failure this is Error: ... and total is 0.

rolls is a flat list. rollDetailed('1d8+1d6') returns two entries with no indication of which die was which — if you need them apart, roll them apart.

When to use it instead of roll()

Reach for rollDetailed() when the individual dice matter:

  • counting successes, hits, or sixes
  • rerolling ones
  • showing the dice in a layout of your own
  • deciding something before anything reaches chat

Reach for roll() when you just want a total and the standard dice row.

Examples

Show your own breakdown

const r = rollDetailed('3d8+2');
sendMessage(`<b>${token.name}</b> channels ${r.breakdown} = <b>${r.total}</b>.`);

Count successes in a dice pool

const pool = rollDetailed(`${token.getProperty('rank')}d6`);
const hits = pool.rolls.filter((d) => d >= 5).length;
sendMessage(`${pool.rolls.join(', ')} → <b>${hits}</b> hit${hits === 1 ? '' : 's'}.`);

Great Weapon Fighting: reroll 1s and 2s once

const first = rollDetailed('2d6');
const kept = first.rolls.map((d) => (d <= 2 ? rollDetailed('1d6').total : d));
const total = kept.reduce((a, b) => a + b, 0) + 3;
sendMessage(`Damage: ${kept.join(' + ')} + 3 = <b>${total}</b>`);

Detect a natural 20

const attack = rollDetailed('1d20+attackBonus');
if (attack.rolls[0] === 20) {
  sendMessage('<b>Critical hit!</b>');
}

Notes and gotchas

  • No chat, no 3D dice, ever. Nothing about this call is visible to anyone until you call sendMessage() yourself.
  • Beware echoing expression into chat. It is the raw string you passed, so sendMessage(r.expression) hands sendMessage() a live dice expression and it rolls it again. Send r.breakdown or r.total instead.
  • Failures are silent. A malformed expression does not throw; you get total: 0 and a breakdown starting with Error:. Check for that if the expression came from user input.
  • roll(expression, false) is the same maths with only the total returned — use it when you do not need rolls or breakdown.

See also

  • roll() — the total, plus the standard chat row and 3D dice
  • sendMessage() — how to display what you rolled
  • Dice