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

How to get a query to do different things at different stages of a formula

Hello! I'm trying to tune up the macros for the Crimson Parcel Games Persona TTRPG sheet as some rules have been changed recently. Here's the code for a basic repeating skill or spell: <button type="roll" class="sheet-roll" name="weaponspell1" value="&{template:default} {{name=@{CharacterNameUsage} casts @{spellname1}!}} {{This costs =@{spellsp1} SP!}} {{This spell targets =@{spelltarget1}!}} {{@{CharacterNameUsage} rolled a =[[@{dice1}+{0d0+(4*@{cap}), 0d0+@{spellhitcalc1}+?{Enemy's Resistant Type|Normal, 0|Weak, 2|Resistant, -2}}dh1]] to hit!}} {{If successful they deal =[[@{spelldamagecalc1}+?{Enemy's Resistant Type|Normal, 0|Weak, 2|Resistant, -2}]] @{spelldamagetype1} damage!}} {{It also =@{spellnotes1}}}"></button> Here's what's going on: The player rolls for hit, which defaults to 2d6 + stat + hit bonus; @{cap} defaults to 1 for an absolute hit cap of +4. A query asks if the foe is weak (it's easier to hit them) or resistant (it's harder to hit them), in which case it adds or subtracts 2. Then it rolls spell damage dice + stat + dmg bonus + 1/4 the caster's level (if applicable). The same query is used to determine an additional damage bonus of 2, -2 or nothing (I don't know why 0d0 is in here and all over the place, I didn't make this sheet) However the community devs have rewritten the rules a little bit in this way: 1) Foes weak to something are easier to hit. Foes resistant-or-better do not gain an evasion bonus anymore 2) Foes weak to something take 1/4 the caster's level in bonus damage. Foes resistant to something take half damage, rounded down (min: 1) I've been trying to get the same query to add a hit bonus in part 1 and 1/4 Level damage bonus in part 2 for Weak. Additionally, I'm trying to remove the hit bonus in part 1 and apply a 0.5 multiplier on damage dealt for Resistant, and it's just not doing what I want. Is it even possible to have a single query modify things in a different way? I know that having it add 1/4LVL and multiply by .5 for damage is a real stretch (if not mathematically impossible)
1766526468

Edited 1766527526
Gauss
Forum Champion
Use the query as an on/off switch. 0 and 1.  ?{Queryname|Yes,1|No,0}*value If you need a 3way on off switch that can also be done but requires a slightly different setup where each section is looking for a specific answer:  {?{Queryname|A,1|B,2|C,3},0}=1*valueA {?{Queryname|A,1|B,2|C,3},0}=2*valueB {?{Queryname|A,1|B,2|C,3},0}=3*valueC An example for using this might be something where different parts of a template are looking for different choices.  There is also another 3choice variation for things where the choices are: Bonus, Nothing, Penalty.  BTW, I wrote this very quickly and basically as I am about to become unavailable. If you give me the exact switches you need I can look at it later in about 4hrs.  Edit: I had some extra time so I am providing an example.  &{template:default} {{name=On/Off Test}} {{Attack=[[1d20+?{Power Attack|On,1|Off,0}*-5]]}} {{Damage=[[1d8+?{Power Attack}*10]]}}
1766552448
timmaugh
Forum Champion
API Scripter
So, the "0d0"s sprinkled around in there are just "parsing protection" against values coming back from the sheet that would otherwise blow up a roll. As for using the query in multiple places, you're working from the character sheet, so you're going to have some problems just in the timing. A character sheet guru might be able to tell you more about whether it's possible (and how to do the) catching the return from a query and using it in multiple places. That said,  you can sometimes do it with certain math tricks (like Gauss demonstrated) if the calculations allow it, or you can do it with scripts. To give a comprehensive example would require the contents of the @{spelldamagecalc1} attribute, but here's something of what it would look like using the Metascript Toolbox. Since I don't have the contents of spelldamagecalc1, I can't modify that... but I can show the proper syntax for the query that would apply a further +1/4  caster level damage (for Weak) or a total 1/2 modifier (for Resistant). Also, your post seemed to indicate that the +1/4 or 1/2 modifier was IN PLACE OF the further +2 or -2 modifier, so I'm going to leave that off. One other note, since I don't know the attribute for the caster's level, I am calling it "@{level}". You'll have to fix that if I'm wrong. !&{template:default} {{name=@{CharacterNameUsage} casts @{spellname1}!}} {{This costs =@{spellsp1} SP!}} {{This spell targets =@{spelltarget1}!}} {{@{CharacterNameUsage} rolled a ={&r}@{dice1}+{0d0+(4*@{cap}), 0d0+@{spellhitcalc1}{&if ?{Enemy's Resistant Type|Normal|Weak|Resistant} = Weak}+2{&end} }dh1{&/r} to hit!}} {{If successful they deal ={&r}{1,round({&if  ?{Enemy's Resistant Type} = Resistant}.5*{&end}( @{spelldamagecalc1} {&if ?{Enemy's Resistant Type} = Weak}+(.25 * @{level}){&end} ))  }kh1{&/r} @{spelldamagetype1} damage!}} {{It also =@{spellnotes1}}} {&simple} Again, this is making assumptions about the contents of @{spelldamagecalc1}... but if it truly only contains "damage dice + stat + damage bonus", as you said in your post, then it does NOT contain the +1/4 or *1/2 math, and I'm good to put it where I have. That said, I did air-code it, so if you have any trouble with it, or if you need to adapt it further and can't see how, post back with the contents of @{spelldamagecalc1} and the name of the "level" attribute, and I can try to help more. Required Scripts To use the above example/rewrite, you'd need the Metascript Toolbox installed in your game (available in the one-click).
1766554301
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
I may be misunderstanding the mechanics, but I think with the exception of the 0.5x damage, this could all be done with the roll query trick Gauss demonstrated. But, to handle the 0.5x damage, I think you'll need to use custom roll parsing. To do that, you'll turn the button into an action button: <button type=" action " class=" act_ sheet-roll" name="weaponspell1"></button> Note that you'll need to add styling to recreate the look of a roll button on this button. Then, you'd write a sheetworker to listen for the action button click. Looking at that macro code, I'm not actually sure if this is in a repeating section or just the same html repeated multiple hard coded times with an index in the name increasing (e.g. spellname1, spellname2, etc). Without knowing that for sure, I can't write up a demo script that would be much use. But essentially, you'd dispatch a query to the user at the start of the function to ask them weak/normal/resistant, and then use normal javascript logic to determine what to do at each of the points that depend on it.
Sorry, I am ADHD-riddled and never got back to y'all. Since I am not particularly well-versed in HTML, I can't really claim that I understand these suggestions but here I go, in order: 1) I don't know how I would build or implement Gauss' three-way switch. I also don't know what the power attack thing they wrote does. 2) Okay, so 0d0 is just a protection thing that I can (or should) leave alone. I can see that timmaugh did something in the quote that is multiplying by .5 and adding something else, but I am only noticing a couple differences in the code and don't understand what exactly it's doing. 3) I don't know how to code javascript and I know effectively nothing about sheetworkers, so I don't know how I'd make an action button, but I suppose it's at least something I could pursue. Overall I'm getting the impression this is far beyond what I should be toying with, and it's definitely not anyone's job to hold my hand through it. However, here is all the code for the repeating Skills section anyway. I cannot claim to know how most of it works, I wasn't on the team that constructed the sheet. <h4 class="sheet-center">Skills</h4>             <div class="sheet-row sheet-padb">               <div class="sheet-col-1-1 sheet-small-label sheet-center">                 <div class="sheet-row sheet-sub-header">                                   <div class="sheet-row sheet-sub-header">                   <div class="sheet-col-1-8 sheet-center sheet-small-label">Skill's Name</div>                   <div class="sheet-col-1-16 sheet-center sheet-small-label">SP Cost</div>                   <div class="sheet-col-1-8 sheet-center sheet-small-label">Skill's Aspect</div>                   <div class="sheet-col-1-16 sheet-center sheet-small-label">Bonus to Hit</div>                   <div class="sheet-col-1-8 sheet-center sheet-small-label">Skill's Damage</div>                   <div class="sheet-col-1-16 sheet-center sheet-small-label">Bonus to Damage</div>                   <div class="sheet-col-1-20 sheet-center sheet-small-label">WP</div>                   <div class="sheet-col-1-14 sheet-center sheet-small-label">Damage Type</div>                   <div class="sheet-col-1-8 sheet-center sheet-small-label">Skill's Targets</div>                   <div class="sheet-col-1-8 sheet-center sheet-small-label">Skill's Effect</div>                   <div class="sheet-col-1-16 sheet-center sheet-small-label">Attack!</div>                 </div>               </div>             </div>           </div>                           <fieldset class="repeating_spell">            <div class="sheet-row">             <div class="sheet-col-1-8">               <input type="text" spellcheck="false" name="attr_spellname1">             </div>             <div class="sheet-col-1-16">               <input type="number" value="0" spellcheck="false" name="attr_spellsp1">             </div>            <div class="sheet-col-1-8">                 <select name="attr_spellaspect1" size="1">                   <option name="attr_spellaspect1" value="0">None</option>                   <option name="attr_spellaspect1" value="@{strengthcalc}">Strength</option>                   <option name="attr_spellaspect1" value="@{magiccalc}">Magic</option>                   <option name="attr_spellaspect1" value="@{endurancecalc}">Endurance</option>                   <option name="attr_spellaspect1" value="@{agilitycalc}">Agility</option>                   <option name="attr_spellaspect1" value="@{luckcalc}">Luck</option>             </div>             <div class="sheet-col-1-16">               <input type="number" value="0" name="attr_bonusspelltohit1">             <input type="hidden" name="attr_spellhitcalc1" value="@{spellaspect1}+@{bonusspelltohit1}">             </div>             <div class="sheet-col-1-8">               <input type="text" value="0" spellcheck="false" name="attr_spelldamage1">             </div>                         <div class="sheet-col-1-16">               <input type="number" value="0" name="attr_bonusspelltodamage1">             <input type="hidden" name="attr_spelldamagecalc1" value="@{spelldamage1}+@{spellaspect1}+@{bonusspelltodamage1}+(@{LV4skill}*(ceil(@{willpower})))">             </div>                  <span style="padding-left:16px">               <input type="checkbox" spellcheck="false" name="attr_LV4skill" value="1" unchecked>                  <span style="padding-left:14px">             <div class="sheet-col-1-14">               <input type="text" spellcheck="false" name="attr_spelldamagetype1">             </div>                        <div class="sheet-col-1-8">                 <select name="attr_spelltarget1" size="1">                   <option name="attr_spelltarget1" value="One Enemy">Single</option>                   <option name="attr_spelltarget1" value="All Enemies">Multiple</option>                   <option name="attr_spelltarget1" value="[[1d4]] Random Enemies">1-4</option>             </div>             <div class="sheet-col-1-8">                              <input type="text" spellcheck="false" name="attr_spellnotes1" rows="1" >             </div>              <div class="sheet-col-1-16">                 <button type="roll" class="sheet-roll" name="weaponspell1" value="&{template:default} {{name=@{CharacterNameUsage} casts @{spellname1}!}} {{This costs =@{spellsp1} SP!}} {{This spell targets =@{spelltarget1}!}} {{@{CharacterNameUsage} rolled a =[[@{dice1}+{0d0+(4*@{cap}), 0d0+@{spellhitcalc1}+?{Enemy's Resistant Type|Normal, 0|Weak, 2|Resistant, -2}}dh1]] to hit!}} {{If successful they deal =[[@{spelldamagecalc1}+?{Enemy's Resistant Type|Normal, 0|Weak, 2|Resistant, -2}]] @{spelldamagetype1} damage!}} {{It also =@{spellnotes1}}}"></button>               </div>               </fieldset> Explained plainly, the fields are in this order: Skill Name as text, # Input for SP Cost, attacking stat as dropdown, # input for Hit Bonus, Damage as text which gets parsed as a roll/formula, # input for damage bonus, WP check box, Damage Type as text, Skill Targets as a dropdown, and skill effect as text WP stands for Willpower, which is ceil(@{level}*.25) or something like that. Checking the box adds WP as a damage enhancement. The desired outcome is: If a combatant is targeted by something they are weak to such as Fire damage, the attack roll gets +2 and the damage roll gains +WP (up from the +2 the code says). If a combatant is targeted by something they resist such as Ice damage, the attack roll will not suffer the -2 penalty in the quoted code (we're removing that from calculations) but they will take half damage rounded down, instead of the -2 in the quoted code. Furthermore there's a few other places that use the same query for resist or not (such as basic weapon attacks) and knowing how to replicate it elsewhere would be awesome
1767025840

Edited 1767025888
timmaugh
Forum Champion
API Scripter
OK... so... let me see if I can contextualize the suggestions you're getting... Gauss is suggesting a method that doesn't require modifying the sheet with JavaScript knowledge nor implementing a mod script Scott is suggesting a way of handling everything in the sheet relying on JavaScript to build a sheetworker I am suggesting a way to handle things by implementing a script that we would assume would be installed in your game Gauss's Suggestion Gauss's suggestion is a query trick that relies on binary math (1 or 0) to turn a mathematical operation "on" or "off". For instance, if you multiply a potential modifier by the resulting binary, the modifier will either stay at its value (if you multiplied by 1) or become 0 (if you multiply by zero). This sort of approach doesn't rely on changing the character sheet NOR does it rely on mod scripts. That isn't to say that you'd be free and clear of modifying the character sheet, since it looks like you're having to change how the query is constructed in the sheet's HTML code, but the point is this doesn't require knowing JavaScript to code a sheetworker. This approach has a way to have a 3-way switch, as Gauss mentioned, but that's different from solving two or three different questions. Look at it this way: Your first modifier is a +2 that only affects the target if they are "Weak" against it. That's easy, we make the query represent 1 and 0 like... Weak = 1 Normal = 0 Resistant = 0 Great. Now your math looks like: MODIFIER ------------------------------------------ TYPE | BASE OP QUERY VAL FINAL ------------------------------------------ Weak | 2 * 1 = 2 Normal  | 2 * 0 = 0 Resistant |  2 * 0 = 0 So you have the correct mod applied in this part of the calculation. Let's see if the same query services for the other part... Your second modifier is a 1/2 reduction in the damage if the target is Resistant (we'll get to Weak in a minute). In this case, you need to get to a point where you can use the same 1/0 as an on/off for this part of the damage. If you think it through, that probably means you're going to have to move into the realm of addition/subtraction rather than strict multiplication, since you don't want to have full damage (1) versus no damage (0). So what if you start with Full Damage and then *subtract* half if the target is resistant? That way, that "one half" side of the subtraction operation can be either a "full one half" (multiplied by 1), or a 0 (multiplied by 0). In that case, you'd want your modifier to be built like MODIFIER ----------------------------------------------- TYPE | BASE OP QUERY VAL FINAL ----------------------------------------------- Weak | .5 * Full * 0 = 0 Normal  | .5 * Full * 0 = 0 Resistant |  .5 * Full * 1 = .5 * Full So you can see that if you start with your Full Damage calculation, you can either subtract half (to get a Resistant total), or you can subtract 0 to get a Weak or Normal value: Full - (.5 * ?{Query} * Full Damage) Similarly, if you think of your 1/4 added damage from being "Weak" as a third modifier, you can construct a method of starting with the base damage and adding either a "full 1/4" further damage, or adding a "0" further damage for this modifier. Now that you see (hopefully) the way this approach can help, you can see a limitation of it... your query values have to be different for each use (Weak should be a "1" in the first and third modifier, but it should be a "0" in the second... and the reverse is true for Resistant). Normally, for a 2 item binary, you can reverse the values pretty easily with a simple operation of subtracting 1 and multiplying by -1: 0 |  0 - 1 = -1 * -1 = 1 1 |  1 - 1 = 0 * -1 = 0 In your case, you have a third option in the mix (the "Normal" option)... and you don't want that one reversed by this same math operation. I'll leave it to Gauss to explain how the 3-option variation of his suggestion might solve this -- for all three modifiers. Or maybe you can see a way to reverse the values for different options in different modifier positions to get the math you need... but this is the point at which I start looking for a script solution (hence, my suggestion). Scott's Suggestion Scott's suggestion would have everything handled in the sheet via sheetworkers and roll parsing. Though I am comfortable in JavaScript, I have not ventured into the peculiarities of Roll20 sheet coding, so I will leave it to him to explain further, if this is something you wanted to pursue (it sounds like that isn't the way you want to go). My Suggestion My suggestion involved the Metascript Toolbox (a pre-written script, so you don't have to perform any JavaScript). It basically relied on IF conditional blocks to modify the line: {&if ... }True case text{&end} In your case, the conditional is checking the result of the query: {&if  ?{Enemy's Resistant Type|Normal|Weak|Resistant} = Weak} So if you have chosen "Weak", then the "true case text" is included in the line... which, in this case, was: +2 Followed by the "END" tag, to close the conditional: {&end} If the value you choose in the query is something OTHER than "Weak", the +2 is not included (e.g., for Normal and Resistant characters). The same thing is happening where Resistant should reduce it by half. In that case, the conditional looks for the query to have responded "Resistant", and includes true case text of ".5*" as a way to reduce the overall damage by half: {&if  ?{Enemy's Resistant Type} = Resistant}.5*{&end}( @{spelldamagecalc1}... And the same goes for the third modifier, adding an extra 1/4 damage if the query response was "Weak": {&if ?{Enemy's Resistant Type} = Weak}+(.25 * @{level}){&end} Hopefully you see how the IF conditionals are remapping the query for each interaction so you could replicate this. If so, notice that there is one other change to the command line... namely that it starts with an exclamation point and includes a {&simple} tag somewhere in it: ! ...text... {&simple} That gives the metascripts a chance to modify the message, then outputs the result to the chat. The thing to bear in mind about this approach is that it requires that the Metascript Toolbox be installed in the game for it to work, which means the owner of the game has to be at least a Pro sub level... but if that's your situation, it gives you a TON of flexibility without having to get into the weeds of JavaScript, yourself.
1767035153
Gauss
Forum Champion
For my 3way value I presented it was more in case you had 3 different fields looking for it for their own purpose.  The reason I was vague is I needed more information.  So far I have:  Weak = +2 attack, +WP damage Normal = no modifiers Resistant = -2 attack, 1/2 damage Is that correct? Are there any further modifiers?  ?{Weak or Resistant|Normal,0|Weak,1|Resistant,-1} attack:  ?{Weak or Resistant|Normal,0|Weak,1|Resistant,-1} *2 damage: ({?{Weak or Resistant},10}=1*WP +other modifiers)*{?{Weak or Resistant},10}<0*0.5 The damage calculation adds WP if Weak, doesn't add WP if weak, and multiplies the whole damage calculation by 0.5. It uses a single query for all of it. 
1767057386
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
I should note that since you are updating a sheet for the github repo, Tim's amazing api script solution won't work because the sheet can't rely on an api script for functionality if its in the repository. If you want, I can pretty quickly write up the sheetworker for doing this.
timmaugh: Thanks for the detailed explanation, that makes a ton of sense. Like Scott says I can't use an API so I think Gauss' solution is the best option, probably. Gauss: You almost have it. It should be... Weak = +2 attack, +WP (1/4 level, rounded up) damage Normal = no modifiers Resistant = -0 attack , 1/2 damage Resistant is presently -2 attack, the community devs are retooling it. Scott: My primary reluctance to involve sheetworkers is not knowing how to implement them, the ramifications of involving them in the first place for performance or maintainability, or basically anything else about them
1767125350
Gauss
Forum Champion
Is  -0 attack is the same as no modifiers?  If that is the case replace the attack line with: attack: { ?{Weak or Resistant|Normal,0|Weak,1|Resistant,-1},0}>1*2