Roll20 uses cookies to improve your experience on our site. Cookies enable you to enjoy certain features, social sharing functionality, and tailor message and display ads to your interests on our site and others. They also help us understand how our site is being used. By continuing to use our site, you consent to our use of cookies. Update your cookie preferences .
×
Create a free account

[Script] ScriptCards - My "Spiritual Successor" to PowerCards

1613061464
timmaugh
Pro
API Scripter
I hate to keep interjecting how APILogic can help... it's just the nature of APILogic that it interacts and extends other scripts. Anyway, I think APIL can solve both of Duncan's requests. Commented Text If you don't want a portion of the command to execute, wrap it in an IF block, and set the test to false: {& if a = b}argument text you don't want to execute{& end} Then, if you want to enable it, set your test to  a = a  and the code will be included. If you want to enable/disable multiple different snippets of your ScriptCards macro at the same time, name the test the first time, and use that elsewhere: {& if ([troubleshoot] a = b)}argument text to enable/disable{&end} ...elsewhere after this point in the macro... {& if troubleshoot}other argument text to enable/disable{&end} Passing Variables Between Macros A DEFINE tag lets you create variables for later reuse in your macro. It can access and return data from sheet items. So if you used an ability, lets say, to simply record the definition of your various terms: Ability : ScriptCardsVariableLibrary {& define ([term1] text to insert when term1 is encountered) ([term2] text to insert when term2 is encountered) } ... then in any ScriptCards macro that wanted to access that library, you would simply have to include the ScriptCardsVariableLibrary call. According to the Roll20 order of operations, ability calls are expanded prior to the message reaching the script. In other words, where your ScriptCards call might look like this: !scriptcard %{Bob|ScriptCardsVariableLibrary} {{ ... other stuff ...what actually reaches the message is !scriptcard {& define ([term1]... Which APILogic intercepts, translates those variables for you, and injects them where it finds the terms you've defined. By the time ScriptCard receives the message, the definition tag is removed, and it only sees a reconstructed command line. ...which is a... *really* cool implementation of APILogic I hadn't even considered, but will now add to the Advanced Usage section of that thread!
1613062566
Duncan R.
Pro
Sheet Author
timmaugh said: I hate to keep interjecting how APILogic can help... it's just the nature of APILogic that it interacts and extends other scripts. Anyway, I think APIL can solve both of Duncan's requests. Inject away, as they say ..  'no such idea as a bad idea'. Although they probably hadn't heard mine. I do have the APILogic thread tagged as had already anticipated on using the extended branching capabilities at some point. So I have no problem using it for #1. #2 is interesting, although I am trying to not make any customisation changes to the character sheet just because over the years I have had 'customisations are bad' drilled into me.  And it also means I can jump between games, pull in a newer version of character sheets and such like without worry about stuff breaking because I forgot to add in attribute, or I can put scriptcard script on interweb for others to use without having to worry about people like me keep asking questions. But I will go down that route if I cant mind another way to do it.
1613063547

Edited 1613063704
timmaugh
Pro
API Scripter
That's fair on #2, but the Roll20 parser also expands a macro call (in fact, the wiki says macros are expanded right after Abilities in the order of operations)... so it seems you should be able to do the same process on a macro, instead. EDIT:...  going to go test this out... I'll report back
1613064256
Duncan R.
Pro
Sheet Author
Kurt J. said: Duncan R. said: Hi @Kurt. Just wondering if you had any more thoughts on: 1. A dedicated comment function or a change to --| so that if you put it in front of another valid command it won't execute it? Only useful for debugging but easier than cutting and pasting code in/out of a scriptcard script while developing. 2. And did you think of any other way I could fudge passing variables between scriptcard macros? I haven't tried using the load/save parameter yet, but that was going to be my next attempt. Just wondered if these were possible or not. For #1, how about a "log" statement that would spit out a line to the API Console log if #debug was turned on and do nothing if it isn't? See below for #2 .. snip .. Forgot to answer this one. Not sure about the solution. So what I was referring to was. Say I had line   --=TotalDice|[$DiceOne] + [$DiceTwo] + [$DramaDice]  + [*R:attackroll] [Attack Bonus] and I wanted to temporarily remove it, (without cut and paste, maybe I thought it was doing something odd, or create a copy and tweak the line) in other scripting languages I would just stick a comment in front of it. e.g. // --=TotalDice|[$DiceOne] + [$DiceTwo] + [$DramaDice]  + [*R:attackroll] [Attack Bonus] but if I do --| --=TotalDice|[$DiceOne] + [$DiceTwo] + [$DramaDice]  + [*R:attackroll] [Attack Bonus] It still tries to execute the line.
1613064323
Duncan R.
Pro
Sheet Author
timmaugh said: That's fair on #2, but the Roll20 parser also expands a macro call (in fact, the wiki says macros are expanded right after Abilities in the order of operations)... so it seems you should be able to do the same process on a macro, instead. EDIT:...  going to go test this out... I'll report back Ah great thanks, saves me having to work out how to do it. As I am still trying to learn everything as I go along.
1613065191
David M.
Pro
API Scripter
Duncan R. said: Forgot to answer this one. Not sure about the solution. So what I was referring to was. Say I had line   --=TotalDice|[$DiceOne] + [$DiceTwo] + [$DramaDice]  + [*R:attackroll] [Attack Bonus] and I wanted to temporarily remove it, (without cut and paste, maybe I thought it was doing something odd, or create a copy and tweak the line) in other scripting languages I would just stick a comment in front of it. e.g. // --=TotalDice|[$DiceOne] + [$DiceTwo] + [$DramaDice]  + [*R:attackroll] [Attack Bonus] Right, basically "ignore this entire line when prefaced by some key string", not "output some comments somewhere".
1613066284
David M.
Pro
API Scripter
Kurt J. said: Yea, --S and --L store variables to state (currently no way to delete them, but I'll work on something). That is likely the only way to pass things back and forth. I guess you could store items as attributes on characters (maybe make a dummy character to store them) and use chatsetattr to set them and the normal attribute notation to read them. Right, I was thinking something like --~WriteStateVar|[$Roll]       //where a Roll or String variable object is written to State (might be tricky allowing multiple object types, though, requiring a typeOf property or similar) --~ReadStateVar|StoredVal      //where the object in State is stored in a new variable StoredVal probably limiting it to one stored object to avoid cluttering up State with a bunch of orphaned objects. Maybe it will be a moot point if timmaugh's method works out. Also don't know how niche the application is relative to how long it would take to implement/test. Side note: The new functions sound great! Is the idea with range to roll as normal, then pass the [$roll] to the --~range function? Or would it be some new syntax at the time the roll is implemented?
1613066866
Duncan R.
Pro
Sheet Author
David M. said: Maybe it will be a moot point if timmaugh's method works out. Also don't know how niche the application is relative to how long it would take to implement/test. My use case is probably niche, although maybe if you could do it it would be popular. I suspect that if it could be done generically with APILogic (instead of, or as well as) that might be quite popular as there are many threads about 'how can I send parameters between macros'. David M. said: Right, basically "ignore this entire line when prefaced by some key string", not "output some comments somewhere". Yep.
1613068474

Edited 1613070713
timmaugh
Pro
API Scripter
So, that method of a "Macro Mule" for Variables will work! Here is the proof of concept: Macro : VariableLibrary {& define ([term1] something)} (explanation: anywhere we see "term1" we will replace with "something") Chat Input: !This is the variable #VariableLibrary you were looking for: term1{&simple} (The {&simple} tag just dumps it out to chat so I can see the result; in a real-world application, you wouldn't do that) Result: There is some quirk of the Roll20 parser that won't expand the macro reference if it is too early in the line (the first thing following the !). Put it downstream of the script handle and you should be fine. EDIT: I meant to mention that testing this helped me find a bug in APILogic, which I have remedied with the newly released version 1.1.1, available at my repo . If you have an earlier version, you'll want to grab the new one. EDIT 2 : This doesn't allow for storing the  changed value of the variable, per se, but that could easily be remedied with an APILogic plugin, which are currently in beta.
1613073254
Kurt J.
Pro
API Scripter
Because ScriptCards uses the -- marker to identify new lines, anything that modifies a line needs to come after the --. How about this as a proposal : I'll reserve the --/ sequence for comment out lines, so if you have  --=TotalDice|[$DiceOne] + [$DiceTwo] + [$DramaDice]  + [*R:attackroll] [Attack Bonus] you could just change it to: --/=TotalDice|[$DiceOne] + [$DiceTwo] + [$DramaDice]  + [*R:attackroll] [Attack Bonus] and it would be commented out. You can do this right now, because the --/ sequence is not defined as anything. I'm also adding "readstateitem" and "writestateitem" as functions. You will be able to store one roll variable and one string in the state that you can retrieve in other scripts. The name of the variable doesn't need to match between scripts since there is only one of each type (it isn't stored with the variable).
1613075908
Duncan R.
Pro
Sheet Author
Kurt J. said: --/=TotalDice|[$DiceOne] + [$DiceTwo] + [$DramaDice]  + [*R:attackroll] [Attack Bonus] and it would be commented out. You can do this right now, because the --/ sequence is not defined as anything. Ah, yes that would be perfect accidental solution.
1613082593
Duncan R.
Pro
Sheet Author
Duncan R. said: Kurt J. said: --/=TotalDice|[$DiceOne] + [$DiceTwo] + [$DramaDice]  + [*R:attackroll] [Attack Bonus] and it would be commented out. You can do this right now, because the --/ sequence is not defined as anything. Ah, yes that would be perfect accidental solution. Yes that works although I confused myself at first by adding '--/' to the start instead of splitting the '--+' to become '--/+' That a good enough work around for me. Thanks.
1613082810
Duncan R.
Pro
Sheet Author
timmaugh said: So, that method of a "Macro Mule" for Variables will work! Here is the proof of concept: Macro : VariableLibrary {& define ([term1] something)} (explanation: anywhere we see "term1" we will replace with "something") Chat Input: !This is the variable #VariableLibrary you were looking for: term1{&simple} (The {&simple} tag just dumps it out to chat so I can see the result; in a real-world application, you wouldn't do that) Result: There is some quirk of the Roll20 parser that won't expand the macro reference if it is too early in the line (the first thing following the !). Put it downstream of the script handle and you should be fine. EDIT: I meant to mention that testing this helped me find a bug in APILogic, which I have remedied with the newly released version 1.1.1, available at my repo . If you have an earlier version, you'll want to grab the new one. EDIT 2 : This doesn't allow for storing the  changed value of the variable, per se, but that could easily be remedied with an APILogic plugin, which are currently in beta. I will have to have a play with this as well, although not sure I will have a chance to get my head around APILogic before the game I am GMing on Saturday. Ditto for any extra features Kurt comes up with. I did notice v1.0 of APILogic in the roll20 script library was giving a warning about missing files, but manually putting in v1.1.1 from your repo got rid of that warning.
1613083122
Kurt J.
Pro
API Scripter
Duncan R. said: timmaugh said: So, that method of a "Macro Mule" for Variables will work! Here is the proof of concept: Macro : VariableLibrary {& define ([term1] something)} (explanation: anywhere we see "term1" we will replace with "something") Chat Input: !This is the variable #VariableLibrary you were looking for: term1{&simple} (The {&simple} tag just dumps it out to chat so I can see the result; in a real-world application, you wouldn't do that) Result: There is some quirk of the Roll20 parser that won't expand the macro reference if it is too early in the line (the first thing following the !). Put it downstream of the script handle and you should be fine. EDIT: I meant to mention that testing this helped me find a bug in APILogic, which I have remedied with the newly released version 1.1.1, available at my repo . If you have an earlier version, you'll want to grab the new one. EDIT 2 : This doesn't allow for storing the  changed value of the variable, per se, but that could easily be remedied with an APILogic plugin, which are currently in beta. I will have to have a play with this as well, although not sure I will have a chance to get my head around APILogic before the game I am GMing on Saturday. Ditto for any extra features Kurt comes up with. I did notice v1.0 of APILogic in the roll20 script library was giving a warning about missing files, but manually putting in v1.1.1 from your repo got rid of that warning. There will be a slew of new functions coming with the next release, including "writestateitem" and "readstateitem" similar to what David suggested above. Probably a day or so away, as I'm also writing a test suite so I can make sure I don't break things with new versions.
1613083928
Kurt J.
Pro
API Scripter
David M. said: Side note: The new functions sound great! Is the idea with range to roll as normal, then pass the [$roll] to the --~range function? Or would it be some new syntax at the time the roll is implemented? It would be the former. That might be a little more code on the script side, but it prevents trying to twist things into the roll parser code. I'd like to keep that as clean as I can. I just finished coding five major functions, most with multiple sub-functions. Rounding (closest, up/ceil, down/floor), Ranging (min, max, clamp), Read/Write State, and string manipulation (before, after, left, right, replace, substring, split) functions are all coded and tested. If there are other function suggestions, let me know as I'm always open to ideas.
1613089600
David M.
Pro
API Scripter
Groovy. As far as other functions, maybe modulo division? 
Another dumb question about repeating resources: what command do you use to access the max value for a given resource?
1613092718
Kurt J.
Pro
API Scripter
Jay R. said: Another dumb question about repeating resources: what command do you use to access the max value for a given resource? Append a ^ to the field name, so [*R:resource_left^]
Kurt J. said: Jay R. said: Another dumb question about repeating resources: what command do you use to access the max value for a given resource? Append a ^ to the field name, so [*R:resource_left^] Ah! I had seen that appendage in the Wiki, but didn't think it applied to repeating commands. Thank you!
Having a recurring issue where a roll variable set through Rfirst is not recognized when I run the modbattr command from ChatSetAttr. I can see from the API window that the right number is being picked up by Rfirst (8, the max value for my player's monk character ki points). But the modbattr command fails to set the Ki value to max. What am I doing wrong here? !scriptcard {{     --#title| ☯️ Short Rest ☯️   --#leftsub|@{selected|token_name}   --#sourceToken|@{selected|token_id}   --#emoteText|*@{selected|token_name} takes a short break to regain his mental focus.*   --#titleCardBackground|#674ea7   --#oddRowBackground|#dcd3f5   --#buttonBackgroundColor|#674ea7   --:CheckAttributes|   --Rfirst|@{selected|character_id};repeating_resource   --:ResourceLoop|   --?"[*R:resource_left_name]" -inc "Ki"|>SetKi;[*R>resource_left];[*R:resource_left^]   --?"[*R:resource_right_name]" -inc "Ki"|>SetKi;[*R>resource_right];[*R:resource_right^]   --Rnext|   --?"[*R:resource_left_name]" -ne "NoRepeatingAttributeLoaded"|ResourceLoop   --^SetKi|   --:SetKi|   --&AttributeName|[%1]   --=KiMax|[%2]   --^ReplenishKi|   --:ReplenishKi|   --=AttributeColor|00C301   --@modbattr|_name @{selected|character_name} _[&AttributeName]|[$KiMax] _silent   --+Replenished|@{selected|token_name} now has [b][#[$AttributeColor.RollText]][$KiMax.Total][/#][/b] Ki Points.   --X| }}
1613131617
Kurt J.
Pro
API Scripter
Make sure modbattr is the command you want to be using... The way I read the chatsetattr information, it adds to or subtracts from an attribute. If you want to just set the value to a specific number setattr is probably the better command. I would take off the _silent as well and let chatsetattr tell you what it is doing until you have it working and then put it back on.
Kurt J. said: Make sure modbattr is the command you want to be using... The way I read the chatsetattr information, it adds to or subtracts from an attribute. If you want to just set the value to a specific number setattr is probably the better command. I would take off the _silent as well and let chatsetattr tell you what it is doing until you have it working and then put it back on. Ok, will try your suggestions. I had already tried setattr before and didn't have success, but it's possible that something else was messed up in my scriptcard.  Edit: OK, problem solved. I was evidently tired enough that I missed a typo in my SetKi section (the closing % was missing from both variables). :)
1613134561
Sr. K
Pro
Sheet Author
Jay R. said: Kurt J. said: Make sure modbattr is the command you want to be using... The way I read the chatsetattr information, it adds to or subtracts from an attribute. If you want to just set the value to a specific number setattr is probably the better command. I would take off the _silent as well and let chatsetattr tell you what it is doing until you have it working and then put it back on. Ok, will try your suggestions. I had already tried setattr before and didn't have success, but it's possible that something else was messed up in my scriptcard.  The two first resources in a D&D 5e Sheet by Roll20 are not in a repeating section: @{class_resource_name} and @{other_resource_name}. I hope it helps.
Sr. K said: Jay R. said: Kurt J. said: Make sure modbattr is the command you want to be using... The way I read the chatsetattr information, it adds to or subtracts from an attribute. If you want to just set the value to a specific number setattr is probably the better command. I would take off the _silent as well and let chatsetattr tell you what it is doing until you have it working and then put it back on. Ok, will try your suggestions. I had already tried setattr before and didn't have success, but it's possible that something else was messed up in my scriptcard.  The two first resources in a D&D 5e Sheet by Roll20 are not in a repeating section: @{class_resource_name} and @{other_resource_name}. I hope it helps. That doesn't really relate to my (now-resolved) issue, though, since I am only checking for repeating resources, not class or other. Thanks, though.
Getting this error, which crashes the API, when I run a macro to transfer potions from one character to another: TypeError: Cannot read property 'nomixmaxhighlight' of undefined TypeError: Cannot read property 'nomixmaxhighlight' of undefined at replaceRollVariables (apiscript.js:22198:23) at apiscript.js:21709:41 at eval (eval at <anonymous> (/home/node/d20-api-server/api.js:154:1), <anonymous>:65:16) at Object.publish (eval at <anonymous> (/home/node/d20-api-server/api.js:154:1), <anonymous>:70:8) at /home/node/d20-api-server/api.js:1662:12 at /home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:93:560 at hc (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:39:147) at Kd (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:93:546) at Id.Mb (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:93:489) at Zd.Ld.Mb (/home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:94:425)
1613148641
The Aaron
Roll20 Production Team
API Scripter
There's a typo on line 818.  It should say nomi n maxhighlight   rather than nomi x maxhighlight
The Aaron said: There's a typo on line 818.  It should say nomi n maxhighlight   rather than nomi x maxhighlight I noticed that too, after I posted. Thanks for the catch. Edit: fixed the typo but the crash still happens.
I think the problem may be that Kurt has the setting as NoMinMaxHilight elsewhere in the code? The script seems to be looking for nominmaxhighlight in a scriptcard regardless of whether the scriptcard is using the parameter. Edit: Stripping all references to nominmaxhighlight from the 0.0.14 code allows my scriptcard to run. 
1613152307

Edited 1613152569
Duncan R.
Pro
Sheet Author
Jay R. said: I think the problem may be that Kurt has the setting as NoMinMaxHilight elsewhere in the code? The script seems to be looking for nominmaxhighlight in a scriptcard regardless of whether the scriptcard is using the parameter. Edit: Stripping all references to nominmaxhighlight from the 0.0.14 code allows my scriptcard to run.  I have 0.0.14 and have scriptcards both with and without  --#noMinMaxHilight and I am not getting any errors in the sandbox Although does appear to be a bug on line 818, so not sure why I don't get issues
Duncan R. said: Jay R. said: I think the problem may be that Kurt has the setting as NoMinMaxHilight elsewhere in the code? The script seems to be looking for nominmaxhighlight in a scriptcard regardless of whether the scriptcard is using the parameter. Edit: Stripping all references to nominmaxhighlight from the 0.0.14 code allows my scriptcard to run.  I have 0.0.14 and have scriptcards both with and without  --#noMinMaxHilight and I am not getting any errors in the sandbox Although does appear to be a bug on line 818, so not sure why I don't get issues Yeah, it's odd. I'm not getting it with every scriptcard I'm running. Just one particular card that makes two ChatSetAttr calls.
1613157616
Kurt J.
Pro
API Scripter
Thanks Aaron. I ninja-updated the GIST without changing the version.
Kurt J. said: Thanks Aaron. I ninja-updated the GIST without changing the version. Hi Kurt. Do you think you could look at this scriptcard to tell me what could be crashing the API? This is the one that generated the nominmax error. !scriptcard   {{   --#title| ⏩ Transfer Potions ⏩   --#leftsub|Greater Healing 🧪🧪   --#sourceToken|@{selected|token_id}   --#targetToken|@{target|token_id}   --#emoteText|*@{selected|token_name} volunteers to give healing potions to @{target|token_name}.*   --&PotionName|greater healing   --:FindSourcePotionType|   --Rfirst|@{selected|character_id};repeating_resource   --:SourceResourceLoop|   --?"[*R:resource_left_name]" -inc "Potion of Greater Healing"|>SetSourcePotionInfo;[*R>resource_left];[*R:resource_left]   --?"[*R:resource_right_name]" -inc "Potion of Greater Healing"|>SetSourcePotionInfo;[*R>resource_right];[*R:resource_right]   --Rnext|   --?"[*R:resource_left_name]" -ne "NoRepeatingAttributeLoaded"|SourceResourceLoop   --^SetSourcePotionInfo|   --:SetSourcePotionInfo|Params are Attribute Reference;Attribute value   --&SourceAttributeRef|[%1%]   --=SourceCount|[%2%]   --^PotionSource|     --:PotionSource|   --=TransferNumber|?{Transfer|0}   --?[$TransferNumber] -gt [$SourceCount]|NoPotion   --@modbattr|_name @{selected|character_name} _[&SourceAttributeRef]|-[$TransferNumber] _silent   --=SourceCountNew|[$SourceCount]-[$TransferNumber]   --^FindTargetPotionType|   --:FindTargetPotionType|   --Rfirst|@{target|character_id};repeating_resource   --:TargetResourceLoop|   --?"[*R:resource_left_name]" -inc "Potion of Greater Healing"|>SetTargetPotionInfo;[*R>resource_left];[*R:resource_left]   --?"[*R:resource_right_name]" -inc "Potion of Greater Healing"|>SetTargetPotionInfo;[*R>resource_right];[*R:resource_right]   --Rnext|   --?"[*R:resource_left_name]" -ne "NoRepeatingAttributeLoaded"|TargetResourceLoop   --^SetTargetPotionInfo|   --:SetTargetPotionInfo|Params are Attribute Reference;Attribute value   --&TargetAttributeRef|[%1%]   --=TargetCount|[%2%]   --^TargetPotion|     --:TargetPotion|   --@modbattr|_name @{target|character_name} _[&TargetAttributeRef]|+[$TransferNumber] _silent   --=TargetCountNew|[$TargetCount]+[$TransferNumber]   --^InventoryUpdate|   --:InventoryUpdate|   --=HealingColor|00C301   --+[c]Potions Transferred: [#[$HealingColor.RollText]][$TransferNumber.Total][/#][/c]   --+@{target|token_name}|now has [b][#[$HealingColor.RollText]][$TargetCountNew.Total][/#][/b] potion(s) of [&PotionName].   --?[$SourceCountNew] -ge 1|HealingSkip   --=HealingColor|FF0000   --:HealingSkip|   --+@{selected|token_name}|now has [b][#[$HealingColor.RollText]][$SourceCountNew.Total][/#][/b] potion(s) of [&PotionName].   --^Final|   --:NoPotion|   --:=NoPotionColor|FF0000   --+[#[$HealingColor.RollText]]Not enough potions for transfer![/#]   --:Final| }}
1613165519
Kurt J.
Pro
API Scripter
Jay R. said: Kurt J. said: Thanks Aaron. I ninja-updated the GIST without changing the version. Hi Kurt. Do you think you could look at this scriptcard to tell me what could be crashing the API? This is the one that generated the nominmax error. !scriptcard   {{   --#title| ⏩ Transfer Potions ⏩   --#leftsub|Greater Healing 離離   --#sourceToken|@{selected|token_id}   --#targetToken|@{target|token_id}   --#emoteText|*@{selected|token_name} volunteers to give healing potions to @{target|token_name}.*   --&PotionName|greater healing   --:FindSourcePotionType|   --Rfirst|@{selected|character_id};repeating_resource   --:SourceResourceLoop|   --?"[*R:resource_left_name]" -inc "Potion of Greater Healing"|>SetSourcePotionInfo;[*R>resource_left];[*R:resource_left]   --?"[*R:resource_right_name]" -inc "Potion of Greater Healing"|>SetSourcePotionInfo;[*R>resource_right];[*R:resource_right]   --Rnext|   --?"[*R:resource_left_name]" -ne "NoRepeatingAttributeLoaded"|SourceResourceLoop   --^SetSourcePotionInfo|   --:SetSourcePotionInfo|Params are Attribute Reference;Attribute value   --&SourceAttributeRef|[%1%]   --=SourceCount|[%2%]   --^PotionSource|     --:PotionSource|   --=TransferNumber|?{Transfer|0}   --?[$TransferNumber] -gt [$SourceCount]|NoPotion   --@modbattr|_name @{selected|character_name} _[&SourceAttributeRef]|-[$TransferNumber] _silent   --=SourceCountNew|[$SourceCount]-[$TransferNumber]   --^FindTargetPotionType|   --:FindTargetPotionType|   --Rfirst|@{target|character_id};repeating_resource   --:TargetResourceLoop|   --?"[*R:resource_left_name]" -inc "Potion of Greater Healing"|>SetTargetPotionInfo;[*R>resource_left];[*R:resource_left]   --?"[*R:resource_right_name]" -inc "Potion of Greater Healing"|>SetTargetPotionInfo;[*R>resource_right];[*R:resource_right]   --Rnext|   --?"[*R:resource_left_name]" -ne "NoRepeatingAttributeLoaded"|TargetResourceLoop   --^SetTargetPotionInfo|   --:SetTargetPotionInfo|Params are Attribute Reference;Attribute value   --&TargetAttributeRef|[%1%]   --=TargetCount|[%2%]   --^TargetPotion|     --:TargetPotion|   --@modbattr|_name @{target|character_name} _[&TargetAttributeRef]|+[$TransferNumber] _silent   --=TargetCountNew|[$TargetCount]+[$TransferNumber]   --^InventoryUpdate|   --:InventoryUpdate|   --=HealingColor|00C301   --+[c]Potions Transferred: [#[$HealingColor.RollText]][$TransferNumber.Total][/#][/c]   --+@{target|token_name}|now has [b][#[$HealingColor.RollText]][$TargetCountNew.Total][/#][/b] potion(s) of [&PotionName].   --?[$SourceCountNew] -ge 1|HealingSkip   --=HealingColor|FF0000   --:HealingSkip|   --+@{selected|token_name}|now has [b][#[$HealingColor.RollText]][$SourceCountNew.Total][/#][/b] potion(s) of [&PotionName].   --^Final|   --:NoPotion|   --:=NoPotionColor|FF0000   --+[#[$HealingColor.RollText]]Not enough potions for transfer![/#]   --:Final| }} This was another bug in the code. I've updated the GIST to 0.0.14a with a fix for this. Essentially, I added a parameter to the replaceRollVariables function and forgot to update the call to that function when using the --& line type. Version 0.0.14a fixes this, and I ran you script above successfully without changing anything except the potion name to match what I have in my test game. Sorry about that! :)
1613166188
Kurt J.
Pro
API Scripter
Make that 0.0.14b :) I found something else :)
Kurt J. said: This was another bug in the code. I've updated the GIST to 0.0.14a with a fix for this. Essentially, I added a parameter to the replaceRollVariables function and forgot to update the call to that function when using the --& line type. Version 0.0.14a fixes this, and I ran you script above successfully without changing anything except the potion name to match what I have in my test game. Sorry about that! :) Ah, thank you, and no problem! I'm happy to help with some minor QA on such a great script. I've converted all my potion macros to scriptcards, and I'm looking forward to using them in my next session. Now working on converting my party macros. 
1613178494

Edited 1613178638
Kurt J.
Pro
API Scripter
ScriptCards v0.0.15 ( GIST ) Big update today, with lots of fun new stuff: Bug Fixes : Fixed a couple of sandbox crash bugs identified by Jay R. and the Aaron New Convention : The "/" line type (--/) is being reserved for commenting out lines in scripts and will not be used as a statement identifier in the future. Line still need to follow the vertical bar rule, but you can change something like --+Hello|World! to --/+Hello|World and ScriptCards will ignore the line during processing. Behavior Change : The getselected  function will now return both a stringVariable and a rollVariable fo the Count portion of the results making the number easier to use in other things. New Operator : The dice roll parser now supports the modulo (%) operator to divide the running total by the next value and return the remainder. New Repeating Section Command: --Rdump| will now output all of the repeating section fields for the currently loaded repeating section to the console log. This can be useful if you are looking to find particular fields in a repeating section. New Function Groups : Instead of creating separate function for each operation, functions are now grouped into sets of related sub functions. See the Wiki page for a full rundown on the functions and subfunctions and the required parameters for each. The existing distance functions are still their own separate functions at this time. Function Group : math.  The math function group contains the following subfunctions: min, max, clamp, round, floor, and ceil. Most of these should be fairly obvious, with possibly the exception of "clamp". Clamping a value keeps in in a range between a lower and upper bound, so clamping a 1d20 roll between 5 and 15 will return the roll if it is between 5 and 15, 5 if it is lower than 5 and 15 if it is higher than 15. Function Group : stateitem.  There are two subfunctions: write, and read . You can use these functions to store one rollvariable and one stringvariable to the game state. One of each type can be persistent and will be saved between scripts and between Roll20 sessions. Function Group : string. This group contains the following string manipulation subfunctions: length, before, after, left, right, substring, split, replace . Please check out the wiki for full details.
Kurt J. said: ScriptCards v0.0.15 ( GIST ) Big update today, with lots of fun new stuff: New Repeating Section Command: --Rdump| will now output all of the repeating section fields for the currently loaded repeating section to the console log. This can be useful if you are looking to find particular fields in a repeating section. Huge thanks for this, Kurt! EDIT: Ran my Scriptcard macros tonight for my session. Healing potions and a full suite of macros for my monk player. Everything worked like a charm and my players were really happy about the ability to just fire healing potions (drink or pour down another character's throat, or transfer between party members) with a couple of clicks. I'm so chuffed. Now, I have to get to work and convert the rest of my macros, when possible, to Scriptcards, especially the other party members. 
1613225291
Kurt J.
Pro
API Scripter
Minor Update - v0.0.15a Only a small change... the getselected function was returning names instead of token_id as indicated in the Wiki. It now returns token ids. My file of test scripts is paying off :)
1613347041

Edited 1613347160
David M.
Pro
API Scripter
Simple Example: Using scriptcards to check the availability of resources and put in conditional logic to either (1) create a button to call another macro or (2) output a message stating that the ability can't be used. This is a pretty basic, but putting it here for anyone new to scriptcards so they have more examples to learn from. Uses repeating resources, button creation, and conditional procedure calls. This came from a discussion on my !radar script thread. The user wanted to check a repeating resource and only allow my script to be called if daily uses were available. This was for a 5e "Divine Sense" application, and the GM didn't want players trying to activate the ability when they shouldn't be able to, potentially gaining information they shouldn't have. Now, !radar can technically be called by another script directly, but it requires both the selected token ID and the calling player ID (to know who to whisper results to) to be passed to the script by the api. SelectManager only handles the tokenID part, AFAIK. So, rather than changing my script (which I should do eventually, I know) I came up with a quick conditional button solution for them and thought it might be useful to others that might want to do something similar for other applications.  First, I created a Collections macro called "DivineSense" (using standard !radar syntax). If named differently, you would change the button action text in the "HasUses" function below. The character name is hardcoded to "Trix" in this example, so you would obviously change that, too (under the Variable Definitions comment), possibly adding a query to make it useable by multiple characters. The conditional portion calls the appropriate function depending on uses left.  !scriptcard {{ --#title|Divine Sense --#leftsub|Paladin Class Ability --:VARIABLE DEFINITIONS| --=Uses|@{ Trix |repeating_resource_$0_resource_left} --=Max|@{ Trix |repeating_resource_$0_resource_left|max} --#rightsub|[$Max]/day --:CHECK REMAINING USES| --+Uses Remaining|[$Uses] --?[$Uses.Total] -gt 0|>HasUses|>NoMoreUses --X|End Macro --:FUNCTIONS| --:HasUses| --+Click to activate|[button]ACTIVATE::!
# DivineSense [/button] --<| --:NoMoreUses| --+[#990000]Ability Unavailable[/#]| --<| }} Ran it with one use remaining. Clicked the activate button to trigger the other macro (the whispered output - Undead nearby!), and ran it again to show the "Unavailable" condition. The button macro would handle the resource decrement with ChatSetAttr if desired.
David M. said: Simple Example: Using scriptcards to check the availability of resources and put in conditional logic to either (1) create a button to call another macro or (2) output a message stating that the ability can't be used. This is a pretty basic, but putting it here for anyone new to scriptcards so they have more examples to learn from. Uses repeating resources, button creation, and conditional procedure calls. This came from a discussion on my !radar script thread. The user wanted to check a repeating resource and only allow my script to be called if daily uses were available. This was for a 5e "Divine Sense" application, and the GM didn't want players trying to activate the ability when they shouldn't be able to, potentially gaining information they shouldn't have. Now, !radar can technically be called by another script directly, but it requires both the selected token ID and the calling player ID (to know who to whisper results to) to be passed to the script by the api. SelectManager only handles the tokenID part, AFAIK. So, rather than changing my script (which I should do eventually, I know) I came up with a quick conditional button solution for them and thought it might be useful to others that might want to do something similar for other applications.  First, I created a Collections macro called "DivineSense" (using standard !radar syntax). If named differently, you would change the button action text in the "HasUses" function below. The character name is hardcoded to "Trix" in this example, so you would obviously change that, too (under the Variable Definitions comment), possibly adding a query to make it useable by multiple characters. The conditional portion calls the appropriate function depending on uses left.  !scriptcard {{ --#title|Divine Sense --#leftsub|Paladin Class Ability --:VARIABLE DEFINITIONS| --=Uses|@{ Trix |repeating_resource_$0_resource_left} --=Max|@{ Trix |repeating_resource_$0_resource_left|max} --#rightsub|[$Max]/day --:CHECK REMAINING USES| --+Uses Remaining|[$Uses] --?[$Uses.Total] -gt 0|>HasUses|>NoMoreUses --X|End Macro --:FUNCTIONS| --:HasUses| --+Click to activate|[button]ACTIVATE::!
# DivineSense [/button] --<| --:NoMoreUses| --+[#990000]Ability Unavailable[/#]| --<| }} Ran it with one use remaining. Clicked the activate button to trigger the other macro (the whispered output - Undead nearby!), and ran it again to show the "Unavailable" condition. The button macro would handle the resource decrement with ChatSetAttr if desired. Nice, David! Funny, I was just working on my paladin's Divine Sense macro today. My solution is to make those powers accessible from a single "powers" menu (per character), and then disappear the "use" button if the power is depleted, but yours looks very elegant. !script {{     --#title| ☪️ Paladin Powers ☪️   --#leftsub|@{selected|token_name}   --#sourceToken|@{selected|token_id}   --#emoteText|*@{selected|token_name} takes stock of his powers.*   --Lsettings|@{selected|token_name}   --=AttributeA|0   --=AttributeB|0   --=AttributeC|0   --=ResourceExpended|FF0000   -->CheckAttributes|   --:Power1|   --?[$AttributeA.Total] -ge 1|DisplayButton   --+ 🙏🏽 |[#[$ResourceExpended.RollText]]Abjure Enemy[/#]   --^HideButton|   --:DisplayButton|   --+ 🙏🏽 |[button]Use::~Sechul'ath the Brave|AbjureEnemy[/button] Abjure Enemy   --:HideButton|   --:Power2|   --?[$AttributeB.Total] -ge 1|DisplayButton2   --+ 🧭 |[#[$ResourceExpended.RollText]]Divine Sense[/#]   --^HideButton2|   --:DisplayButton2|   --+ 🧭 |[button]Use::~Sechul'ath the Brave|DivineSense[/button] Divine Sense   --:HideButton2|   --:Power3|   --?[$AttributeC.Total] -ge 1|DisplayButton3   --+ 🙌🏽 |[#[$ResourceExpended.RollText]]Lay on Hands[/#]   --^HideButton3|   --:DisplayButton3|   --=AttributeColor|00C301   --+ 🙌🏽 |[button]Use::~Sechul'ath the Brave|LayonHands[/button] Lay on Hands [b][#[$AttributeColor.RollText]][$AttributeC.Total][/#][/b] Left   --:HideButton3|   --:Power4|   --?[$AttributeA.Total] -ge 1|DisplayButton4   --+ 🙏🏽 |[#[$ResourceExpended.RollText]]Oath of Vengeance[/#]   --^HideButton4|   --:DisplayButton4|   --=AttributeColor|00C301   --+ 🙏🏽 |[button]Use::~Sechul'ath the Brave|OathofVengeance[/button] Oath of Vengeance [b][#[$AttributeColor.RollText]][$AttributeD.Total][/#][/b] Left   --:HideButton4|   --:CheckAttributes|   --Rfirst|@{selected|character_id};repeating_resource   --:ResourceLoop|   --?"[*R:resource_left_name]" -eq "Channel Divinity"|>SetA;[*R:resource_left]     --?"[*R:resource_right_name]" -eq "Channel Divinity"|>SetA;[*R:resource_right]   --?"[*R:resource_left_name]" -eq "Divine Sense"|>SetB;[*R:resource_left]     --?"[*R:resource_right_name]" -eq "Divine Sense"|>SetB;[*R:resource_right]   --?"[*R:resource_left_name]" -eq "Lay on Hands"|>SetC;[*R:resource_left]     --?"[*R:resource_right_name]" -eq "Lay on Hands"|>SetC;[*R:resource_right]   --Rnext|   --?"[*R:resource_left_name]" -ne "NoRepeatingAttributeLoaded"|ResourceLoop   --<|   --:SetA|   --=AttributeA|[%1%]   --<|   --:SetB|   --=AttributeB|[%1%]   --<|   --:SetC|   --=AttributeC|[%1%]   --<| }}
1613352308
David M.
Pro
API Scripter
Neat! I like the idea of the using a variable for the inline hexcolor formatting. I'll have to remember that one for cases where I have several lines that need the same formatting. Would make it easier to change them all at once as I play around with it.
David M. said: Neat! I like the idea of the using a variable for the inline hexcolor formatting. I'll have to remember that one for cases where I have several lines that need the same formatting. Would make it easier to change them all at once as I play around with it. Yeah, my next step is to create roll variable settings so those hex colors can be applied to every scriptcard by default. So much to learn with this (wonderful) script!
1613397411
Kurt J.
Pro
API Scripter
I'm getting ready for a 1.0.0 release either later today or some time tomorrow. There are a few bug fixes, and a pretty major new feature that I wanted to get completed before calling this a 1.0 release. I also have a new statement type that I want to ensure is tested before release as well.
1613397605
David M.
Pro
API Scripter
Can't wait!
Kurt J. said: I'm getting ready for a 1.0.0 release either later today or some time tomorrow. There are a few bug fixes, and a pretty major new feature that I wanted to get completed before calling this a 1.0 release. I also have a new statement type that I want to ensure is tested before release as well. Woot woot! Can't wait. While I'm here, can anyone tell me what I'm doing wrong with the clamp function? I want the variable to limit between 1 and the max HP of the target token (it's a healing potion), but this syntax doesn't work for me:   --~HealingAmount|math;clamp;4d4+4;1;@{target|token_id|bar1_max}
1613415661
Kurt J.
Pro
API Scripter
Jay R. said: Kurt J. said: I'm getting ready for a 1.0.0 release either later today or some time tomorrow. There are a few bug fixes, and a pretty major new feature that I wanted to get completed before calling this a 1.0 release. I also have a new statement type that I want to ensure is tested before release as well. Woot woot! Can't wait. While I'm here, can anyone tell me what I'm doing wrong with the clamp function? I want the variable to limit between 1 and the max HP of the target token (it's a healing potion), but this syntax doesn't work for me:   --~HealingAmount|math;clamp;4d4+4;1;@{target|token_id|bar1_max} The 4d4+4 won't be processed as a dice roll, and will likely just end up being read as "4". You'll need to do the dice rolling in an --= statement. Also, consider that your method above doesn't take into account the player's current HP. You'll probably want to do something like --=HealAmount|4d4+4 + @{target|bar1_value} --~NewHP|math;clamp;HealAmount;1;@{target|bar1_max} And then use token-mod or setattr to make the changes. Alternatively, if you use alterbar, you can just roll the 4d4+4 without the reference to the current HP and pass it a "+" and the variable reference. It already limits the amount applied to the bar max I believe.
Kurt J. Do you plan to do a one-click version?
1613417001

Edited 1613420504
Kurt J.
Pro
API Scripter
ScriptCards 1.0.0 is Live on the GIST Version 1.0.0 is here, and this is a big one. There were some things I wanted to get completed before officially calling this 1.0.0, hence the sequence of 0.0.x versions prior to this. I do have some plans for what is next (Referencing Roll20 Objects directly from a ScriptCards script), but the development pace will probably slow down quite a bit now that I've got most of what I was planning on implemented. That is, at least the development pace on the API script itself. See the Procedure Libraries section below :) Behind the Scenes Implemented The Aaron’s API_Meta system with the name “ScriptCards”. This is more of a troubleshooting feature than an actual usable feature of the script. Removed the changelog from the comments portion of the script itself, as it was growing very long. Replaced this with some general information about ScriptCards scripts and a link to the Wiki page. Bug Fixes The “R” statement type (repeating section) will now be recognized as either “R” or “r”. It is now possible to include the same roll variable reference multiple times in a line (i.e., [$Roll.Total] [$Roll.Total] will now work correctly). Previously the first use of the reference would work, and the second and beyond would simply return the text of the reference. Cosmetic Change In text output (The .Text property) for roll variables, the "*" operator will now appear as "x" because the "*" character was not being displayed properly in the tooltip for rolls. This change is not applied to the RollText property. Pre-Defined String Variables There are a handful of pre-defined string variables created when a script is run to provide some potentially useful information based on the player running the script: [&SendingPlayerID] – The object ID of the player running the script [&SendingPlayerName] – The Display Name of the player running the script [&SendingPlayerColor] – The hex code for the color associated with the player running the script [&SendingPlayerSpeakingAs] – The entity (usually in “character|-idgoeshere” format) that the player had selected from the Speaking As dropdown menu when the script was run. [&SendingPlayerIsGM] – Will be set to “1” if the player running the script is a GM, and “0” if not. New Statement Type: 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. Procedure Libraries You can now create handouts in your game in Roll 20 with the name format "ScriptCards Library NAME", where name is a name you assign to the library. Library names are case sensitive. It is my hope that the more proficient ScriptCards scripters out there will provide procedure libraries (or procedures that can be included in libraries) for others to use to make their scripting life easier. Be they specific to a game system, or to a type of activity, I think a robust set of libraries that GMs could use to enhance their scripting capabilities would be very valuable to the community. Should such things begin to emerge, I’ll create a portion of the ScriptCards Wiki page to house them. To include one or more libraries in a script, use the +++libname+++ directive (does not need a -- line associated with it). Multiple library names can be specified by separating them with semicolons (i.e., +++General;5E Tools;Colorize+++ would include three libraries (General, 5E Tools, and Colorize). Included libraries are separated from the main script code by the automatic inclusion of "--X|" before the first library is appended to the script, and all libraries are loaded at the end of the script before script processing takes place. Procedures and labels in libraries can be used just as if they were included in the body of your script. Note that this DOES mean that you could, technically, jump into a library with a direct branch (--^) or direct branch conditional, but I recommend using libraries to store reusable procedures. The Notes section of the library handout stores the library code, and is written just like any other ScriptCards code except: -           They cannot use roll queries (?{Some Prompt:}) to get information from the user at execution time. -           They cannot use @{} notation to access character and token information. Both of these limitation stem from the fact that Procedure Libraries are not processed by the chat server, which is what handles these items. Here is an example of handling damage modifications (resistance, vulnerability, and immunity) in D&D 5E with a library: !script {{     +++5E Tools+++     --#|Damage Modifiers Test     --#targettoken|@{target|token_id}     -->Lib5E_CheckDamageModifiers|ResistType;fire     --=DamageRoll|2d10 [&ResistType]     --+Test:|[$DamageRoll] fire damage       -->Lib5E_CheckDamageModifiers|ResistType;cold     --=DamageRoll|2d10 [&ResistType]     --+Test:|[$DamageRoll] cold damage       -->Lib5E_CheckDamageModifiers|ResistType;poison     --=DamageRoll|2d10 [&ResistType]     --+Test:|[$DamageRoll] poison damage     -->Lib5E_CheckDamageModifiers|ResistType;acid     --=DamageRoll|2d10 [&ResistType]     --+Test:|[$DamageRoll] acid damage     --X| }} Library content (In a handout called “ScriptCards Library 5E Tools” NOTE: Paste into Notepad first and then paste into the handout in Roll20 to avoid bringing over HTML formatting from the web site) : --/|ScriptCards Library: 5E Tools version 0.0.1 --/|Provides various utility procedures for D&D 5E games   --/|Lib5E_CheckDamageModifiers handle damage resistance, vulnerability, and immunity. --/|Pass a string variable to be filled with a string to be appended to a dice roll and the damage type     --:Lib5E_CheckDamageModifiers|damageVariableName;damageType --&[%1%]| --?"[*T:npc_vulnerabilities]" -inc "[%2%]"|>_Lib5E_IsVulnerable;[%1%] --?"[*T:npc_resistances]" -inc "[%2%]"|>_Lib5E_IsResistant;[%1%] --?"[*T:npc_immunities]" -inc"[%2%]"|>_Lib5E_IsImmune;[%1%] --<| --:_Lib5E_IsVulnerable| --&[%1%]| * 2 [Vulnerable] --<| --:_Lib5E_IsResistant| --&[%1%]| \ 2 [Resistant] --<| --:_Lib5E_IsImmune| --&[%1%]| * 0 [Immune] --<| T he 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.
Kurt J. said: Jay R. said: Kurt J. said: I'm getting ready for a 1.0.0 release either later today or some time tomorrow. There are a few bug fixes, and a pretty major new feature that I wanted to get completed before calling this a 1.0 release. I also have a new statement type that I want to ensure is tested before release as well. Woot woot! Can't wait. While I'm here, can anyone tell me what I'm doing wrong with the clamp function? I want the variable to limit between 1 and the max HP of the target token (it's a healing potion), but this syntax doesn't work for me:   --~HealingAmount|math;clamp;4d4+4;1;@{target|token_id|bar1_max} The 4d4+4 won't be processed as a dice roll, and will likely just end up being read as "4". You'll need to do the dice rolling in an --= statement. Also, consider that your method above doesn't take into account the player's current HP. You'll probably want to do something like --=HealAmount|4d4+4 + @{target|bar1_value} --~NewHP|math;clamp;HealAmount;1;@{target|bar1_max} And then use token-mod or setattr to make the changes. Alternatively, if you use alterbar, you can just roll the 4d4+4 without the reference to the current HP and pass it a "+" and the variable reference. It already limits the amount applied to the bar max I believe. Thanks. I'll try that out. For reference, I already use token-mod to make the change to the token, and token-mod already limits the amount with the ! character. What I want, in this case, is to output the clamped healing amount (i.e. not greater than the token's bar1 max) in the scriptcard. So I think I'll throw that NewHP variable into the token-mod command, and then again when using an + statement to display the healing amount in the scriptcard. 
1613417757
Kurt J.
Pro
API Scripter
Rober M. said: Kurt J. Do you plan to do a one-click version? Yes, the script will be heading to OneClick (hopefully this Tuesday).