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

Help Streamline/Optimize Sheetworker Script

December 08 (7 years ago)
In my D&D 3.5 custom sheet I track up to four classes and 52 skills. I am tracking skill points spent by class (for class/cross-class purposes). To display unspent skill points by class (skillpoints01_unspent, skillpoints02_unspent, etc.), I have the following "brute force" sheetworker in my sheet four times (once for each class: class01, class02, etc.). This code works, but it is ugly and I am sure it could be more economical and efficient and have it check each class and skill all in one go, but Javascripting is cross-class for me. :-)

I am sure I need to use let and make arrays of the skillnames and an array of class01-class04, and use map and loop through. I also have The Aaron Sheet included and that can probably help make a running total through the loops.

For the sample code below I have eliminated most of the skills and listed just for class01 to keep the code brief. Any advice/assistance/suggestions/scriptomancy appreciated!

on("sheet:opened change:character_level change:acrobatics_class01_points \
change:appraise_class01_points change:bluff_class01_points change:climb_class01_points \
change:craft1_class01_points change:craft2_class01_points change:craft3_class01_points", function() {
  getAttrs(["class01_skillpoints", "acrobatics_class01_points", "appraise_class01_points",
  "bluff_class01_points", "climb_class01_points", "craft1_class01_points",
  "craft2_class01_points", "craft3_class01_points"], function(values) {
    setAttrs({
        "skillpoints01_unspent": (parseInt(values["class01_skillpoints"],10) || 0) - (
            (parseInt(values["acrobatics_class01_points"],10) || 0) +
            (parseInt(values["appraise_class01_points"],10) || 0) +
            (parseInt(values["bluff_class01_points"],10) || 0) +
            (parseInt(values["climb_class01_points"],10) || 0) +
            (parseInt(values["craft1_class01_points"],10) || 0) +
            (parseInt(values["craft2_class01_points"],10) || 0) +
            (parseInt(values["craft3_class01_points"],10) || 0)
            )
        });
    });
});
December 08 (7 years ago)
The Aaron
Pro
API Scripter
The Aaron Sheet only helps with Repeating Sections right now.  Something like this might help:
const classes = [ '01', '02', '03', '04' ];
const skills = [ 'acrobatics', 'appraise', 'bluff', 'climb', 'craft1', 'craft2', 'craft3' ];

const skillAttrs = _.map(classes,(c)=>_.map(skills, (s)=>`${s}_class${c}_points`));
const skillEvents = _.map(skillAttrs,(a)=>`change:${a}`);
const pointsAttrs = _.map(classes,(c)=>`class${c}_skillpoints`);

on(`sheet:opened ${skillEvents.join(' ')}`, function() {
  getAttrs(Array.concat(skillAttrs,pointsAttrs), (values) =>{
    let update = {};
        _.each(classes, (c)=>{
            update[`skillpoints${c}_unspent`]=(parseInt(values[`class${c}_skillpoints`],10)||0) - _.reduce(
                _.map(skills, (s) => parseInt(values[`${s}_class${c}_points`],10)||0 ),
                (m,p) => m+p,
                0);
        });
    setAttrs(update);
  });
});

Note that you might need to replace all the `${stuff}_${other}` things with traditional stuff+"_"+other type things. 


December 09 (7 years ago)
That's what I am talking about. That code is about 10% the length of what I have now. Many, many thanks, TheAaron! I will test this out later today! :-)
December 09 (7 years ago)
The Aaron
Pro
API Scripter
Cheers. =D
December 09 (7 years ago)
Jakob
Sheet Author
API Scripter
The only issue I have with this is that it's using Underscore, not native map() and forEach() and reduce() - but that's a matter of opinion :).
December 09 (7 years ago)
Hmmm... not working. When you say

The Aaron said:
Note that you might need to replace all the `${stuff}_${other}` things with traditional stuff+"_"+other type things.
Do you mean I should do this?
const skillAttrs = _.map(classes,(c)=>_.map(skills, (s)=>`${s} + '_class' + ${c} + '_points'`));
December 09 (7 years ago)
Jakob
Sheet Author
API Scripter

Rabulias said:

Hmmm... not working. When you say

The Aaron said:
Note that you might need to replace all the `${stuff}_${other}` things with traditional stuff+"_"+other type things.
Do you mean I should do this?
const skillAttrs = _.map(classes,(c)=>_.map(skills, (s)=>`${s} + '_class' + ${c} + '_points'`));

I wouldn't replace anything like that at all - but when you do it like this, you'd use
const skillAttrs = _.map(classes,(c)=>_.map(skills, (s)=> s + '_class' + c + '_points'));
The following expressions are equivalent:
s + '_class' + c + '_points'
`${s}_class${c}_points`
December 09 (7 years ago)
The Aaron
Pro
API Scripter
The back ticket ` strings are called Template Literals: https://developer.mozilla.org/en-US/docs/Web/JavaS...

They're really great, the only reason I mentioned the possibility of replacing them is because they might not be supported on older browsers (Any of the ones Roll20 supports should be fine, but some people use other browsers anyway.  CanIUse.com shows IE11 and some mobile browsers not supporting them.
December 09 (7 years ago)
The Aaron
Pro
API Scripter

Jakob said:

The only issue I have with this is that it's using Underscore, not native map() and forEach() and reduce() - but that's a matter of opinion :).

Yeah, I almost removed those, but they're really handy, known to be included, and I don't have to look up the syntax. =D
December 09 (7 years ago)
The Aaron
Pro
API Scripter

Rabulias said:

Hmmm... not working. When you say
So, are you getting an error?
December 09 (7 years ago)

Edited December 09 (7 years ago)
No error message that I can see in the console. I console.log()'d some things and I can see that skillEvents is not getting created properly, generating:

change:acrobatics_class01_points,appraise_class01_points,bluff_class01_points,climb_class01_points,
craft1_class01_points,craft2_class01_points,craft3_class01_points,change:acrobatics_class02_points,
appraise_class02_points,bluff_class02_points,climb_class02_points,craft1_class02_points,
craft2_class02_points,craft3_class02_points,change:acrobatics_class03_points,appraise_class03_points,
bluff_class03_points,climb_class03_points,craft1_class03_points,craft2_class03_points,craft3_class03_points,
change:acrobatics_class04_points,appraise_class04_points,bluff_class04_points,climb_class04_points,
craft1_class04_points,craft2_class04_points,craft3_class04_points

The change: directive is just at the beginning of each set per class, not on each skill.

December 09 (7 years ago)
Also, general sheetworker question: I assume I can't use the same variable names elsewhere in sheetworkers, right?

If I use let skills = or const skills = here, another block of code with let skills = will cause problems?
December 09 (7 years ago)
The Aaron
Pro
API Scripter
Ah!  Replace with this line:
const skillAttrs = _.flatten(_.map(classes,(c)=>_.map(skills, (s)=>`${s}_class${c}_points`)));
December 10 (7 years ago)

Edited December 10 (7 years ago)
Jakob
Sheet Author
API Scripter

Rabulias said:

Also, general sheetworker question: I assume I can't use the same variable names elsewhere in sheetworkers, right?

If I use let skills = or const skills = here, another block of code with let skills = will cause problems?

Yes, if you also use declare them globally (not within a function). Declaring them again within another function is fine. There are ways to encapsulate this definition to not expose the variables to the global scope, if you need to use the same variable names in another context.

On the plus side, it will give a Syntax Error rather than fail silently or just use one value over the other (as it would when using var). So it's actually quite easy to detect if you check your code for syntax errors using some kind of linter.
December 12 (7 years ago)
Wahoo! It's working great! Many thanks again, TheAaron! I did need to rename the consts; thanks for the word on declaration, Jakob.

Any easy summary/reference on declaring them globally vs encapsulating them? I can see some of these being available globally in multiple sheetworker functions (like the array named "skills" that lists all 52 skills so I don't have to copy it over and over again). Others I would want to use solely in one function without worrying about using the same array name elsewhere.
December 12 (7 years ago)
The Aaron
Pro
API Scripter
const and let are block scoped, so you could just put a block around the ones you want to share the definition:
const skills=... // everyone

{
  const classes=... // this block 
  on(‘change:thing1...
  on(‘change:thing2...
}

{
  const classes=... // this block
  on(‘change:thing3...
}