Sheetworker examples for Non-programmers
From Roll20 Wiki
Page Updated: 2022-04-06 |
This is related to Editing(coding) Character Sheets, which require Pro info to be able to use.Main Page: Building Character Sheets |
While the majority of Roll20's character sheets are written using only HTML and CSS, there is often need for "sheetworker scripts"(AKA just "sheetworkers) to either simplify complicated HTML, or add more advanced functionality to a character sheet. These are written in JavaScript, with a few unique features made for Roll20's character sheets.
Character Sheet Development
Getting Started
- Using Custom Sheets
- Building Sheets
(Main Page) - Glossary
- Code Restrictions
- Best Practice
- Common Mistakes
- Tutorials
- Examples, Templates
- Pattern Libraries
- HTML & storing data
- CSS & Styling
General
- Updates & Changelog
- Known Bugs
- Character Sheet Enhancement(CSE)
- Custom Roll Parsing
- Legacy Sheet(LCS)
- (upcoming) Beacon SDK
Reference
- Buttons
- Repeating Sections
- Sheetworkers
- Roll Templates
- sheet.json
- Translation
- Auto-Calc
- Advanced
- All SheetDev Pages
Tools & Tips
Other
For those of us "non-programmers", the examples given on the Sheet Worker Scripts page may be less than exhaustive. This page was created to help better explain how to use sheetworkers in your character sheets.
This page may or may not contain specific examples of sheetworker code, however the information provided is invaluable to learning how to implement sheetworkers into your character sheet. JavaScript: First Steps by Mozilla is a good starting point to get familiar with JavaScript if you want to understand some of the things better.
Contents |
Autocalc Fields and Sheet Workers
(credit: GiGs) A common pitfall is to try to combine autocalc fields and sheet workers. Try not to do this.
First, autocalc fields need to be set as disabled, and sheet workers cannot edit a disabled input. If you want to use a sheetworker to create a value that is displayed but cant be edited, set the input to readonly. this looks the same as disabled, and cant be edited, but sheetworkers can update it.
Second, don't try to grab autocalc fields in a sheet worker. The getAttrs function in a sheet worker will grab the text of an autocalc field, not the number it resolves to. If the attribute is something like "[[@{STR} + @{DEX}]]" then getAttrs will give you a value of "[@{STR} + @{DEX}]]" and not 23 or 30 or whatever number you are expecting.
So, you need to recreate that formula in the sheet worker anyway, by using getAttrs to grab STR and DEX values, and then adding them together within the worker. Alternatively, replace the initial autocalc field with a sheet worker.
Because of these two facts, once you start using sheet workers, you tend to abandon autocalc fields. They dont interact well. You can still use autocalcs for standalone attributes that dont affect anything else, but sheet workers for everything else.
Sheet Worker Tutorial
(credit: GiGs)
All Sheet Workers have a common structure, four steps that must happen in order:
- Event Trigger
- Get Attributes
- Do the Work
- Update the Character Sheet
Event Trigger
Sheet Workers are triggered by something changing on the character sheet. Triggers are covered fully under Sheetworker - Events. On this page we will mainly be looking at the change event. Imagine we have a game where characters have a Hit Point attribute, that is calculated by adding two stats, SIZ and CON together. let's build a sheet worker to calculate that.
First we need to build the trigger:
on("change:siz change:con sheet:opened", function() { });
That's pretty straightforward. Notice that the attribute names are lower case. Confusingly, attributes must always be in lower case when on the event trigger line, but their case doesn't matter anywhere else. Roll20 attribute names are case-insensitive, but must always be lower case on the event trigger line.
You can have as many change:attribute_name statements as you need for the script.
Note: sheet:opened tells the worker to run every time the character sheet is opened. This is optional, but is handy to keep a sheet properly updated.
Get Attributes
So an attribute changes, and its sheet worker is triggered. Now, you must collect the value of all needed attributes. The sheet worker does not automatically know anything about the rest of the character sheet: each sheet worker only knows what data you collect for it.
This is where the getAttrs function comes in.
getAttrs(["SIZ","CON"], function(values) { let siz = values.SIZ; let con = values.CON; });
getAttrs has two steps: the first line, the function line, is where you grab the attributes. They are stored in an data object, whose name is defined after the word function. In this case, values. You can call it whatever you want, most people use values, or just v.
This object is a Javascript Object, and you can read up on that elsewhere. But all you really need to know is, it contains the names and values of the attributes you declared - in this case, SIZ and CON.
Since this object was named values, you get SIZ by using values.SIZ, and con by using values.CON. And that's exactly what we do above - we define two variables, one for each attribute, and assign the values of those attributes.
There is a complication. If you doing math with the stats, you need to convert them into a number. If you don't, you can get an error. There are several ways to do this, a common one is to use parseInt (for whole numbers) or parseFloat (for fractional or decimal numbers). Here's what that looks like:
getAttrs(["SIZ","CON"], function(values) { let siz = parseInt(values.SIZ)||0; let con = parseInt(values.CON)||0; });
That looks a lot more complicated, but don't worry, you dont need to understand it. Just copy it. For the record, the end bit ||0 sets a default of 0. So if the SIZ attribute contains nothing, or text, it will be treated as a value of 0 and an error is avoided.
Do The Work
Each Sheet Worker is designed to do something. Sometimes that will be very complicated, other times like this one it will be very simple. We are just adding two stats, so that looks like this:
let hp = siz + con;
I did say it was simple.
Update the Character Sheet
Now we have the hit point total, we need to actually save it to the character sheet. For that we need the setAttrs function. Assuming the attribute is called hit_points, that would look like this:
setAttrs({ hitpoints: hp });
Note: some sheet workers will update multiple attributes. You seperate them with commas. That would look like this:
setAttrs({ hitpoints: hp, anotherstat: anotherscore });
The final attribute must not have a comma - that breaks the script.
5. Putting It Together
So we now have all the steps needed to put the worker together.
on("change:siz change:con sheet:opened", function() { //sheetworker triggers on any changes to the "siz" or "con" attribute, or when sheet is opened. getAttrs(["SIZ","CON"], function(values) { //get the values for the two attributes, so they can used. let siz = parseInt(values.SIZ)||0; let con = parseInt(values.CON)||0; //saves the current values of the two attributes on two temporary variables, which then can be used easily in calculations. let hp = siz + con; // defines new variable, based on the sum of the two attributes setAttrs({ hitpoints: hp // changes the "hitpoints" sheet attribute to be the value of our temporary variable "hp" }); }); });
Finishing Thoughts
This is a very simple example, but steps 1, 2, and 4, are basically the same in all sheet workers. Once you understand the basic structure, you can easily copy those, and just do the working (section 3). The Sheet Worker Snippets will contain more examples for you to copy.
See Also
- Sheet Worker Snippets
- Universal Sheet Workers - a function that can handle a bunch of similar sheetworkers
- RepeatingSum - sum numbers from a repeating section
- Sheet Worker Optimization(Forum) by Scott C.
- How to integrate table of stats into a sheet(Forum) by GiGs
- Introduction to JavaScript - MDN web docs