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

Personal tools

Difference between revisions of "Script:ScriptCards"

From Roll20 Wiki

Jump to: navigation, search
(Magic Missile)
(Magic Missile)
Line 470: Line 470:
 
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.
 
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.
  
[[File:ScriptCards MagicMissile.png|Magic Missile Script Output]]
+
[[File:ScriptCards_MagicMissile_Fixed.png|Magic Missile Script Output]]
  
 
<pre>
 
<pre>

Revision as of 16:05, 30 January 2021

API ScriptAuthor: Kurt J.
Version: 0.0.5
Last Modified: 2021-01-29
Code: ScriptCards
Dependencies: None
Conflicts: None

Contents

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.

ScriptCardsis 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. SAC includes its own built-in dice roll parser to allow for the use of variables inside dice rolls.

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)
--? Conditinal 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.

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

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.

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)

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

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.

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

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.

The following comparison operators are available:

Comparator Meaning
-eq Equal To
-ne 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).

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

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] Inert 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

Referencing 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.

Example Scripts

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

Divine Smite

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

Divine Smite Script Output

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

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

How It Works

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

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

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

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

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

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

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

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

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

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

Magic Missile

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

Magic Missile Script Output

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

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

How It Works

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

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

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

Line 6 initializes MissileDamage to 0

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

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

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

Line 10 is a label for the missile firing loop

Line 11 Calls the "FireMissile" subroutine

Line 12 increases the DisplayCount variable by 1

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

Line 14 Displays the total damage dealt by the spell.

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

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

Longsword Attack

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

Longsword Script Output

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

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

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

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

  --:Final|
}}

How it Works

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

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

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

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

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

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

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

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

Party Health Status

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

ScriptCards Party Health.png

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

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

How it Works

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

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

Line 8 terminates the script execution.

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

Line 10 is the subroutine label (:HealthCheck)

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

Line 12 defaults to color of the health text to black

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

Line 14 sets the color of the health text to red

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

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

Line 17 returns from the HealthCheck subroutine.