- Anatomy of a Sheet Worker
- Events, and watching Attributes
- Variables – How to Name Things
- Arithmetic in Sheet Workers
- What If? in Sheet Workers
- JavaScript Objects
- Getting Loopy With JavaScript
- Logging in the Browser Console
- Strings, Arrays, and Loops
- Asynchronicity and Things to Avoid With Loops
- Changes and the eventInfo Object
- Action Buttons
- setAttrs and Saving Attributes
- Castle Falkenstein Design – Sheet Workers
- The Perils of Sheet Worker Functions
- The Script Block and Identifying Characters
- Arrays and Dropdowns
- Undefined and Other Error Values
- The Ternary Operator – The One-Line If
- Template Literals
- Functions and the Fat Arrow
- Strings in Sheet Workers
- A Sheet Worker Reprise
There’s a lot you can do with JavaScript, but you are usually concerned with one thing: updating an attribute value. For that, you need to be able to do two things: perform arithmetic and work with strings. We’ll deal with arithmetic in this post. But we’ll touch on a few more advanced things too.
In Anatomy of a Sheet Worker, we learned how to collect attributes, and we learned a bit more about how to Create Variables, and the difference between Numbers and Strings. Now we can do some stuff.
Doing Stuff
The simplest thing is to perform arithmetic of various sorts. Here are some different calculations:
const move = dex + agl;
const move = dex *2 + agl;
const move = (dex + agl) *2;
const move = dex/10 + agl/10;
Code language: JavaScript (javascript)
You can add (+), subtract (-), multiply (*), divide (/), and more. But addition and division are usually all you need. But you also can do this:
dex += 5;
agl -= dex;
Code language: Markdown (markdown)
The +-, -=, *=, and /= syntaxes are shorthand. Instead of typing this:
dex = dex +5;
Code language: Markdown (markdown)
you can simply type:
dex += 5;
Code language: Markdown (markdown)
Whenever you find yourself altering a value, you can use syntax like += or *=. Javascript knows that you are modifying the original value by the modifier.
There is a difference between += and =+, but it’s very subtle and pretty much always irrelevant in sheet workers, so you can ignore it and use either order.
You often round an attribute (to the nearest, rounding down, or rounding up). This is where the math object comes in. You can use Math.round (round to nearest), Math.floor (round down), or Math.ceil (round up):
const move = Math.round(con/10 + str/10);
const str_bonus = Math.floor(str/2) -5;
const income = Math.ceil(wage *100) / 100 ;
Code language: JavaScript (javascript)
The Math object has a bunch of functions attached to it, and they operate on anything in the brackets.
The middle example calculates a stat bonus appropriate for games like D&D (stats of 10-10 have 0.)
The last example rounds to hundredths. So you might want to know (say) dollars, and with cents as decimals. So if you start with something like 17.2465, it will be rounded to 17.25. You never have more than 2 digits after the decimal point.
Calculations can often lead to the same result in different ways.
const move = Math.round((dex + agl) /10);
const agl_bonus = Math.floor((agl-10)/2) -5;
Code language: JavaScript (javascript)
Again they are two different ways of calculating the same result. Just do what feels right to you.
The Max and Min functions are very useful, and I use them maybe more often than I use the rounding functions. Each works the same way – supply a group of numbers separated by commas and it’ll tell you the largest or smallest.
const largest_stat_value = Math.max(dex, agl);
const smallest_stat_value = Math.min(dex, agl)
Code language: JavaScript (javascript)
They are great for limiting values. Say you want to add dex and agl, but the minimum score must be 0:
const sum_of_dex_and_agl = Math.max(0, dex + agl);
Code language: JavaScript (javascript)
Each value to evaluate must be separated by a comma, but you can include calculations in each ‘value’.
You can also nest max and min (and any other function). Say the sum must be at least 0, but no higher than 30, you could do:
const sum_of_dex_and_agl = Math.min(30, Math.max(0, dex + agl));
Code language: JavaScript (javascript)
Here Math.max has been nested inside Math.min. When doing this kind of thing, make sure you keep the number of brackets right, and remember to use min and max correctly. Min gives you the smallest number of the set, and max gives you the largest number. I frequently do these the wrong way around, and have to correct myself!
When you want to create a random number, you have a special ability on roll20 – you can use the dice function. But that’s a bit complex (and will be covered later, under Custom Roll Parsing). In the meantime, if you want to create a random number, you can use the Math.random() function.
This function generates a number between 0 and 0.999999999 (recurring), so you need to multiply by a value to get a dice value, then add 1 otherwise it’ll start at 0. For example, a d6 would be
const d6 = Math.floor(Math.random() *6) +1;
Code language: JavaScript (javascript)
You need to round off because it generates numbers like 0.453267, and you need to round down, and then add 1.
You can use this to create a dice roll function, and we’ll come back to that in the post on loops.
Math.sign gives you the sign (whether a number is positive or negative). This is handy when constructing strings. By default a number will be shown like 17 if positive, and -17 if negative. But you might want positive numbers to be shown like +17.
To understand this needs if statements, and ternary operators, which are covered later, so this is shown as an example without much explanation for now.
This is easily done with Math.sign. Math.sign gives a value of -1 for negative values, 1 for positive values, and 0 for 0 or -0. So think about what you want to happen, and construct an if statement that works for that:
const score = int(v.score);
let with_sign = score;
if (Math.sign(score) >= 0) {
with_sign = "+" + score;
}
Code language: JavaScript (javascript)
This example uses let in place of const because the value of the variable might change.
It also uses + to add two elements in a string, so if the score has a value of 17, it will be shown as +17.
And that is of course wrapped in an if statement. You’ll learn more about those in the next post.
The Math object has a lot of useful functions buried in it (and some that are useless for character sheets). Here’s a list of Math functions I have found useful, most of which have already been mentioned:
- Math.round: Round to nearest whole value.
- Math.ceil: Round up.
- Math.floor: round down.
- Math.max: pick the largest number out of a group.
- Math.min: pick the smallest number.
- Math.random: Generate a random number. handy for creating your own dice functions.
- Math.sign: report the sign of a number. positive = 1, negative = -1, 0 = 0.
- Math.abs: Convert a number to its absolute value, removing its sign.
- Math.pow: calculate the power of a number. Math.pow(number, 2) gives the square of a number, and Math.pow(number, 0.5) gives the square root.
Conclusion
In this post, we described how to perform simple arithmetic. In the next post, we’ll cover conditional calculations – using if statements. You’ll find these very, very useful.