Difference between revisions of "Script:ScriptCards"
From Roll20 Wiki
(→Introduction) |
(→Introduction) |
||
Line 13: | Line 13: | ||
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. | 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.1.19 | ||
+ | Current Development Version : 1.2.3 | ||
'''''<big>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. This is useful for some sheets that have wildly complicated formulas for simple values like Armor Class (3.5 Sheet, I'm looking at you!) </big>''''' | '''''<big>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. This is useful for some sheets that have wildly complicated formulas for simple values like Armor Class (3.5 Sheet, I'm looking at you!) </big>''''' |
Revision as of 14:19, 13 May 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.
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.1.19 Current Development Version : 1.2.3
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. This is useful for some sheets that have wildly complicated formulas for simple values like Armor Class (3.5 Sheet, I'm looking at you!)
- ScriptCards thread(Forum)
- Development Gist - sourcecode before the one-click version is updated
- ScriptCards Intro 45min, Jan 2021
- ScriptCards Magic Missile Deep Dive 39min, Feb 2021
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:
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 --# 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 Either "token" or "betweentokens" Tokens and parameters for generating the effect Visual effects are played on the page the token is on. --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. --* 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
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.
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
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 title Text displayed in the title area of the card ScriptCards 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) 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 titleCardBackground A hex color code representing the background color of the title area. #1c6ea4 titleFontFace Name of the font used on the title area Contrail One titleFontSize Size of the title font 1.2em titleFontLineHeight Line spacing on the title area 1.2em bodyFontSize Size of the text in the card rows 15px bodyFontFace Name of the font used in the card rows Tahoma evenRowBackground Hex code for the background color for even rows #eeeeee oddRowBackground Hex code for the background color for even rows #d0e4f5 evenRowFontColor Hex code for the text color for even rows #000000 oddRowFontColor Hex code for the text color for odd rows #000000 emoteBackground Background color of the emote area #f5f5ba emoteText Text to display in the emote portion of the card None (Empty) emoteState If set to anything other than "visible", the emote portion of the card will not be displayed visible 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 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 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 hideCard If set to any non-default value, the entire card output will be suppressed 0 buttonTextColor Text color of labels on buttons created with [button][/button] #FFFFFF buttonBackground Background color for buttons created with [button][/button] #1C6EA4 buttonBorderColor Border (outline) color for buttons created with [button][/button] #999999 buttonFontSize Text size for captions on buttons created with [button][/button] x-small buttonFontFace Font Family specifier for captions on buttons created with [button][/button] Tahoma roundUp If set to a non-default value, integer division will round up instead of down 0 allowplaintextinrolls If set to a non-zero value, plain character text in rolls will be copied to the roll text 0 diceFontColor Color of the dice created with the [d4] [d6], etc. formatting markers #1C6EA4 dicefontsize Size of the dice created with the [d4] [d6], etc. formatting markers 3.0em usehollowdice If set to a non-zero value, the hollow/outline versions of the dice fonts will be used 0 whisper Comma separated list of who to whisper the output to. Use "gm" for GMs and "self" for the sender showfromfornonwhispers If set to a non-zero value, will include the sender on cards that aren't whispered 0 noMinMaxHilight If set to a non-zero value, rolls included in direct output lines will always have the standard yellow background 0 activepage If et to a page ID, will be used for [*P:] attribute references. The "playerpage" string can be used to retrieve the current player ribbon page. (v1.2.2+) empty
Less frequently used settings These settings can be used, but you should know exactly what you are doing if you set them, as some of these can fundamentally alter ScriptCards behavior:
Name Effect/Use Default Value 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 subtitleSeperator The character(s) that will be placed between leftsub and rightsub ♦ tableBorderRadius CSS specifier for how rounded the borders of the output card are. Use "0px;" for square borders 6px; tableShadow CSS specifier for the drop shadow under the output card 5px 3px 3px 0px #aaa; allowplaintextinrolls If set to a non-zero value, inline rolls will not be filtered out of output text. This is most commonly used when referencing attribute values that contain inline rolls 0 disablestringexpansion If set to a non-zero value, string variable references ([&varname]) will not be replaced with their value, and instead remain as the reference 0 disablerollvariableexpansion If set to a non-zero value, roll variable references ([$varname]) will not be replaced with their value, and instead remain as the reference 0 disableparameterexpansion If set to a non-zero value, subroutine parameter references ([%1%]) will not be replaced with their value, and instead remain as the reference 0 disableattributereplacement If set to a non-zero value, character attribute references ([*-charid:attribute]) will not be replaced with their value, and instead remain as the reference 0 disableinlineformatting If set to a non-zero value, inline formatting (bold, italics, color, text alignment, etc.) will not be performed on --+ lines 0 disablerollprocessing If set to a non-zero value, --= lines will not process dice rolls strings 0
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.
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
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.
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.
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.
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 Double quotes is a feature of 1.2.x =VariableName =Roll;1d20) &VariableName &Result;Hit|&Result;Miss) % or %! The current for...next loop will perform the "next" action (%) or will break out (%!) Requires v1.2.5 or greater
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.
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
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.
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] }}
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| }}
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 Roll Variable to Built-In Function (--~)
ScriptCards has the ability to run a function built into the API script and return the results to a roll variable. 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 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 math min math;min;valueA;valueB rollVariable Returns the smaller of valueA vs valueB math max math;max;valueA;valueB rollVariable Returns the larger of valueA vs valueB math clamp math;clamp;value;lowerBound;upperBound rollVariable Returns value, but restricted to the range of loweBound and upperBound. math round math;round;value rollVariable Rounds value to the nearest integer math floor math;floor;value rollVariable Rounds value down, dropping any decimal portion of the number math ceil math;ceil;value rollVariable Rounds value up to the next integer, dropping any decimal portion of the number 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 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 stringVariable Converts the passed string to lower case and assigns to the passed variable name. (v1.2.3+) string touppercase string stringVariable Converts the passed string to upper case and assigns to the passed variable name. (v1.2.3+) string totilecase string stringVariable Converts the passed string to title case (capitlaizes the first letter of each word) and assigns to the passed variable name. (v1.2.3+) 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" array define arrayname;value1;value2;... none Creates an array called "arrayname" and adds value1, value2, etc. to the array 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 occurances of "currentvalue" in "arayname" 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 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. 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 Returns an array of the active statusmarkers (sometimes called Token Markers) for the specified token
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
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 (--+) 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 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.
If you ID refers to a token, token attributes can be accessed by preceding the attribute name with "t-", for example [*S:t-aura1_radius].
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.
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.
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;5E Tools;Colorize+++ would include three libraries (General, 5E Tools, 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 {{ +++5E Tools+++ --#|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 5E Tools” 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: 5E Tools 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
5E Tools
The 5E Tools 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.
Library Code (Paste into a handout called "ScriptCards Library 5E Tools" in your Roll20 Game):
--/|ScriptCards Library: 5E Tools version 0.0.6 --/|Provides various utility procedures for D&D 5E games --/|NOTES: Some procedures require ChatSetAttr to be installed, see the ScriptCards WIKI for procedure documentation --: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] --<| --:Lib5E_DeductSpellSlot|characterid;slotlevel --=_Lib5ESlotsExpended|[*[%1%]:lvl[%2%]_slots_expended] + 1 --=_Lib5ESlotsExpended|[$_Lib5ESlotsExpended] + 1 --~_Lib5ESlotsExpended|math;min;[$_Lib5ESlotsExpended];[*[%1%]:lvl[%2%]_slots_total] --@setattr|_charid [%1%] _lvl[%2%]_slots_expended|[$_Lib5ESlotsExpended] _silent --<| --:Lib5E_FindResource|character_id;resourceName;resourceReturnNameStringVariable;ResourceReturnValueStringVariable --C[%2%]|[*[%1%]:class_resource_name]:_Lib5E_IsResourceClass|[*[%1%]:other_resource_name]:_Lib5E_IsResourceOther --?"[%2%]" -eq "[*[%1%]:class_resource_name]"|_Lib5E_IsResourceClass --?"[%2%]" -eq "[*[%1%]:other_resource_name]"|_Lib5E_IsResourceOther --Rfirst|[%1%];repeating_resource --:_Lib5E_ResourceLoop| --?"[*R:resource_left_name]" -eq "[%2%]"|_Lib5E_IsResourceLeft --?"[*R:resource_right_name]" -eq "[%2%]"|_Lib5E_IsResourceRight --Rnext| --?"[*R:resource_left_name]" -ne "NoRepeatingAttributeLoaded"|_Lib5E_ResourceLoop --&[%3%]|NotFound --&[%4%]|NotFound --$[%4%]|0 --<| --:_Lib5E_IsResourceClass| --+IsClass| --&[%3%]|class_resource_name --&[%4%]|class_resource --=[%4%]|[*[%1%]:class_resource] --<| --:_Lib5E_IsResourceOther| --+IsOther!| --&[%3%]|class_resource_name --&[%4%]|class_resource --=[%4%]|[*[%1%]:other_resource] --<| --:_Lib5E_IsResourceLeft| --+IsLeft| --&[%3%]|[*R>resource_left_name] --&[%4%]|[*R>resource_left] --=[%4%]|[*R:resource_left] --<| --:_Lib5E_IsResourceRight| --+IsRight| --&[%3%]|[*R>resource_right_name] --&[%4%]|[*R>resource_right] --=[%4%]|[*R:resource_right] --<| --<| --:Lib5E_DivineSmiteDice|targetTokenID;SlotLevelToUse;StringVariableToSet --=_Lib5E_DS_DiceCount|[%2%] + 1 --=_Lib5E_DS_IsFiendOrUndead|0 --?"[*[%1%]:npc_type]" -inc fiend|>_Lib5E_DS_IsBoosted --?"[*[%1%]:npc_type]" -inc undead|>_Lib5E_DS_IsBoosted --=_Lib5E_DS_DiceCount|[$_Lib5E_DS_DiceCount] + [$_Lib5E_DS_IsFiendOrUndead] --&[%3%]|[$_Lib5E_DS_DiceCount.Total]d8 --<| --:_Lib5E_DS_IsBoosted| --=_Lib5E_DS_IsFiendOrUndead|1 --< --:Lib5E_Active_Global_Attack_Modifiers|character_id;StringVariableToSet --&_Lib5E_Temp| --Rfirst|[%1%];repeating_tohitmod --:_Lib5E_GAM_Loop| --?"[*R:global_attack_active_flag]" -eq "1"|>_Lib5EAddGAM;[*R:global_attack_name];[*R:global_attack_roll] --Rnext| --?"[*R:global_attack_name]" -ne "NoRepeatingAttributeLoaded"|_Lib5E_GAM_Loop --&[%2%]|[&_Lib5E_Temp] --<| --:_Lib5EAddGAM| --&_Lib5E_Temp|+ + [%2%] [[%1%]] --<| --:Lib5E_Active_Global_Save_Modifiers|character_id;StringVariableToSet --&_Lib5E_Temp| --Rfirst|[%1%];repeating_savemod --:_Lib5E_GSVM_Loop| --?"[*R:global_save_active_flag]" -eq "1"|>_Lib5EAddGSVM;[*R:global_save_name];[*R:global_save_roll] --Rnext| --?"[*R:global_save_name]" -ne "NoRepeatingAttributeLoaded"|_Lib5E_GSVM_Loop --&[%2%]|[&_Lib5E_Temp] --<| --:_Lib5EAddGSVM| --&_Lib5E_Temp|+ + [%2%] [[%1%]] --<| --:Lib5E_Active_Global_Skill_Modifiers|character_id;StringVariableToSet --&_Lib5E_Temp| --Rfirst|[%1%];repeating_skillmod --:_Lib5E_GSKM_Loop| --?"[*R:global_skill_active_flag]" -eq "1"|>_Lib5EAddGSKM;[*R:global_skill_name];[*R:global_skill_roll] --Rnext| --?"[*R:global_skill_name]" -ne "NoRepeatingAttributeLoaded"|_Lib5E_GSKM_Loop --&[%2%]|[&_Lib5E_Temp] --<| --:_Lib5EAddGSKM| --&_Lib5E_Temp|+ + [%2%] [[%1%]] --<| --:Lib5E_Active_Global_AC_Modifiers|character_id;StringVariableToSet --&_Lib5E_Temp| --Rfirst|[%1%];repeating_acmod --:_Lib5E_GACM_Loop| --?"[*R:global_ac_active_flag]" -eq "1"|>_Lib5EAddGACM;[*R:global_ac_name];[*R:global_ac_val] --Rnext| --?"[*R:global_ac_name]" -ne "NoRepeatingAttributeLoaded"|_Lib5E_GACM_Loop --&[%2%]|[&_Lib5E_Temp] --<| --:_Lib5EAddGACM| --&_Lib5E_Temp|+ + [%2%] [[%1%]] --<| --:Lib5E_Active_Global_Damage_Modifiers|character_id;StringVarNormalDamage;StringVarCritDamage --&_Lib5E_Temp| --&_Lib5E_Temp2| --Rfirst|[%1%];repeating_damagemod --:_Lib5E_GDM_Loop| --?"[*R:global_damage_active_flag]" -eq "1"|>_Lib5EAddGDM;[*R:global_damage_name];[*R:global_damage_damage];[*R:global_damage_critical_damage] --Rnext| --?"[*R:global_damage_name]" -ne "NoRepeatingAttributeLoaded"|_Lib5E_GDM_Loop --&[%2%]|[&_Lib5E_Temp] --&[%3%]|[&_Lib5E_Temp2] --<| --:_Lib5EAddGDM| --&_Lib5E_Temp|+ + [%2%] [[%1%]] --&_Lib5E_Temp2|+ + [%3%] [[%1%] CRIT] --<| --:Lib5E_PC_Attribute_Summary|character_id --+|[t][tr][td][b]Str[/b] [*[%1%]:strength] ([*[%1%]:strength_mod])[/td][td][b]Dex[/b] [*[%1%]:dexterity] ([*[%1%]:dexterity_mod])[/td][td][b]Con[/b] [*[%1%]:constitution] ([*[%1%]:constitution_mod]) [/td][/tr] [tr][td][b]Int[/b] [*[%1%]:intelligence] ([*[%1%]:intelligence_mod])[/td][td][b]Wis[/b] [*[%1%]:wisdom] ([*[%1%]:wisdom_mod])[/td][td][b]Cha[/b] [*[%1%]:charisma] ([*[%1%]:charisma_mod])[/td][/tr] [tr][td][b]AC[/b] [*[%1%]:ac][/td][td][b]HP[/b][*[%1%]:hp]/[*[%1%]:hp^][/td][td][/td][/tr][/t] --<| --:Lib5E_NPC_Attribute_Summary|character_id --+|[t width=100%][tr][td][b]Str[/b] [*[%1%]:strength] ([*[%1%]:strength_mod])[/td][td][b]Dex[/b] [*[%1%]:dexterity] ([*[%1%]:dexterity_mod])[/td][td][b]Con[/b] [*[%1%]:constitution] ([*[%1%]:constitution_mod]) [/td][/tr] [tr][td][b]Int[/b] [*[%1%]:intelligence] ([*[%1%]:intelligence_mod])[/td][td][b]Wis[/b] [*[%1%]:wisdom] ([*[%1%]:wisdom_mod])[/td][td][b]Cha[/b] [*[%1%]:charisma] ([*[%1%]:charisma_mod])[/td][/tr] [tr][td][b]AC[/b] [*[%1%]:npc_ac][/td][td][b]HP[/b][*[%1%]:hp]/[*[%1%]:hp^][/td][td][b]CR[/b] [*[%1%]:npc_challenge][/td][/tr][/t] --<| --:Lib5E_NPC_Qualities_Summary|character_id --+Type|[*[%1%]:npc_type] --?"[*[%1%]:npc_vulnerabilities]" -eq ""|_Lib5E_NPCQS_Skip1 --+Vulnerable|[*[%1%]:npc_vulnerabilities] --:_Lib5E_NPCQS_Skip1| --?"[*[%1%]:npc_resistances]" -eq ""|_Lib5E_NPCQS_Skip2 --+Resistant|[*[%1%]:npc_resistances] --:_Lib5E_NPCQS_Skip2| --?"[*[%1%]:npc_immunities]" -eq ""|_Lib5E_NPCQS_Skip3 --+Immune|[*[%1%]:npc_immunities] --:_Lib5E_NPCQS_Skip3| --?"[*[%1%]:npc_condition_immunities]" -eq ""|_Lib5E_NPCQS_Skip4 --+Cond. Immune|[*[%1%]:npc_condition_immunities] --:_Lib5E_NPCQS_Skip4| --?"[*[%1%]:npc_senses]" -eq ""|_Lib5E_NPCQS_Skip5 --+Cond. Immune|[*[%1%]:npc_senses] --:_Lib5E_NPCQS_Skip6| --<| --:Lib5E_PC_Class_Summary|character_id --&_Lib5E_Temp|[t][tr][td][*[%1%]:class] - [*[%1%]:base_level][/td][/tr] --?"[*[%1%]:multiclass1_flag]" -eq "0"|_Lib5E_PC_Class_Summary_Done --&_Lib5E_Temp|+[tr][td][*[%1%]:multiclass1] - [*[%1%]:multiclass1_lvl] --?"[*[%1%]:multiclass2_flag]" -eq "0"|_Lib5E_PC_Class_Summary_Done --&_Lib5E_Temp|+[tr][td][*[%1%]:multiclass2] - [*[%1%]:multiclass2_lvl] --?"[*[%1%]:multiclass3_flag]" -eq "0"|_Lib5E_PC_Class_Summary_Done --&_Lib5E_Temp|+[tr][td][*[%1%]:multiclass3] - [*[%1%]:multiclass3_lvl] --:_Lib5E_PC_Class_Summary_Done| --&_Lib5E_Temp|+[/t] --+|[&_Lib5E_Temp] --<| --:Lib5E_PC_Attack_List|character_id --&_Lib5E_Temp| --Rfirst|[%1%];repeating_attack --:_Lib5E_PCAL_Loop| --?"[*R:atkname]" -eq "NoRepeatingAttributeLoaded"|_Lib5E_PCAL_Done --&_Lib5E_NameTemp|[*R:atkname] --~_Lib5E_NameTemp|string;replace;(; ;[&_Lib5E_NameTemp] --~_Lib5E_NameTemp|string;replace;); ;[&_Lib5E_NameTemp] --&_Lib5E_Temp|+[button][&_Lib5E_NameTemp]::~[%1%]|[*R>attack][/button] --Rnext| --^_Lib5E_PCAL_Loop| --:_Lib5E_PCAL_Done| --+Available Attacks|[br][&_Lib5E_Temp] --<| --:Lib5E_NPC_Action_List|character_id --&_Lib5E_Temp| --&_Lib5E_FoundOne|0 --Rfirst|[%1%];repeating_npcaction --:_Lib5E_NPCAL_Loop| --?"[*R:name]" -eq "NoRepeatingAttributeLoaded"|_Lib5E_NPCAL_Done --&_Lib5E_NameTemp|[*R:name] --~_Lib5E_NameTemp|string;replace;(; ;[&_Lib5E_NameTemp] --~_Lib5E_NameTemp|string;replace;); ;[&_Lib5E_NameTemp] --&_Lib5E_Temp|+[button][&_Lib5E_NameTemp]::~[%1%]|[*R>npc_action][/button] --&_Lib5E_FoundOne|1 --Rnext| --^_Lib5E_NPCAL_Loop| --:_Lib5E_NPCAL_Done| --?"[&_Lib5E_FoundOne]" -eq "0"|_Lib5E_NPCAL_Skip --+Available Actions|[br][&_Lib5E_Temp] --:_Lib5E_NPCAL_Skip| --<| --:Lib5E_NPC_Legendary_Action_List|character_id --&_Lib5E_Temp| --&_Lib5E_FoundOne|0 --Rfirst|[%1%];repeating_npcaction-l --:_Lib5E_NPCLAL_Loop| --?"[*R:name]" -eq "NoRepeatingAttributeLoaded"|_Lib5E_NPCLAL_Done --&_Lib5E_NameTemp|[*R:name] --~_Lib5E_NameTemp|string;replace;(; ;[&_Lib5E_NameTemp] --~_Lib5E_NameTemp|string;replace;); ;[&_Lib5E_NameTemp] --&_Lib5E_Temp|+[button][&_Lib5E_NameTemp]::~[%1%]|[*R>npc_action][/button] --&_Lib5E_FoundOne|1 --Rnext| --^_Lib5E_NPCLAL_Loop| --:_Lib5E_NPCLAL_Done| --?"[&_Lib5E_FoundOne]" -eq "0"|_Lib5E_NPCLAL_Skip --+Available Legendary Actions|[br][&_Lib5E_Temp] --:_Lib5E_NPCLAL_Skip| --<| --:Lib5E_NPC_Description_List|character_id;repeatingList;Name --&_Lib5E_Temp| --&_Lib5E_FoundOne|0 --Rfirst|[%1%];[%2%] --:_Lib5E_NPCDESCL_Loop| --?"[*R:name]" -eq "NoRepeatingAttributeLoaded"|_Lib5E_NPCDESCL_Done --&_Lib5E_NameTemp|[*R:name] --~_Lib5E_NameTemp|string;replace;(; ;[&_Lib5E_NameTemp] --~_Lib5E_NameTemp|string;replace;); ;[&_Lib5E_NameTemp] --&_Lib5E_Temp|+[&_Lib5E_NameTemp] --&_Lib5E_FoundOne|1 --Rnext| --^_Lib5E_NPCDESCL_Loop| --:_Lib5E_NPCDESCL_Done| --?"[&_Lib5E_FoundOne]" -eq "0"|_Lib5E_NPCDESCL_Skip --+[%3%]|[&_Lib5E_Temp] --:_Lib5E_NPCDESCL_Skip| --<| --:Lib5E_PC_Summary|character_id -->Lib5E_PC_Attribute_Summary|[%1%] -->Lib5E_PC_Class_Summary|[%1%] -->Lib5E_PC_Attack_List|[%1%] --<| --:Lib5E_NPC_Summary|character_id -->Lib5E_NPC_Attribute_Summary|[%1%] -->Lib5E_NPC_Description_List|[%1%];repeating_npctrait;Traits -->Lib5E_NPC_Qualities_Summary|[%1%] -->Lib5E_NPC_Action_List|[%1%] -->Lib5E_NPC_Legendary_Action_List|[%1%] -->Lib5E_NPC_Description_List|[%1%];repeating_npcreaction;Available Reactions[br] --<| --:Lib5E_Character_Summary|character_id --?"[*[%1%]:npc]" -eq "0"|>Lib5E_PC_Summary;[%1%]|>Lib5E_NPC_Summary;[%1%] --<|
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 outputPowerCards 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 a1d20
and add the1d4
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.
!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.
!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.
!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.
!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%] --<| }}