Dice & Randomness
Doodle Engine has two ways to roll dice: the ROLL effect and the roll condition. Both roll a random whole number between min and max (inclusive). min and max must be whole numbers, and min cannot be greater than max. Which one you want depends on a single question: does anyone need to see the number? ROLL stores the result in a variable you can display and reuse. The roll condition just passes or fails.
The examples are dialogue script; Writing Dialogues covers the basics, and silent processing nodes from that guide do the heavy lifting here.
ROLL effect
Section titled “ROLL effect”ROLL <variable> <min> <max>: rolls a random whole number and stores it in a variable. Use this when you need to:
- Display the result to the player
- Branch on the result in multiple places
- Reference the roll value later in the scene
ROLL bluffRoll 1 20NARRATOR: You rolled a {bluffRoll}!When the dialogue appears, the {bluffRoll} placeholder is replaced with the variable’s value. Placeholders work in speaker lines, narrator lines, choices, and notifications.
roll condition
Section titled “roll condition”roll <min> <max> <threshold> rolls a random whole number and returns true when the result is greater than or equal to the threshold. It returns only true or false, making it useful for hidden checks in IF blocks or triggered content.
IF roll 1 20 15 GOTO lucky_findENDTo make a choice roll dice when the player clicks it, send the choice to a node that rolls with ROLL and branches with IF. One roll can lead to several different responses:
CHOICE Try to charm the guard GOTO charm_rollEND
NODE charm_roll ROLL charm 1 20 IF variableGreaterThan charm 17 GOTO charm_amazing END IF variableGreaterThan charm 12 GOTO charm_good END IF variableGreaterThan charm 7 GOTO charm_weak END GOTO charm_failThe engine checks the IF blocks from top to bottom and uses the first matching branch. A roll of 19 goes to charm_amazing, 14 to charm_good, 9 to charm_weak, and 3 to charm_fail.
Skill check pattern
Section titled “Skill check pattern”The most common pattern: roll once with the ROLL effect, show the result, then branch:
NODE skill_check # Roll first, before any dialogue ROLL bluffRoll 1 20 NARRATOR: You consider spinning Marcus a tale to get a free drink.
CHOICE Try the story. GOTO resolve END
CHOICE Back down. END dialogue END
NODE resolve NARRATOR: You spin the tale, rolling a {bluffRoll}.
IF variableGreaterThan bluffRoll 14 ADD relationship bartender 2 SET flag bluffedMarcus GOTO success END
GOTO failure
NODE success NARRATOR: The story lands perfectly. Marcus slides over a free drink. END dialogue
NODE failure NARRATOR: Marcus raises an eyebrow. Nice try. END dialogueHidden check pattern
Section titled “Hidden check pattern”For a check the player doesn’t see, such as a random encounter or lucky find, use the roll condition in an IF block:
NODE explore NARRATOR: You search beneath the loose floorboards.
# 25% chance of finding the coin (roll 1-4, need 4+) IF roll 1 4 4 ADD item old_coin NOTIFY Old coin added to inventory. END
GOTO continueEffects inside an IF block run only when that condition passes. In the hidden check above, the coin and notification are only awarded on the successful roll.
Threshold reference
Section titled “Threshold reference”| Dice | Threshold | Chance |
|---|---|---|
1 20 15 |
15+ on a d20 | 30% |
1 20 11 |
11+ on a d20 | 50% |
1 20 6 |
6+ on a d20 | 75% |
1 4 4 |
4 on a d4 | 25% |
1 2 2 |
2 on a coin flip | 50% |
Text interpolation
Section titled “Text interpolation”{varName} works anywhere in dialogue text, not just with rolls. Any variable
in state.variables can be interpolated:
# Show current goldBARTENDER: "You've got {gold} gold on you. Enough for a drink?"
# Show quest progressNARRATOR: "Reputation: {reputation}."
# Show player profile text and character statsNARRATOR: "{player.name}, your strength is {player.stats.strength}."ELISA: "Ah, you're a {player.stats.class}!"Profile fields use {player.name}, {player.title}, and
{player.biography}. Character stats use {characterId.stats.statKey},
including {player.stats.statKey} for player stats. Numeric and string values
are supported, and localized string stat values are resolved before display.
Hidden underscore-prefixed stats can also be interpolated.
Placeholders work in dialogue lines, choices, and notifications. If a variable, character, field, or stat does not exist, the placeholder is left as written.
Check Your Work
Section titled “Check Your Work”Random branches are the hardest content to test by playing naturally, because you cannot choose what you roll. Studio’s Playtest solves this: after a ROLL, edit the rolled variable in the state inspector to force each branch, and the debug trace shows every condition the roll passed or failed. From the browser, doodle.setVariable('bluffRoll', 20) in dev tools does the same job.