D&D Programming Random Generators

One Dice Six

Table I from Dungeon Master’s Guide Appendix A

It’s common for role-playing rules to include tables for generating complex results, similar to the image to the right from the first edition Dungeon Master’s Guide for generating dungeon maps. The user is meant to roll a twenty-sided dice and find a matching row from the first column. A roll of 4 matches the range of 3-5, indicates a door in the random dungeon and directs the user to Table II.

Automating the results with code provides two advantages over manually rolling. In the moment, at the table, it can be quite dramatic to click once and see a result. The other advantage is being able to rapidly re-roll and pick suitable results, such as when working on a new adventure and riffing on random results.

I built a WordPress plugin that provides a block type for the Gutenberg editor. The editor selects one of the available generators to inject into the page.

Inserting the Magic User Spellbook generator

The generator itself is written in JavaScript. The rules of the generator is written in a domain-specific language I created with the aim of keeping the content human-readable and similar in formatting to how it might appear in print. This allows me to put together a text file, upload it into the plugin and immediately see results.

Generating a 10th Level Mage Spellbook

In the simplest form, the generators are a recipe that runs one more times. The recipe makes references to lookup tables which might return plain text or more lookup table references. For some generators, additional logic or formatting must be built into the JavaScript. I accept this limitation in order to keep the source tables simple.

name: Death
description: What happens when you die
recipe: does not use recipes
repeat: 1

table: deadly_blow 2d6 Result of Deadly Blow
2   Instant Death from blow to {deadly_blow_location}. The character is dead
    with no Save vs Death.
3   Fatal Wound: The character dies in {1d20}0 minutes. Only a wish or similar
    effect can heal wound. Knocked Out until death unless Save vs Death is made.
    If the character makes the save, they are conscious and can move feebly
    but cannot fight or perform otherwise strenuous actions. Location of wound
    is {deadly_blow_location}. Any limb struck is completely useless. If hit in
    the head, the character is {deadly_blow_head}.
4-5 Severed Limb:  {deadly_blow_location}. Blades sever limbs. Crushing weapons
    turn flesh and bone to mush. Puncture wounds severe a major blood vessel,
    causing the limb to become paralyzed and to later shrivel and die. Other
    types of damage, such as fire or acid, burns away flesh over a large area
    to produce a similar effect. In all cases, the limb is lost without magical
    regeneration. If hit location is the head and the character wears no helmet,
    treat this result as a roll of 2, Instant Death. If the hit location is the
    trunk, and the character wears no armor, treat this result as a roll of 3,
    Fatal Wound. Otherwise, the character will die of bleeding in {1d6+2} rounds.
    If the hit location is to the trunk (6-40), a large chunk of flesh is
    destroyed. Skin may grow back over the wound, but it will always look
    grotesque. The area is permanently weak and any blow to this spot will
    instantly kill the character. Bleeding characters may be saved with healing
    magic, a tourniquet, or cauterization with fire, except that cauterization
    will not stop bleeding caused by burns. Surviving characters require
    {3d6} weeks to recover. Knocked Out until death unless Save vs Death is made.
6-7 Broken Bone: {deadly_blow_location}. If hit location is the head (1-5) and
    no helmet is worn, Save vs Death or fall into a coma. Otherwise, {3d6} weeks
    to heal before the limb can be used. Character with broken legs or feet
    cannot stand or walk. If hit location is the the back, the character is
    permanently paralyzed and unable to walk. If hit location is the chest,
    broken ribs will prevent strenuous activity for the duration of recovery.
    Knocked Out {1d20} rounds unless Save vs Death is made.
8-9 Knocked Out for {1d12} rounds from a blow to the head if wearing a helm.
    If no helmet, then treat as a Broken Bone and roll for location (which
    likely will not be the head).
10-11   Stunned for {1d4} rounds and lose helm if wearing helm. Knocked Out for
    {1d12} rounds if not wearing helm.
12  Rage: A surge of adrenaline returns {1d4} hit points per hit die. At the
    end of the combat, the adrenaline drains away, hit points are reduced to
    zero, and the PC faints for {2d6} rounds. If you roll this more than once in a
    single combat consider yourself a Bezerker under the effects of a potion of

table: deadly_blow_location 1d100 Location of Deadly Blow
1       Skull (INT)
2       Eyes (INT)
3       Nose (WIS)
4       Ear (WIS)
5       Mouth (CHA)
6-10    Right Chest (CON)
11-15   Left Chest (CON)
16-20   Right Back (STR)
21-25   Left Back (STR)
26-30   Gut (CON)
31-35   Groin (CON)
36-40   Lower Back (STR)
41-42   Right Shoulder (STR)
43-50   Right Arm, Upper (STR)
51-58   Right Arm, Lower (DEX)
59-60   Right Hand (DEX)
61-62   Left Shoulder (STR)
63-70   Left Arm, Upper (STR)
71-78   Left Arm, Lower (DEX)
79-80   Left Hand (DEX)
81-86   Right Thigh (STR)
87-89   Right Knee (DEX)
90      Right Foot (DEX)
91-96   Left Thigh (STR)
97-99   Left Knee (DEX)
100     Left Foot (DEX)

table: deadly_blow_head 1d6
1-3 blinded
4   deafened
5-6 unable to speak

The code above implements our house rules for what happens when a character goes to zero hit points or below. The generator codes knows how to handle dice rolls (e.g. 2d6+1) and how to match ranges of rolls (e.g. 91-96). It also allow for long times to be broken up with linebreaks and indents, which helps keep the source readable, even usable if printed out.

You can see the generators in action on EmptyZ’s generators page. You can download and use the plugin yourself with the following link.

Download WordPress Plugin

UPDATE: the code is now hosted at GitHub at