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

First Sheetworker help

<div class="sheet-wrapper"> <div class="sheet-2colrow"> <div class="sheet-col"> <h3>Attribtes:</h3> <div class="sheet-row"> <div class="sheet-item sheet-thirtypercent"><label>Strength:</label></div> <div class="sheet-item sheet-sixteenpercent"><input type="number" name="attr_str" value="5" /></div> </div> <div class="sheet-row"> <div class="sheet-item sheet-thirtypercent"><label>Gun Recoil:</label></div> <div class="sheet-item sheet-sixteenpercent"><input type="number" name="attr_recoil" value="0" /></div> <div class="sheet-item sheet-thirtypercent"><label>Recoil Mod:</label></div> <div class="sheet-item sheet-sixteenpercent"><input type="number" name="attr_recoilmod" value="0" /></div> </div> </div> </div> </div> <script type="text/worker"> on("change:str change:recoil sheet:opened", function() { getAttrs(["STR","RECOIL","RECOILMOD"], function(values) { let tempstr = parseInt(values.STR); let temprecoil = parseInt(values.RECOIL); let temprecoilmod = parseInt(values.RECOILMOD); if (temprecoil > tempstr) { let temprecoilmod = temprecoil-tempstr; } else { let temprecoilmod = 0; } setAttrs({ "recoilmod": temprecoilmod }); }); }); </script> So I've thrown together a tiny sheet above to mess about with this sheet worker that won't work. I've got a wopnderful Character Sheet & CSS all working fine but I need sheetworkers to help with the following: A PC has a Strength (str) score. Their gun has a Recoil (recoil) score. If a gun's recoil > str, then the player has a penalty (recoilmod = recoil-str) on their attack. Else there is no penalty (recoilmod = 0) But my sheetworker does nothing. I've played with different things. I've moved the script into the <div></div> tags & renamed every attribute and still no effect. Also one of hte help files showed  parseInt(values.RECOIL)||0  so I tried that, but don't understand what the '||0' does. Any help would be appreciated - I assume it's something simple.
1627186002

Edited 1627186913
Oosh
Sheet Author
API Scripter
JavaScript is (almost always) case sensitive - although getAttrs happens to be case insensitive (due to how Roll20 attributes work), you absolutely need to be in the habit of being precise with upper and lower case: str !== STR. So I would change all the uppercase to lowercase to match the attribute names in the HTML, even though getAttrs specifically should still work the way you've written it. You should also provide the number base for your parseInt() function. This is almost always 10, and parseInt will generally assume so, but to avoid nasty bugs make sure you do this: let tempstr = parseInt(values.str, 10); If parseInt() gives you an unexpected base 2 return somewhere in your code, it could take a lot of headscratching to track down. Secondly, logging is your friend. Log everything while you're nailing a function down, then comment out the logging later to avoid drowning in unwanted feedback. If you do this: console.log(`Getting attributes...`); getAttrs(["STR","RECOIL","RECOILMOD"], function(values) { console.log(`Return from getAttrs: `, values) let tempstr = parseInt(values.STR); let temprecoil = parseInt(values.RECOIL); let temprecoilmod = parseInt(values.RECOILMOD); if (temprecoil > tempstr) { console.log(`temp variables: `, tempstr, temprecoil, temprecoilmod); You'll know immediately whether your event listener has fired, and if getAttrs has returned your attributes or not. This will help you find the source of any issue you might have. Finally, this: parseInt(values.RECOIL)||0 Is the javascript OR operator. If the left-hand side of the statement is falsy, the function will attempt to use the right-hand side instead. When used in the context of declaring a variable, like: let myVariable = parseInt(values.flapBoot, 10) || 0 myVariable is declared as the return from the parseInt() function. If this is undefined, null or any other falsy value it will instead take the value of 0. Worth noting that "falsy values" includes the integer 0, so be careful with this in the context of Attributes which can legitimately be 0. In this case it doesn't matter since the fallback value is 0 anyway, but in some cases where 0 is a valid input, you might want to use the nullish coalescing operator instead, which only looks for null & undefined.
1627189407

Edited 1627189932
GiGs
Pro
Sheet Author
API Scripter
To correct a minor error in oosh's post: Oosh said: You should also provide the number base for your parseInt() function. This is almost always 10, and parseInt will generally assume so, but to avoid nasty bugs make sure you do this: let tempstr = parseInt(values.str, 10); If parseInt() gives you an unexpected base 2 return somewhere in your code, it could take a lot of headscratching to track down. This is outdated advice, and is something you really don't need any more, unless you actually are working in a base other than 10. When working on roll20, you never need to state the base, so can simply use let tempstr = parseInt(values.str); Or, even better as Oosh says, let tempstr = parseInt(values.str) || 0; On the subject of case - I've been meaning to test this more thoroughly, but I noticed when answering a recent question that roll20 was treating attribute names as case sensitive, and the worker in that post only actually worked if the case of the attribute matched the way it was defined on the character sheet. This was never the case in the past, so it may be that a recent update has changed the way this works - but I haven't done any thorough testing. Roll20 have been updating sheet workers a lot this year, so that might have slipped through without an announcement. But whether it has or not, Oosh's advice to make sure you make the case of the attributes match the way its defined in the character sheet is good advice. And using logging will tell you if a sheet worker is firing and help track down where the error actually is. Whenever I have a sheet worker that seems to be not working, I do exactly what oosh did: console.log(`Getting attributes...`); getAttrs(["STR","RECOIL","RECOILMOD"], function(values) { console.log(`Return from getAttrs: `, values) Put a log statement immediately after on(change) line, to see if the sheet worker is actually being triggered properly. And after the getAttrs line, so I can look and see exactly what attribute names and values are being grabbed from the sheet. If both of those work properly, that's when the serious debugging starts - but those two find a lot of silly syntax errors and mental failures :)
1627191469

Edited 1627191777
GiGs
Pro
Sheet Author
API Scripter
Here's one error in the code:             let temprecoilmod = parseInt(values.RECOILMOD);             if (temprecoil > tempstr) {                 let temprecoilmod = temprecoil-tempstr;             } else {                 let temprecoilmod = 0;             } when defining a  variable inside a score (here, any set of { } brackets), it only exists within that scopre. So the temprecoilmods created inside the if statement are different variables to the one that is defined when the if starts. That section should be             let temprecoilmod = parseInt(values.RECOILMOD) || 0;             if (temprecoil > tempstr) {                 temprecoilmod = temprecoil-tempstr;             } else {                 temprecoilmod = 0;             } This way the variable defined outside the if statement is being updated properly. This fixes the sheet worker. (The || 0 on defining attributes might not be needed here, since the inputs are defined as number types, but it depends how different browsers handle "" entries - if they always set that to 0 or the default value, as happens on firefox, the ||0 isnt needed in this case).
1627192334

Edited 1627192895
GiGs
Pro
Sheet Author
API Scripter
Unrelated to this question, I just tested the case sensitivity and I think I've found a roll20 bug. Sheet workers are now both case sensitive, and case-insensitive. When doing a getAttrs, the case does not need to match the value defined in the html. The sheet above defines the str attribute with <input type="number" name="attr_str" value="5" /> So in getAttrs you can use either of getAttrs(["str", getAttrs(["STR", But whichever one you use, when later grabbing the attribute, you must use the same case. So if you use getAttrs(["STR", you must grab it with values.STR It will fail if you try to use values.str even though that's the case actually defined in the html. I am pretty sure - but not 100% certain - that this is new behaviour, and looks very much like a bug to me.
Aha! Many things now happen! Functionality can happen&amp; my sheet can evolve! Thankies. My last question is where does the console log appear/go? As for the case sensitive part, I thought it was something you had to do after reading the wiki - <a href="https://wiki.roll20.net/Sheet_Worker_Scripts" rel="nofollow">https://wiki.roll20.net/Sheet_Worker_Scripts</a> this part here, I'd already ready you should keep your variables lower case, but then this code made it appear like you had to make them upper case in the sheet worker. I figured you needed lower case attributes in the sheet but that the worker needed upper case ones. It left me very confused but I tried my best to learn from what was shown. Who manages the wiki - because maybe this is something that could be edited to not present such a misleading thought?&nbsp; &lt; script type = "text/worker" &gt; on ( "change:siz change:con sheet:opened" , function () { &lt;!-- Lower case Variables --&gt; getAttrs ([ "SIZ" ,"CON"], function (values) { &lt;!-- Transformed into upper case Variables? --&gt; let siz = parseInt (values.SIZ) | | 0 ; &lt;!-- Upper case Variables --&gt; let con = parseInt (values.CON) | | 0 ; &lt;!-- Upper case Variables --&gt; let hp = siz + con; setAttrs ({ "hitpoints" : hp }); }); }); &lt;/ script &gt;
1627202211
GiGs
Pro
Sheet Author
API Scripter
Anyone can edit the wiki. But notice there's nothing wrong with that example. Remember, before the finding I made above this was the situation: In sheet workers, attribute names are case in sensitive - you can use whatever capitalisation you like, and it doesnt matter whether it matches the case used in the sheet's html. The only important thing, which you must do, is use lower case on the on(change) line. Even if the attribute is originally defined as upper case, you must use lower case on the on(change) line. This is still true. Command advice because of this was always to use lower case everywhere, just to avoid accidentally typing the wrong case on the on(change) line. That's still good advice. So there's nothing wrong, per se, with the example on the wiki, but you're right a note should be there encouraging people to use lower case everywhere, if such a note doesnt exist, and the examples should be modified to use that. Regarding console.log - while on your campaign page, type f12, and it'll open the browser console (if youre using firefox or chrome, which you should be). Click the console tab, and you'll see any log messages there.
1627202729
GiGs
Pro
Sheet Author
API Scripter
I've edited that example to use lower case attribute names, and added a recommendation to always use lower case under the "other things" title.
1627209139
Oosh
Sheet Author
API Scripter
GiGs said: To correct a minor error in oosh's post: Oosh said: You should also provide the number base for your parseInt() function. This is almost always 10, and parseInt will generally assume so, but to avoid nasty bugs make sure you do this: let tempstr = parseInt(values.str, 10); If parseInt() gives you an unexpected base 2 return somewhere in your code, it could take a lot of headscratching to track down. This is outdated advice, and is something you really don't need any more, unless you actually are working in a base other than 10 Huh, wasn't aware of that - good to know!
Thanks all for the help here &amp; the lessons. I learned a lot &amp; now I can achieve a lot more :) And thankies for updates to the wiki because other people might be confused too.
1627225401
Andreas J.
Forum Champion
Sheet Author
Translator
GiGs said: In sheet workers, attribute names are case in sensitive - you can use whatever capitalisation you like, and it doesnt matter whether it matches the case used in the sheet's html. The only important thing, which you must do, is use lower case on the on(change) line. Even if the attribute is originally defined as upper case, you must use lower case on the on(change) line. This is still true. Command advice because of this was always to use lower case everywhere, just to avoid accidentally typing the wrong case on the on(change) line. That's still good advice. Yeah, these variations on different parts of character sheets on how to reference character attributes have long since made me use lowercase names in every part of the sheet, to keeps things uniform &amp; to reduce risk of having bugs from incorrect capitalization and stuff. Now and then I've updated older wiki examples to use lowercase names in examples for the same reason. Oh and this isn't even accounting for APIs, no idea if they are case-sensitive to attribute names on sheets, but cant hurt if everything is lowercase to begin with. Kimbo , remember to make next character sheet related thread in the char sheet forum, this subforum is for the Roll20 API (and not same thing the sheetworkers). Makes it less likely for other sheet authors to miss, if posted in the right place :D