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

Yet another question for the Gurus of CC's

Hi again, The great news is all the help I've gotten has done wonders. The bad news is  I am stuck  once more and  unclear where  the problem lies. V&V checks two stats (Intelligence and Agility) on two separate charts with unique bonuses and adds those total bonuses up to get the Damage Bonus. So Intelligence of 43 might earn you a +3 Dam. Bonus, while your Agility of 8 might earn  you a -2 for a final Damage bonus of  1. These are my Functions and my call for them: function agMod(agility) {     let dambonus1 = 0;     if (agility >= 87) dambonus1 = 14;     else if (agility >= 84) dambonus1 = Math.floor(agility/6) - 1;     else if (agility >= 78) dambonus1 = Math.floor(agility/6) - 1;     else if (agility >= 72) dambonus1 = Math.floor(agility/6) - 1;     else if (agility >= 66) dambonus1 = 10;     else if (agility >= 60) dambonus1 = 9;     else if (agility >= 54) dambonus1 = 8;     else if (agility >= 48) dambonus1 = 7;     else if (agility >= 42) dambonus1 = 6;     else if (agility >= 36) dambonus1 = 5;     else if (agility >= 30) dambonus1 = 4;     else if (agility >= 24) dambonus1 = 3;     else if (agility >= 18) dambonus1 = 2;     else if (agility >= 12) dambonus1 = 1;     else if (agility >= 6) dambonus1 = 0;     else if (agility >= 3) dambonus1 = -1;     else if (agility >= 1) dambonus1 = -2;     else dambonus1 = -3;     return dambonus1; }   function damMod(intelligence) {     let dambonus2 = 0;     if (agility >= 87) dambonus2 = 13;     else if (agility >= 81) dambonus2 = 12;     else if (agility >= 75) dambonus2 = 11;     else if (agility >= 69) dambonus2 = 10;     else if (agility >= 63) dambonus2 = 9;     else if (agility >= 57) dambonus2 = 8;     else if (agility >= 51) dambonus2 = 7;     else if (agility >= 45) dambonus2 = 6;     else if (agility >= 39) dambonus2 = 5;     else if (agility >= 33) dambonus2 = 4;     else if (agility >= 27) dambonus2 = 3;     else if (agility >= 21) dambonus2 = 2;     else if (agility >= 15) dambonus2 = 1;     else if (agility >= 9) dambonus2 = 0;     else if (agility >= 3) dambonus2 = 1;     else if (agility >= 1) dambonus2 = -2;     else dambonus2 = -2;     return dambonus2;   }       on("change:agility sheet:opened", function() {       getAttrs(["agility","intelligence","damagemod"], function(values) {         let agility = parseFloat(values.agility,10)||0;         let intelligence = parseFloat(values.intelligence,10)||0;         let damagemod = (agMod(agility)||0) + (damMod(intelligence)||0);         setAttrs({                                         damagemod: damagemod         });     }); }); Let me know  if anything looks glaringly wrong.   Thanks again!
1554317143
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
Well, it would help to know what isn't working. Is nothing happening? Is a value being set incorrectly? Do you have any errors appearing in the developer console? Have you tried logging variables at various points and seeing what gets logged in the developer console?
1554320309

Edited 1554321766
GiGs
Pro
Sheet Author
API Scripter
Scott raises excellent questions. It helps to know exactly which parts aren't working. Though I do notice one problem off the bat: function damMod(intelligence) {     let dambonus2 = 0;     if (agility >= 87) dambonus2 = 13;     else if (agility >= 81) dambonus2 = 12; In this function, you declare intelligence as the function parameter, but throughout the function use agility. So it looks to me like the if statement will fall through all rows till this one: else dambonus2 = -2; and thus the value will always be -2. I notice a bunch of repeating patterns in those functions, so you can simplify them quite easily. It looks like you noticed with the first one and were halfway to completing it. That would be function agMod(score) {     let bonus = 0;     if (score >= 87) bonus = 14;     else if (score >= 6) bonus = Math.floor(score/6) - 1;     else if (score >= 3) bonus = -1; else if (score >= 1) bonus = -2;     else bonus = -3;     return bonus; } I changed the refernece to agility here to score  to illustrate something about functions. When you declare a parameter like: function agMod(score) you can name the parameter anything. You just have to make sure you use that name throughout the function. This is part of the power of functions, its what allows you to use a single function for multiple different purposes. To take another example, you could have a function like this: function getStatMod(score) {     let statbonus = Math.floor(score/2)-5;     return statbonus; } You could then use that to calculate stat bonuses for any d&D attribute, like let strMod = getStatMod(strength); let dexMod = getStatMod(dexterity); let conMod = getStatMod(constitution); When you run the first of those lines, it runs the getStatMod function, and declares "score = strength" like this function getStatMod(let score = strength) Then when you run the second line,  function getStatMod(let score = dexterity) And so on. Throughout the function, whatever name you have chosen (score) will be treated as the variable you sent it (strength, dexterity, or constitution).  Hope that helps understand what's going on there. Also another point to understand: when creating variable names (like dambonus1), they exist only within the function. When the function returns a value and ends, the variables dont exist any more. So you can reuse the same names between different functions. So your second function can be written as function intMod(score) {     let bonus = 0;     if (score >= 87) bonus = 13;     else if (score >= 3) bonus = Math.round(score/6) -2;     else bonus = -2;     return bonus;   } I was able to reuse the score and bonus  variable names, because they only exist within this function, and dont conflict with the earlier function that also uses them. In this function, I used Math.round(), because that rounds to the nearest. Each of the breakpoints are at halfway points between divisions of 6 ( 3/6=  0.5, 9/6 = 1.5, 15/6 = 2.5, etc), so a function that rounds to the nearest should work here. Though it occurs to me it wouldnt be hard to create a single function to do all of the stat mods, if I knew the bonus tables for all your stats. That would be neater. A couple of things about your sheet worker -  It starts with  on("change:agility sheet:opened", function() {       getAttrs(["agility","intelligence","damagemod"], function(values) { The on() line only includes agility. That means whenever agility changes the function runs, but wont run when any other stat changes. Since you have intelligence in the function, you want to include a change:intelligence  statement as well. The second line, getAttrs, includes "damagemod". But you create and set damagemod in the function, and dont call it from the character sheet, so you dont need that in this line. What getAttrs does is grab the attribute values from the character sheet, and stores them in that values object at the end of the second line: getAttrs(["agility","intelligence","damagemod"], function( values ) { See that function(values) ? With this line, the scores for agility, intelligence, and damagemod are being read from the character sheet, and put in an object called values, You are then able to reach into that values object, and pluck out the score, when you have lines like this: let agility = parseFloat(values.agility,10)||0; The values.agility part of that line is where you reach into the values object and grab the agility score. You can only do that because the getAttrs line created the values object. Sheet workers have no way to read the character sheet directly. They cant know the details of any attributes on the sheet. It can only read the values object, which is why you need to use getAttrs to grab the attributes you need, and put them in the values object first. So, getting back to your function: You need to grab attributes that you are going to read from the sheet, but should only grab those attributes you actually do need to read from the sheet. In this case, thats intelligence and agility. So the first two lines should be on ("change:agility change:intelligence sheet:opened", function() {       getAttrs(["agility","intelligence"], function(values) { Putting all that together, you have function agMod(score) {     let bonus = 0;     if (score >= 87) bonus = 14;     else if (score >= 6) bonus = Math.floor(score/6) - 1;     else if (score >= 3) bonus = -1;     else if (score >= 1) bonus = -2;     else bonus = -3;     return bonus; }; function intMod(score) {     let bonus = 0;     if (score >= 87) bonus = 13;     else if (score >= 3) bonus = Math.round(score/6) -2;     else bonus = -2;     return bonus;   }; on("change:agility change:intelligence sheet:opened", function() {       getAttrs(["agility","intelligence"], function(values) {         let agility = parseFloat(values.agility,10)||0;         let intelligence = parseFloat(values.intelligence,10)||0;         let damagemod = agMod(agility)||0 + intMod(intelligence)||0;         setAttrs({                                         damagemod: damagemod         });     }); }); Technically you shouldnt actually need the the ||0 on the agmod and intmod functions, but i left them there since they dont do any harm. The way those functions are written they should always return a valid value. Anyway, there you go, see if this fixes your issues.
Thank you so much, again GiGs.  I really appreciate the lesson and background on how things work. I've  been taking some online lessons on CSS and HTML, but it's hard to find direct comparisons to the workers anywhere. My formatting and so on has been coming along but this JScript type stuff is kind of confusing.  I wanted to point out that the Agility Function and Worker you posted work, but the intelligence portion does seem to be working. Currently the bonus only calculates for agility.  Prior to this it would calculate a single number "3" which seemed to be based on the Intelligence portion of the bonus, however moving the agility or intelligence score would not update the bonus.  I am unsure why the intelligence bonus is not being added to the total bonus. 
1554465462

Edited 1554466038
GiGs
Pro
Sheet Author
API Scripter
It's working perfectly for me, can you post the html you are using for the inputs for agility, intelligence, and damagemod, and the sheet worker code just in case a typo or missing bracket has crept in? Edit: see next post. The code below is good: <h4>Agility:</h4><input type="number" name='attr_agility' value="0">  <h5>Intelligence:</h5><input type="number" name='attr_intelligence' value="0" ><br /> <h5>DamageMod:</h5><input type="number" name='attr_damagemod' value="0" ><br /> <script type="text/worker"> function agMod(score) {     let bonus = 0;     if (score >= 87) bonus = 14;     else if (score >= 6) bonus = Math.floor(score/6) - 1;     else if (score >= 3) bonus = -1;     else if (score >= 1) bonus = -2;     else bonus = -3;     return bonus; }; function intMod(score) {     let bonus = 0;     if (score >= 87) bonus = 13;     else if (score >= 3) bonus = Math.round(score/6) -2;     else bonus = -2;     return bonus;   }; on("change:agility change:intelligence sheet:opened", function() {       getAttrs(["agility","intelligence"], function(values) {         let agility = parseFloat(values.agility,10)||0;         let intelligence = parseFloat(values.intelligence,10)||0;         let damagemod = agMod(agility) + intMod(intelligence);         setAttrs({                                         damagemod: damagemod         });     }); }); </script> Agility and intelligence are both working correctly when i test them.
1554465995

Edited 1554466607
GiGs
Pro
Sheet Author
API Scripter
AHA! I spoke to soon. It seemed to work, but stopped working after a refresh (or maybe I miscalculated). It looks this syntax causes problems: let damagemod = agMod(agility)||0 + intMod(intelligence)||0; When I reversed the order let damagemod = intMod(intelligence)||0 + agMod(agility)||0; intelligence started working and agility stopped working. So it seems it was ignoring everything after the first ||0.  And that makes perfect sense now that I think about it. It's my syntax mistake. One solution is to wrap them in brackets let damagemod = (intMod(intelligence)||0) + (agMod(agility)||0) ; Another is to drop the ||0 completely - you shouldnt need them here anyway let damagemod = intMod(intelligence) + agMod(agility); This might explain a couple of weird errors I'd seen in the past, and hadn't figured out.  I've corrected my previous post.
1554467243
GiGs
Pro
Sheet Author
API Scripter
To explain the error (which was sloppiness on my part) you need to understand what || does. It is an OR operator, which in javascript is used like If-this-thing-is-true || if-not-use-this-instead  So this: (intMod(intelligence)||0) + (agMod(agility)||0); means (if intMod() is valid, use it || if not, use 0 ) + (if aglmod is valid, use it || if not, use 0) Without the brackets it says something very different: if intmod is valid use it ||   if not, use (0 + agMod) if agMod is valid ||       if agMod is not valid, use 0. So that's a big oops on my part. I learned something today, hehe.
GiGs, you really are amazing, dude.  Thank you for all the help and for helping me learn a 1000% more than I did when I started this folly.  Glad it wasn't a total waste of time for you either! FYI: it works perfectly now!
1554630844

Edited 1554634895
UPDATE: I fixed the problem below. Didn't realize there was a repeating_field Name that had to be unique. But I still would appreciate any guidance on how to automate/auto-populate the text fields for Powers and Weaknesses and how I could possibly add roll buttons to roll damage and to hit based on what is selected in the repeating field. This is probably a ton of work, so telling me to "F-off" is perfectly acceptable as a response to this.  But for shits and giggles...   For example : My player gets a Power Blast which has a 1d20 damage and range of Agility + Intelligence. Attacks are d20 based plus an accuracy mod. Damage 1d20 + a damage bonus.  When he selects Power Blast from the Repeatable Fields, I'd like to have the Textarea filled in with this power's description, stat info and have a button or clickable way to roll the attack that also triggers a roll template to chat.  So I've backed myself into a corner again.... I started adding repeating fields to the power, weakness, and equipment sections of the Powers Tab. My goal is to have a drop down list of all the powers in the game (not a massive list but sizable) but for now I have about 5 listed. Likewise, I am planning on doing the same for Weaknesses (a much shorter list), and also adding some options for Equipment (Invention, Vehicle, Personal, etc.). My dream big, fall hard goal is to find a way to populate the "textarea" associated with the repeating field with the pertinent info about each power, but that is probably a pipe dream.  I managed to get the repeatable fields working for Powers, Weaknesses, and Equipment. I could successfully add a field in Powers and fill out the associated "textarea", however an additional repeating field would appear in both Weaknesses, and Equipment. If I deleted one in any section it would delete one in the other sections too. Originally, I thought I had forgotten to give each one an original name and when I was pulling from the examples on the Wiki, but changing the name of each did nothing to resolve the issues. I'm still unclear what the <select class=""> represents in the big picture too.  On the brightside, the V&V sheet is looking really great and I owe 99% of it to GiGs! Thanks in advance! Here is my HTML any help would be much appreciated as always: < div   class = "sheet-tab-content sheet-tab2" >          < div   class = "textarea" >               < p   style = "text-align: center;" >< h2   style = "color:black" > Powers < / h2 >< / p >              < fieldset   class = "repeating_skills" >              < select   name = "attr_powerlist"   class = "powers" >              < option   value = "powerblast" > Power Blast < / option >              < option   value = "heightendstrengtha" > Heightened Strength A < / option >              < option   value = "heightendstrengthb" > Heightened Strength B < / option >              < option   value = "heightendendurancea" > Heightened Endurance A < / option >              < option   value = "heightendenduranceb" > Heightened Endurance B < / option >              < / select >              < textarea   name = "attr_addpowers"  placeholder = "Power Blast:Device: 14 inch range: 1D20 Damage: 20 shots per recharge...etc, etc," >< / textarea >              < / fieldset >                       < / div >                       < br   / >                  < div   class = "textarea" >          < p   style = "text-align: center;" >< h2   style = "color:black" > Weaknesses < / h2 >< / p >              < fieldset   class = "repeating_skills" >              < select   name = "attr_weaknesslist"   class = "powers" >              < option   value = "prejudice" > Prejudice < / option >              < option   value = "physicallimitation" > Physical Limitation < / option >              < option   value = "psychologicallimitation" > Psychological Limitation < / option >              < option   value = "agelimit" > Age < / option >              < / select >              < textarea   name = "attr_weaknesses" placeholder = "Prejudice: Is prejudice against Mutants and Altered Humans... and avacados...etc..." >< / textarea >              < / fieldset >          < / div >          < br   / >              < div   class = "textarea" >              < p   style = "text-align: center;" >< h2   style = "color:black" > Equipment < / h2 >< / p >              < fieldset   class = "repeating_skills" >              < select   name = "equipmentlist"   class = "powers" >              < option   value = "invention" > Invention < / option >              < option   value = "personalequipment" > Personal Equipment < / option >              < option   value = "baseequipment" > Base Equipment < / option >              < option   value = "vehicle" > Vehicle < / option >              < / select >              < textarea   name = "attr_equipment"  placeholder = "List your equipment here..." >< / textarea >      < / div >       < / div >
1554632704

Edited 1554632817
GiGs
Pro
Sheet Author
API Scripter
Thanks :) I'm pretty sure the problem is here you've named all 3 of your repeating sections the same: < fieldset   class = "repeating_skills" > You should call the first < fieldset   class = "repeating_powers" > the second < fieldset   class = "repeating_weaknesses" > and the last < fieldset   class = "repeating_equipment" > With your repeating sections above, you are assigning all the items to the repeating_skills section, and so are getting unpredictable effects. Thats why when you add a row to one of the sections, you get a new row in all of them.
Yup. I caught that and updated the thread. Thanks! I was wondering about using the repeating fields to fill in Texareas based on what is selected. I updated the thread with the info. 
1554636976
GiGs
Pro
Sheet Author
API Scripter
Using a textarea for that isnt the best way to go about it. A text area is good for description, but the actual game mechanics stuff you'd want in individual attributes. Also, I just noticed you tried to put the repeating section contents inside a text area - you can't do that.&nbsp; Normally, if you have a repeating section for attacks, powers, or whatever, you'll add a field (attribute) for every relevant bit, like the stats, and then add a button at the end to use those stats. If you havent read it, you should check out this page for specifics on roll20 html <a href="https://wiki.roll20.net/Building_Character_Sheets" rel="nofollow">https://wiki.roll20.net/Building_Character_Sheets</a> For buttons you add a html entry like so &lt;button type='roll' name='roll_BluffCheck'&nbsp; value='/roll 1d20 + @{Bluff}' &gt;&lt;/button&gt; This will create a button on the character sheet, and when you click it, it will send to chat whatever you have in the value. As you can see here, it is usually used for dice macros. So, the easiest way would be to have a repeating section devoted to attack-type powers, maybe call it attacks. here's a pretty simple layout: &nbsp;&nbsp;&nbsp;&nbsp;&lt;h2 class="powers"&gt;Attacks&lt;/h2&gt;&lt;/p&gt; &lt;h3 class="powers"&gt;Name&lt;/h3&gt; &lt;h3 class="powers"&gt;Accuracy&lt;/h3&gt; &lt;h3 class="powers"&gt;Range&lt;/h3&gt; &lt;h3 class="powers"&gt;Damage&lt;/h3&gt; &lt;h3&gt;class="powers"Roll&lt;/h3&gt; &lt;fieldset class="repeating_attacks"&gt; &lt;input class="powers" type="text" name="attr_attack_name" /&gt; &lt;input class="powers" type="number" name="attr_attack_accuracy" /&gt; &lt;input class="powers" type="text" name="attr_attack_damage" /&gt; &lt;input class="powers" type="text" name="attr_attack_range" /&gt; &lt;button type='roll' name='roll_attacks' value='&amp;{template:default} {{name=repeating_attacks_attack_name}} {{attack=[[1d20+ @{repeating_attacks_attack_accuracy} }} {{damage=@{repeating_attacks_attack_damage} }} '&gt;&lt;/button&gt; &lt;textarea name="attr_addpowers" placeholder="Power Blast:Device: 14 inch range: 1D20 Damage: 20 shots per recharge...etc, etc,"&gt;&lt;/textarea&gt; &lt;/fieldset&gt; You can also add extra fields for manually entered description, etc., but you dont need a textarea to show players what they can already see from the stats in the fieldset. A few things to note here: using the class=powers allows you to set specific style for each entry. For instance, in your CSS you can use .sheet-powers { &nbsp; &nbsp; text-align:center; } h2.sheet-powers { &nbsp; &nbsp; &nbsp;color:black; } This makes every item with the class powers center-aligned, and sets the color of the h2 item specifically to black. This is better than using the style commands you have in a few places. You';d also need to add some styling to the h3 items and the other items to get them to stay on the same line, IIRC display:inline-block &nbsp;should do that. Or maybe you need to change those h3s to divs, I'm a bit out of practice and havent messed with css in a while. But that's not what I'm here to help with - on to the button stuff! See in the fieldset I've added a bunch of attributes. Your button value contains dice macro code. This can be anything that's valid in a normal dice macro, so you can call attributes like @{strength} and @{agility}. If you want to use attributes within the same row of the fieldset, you can simply append the fieldset name to the attribute name. So if you wanted a button that rolled 1d20 + the attack_accuracy bonus, you can use &lt;button type='roll' name='roll_attacks' value='/roll 1d20+@{repeating_attacks_attack_accuracy}'&gt;&lt;/button&gt; The example I have above is a bit more complex, because it uses the default roll template. That is described on this page: <a href="https://wiki.roll20.net/Roll_Templates" rel="nofollow">https://wiki.roll20.net/Roll_Templates</a> You'll have to play around with the button code and the ways of using them, and come back if you have any questions!