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

another quick question...are the attributes sheet specific? I use the shaped sheet and looking at the example "magic missile", --=SlotsTotal|[*S:lvl[$SlotLevel]_slots_total] looks specific to a particular sheet? is that true? thanks again.
David M. - Sorry, should have been clearer.  Actually, it wasn't branching even though the condition was present in both.  Here is the card: !scriptcard  {{   --#title|Peim Weapon Attack   --#sourceToken|@{selected|token_id}   --#targetToken|@{target|token_id}   --#emoteText|[*S:character_name] attacks [*T:character_name]   --#titleCardFont|#ffff00   --#titleCardBackground|#000000   --#evenRowBackground|#ff0000   --#evenRowFontColor|#ffffff   --#oddRowBackground|#006400   --#oddRowFontColor|#ffff00   --#debug|1   --:Attack|     --=TargetAC|@{target|npc_ac}     --?[$TargetAC.Total] -gt 0|DoneWithAC     --=TargetAC|@{target|ac}     --:DoneWithAC|   --:Set Weapon Info|     --=WeaponStats|?{Weapon?|Mace,0|Light Crossbow,1}     --?[$WeaponStats] -eq 0|>SetWeapon;Mace;1d6;bludgeoning;@{selected|strength_mod}     --?[$WeaponStats] -eq 1|>SetWeapon;Light Crossbow;1d8;piercing;@{selected|dexterity_mod}   --:Roll Attack|     --&RollType|?{Advantage or Disadvantage?|Normal,1d20|Advantage,2d20kh1|Disadvantage,2d20kl1}     --=AttackRoll|[&RollType] [BASE] + [$[&Attribute]] [MOD] + @{selected|pb} [PROF] + @{selected|global_attack_mod} [GLOBE]     --+Attack|@{selected|character_name} rolls [$AttackRoll] vs AC [$TargetAC].   --:Determine results|   --?[$AttackRoll.Base] -eq 1|Fumble   --?[$AttackRoll.Total] -lt [$TargetAC.Total]|Miss   --?[$AttackRoll.Base] -eq 20|>Crit;[&WeaponDmg]   --?[$AttackRoll.Total] -ge [$TargetAC.Total] -and [*T:npc_resistances] -inc [&DamageType]|>DamageResist;[&WeaponDmg]   --?[$AttackRoll.Total] -ge [$TargetAC.Total] -and [*T:npc_vulnerabilities] -inc [&DamageType]|>DamageVuln;[&WeaponDmg]   --?[*T:npc_immunities] -inc [&DamageType]|>AttackFails   --?[$AttackRoll.Total] -ge [$TargetAC.Total]|>Hit;[&WeaponDmg]     --:EndMacro|     --X|     --:|AttackFails     --+|[*T:character_name] is Immune to this Type of Damage - the Attack Fails!   --X|   --:PROCEDURES:|   --:SetWeapon| pass weapon, dmg, dmg_type       --&WeaponName|[%1%]       --&WeaponDmg|[%2%]       --&DamageType|[%3%]       --&Attribute|[%4%]   --<|     --:Fumble|       --+Fumble!|The attack went horribly wrong.   --X|     --:Miss|       --+Miss!|The attack missed.   --X|     --:Hit| pass WeaponDmg string     --=Damage| [%1%] [BASE] + [$[&Attribute]] [MOD] + @{selected|global_damage_mod_roll} [GLOBE]     --+Hit!|[*S:character_name] hits [*T:character_name] with a [&WeaponName] for [$Damage] [&DamageType] damage.     --+|[*T:character_name] is immune to [*T:npc_immunities] and Resistant to [*T:npc_resistances].       --@alter|_target|@{target|token_id} _bar|1 _amount|-[$Damage]   --^EndMacro|     --:Crit| pass WeaponDmg string     --=Damage|@{selected|global_damage_mod_roll} [GLOBE] * 2 + [%1%] [BASE] + [%1%] [EX DIE] + [$[&Attribute]] [MOD]     --+Critical Hit!|[*S:character_name] hits [*T:character_name] with a [&WeaponName] for [$Damage] [&DamageType] damage.     --@alter|_target|@{target|token_id} _bar|1 _amount|-[$Damage]   --^EndMacro|     --:|DamageResist     --=WeaponDmg|[$WeaponDmg] \ 2     --+|[*T:character_name] is resistant!   --^Hit|[$WeaponDmg]     --:|DamageVuln     --=WeaponDmg|[$WeaponDmg] * 2     --+|[*T:character_name] Is vulnerable!   --^Hit|[$WeaponDmg]   }} (Line in italic/bold was error checking only and not part of card.)  Hope  this isn't another of my silly syntax errors.  :-(
@Kurt - Is there an updated WIKI for your latest (or close to latest) dev version.  The last one I see is from January of this year.  You've added so much functionality to this tool.  I find myself scouring this forum looking for updated syntax on features and re-learning things you'd added previously.  I'm guessing you don't have a technical writer at your beck and call.  
1620837714
Senjak
Pro
Sheet Author
Here is a simple example I wrote to help me convert 7th edition character stats to Delta Green stats. There are lots and lots of complex examples, but sadly this is the level of example that is the most useful for me right now. !scriptcards {{ --#titlefontlineheight|1.5em --#lineheight|1.2em --#buttonbackground|#C9DAF8 --#titleCardBackground|#000000 --#buttontextcolor|#000000 --#buttonbordercolor|#000000 --#titlefontsize|24px --#subtitlefontsize|24px --#bodyfontsize|24px --#buttonfontsize|24px --#title|DG Stat Conversion --=Base_Str|?{CoC Str|50} --=Base_Con|?{CoC Con|50} --=Base_Size|?{CoC Size|50} --=Base_Dex|?{CoC Dex|50} --=Base_App|?{CoC Appearance|50} --=Base_Edu|?{CoC Edu|50} --=Base_Int|?{CoC Int|50} --=Base_Pow|?{CoC Pow|50} --=Modifier|5 --=Str| [$Base_Str] / [$Modifier] --=Size| [$Base_Size] / [$Modifier] --=Con| [$Base_Con] / [$Modifier] --=Dex| [$Base_Dex] / [$Modifier] --=App| [$Base_App] / [$Modifier] --=Int| [$Base_Int] / [$Modifier] --=Edu| [$Base_Edu] / [$Modifier] --=Pow| [$Base_Pow] / [$Modifier] --=DG_Str| [$Str] + [$Size] / 2 --=DG_Int| [$Int] + [$Edu] / 2 --=DG_Con| [$Con] + [$Size] / 2 --+DG STR:|[$DG_Str] --+DG CON:|[$DG_Con] --+DG DEX:|[$Dex] --+DG INT:|[$DG_Int] --+DG POW:|[$Pow] --+DG CHA:|[$App] }} Senjak
Will M. said: @Kurt - Is there an updated WIKI for your latest (or close to latest) dev version.  The last one I see is from January of this year.  You've added so much functionality to this tool.  I find myself scouring this forum looking for updated syntax on features and re-learning things you'd added previously.  I'm guessing you don't have a technical writer at your beck and call.   Seconding this request. The Wiki is fairly out of date due to all the wonderful functionality Kurt has added. Would be great to see the Wiki updated.
1620840554

Edited 1620840657
Kurt J.
Pro
API Scripter
Will M. said: @Kurt - Is there an updated WIKI for your latest (or close to latest) dev version.  The last one I see is from January of this year.  You've added so much functionality to this tool.  I find myself scouring this forum looking for updated syntax on features and re-learning things you'd added previously.  I'm guessing you don't have a technical writer at your beck and call.   I generally do keep the Wiki updated (I never noticed that there was a "last updated" at the top - I've definitely updated in in the last week or so, so that date doesn't appear to be generated automatically). Everything up to the most recent OneClick version (1.1.19) is updated on the Wiki, and every few releases of development builds I add Wiki items and flag them when the version number if it is later than the current OneClick. I haven't yet done that for 1.2.1 or later yet, but I'll probably bring the Wiki up to 1.2.3 state this evening. I'd live to do a full rewrite on the Wiki article, as it can be a bit rambling right now since it has grown over time with the script, but that is a fairly daunting task :)
1620841011
Kurt J.
Pro
API Scripter
Jay R. said: I'm using an old version of Scriptcards (1.0.9) but I do want to update to the latest. Will the cleanup and new features break the scriptcards I have? What should I be troubleshooting when I make the move? I try to avoid breaking changes wherever possible. The biggest ones that were fairly unavoidable in the 1.2.x series are: If you pass subroutine parameters including double or single quotes, you need to enclose that parameter in the OTHER type of quote, so if you want to pass They're as a parameter, you need to us "The're". I'm contemplating a better solution, but that is what I have for now. If you have branch labels (--:) with names that start with ">", "=", or "&", the new conditional logic that allows non-branching execution will be problematic. However, I would see this as VERY uncommon.
1620841058
Kurt J.
Pro
API Scripter
joeuser said: another quick question...are the attributes sheet specific? I use the shaped sheet and looking at the example "magic missile", --=SlotsTotal|[*S:lvl[$SlotLevel]_slots_total] looks specific to a particular sheet? is that true? thanks again. While ScriptCards itself is not system or sheet specific, by necessity the example scripts will be since each game/sheet calls the attributes different things.
1620841197
Kraynic
Pro
Sheet Author
Kurt J. said: I generally do keep the Wiki updated (I never noticed that there was a "last updated" at the top - I've definitely updated in in the last week or so, so that date doesn't appear to be generated automatically). That "last updated" must only apply to certain parts of the wiki, since it doesn't exist for the 3 character sheet articles I created.  On the sheet article pages, you have to click on the History tab to see the edits.  Doing so on your script article shows a lot of edits on the 9th, so the History tab is tracking the edits correctly.  Apparently the history isn't what is communicating with "last updated", or maybe that is only triggered with an edit to the first part of the page/article?
1620841219
Kurt J.
Pro
API Scripter
Michael C. said:   --?[$AttackRoll.Total] -ge [$TargetAC.Total] -and [*T:npc_resistances] -inc [&DamageType]|>DamageResist;[&WeaponDmg]   --?[$AttackRoll.Total] -ge [$TargetAC.Total] -and [*T:npc_vulnerabilities] -inc [&DamageType]|>DamageVuln;[&WeaponDmg]   --?[*T:npc_immunities] -inc [&DamageType]|>AttackFails You should probably be seeing a console error about an invalid connector for a conditional. In general, the references to npc_immunities, npc_vulnerabilities, and npc_resistances often contains spaces, so they need to be surrounded by quotes:   --?[$AttackRoll.Total] -ge [$TargetAC.Total] -and "[*T:npc_resistances]" -inc [&DamageType]|>DamageResist;[&WeaponDmg]   --?[$AttackRoll.Total] -ge [$TargetAC.Total] -and "[*T:npc_vulnerabilities]" -inc [&DamageType]|>DamageVuln;[&WeaponDmg]   --?"[*T:npc_immunities]" -inc [&DamageType]|>AttackFails
1620841320
Kurt J.
Pro
API Scripter
Kraynic said: Kurt J. said: I generally do keep the Wiki updated (I never noticed that there was a "last updated" at the top - I've definitely updated in in the last week or so, so that date doesn't appear to be generated automatically). That "last updated" must only apply to certain parts of the wiki, since it doesn't exist for the 3 character sheet articles I created.  On the sheet article pages, you have to click on the History tab to see the edits.  Doing so on your script article shows a lot of edits on the 9th, so the History tab is tracking the edits correctly.  Apparently the history isn't what is communicating with "last updated", or maybe that is only triggered with an edit to the first part of the page/article? Even better, it looks like it is a manual setting that has to be updated by editing the whole page with the edit button :) The version number is in there too, which is also the first version released to OneClick.
Kurt J. - I had tried that before but here are the chat outputs for your changes: &nbsp; --?[$AttackRoll.Total] -ge [$TargetAC.Total] -and "[*T:npc_resistances]" -inc [&amp;DamageType]|&gt;DamageResist;[&amp;WeaponDmg] &nbsp; --?[$AttackRoll.Total] -ge [$TargetAC.Total] -and "[*T:npc_vulnerabilities]" -inc [&amp;DamageType]|&gt;DamageVuln;[&amp;WeaponDmg] &nbsp; --?"[*T:npc_immunities]" -inc [&amp;DamageType]|&gt;AttackFails Peim attacks Cadaver Collector Peim Weapon Attack Attack &nbsp;Peim rolls&nbsp;<span class="userscript-showtip userscript-tipsy" title="Roll: 2d20kh1 [BASE] + [$0] [MOD] + 3 [PROF] + 3 [GLOBE] Result: 2d20kh1 (18,10) [BASE] + 0 [MOD] + 3 [PROF] + 3 [GLOBE] " style="box-sizing: content-box; min-width: 1.75em; font-family: undefined; text-align: center; display: inline-block; font-weight: bold; height: 1em; margin-top: -1px; margin-bottom: 1px; padding: 0px 2px; border: 1px solid rgb(135, 133, 10); border-radius: 3px; background-color: rgb(255, 254, 162); color: rgb(0, 0, 0);">24 &nbsp;vs AC&nbsp;<span class="userscript-showtip userscript-tipsy" title="Roll: 17 Result: 17 " style="box-sizing: content-box; min-width: 1.75em; font-family: undefined; text-align: center; display: inline-block; font-weight: bold; height: 1em; margin-top: -1px; margin-bottom: 1px; padding: 0px 2px; border: 1px solid rgb(135, 133, 10); border-radius: 3px; background-color: rgb(255, 254, 162); color: rgb(0, 0, 0);">17 . Hit! &nbsp;Peim hits Cadaver Collector with a Mace for&nbsp;<span class="userscript-showtip userscript-tipsy" original-title="Roll: 1d6 [BASE] + [$0] [MOD] + 0 [GLOBE] Result: 1d6 (1) [BASE] + 0 [MOD] + 0 [GLOBE] " style="box-sizing: content-box; min-width: 1.75em; font-family: undefined; text-align: center; display: inline-block; font-weight: bold; height: 1em; margin-top: -1px; margin-bottom: 1px; padding: 0px 2px; border: 1px solid rgb(102, 0, 0); border-radius: 3px; background-color: rgb(255, 170, 170); color: rgb(102, 0, 0);">1 &nbsp;bludgeoning damage. Cadaver Collector is immune to Necrotic, poison, psychic; bludgeoning, piercing, and slashing from nonmagical attacks that aren’t adamantine and Resistant to undefined. Peim attacks Baphomet Peim Weapon Attack Attack &nbsp;Peim rolls&nbsp;<span class="userscript-showtip userscript-tipsy" title="Roll: 2d20kh1 [BASE] + [$0] [MOD] + 3 [PROF] + 1 [GLOBE] + 10 Result: 2d20kh1 (15,12) [BASE] + 0 [MOD] + 3 [PROF] + 1 [GLOBE] + 10 " style="box-sizing: content-box; min-width: 1.75em; font-family: undefined; text-align: center; display: inline-block; font-weight: bold; height: 1em; margin-top: -1px; margin-bottom: 1px; padding: 0px 2px; border: 1px solid rgb(135, 133, 10); border-radius: 3px; background-color: rgb(255, 254, 162); color: rgb(0, 0, 0);">29 &nbsp;vs AC&nbsp;<span class="userscript-showtip userscript-tipsy" title="Roll: 22 Result: 22 " style="box-sizing: content-box; min-width: 1.75em; font-family: undefined; text-align: center; display: inline-block; font-weight: bold; height: 1em; margin-top: -1px; margin-bottom: 1px; padding: 0px 2px; border: 1px solid rgb(135, 133, 10); border-radius: 3px; background-color: rgb(255, 254, 162); color: rgb(0, 0, 0);">22 . Hit! &nbsp;Peim hits Baphomet with a Mace for&nbsp;<span class="userscript-showtip userscript-tipsy" original-title="Roll: 1d6 [BASE] + [$0] [MOD] + 0 [GLOBE] Result: 1d6 (3) [BASE] + 0 [MOD] + 0 [GLOBE] " style="box-sizing: content-box; min-width: 1.75em; outline: none; font-family: undefined; text-align: center; display: inline-block; font-weight: bold; height: 1em; margin-top: -1px; margin-bottom: 1px; padding: 0px 2px; border: 1px solid rgb(135, 133, 10); border-radius: 3px; background-color: rgb(255, 254, 162); color: rgb(0, 0, 0);">3 &nbsp;bludgeoning damage. Baphomet is immune to Poison; bludgeoning, piercing and slashing that is nonmagical and Resistant to Cold, fire, lightning. (Undefined is because that creature has no resistances).&nbsp; As you can see, both&nbsp; "[*T:npc_resistances]" &nbsp;and " [*T:npc_immunities]" &nbsp;fail to recognize the -inc comparison to [&amp;DamageType] also.&nbsp; Sign me, confabulated.
Is anyone using the Shaped Sheet? I'm trying to get the sample magic missile script working and I cannot get the spell slot count by total or level. I am using "spell_slots_lLEVEL"&nbsp; (sub'ing the LEVEL) as documented in the sheet attr doc but it doesn't appear to work.
1620855996
Kurt J.
Pro
API Scripter
Michael C. said: Kurt J. - I had tried that before but here are the chat outputs for your changes: &nbsp; --?[$AttackRoll.Total] -ge [$TargetAC.Total] -and "[*T:npc_resistances]" -inc [&amp;DamageType]|&gt;DamageResist;[&amp;WeaponDmg] &nbsp; --?[$AttackRoll.Total] -ge [$TargetAC.Total] -and "[*T:npc_vulnerabilities]" -inc [&amp;DamageType]|&gt;DamageVuln;[&amp;WeaponDmg] &nbsp; --?"[*T:npc_immunities]" -inc [&amp;DamageType]|&gt;AttackFails Peim attacks Cadaver Collector Peim Weapon Attack Attack &nbsp;Peim rolls&nbsp;<span class="userscript-userscript-showtip userscript-tipsy" title="Roll: 2d20kh1 [BASE] + [$0] [MOD] + 3 [PROF] + 3 [GLOBE] Result: 2d20kh1 (18,10) [BASE] + 0 [MOD] + 3 [PROF] + 3 [GLOBE] " style="min-width: 1.75em ; font-family: &quot;undefined&quot; ; text-align: center ; display: inline-block ; font-weight: bold ; height: 1em ; margin-top: -1px ; margin-bottom: 1px ; padding: 0px 2px ; border: 1px solid rgb( 135 , 133 , 10 ) ; border-radius: 3px ; background-color: rgb( 255 , 254 , 162 ) ; color: rgb( 0 , 0 , 0 )">24 &nbsp;vs AC&nbsp;<span class="userscript-userscript-showtip userscript-tipsy" title="Roll: 17 Result: 17 " style="min-width: 1.75em ; font-family: &quot;undefined&quot; ; text-align: center ; display: inline-block ; font-weight: bold ; height: 1em ; margin-top: -1px ; margin-bottom: 1px ; padding: 0px 2px ; border: 1px solid rgb( 135 , 133 , 10 ) ; border-radius: 3px ; background-color: rgb( 255 , 254 , 162 ) ; color: rgb( 0 , 0 , 0 )">17 . Hit! &nbsp;Peim hits Cadaver Collector with a Mace for&nbsp; 1 &nbsp;bludgeoning damage. Cadaver Collector is immune to Necrotic, poison, psychic; bludgeoning, piercing, and slashing from nonmagical attacks that aren’t adamantine and Resistant to undefined. Peim attacks Baphomet Peim Weapon Attack Attack &nbsp;Peim rolls&nbsp;<span class="userscript-userscript-showtip userscript-tipsy" title="Roll: 2d20kh1 [BASE] + [$0] [MOD] + 3 [PROF] + 1 [GLOBE] + 10 Result: 2d20kh1 (15,12) [BASE] + 0 [MOD] + 3 [PROF] + 1 [GLOBE] + 10 " style="min-width: 1.75em ; font-family: &quot;undefined&quot; ; text-align: center ; display: inline-block ; font-weight: bold ; height: 1em ; margin-top: -1px ; margin-bottom: 1px ; padding: 0px 2px ; border: 1px solid rgb( 135 , 133 , 10 ) ; border-radius: 3px ; background-color: rgb( 255 , 254 , 162 ) ; color: rgb( 0 , 0 , 0 )">29 &nbsp;vs AC&nbsp;<span class="userscript-userscript-showtip userscript-tipsy" title="Roll: 22 Result: 22 " style="min-width: 1.75em ; font-family: &quot;undefined&quot; ; text-align: center ; display: inline-block ; font-weight: bold ; height: 1em ; margin-top: -1px ; margin-bottom: 1px ; padding: 0px 2px ; border: 1px solid rgb( 135 , 133 , 10 ) ; border-radius: 3px ; background-color: rgb( 255 , 254 , 162 ) ; color: rgb( 0 , 0 , 0 )">22 . Hit! &nbsp;Peim hits Baphomet with a Mace for&nbsp; 3 &nbsp;bludgeoning damage. Baphomet is immune to Poison; bludgeoning, piercing and slashing that is nonmagical and Resistant to Cold, fire, lightning. (Undefined is because that creature has no resistances).&nbsp; As you can see, both&nbsp; "[*T:npc_resistances]" &nbsp;and " [*T:npc_immunities]" &nbsp;fail to recognize the -inc comparison to [&amp;DamageType] also.&nbsp; Sign me, confabulated. &nbsp;I played around with the card a bit, and I found the issue. These three lines are the issue: --:|AttackFails --:|DamageResist --:|DamageVuln These label statements each have the | in the wrong location. They should be --:AttackFails|, --:DamageResist| and --:DamageVuln| (there was a warning being thrown in the log that the labels were not found, because with the | in front the labels were essentially blanks.
1620856415
Kurt J.
Pro
API Scripter
joeuser said: Is anyone using the Shaped Sheet? I'm trying to get the sample magic missile script working and I cannot get the spell slot count by total or level. I am using "spell_slots_lLEVEL"&nbsp; (sub'ing the LEVEL) as documented in the sheet attr doc but it doesn't appear to work. I've never used the shaped sheet, but looking at the HTML here , it looks like the slot levels (for non-warlocks) are in the form "spell_level_1_slots" and "spell_level_1_slots_expended", etc.
Kurt J.&nbsp; Arrrggh. I was afraid of that.&nbsp; My bad - sorry!
Could someone help me figure out how to scale damage based on the level of the character?&nbsp; In Starfinder, Operatives can do Trick Attacks.&nbsp; The damage scales based on level; 1d4 at level 1, 1d8 at level 3, 3d8 at level 5, and 1d8 each 2 levels thereafter.&nbsp; How would I write that so I would have to update every time my players level?
1620861263

Edited 1620862360
Kurt J.
Pro
API Scripter
Brien V. said: Could someone help me figure out how to scale damage based on the level of the character?&nbsp; In Starfinder, Operatives can do Trick Attacks.&nbsp; The damage scales based on level; 1d4 at level 1, 1d8 at level 3, 3d8 at level 5, and 1d8 each 2 levels thereafter.&nbsp; How would I write that so I would have to update every time my players level? You could do something like this. Replace the roll query for the level (?{Level|} with an @{selected|} reference to the characters level for your sheet): !script {{ --&amp;CharLevel|?{Level|} --&amp;DamageDice|1d4 --?[&amp;CharLevel] -ge 3|&amp;DamageDice;1d8 --?[&amp;CharLevel] -ge 5|&amp;DamageDice;3d8 --?[&amp;CharLevel] -le 6|DoneDamage --=Mult|[&amp;CharLevel] - 7 \ 2 + 4 --&amp;DamageDice|[$Mult.Total]d8 --:DoneDamage| --=Damage|[&amp;DamageDice] --+Damage|[$Damage] }} I should note that this is using the conditional assignment features in 1.2.x
1620863757
David M.
Pro
API Scripter
Kurt J. said: joeuser said: Is anyone using the Shaped Sheet? I'm trying to get the sample magic missile script working and I cannot get the spell slot count by total or level. I am using "spell_slots_lLEVEL"&nbsp; (sub'ing the LEVEL) as documented in the sheet attr doc but it doesn't appear to work. I've never used the shaped sheet, but looking at the HTML here , it looks like the slot levels (for non-warlocks) are in the form "spell_level_1_slots" and "spell_level_1_slots_expended", etc. @joeuser: I don't use shaped either, but I made a quick test game and this syntax seemed to work within the naming conventions of the MM script example. Note the calculated value for SlotsExpended based on SlotsTotal and SlotsRemaining. !scriptcard {{ --#title|Magic Missile --#sourceToken|@{selected|token_id} --=SlotLevel|?{Spell Slot Level?|1|2|3|4|5|6|7|8|9} --=SlotsTotal|[*S:spell_level_[$SlotLevel.Total]_slots] --=SlotsRemaining|[*S:spell_level_[$SlotLevel.Total]_slots_remaining] --=SlotsExpended|[$SlotsTotal]-[$SlotsRemaining] --+SlotsTotal|[$SlotsTotal] --+SlotsExpended|[$SlotsExpended] --+SlotsRemaining|[$SlotsRemaining] }}
Ok I don't know where to start on this one I want to make a scriptcard to pull the Passive Perception for all the characters on the page. Any ideas?
1620906007

Edited 1620906988
David M.
Pro
API Scripter
@Craven, something like this? Uses passive_wisdom from the 5e by Roll20 sheet. Select any token on the page before running it. EDIT - edited to display as a roll variable !script {{ --#title|Global Passive Perception --:(1) GET ALL TOKENS INTO THE "allTokens" ARRAY| will have blank 1st element to be removed later --~|array;pagetokens;allTokens;@{selected|token_id} --:(2) PREP ARRAY FOR LOOP| if no array elements then end macro --~tokenid|array;getfirst;allTokens --?[&amp;tokenid] -eq ArrayError|End --:(3) GRAB PASSIVE PERCEPTION FROM EACH TOKEN| --:PPLoop| --:TOKEN MUST BE ON OBJECTS OR GMLAYER AND HAVE A NON_BLANK PASSIVE_WISDOM| --?[*[&amp;tokenid]:t-layer] -ne objects -and [*[&amp;tokenid]:t-layer] -ne gmlayer|NextToken --?[*[&amp;tokenid]:passive_wisdom] -ne ""|&gt;DisplayPP --:NextToken| --~tokenid|array;getnext;allTokens --?[&amp;tokenid] -ne ArrayError|PPLoop --:End| --X| --:DisplayPP| --=PP|[*[&amp;tokenid]:passive_wisdom] ​--+[*[&amp;tokenid]:character_name]|[$PP] --&lt;| }}
Hi, all. Can someone tell me why this doesn't work !scriptcard&nbsp; {{ --=PB|2 --&amp;WeaponName|Longsword &nbsp; &nbsp; &nbsp; &nbsp; --&amp;WeaponsAllowed|Hand Crossbow,Longsword,Rapier,Shortsword tried this way : --?[&amp;WeaponsAllowed] -inc [&amp;WeaponName]|EndClass_Rogue tried this way : --?[&amp;WeaponName] -inc [&amp;WeaponsAllowed]|EndClass_Rogue --=PB|0 --:EndClass_Rogue| --+|PB: [$PB] }} Either way I check includes, [$PB] winds up zero Thanks ahead of time.
1620910238
David M.
Pro
API Scripter
@Roscoe, since the string contains spaces, try wrapping the comparison strings in quotes, e.g. !scriptcard {{ --=PB|2 --&amp;WeaponName|Hand Crossbow --&amp;WeaponsAllowed|Hand Crossbow,Longsword,Rapier,Shortsword --?"[&amp;WeaponsAllowed]" -inc "[&amp;WeaponName]"|EndClass_Rogue --=PB|0 --:EndClass_Rogue| --+|PB: [$PB] }}
Ok, I need a fresh pair of eyes here.&nbsp; I have a snippet that seems to be repeating itself with a return from a gosub to a weird place.&nbsp; So it starts when a PC hits with an attack (PF2). In the Hit logic, there is a conditional to see if there is additional damage with the strike (Flaming, Holy, Frost, etc.).&nbsp; --?"[*R:damage_additional]" -inc d|&gt;FormatAddDamage;1|&gt;NoAdditionalDamage Then I am getting the damage in the field that looks like: 1d6 [Persistent Bleed]+1d6 [Fire]+1d6 [Good] Here is the code for formatting the damage output as well as library procedures processing immunities, resistances, and weaknesses:&nbsp; &nbsp; --:FormatAddDamage| --=Multiplier|[%1%] --~AddDamage|string;split;+;[*R:damage_additional] --=i|0 --=AddDamage|0 &nbsp; --:StartFormatLoop| &nbsp; --=i|[$i] + 1 &nbsp; --=DamageAddValue[$i.Total]|[&amp;AddDamage[$i.Total]] * [$Multiplier] &nbsp; --~DamageAdd[$i.Total]|string;replace;[;;[&amp;AddDamage[$i.Total]] &nbsp; --~DamageAdd[$i.Total]|string;replace;];;[&amp;DamageAdd[$i.Total]] &nbsp; --~DamageAddType[$i.Total]|string;after; ;[&amp;DamageAdd[$i.Total]] &nbsp; --~DamageAddType[$i.Total]|string;tolowercase;[&amp;DamageAddType[$i.Total]] &nbsp; --&gt;CheckWeaknesses|[*T:weaknesses];[&amp;DamageAddType[$i.Total]];DamageAddValue[$i.Total];[$DamageAddValue[$i.Total]] &nbsp; --&gt;CheckResistances|[*T:resistances];[&amp;DamageAddType[$i.Total]];DamageAddValue[$i.Total];[$DamageAddValue[$i.Total]] &nbsp; --&gt;CheckImmunities|DamageAddValue[$i.Total];[&amp;DamageAddType[$i.Total]];[*T:immunities] &nbsp; --?[$DamageAddValue[$i.Total]] -le 0|&gt;StartFormatLoop &nbsp; --&amp;DamageAddOutput|+ and [$DamageAddValue[$i.Total]] [b][&amp;DamageAddType[$i.Total]] damage[/b] &nbsp; --=AddDamage|[$AddDamage] + [$DamageAddValue[$i.Total]] &nbsp; --?[$i] -lt [$AddDamageCount]|&gt;StartFormatLoop &nbsp; --&lt;|Back to Hit Everything seems to work well until the last of the three damage types is processed and should go back to the Hit section. However, the output repeats itself in the Return in the last line. Here is the debug from the console. "Line Counter: 139, Tag:?20 -le 0, Content:&gt;StartFormatLoop" "Condition 20 -le 0 evaluation result: false" "Line Counter: 140, Tag:&amp;DamageAddOutput, Content:+ and [$DamageAddValue[$i.Total]] [b][&amp;DamageAddType[$i.Total]] damage[/b]" "Line Counter: 141, Tag:=AddDamage, Content:6 + 20" "Line Counter: 142, Tag:?3 -lt 3, Content:&gt;StartFormatLoop" "Condition 3 -lt 3 evaluation result: false" "Line Counter: 143, Tag:&lt;, Content:" "Line Counter: 140, Tag:&amp;DamageAddOutput, Content:+ and [$DamageAddValue[$i.Total]] [b][&amp;DamageAddType[$i.Total]] damage[/b]" "Line Counter: 141, Tag:=AddDamage, Content:26 + 20" "Line Counter: 142, Tag:?3 -lt 3, Content:&gt;StartFormatLoop" "Condition 3 -lt 3 evaluation result: false" "Line Counter: 143, Tag:&lt;, Content:" "Line Counter: 64, Tag:=TotalDamage, Content:24+46" The first bolded return bounces back to the Damage Output again for some reason, goes through it again then returns properly. And for the life of me, I have been over this and cannot figure out why this is returning to a previous return point.&nbsp; Any help would stop my drinking. LOL
@David M: Right you were. As usual. Before I go, tell me: Is the reason for the quotes that sometimes [&amp;Variable] can be something other than a string? I gotta tell you guys, I'm loving this ScriptCards. The building hostilities and frustrations at not having a conditional available was moving me away from Roll20. Now I'm settled back in: fat, dumb and happy. Great work!
1620922669
timmaugh
Pro
API Scripter
@Rosco - everything that comes off a sheet will be a string as the API sees it. Typically the quotes are to keep the parser from breaking on (or wrongly parsing) spaces or internal special characters (like single quotes). If you want a conditional in other scripts than ScriptCards, APILogic is a meta-script that gives other scripts that ability. =D
1620924605
Kurt J.
Pro
API Scripter
Erik M. said: Ok, I need a fresh pair of eyes here.&nbsp; &nbsp; --?[$DamageAddValue[$i.Total]] -le 0|&gt;StartFormatLoop I'm guessing this should probably not be a gosub branch, but just a normal branch (ie, take out the &gt; in front of StartFormatLoop
Kurt J. said: Erik M. said: Ok, I need a fresh pair of eyes here.&nbsp; &nbsp; --?[$DamageAddValue[$i.Total]] -le 0|&gt;StartFormatLoop I'm guessing this should probably not be a gosub branch, but just a normal branch (ie, take out the &gt; in front of StartFormatLoop Who would've thought? This worked perfectly.&nbsp;
1620926936

Edited 1620927001
Quick question : How do we get the character id with the notation [*S:...] ? This is for library, and the documentation recommands not to use @{selected|...} syntax.
1620933865
David M.
Pro
API Scripter
Rosco James said: @David M: Right you were. As usual. Before I go, tell me: Is the reason for the quotes that sometimes [&amp;Variable] can be something other than a string? Tim explained it well, but all you really need to remember is: If you are trying to compare strings that could &nbsp;contains spaces or special non-letter characters, it's always safer to wrap them in quotes within your conditionals. &nbsp;
1620934355
Kurt J.
Pro
API Scripter
Lionel T. said: Quick question : How do we get the character id with the notation [*S:...] ? This is for library, and the documentation recommands not to use @{selected|...} syntax. You would need to set them in your script code before calling the library functions. Using the [*S:] notation in a library is fine, while using @{selected} will fail since library code isn't processed by the chat server.
You could do something like this. Replace the roll query for the level (?{Level|} with an @{selected|} reference to the characters level for your sheet): !script {{ --&amp;CharLevel|?{Level|} --&amp;DamageDice|1d4 --?[&amp;CharLevel] -ge 3|&amp;DamageDice;1d8 --?[&amp;CharLevel] -ge 5|&amp;DamageDice;3d8 --?[&amp;CharLevel] -le 6|DoneDamage --=Mult|[&amp;CharLevel] - 7 \ 2 + 4 --&amp;DamageDice|[$Mult.Total]d8 --:DoneDamage| --=Damage|[&amp;DamageDice] --+Damage|[$Damage] }} I should note that this is using the conditional assignment features in 1.2.x Awesome.&nbsp; Thank you for the input, I couldn't get my head around it.
1620973809

Edited 1620980385
@Kurt - on version 1.2.3, I'm getting "Undefined" when returning attributes with empty or 0 (zero) values.&nbsp; This functionality worked in version 1.2.2b, returning the same value I see in the character sheet.&nbsp; I've gone back and forth between version 1.2.3 and 1.2.2b and have been able to confirm that there may be a bug associated with 1.2.3.&nbsp; I'm using the Roll20 5E OGL sheets and testing against NPCs right now.&nbsp;&nbsp; [*[&amp;CharId]:npc_str_save_flag] returns "Undefined"&nbsp; whereas [*[&amp;CharId]:dexterity_mod] returns an appropriate value.&nbsp;&nbsp; I've perused the Character sheet, and it has appropriate values in the fields.&nbsp; I've also issued the chat command&nbsp;@{derro|npc_str_save_flag} and I get a good value of "0". As a Patreon supporter, I got a hold of your version 1.2.6 and confirmed the issue is still present there.&nbsp;&nbsp; BTW, I'm really looking forward to some of your new condition blocks and looping features.&nbsp;&nbsp; Update:&nbsp; I went ahead and looked at your code, comparing the changes between 1.2.2b and 1.2.3 and the issue may be on lines 2502 - 2503.&nbsp; I'm guessing the conditional&nbsp; (!attribute) &nbsp; above it is evaluating to true if&nbsp; attribute&nbsp; has a value of "0" or Null (which are legitimate), and then on the next line&nbsp;&nbsp; character.get(attrName) &nbsp;function bombs and returns "undefined".&nbsp; Commenting out line 2503 fixed my problem.&nbsp;&nbsp; if (character !== undefined &amp;&amp; (!attrName.toLowerCase().startsWith("t-"))) { attribute = getAttrByName(character.id, attrName, opType); if (!attribute) { ----&gt; attribute = character.get(attrName); // Not sure what's happening here but it appears that this line (2503 in v1.2.3) is suspect } if (attrName == "bio") { character.get("bio", function(bio) {attribute = bio} ) } //if (attrName == "bio") { // var getAsync = retrieveAsyncValue(character, "bio"); Going to bed now....It's been fun debugging this issue, but can't keep eyes open any longer.&nbsp;&nbsp;
1620988766

Edited 1620989103
Kurt J.
Pro
API Scripter
Will M. said: @Kurt - on version 1.2.3, I'm getting "Undefined" when returning attributes with empty or 0 (zero) values.&nbsp; This functionality worked in version 1.2.2b, returning the same value I see in the character sheet.&nbsp; I've gone back and forth between version 1.2.3 and 1.2.2b and have been able to confirm that there may be a bug associated with 1.2.3.&nbsp; I'm using the Roll20 5E OGL sheets and testing against NPCs right now.&nbsp;&nbsp; [*[&amp;CharId]:npc_str_save_flag] returns "Undefined"&nbsp; whereas [*[&amp;CharId]:dexterity_mod] returns an appropriate value.&nbsp;&nbsp; I've perused the Character sheet, and it has appropriate values in the fields.&nbsp; I've also issued the chat command&nbsp;@{derro|npc_str_save_flag} and I get a good value of "0". As a Patreon supporter, I got a hold of your version 1.2.6 and confirmed the issue is still present there.&nbsp;&nbsp; BTW, I'm really looking forward to some of your new condition blocks and looping features.&nbsp;&nbsp; Update:&nbsp; I went ahead and looked at your code, comparing the changes between 1.2.2b and 1.2.3 and the issue may be on lines 2502 - 2503.&nbsp; I'm guessing the conditional&nbsp; (!attribute) &nbsp; above it is evaluating to true if&nbsp; attribute&nbsp; has a value of "0" or Null (which are legitimate), and then on the next line&nbsp;&nbsp; character.get(attrName) &nbsp;function bombs and returns "undefined".&nbsp; Commenting out line 2503 fixed my problem.&nbsp;&nbsp; if (character !== undefined &amp;&amp; (!attrName.toLowerCase().startsWith("t-"))) { attribute = getAttrByName(character.id, attrName, opType); if (!attribute) { ----&gt; attribute = character.get(attrName); // Not sure what's happening here but it appears that this line (2503 in v1.2.3) is suspect } if (attrName == "bio") { character.get("bio", function(bio) {attribute = bio} ) } //if (attrName == "bio") { // var getAsync = retrieveAsyncValue(character, "bio"); Going to bed now....It's been fun debugging this issue, but can't keep eyes open any longer.&nbsp;&nbsp; Looks like I introduced this bug when adding the ability to retrieve character properties. In my testing this morning, it looks like a pretty easy fix. The line above that reads: if (!attribute) { Should be: if (attribute === undefined) { Because Javascript sees a 0/null as a false value for a straight if(something) check. I've put a fix on the public GIST as 1.2.3a, and updated the Patreon GIST to 1.2.6b with the same fix. Thank you for your patreon support! :)
1620989796
Kurt J.
Pro
API Scripter
Brien V. said: I'm trying to have the card check to see if the PC is an Operative and, if so, going to a sub to do a trick attack.&nbsp; I'm obviously not doing it correctly.&nbsp; But I don't know what I am doing wrong. !script {{ --+First Class:|@{selected|class_1_name} --?@{selected|class_1_name} -eq Operative|TrickAttack --+Failure:|You're no Operative --X| --:TrickAttack| --?@{selected|class_1_name} -eq "Operative"|=Level;@{selected|class_1_level} --+Operative Level:|[$Level] }} I created a test game, and that code worked fine for me (once I figured out how to create a character). I know it is a strange question, but I noticed that class just gets typed in by the player. Are you sure the spelling on the character sheet (including capitalization) is correct? Is there a space before the class name on the character sheet, etc?
David M. said: @Craven, something like this? Uses passive_wisdom from the 5e by Roll20 sheet. Select any token on the page before running it. EDIT - edited to display as a roll variable !script {{ --#title|Global Passive Perception --:(1) GET ALL TOKENS INTO THE "allTokens" ARRAY| will have blank 1st element to be removed later --~|array;pagetokens;allTokens;@{selected|token_id} --:(2) PREP ARRAY FOR LOOP| if no array elements then end macro --~tokenid|array;getfirst;allTokens --?[&amp;tokenid] -eq ArrayError|End --:(3) GRAB PASSIVE PERCEPTION FROM EACH TOKEN| --:PPLoop| --:TOKEN MUST BE ON OBJECTS OR GMLAYER AND HAVE A NON_BLANK PASSIVE_WISDOM| --?[*[&amp;tokenid]:t-layer] -ne objects -and [*[&amp;tokenid]:t-layer] -ne gmlayer|NextToken --?[*[&amp;tokenid]:passive_wisdom] -ne ""|&gt;DisplayPP --:NextToken| --~tokenid|array;getnext;allTokens --?[&amp;tokenid] -ne ArrayError|PPLoop --:End| --X| --:DisplayPP| --=PP|[*[&amp;tokenid]:passive_wisdom] ​--+[*[&amp;tokenid]:character_name]|[$PP] --&lt;| }} Thanks David M.
Any idea why this happens? !scriptcard {{ --#leftsub|Stuff --#rightsub|Stuff --#titleFontColor|#FFFFFF --#titleCardBackground|#932729 --#evenRowBackground|#B6AB91 --#evenRowFontColor|#000000 --#oddRowBackground|#CEC7B6 --#oddRowFontColor|#000000 --#emoteBackground|#FFFFFF --#tableBorderRadius|8px +++5E Tools+++ --#title|@{selected|token_name} --&gt;Lib5E_Character_Summary|@{selected|character_id} }} &nbsp;
1621033437
Kurt J.
Pro
API Scripter
Craven said: Any idea why this happens? !scriptcard {{ --#leftsub|Stuff --#rightsub|Stuff --#titleFontColor|#FFFFFF --#titleCardBackground|#932729 --#evenRowBackground|#B6AB91 --#evenRowFontColor|#000000 --#oddRowBackground|#CEC7B6 --#oddRowFontColor|#000000 --#emoteBackground|#FFFFFF --#tableBorderRadius|8px +++5E Tools+++ --#title|@{selected|token_name} --&gt;Lib5E_Character_Summary|@{selected|character_id} }} I've seen this happen before when the library code gets mangled by the Roll20 editor. The Wiki doesn't help either because it introduces its own formatting issue. I'll see about setting up a GIST for the library and pointing there from the Wiki instead of including the code directly in the article.
1621034190
Kurt J.
Pro
API Scripter
Kurt J. said: Will M. said: @Kurt - on version 1.2.3, I'm getting "Undefined" when returning attributes with empty or 0 (zero) values.&nbsp; This functionality worked in version 1.2.2b, returning the same value I see in the character sheet.&nbsp; I've gone back and forth between version 1.2.3 and 1.2.2b and have been able to confirm that there may be a bug associated with 1.2.3.&nbsp; I'm using the Roll20 5E OGL sheets and testing against NPCs right now.&nbsp;&nbsp; [*[&amp;CharId]:npc_str_save_flag] returns "Undefined"&nbsp; whereas [*[&amp;CharId]:dexterity_mod] returns an appropriate value.&nbsp;&nbsp; I've perused the Character sheet, and it has appropriate values in the fields.&nbsp; I've also issued the chat command&nbsp;@{derro|npc_str_save_flag} and I get a good value of "0". As a Patreon supporter, I got a hold of your version 1.2.6 and confirmed the issue is still present there.&nbsp;&nbsp; BTW, I'm really looking forward to some of your new condition blocks and looping features.&nbsp;&nbsp; Update:&nbsp; I went ahead and looked at your code, comparing the changes between 1.2.2b and 1.2.3 and the issue may be on lines 2502 - 2503.&nbsp; I'm guessing the conditional&nbsp; (!attribute) &nbsp; above it is evaluating to true if&nbsp; attribute&nbsp; has a value of "0" or Null (which are legitimate), and then on the next line&nbsp;&nbsp; character.get(attrName) &nbsp;function bombs and returns "undefined".&nbsp; Commenting out line 2503 fixed my problem.&nbsp;&nbsp; if (character !== undefined &amp;&amp; (!attrName.toLowerCase().startsWith("t-"))) { attribute = getAttrByName(character.id, attrName, opType); if (!attribute) { ----&gt; attribute = character.get(attrName); // Not sure what's happening here but it appears that this line (2503 in v1.2.3) is suspect } if (attrName == "bio") { character.get("bio", function(bio) {attribute = bio} ) } //if (attrName == "bio") { // var getAsync = retrieveAsyncValue(character, "bio"); Going to bed now....It's been fun debugging this issue, but can't keep eyes open any longer.&nbsp;&nbsp; Looks like I introduced this bug when adding the ability to retrieve character properties. In my testing this morning, it looks like a pretty easy fix. The line above that reads: if (!attribute) { Should be: if (attribute === undefined) { Because Javascript sees a 0/null as a false value for a straight if(something) check. I've put a fix on the public GIST as 1.2.3a, and updated the Patreon GIST to 1.2.6b with the same fix. Thank you for your patreon support! :) While resolved for [*-ID] matches, this bug still exists in the 1.2.3a/1.2.6b code for [*S] and [*T] matches. That will be resolved in 1.2.7 which will be available to everyone shortly with some new language features.
1621037276

Edited 1621038093
Kurt J.
Pro
API Scripter
ScriptCards v 1.2.7 Now Available - Loops and Block Edition The GIST has been updated with version 1.2.7 of ScriptCards, with the following changes: Bug Fix Corrected a bug introduced in 1.2.3 that would return "undefined" for token/character references ([*x:] syntax) that were 0 or null. (Thanks Will M.) Data Statements Support for BASIC-style read/data statements with the --d statement has been added. Data can be defined anywhere in your script with the --d!|element1;element2;element3;etc... statement. Data is pre-processed into a structure that can be read with the --dVarName| command to read the next available data element into a string variable called "VarName". When attempting to read past the last available element, a value of "EndOfDataError" will be returned. You can reset the data pointer to begin reading again from the beginning with --d&lt;|. Here is a simple example script that just reads data lines and outputs the result (Note that this script uses the new For...Next loop functionality (see the next item in this list): !script {{ &nbsp; --%dataLoop|1;1000;1 &nbsp; --dThisItem| &nbsp; --?"[&amp;ThisItem]" -eq EndOfDataError|%! &nbsp; --+Data|[&amp;ThisItem] &nbsp; --%| &nbsp; --d!|welcome;to;the;jungle;"we've";got;RPGs! }} This will read elements from the data statement (--d!) until it hits the end, outputting each element on its own line. Something like this: Any number of --d! statements can be included, and they will be concatenated in the order they appear in the card. Note that a --d!| statement does not do anything at run-time and is pre-parsed so ignored when the interpreter reaches the line itself during execution. For...Next Loops&nbsp; It is now possible to create For...Next loops in ScriptCards with the --% statement type. A loop is defined by starting off with: --%LoopCounter|&lt;start&gt;;&lt;end&gt;;[step] The &lt;start&gt; and &lt;end&gt; values are required, while the [step] parameter is optional. If the step is omitted, it will be assumed to be 1. A string variable called "LoopCounter" will be created and will hold the current iteration value for the loop. Here is a real example: --%LoopCounter|1;10;1 This will begin a loop identified by "LoopCounter" that will start at 1, increasing by 1 each iteration (the step) until it has completed 10 executions. The "next" statement is simply --%|, with no tag or parameters. This indicates to ScriptCards that it should increment the counter and go back to the beginning of the loop. Extending the example above: !script {{ &nbsp; --%LoopCounter|1;10;1 &nbsp; &nbsp; --=Roll|1d20 &nbsp; &nbsp; --+Loop|Counter is [&amp;LoopCounter], roll was [$Roll] &nbsp; --%| &nbsp;}} Will produce: Loops CAN be nested within each other, and the step value can be negative if you wish to run a loop downwards. Here is an example that combines both: !script{{ &nbsp;--#title|Loop Test &nbsp;--#leftsub|Nested Loops! &nbsp;--%loopcounter|1;3;1 &nbsp; &nbsp;--%inner|15;5;-5 &nbsp; &nbsp; &nbsp;--%third|1;3 &nbsp; &nbsp; &nbsp; &nbsp;--+Loops|Outer is [&amp;loopcounter], Inner is [&amp;inner], Third is [&amp;third] &nbsp; &nbsp; &nbsp;--%| &nbsp; &nbsp;--%| &nbsp;--%| }} This runs three nested loops, the outer loop runs from 1 to 3, step 1. The second loop runs from 15 to 5, with a step of -5, and the innermost (third) loop runs from 1 to 3 with an implied step of 1. The output of this script looks like this: Finally, a conditional can end the current iteration of a loop with the % character, or break out of the loop entirely with %!. This is demonstrated in the "Read...Data" section above, where the loop is defined to run 1000 times, but when it hits the "EndOfDataError" item, the conditional uses %! to break the loop. Finally, modifying the LoopCounter variable will not have any impact on the loop or the number of iterations it runs. When execution returns to the top of the loop, the value of the variable will be reset to the current loop counter, which is tracked internally. Here is a more practical example where I rewrote my Spell Slots Report script from this: !scriptcards {{&nbsp; &nbsp; --#title|Spell Slot Report &nbsp; --#sourceToken|@{selected|token_id} &nbsp; --#leftsub|@{selected|character_name} &nbsp; --#emotestate|hidden &nbsp; --?[*S:lvl1_slots_total] -eq 0|Done &nbsp; --=SlotsLeft|[*S:lvl1_slots_total] - [*S:lvl1_slots_expended] &nbsp; --+Level 1|[$SlotsLeft.Total] of [*S:lvl1_slots_total] slots remaining &nbsp; --?[*S:lvl2_slots_total] -eq 0|Done &nbsp; --=SlotsLeft|[*S:lvl2_slots_total] - [*S:lvl2_slots_expended] &nbsp; --+Level 2|[$SlotsLeft.Total] of [*S:lvl2_slots_total] slots remaining &nbsp; --?[*S:lvl3_slots_total] -eq 0|Done &nbsp; --=SlotsLeft|[*S:lvl3_slots_total] - [*S:lvl3_slots_expended] &nbsp; --+Level 3|[$SlotsLeft.Total] of [*S:lvl3_slots_total] slots remaining &nbsp; --?[*S:lvl4_slots_total] -eq 0|Done &nbsp; --=SlotsLeft|[*S:lvl4_slots_total] - [*S:lvl4_slots_expended] &nbsp; --+Level 4|[$SlotsLeft.Total] of [*S:lvl4_slots_total] slots remaining &nbsp; --?[*S:lvl5_slots_total] -eq 0|Done &nbsp; --=SlotsLeft|[*S:lvl5_slots_total] - [*S:lvl5_slots_expended] &nbsp; --+Level 5|[$SlotsLeft.Total] of [*S:lvl5_slots_total] slots remaining &nbsp; --?[*S:lvl6_slots_total] -eq 0|Done &nbsp; --=SlotsLeft|[*S:lvl6_slots_total] - [*S:lvl6_slots_expended] &nbsp; --+Level 6|[$SlotsLeft.Total] of [*S:lvl6_slots_total] slots remaining &nbsp; --?[*S:lvl7_slots_total] -eq 0|Done &nbsp; --=SlotsLeft|[*S:lvl7_slots_total] - [*S:lvl7_slots_expended] &nbsp; --+Level 7|[$SlotsLeft.Total] of [*S:lvl7_slots_total] slots remaining &nbsp; --?[*S:lvl8_slots_total] -eq 0|Done &nbsp; --=SlotsLeft|[*S:lvl8_slots_total] - [*S:lvl8_slots_expended] &nbsp; --+Level 8|[$SlotsLeft.Total] of [*S:lvl8_slots_total] slots remaining &nbsp; --?[*S:lvl9_slots_total] -eq 0|Done &nbsp; --=SlotsLeft|[*S:lvl9_slots_total] - [*S:lvl9_slots_expended] &nbsp; --+Level 9|[$SlotsLeft.Total] of [*S:lvl9_slots_total] slots remaining &nbsp; --:Done| &nbsp; --X| }} to this: !scriptcards {{&nbsp; &nbsp; --#title|Spell Slot Report &nbsp; --#sourceToken|@{selected|token_id} &nbsp; --#leftsub|@{selected|character_name} &nbsp; --#emotestate|hidden &nbsp; --%SlotLevel|1;9;1 &nbsp; &nbsp; --?[*S:lvl[&amp;SlotLevel]_slots_total] -gt 0|[ &nbsp; &nbsp; &nbsp; --=SlotsLeft|[*S:lvl[&amp;SlotLevel]_slots_total] - [*S:lvl[&amp;SlotLevel]_slots_expended] &nbsp; &nbsp; &nbsp; --+Level [&amp;SlotLevel]|[$SlotsLeft.Total] of [*S:lvl[&amp;SlotLevel]_slots_total] slots remaining &nbsp; &nbsp; --]| &nbsp; --%| }} This uses conditional code blocks (see the next item in the list), and both of these scripts produce following output (ignore the typo in "remaining" in the screenshot :) I fixed it in the script but didn't take a new screenshot): Conditional Code Blocks The final new feature for this version of ScriptCards is the ability to define blocks of code in association with conditional statements. Trhis is similar to begin...end or curly braces in some languages, though a bit more limited. As part of the true or false execution branch of a conditional, you can use the "[" character to begin a code block. If that execution path is taken, the code in the block will be executed. Otherwise, the code in the block will be skipped. Blocks are completed with the --]| statement, and can optionally include an "else" block by using --]|[ as the block terminator. Here is an example: !script {{ &nbsp; --=Roll|1d2 &nbsp; --+Roll|[$Roll] &nbsp; --?[$Roll.Total] -eq 2|[ &nbsp; &nbsp; --&amp;Value|Yep! &nbsp; &nbsp; --+|We are inside the TRUE portion of the block &nbsp; --]|[ &nbsp; &nbsp; --&amp;Value|Nope &nbsp; &nbsp; --+|We are inside the FALSE portion of the block &nbsp; --]| &nbsp; --+After|the blocks! &nbsp; --+Value|[&amp;Value] }} In this case, we begin by rolling 1d2 and then use a conditional to see if the result is 2. if it is, we execute everything inside the code block that begins on the conditional line, up until the end of the block - here marked with --]|[ because we have an "else" block. The else block is terminated with --]|. the output of this example looks like this: At this time, blocks cannot be nested, and can only be created as part of a conditional (--[ is not a valid statement type) As always, please let me know if you run into issues!
Loving this. Powercards almost sent me into...well. Thank you for putting logic into macros. My question: Is there a way to add padding or spacing or a way to put in a line break after a paragraph?
1621071219

Edited 1621071318
EvaluateConditional in 1.2.3... switch (components[1]) { &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; case "-gt": if (left &gt; right) return true; break; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; case "-ge": if (left &gt;= right) return true; break; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; case "-lt": if (left &lt; right) return true; break; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; case "-le": if (left &lt;= right) return true; break; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; case "-eq": if (left == right) return true; break; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; case "-eqi" : if (left.tostring().toLowerCase() == right.tostring().toLowerCase()) return true; break; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; case "-ne": if (left !== right) return true; break; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; case "-nei" : if (left.tostring().toLowerCase() !== right.tostring().toLowerCase()) return true; break; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; case "-inc": if (left.toString().toLowerCase().indexOf(right.toString().toLowerCase()) &gt;= 0) return true; break; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; case "-ninc": if (left.toString().toLowerCase().indexOf(right.toString().toLowerCase()) &lt; 0) return true; break; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; } Provoke an api script crash when using -eqi or -nei. Check typo @Kurt J. of the "tostring" calls in cases nei and eqi ! Works write when editing api script and correcting with toString calls. TypeError: left.tostring is not a function TypeError: left.tostring is not a function at evaluateConditional (apiscript.js:14916:28) at processFullConditional (apiscript.js:14876:22) at apiscript.js:13926:22 at eval (eval at &lt;anonymous&gt; (/home/node/d20-api-server/api.js:154:1), &lt;anonymous&gt;:65:16)
1621072956
Kurt J.
Pro
API Scripter
Lionel T. said: EvaluateConditional in 1.2.3... switch (components[1]) { &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; case "-gt": if (left &gt; right) return true; break; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; case "-ge": if (left &gt;= right) return true; break; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; case "-lt": if (left &lt; right) return true; break; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; case "-le": if (left &lt;= right) return true; break; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; case "-eq": if (left == right) return true; break; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; case "-eqi" : if (left.tostring().toLowerCase() == right.tostring().toLowerCase()) return true; break; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; case "-ne": if (left !== right) return true; break; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; case "-nei" : if (left.tostring().toLowerCase() !== right.tostring().toLowerCase()) return true; break; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; case "-inc": if (left.toString().toLowerCase().indexOf(right.toString().toLowerCase()) &gt;= 0) return true; break; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; case "-ninc": if (left.toString().toLowerCase().indexOf(right.toString().toLowerCase()) &lt; 0) return true; break; &nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp; } Provoke an api script crash when using -eqi or -nei. Check typo @Kurt J. of the "tostring" calls in cases nei and eqi ! Works write when editing api script and correcting with toString calls. TypeError: left.tostring is not a function TypeError: left.tostring is not a function at evaluateConditional (apiscript.js:14916:28) at processFullConditional (apiscript.js:14876:22) at apiscript.js:13926:22 at eval (eval at &lt;anonymous&gt; (/home/node/d20-api-server/api.js:154:1), &lt;anonymous&gt;:65:16) Thanks, Lionel. I've fixed the issue and uploaded 1.2.7a to the GIST.
Is there a way to simplify this code?&nbsp; I'm checking to see if a character is an operative and, if so, move down to the section for Trick Attacks.&nbsp; Is there a way to do a Rfind on non-repeating sections?&nbsp; The class section of the starfinder sheet is a set number of entries.&nbsp; I would like to be able to pull the other relevant info from the class entry once I know what line it's on.&nbsp; Thoughts? &nbsp;!script {{ --&amp;OpCheck|@{selected|class_1_name} --?[&amp;OpCheck] -eq Operative|TrickAttack --&amp;OpCheck|@{selected|class_2_name} --?[&amp;OpCheck] -eq Operative|TrickAttack --&amp;OpCheck|@{selected|class_3_name} --?[&amp;OpCheck] -eq Operative|TrickAttack --&amp;OpCheck|@{selected|class_4_name} --?[&amp;OpCheck] -eq Operative|TrickAttack --&amp;OpCheck|@{selected|class_5_name} --?[&amp;OpCheck] -eq Operative|TrickAttack --+Failure:|You're no Operative --X| --:TrickAttack| --+Success:|You are an Operative. --?[&amp;OpCheck] -eq Operative|=Level;@{selected|class_1_level} --+Operative Level:|[$Level] }}
Kurt J. said: Craven said: Any idea why this happens? !scriptcard {{ --#leftsub|Stuff --#rightsub|Stuff --#titleFontColor|#FFFFFF --#titleCardBackground|#932729 --#evenRowBackground|#B6AB91 --#evenRowFontColor|#000000 --#oddRowBackground|#CEC7B6 --#oddRowFontColor|#000000 --#emoteBackground|#FFFFFF --#tableBorderRadius|8px +++5E Tools+++ --#title|@{selected|token_name} --&gt;Lib5E_Character_Summary|@{selected|character_id} }} I've seen this happen before when the library code gets mangled by the Roll20 editor. The Wiki doesn't help either because it introduces its own formatting issue. I'll see about setting up a GIST for the library and pointing there from the Wiki instead of including the code directly in the article. Thank for the info I was able to fix this. When I look at the handout it had the code box formatting around it. I deleted the handout, created a new one. posted the code into notepad ++ and then copy it to the new card. Issue resolved.&nbsp;
1621085737
David M.
Pro
API Scripter
Brien V. said: Is there a way to simplify this code?&nbsp;&nbsp; Doesn't save too many lines, but you could try a for loop (requires the new new v1.27a) with *S notation and turning trickAttack into a procedure to which you pass the class "number" (e.g. 1,2,3,4, or 5). If there is a case where multiple class_n_names are "Operative", the below would print for each one. If you wanted to stop at the first one encountered, you could add a --X| at the bottom of the procedure. !scriptcards {{ --#title|Operative Check --#sourceToken|@{selected|token_id} --#emotestate|hidden --%ClassNum|1;5;1 --?[*S:class_[&amp;ClassNum]_name] -eq Operative|&gt;TrickAttack;[&amp;ClassNum] --%| --X| --:TrickAttack| --+Success:|You are an Operative. --=Level|[*S:class_[%1%]_level] --+Operative Level:|[$Level] --&lt;| }} Not sure about the Rfind question. I haven't really used those yet.
1621086618

Edited 1621086669
Kurt J.
Pro
API Scripter
Craven said: Kurt J. said: Craven said: Any idea why this happens? !scriptcard {{ --#leftsub|Stuff --#rightsub|Stuff --#titleFontColor|#FFFFFF --#titleCardBackground|#932729 --#evenRowBackground|#B6AB91 --#evenRowFontColor|#000000 --#oddRowBackground|#CEC7B6 --#oddRowFontColor|#000000 --#emoteBackground|#FFFFFF --#tableBorderRadius|8px +++5E Tools+++ --#title|@{selected|token_name} --&gt;Lib5E_Character_Summary|@{selected|character_id} }} I've seen this happen before when the library code gets mangled by the Roll20 editor. The Wiki doesn't help either because it introduces its own formatting issue. I'll see about setting up a GIST for the library and pointing there from the Wiki instead of including the code directly in the article. Thank for the info I was able to fix this. When I look at the handout it had the code box formatting around it. I deleted the handout, created a new one. posted the code into notepad ++ and then copy it to the new card. Issue resolved.&nbsp; Good to hear. I did go ahead an move the library out of the Wiki and into a GIST to make things easier. I know several folks have been working on libraries for other game systems, so if anyone wants to do something similar and host their library in a GIST and link it from the Wiki page, that would be great.
I was thinking it didn't work but I needed to update to the newest version.&nbsp; Works a charm.&nbsp; Thank you so much. I'm so bad at this, I read the entire section on the new features and had no idea it was exactly what I needed. David M. said: Doesn't save too many lines, but you could try a for loop (requires the new new v1.27a) with *S notation and turning trickAttack into a procedure to which you pass the class "number" (e.g. 1,2,3,4, or 5). If there is a case where multiple class_n_names are "Operative", the below would print for each one. If you wanted to stop at the first one encountered, you could add a --X| at the bottom of the procedure.
should do the trick ? --&amp;OpCheck|@{selected|class_1_name} @{selected|class_2_name} @{selected|class_3_name} @{selected|class_4_name} @{selected|class_5_name} --?[&amp;OpCheck] -inc Operative|TrickAttack