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

More Sheet Worker Help

I am trying to set up a sheet worker to auto calculate ability modifiers for Castles & Crusades. This is all I have so far becuase I really have no idea how to do conditionals. Help? </script> <script type="text/worker"> on("change:constitution change:constitutionmod sheet:opened", function() {              getAttrs(["Constitution","ConstitutionMod"], function(values) {         let constitution = parseInt(values.Constitution)||0;         let constitutionmod =  ; setAttrs({                                 constitutionmod  }); }); }); </script> The scale is. 2-3 = -3 4-5 = -2 7-8 = -1 9-12 = 0 13-15 = 1 16-17 = 2 18-19 = 3 20-21 = 4 22-23 = 5 24-25 = 6 26-27 = 7 28 = 8 29 = 9 30 = 10
1617376156
CKenny
Sheet Author
hello here is a simple example on how you can do the scale with successives if  statements on("change:constitution change:constitutionmod sheet:opened", function() { getAttrs(["Constitution","ConstitutionMod"], function(values) { let constitution = parseInt(values.Constitution)||0; let modifier; // the scale if (constitution <= 3) modifier = -3; if (constitution <= 5) modifier = -2; if (constitution <= 8) modifier = -1; if (constitution <= 12) modifier = 0; if (constitution <= 15) modifier = 1; if (constitution <= 17) modifier = 2; if (constitution <= 19) modifier = 3; if (constitution <= 21) modifier = 4; if (constitution <= 23) modifier = 5; if (constitution <= 27) modifier = 7; if (constitution == 28) modifier = 8; if (constitution == 29) modifier = 9; if (constitution == 30) modifier = 10; setAttrs({ConstitutionMod : modifier}); }); });
That seems too simple. Is this a trap?
1617381864

Edited 1617381900
Kraynic
Pro
Sheet Author
I think you could shorten that a bit.  Since the modifier always improves by one for every 2 points of stat for a chunk of that range, I think you could remove the lines for constitution 17-27 and replace them all with this: if (constitution <= 27) modifier = Math.round((constitution - 15)*.5); on("change:constitution change:constitutionmod sheet:opened", function() { getAttrs(["Constitution","ConstitutionMod"], function(values) { let constitution = parseInt(values.Constitution)||0; let modifier; // the scale if (constitution <= 3) modifier = -3; if (constitution <= 5) modifier = -2; if (constitution <= 8) modifier = -1; if (constitution <= 12) modifier = 0; if (constitution <= 15) modifier = 1; if (constitution <= 27) modifier = Math.round((constitution - 15)*.5); if (constitution == 28) modifier = 8; if (constitution == 29) modifier = 9; if (constitution == 30) modifier = 10; setAttrs({ConstitutionMod : modifier}); }); });
1617385467

Edited 1617385533
Finderski
Pro
Sheet Author
Compendium Curator
If you use unconnected if statements like this, you'll likely want to reverse the order of the comparisons.  Because if your constitution is 1 then... 1 <= 3 so mod = -3 1 <= 5 so mod = -2 1 <= 1 so mod = -1 ... I think you see where I'm going with this.  You either want to use if/else if/else statement or at least reverse the comparison.  I'd recommend if/else if/else, personally... Also, you're missing 6, is it 4-6 or 6-8? That could affect your final solution.
I got it all to work (including the 6) for every ability score. Much appreciation everyone. Could you show me the if/else example though?
1617390092

Edited 1617390570
Andreas J.
Forum Champion
Sheet Author
Translator
Peacekeeper B said: Could you show me the if/else example though? At this point I suggest you check in on some beginners JavaScript tutorial and guides on how&nbsp; javascript is even structured, because this isn't anymore about how roll20's sheetworkers differ from javascript. <a href="https://www.w3schools.com/js/js_if_else.asp" rel="nofollow">https://www.w3schools.com/js/js_if_else.asp</a> There was also examples on this on the community wiki: <a href="https://wiki.roll20.net/Sheet_Worker_Snippets#parseValues" rel="nofollow">https://wiki.roll20.net/Sheet_Worker_Snippets#parseValues</a> Reading up on how conditionals work in javascript will help you immersely in making any future sheetworkers, because that's one of the most essential parts of programming.
1617466130
CKenny
Sheet Author
Finderski said: If you use unconnected if statements like this, you'll likely want to reverse the order of the comparisons. &nbsp;Because if your constitution is 1 then... 1 &lt;= 3 so mod = -3 1 &lt;= 5 so mod = -2 1 &lt;= 1 so mod = -1 nice catch, I'm so used to follow my one line if statements by return, that I forgot to take that into account
I've learned a lot and am quickly getting the hang of this. The advice and links help greatly.
I'm still trying to figure out how to automatically set stars that are class and level base. Say like BAB in a 3E/Pathfinder game. Is there a way to say: if class == fighter AND Level == X then Y?
You could try to integrate this somehow: on("change:charclass change:charlevel sheet:opened", function() { getAttrs(["Class","Level;"], function(values) { let class = parseInt(values.Class); &nbsp;&nbsp;&nbsp; let level = parseInt(values.Level)||0; // the scale if ((class == "fighter") &amp;&amp; (level == 5)) { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setAttrs({bab: 3}); &nbsp;&nbsp;&nbsp; }); if ((class == "fighter") &amp;&amp; (level == 7)) { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setAttrs({bab: 4}); &nbsp;&nbsp;&nbsp; }); }); }); There might be some way to set up an array but I wouldn't know about that
1617700339

Edited 1617700603
Excellent. Thank you. I stumbled upon &amp;&amp; but wasn't quite sure how it was supposed to look. I keep reminding myself that these aren't powercards and follow different language.
Another one. I am looking online for information and watching tutorials and readin Javascript for Dummies (seriously). But my mind doesn't bend in the right direction without practical help. Why isn't this working? The intent is on tab 1 of the sheet (character) you set your intelligence, and on tab 6 (monster stats) it sets the monsters intelligence level automatically. &lt;script type="text/worker"&gt; on("change:monsterintcat change:intelligence sheet:opened", function() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; getAttrs(["MonsterIntCat","Intelligence",], function(values) { &nbsp; &nbsp; let intelligence = parseInt(values.Intelligence)||0; &nbsp; &nbsp; let modifier; &nbsp; &nbsp; // the scale &nbsp; &nbsp; if (intelligence == 0) modifier = Non; &nbsp; &nbsp; if (intelligence == 1) modifier = Animal; &nbsp; &nbsp; if (intelligence == 2) modifier = Animal; &nbsp; &nbsp; if (intelligence == 3) modifier = Inferior; &nbsp; &nbsp; if (intelligence == 4) modifier = Inferior;&nbsp; &nbsp;&nbsp; &nbsp; &nbsp; if (intelligence == 5) modifier = Inferior; &nbsp; &nbsp; if (intelligence == 6) modifier = Low; &nbsp; &nbsp; if (intelligence == 7) modifier = Low; &nbsp; &nbsp; if (intelligence == 8) modifier = Low; &nbsp; &nbsp; if (intelligence == 9) modifier = Average; &nbsp; &nbsp; if (intelligence == 10) modifier = Average; &nbsp; &nbsp; if (intelligence == 11) modifier = Average; &nbsp; &nbsp; if (intelligence == 12) modifier = Average; &nbsp; &nbsp; if (intelligence == 13) modifier = High; &nbsp; &nbsp; if (intelligence == 14) modifier = High; &nbsp; &nbsp; if (intelligence == 15) modifier = High; &nbsp; &nbsp; if (intelligence == 16) modifier = Superior; &nbsp; &nbsp; if (intelligence == 17) modifier = Superior; &nbsp; &nbsp; if (intelligence == 18) modifier = Genius; &nbsp; &nbsp; if (intelligence == 19) modifier = Genius; &nbsp; &nbsp; if (intelligence == 20) modifier = Supra-Genius; &nbsp; &nbsp; if (intelligence == 21) modifier = Supra-Genius; &nbsp; &nbsp; if (intelligence == 22) modifier = Supra-Genius; &nbsp; &nbsp; if (intelligence == 23) modifier = Supra-Genius; &nbsp; &nbsp; if (intelligence == 24) modifier = Supra-Genius; &nbsp; &nbsp; if (intelligence == 25) modifier = Supra-Genius; &nbsp; &nbsp; if (intelligence == 26) modifier = Deific; &nbsp; &nbsp; if (intelligence == 27) modifier = Deific; &nbsp; &nbsp; if (intelligence == 28) modifier = Deific; &nbsp; &nbsp; if (intelligence == 29) modifier = Deific; &nbsp; &nbsp; if (intelligence == 30) modifier = Deific; &nbsp; &nbsp; setAttrs({MonsterIntCat : modifier});&nbsp; }); }); &lt;/script&gt;
1618711358
Kavini
Roll20 Production Team
Marketplace Creator
Sheet Author
Compendium Curator
You're missing some syntax in the Javascript, specifically the string identifiers ("string"). It could be better written like this: let modifier = (intelligence === 0) ? "Non" : (intelligence &lt;= 2) ? "Animal" : (intelligence &lt;= 5) ? "Animal" : (intelligence &lt;= 8) ? "Low" : (intelligence &lt;= 12) ? "Average" : (intelligence &lt;= 15) ? "High" : (intelligence &lt;= 17) ? "Superior" : (intelligence &lt;= 19) ? "Genius" : (intelligence &lt;= 25) ? "Supra-Genius" : (intelligence &lt;= 30) ? "Deific" : "Uncharted";
Tried the changes, no effect.&nbsp;
1618718873

Edited 1618719008
Kavini
Roll20 Production Team
Marketplace Creator
Sheet Author
Compendium Curator
&lt;input name="attr_Intelligence" type="text" /&gt; &lt;input name="attr_MonsterIntCat" type="text" /&gt; &lt;script type="text/worker"&gt; on("change:monsterintcat change:intelligence sheet:opened", (eventInfo) =&gt; { getAttrs(["Intelligence",], function(values) { const intelligence = parseInt(values.Intelligence) || 0; let modifier = (intelligence === 0) ? "Non" : (intelligence &lt;= 2) ? "Animal" : (intelligence &lt;= 5) ? "Animal" : (intelligence &lt;= 8) ? "Low" : (intelligence &lt;= 12) ? "Average" : (intelligence &lt;= 15) ? "High" : (intelligence &lt;= 17) ? "Superior" : (intelligence &lt;= 19) ? "Genius" : (intelligence &lt;= 25) ? "Supra-Genius" : (intelligence &lt;= 30) ? "Deific" : "Uncharted"; setAttrs({MonsterIntCat : modifier}); }); }); &lt;/script&gt; This appears to work for me, if it doesn't work for you could there be a bug somewhere else on the sheet?
That version worked. There were differences in the upper code I didn't know I needed to change. Things like function to event info and the term const. Very much appreciate the assist. Coding is mostly beyond me. I can learn what I'm shown but have problems figuring out new things. It's one thing to change what is being summoned or changed as to change what is happening behind the scenes. I should be able to use this example you provided to fix a few other codes that aren't working.&nbsp; Can you explain, as you would to a child, why this code is written differently than the earlier one used to assign ability score modifiers? Is it the difference between text and number input?
1618766997
Kavini
Roll20 Production Team
Marketplace Creator
Sheet Author
Compendium Curator
Honestly, I am surprised the first didn't work. The differences between this function and the ones above are almost all stylistic and, in fact, in hindsight I made at least a couple of mistakes. I'll give a brief breakdown of what's happening in this piece of code, so you can follow along. I'm going to include some links for greater clarity. They're all quite short articles providing better technical clarity than I am able to in a forum post. I'd recommend at least reading the beginning of each, or the linked section, but they're not strictly necessary to follow along. Also, this is going to look long and complicated, but it isn't. Well, it isn't complicated, at least. on is a function provided to us by Roll20. In this instance, accepts two arguments, which you can visualize like this: on(argument1, argument2) . The arguments we provide it are a string, containing a list of triggers and a function, that will be executed when one of the trigger requirements are met. For instance, a change to MonsterIntCat triggers us to run the function in the second argument. First Mistake: on is, luckily for my code, case insensitive. This means that monsterintcat and MonsterIntCat are functionally equivalent, but it's still good practice to make sure that these are cased consistently. on("change:MonsterIntCat change:Intelligence sheet:opened"... callbacks are functions we pass as an argument to a function that are then executed by that function. This is only important to us right now in that I will refer to the second argument of the on function as a callback function. eventInfo is a default object that the trigger provides us when the function is run. It contains some contextual information that might be useful to our function. We can access them with dot notation So, for instance, eventInfo.newValue tells you the new value of the changed field. There's a short table here listing the contents. Second Mistake: In this instance, we never use eventInfo, and I only included it as a force of habit. It's needlessly muddying the waters here. You could replace [ (eventInfo) =&gt; { ] with [ () =&gt; { ] or even [ function () { ] and it would be functionality (haha.) equivalent. Which leads me to arrow functions . An arrow function is a slightly different way of defining a function. There are some differences between an arrow function [ () =&gt; {} ] and a regular function [ function() {} ] but in this instance, none of those are relevant, so it's just a stylistic choice. I happen to find arrow functions quicker to write and less visually confusing to read, YMMV. getAttrs is very similar to on . They're both defined by Roll20, both take two arguments. The first argument in this case is an array of "attrs" that we wish to get the values of. The second is a function, but in this case instead of providing us with eventInfo, it provides us with values, which is an object containing the names and values we requested in the first argument. You can imagine it like this: values = { "Intelligence":"10", "OtherExampleAttr":"12", "Etc":"14" } Third Mistake: Again, stylistic, but if I used an arrow function before, I should have used it here, too, for consistency and readability. getAttrs(["Intelligence",], (values) =&gt; { Okay, so now we have our object values which contains the data we want to operate on. Variables requested from Roll20 will often, but not always, arrive to us as a string . It can honestly be quite hard to predict which form they're going to come in, and so it's generally a good idea to convert them into the precise type of variable we want. In this instance, we want a number, and more specifically an Integer . So we define a new variable and use [ parseInt() ] to make it an integer. Defining variables. When defining variables, we have three choices. We can define a let , a const or a var . The rule is this: if you're intending to redefine the value of a variable, use a let. If you're defining a variable once, and it will not change, we use const. There are a few very edge cases to use a var, but a good working rule of thumb is to never use a var. Fourth Mistake: I should have actually made modifier a const. It's defined once, and never redefined. const modifier = (intelligence === 0) ? "Non" : ... Ternary operators. The main difference between my code and the code above is the conditional chain I used to set modifier's value. This is super simple: const value = (condition1) ? value1 &nbsp;&nbsp;&nbsp;: (condition2) ? value2 : (condition3) ? value3 : value4; // Is equivalent to: if (condition1) const value = value1; else if (condition2) const value = value2; else if (condition3) const value = value3; else const value = value4; Simply put, if all you're doing is declaring a variable, a ternary operator is a quicker and cleaner way to write a complicated if/else statement. Again, it's mostly a stylistic preference, but I find the former easier to read. And that's basically it. We use setAttrs to tell Roll20 to update the new value, but this is pretty self explanatory.
Interesting. Thank you for the tips. I am trying to understand it. But when I change it to the following it doesn't work. &lt;script type="text/worker"&gt; &nbsp; &nbsp; on("change:alignment change:lawful change:good change:evil change:chaotic change:neutral1 change:neutral2 sheet:opened", (eventInfo) =&gt; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; getAttrs(["Alignment","Lawful","Good","Evil","Chaotic","Neutral1",Neutral2"], function(values) { &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; const lawful = parseInt(values.Lawful) || 0; const good = parseInt(values.Good) || 0; const evil = parseInt(values.Evil) || 0; const chaotic = parseInt(values.Chaotic) || 0; const neutral1 = parseInt(values.Neutral1) || 0; const neutral2 = parseInt(values.Neutral2) || 0; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; let modifier = (lawful === 2) &amp;&amp; (good === 2) ? "Lawful-Good" : &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; (neutral1 === 2) &amp;&amp; (good === 2) ? "Neutral-Good" : (chaotic === 2) &amp;&amp; (good === 2) ? "Chaotic -Good" : (lawful === 2) &amp;&amp; (neutral2 === 2) ? "Lawful-Neutral" : (neutral1 === 2) &amp;&amp; (neutral2 === 2) ? "Neutral" : (chaotic === 2) &amp;&amp; (neutral2 === 2) ? "Chaotic-Neutral" : (lawful === 2) &amp;&amp; (evil === 2) ? "Lawful-Evil" : (neutral1 === 2) &amp;&amp; (evil === 2) ? "Neutral-Evil" : (chaotic === 2) &amp;&amp; (evil === 2) ? "Chaotic-Evil" : &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; "Uncharted"; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; setAttrs({Alignment : modifier});&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }); &nbsp; &nbsp; }); &lt;/script&gt;
Nevermind, missed a " around Neutral2. D'oh.
Trying to set this up so only pladins of 9th plus level can use this checkbox. &lt;script type="text/worker"&gt; on("change:paladinclass change:smile change:level sheet:opened", function() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; getAttrs(["PaladinClass","Smite","Level"], function(values) { &nbsp; &nbsp; let paladinclass = parseInt(values.PaladinClass)||0; let level = parseInt(values.Level)||0; &nbsp; &nbsp; let modifier; &nbsp; &nbsp; // the scale if (paladinclass &lt;&gt; 1) modifier = 0; if (level &lt;= 9) modifier = 0; &nbsp; &nbsp; setAttrs({Smite : modifier});&nbsp; }); }); &lt;/script&gt;