The chat box accepts normal messages, dice expressions, commands, and
small scripts.
Chat Commands
Before a message is sent, the client parses the text into structured chat
commands. If a line is not recognized as a command or dice expression, it
is sent as normal text. Multiline input is parsed as one script, so
commands like name and /color affect later lines in the
same input.
The current commands are:
Most commands also accept a leading / for muscle memory, but the
examples below use the preferred form without it. Style commands are the
exception: they require / because words like big and
bold are too likely to start normal chat text.
Roll
roll, r, /roll, /r, or any line of
text that can be successfully parsed as a dice expression.
The server parses the command as a dice expression, rolls the dice and
displays the result.
Shuffle
shuffle, shuf, shuff stuff
(/sh also works with a slash)
The text after the shuffle is split on whitespace (although quoted text
is treated as a single thing) and then shuffled. The result is then sent
back. This is useful for if you need a random order of some things.
Choose
choose stuff
(/ch also works with a slash)
The text after the choose is broken up the same way as with the shuffle
command. One of them is chosen and sent back.
Table
table tablename
(/tab and /t also work with a slash)
The named table is looked up and rolled on (which can trigger a roll on
a different table). The result is then sent back. See
tables.
MyTable
mytable tablename
Like table, but rolls on one of your private tables.
Name
name some name
(/n also works with a slash)
Your chatname is temporarily changed to the given name for display
purposes in this collection of lines.
Chat
Any general text.
Not really a command, but here for completeness's sake. Just send some
text.
Say
say some text
(/s also works with a slash)
Says the text, without trying to parse it as a die roll.
Comments
# comment text
A # starts a comment in most contexts.
# This line is ignored.
bonus = 4 # favored terrain
d20 + bonus
Style
/color red
/bold
/italic
/underline
/big
/box or /boxed
/anon
/reset
Applies a style to the rest of the chat commands in the current
macro/multiline input. Color can be a valid CSS color.
bold, italic, underline, big, boxed and anon are all toggles.
Issuing them a second time will turn them off.
Reset will clear all currently applied styles.
Unlike other commands, multiple styles can be applied at once. For example:
name Jon
/color red bold italic
Danger!
/reset
This is plain.
which will make the "Danger!" red, bold and italic.
Jon:Danger!
Jon:This is plain.
Macro Processor
Now for the extra functionality. A preprocessing step interprets the
input, resolves variables and control flow, and sends the resulting
commands. This applies to saved macros and to a single
submitted chat input, so a multiline chat message can define variables
and use them on later lines. We'll refer to a multiline-chat message or anything
more than just some basic text or basic roll as a script.
Example
Here's an example, we will then explain afterwards.
bonus = 4
attack = d20 + bonus
roll attack
I'll break it down line by line.
bonus = 4
The above creates a script variable, setting it to 4. Assignment
statements are "identifier" "=" "whatever stuff". Script variables
last for this one submitted chat input or macro run.
attack = d20 + bonus
The above also creates a script variable, named attack. This one
indirectly references the script variable we created before. When it
comes time to use this variable, multiple expansions will need to
happen. I'll explain that in a second.
roll attack
The above is a roll statement, so we try to replace any terms we can
with known variables. After the first substitution, we end up with:
roll d20 + bonus
There is still a variable in this statement, so it is substituted again.
roll d20 + 4
which is the final line. This line is what will end up being sent to the
server.
Variables only have to be defined when you get to actually substituting
them. This means that we could have written the above as:
attack = d20 + bonus
bonus = 4
roll attack
As variables are lazily substituted, this just works.
Variables are case insensitive. These lines are the same:
roll attack
roll ATTACK
roll Attack
Variables can contain spaces. They cannot contain two consecutive spaces.
Power Attack = 3
roll d20 - Power Attack
In a multi-word variable, the first word cannot be one of the following
as they are used to start commands.
roll
rolll
rll
rol
rl
ro
r
name
n
shuffle
shuff
shuf
sh
choose
ch
table
tab
t
mytable
say
s
color
colour
bold
italic
anon
reset
underline
underlined
box
boxed
big
Expressions
To understand how the system works, it is important to understand what
is an expression for a roll command, in descending precedence.
Dice literal, for example "3d6" or "d20".
Integer literal, for example "3" or "42".
Variable, such as "attack" above.
Parenthesized group, like "(3 + d6)" or "(2*3)."
Spreadsheet expression, like "[cell('Draclar', 'Score', 2)]".
Repeated group, like "3(d20+4>=20)".
Unary operations, like "!4" or "-d6". The unary
operations are "!" (not, turns 0 to 1 and all other values
to 0), "-" (negative), and "+" (which does
nothing).
Multiplication and division, like "3 * 3d6", or
"attack/2".
Addition and subtraction, like "d20+4", or "d6 -
1".
Comparisons, like "d6 == 1" or "d10 <= 2". The
comparison operators are "=", "<", "<=",
">", ">=", "!=".
When substituted, variables are implicitly grouped. This means that
something like:
x = 3 + 2
roll 3*x
will evaluate to 15, as you would expect.
Integer literals are always positive, but since unary operations are
high enough precedence, "-4 + 2" works in the normal way,
producing -2.
Parenthesized vs Repeated groups
A parenthesized group can be anywhere in an expression and is just
for changing precedence. A repeated roll must always start with an
integer and is for evaluating the parenthesized group multiple times,
summing their results.
Rounding
As per the usual rules of rpgs, if you are left with a fractional
result, that result is rounded down. That is still ambiguous, so to be
explicit, rounding will occur at these times:
Before adding, subtracting, or comparing two values.
The final total will be rounded.
This basically works as you would expect, but gives a couple non-obvious
results.
# This produces 2
roll 2/3*3
# This produces 0, left side is
# rounded down to 1, which is not
# greater than 1
roll 3/2 > 1
# This produces 2, as the left side of
# the plus and the right side of the
# plus are both rounded to 1.
roll 3/2 + 3/2
This means that division is not distributive. It is associative.
Rounding is truncation towards 0.
roll -3/2 # produces -1
Grouped Variables
It's annoying to have to define all your variables in every script,
especially when they are values you'll want to use in many places, like
your strength bonus or your base attack bonus. To help with this, you
can define variables in 3 places outside of a script's body:
Attached to the macro (a macro-local variable).
Attached to the macro group (a group variable).
In the special "globals" group (a global variable).
Each of these locations can have any number of variables.
A macro-local variable is always visible in that saved macro, but
cannot be accessed from other macros.
A group variable is visible to macros in that group, but can also be
accessed from other groups via a "dotted" identifier or by a
use or using statement.
A global variable is visible to all macros.
If these variables conflict, the first in the list is used:
Script variables defined in the submitted chat input or saved macro
body (from x = 3 for example).
Variables introduced via use or using are also at
this level.
Macro-local variables.
Group variables.
Global variables.
Not only are these variables accessible in a macro, they are also
available in the chat box. You can select which group is active by
clicking on its tab above the chat. The command from the chat box is
then treated as if it were a macro in that group for the purpose of
variable visibility.
Dotted Identifier and Use
Imagine you have a variable group named Yowa which has
bab as 3 and dex as 2c.
An example of a dotted identifier is as follows:
attack = d20 + Yowa.bab + Yowa.dex
roll attack
In the above example, bab and dex were explicitly
accessed from the Yowa variable group. The above substitutes
to:
roll d20 + 3 +2
This can get pretty repetitive, so to bring all of the variables from a
variable group into the local context, you can use the use or
using statement.
You can then do this:
use Yowa
attack = d20 + bab + dex
roll attack
In the above example, all of the variables from Yowa will then be
available and roll attack substitutes to:
roll d20 + 3 + 2
Variable groups are also case insensitive.
Variable Kinds
There are four kinds of variables that can be defined.
These are pretty straightforward, they are negative or positive
integers.
Boolean Variables
These variables can only take the value of true or false, which are
treated as 1 and 0 respectively.
Expression Variables
These variables are stored as strings, but they must succesfully parse
as an expression in order to be used. You can still take advantage of
lazy evaluation of variables. For example, "d20 + attack" is
a legal expression, but "d20 +" is not as there is no postfix
"+" operator and so it is an incomplete add expression,
missing the right hand side.
Expression variables are very powerful due to the lazy evaluation.
Globally defined expression variables can thus refer to locally
defined variables in your macros.
You can think of these variables as formulas.
Ability Score Variables
These are the same as number variables, but their actual value is the 3.5
ability score modifier that number would produce. For example, a
17 would be treated as a 3 in macros.
Choice Variables
These are like expression variables, but instead of a string you edit,
you choose one from a list of strings. You can define this list.
Prompt Command
prompt or /prompt prompts for a value
and stores that value in the variable before later lines run.
prompt power attack
d20 + attack - power attack
damage + power attack * 2
Set Command
set or /set updates a saved variable without opening
a prompt. Like prompt, it stores the value before later lines
run.
set power attack 3
d20 + attack - power attack
You can also target a group explicitly with a dotted name:
set Yowa.power attack 3
Spreadsheet Expression
Chat and macros can read from spreadsheets. For normal chat and macros,
the active macro tab chooses the spreadsheet context: if the
active macro tab is named Yowa, the macro processor looks for a
spreadsheet named Yowa.
Bare identifiers are resolved as macro variables first. If no macro
variable matches, the identifier is evaluated as a spreadsheet
expression in that active spreadsheet context. This is useful with named
cells. So you can have something like this:
d20 + bab
And if you have a spreadsheet named after your macro group (like
named after your character) and on that spreadsheet is a cell named
"bab" with the value of 2, then the above will be expanded into
d20 + 2
Square brackets evaluate a spreadsheet expression explicitly:
d20 + [str_mod + bab]
In the example above, str_mod + bab is evaluated by the
spreadsheet engine using the active matching sheet, and the result is
inserted into the roll expression. Macro variables can also be expanded
inside the brackets before the spreadsheet expression is evaluated.
sheet or /sheet changes the spreadsheet context for
the rest of the current chat input or macro run. It does not change
which macro tab is active.
sheet Garret
d20 + attack
d20 + [bab + str_mod]
Repeat Statements
You might need to roll certain dice multiple times and don't want to
just copy paste the command (as if you want to change it you'd have to
edit each line). To facilitate that, there is a repeat statement that
will execute the contents of it a certain number of times. It looks like
this:
repeat 4:
d20 + 3
Which will roll d20 + 3 four times, as four different
statements.
The 4 in the above example can also be a variable or an
expression. It cannot contain a dice expression and must evaluate to a
number. If it evaluates to a negative number or zero, the contents of
the repeat statement are executed zero times.
repeat can alternatively be spelled as loop or
times.
repeat blocks are capped at 20.
If Statements
The last major feature is conditional execution. This is done using
if and else. An example:
rapid = 1
if rapid:
roll d20 - 2
roll d20 - 2
else:
roll d20
The if statement is written as "if" "expression" ":". The
trailing colon is mandatory. Without it, it is considered a regular line
of text.
An expression evaluator is then run and if the result is non-zero, it is
considered "true". If it's true, then the indented statements after the
if are evaluated.
An if can have an else, which looks like in the above
example. The indented statements after the else are run if the
expression turned out to be false (0). An if doesn't have to
have an else. There's also else if.
With the if you can conditionally send roll commands and also
conditionally set variables. For example:
prone = 1
if prone:
penalty = 4
else:
penalty = 0
roll d20 - penalty
With all that, we can finally arrive at our final example which uses all
of these features:
name Yowa
use Yowa
attack = d20 + dex + bab
if rapid:
Rapid Attack!
roll attack - 2
roll attack - 2
else:
roll attack
No Dice in Ifs
Note! if conditions cannot contain dice expressions, directly or
indirectly.
Escaping
Rarely, you want to type something that looks like a roll expression,
but isn't, such as telling someone how to roll something:
To roll a strength check, type:
Roll d20 + str
Variable substitution and expression evaluation will be attempted on
this, which would be confusing as it would come out as "Roll d20 + 3" if
you had a str variable set to 3, which would then get rolled! To avoid
this, you can prefix with a "/say " which will cause the rest to be
processed as literal text. You can also use a leading backtick (`) to
the same effect. Do not use a trailing backtick.
/say Roll d20 + str
`Roll d20 + str
Generally, slash commands other than /roll are not substituted, so if
future slash commands are added there will be no problem.
The roll command has to succesfully parse as a dice expression in order
for substitution to get involved, so this is a pretty rare occurrence.
Chat Commands and Macros
The chat box accepts normal messages, dice expressions, commands, and small scripts.
Chat Commands
Before a message is sent, the client parses the text into structured chat commands. If a line is not recognized as a command or dice expression, it is sent as normal text. Multiline input is parsed as one script, so commands like name and /color affect later lines in the same input.
The current commands are:
Most commands also accept a leading / for muscle memory, but the examples below use the preferred form without it. Style commands are the exception: they require / because words like big and bold are too likely to start normal chat text.
Roll
roll, r, /roll, /r, or any line of text that can be successfully parsed as a dice expression.
The server parses the command as a dice expression, rolls the dice and displays the result.
Shuffle
shuffle, shuf, shuff stuff (/sh also works with a slash)
The text after the shuffle is split on whitespace (although quoted text is treated as a single thing) and then shuffled. The result is then sent back. This is useful for if you need a random order of some things.
Choose
choose stuff (/ch also works with a slash)
The text after the choose is broken up the same way as with the shuffle command. One of them is chosen and sent back.
Table
table tablename (/tab and /t also work with a slash)
The named table is looked up and rolled on (which can trigger a roll on a different table). The result is then sent back. See tables.
MyTable
mytable tablename
Like table, but rolls on one of your private tables.
Name
name some name (/n also works with a slash)
Your chatname is temporarily changed to the given name for display purposes in this collection of lines.
Chat
Any general text.
Not really a command, but here for completeness's sake. Just send some text.
Say
say some text (/s also works with a slash)
Says the text, without trying to parse it as a die roll.
Comments
# comment text
A # starts a comment in most contexts.
Style
Applies a style to the rest of the chat commands in the current macro/multiline input. Color can be a valid CSS color. bold, italic, underline, big, boxed and anon are all toggles. Issuing them a second time will turn them off. Reset will clear all currently applied styles.
Unlike other commands, multiple styles can be applied at once. For example:
which will make the "Danger!" red, bold and italic.
Macro Processor
Now for the extra functionality. A preprocessing step interprets the input, resolves variables and control flow, and sends the resulting commands. This applies to saved macros and to a single submitted chat input, so a multiline chat message can define variables and use them on later lines. We'll refer to a multiline-chat message or anything more than just some basic text or basic roll as a script.
Example
Here's an example, we will then explain afterwards.
I'll break it down line by line.
The above creates a script variable, setting it to 4. Assignment statements are "identifier" "=" "whatever stuff". Script variables last for this one submitted chat input or macro run.
The above also creates a script variable, named attack. This one indirectly references the script variable we created before. When it comes time to use this variable, multiple expansions will need to happen. I'll explain that in a second.
The above is a roll statement, so we try to replace any terms we can with known variables. After the first substitution, we end up with:
There is still a variable in this statement, so it is substituted again.
which is the final line. This line is what will end up being sent to the server.
Variables only have to be defined when you get to actually substituting them. This means that we could have written the above as:
As variables are lazily substituted, this just works.
Variables are case insensitive. These lines are the same:
Variables can contain spaces. They cannot contain two consecutive spaces.
In a multi-word variable, the first word cannot be one of the following as they are used to start commands.
Expressions
To understand how the system works, it is important to understand what is an expression for a roll command, in descending precedence.
When substituted, variables are implicitly grouped. This means that something like:
will evaluate to 15, as you would expect.
Integer literals are always positive, but since unary operations are high enough precedence, "-4 + 2" works in the normal way, producing -2.
Parenthesized vs Repeated groups
A parenthesized group can be anywhere in an expression and is just for changing precedence. A repeated roll must always start with an integer and is for evaluating the parenthesized group multiple times, summing their results.
Rounding
As per the usual rules of rpgs, if you are left with a fractional result, that result is rounded down. That is still ambiguous, so to be explicit, rounding will occur at these times:
This basically works as you would expect, but gives a couple non-obvious results.
This means that division is not distributive. It is associative.
Rounding is truncation towards 0.
Grouped Variables
It's annoying to have to define all your variables in every script, especially when they are values you'll want to use in many places, like your strength bonus or your base attack bonus. To help with this, you can define variables in 3 places outside of a script's body:
Each of these locations can have any number of variables.
A macro-local variable is always visible in that saved macro, but cannot be accessed from other macros.
A group variable is visible to macros in that group, but can also be accessed from other groups via a "dotted" identifier or by a use or using statement.
A global variable is visible to all macros.
If these variables conflict, the first in the list is used:
Not only are these variables accessible in a macro, they are also available in the chat box. You can select which group is active by clicking on its tab above the chat. The command from the chat box is then treated as if it were a macro in that group for the purpose of variable visibility.
Dotted Identifier and Use
Imagine you have a variable group named Yowa which has bab as 3 and dex as 2c.
An example of a dotted identifier is as follows:
In the above example, bab and dex were explicitly accessed from the Yowa variable group. The above substitutes to:
This can get pretty repetitive, so to bring all of the variables from a variable group into the local context, you can use the use or using statement.
You can then do this:
In the above example, all of the variables from Yowa will then be available and roll attack substitutes to:
Variable groups are also case insensitive.
Variable Kinds
There are four kinds of variables that can be defined.
Number Variables
These are pretty straightforward, they are negative or positive integers.
Boolean Variables
These variables can only take the value of true or false, which are treated as 1 and 0 respectively.
Expression Variables
These variables are stored as strings, but they must succesfully parse as an expression in order to be used. You can still take advantage of lazy evaluation of variables. For example, "d20 + attack" is a legal expression, but "d20 +" is not as there is no postfix "+" operator and so it is an incomplete add expression, missing the right hand side.
Expression variables are very powerful due to the lazy evaluation. Globally defined expression variables can thus refer to locally defined variables in your macros.
You can think of these variables as formulas.
Ability Score Variables
These are the same as number variables, but their actual value is the 3.5 ability score modifier that number would produce. For example, a 17 would be treated as a 3 in macros.
Choice Variables
These are like expression variables, but instead of a string you edit, you choose one from a list of strings. You can define this list.
Prompt Command
prompt or /prompt prompts for a value and stores that value in the variable before later lines run.
Set Command
set or /set updates a saved variable without opening a prompt. Like prompt, it stores the value before later lines run.
You can also target a group explicitly with a dotted name:
Spreadsheet Expression
Chat and macros can read from spreadsheets. For normal chat and macros, the active macro tab chooses the spreadsheet context: if the active macro tab is named Yowa, the macro processor looks for a spreadsheet named Yowa.
Bare identifiers are resolved as macro variables first. If no macro variable matches, the identifier is evaluated as a spreadsheet expression in that active spreadsheet context. This is useful with named cells. So you can have something like this:
And if you have a spreadsheet named after your macro group (like named after your character) and on that spreadsheet is a cell named "bab" with the value of 2, then the above will be expanded into d20 + 2
Square brackets evaluate a spreadsheet expression explicitly:
In the example above, str_mod + bab is evaluated by the spreadsheet engine using the active matching sheet, and the result is inserted into the roll expression. Macro variables can also be expanded inside the brackets before the spreadsheet expression is evaluated.
sheet or /sheet changes the spreadsheet context for the rest of the current chat input or macro run. It does not change which macro tab is active.
Repeat Statements
You might need to roll certain dice multiple times and don't want to just copy paste the command (as if you want to change it you'd have to edit each line). To facilitate that, there is a repeat statement that will execute the contents of it a certain number of times. It looks like this:
Which will roll d20 + 3 four times, as four different statements.
The 4 in the above example can also be a variable or an expression. It cannot contain a dice expression and must evaluate to a number. If it evaluates to a negative number or zero, the contents of the repeat statement are executed zero times.
repeat can alternatively be spelled as loop or times.
repeat blocks are capped at 20.
If Statements
The last major feature is conditional execution. This is done using if and else. An example:
The if statement is written as "if" "expression" ":". The trailing colon is mandatory. Without it, it is considered a regular line of text.
An expression evaluator is then run and if the result is non-zero, it is considered "true". If it's true, then the indented statements after the if are evaluated.
An if can have an else, which looks like in the above example. The indented statements after the else are run if the expression turned out to be false (0). An if doesn't have to have an else. There's also else if.
With the if you can conditionally send roll commands and also conditionally set variables. For example:
With all that, we can finally arrive at our final example which uses all of these features:
No Dice in Ifs
Note! if conditions cannot contain dice expressions, directly or indirectly.
Escaping
Rarely, you want to type something that looks like a roll expression, but isn't, such as telling someone how to roll something:
Variable substitution and expression evaluation will be attempted on this, which would be confusing as it would come out as "Roll d20 + 3" if you had a str variable set to 3, which would then get rolled! To avoid this, you can prefix with a "/say " which will cause the rest to be processed as literal text. You can also use a leading backtick (`) to the same effect. Do not use a trailing backtick.
Generally, slash commands other than /roll are not substituted, so if future slash commands are added there will be no problem.
The roll command has to succesfully parse as a dice expression in order for substitution to get involved, so this is a pretty rare occurrence.