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

1621294937
Kurt J.
Pro
API Scripter
Will M. said: Kurt J. said: I'm in the process of updating the Wiki, but as a side track I've started updating the first post of this thread with permalinks to the various version update notes. ( First Post ) (I also ninja-updated 1.2.8 to remove the log of the page id for --Vpoint effects :)) A couple suggestions: Add the attribute name list for Tokens (t-*) Correct the syntax description for totitle string function, I believe its currently documented totile   Correct the syntax description for statusmarkers array function should be --~cnt|array;statusmarkers;ArrayName;TokenId I believe. Done :) Thanks Will.
1621295498
David M.
Pro
API Scripter
Think I found the rogue console log statement in v1.2.8. There is a  log(pid) on line 1555 within the  case "point": block that looks like a hold-over from earlier testing.
1621298364
Kurt J.
Pro
API Scripter
David M. said: Think I found the rogue console log statement in v1.2.8. There is a  log(pid) on line 1555 within the  case "point": block that looks like a hold-over from earlier testing. I ninja-updated the 1.2.8 on the GIST to get rid of it :)
1621298473
Kurt J.
Pro
API Scripter
With much thanks to Gabryel, the First Post on this thread is now updated with short descriptions and links to each of the release notes posts. I have also made (most) of the wiki updates to bring it to current. I still need to do statement blocks and perhaps a couple of other items.
Y'all are just awesome.  It's going to take me a month to process this...
LOL.  Just thought of a funny offshoot for Kurt's --vpoint instruction.  For that WWII experience... !scriptcard {{   --%LoopCounter|1;10;1     --=FiftyFifty|1d2         --?[$FiftyFifty] -eq 1|[--=XRoll|1d3150 {NEGATE}]     --=FiftyFifty|1d2         --?[$FiftyFifty] -eq 1|[--=YRoll|1d2450 {NEGATE}]     --+|[$XRoll] [$YRoll]      --Vpoint|[$XRoll] [$YRoll] burst-fire   --%| }} Note: I just plugged in the height and width for the page I was using.  One could add an --i instruction or other means to get the current page height and width to plug in. Be interesting to figure out how to add a timer loop for a less instantaneous version....  Anyway, Enjoy!
1621380543

Edited 1621383218
Kurt J.
Pro
API Scripter
I posted a revised Lightning Bolt script that takes resistance, immunity, and vulnerability into account and uses the {ABS} and {NEGATE} features of 1.2.8 to simplify some of the code. It is also pretty heavily commented as well to explain what is going on. I also had an idea about cone spells, so I may or may not be working on Burning Hands :)
Not sure if anyone has this problem, but when I use the function  string;after;searchText;stringValue I get the search Text included in the return. string;before;searchText;stringValue works perfectly. Give it a try please and let me know what's happening here. !scriptcards {{ --#title|Testing 1,2,3... --#titleFontFace|georgia --#bodyFontFace|georgia --#emoteBackground|#ffffff --#titleCardBackground|#B80404 --#oddrowbackground|#F4F4F4 --#evenrowbackground|#F9EBEB --#titleFontLineHeight|35px --#bodyFontLineHeight|200px --#sourceToken|@{selected|token_id} --&myString|"this side / that side" --~stringBefore|string;before;/;[&myString] --~stringAfter|string;after;/;[&myString] --+Before|[&stringBefore] --+After|[&stringAfter] }}
@ Will, have you made a scriptcard macro to set Condition like blind, charm, prone etc?  
1621397373

Edited 1621443136
Craven said: @ Will, have you made a scriptcard macro to set Condition like blind, charm, prone etc?   Yes - It's integrated into my Player Utility Macros collection (a toolkit for my players).  A couple requirements though: The Scriptcard I call MarkToken The TokenMod API Script You will probably need to tweak the Scriptcard to incorporate your personal Status Markers.  The version I will be posting references some 3rd party Status Markers I had purchased from the Roll20 Marketplace I'll post the code for both on the Scriptcard API Working and Sharing forum.   Here's some screenshots:   Working Left to Right: Player Macro menu card.  Clicking on the Set Condition/Status menu item displays #2. Set Condition/Status card gives the player or gm a list of conditions and status.  When one is clicked it displays #3 and sets the status marker on the token appropriately The Condition/Status help text just reminds the players the effect of the condition or status
Could Someone please give me a practical example for how to set up, srub through, and get data in and out of and array. I keep getting array errors and undefined array variable errors. I get the concept of arrays, just not sure about how to use them in scriptcards. Please be kind. I'm new to this API
Andy said: Could Someone please give me a practical example for how to set up, srub through, and get data in and out of and array. I keep getting array errors and undefined array variable errors. I get the concept of arrays, just not sure about how to use them in scriptcards. Please be kind. I'm new to this API Check out the code for the Page Assets Report found in our scriptcard sharing forum .  It uses an array of token objects to categorize and report out on Token Objects found on a page.  
1621465090

Edited 1621465699
Kurt J.
Pro
API Scripter
Here is my implementation of Burning Hands. Much of the Lightning Bolt code is reused, the difference being that there is no line calculation but instead the definition of arrays for each of the grid directions. These arrays were taken from the templates in Xanathars for cone spells on a grid. This could easily be updated for 30' cones by simply adding more entries to each array. It would also be a simple matter to update the arrays to handle cube spells like Thunderwave. The numbers in the array are x and y offset pairs for each impacted square, assuming the caster is at 0,0 compared to these values. I have emojis for each of the directional arrows in the dropdown, though they can be hard to see on big displays, so I also include the direction name. Anyway, while I've run it several times there could always be bugs, so let me know if you run into anything. (I need to check the damage numbers - they look off to me, but I'll look at them). Found a bug in the saving throw roll on both this and Lightning Bolt. Updated. !script {{ --/|Burning Hands script. Can be changed to other 15' cone-based spells by updating these parameters. --/|larger cones can be defined by updating the array definitions for the diretions to include additional offsets. --/|cube shaped spells could be acocmodated in a similar way. --&spellName|Burning Hands --/|Note: because the spell will be cast at a min level of 1, we use 2 here to get the total dice (2+1=3) --&spellL0DamageDice|2 --/|Prompt for the spell level. Update this to account for the minimum level of the spell --=SpellLevel|?{Spell Slot Level?|1|2|3|4|5|6|7|8|9} --&spellDamageDieType|6 --&damageType|fire --&saveType|dexterity --/|Source Token is the caster, and target token is the "end of the line". Can be a non-creature (no represents) token. --#sourcetoken|@{selected|token_id} --/|Get all of the tokens on the page so we can cache their positions --~|array;pagetokens;alltokens;@{selected|token_id} --#leftsub|Save DC @{selected|spell_save_dc} --#rightsub|Slot Level: [$SpellLevel] --#title|[&spellName] --/|Calculate damage based on spell slot. --=DamageDice|[$SpellLevel.Total] + [&spellL0DamageDice] --=Damage|[$DamageDice.Total]d[&spellDamageDieType] --=HalfDamage|[$Damage.Total] \ 2 --=DoubleDamage|[$Damage.Total] * 2 --=QuarterDamage|[$Damage.Total] \ 4 --/|Since we want to be able to hover over a roll and see the dice details, output the rolled damage at the --/|top of the card. If all critters make their save, the half damage roll won't contain the details. --+|[c][b]Damage Roll: [/b][$Damage][/c] --+|  --/|Create an array to hold the tokens that are intersected by the line. --~|array;define;tokensHit; -->createTokenLookup| --/|Prompt for a direction for hte cast, and define arrays that indicate the relative spaces that will be hit. --&direction|?{Direction|⬆ (UP),U|↗ (UP-RIGHT),UR|➡ (RIGHT),R|↘ (DOWN-RIGHT),DR|⬇ (DOWN),D|↙ (DOWN-LEFT),DL|⬅ (LEFT),L|&#x2196 (UP-LEFT);,UL|} --~|array;define;U;0,-1;0,-2;-1,-2;-1,-3;0,-3;1,-3 --~|array;define;D;0,1;0,2;1,2;-1,3;0,3;1,3 --~|array;define;R;1,0;2,0;2,-1;3,-1;3,0;3,1 --~|array;define;L;-1,0;-2,0;-2,-1;-3,-1;-3,0;-3,1 --~|array;define;UR;1,-1;1,-2;1,-3;2,-1;2,-2;3,-1 --~|array;define;DR;1,1;1,2;1,3;2,1;2,2;3,1 --~|array;define;UL;-1,-1;-1,-2;-1,-3;-2,-1;-2,-2;-3,-1 --~|array;define;DL;-1,1;-1,2;-1,3;-2,1;-2,2;-3,1 --/|Call the "checkForTokenHits" subroutine. The passed parameter will be the per-space VFX. Leave blank for none. -->checkForTokenHits|burn-frost --/|The first item in the array will be a blank dummy item, so remove it. --~|array;removeat;tokensHit;0 --/|Loop through the tokensHit tokens and roll saves for each one and apply damage --~tokenid|array;getfirst;tokensHit --?[&tokenid] -eq ArrayError|endOutput --:loopDisplay| --=SaveRoll|1d20 + [*[&tokenid]:[&saveType]_save_bonus] --/|Compare the save roll to the save DC and either apply full or half damage --?"[*[&tokenid]:npc_immunities]" -inc "[&damageType]"|Immune --?"[*[&tokenid]:npc_resistances]" -inc "[&damageType]"|Resistant --?"[*[&tokenid]:npc_vulnerabilities]" -inc "[&damageType]"|Vulnerable --?[$SaveRoll.Total] -lt @{selected|spell_save_dc}|>ApplyDamageAlterbars;[&tokenid];3;-[$Damage.Total]|>ApplyDamageAlterbars;[&tokenid];3;-[$HalfDamage.Total] --?[$SaveRoll.Total] -ge @{selected|spell_save_dc}|madeSave --/|Here are various damage applications if the creature is immune, resistant, or vulnerable. In some cases, we will reuse output lines, --/|for example, a resistant creature that fails its save will jump to "madeSave", since that is the correct damage amount. (half), while --/|a vulnerable creature that makes its save will jump to "FailedSave" since that will be normal damage. --/|Output a line for a failed saving throw (we will also jump here for a vulnerable creature that MAKES its save) --:FailedSave| --+[*[&tokenid]:t-name]:|Save [$SaveRoll] [r][$Damage] [&damageType][/r] --^afterSave| --:Immune| --+[*[&tokenid]:t-name]:|is not effected by the spell! --^afterSave| --:Resistant| --?[$SaveRoll.Total] -lt @{selected|spell_save_dc}|>ApplyDamageAlterbars;[&tokenid];3;-[$HalfDamage.Total]|>ApplyDamageAlterbars;[&tokenid];3;-[$QuarterDamage.Total] --?[$SaveRoll.Total] -lt @{selected|spell_save_dc}|madeSave --+[*[&tokenid]:t-name]:|Save [$SaveRoll] [r][$QuarterDamage] [&damageType][/r] --^afterSave| --:Vulnerable| --?[$SaveRoll.Total] -lt @{selected|spell_save_dc}|>ApplyDamageAlterbars;[&tokenid];3;-[$DoubleDamage.Total]|>ApplyDamageAlterbars;[&tokenid];3;-[$Damage.Total] --?[$SaveRoll.Total] -ge @{selected|spell_save_dc}|FailedSave --+[*[&tokenid]:t-name]:|Save [$SaveRoll] [r][$DoubleDamage] [&damageType][/r] --^afterSave| --/|Output a line for a successful saving throw --:madeSave| --+[*[&tokenid]:t-name]:|Save [$SaveRoll] [r][$HalfDamage] [&damageType][/r] --:afterSave| --~tokenid|array;getnext;tokensHit --?[&tokenid] -ne ArrayError|loopDisplay --:endOutput| --X| --:ApplyDamageTokenmod|Parameters are tokenid;bar#;amount --@token-mod|_ignore-selected _ids [%1%] _set bar[%2%]_value|[%3%] --<| --:ApplyDamageAlterbars|Parameters are tokenid;bar#;amount --@alter|_target|[%1%] _bar|[%2%] _amount|-[%3%] _show|none --<| --:checkForTokenHits|parameter is vfx descriptor --=baseX|[*S:t-left] - 1 \ 70 --=baseY|[*S:t-top] - 1 \ 70 --~offset|array;getfirst;?{Direction} --:checkTokenLoop| --?"[&offset]" -eq "ArrayError"|endCheckForTokenHits --~split|string;split;,;[&offset] --=thisX|[$baseX] + [&split1] --=thisY|[$baseY] + [&split2] --/|IF we passed a visual effect specifier in %1%, create a point VFX in the square --?"X[%1%]X" -ne "XX" |[ --=VX|[$thisX] * 70 + 35 --=VY|[$thisY] * 70 + 35 --vpoint|[$VX] [$VY] [%1%] --]| -->checkTokens|[$thisX];[$thisY] --~offset|array;getnext;?{Direction} --^checkTokenLoop| --:endCheckForTokenHits| --<| --/|Reads the variables created by createTokenLookup to find any tokens that occupy a given space. --:checkTokens|x;y --?"X[&tok[%1%]-[%2%]]X" -ne "XX"|[ --~split|string;split;!;[&tok[%1%]-[%2%]] --%P|1;[$splitCount.Total];1 --=var|split[&P] --?"X[&[$var.RollText]]X" -eq "XX"|% --~exists|array;indexof;tokensHit;[&[$var.RollText]] --?[&exists] -ne ArrayError|skipAdd --?[&[$var.RollText]] -eq ArrayError|skipAdd --~|array;add;tokensHit;[&[$var.RollText]] --:skipAdd| --%| --<| --/|Creates a series of string variables with names like 'tok12-15' which represent the various squares that are --/|occupied by tokens on the page. Handle 1x1, 2x2, and 3x3 tokens by simply adding extra squares in the appropriate --/|pattern around the center point location. The result is that if there are two tokens at 12,15, the tok12-15 string --/|will contain something like "-asln34njfn2nafd!-sdnfklaserfs" (IDs separated by exclamation points) that we can use to --/|quickly evaluate hits by essentially asking "what is in square 12x15" by just reading the variable. --:createTokenLookup| --~tokenid|array;getfirst;alltokens --:tokenSetupLoop| --?[&tokenid] -eq ArrayError|endSetupLoop --=tLeft|[*[&tokenid]:t-left] - 1 \ 70 --=tTop|[*[&tokenid]:t-top] - 1 \ 70 --=tWidth|[*[&tokenid]:t-width] --?[$tWidth] -eq 70|[ --&tok[$tLeft]-[$tTop]|+[&tokenid]! --/+[*[&tokenid]:character_name]|At [$tLeft],[$tTop] : [&tok[$tLeft.Total]-[$tTop.Total]] --]| --?[$tWidth] -eq 140|[ --=NX|[$tLeft] + 1 --=NY|[$tTop] + 1 --&tok[$tLeft]-[$tTop]|+[&tokenid]! --&tok[$tLeft]-[$NY]|+[&tokenid]! --&tok[$NX]-[$tTop]|+[&tokenid]! --&tok[$NX]-[$NY]|+[&tokenid]! --]| --?[$tWidth] -eq 210|[ --=PX|[$tLeft] - 1 --=PY|[$tTop] - 1 --=NX|[$tLeft] + 1 --=NY|[$tTop] + 1 --&tok[$tLeft]-[$tTop]|+[&tokenid]! --&tok[$PX]-[$PY]|+[&tokenid]! --&tok[$tLeft]-[$PY]|+[&tokenid]! --&tok[$NX]-[$PY]|+[&tokenid]! --&tok[$PX]-[$tTop]|+[&tokenid]! --&tok[$NX]-[$tTop]|+[&tokenid]! --&tok[$PX]-[$NY]|+[&tokenid]! --&tok[$tLeft]-[$NY]|+[&tokenid]! --&tok[$NX]-[$NY]|+[&tokenid]! --]| --~tokenid|array;getnext;alltokens --^tokenSetupLoop| --:endSetupLoop| --<| }}
Anyone know of a script card the works for DeathSave? that also mark the character sheet with the correct response. An maybe a macro that will clear the attempts. 
Hey, All: About making API calls. I have this same problem with PowerCards as well as ScriptCards. I can’t seem to make my own API calls. I want to use Token-Mod API to set the status of a token. I would normally code !token-mod --set statusmarkers#!dead. With Scriptcards I’m trying with:  !scriptcard  {{ --@token-mod| _set statusmarkers#!dead }} No go. It’s not just a quick fix I'm looking for. It’s the concept I’m missing. I mean, go ahead and throw in the fix, but ‘splain how it works or won't work. What am I missing when I want to make similar calls with other APIs? As always, thanks ahead of time for the help.
Rosco James said: Hey, All: About making API calls. I have this same problem with PowerCards as well as ScriptCards. I can’t seem to make my own API calls. I want to use Token-Mod API to set the status of a token. I would normally code !token-mod --set statusmarkers#!dead. With Scriptcards I’m trying with:  !scriptcard  {{ --@token-mod| _set statusmarkers#!dead }} No go. It’s not just a quick fix I'm looking for. It’s the concept I’m missing. I mean, go ahead and throw in the fix, but ‘splain how it works or won't work. What am I missing when I want to make similar calls with other APIs? As always, thanks ahead of time for the help. You may have to toggle a TokenMod configuration to allow for use of PlayerId's.  !token-mod --help command I believe will present you the option to toggle. When issuing commands from ScriptCard, TokenMod cant tell that the GM is executing the command and by default disallows it.  
1621528130
David M.
Pro
API Scripter
Will M. said: You may have to toggle a TokenMod configuration to allow for use of PlayerId's.  !token-mod --help command I believe will present you the option to toggle. When issuing commands from ScriptCard, TokenMod cant tell that the GM is executing the command and by default disallows it.   There is also a checkbox to toggle this option in the API console when you click on the token-mod script, in case you don't want to wade through the pages of documentation in the help.
1621529159
timmaugh
Pro
API Scripter
Rosco James said: Hey, All: About making API calls. I have this same problem with PowerCards as well as ScriptCards. I can’t seem to make my own API calls. I want to use Token-Mod API to set the status of a token. I would normally code !token-mod --set statusmarkers#!dead. With Scriptcards I’m trying with:  !scriptcard  {{ --@token-mod| _set statusmarkers#!dead }} No go. It’s not just a quick fix I'm looking for. It’s the concept I’m missing. I mean, go ahead and throw in the fix, but ‘splain how it works or won't work. What am I missing when I want to make similar calls with other APIs? As always, thanks ahead of time for the help. In addition to Will's excellent advice, when one API calls another, there is no selected token array, so you have to modify your line slightly. Sometimes, as with TokenMod, there is a way to do it within the command line itself: !token-mod --set statusmarkers#!dead ...becomes... !token-mod --set statusmarkers#!dead --ignore-selected --ids -M1234567890abcdef (Which is where Will's advice comes into play, requiring you to allow players to utilize IDs). If there is only ever one token selected, you can still resolve that with an @{selected|...} formation, since those will resolve even though the token won't survive as part of the array of selected tokens: !token-mod --set statusmarkers#!dead --ignore-selected --ids @{selected|token_id} Alternatively, whether or not a script offers a command-line way to designate the tokens to affect, or if you want to limit the players' ability to affect only the tokens they can select (instead of allowing the players to utilize the ids argument), you can use SelectManager to restore the selected tokens to downstream, API-generated script calls. For a call to TokenMod, which can affect all of the selected tokens, you wouldn't have to do anything other than ensure that SelectManager was configured to hand back the selected tokens (which it is by default). For another script that expected a single selected token but which you wanted to operate over many individual tokens, you can use SelectManager's !forselected handle. That will iterate the command over each token originally selected as individual calls. It offers a customizable escape character if you wanted to defer the detection of a token/character specific piece of data until the downstream call is made. While this deferral *doesn't* allow for standard roll20 parsable constructs (like @{selected|token_id} ) because there IS NO selected token until SelectManager restores it, it does allow for Fetch retrievals. Imagine using !forselected to call Spawn to tell 10 tokens to simultaneously spawn their "familiar". The name of each familiar is stored on the associated character sheet of each original token in an attribute called "FamiliarName". We don't want all 10 spawned tokens to be named "Albertus" just because the first character happened to have that in the FamiliarName field. We want them individualized. That command might look like: !forselected(^) !Spawn --name|@^(selected.FamiliarName) --offset|1,1 ...where the ^ character is being utilized to break up the Fetch construction of @(selected.FamiliarName) . When SelectManager dispatches the Spawn call for each token, that character is removed and the individual selected token is returned, so when the command line hits the installed scripts the Fetch construct is detectable and it has the correct token to pull information from. Obviously, the above lines must pass through one more syntax change to make them work in the ScriptCards macro (replacing -- with _, for instance). Also, if you are going to use more than one of the metascripts, I strongly suggest you install ZeroFrame as a controlling structure that lets you order and loop over them.
So, I am a little leery of throwing something out there given the incredible effort my last "thought experiment" instigated.  :-)  (Something like the little kid that throws out the first baseball - toss it up in the air vaguely somewhere then run like hell.)  But here goes: 1.  Tokenmod and other scripts allow selection of multiple targets (e.g. @{target|1|token_id} , @{target|1|token_id}, etc.) within the script.  I know Kurt used the --i parameter to call for selected tokens in Magic Missile as well.  However, neither tokenmod nor the --i function can select another target in response to a condition after you had originally selected a target for the script.  (e.g.. chaos bolt.  Select target. Attack. If both die = 8 then pick another target to attack.) 2. Asking a subsequent question only as part of a condition.  --&Cat|?{what is the name of your cat?|}  then later on in the script, (random 50/50 roll) --&Newcat||Your cat didn't make it, what is the name of your new cat?|}.  I.e. the second question would not be asked unless the condition of the first cat had changed.  At this time, both questions are asked (relatively) simultaneously regardless of the status of the condition.  BTW I am awed by the talent of this group but, in particular, Kurt's scriptcard API is as awesome as can be.  Kudos to all.
1621532714
David M.
Pro
API Scripter
Michael, maybe the chaos bolt scriptcard could just conditionally output a button that would call another instance of the chaos bolt? If the conditions aren't met, then the player isn't given the option to target another (the button isn't printed). 
As usual, the community jumped right in. Thanks everybody. Turns out this made the difference:    Players can IDs is currently   ON Toggle Nice catch, Will & David M’s. It was an easy find either way. Now this works !scriptcard  {{   --@token-mod| _set statusmarkers#dead _ignore-selected _ids @{selected|token_id} }} Not to be piggish nor priggish, I still feel the need to know how to think about future API calls. For example: I don’t know why  !scriptcard  {{  --@alter|_target|@{target|token_id} _bar|1 _amount|-[$tDmg] _show|none }}   works. I just cut and pasted from the documentation. Do I suppose every API will have the appropriate instructions? How deep can one nest an API within scripts?  I'm old enough to really miss the old user group gatherings. Even Border's Book Stores, where you could find a tech book about anything. And have a cup of coffee.
1621536838
David M.
Pro
API Scripter
Yes, each script will have its own syntax so you will have to review the documentation for each. When calling from scriptcards, you replace the leading !ScriptCommand with --@ScriptCommand| and then if there are any double dash("--") delimiters that the subordinate script uses, you replace those with underscores. Since scriptcards also uses double dashes to separate commands, it will get confused otherwise. Then, scriptcards re-builds the standard subordinate script syntax before sending the command off to the chat. There may some additional tricks you have to play if the subordinate script requires, say, a selected token, or does not natively handle being called from another script. That's where some of timmaugh's meta scripts can come in really handy. But that is too broad of a topic for one response :)
1621545438
timmaugh
Pro
API Scripter
Rosco James said: As usual, the community jumped right in. Thanks everybody. Turns out this made the difference:    Players can IDs is currently   ON Toggle Nice catch, Will & David M’s. It was an easy find either way. Now this works !scriptcard  {{   --@token-mod| _set statusmarkers#dead _ignore-selected _ids @{selected|token_id} }} Not to be piggish nor priggish, I still feel the need to know how to think about future API calls. For example: I don’t know why  !scriptcard  {{  --@alter|_target|@{target|token_id} _bar|1 _amount|-[$tDmg] _show|none }}   works. I just cut and pasted from the documentation. Do I suppose every API will have the appropriate instructions? How deep can one nest an API within scripts?  I'm old enough to really miss the old user group gatherings. Even Border's Book Stores, where you could find a tech book about anything. And have a cup of coffee. First, you are not alone in the struggle to understand what you need to do to trigger behaviors in Roll20, let alone what each individual script requires for you to activate behaviors in it! I think everybody goes through that. =D I wanted to add my thoughts to what David has already said, so I created a Demystifying Using Scripts thread so as to not pollute this thread with the (sometimes long) answers. Hopefully it helps!
@David - that would certainly work but it would be nice to be able to add targets off a conditional (or unconditional) branch without leaving the script.  
Kurt J. said: Here is my implementation of Burning Hands. Much of the Lightning Bolt code is reused, the difference being that there is no line calculation but instead the definition of arrays for each of the grid directions. These arrays were taken from the templates in Xanathars for cone spells on a grid. This could easily be updated for 30' cones by simply adding more entries to each array. It would also be a simple matter to update the arrays to handle cube spells like Thunderwave. The numbers in the array are x and y offset pairs for each impacted square, assuming the caster is at 0,0 compared to these values. I have emojis for each of the directional arrows in the dropdown, though they can be hard to see on big displays, so I also include the direction name. Anyway, while I've run it several times there could always be bugs, so let me know if you run into anything. (I need to check the damage numbers - they look off to me, but I'll look at them). Found a bug in the saving throw roll on both this and Lightning Bolt. Updated. !script {{ --/|Burning Hands script. Can be changed to other 15' cone-based spells by updating these parameters. --/|larger cones can be defined by updating the array definitions for the diretions to include additional offsets. --/|cube shaped spells could be acocmodated in a similar way. --&spellName|Burning Hands --/|Note: because the spell will be cast at a min level of 1, we use 2 here to get the total dice (2+1=3) --&spellL0DamageDice|2 --/|Prompt for the spell level. Update this to account for the minimum level of the spell --=SpellLevel|?{Spell Slot Level?|1|2|3|4|5|6|7|8|9} --&spellDamageDieType|6 --&damageType|fire --&saveType|dexterity --/|Source Token is the caster, and target token is the "end of the line". Can be a non-creature (no represents) token. --#sourcetoken|@{selected|token_id} --/|Get all of the tokens on the page so we can cache their positions --~|array;pagetokens;alltokens;@{selected|token_id} --#leftsub|Save DC @{selected|spell_save_dc} --#rightsub|Slot Level: [$SpellLevel] --#title|[&spellName] --/|Calculate damage based on spell slot. --=DamageDice|[$SpellLevel.Total] + [&spellL0DamageDice] --=Damage|[$DamageDice.Total]d[&spellDamageDieType] --=HalfDamage|[$Damage.Total] \ 2 --=DoubleDamage|[$Damage.Total] * 2 --=QuarterDamage|[$Damage.Total] \ 4 --/|Since we want to be able to hover over a roll and see the dice details, output the rolled damage at the --/|top of the card. If all critters make their save, the half damage roll won't contain the details. --+|[c][b]Damage Roll: [/b][$Damage][/c] --+|  --/|Create an array to hold the tokens that are intersected by the line. --~|array;define;tokensHit; -->createTokenLookup| --/|Prompt for a direction for hte cast, and define arrays that indicate the relative spaces that will be hit. --&direction|?{Direction|⬆ (UP),U|↗ (UP-RIGHT),UR|➡ (RIGHT),R|↘ (DOWN-RIGHT),DR|⬇ (DOWN),D|↙ (DOWN-LEFT),DL|⬅ (LEFT),L|&#x2196 (UP-LEFT);,UL|} --~|array;define;U;0,-1;0,-2;-1,-2;-1,-3;0,-3;1,-3 --~|array;define;D;0,1;0,2;1,2;-1,3;0,3;1,3 --~|array;define;R;1,0;2,0;2,-1;3,-1;3,0;3,1 --~|array;define;L;-1,0;-2,0;-2,-1;-3,-1;-3,0;-3,1 --~|array;define;UR;1,-1;1,-2;1,-3;2,-1;2,-2;3,-1 --~|array;define;DR;1,1;1,2;1,3;2,1;2,2;3,1 --~|array;define;UL;-1,-1;-1,-2;-1,-3;-2,-1;-2,-2;-3,-1 --~|array;define;DL;-1,1;-1,2;-1,3;-2,1;-2,2;-3,1 --/|Call the "checkForTokenHits" subroutine. The passed parameter will be the per-space VFX. Leave blank for none. -->checkForTokenHits|burn-frost --/|The first item in the array will be a blank dummy item, so remove it. --~|array;removeat;tokensHit;0 --/|Loop through the tokensHit tokens and roll saves for each one and apply damage --~tokenid|array;getfirst;tokensHit --?[&tokenid] -eq ArrayError|endOutput --:loopDisplay| --=SaveRoll|1d20 + [*[&tokenid]:[&saveType]_save_bonus] --/|Compare the save roll to the save DC and either apply full or half damage --?"[*[&tokenid]:npc_immunities]" -inc "[&damageType]"|Immune --?"[*[&tokenid]:npc_resistances]" -inc "[&damageType]"|Resistant --?"[*[&tokenid]:npc_vulnerabilities]" -inc "[&damageType]"|Vulnerable --?[$SaveRoll.Total] -lt @{selected|spell_save_dc}|>ApplyDamageAlterbars;[&tokenid];3;-[$Damage.Total]|>ApplyDamageAlterbars;[&tokenid];3;-[$HalfDamage.Total] --?[$SaveRoll.Total] -ge @{selected|spell_save_dc}|madeSave --/|Here are various damage applications if the creature is immune, resistant, or vulnerable. In some cases, we will reuse output lines, --/|for example, a resistant creature that fails its save will jump to "madeSave", since that is the correct damage amount. (half), while --/|a vulnerable creature that makes its save will jump to "FailedSave" since that will be normal damage. --/|Output a line for a failed saving throw (we will also jump here for a vulnerable creature that MAKES its save) --:FailedSave| --+[*[&tokenid]:t-name]:|Save [$SaveRoll] [r][$Damage] [&damageType][/r] --^afterSave| --:Immune| --+[*[&tokenid]:t-name]:|is not effected by the spell! --^afterSave| --:Resistant| --?[$SaveRoll.Total] -lt @{selected|spell_save_dc}|>ApplyDamageAlterbars;[&tokenid];3;-[$HalfDamage.Total]|>ApplyDamageAlterbars;[&tokenid];3;-[$QuarterDamage.Total] --?[$SaveRoll.Total] -lt @{selected|spell_save_dc}|madeSave --+[*[&tokenid]:t-name]:|Save [$SaveRoll] [r][$QuarterDamage] [&damageType][/r] --^afterSave| --:Vulnerable| --?[$SaveRoll.Total] -lt @{selected|spell_save_dc}|>ApplyDamageAlterbars;[&tokenid];3;-[$DoubleDamage.Total]|>ApplyDamageAlterbars;[&tokenid];3;-[$Damage.Total] --?[$SaveRoll.Total] -ge @{selected|spell_save_dc}|FailedSave --+[*[&tokenid]:t-name]:|Save [$SaveRoll] [r][$DoubleDamage] [&damageType][/r] --^afterSave| --/|Output a line for a successful saving throw --:madeSave| --+[*[&tokenid]:t-name]:|Save [$SaveRoll] [r][$HalfDamage] [&damageType][/r] --:afterSave| --~tokenid|array;getnext;tokensHit --?[&tokenid] -ne ArrayError|loopDisplay --:endOutput| --X| --:ApplyDamageTokenmod|Parameters are tokenid;bar#;amount --@token-mod|_ignore-selected _ids [%1%] _set bar[%2%]_value|[%3%] --<| --:ApplyDamageAlterbars|Parameters are tokenid;bar#;amount --@alter|_target|[%1%] _bar|[%2%] _amount|-[%3%] _show|none --<| --:checkForTokenHits|parameter is vfx descriptor --=baseX|[*S:t-left] - 1 \ 70 --=baseY|[*S:t-top] - 1 \ 70 --~offset|array;getfirst;?{Direction} --:checkTokenLoop| --?"[&offset]" -eq "ArrayError"|endCheckForTokenHits --~split|string;split;,;[&offset] --=thisX|[$baseX] + [&split1] --=thisY|[$baseY] + [&split2] --/|IF we passed a visual effect specifier in %1%, create a point VFX in the square --?"X[%1%]X" -ne "XX" |[ --=VX|[$thisX] * 70 + 35 --=VY|[$thisY] * 70 + 35 --vpoint|[$VX] [$VY] [%1%] --]| -->checkTokens|[$thisX];[$thisY] --~offset|array;getnext;?{Direction} --^checkTokenLoop| --:endCheckForTokenHits| --<| --/|Reads the variables created by createTokenLookup to find any tokens that occupy a given space. --:checkTokens|x;y --?"X[&tok[%1%]-[%2%]]X" -ne "XX"|[ --~split|string;split;!;[&tok[%1%]-[%2%]] --%P|1;[$splitCount.Total];1 --=var|split[&P] --?"X[&[$var.RollText]]X" -eq "XX"|% --~exists|array;indexof;tokensHit;[&[$var.RollText]] --?[&exists] -ne ArrayError|skipAdd --?[&[$var.RollText]] -eq ArrayError|skipAdd --~|array;add;tokensHit;[&[$var.RollText]] --:skipAdd| --%| --<| --/|Creates a series of string variables with names like 'tok12-15' which represent the various squares that are --/|occupied by tokens on the page. Handle 1x1, 2x2, and 3x3 tokens by simply adding extra squares in the appropriate --/|pattern around the center point location. The result is that if there are two tokens at 12,15, the tok12-15 string --/|will contain something like "-asln34njfn2nafd!-sdnfklaserfs" (IDs separated by exclamation points) that we can use to --/|quickly evaluate hits by essentially asking "what is in square 12x15" by just reading the variable. --:createTokenLookup| --~tokenid|array;getfirst;alltokens --:tokenSetupLoop| --?[&tokenid] -eq ArrayError|endSetupLoop --=tLeft|[*[&tokenid]:t-left] - 1 \ 70 --=tTop|[*[&tokenid]:t-top] - 1 \ 70 --=tWidth|[*[&tokenid]:t-width] --?[$tWidth] -eq 70|[ --&tok[$tLeft]-[$tTop]|+[&tokenid]! --/+[*[&tokenid]:character_name]|At [$tLeft],[$tTop] : [&tok[$tLeft.Total]-[$tTop.Total]] --]| --?[$tWidth] -eq 140|[ --=NX|[$tLeft] + 1 --=NY|[$tTop] + 1 --&tok[$tLeft]-[$tTop]|+[&tokenid]! --&tok[$tLeft]-[$NY]|+[&tokenid]! --&tok[$NX]-[$tTop]|+[&tokenid]! --&tok[$NX]-[$NY]|+[&tokenid]! --]| --?[$tWidth] -eq 210|[ --=PX|[$tLeft] - 1 --=PY|[$tTop] - 1 --=NX|[$tLeft] + 1 --=NY|[$tTop] + 1 --&tok[$tLeft]-[$tTop]|+[&tokenid]! --&tok[$PX]-[$PY]|+[&tokenid]! --&tok[$tLeft]-[$PY]|+[&tokenid]! --&tok[$NX]-[$PY]|+[&tokenid]! --&tok[$PX]-[$tTop]|+[&tokenid]! --&tok[$NX]-[$tTop]|+[&tokenid]! --&tok[$PX]-[$NY]|+[&tokenid]! --&tok[$tLeft]-[$NY]|+[&tokenid]! --&tok[$NX]-[$NY]|+[&tokenid]! --]| --~tokenid|array;getnext;alltokens --^tokenSetupLoop| --:endSetupLoop| --<| }} Your scripts are currently disabled due to an error that was detected. Please make appropriate changes to your script's code and click the "Save Script" button. We will then attempt to start running the scripts again.  More info...  If this script was installed from the Script Library, you might find help in the Community API Forum. For reference, the error message generated was:  ReferenceError: arrayvariables is not defined ReferenceError: arrayvariables is not defined at apiscript.js:8323:30 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:1708: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) at /home/node/d20-api-server/node_modules/firebase/lib/firebase-node.js:111:400 "ScriptCards Error: Label [ is not defined on line 137" "ScriptCards Error: Label [ is not defined on line 137" "ScriptCards Error: Label [ is not defined on line 137" "ScriptCards Error: Label [ is not defined on line 137" "ScriptCards Error: Label [ is not defined on line 137" "ScriptCards Error: Label [ is not defined on line 137" "ScriptCards Error: Label [ is not defined on line 137" "ScriptCards Error: Label [ is not defined on line 137" "ScriptCards Error: Label [ is not defined on line 137" "ScriptCards Error: Label [ is not defined on line 137" "ScriptCards Error: Label [ is not defined on line 137" "ScriptCards Error: Label [ is not defined on line 137" "ScriptCards Error: Label [ is not defined on line 137" "ScriptCards Error: Label [ is not defined on line 137" "ScriptCards Error: Label [ is not defined on line 101" "ScriptCards Error: Label [ is not defined on line 113" "ScriptCards Error: Label % is not defined on line 117" I get these errors after running this code. I get nearly the same errors for the lightning bolt example you made. Am I supposed to alter this code to make it work? BTW- I love what you've made here and I'm eager to master it. I've already been able to re-script almost all of the PowerCards macros I made in less than a week. Great work. I can't wait to be proficient enough to contribute to the community. Any help with this you  can provide is GREATLY appreciated.
1621550087
Kurt J.
Pro
API Scripter
@Andy, what version of ScriptCards do you have installed? The latest OneClick version won't support many of the features used in these scripts. The latest version  (currently 1.2.8) will be needed.
Kurt J. said: @Andy, what version of ScriptCards do you have installed? The latest OneClick version won't support many of the features used in these scripts. The latest version  (currently 1.2.8) will be needed. Oh Snap! Thx! That was driving me bonkers. And, once again. you are doing great stuff here. Thank you so much!
Andy said: Kurt J. said: @Andy, what version of ScriptCards do you have installed? The latest OneClick version won't support many of the features used in these scripts. The latest version  (currently 1.2.8) will be needed. Oh Snap! Thx! That was driving me bonkers. And, once again. you are doing great stuff here. Thank you so much! Yup that was the fix. OMG I thought I wasn't understanding how arrays worked or something, but I was just out of date. This made my day! Thatnks Kurt! :)
1621556521
Kurt J.
Pro
API Scripter
Andy said: Andy said: Kurt J. said: @Andy, what version of ScriptCards do you have installed? The latest OneClick version won't support many of the features used in these scripts. The latest version  (currently 1.2.8) will be needed. Oh Snap! Thx! That was driving me bonkers. And, once again. you are doing great stuff here. Thank you so much! Yup that was the fix. OMG I thought I wasn't understanding how arrays worked or something, but I was just out of date. This made my day! Thatnks Kurt! :) Glad to hear it is working :) And I'll fix the bug in the "after" function for the next release.
1621558642
Kurt J.
Pro
API Scripter
Michael C. said: So, I am a little leery of throwing something out there given the incredible effort my last "thought experiment" instigated.  :-)  (Something like the little kid that throws out the first baseball - toss it up in the air vaguely somewhere then run like hell.)  But here goes: 1.  Tokenmod and other scripts allow selection of multiple targets (e.g. @{target|1|token_id} , @{target|1|token_id}, etc.) within the script.  I know Kurt used the --i parameter to call for selected tokens in Magic Missile as well.  However, neither tokenmod nor the --i function can select another target in response to a condition after you had originally selected a target for the script.  (e.g.. chaos bolt.  Select target. Attack. If both die = 8 then pick another target to attack.) 2. Asking a subsequent question only as part of a condition.  --&Cat|?{what is the name of your cat?|}  then later on in the script, (random 50/50 roll) --&Newcat||Your cat didn't make it, what is the name of your new cat?|}.  I.e. the second question would not be asked unless the condition of the first cat had changed.  At this time, both questions are asked (relatively) simultaneously regardless of the status of the condition.  BTW I am awed by the talent of this group but, in particular, Kurt's scriptcard API is as awesome as can be.  Kudos to all. Unfortunately this is somewhat down to limitations of the API itself. When a macro/script is called, the Roll20 Chat Server runs through and does the following things (in this order) Replace @{} references with values (like @{selected|character_id}, etc. Prompt the user for any Roll Query (?{...|...}) selections Calculate any inline rolls ([[ 1d20 + 5 ]]) and replace the rolls text with $[[0]], $[[1]], etc. There may be other steps that I'm missing (html character replacement falls in there somewhere, but I didn't try it out to determine where), but the above is the reason you can do: !Something [[ 1d20 + ?{What|@{selected|hp}|@{selected|strength_mod}} ]] versus @{target|AC} but not  @{selected|?{What?|strength_mod|pb}} since the attribute lookup in the second line will be executed before the roll query is prompted. After all of this is done, the chat server will hand the text (along with some things like information on selected tokens, what the results behind the inline rolls are, and who sent the message) to the API. This means that the for the line above (that works), the API will see something like this: !Something $[[0]] versus 16 It will have no idea that you looked up attributes, or had a target, or were asked a question. When the API sends something to chat with the SendChat function, of the three processes listed above, attribute substitution is performed (though there is no "selected" (you can use character names or IDs, though), and inline roll parsing takes places. Roll Queries, however, do not. Even if you use the "player|-playerid" format for the SpeakingAs parameter of SendChat, it isn't really tied to that player so as far as the chat server is concerned there is no one to ask the question of since the API couldn't answer it. For the same reason (there is noone to ask) you can't use @{target...} in SendChat either. In the end, David's suggestion is probably the only realistic way to do it... even then, the request has to come from a player action to pop up the target selection or roll query.
1621562690

Edited 1621562736
timmaugh
Pro
API Scripter
Kurt J. said: Unfortunately this is somewhat down to limitations of the API itself.... *SNIP*...  you can do: !Something [[ 1d20 + ?{What|@{selected|hp}|@{selected|strength_mod}} ]] versus @{target|AC} but not  @{selected|?{What?|strength_mod|pb}} since the attribute lookup in the second line will be executed before the roll query is prompted. Kurt, as usual, makes excellent points. The net effect is that any/all targeting calls and roll queries must be processed at the top level of the macro (not in any conditional branch or sub-script call)... so you end up getting prompted with them ALL at the start of the parsing. On the above issue, however, where you might want to resolve the roll query before you retrieved the information from the token or character, Fetch and ZeroFrame can help in many circumstances. To rework Kurt's example but use a Fetch construction: @(selected.?{What?|strength_mod|pb}) That works. Now, you could handle the same idea with standard Roll20 constructions like this: ?{What?|@{selected|strength_mod}|@{selected|pb}} *As long as both attributes exist*, because they will be retrieved before the roll query is presented to you. If either of them fail (that is, they don't exist), the command line will error out. Maybe that was exactly the reason why you would want to do the retrieval in the opposite order - to make sure that in a given circumstance you pick the proper attribute, if possible. In that sort of case, where it is possible that an attribute might not exist, you can provide a default value to Fetch, here a 0: @(selected.?{What?|strength_mod|pb}[0]) The other reason to maybe want to perform the operations in this order is to introduce some random factor into the selection of an attribute. If you had 3 attributes you could select from that were named some1, some2, and some3, you could randomize the selection between them with an inline roll, extracting the result: @(selected.some[[1d3]].value} Fetch can work with "selected", a token name, a character name, or "speaker."
1621564428

Edited 1621567529
Update: I figured out a neat trick, you can actually define [&reentryval] (part of [rbutton] syntax for passing a parameter) the first time you run a script card, thereby setting up a DEFAULT value for [&reentryval].  Handy for establish initial value for script cards you recall over and over again with different parameters.  I've implemented this in my latest Page Assets scripts and can be found on the sharing forum .   Hopefully this is a simple question:  What is the best way to test for an Empty Roll or String variable? I'm trying to establish a default value the first time a ScriptCard runs, and then give the user an option to change it using Reentry logic the next time they enter.  I'm attempting to test for an empty Roll variable (or String) the first time the code runs, but it doesn't always seem to work.  It may be I've had too much bourbon tonight while coding, I'm just flummoxed. 
Kurt J. said: Andy said: Andy said: Kurt J. said: @Andy, what version of ScriptCards do you have installed? The latest OneClick version won't support many of the features used in these scripts. The latest version  (currently 1.2.8) will be needed. Oh Snap! Thx! That was driving me bonkers. And, once again. you are doing great stuff here. Thank you so much! Yup that was the fix. OMG I thought I wasn't understanding how arrays worked or something, but I was just out of date. This made my day! Thatnks Kurt! :) Glad to hear it is working :) And I'll fix the bug in the "after" function for the next release. Thanks Again Kurt. I appreciate what you're creating. I know it's easier to critique than create.
@Kurt/tim - Thanks, guys - I see the issues now.  Well, Santa doesn't always give us the Christmas presents we ask for and I know there are workarounds I can use (like David's).  :-)  I just wanted to minimize the number of times I told players, "hold on while I fix that."  ;-)
Looking to make a index card for what marker I am using for my conditions and custom markers.  The old one I had for power card required a handout. Any know how to do this for Scriptcards? Example of my old powercard.
I think you would have to upload each of the condition graphics as an image in your library, then use the --+|[img]url[/img] syntax, referencing the image in the url.  
1621695797

Edited 1621696827
Kurt J.
Pro
API Scripter
Craven said: Looking to make a index card for what marker I am using for my conditions and custom markers.  The old one I had for power card required a handout. Any know how to do this for Scriptcards? Example of my old powercard. This is actually really easy to do in ScriptCards. The language supports [sm]StatusName[/sm] as a formatting option, and will look for a status marker matching the name and put its icon there. No need to host separate images, as ScriptCards asks your Campaign for the URLs, so it can display them without them being in your library. The images are a little large for my taste, so I added "width=25" to shrink them down a bit. Below are two scripts. The first is a generic script that anyone can updated to list the conditions they use. the second script duplicates the image you posted above (except the gradient on the title bar and some line spacing) :) Note that I don't use custom status markers, though from what I understand they have names just like the default ones. You should be able to substitute/add those names to the [sm] formatting to show them.  I just added some custom markers to my game, and they work fine with the [sm] code as long as you know the name used internally. If you add them mid-game, you'll need to restart the sandbox so the routine that gets the list of markers re-runs. Script #1 - Generic Statusmarker List with Names !script {{ --#title|Condition Symbols --#leftsub|Meaning of the Symbols. --+[sm width=25px]skull[/sm]|[b]skull[/b] --+[sm width=25px]sleepy[/sm]|[b]sleepy[/b] --+[sm width=25px]half-heart[/sm]|[b]half-heart[/b] --+[sm width=25px]half-haze[/sm]|[b]half-haze[/b] --+[sm width=25px]interdiction[/sm]|[b]interdiction[/b] --+[sm width=25px]snail[/sm]|[b]snail[/b] --+[sm width=25px]lightning-helix[/sm]|[b]lightning-helix[/b] --+[sm width=25px]spanner[/sm]|[b]spanner[/b] --+[sm width=25px]chained-heart[/sm]|[b]chained-heart[/b] --+[sm width=25px]chemical-bolt[/sm]|[b]chemical-bolt[/b] --+[sm width=25px]death-zone[/sm]|[b]death-zone[/b] --+[sm width=25px]drink-me[/sm]|[b]drink-me[/b] --+[sm width=25px]edge-crack[/sm]|[b]edge-crack[/b] --+[sm width=25px]ninja-mask[/sm]|[b]ninja-mask[/b] --+[sm width=25px]stopwatch[/sm]|[b]stopwatch[/b] --+[sm width=25px]fishing-net[/sm]|[b]fishing-net[/b] --+[sm width=25px]overdrive[/sm]|[b]overdrive[/b] --+[sm width=25px]strong[/sm]|[b]strong[/b] --+[sm width=25px]fist[/sm]|[b]fist[/b] --+[sm width=25px]padlock[/sm]|[b]padlock[/b] --+[sm width=25px]three-leaves[/sm]|[b]three-leaves[/b] --+[sm width=25px]fluffy-wing[/sm]|[b]fluffy-wing[/b] --+[sm width=25px]pummeled[/sm]|[b]pummeled[/b] --+[sm width=25px]tread[/sm]|[b]tread[/b] --+[sm width=25px]arrowed[/sm]|[b]arrowed[/b] --+[sm width=25px]aura[/sm]|[b]aura[/b] --+[sm width=25px]back-pain[/sm]|[b]back-pain[/b] --+[sm width=25px]black-flag[/sm]|[b]black-flag[/b] --+[sm width=25px]bleeding-eye[/sm]|[b]bleeding-eye[/b] --+[sm width=25px]bolt-shield[/sm]|[b]bolt-shield[/b] --+[sm width=25px]broken-heart[/sm]|[b]broken-heart[/b] --+[sm width=25px]cobweb[/sm]|[b]cobweb[/b] --+[sm width=25px]broken-shield[/sm]|[b]broken-shield[/b] --+[sm width=25px]flying-flag[/sm]|[b]flying-flag[/b] --+[sm width=25px]radioactive[/sm]|[b]radioactive[/b] --+[sm width=25px]trophy[/sm]|[b]trophy[/b] --+[sm width=25px]broken-skull[/sm]|[b]broken-skull[/b] --+[sm width=25px]frozen-orb[/sm]|[b]frozen-orb[/b] --+[sm width=25px]rolling-bomb[/sm]|[b]rolling-bomb[/b] --+[sm width=25px]white-tower[/sm]|[b]white-tower[/b] --+[sm width=25px]grab[/sm]|[b]grab[/b] --+[sm width=25px]screaming[/sm]|[b]screaming[/b] --+[sm width=25px]grenade[/sm]|[b]grenade[/b] --+[sm width=25px]sentry-gun[/sm]|[b]sentry-gun[/b] --+[sm width=25px]all-for-one[/sm]|[b]all-for-one[/b] --+[sm width=25px]angel-outfit[/sm]|[b]angel-outfit[/b] --+[sm width=25px]archery-target[/sm]|[b]archery-target[/b] }} Script #2 - Duplicating Craven's Status Marker List !script {{ --#title|Condition Symbols --#leftsub|Meaning of the Symbols. --#titlecardbackground|#990000 --#evenrowbackground|#B6AB91 --#oddrowbackground|#CEC7B6 --+[sm width=25px]angel-outfit[/sm]|[b]Blessed[/b] --+[sm width=25px]bleeding-eye[/sm]|[b]Blind[/b] --+[sm width=25px]chained-heart[/sm]|[b]Charmed[/b] --+[sm width=25px]interdiction[/sm]|[b]Deafened[/b] --+[sm width=25px]screaming[/sm]|[b]Frightened, 1-Rage[/b] --+[sm width=25px]grab[/sm]|[b]Grappled[/b] --+[sm width=25px]ninja-mask[/sm]|[b]Invisible[/b] --+[sm width=25px]aura[/sm]|[b]Paralyzed, 1-Petrified[/b] --+[sm width=25px]skull[/sm]|[b]Poisoned[/b] --+[sm width=25px]back-pain[/sm]|[b]Prone[/b] --+[sm width=25px]fishing-net[/sm]|[b]Restrained[/b] --+[sm width=25px]sleepy[/sm]|[b]Stunned, 1-Unconcious[/b] }}
Nice - I didn't even know the [SM] syntax existed.  One Caveat, a lot of my custom markers have a "::" in them, which can confuse the button logic, if placed in side of a button.  For example, this is the name of my Deafened status marker: Deafened::243729.
Scriptcard proposition : button to call a library sub Would it be reasonnable to be able to call a library sub with parameters through a button from a scriptcard ? Eg. --+|[button]label::+++lib+++subName;param1;param2;...;paramN[/button] Which would be a shortcut for !script{{ +++lib+++ -->subName|param1;param2;param3;...;paramN }} Do you people would have any suggestion for a better declaration ? Is that even a good idea ? We are returning to the ever lasting problem in Roll20 : no folder for macro list, which pisses off everybody for ages ! With this kind of functionnality -> i would folder my #general macros in scriptcard libs !
@Kurt - on your Distance calcs, could you divide the result by 70 after you perform your final equation? On very large maps with a snapping_increment less than 1 (like .2), the rounding being performed is having a significant impact on the result.  For example: Go from this: case "euclideandistance": var result = 0; if (params.length >= 3) { var token1 = getObj("graphic", params[1]); var token2 = getObj("graphic", params[2]); if (token1 && token2) { // Calculate the euclidean unit distance between two tokens (params[1] and params[2]) var x1 = token1.get("left") / 70; var x2 = token2.get("left") / 70; var y1 = token1.get("top") / 70; var y2 = token2.get("top") / 70; result = Math.floor(Math.sqrt(Math.pow((x1-x2),2)+Math.pow((y1-y2),2))); } } rollVariables[variableName] = parseDiceRoll(result.toString(), cardParameters); break; to this: case "euclideandistance": var result = 0; if (params.length >= 3) { var token1 = getObj("graphic", params[1]); var token2 = getObj("graphic", params[2]); if (token1 && token2) { // Calculate the euclidean unit distance between two tokens (params[1] and params[2]) var x1 = token1.get("left"); var x2 = token2.get("left"); var y1 = token1.get("top"); var y2 = token2.get("top"); result = Math.floor(Math.sqrt(Math.pow((x1-x2),2)+Math.pow((y1-y2),2))) / 70.0; } } rollVariables[variableName] = parseDiceRoll(result.toString(), cardParameters); break;
Kurt you rock. Thank you so much for taking the time to do this. When I am done I will post this in the other chat with a link to the marker pack I used.
Craven, I am loving the list of useful utilities/macros.  Thank you very much for doing this.
I think this is a Scriptcard issue so I thought that maybe this would be the better place to ask: currently I'm trying to make a Macro that deals damage and then checks to see if a creature is going to be below 50% hp or 0% hp and apply the Red or Dead Statusmarker respectively. So far it works but when I run it, it asks for a Target 2 times, the first for a 'Target' and the second for a '1'. Here's the exact syntax: @{target|1|hp|max} If I try that syntax outside of a Scriptcard it works without asking for a second target. I can't change the '1' out since without it, the check returns 'undefined,' so I'm a bit stuck. I've also tried using the '[*T:var]' syntax but that also yields 'undefined.' I'm using that like so: [*T:1|hp|max] If y'all know a better way to get the Max HP of a @{target} within Scriptcards it'd be much appreciated, thanks! For the sake of thoroughness, here's the line in its context:   --:Mark| --=HalfHP|@{target|1|hp|max} \ 2 --=TotalHP|@{target|bar1} + @{target|bar3} --=EstFinalHP|[$TotalHP] - [$TotalDamage] --? [$EstFinalHP] -le [$HalfHP]|MarkRed --? [$EstFinalHP] -le 0|MarkDead --:ReturnMark| --<|
1621810413
Kurt J.
Pro
API Scripter
Lionel T. said: Scriptcard proposition : button to call a library sub Would it be reasonnable to be able to call a library sub with parameters through a button from a scriptcard ? Eg. --+|[button]label::+++lib+++subName;param1;param2;...;paramN[/button] Which would be a shortcut for !script{{ +++lib+++ -->subName|param1;param2;param3;...;paramN }} Do you people would have any suggestion for a better declaration ? Is that even a good idea ? We are returning to the ever lasting problem in Roll20 : no folder for macro list, which pisses off everybody for ages ! With this kind of functionnality -> i would folder my #general macros in scriptcard libs ! Library code can't use any @{} notation because it is never processed by the chat server, so that might be problematic. The most common solution i've seen is to create one or more "Macro Mule" characters and use them to store generic macros instead of the campaign-based macro tab. Easy buttons already exist for those (sheetbuttons) in ScriptCards.
1621810498
Kurt J.
Pro
API Scripter
Will M. said: @Kurt - on your Distance calcs, could you divide the result by 70 after you perform your final equation? On very large maps with a snapping_increment less than 1 (like .2), the rounding being performed is having a significant impact on the result.  For example: Go from this: case "euclideandistance": var result = 0; if (params.length >= 3) { var token1 = getObj("graphic", params[1]); var token2 = getObj("graphic", params[2]); if (token1 && token2) { // Calculate the euclidean unit distance between two tokens (params[1] and params[2]) var x1 = token1.get("left") / 70; var x2 = token2.get("left") / 70; var y1 = token1.get("top") / 70; var y2 = token2.get("top") / 70; result = Math.floor(Math.sqrt(Math.pow((x1-x2),2)+Math.pow((y1-y2),2))); } } rollVariables[variableName] = parseDiceRoll(result.toString(), cardParameters); break; to this: case "euclideandistance": var result = 0; if (params.length >= 3) { var token1 = getObj("graphic", params[1]); var token2 = getObj("graphic", params[2]); if (token1 && token2) { // Calculate the euclidean unit distance between two tokens (params[1] and params[2]) var x1 = token1.get("left"); var x2 = token2.get("left"); var y1 = token1.get("top"); var y2 = token2.get("top"); result = Math.floor(Math.sqrt(Math.pow((x1-x2),2)+Math.pow((y1-y2),2))) / 70.0; } } rollVariables[variableName] = parseDiceRoll(result.toString(), cardParameters); break; I am careful about changing the way things work in case someone is using them in a macro, but how about this: I can create a new distance method, maybe euclidianpixels that returns the raw value you could then divide by 70, or euclidianlongrange that does the /70 as you describe above.
non said: I think this is a Scriptcard issue so I thought that maybe this would be the better place to ask: currently I'm trying to make a Macro that deals damage and then checks to see if a creature is going to be below 50% hp or 0% hp and apply the Red or Dead Statusmarker respectively. So far it works but when I run it, it asks for a Target 2 times, the first for a 'Target' and the second for a '1'. Here's the exact syntax: @{target|1|hp|max} If I try that syntax outside of a Scriptcard it works without asking for a second target. I can't change the '1' out since without it, the check returns 'undefined,' so I'm a bit stuck. I've also tried using the '[*T:var]' syntax but that also yields 'undefined.' I'm using that like so: [*T:1|hp|max] If y'all know a better way to get the Max HP of a @{target} within Scriptcards it'd be much appreciated, thanks! For the sake of thoroughness, here's the line in its context:   --:Mark| --=HalfHP|@{target|1|hp|max} \ 2 --=TotalHP|@{target|bar1} + @{target|bar3} --=EstFinalHP|[$TotalHP] - [$TotalDamage] --? [$EstFinalHP] -le [$HalfHP]|MarkRed --? [$EstFinalHP] -le 0|MarkDead --:ReturnMark| --<| Hi non ! I don't understand : If you define TotalHP as you did ( @{target|bar1} + @{target|bar3})  you might as well have used bar1_max and bar3_max instead then HalfHP is set with the following :     --=calcul1|[$TotalHP]/2     --~HalfHP|math;ceil;[$calcul1 Unless there is something that I don't get of course !^^
Hi guys ! Am I dreaming or I've seen some of you working on a radar script ? I am asking 'cause that would be the next stage of my scripts...No that I have coded the 300 spells it would be nice to take range into consideration more precisely ^^ Bye and thanks in advance for the help each of you bring us !
1621810988
Kurt J.
Pro
API Scripter
non said: I think this is a Scriptcard issue so I thought that maybe this would be the better place to ask: currently I'm trying to make a Macro that deals damage and then checks to see if a creature is going to be below 50% hp or 0% hp and apply the Red or Dead Statusmarker respectively. So far it works but when I run it, it asks for a Target 2 times, the first for a 'Target' and the second for a '1'. Here's the exact syntax: @{target|1|hp|max} If I try that syntax outside of a Scriptcard it works without asking for a second target. I can't change the '1' out since without it, the check returns 'undefined,' so I'm a bit stuck. I've also tried using the '[*T:var]' syntax but that also yields 'undefined.' I'm using that like so: [*T:1|hp|max] If y'all know a better way to get the Max HP of a @{target} within Scriptcards it'd be much appreciated, thanks! For the sake of thoroughness, here's the line in its context:   --:Mark| --=HalfHP|@{target|1|hp|max} \ 2 --=TotalHP|@{target|bar1} + @{target|bar3} --=EstFinalHP|[$TotalHP] - [$TotalDamage] --? [$EstFinalHP] -le [$HalfHP]|MarkRed --? [$EstFinalHP] -le 0|MarkDead --:ReturnMark| --<| @{} notation is processed by the chat server before ScriptCards ever sees it. The reason you are being prompted twice is that your macro is asking for two targets: an unamed targetwith @{target|bar3} and a target named "1" with @{target|1|hp|max}. In both cases, ScriptCards only gets to see the final result of this lookup, and never knows there was any targeting done. If you wish to use the [*T:] notation, you need to set the #targettoken parameter. This can be done like this: --#targettoken|@{target|token_id}. From then on, you can use [*T:attribute] to retrieve character attributes or [*T:t-attribute] to retrieve token attributes. Since it isn't  a complete script, I can't test it, but something along these lines should work: --:Mark| --#targettoken|@{target|token_id} --=HalfHP|[*T:hp^] \ 2 --=EstFinalHP|[*T:hp] - [$TotalDamage] --? [$EstFinalHP] -le [$HalfHP]|MarkRed --? [$EstFinalHP] -le 0|MarkDead --:ReturnMark| --<| Also, if you are using something like Token_mod, etc to apply the damage, keep in mind that it won't take place until after the script completes, so it isn't possible to check before and after status of attributes. What you have above is the right way to do it (look at what it was beforehand and subtract the new damage amount and compare that.
1621814773
David M.
Pro
API Scripter
Woombak said: Am I dreaming or I've seen some of you working on a radar script ? Yep, that's me. You can direct any questions about it that aren't scriptcard-related to the dedicated thread , though its scope is really more detection-oriented rather than "do stuff to the things". <<At the risk of being both premature and off-topic for this thread: I had a novel UI idea and had started a new script for that exact purpose a while ago that was radar-adjacent, but it was a bear and I paused work on it early in development to focus on other things. I should probably resurrect that project, though no promises that it will pan out. End of off-topic discussion - you may now resume normal scriptcard-relevant conversations ;) >>
How can i call a macro from within scriptcard without using a button. Example I have a macro called longrest and shortrest and I want to make a scriptcard that players select --&chose|?{What type of rest?|Long, |Short, } that will run the correct macro. The macros are stored on a character sheet.