Skip to content

Content Generation

Joe Snee edited this page Jul 6, 2020 · 7 revisions

The DMBinder extension has an extensive (and continually expanding) set of content generation tools.

There are currently 5 main types of content generators (there is technically another generator type, "import", but that simply imports the generator configuration from another file):

Configuration of your content generators are stored in JSON format in files that use the extension .dmbgen.json. These files (or a folder that contains these files) is added to your campaign.json file.

There are three main parts of a .dmbgen.json file: the generator type, the generator values, and an optional list of additional generators referenced by the main generator.

Values of all but the Markov generators support a custom syntax for accomplishing complex text generation. Currently, the following features are supported:

  • Calling another (or the same) content generator and inserting its output into the current text.
    • When invoking a content generator, saving its output to a context variable for later use.
  • Inserting the value of a context variable into the current text.
  • Making a custom dice roll to generate a number.

Calling Another Generator

Subsequent generators are invoked by wrapping the name of the generator you want to call in curly braces, {generatorName}. More on how to specify other generators below.

Calling Another Generator Multiple Times

Generators can be called multiple times using a simple syntax, after the generator name, add the number of times you want to call it wrapped in angled brackets (< and >). You may optionally, provide some separator text to go between each time the generator is invoked, before the closing angle bracket (>) and prefixed with a pipe (|). For example: {generatorName<2|, >} will call "generatorName" 2 times and put a ", " in between each result.

Utilizing Context Variables

Context variables are values that are generated or otherwise specified that can be saved to use later in another generator or later in the same string. The variable name is specified after the generator name or dice roll, but before the closing curly brace and is preceeded by a colon, ":":

  • {generatorName:variableName}
  • {#2d4 + 6:variableName}

In the examples above, the reference generator will be called or the dice roll calculated and the resulting value will be output as text, but also saved until the content generator finishes processing. If another generator expression is encountered with the same variable name, that expression will simply return the previously stored value (it will not call a referenced generator or calculate a dice roll). You may also specify only a variable name (it still needs to be preceeded by a colon and wrapped in curly braces) and it will return the stored variable, but if you specify a variable that hasn't been set yet, it will insert nothing and display a warning popup in the corner.

Example: If you had the following generator configuration:

{
    "generatorType": "basic",
    "values": [
        "You find {#2d6 + 1:goldPieces} gp. John is jealous of your {:goldPieces} gold."
    ]
}

And the "dice roll" came to be 7, the output would be:

You find 7 gp. John is jealous of your 7 gold.

Note: It is important to note that the generator expression will be evaluated left-to-right and expand as it goes. What this means is if you have a generator value like:

"{npcName} is the town's {npcProfession}"

And "npcName" had a value like:

"{npcFirstName} {npcLastName}"

The generator would work left-to-right and resolve "npcName" first, producing:

"{npcFirstName} {npcLastName} is the town's {npcProfession}"

Now, the first expression from the left is "npcFirstName", which would be resolved next.

Making a Dice Roll

Making a custom dice roll is as simple as preceeding the roll with "{#" and proceeding it with "}", "{#2d6 + 4}". When using a dice roll expression, the following rules must be observed:

  • An "expression" is one or more "terms" separated by one of the supported mathematical operators: + (addition), - (subtraction), * (multiplication), or / (division).
  • A "term" is either a "dice roll" or an integer.
  • A "dice roll" term uses the "#d#" format, where the first "#" represents an integer for how many times to roll the die and the second represents the highest value on the die (i.e. "2d4" means "roll a 4-sided dice 2 times").
  • The first term must be a "dice roll" (i.e. "{#1d4 + 3}" is valid, but "{#3 + 1d4}" isn't valid).
  • The first term cannot have spaces in front of it (i.e."{# 1d4 + 3}" is not valid).
  • The first term, as well as any grouping of terms, may be nested in parentheses to specify order of operations (i.e "{#(1d4 + 3) * 2}").
  • There must be exactly 1 space between each of the terms (i.e. "{#1d4    +    3}" and "{#1d4+3}" are not valid).

Formatting the Dice Roll Output

Custom dice rolls made from within a generator can be specified a format to use when inserting the result into the generated text. The format borrows the "Format Specification Mini-Language" from Python3. The format is specified immediately after the dice roll and wrapped in square brackets, "[]". The syntax is as follows (all of the following are optional, unless otherwise specified), in the order specified in the list below:

  • Fill character (if specified, alignment must also be specified) [Default: ' ' (space)]
  • Alignment indicator [Default: '>' (right-aligned)]
  • Positive/negative sign indicator [Default: '-' (negative only)]
  • The "alternate form" indicator
  • The "sign-aware zero-padding" indicator
  • Minimum text width
  • Thousands grouping indicator
  • Decimal precision (preceeded by a period: ".") [Default: '6' (for non-integers)]
  • Output format type [Default: 'd' (decimal format)]
Dice Roll Formatting: Fill, Alignment and Width

A fill character can be any character other than a curly brace ({ or }). The fill character, when specified alongside alignment and width, is added to the formatted text, until the length of the text equals the specified width. If not specified, a single space ' ' is used as the default.

The alignment indicator is one of the following:

Option Description
< Left-aligns the text ( adds the fill to the right)
> Right-aligns the text (adds the fill to the left)
= Right-aligns the text, but places the positive/negative sign, if any, to the left of the fill (adds the fill between the sign and the number)
^ Centers the text (adds the fill to either side of the number, starting with the right side)

If not specified, the output will be right-aligned by default.

The minimum text width is a number that specifies the minimum number of characters to be in the output. If provided, the fill character will be added to the text, in the order determined by the alignment, until the number of characters matches the minimum width. If not specified, no fill characters will be added to the text (regardless of alignment or fill).

Example:

{#1d4[0>3]}

The generator expression above indicates that a single d4 die should be rolled, and its result should be right-aligned (as indicated by the alignment indicator: ">"), adding 0s (as indicated by the fill character: "0") until the text reaches a width of 3 (as indicated by the width: "3").
If, say, a 4 was rolled, the example above would output: 0004

Dice Roll Formatting: Positive/Negative Sign

A sign indicator can be provided to specify how to indicate positive and negative numbers:

Option Description
+ Displays a sign for both positive (+) and negative (-) numbers
- Only display a sign for negative (-) numbers
(space) Displays a space (" ") for positive numbers and a minus sign (-) for negative numbers

If not specified, the negative-only (-) option is used.

Dice Roll Formatting: Alternate Form

A hashtag/pound sign/octothorpe (#) is used output the number with the radix/base prefix of 0b (for binary), 0o (for octal), or 0x (for hexadecimal). For example, if {#1d4} would output: 4 and {#1d4[b]} (see "Format Type", below) would output: 100, {#1d4[#b]} would output: 0b100.

Dice Roll Formatting: Sign-Aware Zero-Padding

Sign-aware zero-padding is just a shortcut for the = (equals) alignment and a fill character of 0 (zero). This indicator can only be used if both alignment and fill character aren't specified (and like alignment and fill, really only does anything if you specify a width). For example: if {#1d4[+03]} would roll a "4", the generator expression would output +04:

  • Rolled a 4 (1d4)
  • Show plus signs for positive numbers (+)
  • Pad with zeros between the sign and the number (0)
  • Make sure the output is at least 3 characters (3)
Dice Roll Formatting: Width

By specifying the width, the output text will add fill characters, based on the alignment, until it reaches the width specified. If not specified, no fill characters will be added to the output.

Dice Roll Formatting: Thousands Grouping

A grouping character can be specified to use as the thousands separator:

  • , (1,000)
  • _ (1_000)
Dice Roll Formatting: Precision

The precision can be provided to indicate how many digits past the decimal to include. The precision needs to be preceeded by a period ("."). For example: if {#1d4 / 12[.2]} would roll a "1", the generator would output 0.08.

Dice Roll Formatting: Format Type

The format type specifies the format to output the number:

Option Description
b Binary (base 2)
c Convert the value to the corresponding unicode character
d Decimal (base 10)
o Octal (base 8)
x Hexadecimal (base 16)
X Uppercase hexadecimal
n Use the current locale to insert the appropriate number separators
e Scientific notation
E Uppercase scientific notation
f Fixed-point notation
F Uppercase fixed-point notation
g General format (based on Python's "general format"; basically, it uses scientific notation for really big or really small numbers and fixed-point or integers for everything else)
G Uppercase general format
% Percent (multiplied by 100, followed by a percent sign, and otherwise treated as a fixed-point number)

If not specified, will default to d.


Example 1:

{#(1d10 - 1) / 10 + 1d10 / 100[.2%]}

If a "2" and "5" are rolled, respectively, the output will be:

25.00%

Example 2:

The sword you find is {#1d1 * {#1d4:toHit}[+]} to hit and worth {#{:toHit}d12 * 10} gp.

If a "2" is rolled for the "1d4" (causing 2 d12s to be rolled) and a "2" and "8" are rolled for the "2d12", the output will be:

The sword you find is +2 to hit and worth 100 gp.

Content Generation: Basic

The "basic" content generator is just that, basic. All it does is simply pick, at random, from a list of provided values.

Basic Content Generation Example

coolNames.dmbgen.json:

{
    "generatorType": "basic",
    "values": [
        "John",
        "Kathy",
        "Sam"
    ]
}

Example Output:

Kathy

Content Generation: Markov

The "Markov" content generator uses Markov chains to generate original names or words based on an existing sampleset. More information on how Markov chains work can be found on Wikipedia, but this Markov chain implementation is based on the one listed on (possibly one of my favorite websites to use for D&D, and one of my biggest inspiriations for this extension) donjon.bin.sh.

Markov Content Generation Example

coolNames.dmbgen.json:

{
    "generatorType": "markov",
    "values": [
        "John",
        "Kathy",
        "Sam",
        "Fred",
        "George",
        "Elizabeth",
        "Angela",
        "Billy",
        "Meredith"
    ]
}

Example Output:

Joreoreo

NOTE: This example is almost identical to the one above, but will generate completely different content. Instead of picking one of the options in the "values" list, it uses those values to generate a Markov chain cache which it uses to generate a completely "new" value that tries to use patterns found in the list of values provided. When using Markov generation, the more values you can provide, the better it works.

Content Generation: Multiline

The "multiline" content generator is primarily intended to be used in conjunction with other content generators (but I suppose could be used alone). It's sole purpose is to combine all of the values listed, instead of picking just one.

Multiline Content Generation Example

magicSword.dmbgen.json:

{
    "generatorType": "multiline",
    "values": [
        "> ### Magic Sword",
        ">___",
        "> This is a really cool item!"
    ]
}

Output:

> ### Magic Sword
>___
> This is a really cool item!

Again, this generator is more useful when you reference other generators, as covered below.

Content Generation: Roll Table

The "roll table" content generator is similar to basic, but the values are weighted. Each value is assigned a value (or range of values), beginning at 1, in the configuration. When content is generated, a random number is picked, between 1 and the highest number specified in the configuration, and whichever value that corresponds with is chosen.

Roll Table Content Generation Example

coolTreasures.dmbgen.json:

{
    "generatorType": "rollTable",
    "rollValues": {
        "1-2": "10gp",
        "3-4": "3 emeralds",
        "5-6": "+1 longsword",
        "7-8": "+1 Ring of Protection",
        "9": [
            "Scroll of Wish",
            "Bag of Holding",
            "+3 Leather Armor"
        ]
    }
}

In the example above, there would be a random roll on a d9 (random number chosen between 1 and 9) Example Outcome (assuming a 4 was "rolled"):

3 emeralds

Content Generation: Switch

The "switch" content generator has an attribute that controls the outcome (called "condition") and a list of possible values for that attribute, where each possible value has either a single result or a list of results to pick from randomly. If the condition already has a value in the current context, then the value is chosen from the corresponding value for that condition. But if the condition doesn't have a value in the current context, one is picked randomly from the list of values and assigned to that attribute in the current context.

Say you had a name generator. That name generator might have a switch generator to generate a name based on an attribute called "race". Your switch generator may have a list of possible "races" ("human", "dwarf", "elf", etc.) where each "race" had either a list of names to pick from, or a single result that called a subsequent generator (i.e. the "human" result calls another generator called "humanName"). When you call the generator, if you had specified a value for "race", it would pick the value (or randomly from the list of values, if you specify a list rather than a single value) for that race. If you don't specify a "race", it will pick a random value for "race", save that value for the "race" attribute in the current context (for other generators that may use it) and then picks a corresponding result from the race it picked.

Switch Content Generation Example

coolNames.dmbgen.json:

{
    "generatorType": "switch",
    "condition": "race",
    "switchValues": {
        "dwarf": "Gimli",
        "elf": "Legolas",
        "human": "Aragorn"
    }
}

Outcome (assuming "dwarf" was specified for "race"):

Gimli

Referencing Other Generator Sources

Coming soon!

Importing Generators From Other Files

Coming soon!

Clone this wiki locally