Skip to content

Chartopia Domain Language

Introduction

The Chartopia domain language is a template language specifically designed to help creators add more randomness to their random tables and generators. As a template language, programming 'code' can be inserted in and around simple 'static' text and images that are rendered to the screen. The code part of the Chartopia domain language can be used to change what and when certain things are rendered.

The features of the Chartopia domain language are such that random creation can be achieve without the need for traditional tables at all; in many ways, it's a programming language specifically made for RPG random generation.

The primary uses of the Chartopia domain language is

  • Rolling on other charts
  • Doing dice rolls calculations
  • Rolling on small lists. Weighted lists if required.
  • Complex programming tasks such as loops, conditions, variable assignment and function calls.

There are three distinct programming styles that can be used as the code, each of which have their own advantages. When writing your generator, you'll likely use a mixture of styles.

Expression notation

This is represented by curly braces, {...}, and also renders the result as plain text. Expression notation is useful for quick, inline calculations. The result of an expression is plain text.

Macro notation

Those familiar with spreadsheets may be more comfortable using the macro notation, e.g. MACRO(...). It is a command syntax that will always render the result as plain text.

Code block notation

This notation is from performing more programming like tasks and is done within a curly-brace-percent-sign block, e.g. {%...%}. Often it used for assigning the result of a calculation to a variable, but it also used for condition checks and loops. Note that the code block doesn't render anything itself, but it does affect static text, especially if the code block itself surrounds static text (or macros or expression notation), within a {%...%}...{% end %}

Note that it's possible to use expression notation within macros, and possible to use macros within expression notation.

Expression Notation

Chartopia's expression notation is represented by a single set of curly braces with an instruction inside, e.g. {...}.

Rollable Lists

  • {item1|item2|item3} Choose randomly between item1, item2 or item3.
  • {item|} Choose randomly between item or nothing
  • {item1|item2 with \| pipe|item3} Choose randomly between item1, item2 with | pipe or item3
  • {item1|{a|b|c}|item2} Choose randomly between item1, result of rolling on list {a|b|c} or item2

Equations

  • {3+4-7.5 + (5-7)/2 + 6^2 + 4.1^0.5 + (-1)^4} Supported operators: + (sum), - (subtraction), / (division), * (multiplication), ^ (exponentiation)
  • {d4} Random roll of d4 dice
  • {3d12} Sum of 3 random rolls of d12 dice
  • {-4+1.5*d3} Single dice example
  • {1+2*3d12-d4^3} Example with multiple dice
  • {item1 {d2+10}|item {4d12}} {d2+10} and {4d12} will be evaluated to random numbers. Curly brackets around equations are compulsory. {item1 d2+10} will be treated as plain text
  • {17 % 5} Calculates the modulo

Math functions

  • {highest(2, 4d12)} Sum of two highest rolls out of 4 rolls of d12 dice
  • {lowest(2, 4d12)} Sum of two lowest rolls out of 4 rolls of d12 dice
  • {round(5+3.5)} Rounds off the number to the nearest integer
  • {round(3.12345, 2)} Rounds off the number to the given number of digits
  • {ceil(1.2+d12)} Rounds up to the nearest whole number
  • {floor(1.5)} Rounds down to the nearest whole number
  • {min(7, ceil(5.1+d3))} Finds minimum between two values
  • {max(1+d12, 5)} Finds maximum between two values

Conditions

  • {75%?item1|25%?item2} 75% chance of choosing item1 and 25% chance of choosing item2
  • {75%?item1|item2} 75% chance of choosing item1 and 25% chance of choosing item2
  • {75%?item|} 75% chance of choosing item1 and 25% chance of choosing nothing
  • {a|50%?b|10%?c} 40% chance of choosing a, 50% chance of choosing b and 10% chance of choosing c
  • {1-3?item1|4?item2} If d4 dice value is 1, 2 or 3, item1 is chosen. If d4 dice value is 4, item2 is chosen. This is the same as 75% chance of choosing item1 and 25% chance of choosing item2. Dice values must be consecutive and cannot be automatically deducted.

Errors

  • {a|50%?b|c} Error in condition. Error message appears on mouse hover

Escaping Characters

The following characters are treated specially by Chartopia: {, }, ?, |, [ and ], and need to be escaped using a backslash if used inside the expression notation. For example, to have a curly brace be rendered, then a backslash needs to be prepended \{

If the desired result is a backslash and an opening curly brace, then two backslashes are required, i.e. \\{.

Macro Notation

The macro notation syntax is similar to that used by spreadsheets. The syntax comprises a capitalized method name with a pair of parenthesis that encompasses the arguments/parameters.

Linked Charts

The most common usage of the macro notation is to have one chart roll on another chart; in Chartopia, this is referred to as linked charts. To roll on a linked chart, the CHART and REROLL macros can be used.

The following shows the different options that can be applied when rolling on a linked chart.

Chart

  • CHART(123) Roll on chart with id 123.
  • CHART("My chart") Roll on chart with title "My Chart". Chart title is case-sensitive.
  • CHART(name="My chart", cols="1") Roll on the first column of chart with title "My Chart".
  • CHART(name="My chart", filter="test") Behaves similarly to 'filter', but where the text of a table cell's text must be identical.
  • CHART(name="My chart", filter="test", filter_cols="1, 3-5") Roll on the rows that contain "test" in the first, third, fourth or fifth column from the chart called "My Chart".
  • CHART(name="My chart", filter="test", filter_cols="1", cols="2") Roll on the rows that contain "test" in the first column from the chart called "My Chart" but return only the second column.
  • CHART(name="My chart", filter_exact="test") Roll on the rows that "test" in the first column from the chart called "My Chart" but return only the second column.
  • CHART(name="My chart", dice="2d12") Roll 2d12 on chart called "My chart". If the result of the dice roll is outside of the chart range, an empty value is returned instead. The dice value can be any valid equation.
  • CHART(name="My chart", loops_allowed="true") Roll on chart called "My chart" and allow loops. By default, Chartopia shows an error in the event of too many loops. Setting loops_allowed to true will hide the error and return the result up to Chartopia's loop limit.
  • CHART(name="My chart", render_style="vertical_no_cols") Roll on chart called "My chart" but change the default rendering so that the rolled result will display each column on a new paragraph, excluding column names. For more examples, refer to default roll result formatting.

Reroll

  • REROLL() Reroll on the current chart.
  • REROLL(cols="1") Reroll on the current chart and return only the first column.
  • REROLL(filter="test") Reroll on the rows that contain "test" from the current chart.
  • REROLL(filter="test", filter_cols="1, 3-5") Reroll on the rows that contain "test" in the first, third, fourth or fifth column from the current chart.
  • REROLL(filter="test", filter_cols="1", cols="2") Reroll on the rows that contain "test" in the first column from the current chart but return only the second column.
  • REROLL(dice="2d12") Reroll 2d12 on current chart. If the result of the dice roll is outside of the chart range, an empty value is returned instead. The dice value can be any valid equation.
  • REROLL(loops_allowed="true") Reroll on current chart and allow loops. By default, Chartopia shows an error in the event of too many loops. Setting loops_allowed to true will hide the error and return the result up to Chartopia's loop limit.
  • REROLL(render_style="vertical_no_cols") Reroll on current chart but change the default rendering so that the rolled result will display each column on a new paragraph, excluding column names. For more examples, refer to default roll result formatting.

Aggregation

Chartopia can aggregate results of random rolls via the AGGR macro which accepts the number of rolls to perform (number or any valid equation) and an entity that may contain any combination of text and/or other macros. The result of the macro is a comma-separated list of generated items. The number of times an item was generated is shown adjacent. It is important to note that if the entity that the macro rolls on contains unmatched brackets, they must be escaped with a backslash, e.g. \(.

  • AGGR(3, CHART("My chart")) Roll on chart with title "My Chart" 3 times. If all 3 rolled results are different, all of them will be displayed. The rolled results that are identical will be aggregated
  • AGGR(3d12, CHART("My chart")) Roll on chart with title "My Chart" random number of times determined by 3d12 roll
  • AGGR(2, CHART(name="My chart", cols="1")) Roll on the first column of chart with title "My Chart" 2 times
  • AGGR(3, REROLL()) Reroll on the current chart 3 times
  • AGGR(d3, REROLL(cols="2")) Reroll on the current chart the number of times randomly generated by rolling d3 dice and return only the second column
  • AGGR(d3+12, {apple|pear|carrot} and CHART("Desserts")) Roll on the expression "{apple|pear|carrot} and CHART("Desserts")" the number of times determined by the equation d3+12
  • AGGR(12, {apple|pear (sweet)|carrot}) Roll on the list "{apple|pear (sweet)|carrot} 12 times. The brackets inside the rollable list are matching, so no need to escape them
  • AGGR(12, {apple|pear \(sweet|carrot}) Roll on the list "{apple|pear (sweet|carrot} 12 times. The brackets inside the rollable list are NOT matching, so it is necessary to escape them
  • JOIN("-", AGGR(12, {apple|pear (sweet)|carrot})) Roll on the list "{apple|pear (sweet)|carrot} 12 times and join the result using "-"

Unique Results

The UNQ macro returns a given number of unique results. It accepts the same parameters as the AGGR macro, and generated unique results are shown as a comma-separated list. Since this macro requires a given number of unique results to be generated, it may show an error if it fails to generate the requested number of unique results after 1000 attempts.

  • UNQ(3, CHART("My chart")) Roll on chart with title "My Chart" several times until 3 unique results are generated
  • UNQ(3d12, CHART("My chart")) Roll on chart with title "My Chart" and select random number of unique results determined by 3d12 roll
  • UNQ(3, REROLL()) Reroll on the current chart and select 3 unique results
  • UNQ(d3+12, {apple|pear|carrot} and CHART("Desserts")) Roll on the expression {apple|pear|carrot} and CHART("Desserts")" and select the number of unique results determined by the equation d3+12
  • UNQ(12, {apple|pear (sweet)|carrot}) Roll on the list {apple|pear (sweet)|carrot} and select 12 unique results. The brackets inside the rollable list are matching, so no need to escape them
  • UNQ(12, {apple|pear \(sweet|carrot}) Roll on the list {apple|pear (sweet|carrot} and select 12 unique results. The brackets inside the rollable list are NOT matching, so it is necessary to escape them.
  • JOIN(":", UNQ(12, {apple|pear (sweet)|carrot})) Roll on the list {apple|pear (sweet)|carrot}, select 12 unique results and join the result with ":" symbol

Unique Rows

The UNQ_ROWS macro is similar to the UNQ macro. But instead of generating unique results it selects a given number of unique rows from the given chart. This macro allows only chart as a second argument. Chart can have any parameters except dice setup. If dice is specified as a parameter, it will be ignored.

  • UNQ_ROWS(12, CHART(1)) Roll on the chart with id 1 and select 12 unique rows.
  • UNQ_ROWS(12, CHART(id="1", filter="banana")) Roll on the chart with id 1, select 12 unique rows that meet given filter.
  • UNQ_ROWS(12, CHART(id="1", cols="1,3")) Roll on the chart with id 1, select 12 unique rows and show columns 1 and 3 only.
  • UNQ_ROWS(12, REROLL()) Re-roll on the current chart and select 12 unique rows.
  • UNQ_ROWS(12, REROLL(cols="2")) Re-roll on the current chart, select 12 unique rows and return column 2.
  • JOIN("---", UNQ_ROWS(12, CHART(1))) Roll on the chart with id 1, select 12 unique rows and join the result with "---".
Error
  • UNQ_ROWS(12, CHART(id="1", dice="3d2")) The "dice" parameter is not allowed when UNQ_ROWS macro is used.

Letter case modification

  • LOWER(CHART(123) or {APPLE|CARROT}) Everything inside the LOWER macro will be converted to lower case
  • UPPER(CHART(123) {apple|carrot}) Everything inside the UPPER macro will be converted to upper case
  • SNTCE(CHART(123) {apple|carrot}) Everything inside the SNTCE macro will be converted to sentence case, i.e. only the first letter will be capitalized
  • TITLE(CHART(123) {apple|carrot}) Everything inside the TITLE macro will be converted to title case, i.e. the first letter of each word will be capitalized (with the exception of small/minor words).

Code Block Notation

The code block notation is how Chartpoia provides programming instructions. Code blocks are powerful, but they are also more complex than the macro and expression notations, which only result in plain text. Code blocks however, are responsible for executing instructions such as loops, conditional logic (if/elseif/else) and variable assignment, usually as a result of calling a function.

As a quick example, for variable assignment, a code block can be a single line, e.g. {% result = {d12} %}. In the case of loops, a begin-end block surrounds static text or other commands

{% for i in range from:1 to:{d12} %}
{{i}}
{% end %}

Data Types

The Chartopia Domain Language supports a number of data types which can be assigned to variables for continued reuse.

Strings
These are plain text and are defined by quotation marks. e.g. "Dragon".
Numbers
Can be whole numbers, decimals and can be either positive or negative.
Arrays
These are a comma separated lists of any datatype, including the array data type, and Chartopia expressions. A simple array can contain a list of the same datatype e.g. ["Ranger", "Rogue", "Wizard"], or be complex by containing different data types, e.g. ["Dragon", 123, {gold|silver|copper}]. More on arrays here.

Variables

Chartopia can assign any of the above data types to a variable by using code blocks.

For example:

  • Strings are assigned to variables using quotes: {% creature = "Dragon" %}
  • Numbers are assigned using {% num = 123 %} or {% neg_pie = -3.14 %}
  • Arrays are assigned using square brackets: {% my_list = ["Ranger", "Rogue", "Wizard"] %}
  • The result of an expression can be assigned to a variable using {% pet = {cat|dog|parrot} %}
  • Variables can be assigned to other variables using {% pet = cat %} where cat is already assigned with something like {% cat = "tabby" %}. Note that variable assignment copies the content of the right-hand side variable into the left, meaning that if cat was assigned a new value/string, then pet remains unaffected.

Variable Naming

All variable names must begin with a letter of the alphabet, or an underscore. After the first initial character, variable names can contain letters, numbers or underscores.

Rendering Variables as Text

In order to use variables within the expression notation or macros, the variable must be wrapped in a {$...}, for example: {gold|silver|copper|{$rare_gem}} or CHART("{$chart_name}"). This is referred to as rendering the variable as text.

In case you're wondering why the $ is needed at all, it's because both notations expect plain text. It's impossible to differentiate a variable from plain text unless there's something like a preceding $ to identify it.

For example, {gold|silver|copper} is typical expression notation, but let's say you had a variable with some special loot. If you use {gold|silver|special_loot} then special_loot will be be interpreted as plain text. To use the text assigned to that variable, it first has to be rendered to text. The required syntax will be {gold|silver|{$special_loot}}.

Code blocks on the other hand, recognise variables. Given that variables could also refer to different data types (text/string, numbers and arrays), it's discouraged to convert them to text first.

Avoid using {% new_var = {$my_var} %}. It's possible, but it's much cleaner to use {% new_var = my_var %}. It's also more accurate, because my_var could be a data type that is not plain text. To render an array to text first may result in unexpected side effects.

If you just want to render a variable, then you can either use the print notation e.g. {{creature}} or the render as text notation {$creature}.

Several examples of how to set variables and use them are shown below.

Variable assignment

  • {% pet = "fluffy cat" %} Create a variable called pet that contains plain text "fluffy cat"
  • {% pet = "fluffy \"super\" cat" %} Create a variable called pet that contains plain text with double quotes "fluffy \"super\" cat"
  • {% pet = { fluffy cat } %} Create a variable called pet that contains plain text " fluffy cat " where trailing spaces are preserved
  • {% snack = {apple|banana|carrot} %} Create a variable called snack that will contain either apple or banana or carrot
  • {% snack = {CHART("Snacks")} %} Create a variable called snack that will contain a random result from chart called "Snacks". If chart contains multiple columns, the result will be joined together with spaces, column names are not shown
  • {% snack = {CHART("Snacks")} %}I like {$snack} Create a variable called snack that will contain a random result from chart called "Snacks" and prints a sentence "I like " followed by the value of the variable snack
  • {% number = 32.12 %}I have {$number} kg of apples Create a variable called number that will contain number 32.12 and print a sentence "I have 32.12 kg of apples"
  • {% test = another_variable %} Create a variable called test that will contain a copy of the content of the variable called another_variable

Printing variables

  • I have {$pet} Show a sentence "I have " followed by the value of the variable pet. Variables can be used without being set in a chart if they are set by the calling chart. If during roll the variable does not have a value, an error will be shown instead

Using variables inside macros

  • CHART({$chartid}) Roll on chart with id determined by chartid variable value. The value of the variable can only be an integer. If the value of the variable is not a valid chart id, an error will be shown during roll
  • CHART(id="{$chartid}") Roll on chart with id determined by chartid variable value. The value of the variable can only be an integer. If the value of the variable is not a valid chart id, an error will be shown during roll
  • CHART("{$chartname}") Roll on chart with name determined by chartname variable value. If the value of the variable is not a valid chart name, an error will be shown during roll. Note: variables in chart name are not allowed to be mixed with text, e.g. CHART("NPCs from {$town}") will be interpreted as text and variable won't be substituted with its value. To accommodate such a scenario another variable should be declared {%title=NPCs from {$town} %}CHART("{$title}")
  • CHART(name="{$chartname}") Roll on chart with name determined by chartname variable value. If the value of the variable is not a valid chart name, an error will be shown during roll
  • CHART(id="1", filter="{$filter}") Roll on chart with title "Test" and filter rows based on the value of variable filter. All chart parameters accept variables
  • CHART(id="1", filter="dragon and {$filter} from {village|city}" The filter parameter of CHART macro allows any domain language features to be mixed together. Roll on chart with title "Test" and filter rows based on the value of construct "dragon and {$filter} from {village|city}"

Using variables inside expressions

  • {apple|{$snack}|banana} Roll on rollable list which contains a variable as one of the items
  • {{$a}%?apple|banana} a% chance of choosing apple. If variable a has invalid percentage value during roll, an error will be shown. Percentage sign is essential in this case, otherwise variable will be interpreted as a range condition
  • {1-{$a}?apple|3?banana} If dice value is between 1 and value of variable a, apple is chosen. If dice value is 3, banana is chosen. If variable a has an invalid range value during roll, an error will be shown

Using variables to create dice

  • {% a = 2 %}{{$a}2} Variables can be added to equations in any way, chained, combined with number or dice, etc. The result of the roll will be 22
  • {% a = 2 %}{{$a}d12} The result of the roll will be 2d12 dice roll
  • {% a = 2 %}{% b = 8 %}{{$a}d{$b}} The result of the roll will be 2d8 dice roll

Variable Scope

When a variable is assigned a value, the variable can be used in all charts that are called from that point down.

For example, if chart A rolls on chart B, and inside chart B, a value is assigned to variable z, it means that if chart B calls chart C, then chart C can use the variable z. Chart A will not be able to use z.

As a variation, if chart A did have a variable z, then chart B would have its own copy of z with a new value. This means that if chart A uses z after calling chart B, then it will use the same value of z as before calling chart B.

This is called variable scope.

This is an important consideration when linking to other charts that use their own variables. If both the calling chart, and the linked chart have variables with the same name, these scoping rules ensure that the calling chart doesn't "trample over" the variables set in the linked chart.

Further notes:

  • If a variable is assigned in a table row, its value is visible/scoped to the entire row and its columns. Assigned variables, however, are not scoped to other table rows of that table.
  • If a variable is assigned in a calling (top most) chart, its value will be accessible to all linked charts of the calling chart.

Arrays

Arrays are like a list of items, but are different to other data types in that individual items can be accessed. Arrays are also multi-dimensional, meaning that an array can contain arrays.

Individual elements of an array can be accessed using a dot and an index value starting from one or variable starting from $ followed by the variable name.

Example 1:

{% my_list = ["gold", "silver", "copper"] %}
{{my_list.1}}, {{my_list.3}}

will render gold, copper to the result.

Example 2:

{% my_list = [["gold", "silver", "copper"], ["ruby", "emerald", "sapphire"]] %}
{{my_list.1.2}}, {{my_list.2.3}}

will render silver, sapphire to the result.

Example 3:

{% index = 2 %}
{% my_list = ["gold", "silver", "copper"] %}
{{my_list.$index}}

will render silver to the result.

Conditionals

Conditional code blocks provide a means to render different content based on a comparison check. For example, if a variable is assigned a dragon, then some extra text can be displayed. There are also else blocks to render something in the event of not satisfying the conditional check.

A typical use case is to compare a variable against text. The conditional code block allows to compare strings, numbers, results of random rolls (by using curly brackets notation) and variables. Code blocks distinguish between the following language constructs:

  • Plain text is enclosed by quotes, e.g. "some text here"
  • Domain language expression is enclosed by curly brackets and can contain any macros, e.g. {apple|banana|CHART("Exotic fruit")}
  • Plain number, e.g. 12
  • Variable is plain text that meets variable name conditions, e.g. my_variable

Currently supported operators are ==, !=, <, >, <=, >=, as well as the logical operators or, and and not. Note that the operators <, >, <=, >= work only on numbers or language features that resolve to a number, otherwise, an error will be shown during the roll.

{% if creature == "dragon" %}
The dragon roars.
{% end %}

Assuming the creature variable has been assigned the text dragon, render "The dragon roars." as the rolled result.

{% if creature == "dragon" or creature == "butterfly" %}
The creature can fly.
{% end %}

Assuming the creature variable has been assigned the text dragon or butterfly, render "The creature can fly." as the rolled result.

{% if not creature == "dragon" %}
This is not a dragon.
{% end %}

Assuming the creature variable has been assigned the text that is not dragon, render "This is not a dragon." as the rolled result.

{% if creature == "dragon" and place == "Aotearoa" %}
This is a New Zealand dragon.
{% end %}

Assuming the creature variable has been assigned the text that is dragon and the place variable has been assigned the text that is Aotearoa, render "This is a New Zealand dragon." as the rolled result.

{% if creature == {dragon} %}
The dragon roars.
{% end %}

Same as previous example, but expression notation is used instead of plain text.

{% if creature == another_creature %}
The dragon roars.
{% end %}

Compares if value of variable creature is the same as value of variable another_creature. If the values are the same, render "The dragon roars." as the rolled result.

{% if creature == "dragon" %}
The dragon roars.
{% else %}
There's an eerie silence.
{% end %}

One of two different bodies of text are displayed depending on whether or not creature is set to dragon.

{% if creature == "dragon" %}
The dragon roars.
{% elif creature == "goblin" %}
The party laughs.
{% elif creature == "unicorn" %}
The unicorn flies away.{% end %}

One of three different bodies of text are displayed depending on whether or not creature is set to dragon, goblin or unicorn. If creature is set to something else, nothing is displayed.

{% if creature == "dragon" %}
The dragon roars.
{% elif creature == "goblin" %}
The party laughs.
{% else %}
There's an eerie silence.
{% end %}

One of three different bodies of text are displayed depending on whether or not creature is set to dragon, goblin or neither. Note that elif cannot appear straight after else.

{% if creature == {black dragon|CHART(id="123", name="dragons")} %}
CHART(id="456", name="Dragon Encounters")
{% end %}

Comparisons can be made against any Chartopia domain language feature by using expressions.

{% if {d4} == {1|2|3|4} %}
CHART(id="456", name="Dragon Encounters")
{% end %}

Comparisons can be used with just expressions. In this toy example, there's a 0.0625 change of the dice roll matching the rollable list result.

{% if {d12} > 6 %}
Hit!
{% end %}

Example of comparing a dice roll against the constant value with > operator.

{% if value == "" %}
CHART(id="456", name="Dragon Encounters")
{% end %}

Comparison against empty value is done via comparing to "" or {}.

Loops

It is possible to iterate, or 'loop through' a collection of data. In programming terms, a collection of data that can be iterated over is called an enumerable.

In Chartopia, the following data is enumerable:

Array
Each item in an array can be iterated over.
A rolled result
After rolling on a chart, it's possible to iterate over each column of the table row that is returned.
{% for item in ["gold", "silver", "copper"] %}
{{item}}
{% end %}

For each element in the array, print it to the screen.

{% loot = ["gold", "silver", "copper"] %}
{% for item in loot %}
* {{item}}
{% end %}

Assign an array to the variable called loot, then, for each element in the array, create a bullet point list using Markdown syntax.

{% monster = roll_chart name:"Monsters" %}
{% for column in result %}
**{{result.name}}** {{result.value}}
{% end %}

Assign the result of rolling on a chart to a variable called monster, then, for each table column in the result (which is a row in a table), print that column's name and value, where the name is made bold using Markdown syntax.

{% for item in ["gold", "silver", "copper"] %}{{item}}, {% end %}

For each element in the array, print it to the screen, but all on the same line, separated by a comma.

Chartopia Functions

Chartopia template language functions allow the user to perform complex functionality within a single code block, {% ... %}, or print block, {{ ... }}.

They are similar to macros (e.g. CHART(...) and AGGR(...), but instead of returning simple text, they return an object that can be utilised in different ways depending on the object returned.

For those familiar with programming languages, Chartopia template functions are just like any other programming language's functions, but the syntax is such to make it appropriate for a template language.

The objects returned by Chartopia functions can be assigned to variables, used in {% if ... %} conditions, or have their default representation printed directly. This is best demonstrated with an example.

Example: Creating a stat-block

A character stat-block is quite a complex operation, and not something easily done with simple random tables alone because of the number of constraints and rules that need to be applied. A Chartopia function can hide a lot of the complexity.

Variable Assignment

To create a stat-block, one can call the create_stat_block function and assign the resulting stat-block to a variable called stat_block e.g.

{% stat_block = create_stat_block min_point:1 max_point:5 total_points:15 skills:"Brawn, Cunning, Presence, Agility, Intellect, Willpower" %}.

Note how the create_stat_block function requires the following parameters in order to be correctly configured.

  • The characteristics to use.
  • The maximum amount of 'skill points' to allocated across the characteristics.
  • The minimum and maximum number of points that can be assigned to each characteristic.

For those familiar with Fantasy Flight Games' Star Wars RPG, these character characteristics will look familiar. This is taking 15 skill points and allocating them randomly among the six characteristics so that no characteristic is ever zero, and that no characteristic is ever higher than 5.

Printing the stat-block

After a stat-block has been created and assigned to a variable called stat_block, it's possible to print it to the screen using the print notation.

{{stat_block}}

It's also possible to avoid assigning to a variable and just print directly.

{{create_stat_block min_point:1 max_point:5 total_points:15 skills:"Brawn, Cunning, ..." }}

To assign the value to a variable and print it at the same time, do the following.

{{stat_block = create_stat_block min_point:1 max_point:5 total_points:15 skills:"Brawn, Cunning, ..." }}

Conditions

Objects returned by functions can also be compared against other objects. For example, if an existing stat_block variable were to be compared with a brand new one, one could use the following:

{% if stat_block == create_stat_block min_point:1 max_point:5 total_points:15 skills:"Brawn, Cunning, Presence, Agility, Intellect, Willpower" %}.

Object Properties

Objects returned by functions can have properties associated with them depending on the object. In the case of the stat-block, it's possible to examine the number of points associated with each characteristic.

In the above example, the number of points assigned to "Agility" can be examined by using dot notation, stat_block.Agility. The property name can also be stored in a variable, and the object property can be accessed via that variable as shown below.

{% property = "Agility" %}
{{stat_block.$property }}

Just like the stat_block object, these properties can also printed using the print notation, or used in conditions.

When using expression notation, properties can also be used.

Function arguments

Functions often require parameters (arguments). In the Chartopia Domain Language, parameters are specified after the function as name-value pairs, where the name and value are separated by a colon. For example, to roll on chart with id 288, we can use the following:

{{ roll_chart id:288 }}

Multiple parameters are separated by a space.

{{ roll_chart id:288 cols:1 }}

Some functions support positional arguments. This is when the position a parameter appears in the list of parameters, dictates what it represents. For example, the roll_chart function supports one positional argument, which corresponds to id. Hence, the example from above can rewritten as:

{{ roll_chart 288 }}

The non-positional arguments can be specified in a regular way after the positional ones. For example:

{{ roll_chart 288 cols:1 }}

Functions can have more than one positional arguments. For example, the concat function uses the two parameters, left and right, to specify the two items to concatenate into an array:

{% result = concat left:"apple" right:"banana" %}

Since the concat function supports two positional arguments, the preceding example can be rewritten as:

{% result = concat "apple" "banana" %}

The order of positional arguments matters. In the above example, the first argument is always interpreted as left and the second argument is interpreted as right.

The function documentation states which arguments can be used positionally.

Available Functions

Chartopia has built in functions to assist in common random generator tasks. This library will grow in time.

Stat block


Generates a stat block. The resulting object is enumerable, e.g. it can be used inside for loops or as a source for other functions that require enumerable objects.

Examples

{% stat_block = create_stat_block min_point:1 max_point:5 total_points:15 skills:"Brawn, Cunning, Presence, Agility, Intellect, Willpower" %}

{% stat_block = create_stat_block min_point:1 max_point:5 total_points:15 skills:["Brawn", "Cunning", "Presence", "Agility", "Intellect", "Willpower"] %}

{% stat_block = create_stat_block min_point:1 max_point:5 total_points:15 skills:["Brawn", "Cunning", "Presence", "Agility", "Intellect", "Willpower"] %}
{% for skill_point in stat_block %}
* {{skill_point}}
{% end %}
Parameters
  • total_points generated stat block points will sum up to exactly this number.
  • max_point maximum allowed points per skill.
  • min_point minimum allowed points per skill.
  • skills Can either be a string of comma separated list of skills, e.g. skill1, skill2, skill3, or an array. Note: only alphanumeric characters, underscore and spaces are allowed as skill names. Spaces after and before skill name will be stripped.

Each skill will be assigned a random number between min_point and max_point, the sum of all skills is equal to total_points.

Properties
  • Returned object has properties that correspond to skill names, e.g. {{stat_block.Willpower}}. If skill has a space, to access the skill use one underscore instead of spaces, e.g. {{stat_block.Amazing_willpower}}. Property names are case-sensitive. Additionally, it is possible to refer to skills by index, for example, {{stat_block.1}} corresponds to the first skill.
  • size number of skills.
Default rendering

By default all skills are rendered as a table, e.g. {{create_stat_block min_point:1 max_point:5 total_points:15 skills:"Brawn, Cunning, Presence, Agility, Intellect, Willpower"}} will render as:

Brawn Cunning Presence Agility Intellect Willpower
4 1 4 1 1 4
Positional arguments

None

Roll Chart


Rolls on the specified chart and returns a rolled row object. The parameters must include either id or name in order to identify a chart, but all others are optional.

Examples

{% rolled_row = roll_chart name:"Dragons" %}

{% rolled_row = roll_chart name:"Dragons" cols:"2" %}

Parameters

  • id chart id.
  • name chart name.
  • cols comma-separated list of columns to return, for example cols="1", cols="2, 4, 1", cols="1-3" or cols="3-5, 1, 2". The order of columns match the value given to this parameter.
  • filter only rows containing text that matches the value assigned to filter will be rolled upon.
  • filter_exact only rows where the text is identical to the value assigned to filter_exact will be rolled upon. NB: filter_exact will override filter if both are arguments.
  • filter_cols this parameter is used only if filter is specified and applies the filter only to columns specified by filter_cols. The format is the same as for cols.
  • dice specifies an exact row to return via either a constant, e.g. dice:1, or by a dice roll, e.g. dice:{2d12}. If the result of the dice roll is outside of the chart range, an empty value is returned.
    loops_allowed: by default, Chartopia shows an error in the event of too many loops. Setting loops_allowed to true will hide the error and return the result up to Chartopia's loop limit.
  • render_style by default, Chartopia will render a chart based on its rolled result formatting, which is set by the author of the chart. This can be overridden by using this attribute. Possible values are:
    • vertical: Each table cell from a rolled result is rendered with its column name and column data vertically down the screen.
    • vertical_no_col_names: Each table cell of the rolled result is rendered vertically down the screen with column names excluded.
    • horizontal: Each table cell from a rolled result is rendered across the screen as if like a sentence. The column name precedes the column data.
    • horizontal_no_col_names: Each table cell from a rolled result is rendered across the screen as if like a sentence. The column name is excluded.
Properties
  • size number of columns.
  • dice_val a comma-separated list of rows that the rolled row object corresponds to. If chart roll type is 'roll once on table', then dice_val corresponds to row number. If chart roll type is 'roll once per column', then dice_val corresponds to a comma-separated list of rows that were used to generate the rolled row object.
  • rolled_row.x returns a data object corresponding to the data at column x of a rolled row object. Indexing starts at 1. The object can be used directly like {% col = rolled_row.2 %}{{ col }} which will use the default rendering of the column and will display table cell content.
    • rolled_row.x.name the column name of the column at index x of the rolled result object.
    • rolled_row.x.value the data/value of the column at index x of the rolled result object.
  • rolled_row.column_name returns a data object corresponding to the data at the column with name column_name of a rolled row object. Columns can also be accessed by their name if they only contain alphanumeric characters, underscore symbol or spaces (all spaces will be replaced with an underscore symbol), e.g. if the first column has name "Col1", it can be accessed like rolled_row.Col1. If another column is named "my column", it can be accessed like rolled_row.my_column If a column has name "result!!!", such a column can only be accessed by its index.
    • rolled_row.column_name.name the column name of the column called column_name of the rolled row object.
    • rolled_row.column_name.value the data/value of the column called column_name of the rolled row object.
Default rendering

By default, the rolled row object will render identically to the CHART macro.

Positional arguments
  • id

Consumable List


Creates a list object that, whenever printed, will render a randomly selected item from the list, then remove that item from the list. If an item is attempted to be printed from an empty list, an error is raised.

If the source of items contains objects, getting the item from consumable list via print notation {{c}} will return a string representation of that object and not the object itself. The object can be retrieved via get property, for example: {% a = [[1,2], [3,4]]%}{% c = consumable_list items:a %}{{c.get.1}}

Examples

{% c = consumable_list items:"gold, silver, copper" %}

{% c = consumable_list items:["platinum", "gold", {ruby|pearl|sapphire}] %}

The object returned by the consumable list is enumerable and can be used inside a loop. In the example below, a random permutation of the items inside the consumable list will be printed.

{% c = consumable_list items:"gold, silver, copper" %}
{% for i in c %}{{i}}{% end %}

If before iterating over the consumable list inside the loop, an item is printed from the consumable list, the loop will print all remaining items. In the example below, a consumable list is created and an item is popped and print from it, then the remaining items iterated over.

{{ c = consumable_list items:"gold, silver, copper" }}
{% for i in c %}{{i}}{% end %}

If the consumable list is used to print an item after the loop, an error will occur because the loop will always remove all remaining items from the list.

{% c = consumable_list items:"gold, silver, copper" %}
{% for i in c %}{{i}}{% end %}
{{ c }}

It is possible to use a consumable list in another function that requires an enumerable as input. In the example below, the filter function returns a list of items from the consumable list that contain 0. The order of items is random since a consumable list stores a random permutation of the given source of items.

{% a = consumable_list [1, 10, 20, 3] %}
{% b = filter a 0 %}
{{b.size}} {{b.1}} {{b.2}}
Parameters
  • items Can be either a string of comma separated list of items, or an array. The array can contain any of the Chartopia data types.
Properties
  • get Gets the item from the consumable list as an object instead of a string.
Default rendering

The list object will render a randomly selected item from the list.

For example: {% c = consumable_list items:"gold, silver, copper" %}, if printed using {{c}} - {{c}} - {{c}} could result in rendering copper - gold - silver.

Positional arguments
  • items

Consumable List Loop


Creates a list object that, whenever printed, will render a randomly selected item from the list, then remove that item from the list. When the list is emptied, it is reset with the initial list's contents.

If the source of items contains objects, getting the item from consumable list via print notation {{c}} will return a string representation of that object and not the object itself. The object can be retrieved via get property, for example: {% a = [[1,2], [3,4]]%}{% c = consumable_list_loop items:a %}{{c.get.1}}.

Examples

{% c = consumable_list_loop items:"gold, silver, copper" %}

{% c = consumable_list_loop items:["platinum", "gold", {ruby|pearl|sapphire}] %}

Parameters
  • items Can be either a string of comma separated list of items, or an array. The array can contain any of the Chartopia data types.
Properties
  • get Gets the item from the consumable list as an object instead of a string.
Default rendering

The list object will render a randomly selected item from the list.

For example: {% c = consumable_list items:"gold, silver, copper" %}, if printed using {{c}} - {{c}} - {{c}} - {{c}} could result in rendering copper - gold - silver - gold.

Positional arguments
  • items

Get Chart


Creates a chart object that can be accessed as if it were spreadsheet data, but with the benefit of being able to roll on it, either in full or in part. The parameters to get_chart are almost the same as for roll_chart, but by default, printing the returned chart object will render its title only.

The object returned by get_chart is enumerable (see loops). This means that each row can be iterated over. Each table cell for a row can also be iterated over. For example, the following will print the column title (as bold) and rolled text for every table cell of every row in the chart with id 123.

{% row in get_chart id:123 %}
{% col in row %}
**{{col.name}}** {{col.rolled}}
{% end %}
{% end %}
Examples

{% my_chart = get_chart id:123 %}

{% my_chart = get_chart name:"Dragons" %}

{% my_chart = get_chart id:"Weapons" cols:"1-3,5" filter_cols:"1" filter:"Ranged" %}

Parameters
  • id chart id.
  • name chart name.
  • cols comma-separated list of columns to return, for example cols:"1", cols:"2, 4, 1", cols:"1-3" or cols:"3-5, 1, 2". The order of columns match the value given to this parameter.
  • filter only rows containing text that matches the value assigned to filter will be rolled upon.
  • filter_exact only rows where the text is identical to the value assigned to filter_exact will be rolled upon. NB: filter_exact will override filter if both are arguments.
  • filter_cols this parameter is used only if filter is specified and applies the filter only to columns specified by filter_cols. The format is the same as for cols.
  • dice specifies an exact row to return via either a constant, e.g. dice:1, or by a dice roll, e.g. dice:{2d12}. If the result of the dice roll is outside of the chart range, an empty value is returned.
  • render_style Overrides the default rendering style set by the owner of the chart. Refer to default roll result formatting.
  • loops_allowed by default, Chartopia shows an error in the event of too many loops. Setting loops_allowed to true will hide the error and return the result up to Chartopia's loop limit.
Properties
  • title The title/name of the chart.
  • name The title/name of the chart.
  • subtitle The subtitle of the chart.
  • image_url The url of the image used by the chart.
  • citation The citation of the chart.
  • owner The owner of the chart.
  • dice_type The dice that has been set to be used to roll on the chart.
  • row_count The number of rows in the chart.
  • column_count The number of columns in the chart.

An individual row object can be accessed using dot notation, e.g. my_chart.x where x is the row number (NB: row counting starts from one). An individual table cell can be accessed using my_chart.x.y where x is the row number and y is the column number (starting from one).

  • my_chart.x Returns a row object representing row number x. When rendered using the print notation, the raw data for that row will be printed using the default rendering set by the default row formatting for that chart, unless the render_style is set as a parameter to get_chart.
  • my_chart.x.y Returns a cell object representing the table cell at position (x, y) where x is the row number and y is the column number starting at one. When rendered using the print notation, the raw data for that table cell is used.
  • my_chart.x.rolled Returns the rolled result text of the xth row. Note that this result will be the same every time. When printed using the print notation, the default rendering set by the default row formatting for that chart will be used, unless the render_style is set as a parameter to get_chart.
  • my_chart.x.y.rolled Returns the rolled result text of the table cell at position (x, y) where x is the row number and y is the column number starting at one. Note that this result will be the same every time.
  • my_chart.x.column_name Returns a cell object representing the table cell at row x (starting from one) at the column name called column_name. If the column name has spaces, then an underscore will be required.
Default rendering

A chart object will render a random rolled result of the corresponding chart.
A row object will render raw text of that row using the default render style set for that chart.
A cell object will render raw text of that table cell

Positional arguments
  • id

Remove


Removes items from a given source of items at given positions.

Examples

{% result = remove source:["gold", "silver", "copper"] at:2 %}

{% result = remove source:["platinum", "gold", "ruby", {pearl|sapphire}] at:"1-2,4" %}

Parameter
  • source An enumerable from which to remove items, e.g. an array, result of get_chart or roll_chart. If a simple object is given as a source, e.g. just a string or a number, then it is interpreted as an array with a single item in it.
  • at Position or positions of items to remove. It can be a single number, a comma-separated list of positions, or a range of positions, for example "1,3,7-9". If the given position does not exist, it will be ignored.
Properties
  • result.x Returns an object contained at position x in source (where x starts at 1).
Default rendering

A randomly selected item from the list of items left in the source, or an empty string if all items were removed.

For example: {{remove source:["gold", "silver", "copper"] at:2 }}, will result in rendering gold or copper.

Positional arguments
  • source
  • at

Concat


Concatenates two items together into an array.

Examples

{% result = concat left:["gold", "silver", "copper"] right:"pearl" %}

{% result = concat left:"apple" right:"banana" %}

Parameters
  • left The left most item of the resulting concatenation. It can be a simple object, such as a string or number, or a complex object such as an array or entire chart.
  • right The right most item of the resulting concatenation.
Properties
  • result.x Returns an object contained at position x in the resulting concatenated array.
Default rendering

A random item selected from the list of items in the resulting concatenated array (where x starts at 1).

For example: {{concat left:["gold", "silver", "copper"] right:"dog"}}, will result in rendering either gold, silver, copper or dog.

Positional arguments
  • left
  • right

Range


Generates an array of numbers between the two given numbers, from and to, inclusive of to. When from is smaller than to, the generated array will, by default, increment by 1 until it reaches the value set by to. When from is greater than to, the generated array will, by default, decrement by 1 until the vale of to is reached.

A different increment can be set using step. An unreachable to value will result in a roll time error. step is always a positive number; the direction being determined by from and to.

Examples

{% result = range from:1 to:10 %}

{% result = range from:7 to:-2 step:0.5 %}

{% for i in range from:-6 to:{d12} step:2 %}
* {{i}}
{% end %}
Parameters
  • from The starting value of the generated array (range of values). This parameter is optional. The default value is 0.
  • to The end value of the generated array (range of values).
  • step The step amount. The default value is 1. The step must be a positive number.
Properties
  • result.x Returns number contained at position x in the generated range (where x starts at 1).
Default rendering

A random item from the list of numbers in the specified range.

For example: {{range from:2 to:10 step:5 }}, will result in rendering 2 or 7.

Positional arguments

None

Create chart view


Joins two given charts (or objects) together into a chart view that can be used later to roll on. The rows of the chart given by left parameter will be followed by the rows of the chart given by right parameter. The column headers are resolved based on the value of join parameter described below. The resulting chart view behaves like an any other chart, but only exists for as long as the generator requires it.

Examples

{% result = create_chart_view left:1 right:2 %}

{% result = create_chart_view left:"Chart 1" right:"Chart 2" join:"right" %}

{% result = create_chart_view left:[1,2,3,4] right:"Chart 2" join:"both" %}

Parameters
  • left The id or name of the left chart. The value could also be an array or a variable pointing to a chart view or an array.
  • right The id or name of the right chart. The value could also be an array or a variable pointing to a chart view or an array.
  • join The chart join mode. Possible values are:
    • left column names will come from the chart specified by the parameter, left. The joined chart view will have the same number of columns as the left chart, e.g. if the right chart has more columns than the left chart those columns will be ignored, and if the right chart has less columns than the left chart, then columns with empty values will be added.
    • right column names will come from the chart specified by the parameter, right. The joined chart view will have the same number of columns as the right chart, e.g. if the left chart has more columns than the right chart those columns will be ignored, and if the left chart has less columns than the right chart, then columns with empty values will be added.
    • both column names will come from both charts. The joined chart view will have the same number of columns as the maximum between right and left charts, e.g. if the left chart has more columns than the right chart, all columns will have the names from the left chart, and if the left chart has less columns than the right chart, then column names of the left chart will be used first, and the rest of the columns will have names from the right chart. None of the columns will be ignored.
  • dice_type The dice type. By default, the dice type of chart view will have linear probability.
Properties
  • row_count Total number of rows.
  • column_count Total number of columns.
  • dice_type The dice type.
  • result.x A row object representing row number x. When rendered using the print notation, the raw data for that row will be printed using the rendering set by the default row formatting for that chart.
  • result.x.y A cell object representing the table cell at position (x, y) where x is the row number and y is the column number starting at one. When rendered using the print notation, the raw data for that table cell is used.
Default rendering

Random rolled result of the created chart view. Every time the variable pointing to chart view is printed, it will roll on that chart, potentially rendering something different each time.

Positional arguments
  • left
  • right

Roll chart view


Rolls on the given source which could be a chart view, an enumerable such as array or rolled row or any domain language construction or data type such as an expression or a string.

Examples

{% chart = create_chart_view left:1 right:2 %}

{% result = roll_chart_view source:chart %}

{% result = roll_chart_view source:chart filter:"dragon" cols:"1-2" %}

{% result = roll_chart_view source:["{cat|dog}", "cat", "fluffy"] filter:"cat" %}

{% result = roll_chart_view source:{dog|maine coon} %}

{% result = roll_chart_view source:"My pet is a {dog|cat}" %}

Parameters
  • source any domain language construction or data type such as an expression, a string, an array, etc.

All other parameters are exactly the same as the roll_chart function, except id and name.

Properties

Properties are the same as for roll_chart function.

Default rendering

Random roll of the given source. Unlike the default rendering of create_chart_view, the variable pointing to the result of roll_chart_view will always hold the same value when printed.

Positional arguments
  • source

Filter


Returns a subset of items from an enumerable where items matching a pattern and mode are kept; those not matching the pattern and mode are removed.

For the opposite of filter, refer to exclude.

Examples

{% result = filter source:["cat", "dog", "parrot"] pattern: "cat"%}

{% result = filter source:[" fluffy cat", "fluffy dog", "parrot"] pattern:"fluffy" mode:"starts_with" %}

{% chart = get_chart id:288 %}
{% result = filter source:chart pattern: "Grenade"%}
{{result.size}}
{% chart = get_chart id:288 %}
{% result = filter source:chart pattern: "Grenade" cols:"1"%}
Parameters
  • source The object being filtered. It can be any enumerable object such as an array or chart.
  • pattern Pattern for filtering.
  • mode Specifies the way in which the pattern is compared against an item. Possible options:
    • contains - item is matched if the source item contains pattern (default mode)
    • exact - item is matched if the source item is the same as pattern
    • starts_with - item is matched if the source item starts with pattern
    • ends_with - item is matched if the source item ends with pattern
    • icontains - case insensitive version of contains mode
    • iexact - case insensitive version of exact mode
    • istarts_with - case insensitive version of starts_with mode
    • iends_with - case insensitive version of ends_with mode
  • cols Columns of the source item to match the pattern on. If the source item isn't a chart (e.g. an array), and cols is specified, the function will return an empty result. If the source item has columns (e.g is a chart) and multiple columns are provided (e.g. cols:"1,2,5-7"), then if at least one column value matches the pattern, the entire row will be matched.
Properties
  • result.size Returns total number of filtered items.
  • result.x A row object representing row number x. It depends on the source. If the source is a chart, then result.x will correspond to a chart row. If the source is an array, then result.x will correspond to an item in the array.
  • All of the non-enumerable properties of the source if any. For example, if the source was a chart obtained via get_chart function, then the filtered chart will also contain such properties as name and column_count (the same as the chart).
Default rendering

A random item selected from the list of items in the resulting filtered array.

For example: {{filter source:["gold", "silver", "copper"] pattern:"o"}}, will result in rendering either gold or copper.

Positional arguments
  • source
  • pattern

Exclude


Returns a subset of items from an enumerable where items matching a pattern and mode are removed.

For the opposite of exclude, refer to filter.

Examples

{% result = exclude source:["cat", "dog", "parrot"] pattern: "cat"%}

{% result = exclude source:[" fluffy cat", "fluffy dog", "parrot"] pattern:"fluffy" mode:"starts_with" %}

{% chart = get_chart id:288 %}
{% result = exclude source:chart pattern: "Grenade"%}
{{result.size}}
{% chart = get_chart id:288 %}
{% result = exclude source:chart pattern: "Grenade" cols:"1"%}
Parameters
  • source The object that will have items excluded/removed. It can be any enumerable object such as an array or chart.
  • pattern Pattern for exclusion.
  • mode Specifies the way in which the pattern is compared against an item. Possible options:
    • contains - item is matched if the source item contains pattern (default mode)
    • exact - item is matched if the source item is the same as pattern
    • starts_with - item is matched if the source item starts with pattern
    • ends_with - item is matched if the source item ends with pattern
    • icontains - case insensitive version of contains mode
    • iexact - case insensitive version of exact mode
    • istarts_with - case insensitive version of starts_with mode
    • iends_with - case insensitive version of ends_with mode
  • cols Columns of the source item to match the pattern on. If the source item isn't a chart (e.g. an array), and cols is specified, the function will return an empty result. If the source item has columns (e.g is a chart) and multiple columns are provided (e.g. cols:"1,2,5-7"), then if at least one column value matches the pattern, the entire row will be matched.
Properties
  • result.size Returns total number of remaining items after exclude has been applied.
  • result.x A row object representing row number x. It depends on the source. If the source is a chart, then result.x will correspond to a chart row. If the source is an array, then result.x will correspond to an item in the array.
  • All of the non-enumerable properties of the source if any. For example, if the source was a chart obtained via get_chart function, then the post-exclusions chart will also contain such properties as name and column_count (the same as the chart).
Default rendering

A random item selected from the list of items in the resulting array after exclusions have been applied.

For example: {{exclude source:["gold", "silver", "copper"] pattern:"v"}}, will result in rendering either gold or copper.

Positional arguments
  • source
  • pattern

Unique


Returns an array of randomly selected unique items from a given source. The maximum number of unique items is limited to 1000. If the given number of unique items cannot be generated, an error will appear during roll.

For enforcing a constraint whereby a row is only selected once, refer to unq_rows

Examples

Returns an array of two unique items from a list of four items.
{% result = unq source:["cat", "dog", "parrot", "cat"] count:2 %}

Returns an enumerable of ten unique row objects from the chart with id 288.

{% chart = get_chart id:288 %}
{% result = unq source:chart count:10 %}
{{result.1}}

Returns an enumerable of potentially two to twelve unique row objects from the chart with id 288. The results are then looped through and rendered as a bullet point list.

{% chart = get_chart id:288 %}
{% result = unq source:chart count:{2d6} %}
{% for item in result %}
* {{ item }}
{% end %}
Parameters
  • source The object to select unique items from. It can be any enumerable object such as an array or chart.
  • count The number of unique items.
Properties
  • result.size Returns the total number of unique items.
  • result.x An object representing the xth item in the returned results; the type of object depends on the source. If the source is a chart, then result.x will correspond to a chart row; if the source is an array, then result.x will correspond to an item in the array.
Default rendering

A random item selected from the resulting array of unique items.

Positional arguments
  • source
  • count

Unique Rows


Returns an array of random results from a given source, but where each row of the source can only be used once. The constraint of ensuring a row is only used once means that it is possible for the resulting array to contain identical items, so long as they correspond to different rows of the source. The maximum number of unique rows is limited to 1000. If the given number of unique rows cannot be generated, an error will appear at roll time.

unq_rows is different to unq in that the focus is on ensuring uniqueness only of rows in a table (or items in an enumerable) instead of uniqueness of the final results, therefore it's possible for the resulting array to have duplicate results.

Examples

Returns an array of two unique rows from a list of four items. Since cat appears twice in this array, the resulting array might contain cat twice.
{% result = unq_rows source:["cat", "dog", "parrot", "cat"] count:2 %}

Returns an enumerable of ten unique row objects from the chart with id 288. The content of each such row can be identical as long as they correspond to different rows of the chart with id 288.

{% chart = get_chart id:288 %}
{% result = unq_rows source:chart count:10 %}
{{result.1}}
Parameters
  • source The object to select unique rows from. It can be any enumerable object such as an array or chart.
  • count The number of unique rows.
Properties
  • result.size Returns the total number of selected items.
  • result.x An object representing the xth item in the returned results; the type of object depends on the source. If the source is a chart, then result.x will correspond to a chart row; if the source is an array, then result.x will correspond to an item in the array.
Default rendering

A random item selected from the resulting array of selected items corresponding to unique rows.

Positional arguments
  • source
  • count

Join


Joins a list of items using a provided separator. The result of a join is a simple string. If a separator is not specified, then a comma is used by default.

Examples

Joins the contents of an array together, separated by a comma (the default), and saves the resulting string to a variable called result, which is then printed.

{% result = join source:["cat", "dog", "parrot", "cat"] %}
{{result}}

Joins the contents of an array together, separated by a custom string ->, then prints. This is done with a single command.
{{join source:["cat", "dog", "parrot", "cat"] sep:"->"}}

Rolls 4d3 random items from a loot table, adds them to an array, then uses join to print the resulting items as a Markdown bullet point list.

{% items = [] %}
{% for i in range to:{4d3} %}
{% item = roll_chart id:288 %}
{% items = join left:items right:item %}
{% end %}
* {{join source:items sep:"
* "}}
Parameters
  • source The object items of which should be joined. It can be any enumerable object such as an array or chart.
  • sep Optional separator. By default, the separator is a comma followed by a space.
Default rendering

The resulting joined string.

Split


Splits a given string into a list of strings using a provided separator. If a separator is not specified, then a comma is used by default.

Examples

Splits the contents of a string, separated by a comma (the default), and saves the resulting strings to an array called result, the elements of which are then printed.

{% result = split source:"cat,dog,parrot" %}
{{result.1}} and {{result.2}} and {{result.3}}

Splits the contents of a string by a custom separator ->.

{% result = split source:"cat->dog->parrot" sep:"->"%}
{{result.1}} and {{result.2}} and {{result.3}}

Rolls on a chart and splits the result. Note that if the chart's default rendering contains a column header, the header will be part of the split string.

{% rolled_result = roll_chart id:288 %}
{% result = split source:rolled_result %}
{{result}}

Rolls on a chart and splits the result. The example below uses rolled_result.1 (the first column of the rolled result) as a source, which prevents the column header from being part of the split string.

{% rolled_result = roll_chart id:288 %}
{% result = split source:rolled_result.1 %}
{{result}}
Parameters
  • source The string to be split into an array of strings.
  • sep Optional separator. By default, the separator is a comma.
Default rendering

A random item selected from the resulting array of split strings.

Positional arguments.
  • source
  • sep

Lower


Converts the given input to lower case.

Examples
{{ lower "Fluffy CAT" }}
{{ lower {CAT|Dog} }}
{{ lower input:{CAT|Dog} }}
Parameters
  • input The input string to convert to lower case. The input can be any valid domain language construct such as a string, expression, array or variable. When an array is used as the input to the lower function, a random item will be selected first, then transformed to lower case.
Default rendering

The input string converted to lower case.

Positional arguments
  • input

Upper


Converts the given input to upper case.

Examples
{{ upper "Fluffy CAT" }}
{{ upper {CAT|Dog} }}
{{ upper input:{CAT|Dog} }}
Parameters
  • input The input string to convert to upper case. The input can be any valid domain language construct such as a string, expression, array or variable. When an array is used as the input to the upper function, a random item will be selected first, then transformed to upper case.
Default rendering

The input string converted to upper case.

Positional arguments
  • input

Title


Converts the given input to title case.

Examples
{{ title "Fluffy CAT" }}
{{ title {CAT|Dog} }}
{{ title input:{CAT|Dog} }}
Parameters
  • input The input string to convert to title case. The input can be any valid domain language construct such as a string, expression, array or a variable. When an array is used as the input to the title function, a random item will be selected first, then transformed to title case. If the input string contains at least one upper case letter, it won't be converted, for example, "ABC" will remain "ABC" and "CaSe" will remain "CaSe". If this is not desired the input string should be converted to lower case first, and then to title case as shown below.
{{ "Fluffy CAT" |> lower |> title }}
Default rendering

The input string converted to title case.

Positional arguments
  • input

Sntce


Converts the given input to sentence case, i.e. the first letter of the first word is converted to upper case.

Examples
{{ sntce "Fluffy CAT" }}
{{ sntce {CAT|Dog} }}
{{ sntce input:{CAT|Dog} }}
Parameters
  • input The input string to convert to sentence case. The input can be any valid domain language construct such as a string, expression, array or a variable. When an array is used as the input to the sntce function, a random item will be selected first, then transformed to sentence case.
Default rendering

The input string converted to sentence case.

Positional arguments
  • input

Trim


Trims (removes) whitespace from the beginning and end of a given string.

Examples
{{ trim "  Fluffy cat  " }}
{{ trim { cat|dog } }}
{{ trim input:{ cat|dog } }}
Parameters
  • input The input string to trim whitespace. The input can be any valid domain language construct such as a string, expression, array or variable. When an array is used as the input to the trim function, a random item will be selected first, then trimmed.
Default rendering

The input string with trimmed whitespace.

Positional arguments
  • input

Ltrim


Trims (removes) whitespace from the beginning of a given string.

Examples
{{ ltrim "  Fluffy cat  " }}
{{ ltrim { cat|dog } }}
{{ ltrim input:{ cat|dog } }}
Parameters
  • input The input string to trim whitespace from the beginning of. The input can be any valid domain language construct such as a string, expression, array or variable. When an array is used as the input to the trim function, a random item will be selected first, then trimmed.
Default rendering

The input string with whitespace removed from the beginning.

Positional arguments
  • input

Rtrim


Trims (removes) whitespace from the end of a given string.

Examples
{{ rtrim "  Fluffy cat  " }}
{{ rtrim { cat|dog } }}
{{ rtrim input:{ cat|dog } }}
Parameters
  • input The input string to trim whitespace from the end of. The input can be any valid domain language construct such as a string, expression, array or variable. When an array is used as the input to the trim function, a random item will be selected first, then trimmed.
Default rendering

The input string with whitespace removed from the end.

Positional arguments
  • input

A vs An


Prepends an indefinite article to a given word. This works for the English language only.

Examples
{{ a_an "cat" }}
{{ a_an {apple|banana} }}
{{ a_an input:{apple|banana} }}
Parameters
  • input The input string to prepend with an indefinite article. The input can be any valid domain language construct such as a string, expression, array or variable. When an array is used as the input to the a_an function, a random item will be selected first, then prepended with an indefinite article.
Default rendering

The input string prepended with an indefinite article.

Positional arguments
  • input

If true


Given an expression, returns the left most statement if the expression evaluates to true, otherwise it returns the rightmost statement. The if_true is an alternative to if/else code blocks, and are appropriate for shorter condition checks.

The if_true function is similar to the ternary operator used in other programming languages.

Examples

In the examples below "he" will be printed because the variable, gender, is male.

{% gender = "male" %}
{{ {gender == "male"} |> if_true then:"he" else:"she"}}
{% gender = "male" %}
{{ {gender == "male"} |> if_true "he" "she"}}

The else parameter is optional; it is an empty string by default. In the example below, since the variable gender is not female, and the else parameter is not given, nothing will be printed.

{% gender = "male" %}
{{ {gender == "female"} |> if_true then:"she"}}
{% gender = "male" %}
{% result = if_true {gender == "male"} "he" "she"}

Complex objects can be used too, as shown below.

{% result = if_true {{d6} > 2} [1,2,3] [4,5,6] %}
{{ result.size }} - {{ result.1 }}
Parameters
  • condition The condition expression.
  • then The object that is returned when the condition is true.
  • else The object that is returned when condition is false. This parameter is optional. It is set to empty string if it is not given.
Default rendering

The default rendering string of the object returned by the function.

Positional arguments
  • condition
  • then
  • else

Plural


Given a singular word, the function returns its plural form.

Examples

{{ "cat" |> plural }}

The plural function can take an optional second argument, count, that represents a quantity. If count is equal to one, then the input word is not pluralized. In the examples below, the text cat will be printed.

{{ "cat" |> plural 1}}
{{ "cat" |> plural "one"}}

If the number is not equal to one, then the word will be pluralized. In the examples below, cats will be printed.

{{ "cat" |> plural 10}}
{{ "cat" |> plural "ten"}}

In practice, count will likely be a variable that may or may not be equal to one. This may affect multiple words, such as the following example where consideration must be made for is/are and cat/cats.

{% num_cats = {d3} %}
There {{"is" |> plural num_cats}} {{num_cats}} {{ "cat" |> plural num_cats }}.
Parameters
  • input An input word in singular form. If the word is plural already, the result of the function is undefined and likely incorrect.
  • count An optional count/quantity. When count is equal to one the input string remains unmodified. In all other cases it gets pluralized; this includes floating point numbers, negative numbers and zero.
Default rendering

The plural form of the input string.

Positional arguments
  • input
  • count

Data Blocks


A data block is an alternative format for creating an array. The advantage is that there is no need for comma separation between entries, or double quotes around strings. This allows for a more list-like syntax, akin to a single column subtable. The example below creates a data block comprising three items that can be accessed via the variable items.

{% data_block items %}
{apple|strawberry}
banana
carrot
{% end %}

The variable items is an array of 3 elements where each element can be accessed by an index, e.g. items.1. The size of the array can be queried using items.size. By default, printing an array will randomly select an item from it and print it, for example, {{items}} might print {apple|strawberry}, banana or carrot. If the rolled result needs to be saved to a variable for later, then the roll_chart_view function can be used, e.g. {% result = roll_chart_view source:items %}.

It is important to note that printing a specific item from the data block, e.g. {{items.1}} will print the raw text of that item, e.g. {apple|strawberry}; it won't roll the element. In order to roll on a specific element in the data block use the roll_chart_view function like so {{roll_chart_view source:items.1}}. i.e. the item has to be used in an array.

Each item inside a data block can be arbitrarily complicated. It can even contain a nested data block inside. All complicated structures such as loops, data blocks, conditionals or even expressions that span multiple lines are treated as a single item of the data block. The example below shows a data block with three items where the first item is an expression that contains multiple lines, the second item is a for loop and the third item is a complex string with a combination of macros and functions.

{% data_block items %}
{apple|strawberry with
new line
and another new line}
{% for i in [1,2,3] %}
{{i}}
{% end %}
Fluffy cat was walking in the CHART("Location") and hoping to find another cat with {{consumable_list items:"green, brown, gray"}} eyes
{% end %}

The variable that stores a data block can be used as any other variable, so it must be created before it is used, otherwise an error will appear at roll time. That variable cannot be used inside the data block it is supposed to store; doing so will also result in an error at roll time.

Row weighting

Each entry in a data block can be assigned a weight in order to change the probability of it being rolled. This is done with a caret symbol (^) followed by a numeric value. When an explicit weight is omitted, the weight is 1.

The example below shows simple weights being applied to two of the three entries; apple has the weight of 10, banana has the weight of 3, and carrot has the default weight of 1.

{% data_block items %}
apple^10
banana^3
carrot
{% end %}

The following example shows more complicated scenarios where weights are determined either from variables, or calculated as part of an expression. It's possible to prevent an entry from being rolled by giving it a weight of zero.

{% a = 100 %}
{% b = {5 + 10} %}

{% data_block items %}
apple^{{a}}
banana^{$b}
carrot^{{$a} + 200}
strawberry^{{ {a == 100} |> if_true 1 0 }}
blueberry^{1|2|5}
{% end %}

Advanced Object Property Usage

Object properties were introduced in the stat-block function example. Many chart objects have properties associated with them, and are accessed using dot notation e.g. object.property

To demonstrate some advance usage of properties, let's consider an array that is populated with some dice values.

{% my_array = [{d4}, {d6}, {d8}, {d10}, {d12}] %}

The variable called my_array holds 5 different random values and each can be accessed using dot notation, e.g my_array.1 will access the first value from the array, which is the result of a d4 dice roll.

How you decide to use that property though, decides the syntax required.

Properties within code blocks

If using within code blocks, then it's recommended to use the variable and its property natively. For example, if assigning the d4 to another variable, use

{% my_d_four = my_array.1 %}
{{my_d_four}}
Properties within expression notation

If you wish to use the variable within expression notation, for example to render an equation, then the $ symbol will be required.

{3 * {$my_array.1})}

When the property is a variable

If the property itself was determined by a random number, then that can be used with the $ prefix to access the value at that index in the array.

{% index = {d5} %}
{{my_array.$index}}
Properties within macro notation

If you want to use the value of one of the indices to be used to retrieve an exact row from a chart using the chart macro, then the $ prefix will be used for the variable itself.

CHART(name="Threats", dice="{$my_array.1}")

Notice that in this example, the variable and its property are being rendered to text, inserted between the quotes of the dice argument, then used in the chart macro.

Comments

Comment blocks are useful for describing aspects of the code, and are ignored when generating a result. The notation is as follows: {# comment goes here #}.

The comment block can be across multiple lines.

{#
comment goes here
...and here.
#}

Pipe Notation

The Chartopia Domain Language supports the concept of pipes, which is a syntax written linearly, left to right, whereby the output of a function flows into the next function as an input.

Pipes are a common functional programming technique present in many programming languages.

A common operation for a pipe would be to take a string of comma-separated items, split it, then re-join them again using a different separator. In Chartopia, a non-pipe way to achieved this would be to do the following:

{% my_fruit = "apple, banana, orange"%}
{% my_fruit = split my_fruit ", " %}
{{ join my_fruit "->" }}

To achieve the same result with pipes, the following can be be used:

{% my_fruit = "apple, banana, orange "%}
{{ my_fruit |> split ", " |> join "->" }}

In the example above, the my_fruit string is created first, then is used as the input of a split function. The pipe operator, |>, indicates the left to right flow. The split function defines the separator ", " to create an enumerable of the three fruits, which then flows through the next pipe operator into the join function. The join function takes the enumerable of fruit items and creates a new string using the custom separator ->. The result of executing this pipe will be apple->banana->orange.

Only functions that support positional arguments can be used with pipes because the first argument acts as the input to a piped function. The remaining arguments are listed after the function name (if required). If the function supports more than one positional argument, then they can be listed straight after the function name. For example, the concat function has two positional arguments left and right that can be used with a pipe as follows:

{{ [1,2,3] |> concat [4,5] }}

Non-positional arguments are written in the same way they are used in regular functions:

{{ 288 |> roll_chart filter:"Mask" }}

The functions used for pipes are typically very simple, but the power comes from piping (chaining) multiple functions together:

{{ 288 |> get_chart render_style:"horizontal_no_col_names" |> filter "Mask" |> join "; " }}

The example above gets the chart with id 288 and renders to a style that ensures there are no column names. This chart is then filtered using the given pattern, Mask. The filter function returns an enumerable, in this case a list of all rows that have "Mask" in it, which is then joined into a string using a semicolon as a separator.

Whitespace Control

The Chartopia domain language's code blocks and print statements keep whitespace by default, including spaces, tabs, carriage returns (\r) and newlines (\n), but sometimes it's desireable to control how space it utilised.

Whitespace can be stripped before and/or after code blocks, print notation and comments with the addition of a hyphen: {%- ... -%} and {{- ... -}} {#- ... -#}.

In the following example, the code block will be rendered as an empty line on account of it being on a different line.

{% character = "Obi-wan" %}
Hello
{% if character == "Obi-wan" %}
there
{% end %}

The raw outputted result will be the following.


Hello

there

Assuming the raw output is Markdown, rendering the Markdown to HTML will result in the following.

<p>Hello</p>
<p>there</p>

The next example adds hyphens to control the whitespace, resulting in the text collapsing to a single line.

{% character = "Obi-wan" -%}
Hello
{%- if character == "Obi-wan" -%}
there
{%- end %}

However, note that this will remove all the spaces.

Hellothere.

The solution can be slight rearrangement of the newlines, e.g.

{% character = "Obi-wan" -%}
Hello {% if character == "Obi-wan" -%}
there
{%- end %}

or by explicitly adding a space inside some curly braces, e.g.

{% character = "Obi-wan" -%}
{Hello }
{%- if character == "Obi-wan" -%}
there
{%- end %}

Whitespace and Markdown

Chartopia uses github flavoured Markdown as its preferred markup language, so multiple line breaks are ignored as per the Markdown specification. For the purposes of a webapp, the Markdown output is ultimately rendered to HTML, but on a mobile phone, the renderer will likely be native to the platform and not HTML. This is why Markdown is encouraged, because it's slightly more portable.

Note that Chartopia Domain Language code doesn't have to use HTML, it could use LaTeX, HTML or any other markup language, but Chartopia's target platforms work well with Markdown.

Other (deprecated)

Other usable macros are presented below. These are now deprecated and it's recommended to use the newer syntax.

  • EQN(12) Returns 12 - Superceded by {12}
  • EQN(d12) Roll d12 dice - Superceded by {d12}
  • EQN(2d12) Roll d12 dice twice and sum up the result - Superceded by {2d12}
  • [apple;pear;apricot] Roll d3 dice on the rollable list of apple, pear and apricot - Superceded by {apple|pear|apricot}
  • [1:apple; 2-3:pear; 4-8:apricot] Roll d8 dice on the rollable list of apple, pear and apricot. Dice value 1 will return apple, dice value between 2 and 3 will return pear and dice value between 4 and 8 will return apricot. - Superceded by {1?apple|2-3?pear|4-8?apricot}
  • AGGR(2d10,[apple;pear;apricot]) Roll d3 dice on the rollable list of apple, pear and apricot, then do this 2d10 times. Identical results will be aggregated - Superceded by AGGR(2d10,{apple|pear|apricot})