Difference between revisions of "Script:ScriptCards"
From Roll20 Wiki
(→Example Scripts) |
(→What to Know if you are Coming from PowerCards) |
||
Line 947: | Line 947: | ||
== What to Know if you are Coming from PowerCards == | == 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. | ||
+ | |||
+ | ::{| class="wikitable" | ||
+ | |- | ||
+ | ! 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 --+ line type produces output | ||
+ | |- | ||
+ | | PowerCards lines begin with two dashes (--) followed by a unique tag name for the line, followed by a vertical bar and the content for the line. || ScriptCards lines begin with two dashes (--) followed by a '''statement type identifier''', which is a single character that identifies the type of line to the interpreter. This is followed by a tag (frequently optional), a vertical bar, and the parameters for the statement being executed. | ||
+ | |- | ||
+ | | PowerCard macros are always processed top to bottom. Lines can be hidden so they don't output anything, but there is no looping or branching (--SkipTo looks like a branch, but it just hides all of the lines until the referenced label. || ScriptCards scripts support true branching, including direct branching (--^) and procedure branching (--> and --<). Procedures support parameters and a call stack so procedures can be nested to call other procedures. | ||
+ | |- | ||
+ | | All lines in a PowerCards macro need to have unique tags because PowerCards builds the card as a single Java 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 most 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) | ||
+ | |- | ||
+ | | PowerCards relies on the Roll20 Quantum Roll server and inline rolls for all dice functions || ScriptCards includes its own dice roll parser, and '''''does not support''''' inline rolls. | ||
+ | |- | ||
+ | | PowerCards RollIDs (often mistaken for variables) are assigned by analyzing the results of an inline roll, and cannot be referenced in other rolls, so you can't roll a 1d4 and then roll a 1d20 and add the 1d4 result because all of the rolls happen on the chat server before PowerCards gets the macro text. || ScriptCards supports two types of variables: Roll Variables and String Variables. Because ScriptCards uses its own roll parser and is not dependent upon the chat server, rolls and their results can be used in other rolls, math functions, output, etc. | ||
+ | |} | ||
== Example Scripts == | == Example Scripts == |
Revision as of 12:44, 17 February 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.
ScriptCards is not game-system specific, and can be used with any system/sheet.
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 doe not have any system ties to D&D4E.
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.
- 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 This 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 could be considered a spiritual successor 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 intrinsic 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 one of the two subtitles dependent upon the results of a dice roll, and while I’ve implemented a simple “skip forward” mechanism 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 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.
Implemented 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.
What is a ScriptCard
A ScriptCard is a macro that will produce a card of information in the chat window. A ScriptCard is composed of an API command in chat !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 what it should do.
Structure of a ScriptCard Line
All ScriptCard lines begin with two dashes, followed by an identifying symbol that identifies to 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.
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.
Prefix Statement Type Tag Content --# Set Card Parameter Parameter Name Parameter Value --+ Direct Output Output in bold at start of line. Output in normal text after Tag --= Assign Roll Variable Variable Name Roll Equation (or text) to assign --@ API Call API command API call Parameters (replace -- with _) --: Branch Label Label Name Unused (Comments if desired) --^ Branch To Label name to branch to Unused (Comments if desired) --> Call Procedure Label name to call Procedure parameter list semicolon (;) separated --< Return from Sub Unused Unused (Comments if desired) --? Conditional Branch Condition to be evaluated Label name to branch to if true. If the label name is preceded with a > symbol, this will be a procedure call branch, and a semicolon (;) separated list of parameters can be added after the label name. --s Store to Persistent Storage "settings", "rollvariables", or "stringvariables" Name of the data set to store (see save/load section below) *Requires v 0.0.8 --l Load from Persistent Storage "settings", "rollvariables", or "stringvariables" Name of the data set to store (see save/load section below) *Requires v 0.0.8 --v Create Visual Effect Either "token" or "betweentokens" Tokens and parameters for generating the effect *Requires v 0.0.10 --e Echo to Chat Name to send chat command as Chat message to send *Requires v 0.0.10 --& Set string variable String variable name Content to store in the string variable *Requires v 0.0.10 --R Retrieve Repeating Section Row information "find", "first", or "next" Parameters for retrieving row information. See Referencing below *Requires v 0.0.13 --~ Assign Roll Var to built in function Function Name Parameters for function *Requires v 0.0.13 --c Case Statement Test Value Vertical bar separated list of cases, with the match:branchlabel format. Can contain procedure calls and parameters. *Requires v 1.0.0
ScriptCard Statement Type Details
The sections below detail the individual statement types supported by ScriptCards
Set ScriptCard Parameter (--#)
A --# line 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 lines, 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 buttonBackgroundColor Background color for buttons created with [button][/button] #1C6EA4 buttonBorderColor Border (outline) color for buttons create with [button][/button] #999999 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
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
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 *Requires v0.0.8 .tableEntryImgURL The image source portion of the result of a table roll *Requires v0.0.8 .tableEntryValue Numeric value of tableEntryText (via parseInt). If a non-numeric value, will be 0 *Requires v0.0.10b
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 is called to modify a token's Bar 3 value.
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 Branch (--?)
A conditional statement contains some equation in the Tag that will be evaluated. If the result of the evaluation is true, execution will branch to the label specified by the Content portion of the statement.
If the label is preceded by a ">" character, the branch will be treated as a gosub. In this case, a semicolon separated list of parameters to pass to the subroutine can be appended to the content.
Examples:
--?[$AttackRoll.Base] -eq 20|CriticalHit --?[$AttackRoll.Base] -eq 1|>Fumble;@{selected|dexterity_mod} --?@{target|npc_type} -inc "undead"|IsUndead
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 last example looks for the word "undead" in the npc_type attribute of the targeted character. If it exists in the text, the code will branch to the IsUndead label.
Text that does/may contain a space should be enclosed in double quotes.
Note: As of version 0.0.10, you can also specify a branch destination on a False result from the conditional. To do this, append a vertical bar followed by the false branch label. Procedure call branches with parameters are supported in both cases.
Example of a True and False Branch Conditional:
--?[$Attack.Total] >= [$ArmorClass]|>Hit|>Miss
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.
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).
As of version 0.0.8, 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. 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.
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.
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".
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 *Requires v0.0.8 .tableEntryImgURL The image source portion of the result of a table roll *Requires v0.0.8 .tableEntryValue If the tableEntryText is purely numeric, will contain the numeric value *Requires v0.0.8
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 Attributes
A character 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.
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.
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.
Procedure Libraries
Requires version 1.0.0
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.
Library Code (Paste into a handout called "ScriptCards Library 5E Tools" in your Roll20 Game):
--/|ScriptCards Library: 5E Tools version 0.0.2 --/|Provides various utility procedures for D&D 5E games --/|NOTE: Some procedures require ChatSetAttr to be installed --/|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] --<| --/|Lib5E_DeductSpellSlot will use chatsetattr to reduce expend a spell slot of a given level --/|Pass a character_id and the slot level number --: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 --:ResourceLoop| --?"[*R:resource_left_name]" -eq "[%2%]"|_Lib5E_IsResourceLeft --?"[*R:resource_right_name]" -eq "[%2%]"|_Lib5E_IsResourceRight --Rnext| --?"[*R:resource_left_name]" -ne "NoRepeatingAttributeLoaded"|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] --<| --<|
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 --+ line type produces output PowerCards lines begin with two dashes (--) followed by a unique tag name for the line, followed by a vertical bar and the content for the line. ScriptCards lines begin with two dashes (--) followed by a statement type identifier, which is a single character that identifies the type of line to the interpreter. This is followed by a tag (frequently optional), a vertical bar, and the parameters for the statement being executed. PowerCard macros are always processed top to bottom. Lines can be hidden so they don't output anything, but there is no looping or branching (--SkipTo looks like a branch, but it just hides all of the lines until the referenced label. ScriptCards scripts support true branching, including direct branching (--^) and procedure branching (--> and --<). Procedures support parameters and a call stack so procedures can be nested to call other procedures. All lines in a PowerCards macro need to have unique tags because PowerCards builds the card as a single Java 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 most 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) PowerCards relies on the Roll20 Quantum Roll server and inline rolls for all dice functions ScriptCards includes its own dice roll parser, and does not support inline rolls. PowerCards RollIDs (often mistaken for variables) are assigned by analyzing the results of an inline roll, and cannot be referenced in other rolls, so you can't roll a 1d4 and then roll a 1d20 and add the 1d4 result because all of the rolls happen on the chat server before PowerCards gets the macro text. ScriptCards supports two types of variables: Roll Variables and String Variables. Because ScriptCards uses its own roll parser and is not dependent upon the chat server, rolls and their results can be used in other rolls, math functions, output, etc.
Example Scripts
Below are some sample scripts that utilize the various statement types in ScriptCards:
Divine Smite
This script will prompt the user for a spell slot level to expend on a divine smite. It will check the target's npc_type to see if it is an Undead or Fiend, which adds an additional d8 to the smite roll.
!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 YouTube 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%] --<| }}