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

Looking for One-Click Attack and Ammo Tracking

I apologize if this is answered somewhere in the R20 documentation or forums, but I can't find it. I have a custom character sheet. In that sheet, I have a missile attack roll button inside a repeating section that sends its repeating item roll data to a roll template. Pretty standard, nothing fancy (see below). When the attack roll button is clicked, I want ammo to be auto deducted from a field within the repeating item. I understand how the !ammo API script works and am able to wire it up to my repeating row ammo field. I can call the API from a roll button value attribute, but I can't seem to "combine" the API call with the roll template information. Here are two buttons (each inside the repeating section) that each work fine - I want to combine  the functionality so I don't have to take any additional, manual action to deduct the ammo: <button type='roll' class='rollbutton' value='!ammo @{selected|character_id} repeating_missile_$0_missile_ammo -1 arrow' name='roll_missile_test'> Test</button> <button type='roll' class='rollbutton' value='@{whispertoggle} &{template:custom} {{title=@{banner_missile} **Missile Attack Throw**}} {{subtitle=@{character_title} @{selected|token_name}}} {{color=red}} {{Attack/Weapon=@{missile_name}}} {{Target=[[@{attack_throw}+(?{Target AC|0}[target AC])]]}} {{Roll=[[1d20+@{dex_mod}[dex]+@{missile_bonus}[wpn]+?{Range|Short,0|Medium,-2|Long,-5}[range]+@{class_damage_bonus_missile}[class]+@{fss_missile}[fss]-@{fatigue}[fatigue]+(?{Modifier|0}[mod])]]}} {{damage=[[{@{missile_damage}+(@{missile_is_thrown}*@{damage_attr})+(@{class_damage_bonus_missile}[class])-@{fatigue}[fatigue], 0d1+1}k1]]}} {{effects=@{missile_effects}}}' name='roll_missile_attack'> Attack</button> If I can't do what I'm asking, is there any way to do this through a sheet worker function via an action button? Or some other approach that results in, "player clicks button = roll attack and deduct ammo"?
1699727367

Edited 1699727438
vÍnce
Pro
Sheet Author
Maybe try adding the !ammo command after the roll template. value='@{whispertoggle} &{template:custom} {{title=@{banner_missile} **Missile Attack Throw**}} {{subtitle=@{character_title} @{selected|token_name}}} {{color=red}} {{Attack/Weapon=@{missile_name}}} {{Target=[[@{attack_throw}+(?{Target AC|0}[target AC])]]}} {{Roll=[[1d20+@{dex_mod}[dex]+@{missile_bonus}[wpn]+?{Range|Short,0|Medium,-2|Long,-5}[range]+@{class_damage_bonus_missile}[class]+@{fss_missile}[fss]-@{fatigue}[fatigue]+(?{Modifier|0}[mod])]]}} {{damage=[[{@{missile_damage}+(@{missile_is_thrown}*@{damage_attr})+(@{class_damage_bonus_missile}[class])-@{fatigue}[fatigue], 0d1+1}k1]]}} {{effects=@{missile_effects}}} !ammo @{selected|character_id} repeating_missile_$0_missile_ammo -1 arrow' Might need to include a %NEWLINE% between them. 
1699736083
GiGs
Pro
Sheet Author
API Scripter
If you arent adding a script call like Vince suggests, you can only do this with Custom Roll Parsing (as described in detail here: <a href="https://cybersphere.me/guide-to-custom-roll-parsing/" rel="nofollow">https://cybersphere.me/guide-to-custom-roll-parsing/</a>} CRP will allow you to use an action button, and combine the roll with an automatic stat change. But it's not easy to set up.
1699747212

Edited 1699894102
Vince's method did not work, most likely because both the roll and the API call require separate Chat window execution. I went ahead and implemented GiGs CRP and it worked beautifully. :D THANK YOU! Final sheet worker: on('clicked:repeating_missile:missile-attack', () =&gt; { &nbsp; &nbsp; getAttrs(['repeating_missile_missile_name', 'repeating_missile_missile_bonus', 'repeating_missile_missile_damage', 'repeating_missile_missile_is_thrown', 'repeating_missile_missile_effects', 'repeating_missile_missile_ammo'], function(values) { &nbsp; &nbsp; &nbsp; &nbsp; const missileName = values.repeating_missile_missile_name; &nbsp; &nbsp; &nbsp; &nbsp; const missileBonus = parseInt(values.repeating_missile_missile_bonus) || 0; &nbsp; &nbsp; &nbsp; &nbsp; const missileDamage = values.repeating_missile_missile_damage; &nbsp; &nbsp; &nbsp; &nbsp; const missileIsThrown = parseInt(values.repeating_missile_missile_is_thrown) || 0; &nbsp; &nbsp; &nbsp; &nbsp; const missileEffects = values.repeating_missile_missile_effects; &nbsp; &nbsp; &nbsp; &nbsp; const missileAmmo = parseInt(values.repeating_missile_missile_ammo) || 0; &nbsp; &nbsp; &nbsp; &nbsp; startRoll(`@{whispertoggle} &amp;{template:custom} {{title=@{banner_missile} **Missile Attack Throw**}} {{subtitle=@{character_title} @{selected|token_name}}} {{color=red}} {{Attack/Weapon=${missileName}}} {{Ammo Remaining=${missileAmmo - 1}}} {{Target=[[@{attack_throw}+(?{Target AC|0}[target AC])]]}} {{Roll=[[1d20+@{dex_mod}[dex]+${missileBonus}[wpn]+?{Range|Short,0|Medium,-2|Long,-5}[range]+@{class_damage_bonus_missile}[class]+@{fss_missile}[fss]-@{fatigue}[fatigue]+(?{Modifier|0}[mod])]]}} {{damage=[[{${missileDamage}+(${missileIsThrown}*@{damage_attr})+(@{class_damage_bonus_missile}[class])-@{fatigue}[fatigue], 0d1+1}k1]]}} {{effects=${missileEffects}}}`, roll =&gt; { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; finishRoll(roll.rollId); &nbsp; &nbsp; &nbsp; &nbsp; }); &nbsp; &nbsp; &nbsp; &nbsp; const output = {}; &nbsp; &nbsp; &nbsp; &nbsp; output['repeating_missile_missile_ammo'] = missileAmmo - 1; &nbsp; &nbsp; &nbsp; &nbsp; setAttrs(output); &nbsp; &nbsp; }); &nbsp; });
1699755244

Edited 1699778137
vÍnce
Pro
Sheet Author
+1 for a CRP solution. omonubi said: Vince's method did not work, most likely because both the roll and the API call require separate Chat window execution. That's odd.&nbsp; I often use multiple api mod calls in the same macro without issue. example; @{selected|PC-whisper} &amp;{template:pf_generic} @{selected|toggle_accessible_flag} @{selected|toggle_rounded_flag} {{color=@{selected|rolltemplate_color}}} {{header_image=@{selected|header_image-pf_block-check}}} {{character_name=@{selected|character_name}}} {{character_id=@{selected|character_id}}} {{subtitle}} {{name=healed}} !token-mod --set statusmarkers|!chained-heart !setattr --sel --hp|%hp_max% Maybe a sheet roll changes what is sent to chat...? UPDATED; Actually, I normally do this using macros in the vtt, not from a roll button... so, I tested and you are right omonubi, only the first line is executed when it comes from a sheet roll. ;-( non-CRP option; use a textarea attribute "placeholder" (hidden is optional) to hold the multi-line macro using actual line-breaks and then use the textarea as the button's value. You can include the line-breaks in the html using " &amp;#13;&amp;#10; " which adds a new line and carriage return. &lt;button type="roll" name="roll_multiline" value="@{multi_textarea}"&gt;Roll Multi-line Macro&lt;/button&gt; &lt;textarea name="attr_multi_textarea" class="hidden"&gt;Line One &amp;#13;&amp;#10; Line Two &amp;#13;&amp;#10; Line Three&lt;/textarea&gt; Example using your code from above; &lt;textarea name='attr_missile_test' class="hidden"&gt;@{whispertoggle} &amp;{template:custom} {{title=@{banner_missile} **Missile Attack Throw**}} {{subtitle=@{character_title} @{selected|token_name}}} {{color=red}} {{Attack/Weapon=@{missile_name}}} {{Target=[[@{attack_throw}+(?{Target AC|0}[target AC])]]}} {{Roll=[[1d20+@{dex_mod}[dex]+@{missile_bonus}[wpn]+?{Range|Short,0|Medium,-2|Long,-5}[range]+@{class_damage_bonus_missile}[class]+@{fss_missile}[fss]-@{fatigue}[fatigue]+(?{Modifier|0}[mod])]]}} {{damage=[[{@{missile_damage}+(@{missile_is_thrown}*@{damage_attr})+(@{class_damage_bonus_missile}[class])-@{fatigue}[fatigue], 0d1+1}k1]]}} {{effects=@{missile_effects}}} &amp;#13;&amp;#10; !ammo @{selected|character_id} repeating_missile_$0_missile_ammo -1 arrow&lt;/textarea&gt; &lt;button type='roll' class='rollbutton' value='@{missile_test}' name='roll_missile_attack'&gt; Attack&lt;/button&gt;
That's clever, Vince. Thanks!
1699802643
GiGs
Pro
Sheet Author
API Scripter
vÍnce said: you are right omonubi, only the first line is executed when it comes from a sheet roll. ;-( I've noticed from time to time that there is extra parsing going on with sheet&nbsp; rolls that messes some macros up. I haven't investigating exactly what it affects, but if your sheet rolls are complex or contain html substutions, you do need to check they work as expected.
1699803106
GiGs
Pro
Sheet Author
API Scripter
Nice work Omonubi. One thing I'd suggest: Roll20 stores values natively as strings, so if you atr going to do arithematic with something you should coerce the values to numbers. So this: const missileAmmo = values['repeating_missile_missile_ammo']; would become one of these: const missileAmmo = parseInt(values['repeating_missile_missile_ammo']) || 0; const missileAmmo = parseFloat(values['repeating_missile_missile_ammo']) || 0; const missileAmmo = +values['repeating_missile_missile_ammo'] || 0; The last two are basically the same, the first one is if you are specifically dealing with integers, whole numbers. Strings will cause an error when you attempt to do arithmetic with them. Now javascript does try to convert variables to their expected data, and roll20 sometimes interprets number input as actual numbers, so you don't always get an error. But you it's better not to rely on this when there is a way to make sure the code does what you want it to every time.
1699893811

Edited 1699893862
Yep, I realized after I posted the code I "slopped" my way through the const assignments. I found this great &nbsp;site that explained it all just the way you did, above. ;) I amended the example, above.&nbsp; (I have also since gone back through all my sheet workers and applied these data type conversions.) GiGs said: One thing I'd suggest: Roll20 stores values natively as strings, so if you atr going to do arithematic with something you should coerce the values to numbers.
1699899396
GiGs
Pro
Sheet Author
API Scripter
What a great site - everyone should check it out :)