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

Is there an API that can roll saves for groups then apply a condition to the tokens that failed?

I've been using Jakob's GroupCheck+apply damage API and am very happy with it. Fire Balling my life away. But I've found I need an API that can roll group saves and apply conditions. For something like Hypnotic Pattern. Any suggestions?
1629948394
timmaugh
Pro
API Scripter
You probably won't find one that will do all of that, though there are a couple of options that let you chain others together. ScriptCards lets you build your own processing "functions" to take action only when and how necessary. Metascripts, on the other hand, play in the command lines of other scripts and let you launch them in your own time, after you have the command line in the shape you want. SelectManager has a forselected handle that iterates over the selected tokens, issuing a command line that is customizable for each. Using this, you could have a single save check rolled for a group of tokens which you then individually compare to an attribute for the save attempt, or you could let each token have a unique roll, and check that roll against the same attribute. APILogic gives you the ability to have If/Else logic in your command line, taking one branch given a condition (a failed save), and another branch given a different condition (a successful save). Fetch lets you retrieve data from a token or the sheet as necessary, timed to work with SelectManager's forselected handle. And ZeroFrame lets you control the timing even more, and gives you the capability of getting more complex, chained, or recursive actions. Given  your situation, your workflow would probably be something like: I need <some group of tokens> to roll saves versus <some attribute>. If they fail the check, then I need to apply <some condition>. In practice, that might be something like: !forselected(^) {^if [^[^1d20 + @^(selected.save-mod[0])^]^] > @^(selected.save-attr)}<...command to apply condition -- like token-mod...>{^&end} Post back with more details about what you need to happen (and the other scripts that might be involved -- including command lines), and I can try to help you put a full macro together.
Lee said: I've been using Jakob's GroupCheck+apply damage API and am very happy with it. Fire Balling my life away. But I've found I need an API that can roll group saves and apply conditions. For something like Hypnotic Pattern. Any suggestions? Tokenmod accepts multiselect and I have a generic statusmarker apply hotkey.  The only catch is I have to know the exact spelling of each statusmarker, but as a forever DM in roll20, thats no problem.  I even have custom statusmarkers and know all of them too.   !token-mod --set statusmarkers|!?{What statusmarker?}
1629976814

Edited 1629977969
David M.
Pro
API Scripter
As a follow-up to Tim's mention of scriptcards, here's an example of a scriptcard macro for 5e Turn Undead. It finds tokens within range that are "undead", rolls their saves, and applies condition markers based on success/fail (two failure modes - turned and destroyed, with different markers for each). Similar logic could be applied for Hypnotic Pattern, etc. It could also be modified to roll and apply damage. There are several examples of this in the thread I linked (tip: the first post has an index with links). EDIT - I forgot I had another version of this that hides the creature names from the public output and whispers the actual names to the GM. It also uses the Spawn script with a custom image for the animated effects instead of Radar. !script {{ --#title|@{selected|character_name} Turns Undead! --#leftsub|Save DC @{selected|spell_save_dc} --:(0) CREATE AN ANIMATED EFFECT WITH SPAWN SCRIPT| uses SelectManager to retain selected token --@forselected|Spawn _name|HolyBurst _expand|50,30, true _size|13,13 _order|tofront --:(1) DETERMINE CR OF UNDEAD THAT CAN BE DESTROYED| --=charLevel|@{selected|level} --?[$charLevel] -lt 5|>SetCRdestroy;0 --?[$charLevel] -ge 5 -and [$charLevel] -lt 8|>SetCRdestroy;0.5 --?[$charLevel] -ge 8 -and [$charLevel] -lt 11|>SetCRdestroy;1 --?[$charLevel] -ge 11 -and [$charLevel] -lt 14|>SetCRdestroy;2 --?[$charLevel] -ge 14 -and [$charLevel] -lt 17|>SetCRdestroy;3 --?[$charLevel] -ge 17|>SetCRdestroy;4 --:(2) GET ALL TOKENS INTO THE "allTokens" ARRAY| will have blank 1st element to be removed later --~|array;pagetokens;allTokens;@{selected|token_id} --:(3) CREATE THE "inRange" ARRAY TO HOLD TOKENS IN RANGE| --~|array;define;inRange; --:(4) PREP ARRAY FOR LOOP| if no array elements then end macro --~tokenid|array;getfirst;allTokens --?[&tokenid] -eq ArrayError|endOutput --:(5) FIND ALL TOKENS IN RANGE| --:RangeLoop| --:TOKEN MUST BE ON OBJECTS OR GMLAYER AND TYPE MUST INCLUDE UNDEAD| --?[*[&tokenid]:t-layer] -ne objects -and [*[&tokenid]:t-layer] -ne gmlayer|NextToken --?"[*[&tokenid]:npc_type]" -ninc "undead"|NextToken --:CHECK DISTANCE IN UNITS. 30ft is 5UNITS| --~dist|distance;@{selected|token_id};[&tokenid] --?[$dist] -gt 5|NextToken --:ADD TO THE "inRange" ARRAY| --~|array;add;inRange;[&tokenid] --:NextToken| --~tokenid|array;getnext;allTokens --?[&tokenid] -ne ArrayError|RangeLoop --:(6) REMOVE DUMMY FIRST ITEM IN inRange ARRAY| --~|array;removeat;inRange;0 --:(7) ROLL SAVES FOR EACH TOKEN IN RANGE| if fail, set a token condition marker to denote turned --~tokenid|array;getfirst;inRange --?[&tokenid] -eq ArrayError|End --=i|0 --:SaveLoop| --=i|[$i]+1 --&FailureText| -->GetSaveBonus|[&tokenid];wisdom;wis --=SaveRoll|1d20 + [$saveBonus] [BONUS] --?[$SaveRoll.Total] -ge @{selected|spell_save_dc}|>MadeSave;[$i]|>FailedSave;[$i] --~tokenid|array;getnext;inRange --?[&tokenid] -ne ArrayError|SaveLoop --:End| --X| --:PROCEDURES| --:SetCRdestroy| accepts CR as parameter --=CRdestroy|[%1%] --<| --:GetSaveBonus| accepts tokenid, full attribute name, short attribute name as parameters --:TAKE THE GREATER OF "attribute_save_bonus" OR "npc_attr_save_base"| --=bonus1|[*[%1%]:[%2%]_save_bonus] --&bonus2|[*[%1%]:npc_[%3%]_save_base] --:SOMETIMES "npc_attr_save_base" IS BLANK, SO SET TO -99. OTHERWISE USE ATTR VALUE| --?X[&bonus2] -eq "X"|>Set_npc_attr_save_bonus;-99|>Set_npc_attr_save_bonus;[&bonus2] --:FINALLY SET THE SAVE BONUS| --?[$bonus2] -gt [$bonus1]|>SetSaveBonus;[$bonus2]|>SetSaveBonus;[$bonus1] --<| --:Set_npc_attr_save_bonus| blank value is set to -99, otherwise use value stored in attribute --=bonus2|[%1%] --<| --:SetSaveBonus| --=saveBonus|[%1%] --<| --:MadeSave| --*[*[&tokenid]:character_name]:|[#009900][b]Made Save[/b][/#] [$SaveRoll] --+Creature [%1%]:|[#009900][b]Made Save[/b][/#] [$SaveRoll] --<| --:FailedSave| add either a dead or fear condition marker to the token, depending on CR --=CR|[*[&tokenid]:npc_challenge] --?[$CR] -le [$CRdestroy]|>AddConditionMarker;[&tokenid];dead;-Dest.|>AddConditionMarker;[&tokenid];Fear::1510130;-Turn --*[*[&tokenid]:character_name]:|[#990000][b]Failed Save[/b][/#] [$SaveRoll] [b][&FailureText][/b] --+Creature [%1%]:|[#990000][b]Failed Save[/b][/#] [$SaveRoll] [b][&FailureText][/b] --<| --:AddConditionMarker| accepts tokenID, condition marker, and descriptive text as parameters --@token-mod|_ignore-selected _ids [%1%] _set statusmarkers|[%2%] --&FailureText|[%3%] --<| }} Click for animated gif:
That kicks ass, I will be using that. But it would be handy if there was something with the flexibility to be used for hypnotic pattern, confusion, stinking cloud, entangling roots ext... I'll check out the link. 
1630003865
David M.
Pro
API Scripter
The scriptcard above could be modified for different spells, or even multiple spells if you really wanted to build in the logic. The thread I linked is just for completed, working scriptcards. Here is the wiki documentation for the script, and here's where you would want to post if you need some help with a scriptcard problem. Btw, the one above uses a bunch of different techniques (arrays, loops, attribute syntax, gm-only whispers, farming out other scripts, etc.) - not all scriptcards need to be that complicated. Btw 2, the animated effect above was created using the SpawnDefaultToken script, which in this case was called from within the scriptcard macro (which is made possible by the SelectManager script, whew!). It is just added flair and not required for the primary functionality.
Wow i love this effect !!! please share !!! hehe On my side, i'd love to get something that groupschecks+applydamage (groupcheck on selected tokens, and apply damage on a separate click, not directly in the group check), but also that takes into consideration the immunities or vulnerabilities/resistances of the monsters !! I know that there are scriptcards like fireball from kurt, that does take into consideration the immunities and so on of the monsters, and automatically apllies damages, but it works automatically on an area, and i'd prefer just the funcitionalities of the group check on selected tokens.... Group check really needs the immunities thing improvement and i'm sure that scriptcards magic can have the answer. I wish i could combine a multi token selection, the getsave routine, and a button at the bottom of the saves card so it can then apply damages. (of course that would imply to know what kind of damages it makes, and the rest of the group check routine (what save ? DC ? What if made or fail save...?)
1630023915
David M.
Pro
API Scripter
Scriptcards has two ways to get selected token ids. The first, shown below, populates a series of string variables. From the wiki: Assign Variable to Built-In Function (--~) ScriptCards has the ability to run a function built into the API script and return the results to a variable. Some functions return roll variables, while others return strings. See the function table below for details. The format is: --~VariableName|function;param1;param2;param3;... Function Name Parameters Description getselected none Using the variable name in the tag, a series of string variables will be created: VariableNameCount will contain the number of selected tokens. VariableName1 will contain the token ID of the first selected token, VariableName2 the second, etc. Here's an example of how you can loop through the selected tokens. You could use this method instead of going through the tokens on page array and filtering on distance to convert Kurt's Fireball example or to generalize it. !script {{ --#title|Loop through Selected Toks Example --~ids|getselected --=i|0 --:Loop| --=i|[$i] +1 --+Token [$i]|[&ids[$i.Raw]] --?[$i] -lt [$idsCount]|Loop }} The second way is to use one of the newer array functions (getselected is bolded below). This is also described in the wiki. Function Name Sub Function Parameters Return Type Description array define arrayname;value1;value2;... none Creates an array called "arrayname" and adds value1, value2, etc. to the array array sort arrayname none Sorts the specified array in place in ascending order array add arrayname;value1;value2;... none Adds value1, value2, ... to the existing array "arrayname" array remove arrayname;value1;value2;... none Removes value1, value2, ... from the existing array "arrayname". Resets the array index to 0. array replace arrayname;currentvalue;newvalue none Replaces all occurrences of "currentvalue" in "arayname" with "newvalue" array getindex arrayname stringVariable Retrieves the current index in "arrayname" and stores it in the supplied string variable array setindex arrayname;newindex none Sets the current index in array "arrayname" to "newindex" array getcurrent arrayname stringVariable Gets the item at the current array index in "arrayname" and returns it as a string variable. Will return "ArrayError" if there is no current item. array getnext arrayname stringVariable Increments the current index in "arrayname" and returns the new current value. Will return "ArrayError" if the end of the array is reached. array getprevious arrayname stringVariable Decrements the current index in "arrayname" and returns the new current value. Will return "ArrayError" if the the current index was already zero. array getfirst arrayname stringVariable Set the current index of "arrayname" to zero and retrieve the current item. Will return "ArrayError" if there is no current item. array getlast arrayname stringVariable Set the current index of "arrayname" to the last item in the array and retrieve the current item. Will return "ArrayError" if there is no current item. array removeat arrayname;indexposition none Removes the item at index "indexposition" from "arrayname". Resets the current array index to 0. array indexof arrayname;searchvalue stringVariable Searches the array "arrayname" for and item with the value of "searchvalue" and, if found, returns the index of the first matching value or "ArrayError" if not found array getlength arrayname stringVariable Returns the number of items in array "arrayname" array pagetokens arrayname;tokenid;(optional filter) stringVariable Creates an array (arrayname) of all of the token ids (technically Graphics objects) on the same page as the specified token id. Returns the number of tokens found to the stringVariable. Available optional filters are : all, char, graphic, pc, npc. The filters will return only those tokens that match that criteria (char means tokens have a "represents", graphic doesn't. pc indicates a represents token has a controlledby, npc doesn't.) array selectedtokens arrayname stringVariable Creates an array (arrayname) of all of the token ids (technically Graphics objects) selected when the script was executed. Returns the number of tokens found to the stringVariable. array stringify arrayname stringVariable Returns all of the items in "arrayname" as a string separated by semicolons (;) array fromstring arrayname delimiter;string Creates an array from "string", splitting "string" on "delimiter" to separate the items array statusmarkers arrayname;tokenid none Creates an array (arrayname) of the active statusmarkers (sometimes called Token Markers) for the specified tokenid
tagging this so that i can play with it later.
1630381753

Edited 1630382741
Victor B.
Pro
Sheet Author
API Scripter
No, the reality is you won't find this for what you want.  You can create a specific macro for every spell, but that will get tedious based on number of spells.  Also you need to have strong programming skills to create a turn undead macro and convert to every other spell in 5e which is insane.   There's no way around rolling.  Group check is close, great API but doesn't tell you the actual token that succeeded and failed.  Give a simple list.  Apply damage, which is an unpublished (to my knowledge) add on is a great way to auto apply damage using Group Check.  The combo is awesome. Limitations.  If you roll advantage, has to be done outside of the API, etc., but still great.  You need an ability to select tokens and apply a condition that has a duration AFTER you've rolled the saves.  Track that condition and duration through the combat.  Remove that condition if after the duration.  Show to the GM that a concentration check is needed if damage is taken.  That's combat master.  Honestly nothing else comes close.  
Hi,  With Michael's help, I've been able to correct some mistakes I made.  I actually corrected all the $ and & mistakes and it seems to work pretty well now.  !script {{ --/|Demande quel JP, quel DD, quels degats, quel effet sauvegarde, quel type dégats --&saveType|?{Quel JP?|Dexterité,dex|Constitution,con|Sagesse,wis} --=DC|?{DD ?|15} --=Damage|?{Dégats} --&DCeffect|?{Effet Sauvegarde ?|Annule,annule|Demi dégats,demi} --&damageType|?{Quel type de Dégats ?|Acide,acid|Contondant,bludgeoning|Feu,fire|Force,force|Foudre,lightning|Froid,cold|Nécrotique,necrotic|Perforant,piercing|Poison,poison|Psychique,psychic|Radiant,radiant|Tonnerre,thunder|Tranchant,slashing} --/|Get all of the tokens on the page so we can cache their positions --~|array;pagetokens;alltokens;@{selected|token_id} --#leftsub|DD [$DC] --#rightsub|Dégats: [$Damage] --#title|JP de Groupe --#titleCardBackground|#03038a --#oddRowBackground|#d8d8e6 --#evenRowBackground|#FFFFFF --#whisper|gm --/|Calculate damage --=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 with the selected token --~tokenid|array;selectedtokens;Selected --/|The first item in the array will be a blank dummy item, so remove it. --~|array;removeat;selected;0 --/|Loop through the tokensHit tokens and roll saves for each one and apply damage --~tokenid|array;getfirst;Selected --?[&tokenid] -eq ArrayError|endOutput --:loopDisplay| --=SaveRoll|1d20 + [*[&tokenid]:npc_[&saveType]_save] --/|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 [$DC]|>ApplyDamageTokenmod;[&tokenid];1;-[$Damage.Total]|>ApplyDamageTokenmod;[&tokenid];1;-[$HalfDamage.Total] --?[$SaveRoll.Total] -ge [$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]:|n'est pas affecté par le sort ! --^afterSave| --:Resistant| --?[$SaveRoll.Total] -lt [$DC]|>ApplyDamageTokenmod;[&tokenid];1;-[$HalfDamage.Total]|>ApplyDamageTokenmod;[&tokenid];1;-[$QuarterDamage.Total] --?[$SaveRoll.Total] -lt [$DC]|madeSave --+[*[&tokenid]:t-name]:|Save [$SaveRoll] [r][$QuarterDamage] [&damageType][/r] --^afterSave| --:Vulnerable| --?[$SaveRoll.Total] -lt [$DC]|>ApplyDamageTokenmod;[&tokenid];1;-[$DoubleDamage.Total]|>ApplyDamageTokenmod;[&tokenid];1;-[$Damage.Total] --?[$SaveRoll.Total] -ge [$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;Selected --?[&tokenid] -ne ArrayError|loopDisplay --:endOutput| --X| --:ApplyDamageTokenmod|Parameters are tokenid;bar#;amount --@token-mod|_ignore-selected _ids [%1%] _set bar[%2%]_value|[%3%] --<| }} Now i have 2-3 last issues in what i try to achieve. First  : For DCeffect, when i choose "annule" i'd like to have the script jump to the immune save test part. For example, some cantrips can affect several creatures, but there are no effect if they make the save. I should put a conditional : maybe something like --?"[*[&DCeffect]] -inc "annule" -and [$SaveRoll.Total] -ge [$DC]|Immune Would that be correct ? And should i put this in the list of rolls comparisons ? or somewhere else ? Second  : I'd like to put a button so the damages are rolled only if i press this button, and not automatically as it is for the moment. How to write this button command ?and do i have to put it instead of every >applydamagetokenmod commands ? or only once just before the tokenmod command ? Third (but that's just a little cherry on the big cake) :  I have a little tokenmod macro that puts the deadmarker and switch the token to the maplayer when one of my monsters dies (that is helpful when i have a lot of monsters, because it puts them "toback" and prevents me to select them by mistake. How easy would it be to say that : --?"[*[&tokenid]:bar1] -lt 1|>applytokenmarkerandmoveitonmaplayer Would that work ? There's no "or else" in that line...don't know if it needs one or not, and i think i should probably put some parameters in that subroutine call Where would that subroutine be placed in the script ? Would the script remember whose token we're talking about ? It seems pretty easy but maybe it's not that easy at all.... Thanks for your help.