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

Sheet Worker Conditional Statement

April 17 (5 years ago)

Edited April 17 (5 years ago)

Hey all!

I am trying to introduce conditional statements into my Sheet Worker! What am I doing wrong here? I simply want the value X (resist_spellSlot_total) equal a value of 1 should its value be LESS THAN OR EQUAL TO a value of 0. Essentially I do not want a negative number or 0.


on("change:resist_spellSlot_total change:Wisdom change:Resist_rating change:Resist_armor sheet:opened", function()
{
    getAttrs(['resist_spellSlot_total', 'Resist_rating', 'Wisdom', 'Resist_armor'], function(values)
    { 
            if (resist_spellSlot_total >= 1)
            {
              setAttrs({ resist_spellSlot_total: +Wisdom + +Resist_rating });
            }
            else
            {
              setAttrs({ resist_spellSlot_total: + 1 });
            }    
    });
});


April 17 (5 years ago)
GiGs
Pro
Sheet Author
API Scripter

There are a few issues.

The first is the change line: attributes on this line must always in lower case. It doesnt matter what they are in reality, you must always write them in lower case here. So that line should be

on('change:resist_spellslot_total change:wisdom change:resist_rating change:resist_armor sheet:opened', function()

(Btw, I used single quotes, ', instead of double quotes "  - it doesnt matter which you use. Its a personal preference.)


Then, sheet workers don't know anything about attributes. That means when you write this

if (resist_spellSlot_total >= 1)

the worker has no idea what this "resist_spellSlot_total" is

All the attributes in the getAttrs line, are stored in the values object, here:

getAttrs(['resist_spellSlot_total', 'Resist_rating', 'Wisdom', 'Resist_armor'], function(values)

That line basically says: "scan the character sheet, and grab the names and scores of resist_spellSlot_total, Resist_rating, Wisdom, Resist_armor, and store them in the object called values."

So now you have them in the values object, to actually use them, you have to read them from that object. Which you do like this:

let resist_spell_total = values.resist_spellSlot_total;

The name after let is a variable. It's a temporary name you create, to hold this attribute value. The actual name doesnt matter, it could just as easily be

let rsst = values.resist_spellSlot_total;

But now that you have it you can use it like so

if (resist_spell_total >= 1)

This looks like it will work, but there's another problem.

attributes in character sheets are stored as text, not numbers. So that attribute might have a score of, say "7". This is different from 7. Note the quotes.

You need to convert it into a number, so that comparisons like >=1 work. There's several ways to do that. A popular way is to use the parseInt function, like so

let resist_spell_total = parseInt(values.resist_spellSlot_total) || 0;

This will get the value of that attribute, and if it is something that cant be converted to a number, will return the value 0 (the number right at the end). This is important because people might enter a word instead of a number, and parseInt will crash the script if it encounters a word it cant convert into a number. The || 0 at the end stops that happening.

It looks like you have seen other ways to convert an attribute to a number. You can do this:

let resist_spell_total = +values.resist_spellSlot_total || 0;

Putting a + at the start will force roll20 to try to treat it as a number. You still need the ||0 at the end in case its not a number.


With these things in mind, and one extra thing I'll explain after, here's how I would rewrite your worker:

on('change:resist_spellslot_total change:wisdom change:resist_rating change:resist_armor sheet:opened', function()
{
    getAttrs(['resist_spellSlot_total', 'Resist_rating', 'Wisdom', 'Resist_armor'], function(values)
    { 
        let resist__total = +values.resist_spellSlot_total||0;
        let wisdom = +values.Wisdom || 0;
        let resist = +values.Resist_rating || 0;
        let armor = +values.Resist_armor || 0;
        let result = 0;
        if (resist__total >= 1)
        {
            result =  wisdom + resist;        }
        else
        {
            resist = 1;
        }    
        setAttrs({ resist_spellSlot_total: result});
    });
});

Notice I've declared all the attributes at the start, with let statements. You dont need to do that, but when you are new to script writing, it's a really good habit to get into. When you have inevitable problems, having the attributes declared as variables like this makes it easier to examine their values (through techniques not covered here), and find out where the error is happening. It's a bit more writing, but it;s worth doing.

It also makes doing things like this much easier:

(+values.Wisdom||0) + (+values.Resist_rating ||0)

You dont ened the +'s at the start, once you have declared the variables earlier, nor do you need those brackets. Thats what your original expression should have looked like, btw. But the version i posted above avoids that ugliness.

Finally noticed I created a result variable, and used that instead of setAttrs inside the if statements? It's really important to get in the habit of keeping the number of times you use setAttrs to as few as possible, ideally one.  Now in this script, it doesnt matter since the setAttrs is inside an if statement; each time it is run, only one setAttrs will run anyway. But its very easy to write bad scripts that have too many setattrs calls (which will slow your sheet down), so its important to get into the habit of writing code with just one setAttrs per worker.


There you go, hope that helps. And hopefully I havent made any typos, so it actually works, lol.


One thing i notice, you have resist_armour on the getAttrs line, but its not used in the worker at all. Is there something missing?

The next ting to notice 

April 17 (5 years ago)

Edited April 17 (5 years ago)

WOW! Thanks @GiGi! This was a super big help! I really appreciate how well you detailed and explained the issues!

I inserted your reworked version, but alas however the script is not working atm 'T'o'T'


What I am trying to affect is...

<input type="number" class="sheet-textbox_2" name="attr_resist_spellSlot_total" value="0" readonly/>


EDIT

To be more specific, the attr_resist_spellSlot_total is only remaining at a value of 0 and will not dynamically change?

April 17 (5 years ago)
GiGs
Pro
Sheet Author
API Scripter

Okay I'm looking closer at what your code actually does, and I think its probably not set up correct. At the moment, it responds to changes in the resist_spellSlot_total (among others), performs a calculation, then sets resist_spellSlot_total, which triggers the event again because that value changed. So, you probably dont want that on the change line.

Can you post the code for the wisdom and resist_rating inputs?

Also do you have the sheet worker in a properly formed script block, which looks like

<script="text/worker">


</script>
April 17 (5 years ago)
GiGs
Pro
Sheet Author
API Scripter

This line is very suspect too

if (resist__total >= 1)

Not in terms of the sheet worker, but in terms of how you want this calculation to work. You are calculating its value, but basing that value on its value. It's circuitous, and seems like its probably wrong.

Can you explain what this calculation represents, and how it is calculated? don't mention the roll20 character sheet at all. Imagine we are playing at your game table,  and explain what the rulebook would say to me about this calculation.

HEY!


Based off of your last two posts, I got it to work with:

on(' change:wisdom change:resist_rating change:resist_armor sheet:opened', function()
{
    getAttrs(['resist_spellSlot_total', 'Resist_rating', 'Wisdom', 'Resist_armor'], function(values)
    { 
        let wisdom = +values.Wisdom || 0;
        let resist = +values.Resist_rating || 0;
        let resist_total = wisdom + resist || 0;
        let result = 0;
        if (resist_total >= 1)
        {
            result =  wisdom + resist;        }
        else
        {
            result = 1;
        }    
        setAttrs({ resist_spellSlot_total: result});
    });
});
April 17 (5 years ago)
GiGs
Pro
Sheet Author
API Scripter

Great!

Just for neatness you want to remove that unnecessary spaces at the start in this line

on('change:wisdom change:resist_rating change:resist_armor sheet:opened', function()

It isnt a problem here, but you want to be careful about the syntax - it can sometimes be an issue.