Character Vault
Any Concept / Any System
Compendium
Your System Come To Life
Roll20 for Android
Streamlined for your Tablet
Roll20 for iPad
Streamlined for your Tablet

Personal tools

Difference between revisions of "Script:ScriptCards"

From Roll20 Wiki

Jump to: navigation, search
(Comment (--/))
(Comment (--/))
Line 123: Line 123:
 
</pre>
 
</pre>
  
Using this style will ''sometimes'' work:
+
Using this style will sometimes work, but is not recommended.
 
<pre>
 
<pre>
 
!script {{
 
!script {{
Line 136: Line 136:
 
}}
 
}}
 
</pre>
 
</pre>
But it's not recommended, because it can lead to unwanted behavior (like a mysterious line that appears on your output card, and only says: "IsRight").
+
Because it can lead to unwanted text appearing on your output card.
  
 
=== Set Parameter (--#) ===
 
=== Set Parameter (--#) ===

Revision as of 16:59, 28 September 2021

Introduction

ScriptCards provides a script interpreter that can be used to create powerful macros that display the results of player/NPC actions, or display other information in a pleasing visual format in your game's chat window. The scripting language contains variables (both dice-roll (enhanced numerics) and strings) as well, conditionals, branching, subroutines with parameters, and a set of built-in functions to simplify working with Roll20 information.

API ScriptAuthor: Kurt J.
Version: 1.4.0e
Last Modified: 2021-09-24
Dependencies: None
Conflicts: None

ScriptCards is not game-system specific, and can be used with any system/sheet. Near the end of this Wiki there is a section set aside for libraries that can implement system-specific tasks, with the hope that enthusiasts playing particular systems will create and share utility functions that can be utilized by the wider community.

The default display style for ScriptCards output is similar to the format used to document player and NPC abilities in Dungeons and Dragons 4th Edition, but does not have any system ties to D&D4E.

Current OneClick Version : 1.4.0e

Current Development Version : 1.4.4

Critically Important: ScriptCards does not use/parse inline rolls. ScriptCards includes its own built-in dice roll parser to allow for the use of variables inside dice rolls. As of version 1.2.3, ScriptCards will now take inline rolls and substitute the total result value in statement strings, meaning that you can utilize inline rolls but ScriptCards will only see the result of the roll, and not parse the roll components itself.


Contents

Is ScriptCards Related to PowerCards?

I (Kurt J.) have been maintaining and updating PowerCards for a couple of years now, and ScriptCards isn't an effort to supplant PowerCards, but rather represents my effort to address some of the most common issues that PowerCards users run into because of the intrinsic nature of the way PowerCards was conceived and developed over time. ScriptCards is more of a follow-up to PowerCards. Perhaps the most frequent question asked in the PowerCards thread on the forum is something along the lines of “how do I use the result of THIS roll in the roll I make two lines later?” Unfortunately, due to the architecture of PowerCards, this isn’t possible.

Besides this issue, there are various elements of a PowerCards macro that can’t support certain features. For example, you can’t set most card-wide settings (name, leftsub, rightsub) dependent upon the results of a dice roll, and while I’ve implemented a simple “skip forward” mechanism in PowerCards to allow for some flow control, true branching (forward and backwards) is not possible due to the way cards are processed. While it might be possible to rewrite some of the core of PowerCards to allow for implementation of (some) of these features, the result would be a very different script that would not be backwards compatible with the host of users currently using PowerCards in their games.

Instead, I have taken the approach of writing a completely new script from the ground up. There is very little (if any) of the original PowerCards code included in ScriptCards because I am fundamentally changing the way the macro is processed. Note that this isn’t a slight against the original author of PowerCards (Sky). The script has been widely used for years now, and is a testament to the flexibility of the original code that I was able to add so many features over the past two years.

By implementing ScriptCards as a new, separate script, those using PowerCards as it currently exists can continue to do so without interruption, while those interested in the functionality of ScriptCards can make use of its updated feature set. The two script (PowerCards and ScriptCards) can happily coexist in the same game, and do not interfere with each other in any way.

Check the What to Know if you are Coming from PowerCards-section for a comparison table between the two scripts.

What is a ScriptCard Script

A ScriptCard Script is text written into the chat window (either typed directly, pasted, or run via a macro) that will produce a card of information in the chat window. A ScriptCard Script is composed of an API command: !scriptcard {{ }} enclosing any number of lines that determine the output that will be added to the card. At it simplest, the following macro:

!scriptcard  {{ }}

Will produce just a title card that displays “ScriptCards” as the name:

Scriptcard blank.png

Of course, this is just the simplest type of macro and isn’t very useful. In order to produce useful output, we need to include lines between the {{ and }} that direct the API script as to what it should do.

Structure of a ScriptCard Line

All ScriptCard lines begin with two dashes, followed by an statement identifier character that lets ScriptCards what type of line it is. There are several of these, and they are detailed in the next section. After the line type identifier, a Tag name is supplied. This name is essentially free-form and CAN be omitted in the case of some line types. Also note that if you are used to using PowerCards, Tags in ScriptCards do not need to be unique.

Following the Tag is a vertical bar, and then the content of the line itself. Again, each type of line might interpret this content differently.

Identifier Statement Type Tag Content Notes
--/ Comment unused unused The --/ sequence is used to add comments to a script. No processing will take place on a --/ line, so the tag and comment can be freely used to add notes to your code.
--# Set Parameter Parameter name Desired parameter value Parameters generally control the behavior of large segments of the output card. Things like the Title of the card, the colors of the header and rows, etc. There are also parameters that control how various features of the card behave (like "usehollowdice").
--+ Direct Output Free Text - Is output in bold at start of the line. Output in normal text after Tag Direct Output statements are what creates row sections on the output card. A script without any direct output sections will end up looking similar to the sample at the start of this wiki (the !script {{ }} script) because all other statement types do not create output lines.
--= Assign Roll Variable Variable Name Roll Equation (or text) to assign Roll/Numeric variables are assigned with this command. The content will be processed as a dice roll, and various properties will be set along with the numeric results.
--& Assign String Variable Variable name Content to store in the string variable. Roll Variables and String Variables are completely separate entities, and can technically share names, but this would likely lead to confusion and should be avoided.
--@ API Call API ! Command API call parameters (replace -- with _) Other Roll20 API scripts can be called using this command. The Tag is the trigger command for the API script (i.e., !token-mod, or !setattr, etc.)
--: Branch Label Label Name Unused (Comments if desired) Branch labels are the destination for branch and procedure call statement types. The content portion of the statement is unused, though it is recommended to list parameter information here if you are writing a procedure that accepts passed parameters
--^ Branch To Label name to branch to Unused (Comments if desired) An unconditional branch to a label (--:). Execution of the script will jump to the line after the named label.
--> Call Procedure Label name to call Procedure parameter list semicolon (;) separated An unconditional procedure call. Execution will jump to the line after the named label, and a return statement (--<) will return execution to the line after the procedure call
--< Return from Sub Unused Unused (Comments if desired) The return statement returns execution to the most recent procedure call line. Note that the vertical bar is required for the statement to be complete.
--? Conditional Branch Condition to be evaluated True Branch Label|False Branch Label The condition will be evaluated and execution will jump to one of the two indicated branches (or simply continue to the next line if only a True branch is specified and the result is False). You can make the branch a procedure call by prefixing the label with a > symbol. In this case, you can included a semicolon separated list of parameters.
--s Store to Persistent Storage "settings", "rollvariables", or "stringvariables" Name of the data set to store (see save/load section below) This statement type (and the --l statement) still function, but it is recommended to use the storage mechanism in the --~ command instead.
--l Load from Persistent Storage "settings", "rollvariables", or "stringvariables" Name of the data set to store (see save/load section below) This statement type (and the --s statement) still function, but it is recommended to use the storage mechanism in the --~ command instead.
--v Create Visual Effect "token", "betweentokens", or "point" Tokens and parameters for generating the effect Visual effects are played on the page the token is on. "point" effects require Version 1.2.8+
--e Echo to Chat Name to send chat command as Chat message to send Variable substitution takes place on the tag and content.
--R Retrieve Repeating Section Row information "find", "first", or "next" Parameters for retrieving row information. See Referencing below Working with repeating section information on character sheets is possible without tracking row indexes ($0, $1, etc.) by using the --R statements.
--~ Assign a variable to the result of a built-in function Variable Name Parameters for function call ScriptCards includes a number of built-in functions for things like measuring distance, manipulating strings, etc. The type of variable that gets set (Roll or String) is dependent upon the function that is being called.
--c Case Statement Test Value Vertical bar separated list of cases, with the match:branchlabel format. Branch labels can be procedure calls by prefixing them with ">", and can contain parameters.
--i Information Request User Prompt;Button Caption InfoType;VariableName;ParameterText See full documentation below.
--d Data Statement  ! for data definition or StringVar for data read For definition lines, a semicolon separated list of data elements. Unused to read lines. Similar to BASIC read/data statements. --d! defines string data elements anywhere in your code. --dvarName reads the next data element into varName.
--% For...Next Loop Loop Counter for "For", empty for "Next" For "For", Start;End;Step, empty for Next See For...Next Loop documentation below. Allows you to create loops that will run a specified number of times with a loop counter.
--* GM Output Free Text - Is output in bold at start of the line. Output in normal text after Tag GM Output statements are whispered to the GM as a separate card after the output of the main card is completed. Their use is identical to the Direct Output statement (--+). If there are no GM Output statements in a card, no GM card will be whispered.

ScriptCard Statement Type Details

The sections below detail the individual statement types supported by ScriptCards

Comment (--/)

A --/ statement is ignored by the ScriptCards parser. You can use this type of statement to add comments and informational text to your script.

Example:

!script {{
  --/|Script Name : Fireball
  --/|Purpose     : Allow the player to cast a fireball and blow stuff up!
  .
  .
  .
}}

Using this style will sometimes work, but is not recommended.

!script {{
  --/|When you have a very
      long comment, then
      you sometimes have
      to put it in multiple
      lines.
  .
  .
  .
}}

Because it can lead to unwanted text appearing on your output card.

Set Parameter (--#)

A --# statement sets parameters used by ScriptCards when the card output is built. These include things like the title of the card, the background colors used for various portions of the card, the content of the left and right subtitle blocks, the tokens displayed in the emote (if any), the emote text, etc. A full list of these setting values is included below.

For settings statements, the Tag determines the setting that will be updated, while the Content determines the value that will be stored in that setting.

For global settings, if the same setting is set multiple times in a script, the MOST RECENTLY EXECUTED setting will be what is used when the card output is built. Most settings are "Per-Line", meaning they will only impact output lines generated after the setting is made, and can thus be changed with every line if desired.

Examples:

  --#title|Magic Missile
  --#leftsub|Level 1 Spell
  --#rightsub|Force Damage

The three examples above set the “title”, “leftsub”, and “rightsub” values for the card to the content value for the line.

Content portions can include roll variables (see --= lines below) and can be used multiple times in a macro. The last execution of a setting line will be the one used when the card output is generated. Settings Lines do not produce output lines on the card.

The following settings are available (note that parameter names are not case sensitive):

Name Effect/Use Default Value Type
activepage If set to a page ID, will be used for [*P:] attribute references. The "playerpage" string can be used to retrieve the current player ribbon page. empty Per-Line
allowplaintextinrolls If set to a non-zero value, plain character text in rolls will be copied to the roll text 0 Per-Line
bodyFontFace Name of the font used in the card rows Helvetica Global
bodyFontSize Size of the text in the card rows 14px Global
bodybackgroundimage Specify an image (content for a CSS background-image tag) for the body area none Global
buttonBackground Background color for buttons created with [button][/button] #1C6EA4 Per-Line
buttonBorderColor Border (outline) color for buttons created with [button][/button] #999999 Per-Line
buttonFontFace Font Family specifier for captions on buttons created with [button][/button] Tahoma Per-Line
buttonFontSize Text size for captions on buttons created with [button][/button] x-small Per-Line
buttonTextColor Text color of labels on buttons created with [button][/button] #FFFFFF Per-Line
debug If set to a non-zero value, will output lots (and LOTS) of information to the API console log about the running script. Useful for troubleshooting. 0 Per-Line
deferralcharacter Changes the meta script deferral sequence to the specified value ^ Per-Line
diceFontColor Color of the dice created with the [d4] [d6], etc. formatting markers #1C6EA4 Per-Line
dicefontsize Size of the dice created with the [d4] [d6], etc. formatting markers 3.0em Per-Line
disableinlineformatting If set to a non-zero value, inline formatting (bold, italics, color, text alignment, etc.) will not be performed on --+ lines 0 Per-Line
disablerollprocessing If set to a non-zero value, --= lines will not process dice rolls strings 0 Per-Line
emoteBackground Background color of the emote area #f5f5ba Global
emoteFont Name of the font used in emote area (above the title of the output card) Georgia Global
emoteFontColor Color of the font in the emote area None (Empty) Global
emoteFontSize Size of the font used in the emote area 14px Global
emoteFontWeight Font weight for the font in the emote area bold Global
emoteState If set to anything other than "visible", the emote portion of the card will not be displayed visible Global
emoteText Text to display in the emote portion of the card None (Empty) Global
emotefont Name of the font used in the emote text area font-family: Georgia, serif; font-weight: bold; Global
evenRowBackground Hex code for the background color for even rows #eeeeee Per-Line
evenRowFontColor Hex code for the text color for even rows #000000 Per-Line
evenrowbackgroundimage Specify an image (content for a CSS background-image tag) for the even card rows none Per-Line
executionlimit Maximum number of script lines the interpreter will try to execute. This prevents "infinite loop" sandbox crashes 40000 Global
hideCard If set to any non-default value, the entire card output will be suppressed 0 Global
hideTitleCard If set to any non-default value, the top portion of the card (title and subtitle area) will not be included on the output 0 Global
leftsub Subtitle text. Will be centered if rightsub isn’t specified, otherwise will be offset to the left with a separator between leftsub and rightsub. None (Empty) Global
lineheight Vertical size of each line on the output card normal Per-Line
nominmaxhighlight If set to anything other than "0", rolls will not display crit/fumble/mixed highlight colors. 0 Per-Line
norollhighlight If set to anything other than "0", rolls will not be formatted (plain numbers) but will still get a tooltip with details (v1.3.6b+) 0 Per-Line
oddRowBackground Hex code for the background color for even rows #d0e4f5 Per-Line
oddRowFontColor Hex code for the text color for odd rows #000000 Per-Line
oddrowbackgroundimage Specify an image (content for a CSS background-image tag) for the odd crd rows none Per-Line
reentrant Used to name a script for rentrant button use 0 Global
rightsub Subtitle text. Will be centered if leftsub isn’t specified, otherwise will be offset to the right with a separator between leftsub and rightsub. None (Empty)0 Global
rollhilightlineheight Determines the height of the hilight box placed around roll results (1.4.2+) 1.0em Per-Line
roundUp If set to a non-default value, integer division will round up instead of down 0 Per-Line
showfromfornonwhispers If set to a non-zero value, will include the sender on cards that aren't whispered 0 Global
sourceToken Token ID of the Source character. Will be displayed in the left portion of the emote area if specified, and will be used for referencing attributes. None Per-Line
subtitleFontColor Color of the text in the subtitle areas #FFFFFF Global
subtitleFontFace Name of the font used on the subtitle sections Tahoma Global
subtitleFontSize Size of the subtitle font 13px Global
subtitleSeperator The character(s) that will be placed between leftsub and rightsub Global
tableBorderRadius CSS specifier for how rounded the borders of the output card are. Use "0px;" for square borders 6px; Global
tableShadow CSS specifier for the drop shadow under the output card 5px 3px 3px 0px #aaa; Global
tablebgcolor Background color of the whole card. Normally not visible #EEEEEE Global
tableborder Color of the border that surrounds the whole card 2px solid #000000; Global
targetToken Token ID of the Target character. Will be displayed in the right portion of the emote area if specified, and will be used for referencing attributes. None Per-Line
timezone IANA Specifier for the local time zone, used in system/date functions merica/New_York Per-Line
title Text displayed in the title area of the card ScriptCards Global
titleCardBackground A hex color code representing the background color of the title area. #1c6ea4 Global
titleFontColor Color of the text on the card title #FFFFFF Global
titleFontFace Name of the font used on the title area Contrail One Global
titleFontLineHeight Line spacing on the title area 1.2em Global
titleFontSize Size of the title font 1.2em Global
titlecardbackgroundimage Specify an image (content for a CSS background-image tag) for the title card area none Global
titlecardbottomborder Border CSS specifier for the bottom of the title card area 2px solid #444444; Global
titlecardgradient If set to non-zero value, will place a vertical gradient on the title card area 0 Global
usehollowdice If set to a non-zero value, the hollow/outline versions of the dice fonts will be used 0 Per-Line
whisper Comma separated list of who to whisper the output to. Use "gm" for GMs and "self" for the sender none }

Setting Lines do not produce output lines on the card

Direct Output (--+)

A direct output line display a line of content on the ScriptCard. It can be a simple line of text with a Tag/Content pair, or it can include Roll Variable references and inline formatting. The Tag can be blank (the | is still required). If a tag is specified, it is output in bold at the beginning of the line followed by the content.

Examples of Direct Output lines:

  --+Hello|World
  --+Attack|The monster rolls [$Attack] to hit!
  --+Damage|@{target|token_name} is hit for [$Damage] [#3333AA][b]frost[/b][/#] damage.

Direct Output lines support inline formatting, roll variable replacement, character attribute references, and procedure variables.

GM Output (--*)

A GM Output line is identical to a direct output line except that it will be sent on a separate card that is only visible to GMs.

Example:

  --+PlayerLine|This line is shown on the public card
  --*GMLine|This line will only be shown to GMs, on a separate card.

Roll Variable Assignment (--=)

In ScriptCards, when you want to roll dice you need to store the result of the roll into a Roll Variable. This is done by specifying the name of the Roll Variable as the Tag, and the roll text as the Content of the line.

All components of a roll equation should be separated with spaces.

Examples:

  --=MissileDamage|1d4 + 1
  --=Attack|1d20 + @{selected|strength_mod} [STR] + @{selected|pb} [PROF]

In these examples, the MissileDamage Roll Variable will be set to the result of rolling 1d4 and adding 1. The Attack Roll Variable will roll 1d20, add the selected character’s strength modifier and proficiency bonus (assuming D&D 5E) and store that value into the variable. Text enclosed in square brackets ([]) is considered "flavor text" and will be added to the result text but does not impact the roll result.

The following dice formats are supported:

Format Pattern Example Description
XdY 3d8 Simple format. Roll a Y-sided die X times
XdYkhZ 2d20kh1 Roll Y-sided die X times and keep the highest Z number of dice
XdYklZ 4d6kl3 Roll Y-sided die X times and keep the lowest Z number of dice
XdY>Z 5d6>3 Roll Y-sided die X times and count a 1 for each roll greater than Z
XdY<Z 5d6<3 Roll Y-sided die X times and count a 1 for each roll less than Z

Note: The dice formulae below are supported in the development version of ScriptCards and will be merged with the table above when activated on OneClick

Format Pattern Example Description
XdYr<Q and XdYr>Q 10d6r<2 Roll a Y-sided die X times, rerolling results less than or equal (or greater than or equal to) to Q
XdYro<Q and XdYro>Q 10d6ro<2 Roll a Y-sided die X times, rerolling results less than or equal (or greater than or equal to) to Q one time, keeping the reroll result
XdY! and XdY!>Q and XdY!<Q 8d6! Roll a Y-sided die X times, rerolling max results and adding them to the total for the die (or rerolling results >= or <= Q and adding (Exploding dice)
XdYkhZr<Q and XdYkhZr>Q 4d6kh3r<1 Roll a Y-sided die X times, rerolling results less than or equal to (or greater than or equal to) Q, and keep the highest Z results

The following operators are supported in a roll equation:

Operator Operation
+ Addition
- Subtraction
* Multiplication
/ Division
\ Integer Division (Rounds down)
 % Modulo (Remainder of Divison)

Roll Variables can be accessed at any time after they have been created by using the [$VariableName] format, with the following optional modifiers:

Modifier Meaning
No modifier In a Direct Output Line (--+) will be replaced with a formatted roll display, including a mouseover with roll text details. In any other type of line, will display the same results as .Total
.Total The end result of the roll equation as an unformatted number
.Base The cumulative result of any dice rolled in the Roll Text (Numeric modifiers are not included)
.Ones The number of dice in the roll that came up as 1s
.Aces The number of dice in the roll that came up as the maximum number on the die
.Odds The number of dice in the roll that came up with an odd number
.Evens The number of dice in the roll that came up with an even number
.RollText The raw text of the roll that was use to generate the results
.Text A text representation of the results of the roll, including the numbers rolled for each die
.tableEntryText The text portion of the result of a table roll
.tableEntryImgURL The image source portion of the result of a table roll
.tableEntryValue Numeric value of tableEntryText (via parseInt). If a non-numeric value, will be 0
.Raw The total numeric result without any formatting, even if placed somewhere formatting would normally be done.

Examples:

  --+Total Damage|[$MissileDamage.Total] (roll was 1d4+1)
  --+Base Damage|[$MissileDamage.Base]  (without the +1)
  --=Attack|1d20 + @{selected|strength_mod} [STR] + @{selected|pb} [PROF] + [$BlessBonus] [Bless]

In this case, 1d4 will be rolled and stored in “BlessBonus”, which can then be used in the Attack line.

Mathematical Functions in Roll Expressions

The ScriptCards roll parser works from left to right, always maintaining a current value and applying whatever comes next to the total. The following in-line functions to the roll parser. These are:

Expression Meaning
{ABS} Absolute Value
{CEIL} Ceiling value (round up to the next whole number)
{FLOOR} Floor value (round down to the next whole number)
{ROUND} Round value (round up if the decimal portion is greater than 0.5, otherwise round down)
{NEGATE} Multiply the value by negative one.
{SQRT} Take the square root of the running value. (1.4.1+)
{SQUARE} Square the running value. (1.4.2+)
{CUBEROOT} Take the cube root of the running value. (1.4.2+)
{CUBE} Cube the running value. (1.4.2+)
{SIN} Return the SIN of running value. (1.4.2+)
{COS} Return the COS of running value. (1.4.2+)
{TAN} Return the TAN of running value. (1.4.2+)
{ASIN} Return the ASIN of running value. (1.4.2+)
{ACOS} Return the ACOS of running value. (1.4.2+)
{ATAN} Return the ATAN of running value. (1.4.2+)


Special Notes about Dice Rolls (READ THIS!): In order to support the ability to include Roll Variable values in rolls, ScriptCards does not use the built-in Roll20 dice rolling engine, and does not support “inline rolls” (rolls included with [[ ]] in the card). Because I have included my own roll parser, there may be some odd roll methods that are not currently implemented. If you run into dice roll options that don’t work, please let me know and I’ll try to support them.

Special Notes Update: As of version 1.2.3, inline rolls will be parsed by ScriptCards, using only the FINAL RESULT of the roll. The components (dice, modifiers, etc.) will not be visible to ScriptCards.

Rolling on Rollable Tables You can also roll on a rollable table using the expression [T#tablename], where tablename is the case-sensitive name of the table in your game. Proper weighting for each entry in the table is taken into account when rolling on rollable tables. The .tableEntryText and .tableEntryImgURL properties of the Roll Variable will be set to the matching values on the resultant table entry.

Roll Variable Lines do not produce output lines on the card.

String Variable Assignment (--&)

String variables function in most ways like roll variables, except that they do not attempt to process any dice rolls, and do not have the list of properties that a roll variable has. They are designed to simply contain text. To assign a string variable, use the --& statement:

  --&MyText|Hello

Here, we assign the text "Hello" to the string variable named MyText. You can also append text to a string variable by prefixing the content with a + sign:

  --&MyText|+ World

If run after the statement above, MyText will now contain "Hello World".

String variables can be referenced using the syntax [&variablename]

Call API (--@)

ScriptCards can use a Call API instruction to execute other API commands. The Tag contains the API command to use (alter, or roll20AM, for example - do not include the !) The content portion of the statement contains the parameters that are passed to the API script. Because the -- sequence can't be used here, an underscore (_) at the beginning of the line or preceded by a space is replaced with -- before the API command is executed.

Examples:

  --@eh|list
  --@alter|_target|@{target|token_id} _bar|3 _amount|-[$Damage]

In the first example above, the command !eh list will be executed, calling EncounterHelper. In the second, AlterBars(Forum) is called to modify a token's Bar 3 value.

Note: When ScriptCards (or any API script) runs other API script commands, there is not an associated player attached to the executed command. This means that the script being called won't know if the person running the ScriptCard is, for example, a GM. The most common instance of this is when calling !token-mod and trying to use --ids instead of acting on selected tokens. Since this is an ability normally limited to GMs, you need to enable "Players can IDs" (in !token-mod config).

See API:Script Index for more options.

Branch Label (--:)

A branch label defines a line in your code that can be reached by one of the branching instructions (--^, -->, or --?). The Tag serves as the label name, and must be unique on the card.

The vertical bar (|) separator must be present, but the content portion of the line is unused and can be treated as a comment.

Examples:

  --:MyLoop|
  --:CriticalHit|Will jump here if we roll a critical hit!

A Branch Label line does not produce an output line on the card.

Branch (--^)

A Branch line jumps execution to the label indicated by the Tag. The vertical bar (|) separator must be present, but the content portion of the line is unused and can be treated as a comment.

Examples:

  --^MyLoop|Jumps to MyLoop
  --^SkipCrit|We didn't crit, so skip the Crit code

A Branch line does not produce an output line on the card.

Call Procedure (-->)

Similar to a branch, a Call Procedure (sometimes knows as a "gosub") line branches execution to the label indicated by the Tag. However, the return pointer of the call will be pushed onto a stack so that a Return instruction (--<) will return execution to the next line in the card. A list of parameters for the subroutine can be passed as the content portion of the tag, and are separated by semicolons (;).

Examples:

  -->FixFormat|#3333FF;#999999

In this example, a label called "FixFormat" will be branched to as a subroutine, passing the parameters "#3333FF" and "#999999". In the subroutine, these parameters are referenced by number as [%1%] and [%2%].

Return (--<)

A return instruction marks the end of a Gosub procedure. Execution will return to the statement after the one that called the subroutine. The Tag and Content portions are both optional, but the vertical bar separator must be included.

Examples:

  --<|
  --<|End of MySub

In both cases, the value of the tag and the content portions of the statement are ignored, but the vertical bar separator must still be present.

Conditional Statement (--?)

A conditional statement contains some equation in the Tag that will be evaluated. If any part of the comparison can/does contain a space, it needs to be surrounded by double quotes

Based on the true/false result of the evaluation, one of two execution paths will be taken. These execution paths are detailed in the content section of the statement. The "if true" path is specified first (directly after the vertical bar), and the "if false" path is specified after it, also separated by a vertical bar.

Example:

  --?[$AttackRoll.Total] -ge [$TargetAC]|Hit|Miss

Prior to version 1.2.1, all conditional statements resulted in either a branch to a label statement, or a gosub branch. As of version 1.2.1 additional options for what happens when a condition is matched were added, and 1.2.5 adds further additional functionality.

Branch Format Meaning
Label If just a label is specified, execution will branch to that label when the comparison is matched.
>Label If a label name is preceded by a ">" character, a gosub branch will be performed. In this case, parameters can be passed to the subroutine by separating them from the label and each other with semicolons (;). Parameters that can contain a semicolon (like token/character IDs) should be surrounded by double quotes
=VariableName =Roll;1d20)
&VariableName &Result;Hit|&Result;Miss)
 % or %! The current for...next loop will perform the "next" action (%) or will break out (%!)
[ Code block (see below)

Examples:

  --?[$AttackRoll.Base] -eq 20|CriticalHit
  --?[$AttackRoll.Base] -eq 1|>Fumble;@{selected|dexterity_mod}
  --?"@{target|npc_type}" -inc "undead"|&MonsterType;Undead|&MonsterType;Not Undead
  --?[$Attack.Total] >= [$ArmorClass]|>Hit|>Miss

In the first example, if the Base value of AttackRoll is a 20 (natural 20 on the die) execution will branch to the CriticalHit label.

In the second example, if the Base value of the AttackRoll is 1 a gosub branch will be executed to the "Fumble" label, and passed the value of the selected character's dexterity_mod as parameter [%1%].

The third example looks for the word "undead" in the npc_type attribute of the targeted character. If it exists in the text, the MonsterType string variable will be set to "Undead", otherwise it will be set to "Not Undead".

The final example would call the "Hit" procedure on a hit and the "Miss" procedure on a miss and return execution to the next line after the procedure calls were finished.

Text that does/may contain a space should be enclosed in double quotes.

The following comparison operators are available:

Comparator Meaning
-eq Equal To
-eqi Case insensitive Equal To
-ne Not Equal To
-nei Case insensitive Not Equal To
-gt Greater Than
-ge Greater Than or Equal To
-lt Less Than
-le Less Than or Equal To
-inc Includes (text strings).
-ninc Does Not Include (text strings).

Multi-part conditionals are supported with -and and -or as separators. For example:

--?[$Attack.Total] -ge @{target|npc_ac} -and [$Attack.Base] -ne 20|HitButNotCrit

Multi-part conditionals are evaluated from left to right, and each evaluation is either ANDed or ORed with the current cumulative state. This means that (assuming "true" and "false" are actually conditional expressions that evaluate to either true or false):

true AND false OR true

Will be evaluated as true. The first two (true and false) will be false, but then false OR true will be true.

Conversely:

true or false and false

Will be false, because the first true and false will evaluate to true, and then true and false will be false.

CODE BLOCKS

A new feature (1.2.7), code block allow you to treat a group of statements as a single unit based on a condition. This is similar to begin...end or curly braces in some languages, though a bit more limited. As part of the true or false execution branch of a conditional, you can use the "[" character to begin a code block.

If that execution path is taken, the code in the block will be executed. Otherwise, the code in the block will be skipped. Blocks are completed with the --]| statement, and can optionally include an "else" block by using --]|[ as the block terminator. Here is an example:

!script {{
  --=Roll|1d2
  --+Roll|[$Roll]
  --?[$Roll.Total] -eq 2|[
    --&Value|Yep!
    --+|We are inside the TRUE portion of the block
  --]|[
    --&Value|Nope
    --+|We are inside the FALSE portion of the block
  --]|
  --+After|the blocks!
  --+Value|[&Value]
}}

In this case, we begin by rolling 1d2 and then use a conditional to see if the result is 2. if it is, we execute everything inside the code block that begins on the conditional line, up until the end of the block marked with --]|[ because we have an "else" block. The else block is terminated with --]|.

At this time, blocks cannot be nested, and can only be created as part of a conditional (--[ is not a valid statement type)

A conditional statement does not produce a line of output on the card.

Case Statement (--c)

The case statement (--c) allows you to specify a value to test as the tag and a list of possible matches. These matches are case-insensitive. Matching groups are separated with vertical bars and matches and their branch labels are separated by a colon (:). Each match condition includes a branch label that will be used if the test value matches the item. If none of the values are matches, the script will simply proceed onto the next line. Both direct and procedure branches are supported, and procedure branches can include parameters as normal. Example:

!script {{
    --#title|Case Statement Testing
    --=Roll|1d4
    --C[$Roll.Total]|1:>One;[$Roll]|2:>Two;[$Roll]|3:>Three;[$Roll]|4:>Four;[$Roll]
    --X|

    --:One|  --+Value|was One ([%1%])  --<|
    --:Two|  --+Value|was Two ([%1%])  --<|
    --:Three|  --+Value|was Three ([%1%])  --<|
    --:Four|  --+Value|was Four ([%1%])  --<|
}}

This script uses the value of [$Roll.Total] and compares it against 1, 2, 3, and 4, using a gosub branch to the matching value. The first match test is “1:>One;[$Roll]”, where “1” is the value being matched, followed by a procedure branch to “One” which gets the roll variable as a parameter.

Save and Load (--s and --l)

This statement pair is used to either store (--s) or load (--l) data from persistent storage. Items stored in persistent storage remain between card rolls and between Roll20 sessions. There are two types of data that can be stored: settings and roll variables.

Examples:

--Ssettings|GreenStyle
--Srollvariables|FirstCardVars

In this case, the tag for the statement determines what type of item is being saved (settings or rollvariables). When saving settings, all non-default settings are written to the named setting storage value. When Roll Variables are saved, all variables that currently exist will be saved to the named storage value.

Loading stored items simply requires the same command with the --l statement type:

--Lsettings|GreenStyle
--Lrollvariables|FirstCardVars

When loading settings, all stored settings will be applied to the current card settings. You can override settings by changing them after the load.

When loading roll variables, the saved variables will be added to (or overwrite if they have the same name) any variables on the current card. This means it is safe to create roll variables before the load statement.

Practical Uses The major intended use of persistent storage is for storing card formats for use in later scripts. For example, the following script:

!scriptcard {{
  --#titlecardbackground|#22CC22
  --#oddrowbackground|#cceecc
  --#evenrowbackground|#99ee99
  --Ssettings|@{selected|token_name}
}}

Would save the titlecardbackground, oddrowbackground, and evenrowbackground settings to a saved list named after the selected token's name. When creating cards for that token to run later, you could include the line:

--Lsettings|@{selected|token_name}

To load all of the settings at once. By creating these setting sets for each character, you can specify a different color scheme for each character that can then be used in cards with a single formatting line.

There is a supplemental ! command added to support saved settings:

!sc-liststoredsettings

Will produce a list of all stored setting names, with buttons to list the setting values stored in each group and a button to delete groups as needed.

Visual Effects (--v)

The --v statement can be used to create visual effects on the tabletop. The tag portion of the statement can be either "token" or "betweentokens". The content portion of the statement contains the required parameters for the effect generation, separated by spaces. If the effect is "none", no effect will be played. If any other value that doesn't match a Roll20 effect name will result in a burst-fire effect.

For "token" effects, the parameters are the token id for the token the effect happens on, followed by the effect specifier.

Example:

  --vtoken|@{selected|token_id} burst-fire

For "betweentoken" effects, the parameters are the source token id, the target token id, and the effect specifier.

Example:

  --vbetweentokens|@{selected|token_id} @{target|token_id} beam-magic

Version 1.2.8+

An additional effect specifier, "point" is available in 1.2.8+. This specifier allows you to create a visual effect at a designated X/Y pixel coordinate. Future updates will add custom-vfx support to this option. The parameters are the X and Y coordinates and the effect descriptor. As of version 1.2.9, you can also use custom effect specifiers with Point effects:

  --vpoint|150 200 burst-fire

Echo to Chat (--e)

The echo statement is simply a call to the API's sendChat command, using the tag as the speakingAs parameter and the content as the text to send.

Example:

  --eThe Ghost|/em hovers around @{selected|character_name}... BOO!

Would output "The Ghost hovers around (charactername)... BOO!" as an emote to chat. This will happen whether or not you have a character named "The Ghost" in your journal or not (roll20 sees this message as coming from the API, not from a player or a character).

Whispering

You can use the echo statement to send a whisper, but there's a trick to it. If you execute this code here:

--eThe Ghost|/w ExamplePlayerName Boo.

Then the player named "ExamplePlayerName" would see on his screen a whisper from "The Ghost" that says "Boo."... but you would not see anything on your screen! And you wont see anything on your screen no matter what you try to replace "The Ghost" with... not even if you try to use "GM" or your own player name. Because, again, roll20 sees the message as coming from the API, not from a player or a character.

So, in conclusion, it's best to use something like this when you're sending a whisper:

!script {{
  --#hidecard|1
  --&sender|The Ghost
  --&receiver|ExamplePlayerName
  --&message|Boo.
  --e[&sender]|/w [&receiver] [&message]
  --eScriptCards|/w gm **Whispered from [&sender] to [&receiver]:** [&message] 
}}

This will ensure that the message appears in your chat feed as well.

Repeating Section Access (--R)

ScriptCards (as of v0.0.13) supports accessing repeating section rows on a character sheet with the --R statement type.

There are three basic commands you can use with --R, and they are specified by the tag used:

  --Rfind|characterid;EntryName;SectionPrefix;SearchField

This is the most direct way to access a repeating section row. Supplying the character ID, followed by what you are looking for (Greatsword, for example), followed by the character sheet's section prefix (repeating_attack), followed by the field to check what you are searching for (atkname) will load the matching section (if found) into the script parsers memory. For example:

  --Rfind|@{selected|character_id};Greatsword;repeating_attack;atkname

Will look at the character's "repeating_attack" section for an entry with an atkname value equal to "Greatsword". Similarly:

--Rfind|@{selected|character_id};Bite;repeating_npcaction;name

Will look for a "Bite" action on an NPC's action list.

  --Rfirst|characterid;section prefix

This form of the --R command will look at all of the entries in the specified repeating section and load the first one into memory:

  --Rfirst|@{selected|character_id};repeating_attack

Would load the character's first "repeating_attack" row into memory.

--Rnext|

No parameters are required for --Rnext, which loads the next entry in the list that was obtained with "first" into memory.

However a row is obtained, it will be parsed to replace any attribute references (ie, @{level}) with the corresponding character attribute.

If at any point, a valid entry isn't found (find doesn't find something, first doesn't see any rows, or next goes off the end of the list) any attempts to reference the row data will return "NoRepeatingAttributeLoaded".

You can reference repeating attribute data using the syntax [*R:attributename] syntax (similar to referencing standard character attributes).

Here are some examples:

Display the details of the "Greatsword" PC attack:

!script {{
 --Rfind|@{selected|character_id};Greatsword;repeating_attack;atkname
 --+Attack Name|[*R:atkname]
 --+Base Damage|[*R:dmgbase]
}}

Repeating Greatsword Attack

List all of the actions an NPC can take (just actions, not legendary, etc.)

!script {{
 --#title|NPC Actions
 --#leftsub|@{selected|token_name}
 --Rfirst|@{selected|character_id};repeating_npcaction
 --:DisplayLoop|
 --?"[*R:name]" -eq NoRepeatingAttributeLoaded|Done
 --+Action:|[*R:name] [*R:attack_damage] [*R:attack_damagetype]
 --?"[*R:attack_damage2]" -eq ""|NoSecondaryDamage
 --+ |[*R:attack_damage2] [*R:attack_damagetype2]
 --:NoSecondaryDamage|
 --Rnext|
 -->DisplayLoop|  
 --:Done|
}}

Scriptcards repeating npcactions.png

In the script above, we get the "first" repeating_npcaction and display information about it. We then execute "next" and repeat until we run into "NoRepeatingAttributeLoaded".

Special debugging command: dump

--Rdump|

The "dump" command will list all of the attributes ScriptCards knows about for the currently loaded repeating row to the API Console Log.

Assign Variable to Built-In Function (--~)

ScriptCards has the ability to run a function built into the API script and return the results to a variable. Some functions return roll variables, while others return strings. See the function table below for details. The format is:

--~VariableName|function;param1;param2;param3;...

Function Name Parameters Description
distance token_A_ID;token_B_ID Calculate the Chebyshev distance in grid units between two tokens. This is the measurement scheme D&D 4E/5E use for diagonal distance measurement
euclideandistance token_A_ID;token_B_ID Calculate the Euclidean distance between two tokens. This is essentially the Pythagorean theorem in action. Returns the result in grid units.
euclideanpixel token_A_ID;token_B_ID Calculate the Euclidean distance between two tokens and returns the result is pixels instead of grid units.
euclideanlong token_A_ID;token_B_ID Calculate the Euclidean distance between two tokens and returns the result in grid units, but the grid unit conversion is performed AFTER the pixel distance is calculated instead of before. More accurate over long distances.
manhattandistance token_A_ID;token_B_ID Also called "taxicabdistance" (which is an acceptable function name), this measures to how-many-over, how-many-up/down distance, disallowing diagonal movement.
getselected none Using the variable name in the tag, a series of string variables will be created: VariableNameCount will contain the number of selected tokens. VariableName1 will contain the token ID of the first selected token, VariableName2 the second, etc.

Functions with Sub Functions

Most ScriptCards functions are grouped into set as sub functions. The table below lists the major functions and their sub functions.

Function Name Sub Function Parameters Return Type Description
array define arrayname;value1;value2;... none Creates an array called "arrayname" and adds value1, value2, etc. to the array
array sort arrayname none Sorts the specified array in place in ascending order
array add arrayname;value1;value2;... none Adds value1, value2, ... to the existing array "arrayname"
array remove arrayname;value1;value2;... none Removes value1, value2, ... from the existing array "arrayname". Resets the array index to 0.
array replace arrayname;currentvalue;newvalue none Replaces all occurrences of "currentvalue" in "arayname" with "newvalue"
array setatindex arrayname;index;newvalue none Replaces the array item at index "index" with "newvalue"
array getindex arrayname stringVariable Retrieves the current index in "arrayname" and stores it in the supplied string variable
array setindex arrayname;newindex none Sets the current index in array "arrayname" to "newindex"
array getcurrent arrayname stringVariable Gets the item at the current array index in "arrayname" and returns it as a string variable. Will return "ArrayError" if there is no current item.
array getnext arrayname stringVariable Increments the current index in "arrayname" and returns the new current value. Will return "ArrayError" if the end of the array is reached.
array getprevious arrayname stringVariable Decrements the current index in "arrayname" and returns the new current value. Will return "ArrayError" if the the current index was already zero.
array getfirst arrayname stringVariable Set the current index of "arrayname" to zero and retrieve the current item. Will return "ArrayError" if there is no current item.
array getlast arrayname stringVariable Set the current index of "arrayname" to the last item in the array and retrieve the current item. Will return "ArrayError" if there is no current item.
array removeat arrayname;indexposition none Removes the item at index "indexposition" from "arrayname". Resets the current array index to 0.
array indexof arrayname;searchvalue stringVariable Searches the array "arrayname" for and item with the value of "searchvalue" and, if found, returns the index of the first matching value or "ArrayError" if not found
array getlength arrayname stringVariable Returns the number of items in array "arrayname"
array pagetokens arrayname;tokenid;(optional filter) stringVariable Creates an array (arrayname) of all of the token ids (technically Graphics objects) on the same page as the specified token id. Returns the number of tokens found to the stringVariable. Available optional filters are : all, char, graphic, pc, npc. The filters will return only those tokens that match that criteria (char means tokens have a "represents", graphic doesn't. pc indicates a represents token has a controlledby, npc doesn't.)
array selectedtokens arrayname stringVariable Creates an array (arrayname) of all of the token ids (technically Graphics objects) selected when the script was executed. Returns the number of tokens found to the stringVariable.
array stringify arrayname stringVariable Returns all of the items in "arrayname" as a string separated by semicolons (;)
array fromstring arrayname delimiter;string Creates an array from "string", splitting "string" on "delimiter" to separate the items
array statusmarkers arrayname;tokenid none Creates an array (arrayname) of the active statusmarkers (sometimes called Token Markers) for the specified tokenid
math angle math;angle;tokenid;tokenid rollVariable Calculates the angle between two tokens and returns the value in degrees
math ceil math;ceil;value rollVariable Rounds value up to the next integer, dropping any decimal portion of the number
math clamp math;clamp;value;lowerBound;upperBound rollVariable Returns value, but restricted to the range of loweBound and upperBound.
math floor math;floor;value rollVariable Rounds value down, dropping any decimal portion of the number
math max math;max;valueA;valueB rollVariable Returns the larger of valueA vs valueB
math min math;min;valueA;valueB rollVariable Returns the smaller of valueA vs valueB
math round math;round;value rollVariable Rounds value to the nearest integer
string length string;length;stringValue rollVariable Returns the length of stringValue in characters
string before string;before;searchText;stringValue stringVariable Searches stringValue for searchText and returns the portion of stringValue prior to that text
string after string;after;searchText;stringValue stringVariable Searches stringValue for searchText and returns the portion of stringValue after that text
string left string;left;count;stringValue stringVariable Returns the leftmost count characters of stringValue
string right string;right;count;stringValue stringVariable Returns the rightmost count characters of stringValue
string replace string;replace;searchText;replaceText;stringValue stringVariable Replaces searchText in stringValue with replaceText and returns the resulting string
string replaceall string;replace;searchText;replaceText;stringValue stringVariable Replaces all intances of searchText in stringValue with replaceText and returns the resulting string Requires 1.2.9+
string trim string;trim;stringValue stringVariable Removes leading and trailing spaces from stringValue and returns the result.
string substring string;substring;start;count;stringValue stringVariable Returns count characters starting at start from stringValue
string split string;split;delimiter;stringValue special Splits stringValue into pieces, breaking it at delimiter. Returns a rollVariable with "Count" appended to the assigned variable name and a series of string variables with numbers appended (starting at 1) for each of the returned pieces.
string tolowercase string;tolowercase;stringValue stringVariable Converts the passed string to lower case and assigns to the passed variable name.
string touppercase string stringVariable Converts the passed string to upper case and assigns to the passed variable name.
string totitlecase string stringVariable Converts the passed string to title case (capitlaizes the first letter of each word) and assigns to the passed variable name.
stateitem write stateitem;write;variableType None Writes the variable specified in the tag to persistent storage. Specify either rollvariable or stringvariable for variableType. One of each type can be stored in persistent storage at a time.
stateitem read stateitem;read;variableType Depends on variableType Reads the stored variable of the specified type (either rollvariable or stringvariable) and stores the result in a variable named for the line tag.
turnorder clear none none Clears all entries from the t Turn Tracker/Initiative
turnorder addtoken tokenid;trackervalue none Adds the token represented by "tokenid" to the initiative tracker with an initiavie value of "trackervalue"
turnorder replacetoken tokenid;trackervalue none Replaces the token represented by "tokenid" in the initiative tracker with an initiavie value of "trackervalue". Will add the token if it doesn't exist in the tracker.
turnorder removetoken tokenid none Removes the token represented by "tokenid" from the initiative tracker if it exists
turnorder addcustom textlabel;trackervalue none Add a custom text entry to the t Turn Tracker/Initiative named "textlabel" with an initiative value of "trackervalue"
system date getdatetime stringVariable Returns the date time in the active timezone (see settings)
system date getdate stringVariable Returns the date in the active timezone (see settings)
system date gettime stringVariable Returns the time in the active timezone (see settings)
system dumpvariables "rolls", "string", or "array" none Dumps all of the defined variables of the indicated type to the console log
system findability system;findability;charactername;abilityname stringVariable Returns the object ID of the ability on the indicated character or "AbilityNotFound"

Examples:

--~HowFarAway|distance;@{selected|token_id};@{target|token_id}

Returns the distance (Chebyshev) between the selected and target tokens and stores it in "HowFarAway".

--SelectedDudes|getselected

If 5 tokens were selected, 6 variables would be created: SelectedDudesCount (with a value of 5), SelectedDudes1, SelectedDudes2, SelectedDudes3, SelectedDudes4, SelectedDudes5.

Information Request (--i)

An Information Request statement allows your script to pause and “ask” the user for additional input. The statement type is --i, and uses the Tag portion of the statement to define a prompt to the user and the caption of a button that will be displayed for the user to press to provide additional information. The content portion of the line is made up of a series of information request in the format “type;VariableName;PromptText”, with each request separate by double vertical bars.

ScriptCards will use the display text and the button caption to whisper the script sender a message with a button to click that can ask for information via roll queries or ask for targets to be selected. Multiples of each type and combinations are allowed. The result of each information request will be stored in a string variable matching the “VariableName” parameter for that request.

After the user has clicked the button and responded to the requests, ScriptCards will resume processing the script from where it left off.

Here is an example “i” line:

--IScriptCards needs additional information to continue;Click to select a target and provide information|t;MyNewTarget;Missile1Target||q;MyNameIs;What is your name?

The sample above will whisper the user "ScriptCards needs additional information to continue" and provide a button labeled "Click to select a target and provide information". When the user clicks the button, they will be requested to select a target labeled "Missile1Target" and a prompt will appear asking that they enter their name into a text field.

Supported information request types are “t” for target token, and “q” for query.

For “t” types, specify the variable name to store the token ID in as the second parameter and the prompt text that will appear in the “Choose Target” window (i.e. Choose Target: Missile1Target above).

For “q” types, specify the variable name to store the response in as the second parameter, and the text of the roll query without the ?{} identifiers. You can specify values for dropdowns, etc. For example:

q;UserName;What is your name?|Fred|Bob|Sally|Nancy

Would have a dropdown menu with four choices.

Inline Formatting

Inline formatting is processed on Direct Output lines only (--+ lines) and the following inline format markup is available:

Formatting Tags Description
[b]..[/b] Bold the text between the markers
[i]..[/i] Italicize the text between the markers
[u]..[/u] Underline the text between the markers
[s]..[/s] Strike-Thru the text between the markers
[c]..[/c] Center alignment
[l]..[/l] Left alignment
[r]..[/r] Right alignment
[j]..[/j] Full justification alignment
[#xxx]..[/#] or [#xxxxxx]..[/#] Use a 3 or 6 digit hex code to colorize the text between the markers
[img]..[/img] Insert an image. The full URL of the image goes between the markers. You can include HTML attributes to be applied to the img tag in the opening marker (ie, [img width=128 height=128] )
[button]caption::action[/button] Create a button with the label "caption" that performs the action defined by "action".
[t] Converted to HTML table tag. Text after the "t" will be included inside the tag (width, border, etc)
[/t] Converted to HTML close table tag.
[tr] Converted to HTML table row tag. Text after the "tr" will be included inside the tag
[/tr] Converted to HTML close table row tag.
[td] Converted to HTML table cell tag. Text after the "tr" will be included inside the tag
[/td] Converted to HTML close table cell tag.

Variables

ScriptCards supports two types of variables : Roll Variables and String Variables. Either type can be used in a conditional statement, or use to substitute their value into the tag or content portion of other statements. For both types of variables, variable names are case sensitive. While it is possible to assign both a string and a roll variable the same name, doing so will likely result in confusion when looking at the script later, so it is not recommended.

String Variables are assigned with the --& statement and are referenced using [&variableName] notation.

Roll Variables are assigned with the --= statement, and the assignment value is always processed by the ScriptCards Roll Processor (resolves dice rolls, etc.)

There are a handful of variables assigned automatically when a ScriptCard is executed. These are all string variables, and are:

Variable Value
SendingPlayerID Contains the object ID of the player that sent the macro
SendingPlayerName Contains the display name of the player
SendingPlayerColor Contains the color code associated with the player
SendingPlayerSpeakingAs The contents of the "Speaking As" dropdown window
SendingPlayerIsGM Contains 1 if the player is a GM, and 0 if the player is NOT a GM

Arrays

Arrays are a special type of variable, and are managed by the function (--~ command). All of the array function commands follow the same pattern:

--~variableName|array;subcommand;arrayname;param1;param2;param3;...

Not all array commands return anything to "variableName". The function table above will specify the return type of the command if any.

There are a couple of different ways to create an array:

The define array subcommand creates (or recreates) an array and assigns it values - one for each included parameter after the array name. For example:

--~|array;define;Fruits;mango;peach;strawberry;apricot;banana;apple

will create an array called Fruits with 6 elements in the order listed in the command (mango, peach, etc.)

You can also use two other subcommands to create arrays based on tokens:

--~Count|array;pagetokens;Everybondy;@{selected|token_id}

and

--~Count|array;selectedtokens;Selected

In both cases, arrays of tokens will be created, and a string variable called "Count" will be set to the number of tokens in the array. The pagetokens command returns (by default) all of the tokens on the page that contains the token passed as the parameter after the array name. You can filter the tokens that "pagetokens" includes in the array by appending an optional parameter describing the type of token you are looking for:

--~Count|array;pagetokens;Everybondy;@{selected|token_id};npc

Will return only tokens on the page that represent characters that do not have a controlledby parameter set. The available options are "all" (default), "char", "graphic", "pc", and "npc".

The selectedtokens command returns an array with all of the tokens that were selected when the script was called.

You can also use an arbitrary string to create an array, specifying a delimiter with the fromstring command:

--&names|Fred
--&names|+,Sally
--&names|+,Ted
--&names|+,Joyce
--~|array;fromstring;,;[&names]

The above example builds a comma-separated string and then uses "fromstring" to create an array with 4 elements from it, specifying the comma as the delimiter.

Finally, you can use the statusmarkers command to create an array with one entry for each active status marker on a specified token:

--~|array;statusmarkers;Conditions;@{selected|token_id}

will create an array with one entry for each status active on the selected token. The array elements will be the internal name of the status (if you are using custom status marker packs, the names will be specified in the marker pack).

Traversing Arrays

Each array keeps track of an internal index position (starting at 0). Several commands let you manage this index:

  • getindex returns the current index value
  • setindex sets the index to the specified location in the array
  • getlength returns the number of elements in the array
  • indexof returns the index location of the specified element

Other commands let you retrieve values from the array:

  • getfirst sets the index to 0 and returns the value at that position
  • getnext advances the index by 1 and returns the new current value
  • getprevious reduces the index by 1 and returns the new current value
  • getlast sets the index to the last elements in the array and returns the new current value

If/when you hit the end of the array, you will get a return value of "ArrayError", which can be used to detect the end of the array when looping through by index. See Referencing Array Elements below for additional information.

Manipulating Array Elements

Several array commands deal with inserting, removing, and modifying elements:

  • add works just like define, except that it takes an existing array and adds elements to it based on the passed parameters
  • remove looks for items matching each passed parameter and removes them from the indicated array if they exist
  • removeat allows you to specify an index location in the array and remove the element at that position
  • replace searches an array for a value and replaces all occurrences of it with a new value (if found)
  • sort sorts the elements in the array in ascending order
  • strinfigy returns a string variable that includes each array element separated by semicolons (;)

Referencing Array Elements

You can either use the index (getfirst, getnext, etc.) to traverse an array and work with the values, or you can use (new in 1.3.1) direct array element referencing.

!script {{
 --~dummy|array;pagetokens;myarray;@{selected|token_id}
 --~count|array;getcount;myarray
 --+Total:|There are [&count] graphical objects on the page
 --~testvar|array;getfirst;myarray
 --:loop|
 --+Value|[*[&testvar]:character_name]
 --~testvar|array;getnext;myarray
 --?[&testvar] -ne ArrayError|loop
 --+Loop1|Is Done!
}}

This example defines an array based on the tokens on the page and then loops through them, starting with a getfirst, displaying the character name, and using getnext until the result is "ArrayError", at which point the loop exits. Here is the same routine, except it uses a For...Next loop and direct array referencing:

!script {{
 --~dummy|array;pagetokens;myarray;@{selected|token_id}
 --~count|array;getcount;myarray
 --+Total:|There are [&count] graphical objects on the page
 --%loopCounter|1;[&count]
   --+Value|[*[@myarray([&loopCounter])]:character_name]
 --%|
 --+Loop|Is Done!
}}

This line : --+Value|[*[@myarray([&loopCounter])]:character_name] uses [@arrayName(index)] format (inside a [*characterid:attribute] syntax) to perform the same task as running through the loop with the index.

(Note: Additional examples are on the way...)

For...Next Loops

For...Next loops in ScriptCards are supported with the with the --% statement type. A loop is defined by starting off with:

--%LoopCounter|<start>;<end>;[step]

The start and end values are required, while the step parameter is optional. If the step is omitted, it will be assumed to be 1. A string variable named after the line tag ("LoopCounter" in the case above) will be created and will hold the current iteration value for the loop. Here is a real example:

--%LoopCounter|1;10;1

This will begin a loop identified by "LoopCounter" that will start at 1, increasing by 1 each iteration (the step) until it has completed 10 executions.

The "next" statement is simply --%|, with no tag or parameters. This indicates to ScriptCards that it should increment the counter and go back to the beginning of the loop. Extending the example above:

!script {{
  --%LoopCounter|1;10;1
    --=Roll|1d20
    --+Loop|Counter is [&LoopCounter], roll was [$Roll]
  --%|
 }}

The --%!| sequence will break out of the loop, no matter how many iterations are remaining.

The % and %! character sequences can also be used as part of a 1.2.1+ non-branching conditional to continue or break the loop:

--?"X[&RollInto]X" -eq "XX"|%

In this example, if the string variable RollInfo is empty, the loop will return to the top and continue with the next iteration, while:

--?"X[&RollInto]X" -eq "XX"|%!

Would cause the whole loop to end if the condition were true.

Referencing

Roll Variables

Roll Variables can be referenced from the content portion of any line type, and from the tag portion of conditional statements. The referenced value is replaced when the line is executed.

There are several modifiers that can be used to reference parts of a roll:

Modifier Meaning
No modifier In a Direct Output Line (--+), GM Output Line (--*), or String Assignement (--&), will be replaced with a formatted roll display, including a mouseover with roll text details. In any other type of line, will display the same results as .Raw
.Total The end result of the roll equation. Formatting rules for "No Modifier" apply based on line type.
.Raw The total value of the roll variable without any formatting, no matter what kind of line the reference is used in.
.Base The cumulative result of any dice rolled in the Roll Text (Numeric modifiers are not included)
.Ones The number of dice in the roll that came up as 1s
.Aces The number of dice in the roll that came up as the maximum number on the die
.Odds The number of dice in the roll that came up with an odd number
.Evens The number of dice in the roll that came up with an even number
.RollText The raw text of the roll that was use to generate the results
.Text A text representation of the results of the roll, including the numbers rolled for each die
.tableEntryText The text portion of the result of a table roll
.tableEntryImgURL The image source portion of the result of a table roll
.tableEntryValue If the tableEntryText is purely numeric, will contain the numeric value

String Variables

To reference a string variable, use the notation [&variablename]. String variables can be referenced in direct output, roll variable assignment, and string variable assignment statements.

Character/Token Attributes

A character or token attribute can be referenced from content portion of any type of line and is substituted when the line is executed. The general format for referencing a character attribute is [*ID:attribute]. ID can be a token ID or a character ID (these start with a dash). Additionally if you have specified a sourceToken or targetToken, you can substitute "S" or "T" for the ID (for example [*S:npc_type] will retrieve the npc_type attribute from the source token.

By default, all attribute references will be pulled from the character object that the ID represents (either directly or by being a Token ID that represents a character).

Keep in mind, that if you want to access the "max" of a character attribute (for example, the max hit points), then you cannot trust the name that your roll20 character sheet shows you when you hover your mouse over the max hit points. For example, this reference will not work: [*S:hp_max]. Instead, you need to use this reference: [*S:hp^].

If your ID refers to a token, token attributes can be accessed by preceding the attribute name with "t-", for example [*S:t-aura1_radius]. Supported token attributes are:

t-name t-id t-statusmarkers t-bar1_value
t-bar1_max t-bar2_value t-bar2_max t-bar3_value
t-bar3_max t-top t-left t-width
t-height t-rotation t-layer t-aura1_radius
t-aura1_color t-aura2_radius t-aura2_color t-aura1_square
t-aura2_square t-tint_color t-light_radius t-light_dimradius
t-light_angle t-light_losangle t-light_multiplier t-light_otherplayers
t-light_hassight t-flipv t-fliph t-controlledby
t-_cardid t-_pageid t-imgsrc t-bar1_link
t-bar2_link t-bar3_link t-represents t-layer
t-isdrawing t-name t-gmnotes t-showname
t-showplayers_name t-showplayers_bar1 t-showplayers_bar2 t-showplayers_bar3
t-showplayers_aura1 t-showplayers_aura2 t-playersedit_name t-playersedit_bar1
t-playersedit_bar2 t-playersedit_bar3 t-playersedit_aura1 t-playersedit_aura2
t-lastmove t-adv_fow_view_distance t-has_bright_light_vision t-has_night_vision
t-night_vision_distance t-emits_bright_light t-bright_light_distance t-emits_low_light
t-low_light_distance t-has_limit_field_of_vision t-limit_field_of_vision_center t-limit_field_of_vision_total
t-has_limit_field_of_night_vision t-limit_field_of_night_vision_center t-limit_field_of_night_vision_total t-has_directional_bright_light
t-directional_bright_light_center t-directional_bright_light_total t-has_directional_dim_light t-directional_dim_light_center
t-directional_dim_light_total t-lightColor

It is important to note that some attributes names on tokens have corresponding attribute names on characters, which represent different values. For example, [*T:id] returns the character ID, while [*T:t-id] returns the token ID.

Subroutine Parameters

When using a gosub statement (-->) or a conditional marked as a gosub (prefixing the label with a > character), you can pass any number of parameters separated by semicolons (;) that the code in the subroutine can utilize.

Subroutine parameters are numbered starting at 1, and are accessed by using the notation [%number%], so the first parameter is [%1%], the second is [%2%], etc.

Parameter substitution happens on all line types, and happens prior to character attribute references or roll variable substitution.

Campaign Attribute

You can retrieve properties of the API's Campaign object with the [*C:attributename] syntax. For example, [*C:playerpageid] will retrieve the current player ribbon page from the Campaign object.

Page Attributes

If you have set the activepage parameter, you can retrieve page-related properties with the [*P:attributename] syntax, including the page's UDL parameters.

Repeating Section Values

You can reference repeating attribute data using the syntax [*R:attributename] syntax (similar to referencing standard character attributes). The currently active repeating row information will be used to retrieve attribute values. You can also retrieve the full attribute name for a repeating row attribute by using the [*R>attributename] notation. This is useful to pass to things like chatsetattr.

Array Elements

After an array has been declared, the elements can be referenced with [@arrayName(index)]. Array indices start at 0.

Deferred Resolution for Meta Scripts

As of 1.2.9, ScriptCards supports a deferral character for use when calling another API script with via the --@ statement, to defer processing of meta script references so they get processed prior to the sub-API call insted of prior to ScriptCards execution. To defer this processing for meta script (SelectManager, Fetch) by inserting a deferral character into the meta call. For example, if I want to have ScriptCards call TokenMod as if the token for "Quej Gr'stra" (yes, I let Roll20 name my test NPCs) I could use something like this:

 --@token-mod|{^& select Quej Gr'stra} _on showname

The "^" in between { and & will prevent SelectManager from seeing the call when the ScriptCard script is processed, but the --@ statement will remove the deferral character so the command that will be sent by ScriptCards is:

 !token-mod {& select Quej Gr'stra} --on showname

With the deferral character removed, SelectManager will see the {& select ...} and do its magic.

While the default deferral character is "^", the deferral character is a setting that can be changed:

 --#deferralcharacter|%

Will make % the deferral character for future --@ statements in the running script.

There are currently three supported Meta script structures: {^&...} for SelectManager, @^(...) and *^(...) for fetch, where the ^ in the structures here represents the placement of the deferral character.

Arrays

Arrays are a new data type introduced in version 1.1.12 of ScriptCards, and are manipulated with associated function (--~) commands.

  • Arrays are a lists of strings. Items in an array cannot contain the semi-colon (;) character, as that is used to separate parameters in the function code that deals with arrays.
  • Arrays are accessed via the --~ script command. In some cases, the value of the tag (variable name) for array commands is not used, and can be a dummy value or simply omitted. I have omitted them in the statements below.
  • All commands that DO return a value return string values, even if the content is numeric.
  • If a command returns a value and there is some sort of reason that it isn't an array value, you will get "ArrayError" in the return value. This can happen if you reach the end of an array while stepping through it, for example, so checking for "ArrayError" can serve as the end condition for a loop.
  • Each array keeps track of its current index, allowing you to step forward and backwards through arrays.
  • Any number of arrays can be defined.
  • Unlike string variables and roll variables, array variables cannot (currently) be referenced directly. It is necessary to use the function (--~) syntax to manipulate arrays and get values from them as strings for use in other parts of your script.


Reentrant Scripts

Reentrant scripts allow you to create buttons in your script code that will re-execute the script at a given label within the code. If you set the reentrant setting (--#reentrant|somevalue) to a non-zero value, your setting and variable information will be preserved between executions. Reentrant script can be used to present menus or choices and then continue acting.

Reentrant buttons are created with the [rbutton]Caption::ReentryLabel;Parameter[/rbutton] construct. The caption will be displayed on the generated button. ReentryLabel is the name of a label in your script that the button will jump to when clicked, and Parameter will be passed in as a string value called "reentryval".

Example:

!script {{
  --#reentrant|testing
  --=Roll|1d20
  --+Roll|[$Roll]
  --&String|That was a [$Roll.Raw]!
  --~x|array;define;MyArray;Apple;Banana;Orange
  --+Try it|[rbutton]Hello!::EXEC_PC_SPELL;9[/rbutton]
  --X|

  --:EXEC_PC_SPELL|
  --+ReentryVal|[&reentryval]
  --+The value of Roll is|[$Roll]
  --+Value of String|[&String]
  --+Array|[@MyArray(0)]
  --X|
}}

This script sets up some variables and then displays a button labeled "Hello!". If the user clicks the button, the script will be re-entered starting at the "EXEC_PC_SPELL", which will display the content of the variables from the original execution.

Note: This section needs to be expanded upon

Procedure Libraries

You can now create handouts in your game in Roll 20 with the name format "ScriptCards Library NAME", where name is a name you assign to the library. Library names are case sensitive. It is my hope that the more proficient ScriptCards scripters out there will provide procedure libraries (or procedures that can be included in libraries) for others to use to make their scripting life easier. Be they specific to a game system, or to a type of activity, I think a robust set of libraries that GMs could use to enhance their scripting capabilities would be very valuable to the community. Should such things begin to emerge, I’ll create a portion of the ScriptCards Wiki page to house them.

To include one or more libraries in a script, use the +++libname+++ directive (does not need a -- line associated with it). Multiple library names can be specified by separating them with semicolons (i.e., +++General;dnd5elib;Colorize+++ would include three libraries (General, dnd5elib, and Colorize).

Included libraries are separated from the main script code by the automatic inclusion of "--X|" before the first library is appended to the script, and all libraries are loaded at the end of the script before script processing takes place.

Procedures and labels in libraries can be used just as if they were included in the body of your script. Note that this DOES mean that you could, technically, jump into a library with a direct branch (--^) or direct branch conditional, but I recommend using libraries to store reusable procedures. The Notes section of the library handout stores the library code, and is written just like any other ScriptCards code except:

  • They cannot use roll queries (?{Some Prompt:}) to get information from the user at execution time.
  • They cannot use @{} notation to access character and token information.

Both of these limitation stem from the fact that Procedure Libraries are not processed by the chat server, which is what handles these items.

Here is an example of handling damage modifications (resistance, vulnerability, and immunity) in D&D 5E with a library:

!script {{
    +++dnd5elib+++
    --#|Damage Modifiers Test
    --#targettoken|@{target|token_id}
    -->Lib5E_CheckDamageModifiers|ResistType;fire
    --=DamageRoll|2d10 [&ResistType]
    --+Test:|[$DamageRoll] fire damage

    -->Lib5E_CheckDamageModifiers|ResistType;cold
    --=DamageRoll|2d10 [&ResistType]
    --+Test:|[$DamageRoll] cold damage

    -->Lib5E_CheckDamageModifiers|ResistType;poison
    --=DamageRoll|2d10 [&ResistType]
    --+Test:|[$DamageRoll] poison damage

    -->Lib5E_CheckDamageModifiers|ResistType;acid
    --=DamageRoll|2d10 [&ResistType]
    --+Test:|[$DamageRoll] acid damage

    --X|
}}

Library content (In a handout called “ScriptCards Library dnd5elib” NOTE: Paste into Notepad first and then paste into the handout in Roll20 to avoid bringing over HTML formatting from the web site):

--/|ScriptCards Library: dnd5elib version 0.0.1
--/|Provides various utility procedures for D&D 5E games

--/|Lib5E_CheckDamageModifiers handle damage resistance, vulnerability, and immunity. 
--/|Pass a string variable to be filled with a string to be appended to a dice roll and the damage type   

--:Lib5E_CheckDamageModifiers|damageVariableName;damageType
--&[%1%]|
--?"[*T:npc_vulnerabilities]" -inc "[%2%]"|>_Lib5E_IsVulnerable;[%1%]
--?"[*T:npc_resistances]" -inc "[%2%]"|>_Lib5E_IsResistant;[%1%]
--?"[*T:npc_immunities]" -inc "[%2%]"|>_Lib5E_IsImmune;[%1%]
--<|

--:_Lib5E_IsVulnerable| --&[%1%]| * 2 [Vulnerable] --<|
--:_Lib5E_IsResistant| --&[%1%]| \ 2 [Resistant] --<|
--:_Lib5E_IsImmune| --&[%1%]| * 0 [Immune] --<|

The idea is that the functions in the library create a string that can be appended to a roll to modify the output based on resistances, so you pass Lib5E_CheckDamageModifiers the name of the string variable you want to use and the damage type. The variable (ResistType in this case) will include either nothing, “* 2 [Vulnerable]”, “\ 2 [Resistant]”, or “* 0 [Immune]” which can be included in a roll assignment (--=) to modify the damage as appropriate. The order here might be important if an NPC is misconfigured to be both resistant and immune to the same damage type. Since immune is an absolute, having it last ensures that it will override resistant or vulnerable. A creature that is both vulnerable and resistant (again, misconfigured) will come back as resistant since that condition is checked after vulnerable. Some notes: I prefix my library labels with either “Lib5E_” or “_Lib5E_” as a clarity convention. This isn’t strictly necessary but you should be aware that if two libraries (or if your script and a library) define the same label, the last label defined will win. Since libraries are appended to the end of the script in the order you include them in the +++libname+++ directive, you can somewhat control this, but it is probably best to avoid re-declaring labels.

In my case, items beginning with “Lib5E_” are intended to be called by scripts, while items beginning with “_Lib5E_” are intended to be used as subroutines by the “public” procedures. Of course, there is no reason you couldn’t call them directly.

You might also note that I’ve included some library information in comment lines (--/|) at the top of the library. These are ignored by ScriptCards, and are a good way to convey requirements, parameters, usage information, etc.

Example Libraries

dnd5elib

Download the dnd5elib Library from the ScriptCards GitHub

The dnd5elib library provides a collection of utility procedures that help simplify dealing with the D&D 5E Official Sheet. Some of the procedures in this library require chatsetattr to be installed in your game. This is a growing library, and currently only has a handful of routines. They are:

Procedure Name Notes
Lib5E_CheckDamageModifiers parameters, pass the Lib5E_CheckDamageModifiers procedure a variable name (no reference information) and a damage type (i.e., fire, cold, bludgeoning, etc.) and a string variable with the name passed in as the first parameter will be created that contains text that can be included in a roll line (--=) in order to modify the roll as appropriate. For example, -->Lib5E_CheckDamageModifiers|ResistType;fire will check the current target character's attributes for "fire" and will either return an empty string (no references), "* 0 [Immune]" if the creature is immune, "\ 2 [Resistant]" if the creature is resistant, or "* 2 [Vulnerable]" if the creature is vulnerable to fire damage.
Lib5E_DeductSpellSlot Pass in a character_id and a slot level, and the script will expend one spell slot of that level, capping the value at 0 slots remaining. For Example -->Lib5E_DeductSpellSlot|@{selected|character_id};1 to deduct a first level spell slot from the selected character.
Lib5E_FindResource Used to locate a resource value on a character. Pass in a character_id, a resource name, and two variable names. The procedure will check both repeating and non-repeating resources looking for a resource whose name matches what was passed in and return three variables. The first will be a string variable named for the 3rd parameter and contains the attribute name of the resource's "name" field. The second will be a string variable named after parameter 4 and contains the resource's value field attribute name, and the third variable is a Roll Variable, also named after the 4th parameter that contains the current resource value. Example: -->Lib5E_FindResource|@{selected|character_id};Crossbow bolts;ResName;ResValue will find "Crossbow bolts" as a resource on the character and return [&ResName] which is the name of the resource attribute, [&ResValue] which is the name of the attribute that stores the value and [$ResValue] which is the current numeric value of the resource.
Lib5E_Active_Global_Attack_Modifiers Pass a character ID and a string variable to set the return value. This procedure will look through the Global Attack Modifiers (repeating_tohitmod_*) for rows that are active (checked on the character sheet) and return a string with the dice rolls and descriptions for each (for example, if I have "Bless" for 1d4 active and "Being Cool" for +2 active, I will get a return string " + 1d4 [Bless] + 2 [Being Cool]" that can be used in a dice roll.
Lib5E_Active_Save_Modifiers Pass a character ID and a string variable to set the return value. This procedure will look through the Global Save Modifiers (repeating_savemod_*) for rows that are active (checked on the character sheet) and return a string with the dice rolls and descriptions for each (for example, if I have "Bless" for 1d4 active and "Being Cool" for +2 active, I will get a return string " + 1d4 [Bless] + 2 [Being Cool]" that can be used in a dice roll.
Lib5E_Active_Skill_Modifiers Pass a character ID and a string variable to set the return value. This procedure will look through the Global Skill Modifiers (repeating_skillmod_*) for rows that are active (checked on the character sheet) and return a string with the dice rolls and descriptions for each (for example, if I have "Guidance" for 1d4 active and "Being Cool" for +2 active, I will get a return string " + 1d4 [Guidance] + 2 [Being Cool]" that can be used in a dice roll.
Lib5E_Active_AC_Modifiers Pass a character ID and a string variable to set the return value. This procedure will look through the Global Save Modifiers (repeating_savemod_*) for rows that are active (checked on the character sheet) and return a string with the dice rolls and descriptions for each (for example, if I have "Shield of Faith" with a value of 2 active, I will get a return string " + 2 [Shield of Faith]" that can be used in a dice roll.
Lib5E_Active_Damage_Modifiers Pass a character ID and TWO string variable to set the return value. The first string will be for normal damage, and the second will be the additional damage on a crit. This procedure will look through the Global Damage Modifiers (repeating_damagemod_*) for rows that are active (checked on the character sheet) and return two strings with the dice rolls and descriptions for them (for example, if I have "Sneak Attack" with a value of 1d6 normal and 1d6 critical damage active, I will get a return string " + 1d6 [Sneak Attack]" and another string of " + 1d6 [Sneak Attack CRIT]" that can be used in a dice rolls.
Lib5E_DivineSmiteDice Used to calculate the number of dice to be rolled for a paladin's Divine Smite. Pass a target token id, a spell slot level, and a string variable to be set to the dice roll amount based on the NPC_TYPE attribute of the target token. The returned variable will contain a dice roll (like "3d8" that can be used in a --= line)
Lib5E_Character_Summary Outputs a mini character sheet, including clickable buttons for attacks, actions, legendary actions, etc. Will automatically detect a PC vs NPC and output the appropriate sections.

Due to formatting issues with the Wiki, the library code has been moved to a GITHUB GIT. Please view the GIST in raw mode and copy the text and paste it into a handout called "ScriptCards Library dnd5elib" in your Roll20 Game.

What to Know if you are Coming from PowerCards

Note: This section is a work in progress.

While ScriptCards and PowerCard have very similar output goals, their internals and use are quite different. The table below summarizes some of the major differences between the scripts.

PowerCards ScriptCards
With a handful of exceptions, all lines in a PowerCard macro are intended to produce a line of output on the final card. With ScriptCards, ONLY the --+ and --* statement types produces output
PowerCards lines begin with two dashes (--) followed by a unique tag name for the line, followed by a vertical bar and the content for the line. ScriptCards lines begin with two dashes (--) followed by a statement type identifier, which is a single character that identifies the type of line to the interpreter. This is followed by a tag (frequently optional), a vertical bar, and the parameters for the statement being executed.
PowerCard macros are always processed top to bottom. Lines can be hidden so they don't output anything, but there is no looping or branching (--SkipTo looks like a branch, but it just hides all of the lines until the referenced label. ScriptCards scripts support true branching, including direct branching (--^) and procedure branching (-->) and (--<). Procedures support parameters and a call stack so procedures can be nested to call other procedures.
All lines in a PowerCards macro need to have unique tags because PowerCards builds the card as a single JavaScript object using the tag names to store what will be displayed. This is why repeated tag names always result in the last one being shown. ScriptCards tags do not need to be unique, and in the case of many line types are optional.
PowerCards conditionals result in either showing or hiding the line they are on. ScriptCards conditionals only support branching as the result of the comparison. This branching can be direct (a GOTO) or procedural (a GOSUB) NOTE: As of version 1.2.0, ScriptCards also supports roll/string variable assignment as a result of conditional evaluation
PowerCards relies on the Roll20 Quantum Roll server and inline rolls for all dice functions ScriptCards includes its own dice roll parser, and does not support inline rolls.
PowerCards RollIDs (often mistaken for variables) are assigned by analyzing the results of an inline roll, and cannot be referenced in other rolls, so you can't roll a 1d4 and then roll a 1d20 and add the 1d4 result because all of the rolls happen on the chat server before PowerCards gets the macro text. ScriptCards supports two types of variables: Roll Variables and String Variables. Because ScriptCards uses its own roll parser and is not dependent upon the chat server, rolls and their results can be used in other rolls, math functions, output, etc.

Example Scripts

Below are some sample scripts that utilize the various statement types in ScriptCards:

Divine Smite

This script will prompt the user for a spell slot level to expend on a divine smite. It will check the target's npc_type to see if it is an Undead or Fiend, which adds an additional d8 to the smite roll.

Divine Smite Script Output

!scriptcard  {{
  --#title|Divine Smite
  --=DiceCount|?{Spell Slot Level?|1|2|3|4|5|6|7|8|9} + 1
  --=IsFiendOrUndead|0
  --?"@{target|npc_type}" -inc fiend|>IsBoosted
  --?"@{target|npc_type}" -inc undead|>IsBoosted
  --=TotalDice|[$DiceCount] + [$IsFiendOrUndead]
  --=SmiteRoll|[$TotalDice]d8
  --#emoteText|@{selected|token_name} smites @{target|token_name}
  --#sourceToken|@{selected|token_id}
  --#targetToken|@{target|token_id}
  --+Smite|deals [$SmiteRoll] radiant damage.
  --X|

  --:IsBoosted|
  --=IsFiendOrUndead|1
  --<|
}}

How It Works

The first line sets the "title" card parameter to "Divine Smite".

Line 2 Shows a query to the user asking for the spell slot level, adds one and stores the value in the "DiceCount" Roll Variable. The query/dropdown is generated by the chat server prior to the script being executed.

Line 3 defaults the "IsFiendOrUndead" Roll Variable to 0.

Lines 4 and 5 compare the target's "npc_type" attribute (passed by the chat server as text) to see if they include either "undead" or "fiend". If true, the IsBoosted subroutine will be called. No parameters are passed to this subroutine.

Line 6 sets the "TotalDice" variable to the base (DiceCount) number plus the IsFiendOrUndead number, which will be a 0 or a 1.

Line 7 calculates "SmiteRoll" by rolling a number of d8 equal to the "TotalDice" value.

Lines 8-10 set the parameters for the emote, which appears above the card content. By setting the sourceToken and the targetToken, their icons will appear in the emote surrounding the text describing the action.

Line 11 is the only line that actually produces output on the card. It results in "Smite deals # radiant damage".

Line 12 ends the script execution, preventing the script from continuing and running the subroutines out of context.

Lines 14-16 are the IsBoosted subroutine, starting with the :IsBoosted label. The IsFiendOrUndead variable is set to 1, and a return from subroutine is executed.

Magic Missile

This script demonstrates using a loop and calling a subroutine to fire a number of missiles determine by the spell slot level used to cast the spell.

Magic Missile Script Output

!scriptcard  {{ 
  --#title|Magic Missile
  --#sourceToken|@{selected|token_id}
  --#targetToken|@{target|token_id}
  --=MissileCount|?{Spell Slot Level?|1|2|3|4|5|6|7|8|9} + 2
  --=DisplayCount|1
  --=MissileDamage|0
  --#leftsub|Slot level ?{Spell Slot Level?}
  --#rightsub|Ranged Attack
  --#emoteText|Fred uses a level ?{Spell Slot Level?} spell slot to fire [$MissileCount.Total] missiles of magical force!
  --:MissileLoop|
  -->FireMissile|
  --=DisplayCount|[$DisplayCount] + 1
  --?[$DisplayCount] -le [$MissileCount]|MissileLoop
  --+Total|Total damage is [$MissileDamage]
  --X|

  --:FireMissile|
  --=ThisMissile|1d4 + 1
  --=MissileDamage|[$MissileDamage] + [$ThisMissile]
  --+Missile|[$DisplayCount.Total] Hits for [$ThisMissile] [b]force[/b] damage
  --<|
}}

How It Works

Lines 1-3 set the card title, the source token and the target token. Setting these tokens causes their icons/avatars to appear in the Emote section of the card.

Line 4 asks the user what spell slot level they wish to use to cast magic missile. The number of missiles fired is equal to 2 plus the spell level, and this is stored in the MissileCount variable.

Line 5 stores a 1 in the DisplayCount variable. This will be used to control the loop to determine the number of missiles fired and the missile number when displaying damage rolls.

Line 6 initializes MissileDamage to 0

Line 7 sets the left subtitle to the text "Slot Level #", where # is the spell slot level being used.

Line 8 sets the right subtitle to the text "Ranged Attack".

Line 9 sets the emoteText parameter with a description of the action, including the slot level and number of missiles fired.

Line 10 is a label for the missile firing loop

Line 11 Calls the "FireMissile" subroutine

Line 12 increases the DisplayCount variable by 1

Line 13 Checks to see if there are still missles to fire (DisplayCount <= MissileCount) and if so branches to MissileLoop

Line 14 Displays the total damage dealt by the spell.

Line 15 stops execution of the script to prevent out of context execution of the subroutine.

Lines 76-21 are the FireMissile subroutine, beginning with the FireMissile label. The 1d4+1 is rolled and assigned to "ThisMissile". The result is added to the existing MissileDamage total, and a line for the current missile is displayed with the missile number and the damage for the missile.

Longsword Attack

This script demonstrates a standard 5E D&D melee weapon attack, including detection of misses, fumbles, hits, and critical hits. If installed, alterbars is used to decrement the target's BAR3 value by the damage dealt.

Longsword Script Output

!scriptcard  {{
  --#title|Longsword
  --#leftsub|Melee Attack
  --#sourceToken|@{selected|token_id}
  --#targetToken|@{target|token_id}
  --#emoteText|@{selected|token_name} attacks @{target|token_name}
  --=TargetAC|@{target|npc_ac}
  --?[$TargetAC.Total] -gt 0|DoneWithAC
  --=TargetAC|@{target|ac}
  --:DoneWithAC|
  --=AttackRoll|1d20 + @{selected|strength_mod} [STR] + @{selected|pb} [PROF]
  --+Attack|@{selected|token_name} rolls [$AttackRoll] vs AC [$TargetAC].
  --?[$AttackRoll.Base] -eq 20|Crit
  --?[$AttackRoll.Base] -eq 1|Fumble
  --?[$AttackRoll.Total] -ge [$TargetAC.Total]|Hit
  --+Miss|The attack missed.
  --^Final|

  --:Fumble|
  --+Fumble!|The attack went horribly wrong.
  --^Final|

  --:Hit|
  --=Damage|1d8 + @{selected|strength_mod} [STR]
  --+Hit!|The attack hit @{target|token_name} for [$Damage] slashing damage.
  --@alter|_target|@{target|token_id} _bar|3 _amount|-[$Damage]
  --^Final|

  --:Crit|
  --=Damage|1d8 + @{selected|strength_mod} [STR] + 1d8 [CRIT]
  --+Critical Hit!|The attack hit @{target|token_name} for [$Damage] slashing damage.
  --@alter|_target|@{target|token_id} _bar|3 _amount|-[$Damage]

  --:Final|
}}

How it Works

In lines 1-5, we set the title, subtitle, and emote text along with the tokens for the emote area.

Lines 6-9 allow us to determine the AC of the target. On the 5E Roll20 sheet, NPCs armor class is stored in "npc_ac", while PCs armor class is in "ac". First we grab npc_ac and if it is zero, we check AC.

Line 10 rolls the attack roll, rolling 1d20 and adding the attacker's strength modifier and proficiency bonus

Line 11 displays the result of the attack roll on the card

Lines 12-14 determine what kind of result the attack had. If the .Base value of the roll was 20, we branch to "Crit". If it was 1, we branch to "Fumble". If the .Total value of the roll was greater than or equal to the AC that was determined in Lines 6-9, we branch to Hit.

Assuming we didn't branc anywhere, the result of the attack was a miss, so we display that on line 15 and then branch to "Final"

This is followed by three branch segments, :Fumble, :Hit, and :Crit. A fumble displays a text message and branches to :Final.

On a hit or a crit, we roll Damage (adding additional damage dice on a crit). We display a "Hit!" or "Critical Hit!" message and then make an API call to AlterBars, passing it the token id, bar we want to modify (3 in this case), and the amount we want to modify by the Damage value.

Party Health Status

This example calculates the current Hit Points remaining and HP percentage for each character and creates a color-coded display with the current party status.

ScriptCards Party Health.png

!scriptcard  {{
  --#title|Party Status
  --#titleCardBackground|#33CC33
  --#oddrowbackground|#bfee90
  --#evenrowbackground|#90eebf
  -->HealthCheck|@{Quej Grastra|character_id}
  -->HealthCheck|@{Brim Cheuto|character_id}
  -->HealthCheck|@{Odug Ututees|character_id}
  --X|End of card Execution

  --:HealthCheck|
  --=HealthPerc|[*[%1%]:hp] / [*[%1%]:hp^] * 100 \ 1
  --=HealthColor|000000
  --?[$HealthPerc.Total] -gt 50|HealthSkip
  --=HealthColor|FF0000
  --:HealthSkip|
  --+[*[%1%]:character_name]|has [#[$HealthColor.RollText]][*[%1%]:hp] of [*[%1%]:hp^][/#] HP [R]([$HealthPerc.Total]%)[/R]
  --<|End of HealthCheck
}}

How it Works

Lines 1-4, we set the card title, and set the title background and row background colors to shades of green.

Lines 5-7 make gosub calls the the "HealthCheck" subroutine, passing in the character ID of each of the named characters (these are the names of the characters in my test game)

Line 8 terminates the script execution.

The remaining lines of the script are the HealthCheck subroutine, which works like this:

Line 10 is the subroutine label (:HealthCheck)

Line 11 uses the character id passed as a parameter and combines it with character attribute lookup *(...) to retrieve the value of "hp" and "hp^" for the character. The ^ character is used to specify that we want the MAX value for this attribute for the second call. We divide these two numbers and multiple by 100 to get a percentage. Finally, we use integer division by 1 to round the percentage and drop the decimals. The end result gets stored in the HealthPerc roll variable.

Line 12 defaults to color of the health text to black

Line 13 check to see if the health percentage is greater than 50. If so, it branches to HealthSkip, preventing the script from executing line 13.

Line 14 sets the color of the health text to red

Line 15 is the label that will be branched to from Line 13 to skip the red coloring

Line 16 again uses character attribute substitution and the passed parameter value to output a display line containing the character name, the colorized health total, and the percentage value. The percentage is right-justified.

Line 17 returns from the HealthCheck subroutine.

Expanded Magic Missile Script

This is the expanded and enhanced version of the Magic Missile script covered in this video. It includes visual and audio effects, checking and deducting spell slots, and applying damage using either Token-Mod or Alterbars.

!scriptcard {{ 
  --#title|Magic Missile
  --#sourceToken|@{selected|token_id}
  --#targetToken|@{target|token_id}

  -->GetAndCheckSlotInformation|

  --=MissileCount|[$SlotLevel] + 2
  --=DisplayCount|1
  --=MissileDamage|0
  --#leftsub|Slot level [$SlotLevel]
  --#rightsub|Ranged Attack
  --#emoteText|@{selected|character_name} uses a level [$SlotLevel.Total] spell slot to fire [$MissileCount.Total] missiles of magical force!

  --:MissileLoop|
  -->FireMissile|
  --=DisplayCount|[$DisplayCount] + 1
  --?[$DisplayCount] -le [$MissileCount]|MissileLoop
  --+Total|Total damage is [$MissileDamage]
  -->DeductSpellSlot|
  --#rightsub|Level [$SlotLevel] Left: [$SlotsRemaining] 
  -->PlayEffects|none;burst-smoke;beam-magic;spell_01
  -->ApplyDamageTokenmod|@{target|token_id};3;-[$MissileDamage]
  -->ApplyDamageAlterbars|@{target|token_id};3;-[$MissileDamage]
  --X|

  --:FireMissile|
  --=ThisMissile|1d4 + 1
  --=MissileDamage|[$MissileDamage] + [$ThisMissile]
  --+Missile|[$DisplayCount.Total] Hits for [$ThisMissile] [b]force[/b] damage
  --<|

  --:GetAndCheckSlotInformation|
  --=SlotLevel|?{Spell Slot Level?|1|2|3|4|5|6|7|8|9}
  --=SlotsTotal|[*S:lvl[$SlotLevel]_slots_total]
  --=SlotsExpended|[*S:lvl[$SlotLevel]_slots_expended]
  --?[$SlotsExpended.Total] -ge [$SlotsTotal.Total]|NoSlotsLeft
  --<|

  --:NoSlotsLeft|
  --+|[*S:character_name] has no level [$SlotLevel.Total] spell slots available.
  --X|

  --:DeductSpellSlot|
  --=SlotsExpended|[$SlotsExpended] + 1
  --@setattr|_charid [*S:character_id] _lvl[$SlotLevel]_slots_expended|[$SlotsExpended] _silent
  --=SlotsRemaining|[$SlotsTotal] - [$SlotsExpended]
  --<|

  --:PlayEffects|Parameters are : source effect; target effect; line effect; sound effect
  --vtoken|@{selected|token_id} [%1%]
  --vtoken|@{target|token_id} [%2%]
  --vbetweentokens|@{selected|token_id} @{target|token_id} [%3%]
  --@roll20AM|_audio,play,nomenu|[%4%]
  --<|

  --:ApplyDamageTokenmod|Parameters are tokenid;bar#;amount
  --@token-mod|_ignore-selected _ids [%1%] _set bar[%2%]_value|[%3%]
  --<|

  --:ApplyDamageAlterbars|
  --@alter|_target|[%1%] _bar|[%2%] _amount|[%3%]
  --<|
}}