Castle Falkenstein Design – Sheet Workers

I created the Castle Falkenstein sheet to act as a tutorial. My original plan was as I completed the guide for each section (HTML, CSS, Sheet Workers, Repeating Sections, RollTemplates, and Translations), I would show my work upgrading the sheet. But someone else has gone in and added translations (against my request), and the sheet can no longer be used as a tutorial the way I intended. The HTML sheet has too much distracting stuff in it, not to mention the early addition of a translation file which probably wouldn’t match my original intention.

I understand the need for translations for the sheet. I was delayed working on the sheet for health reasons for most of last year, so I sympathise with the impatience to get it working for different language users. It’s flattering, if frustrating, that someone was so eager to add this element.

The sheet doesn’t need much work done for sheet workers, and that section is pretty much isolated from the rest of the sheet, so I can add sheet workers easily enough. After that, I’ll abandon the sheet with bittersweet feelings, and leave it open for the community to do what they want with it.

Script Block

When adding sheet workers, the first thing you need to do is add a script block. This will contain all your sheet workers. It is very simple and looks like this, added to the end of your html file:

<script type="text/worker">
   /* all sheet workers go between the two script lines */



</script>Code language: JavaScript (javascript)

Wound Boxes

The sheet has a Current and Maximum Health. At the moment, it is easy for the current health to exceed the maximum, and be reduced below zero. We’ll add a sheet worker to constrain current health between those two limits. The inputs look like this:

<input type="number" name="attr_wounds" class="no-spinners" value="0">
<input type="number" name="attr_wounds_max" class="no-spinners" value="0">Code language: HTML, XML (xml)

Whenever the wounds_max changes, we want to change the current wounds. And whenever current wounds changes, we want to make sure it is not above the maximum.

on('change:wounds', function() {
    getAttrs(['wounds', 'wounds_max'], function(values) {
        const current = +values.wounds || 0;
        const max  = +values.wounds_max || 0;
        if (current > max ) {
            setAttrs({
                wounds: wounds_max,
                {silent: true}
            });
        }
    });
}); Code language: JavaScript (javascript)

With this worker, we get the current value and the max value. We do a simple check if the current wounds are above the maximum, and if so, set the new score.

One complication: Let’s say max wounds are 10 and current wounds are set to 11. This change would be detected, triggering this worker, and wounds would be set to 10. But, in turn, that change would be detected, and cause the sheet worker to fire again. Silent:true stops that.

Now we have to decide what happens when max changes. If the current is less than equal to the max, lets increase it. If max drops below the current, let’s drop the current to max. So we have this sheet worker.

on('change:wounds_max', function() {
    getAttrs(['wounds', 'wounds_max'], function(values) {
        let current = +values.wounds || 0;
        const max  = +values.wounds_max || 0;
        if(max < current || current > max) {
            setAttrs({
                wounds: wounds_max,
                silent: true
            });
        }
    });
});Code language: JavaScript (javascript)

We could leave it there, but looking at the if statement and the contents, it’s clear that these two sheet workers do something very similar. So lets combine them.

on('change:wounds change:wounds_max', function() {
    getAttrs(['wounds', 'wounds_max'], function(values) {
        let current = +values.wounds || 0;
        const max  = +values.wounds_max || 0;
        if(max < current || current > max) {
            setAttrs({
                wounds: wounds_max,
                silent: true
            });
        }
    });
});Code language: JavaScript (javascript)

That took no effort at all.

After testing, we realise that if max increases, current does not increase – which it should. To solve this, we would need to use eventInfo, and check if the max increased, But unfortunately, the sandbox was bugging out and failing to show newvalue and previousValue, so we couldn’t include that at the time of writing. The current code is still an improvement of the old code, but now if the max increases, players and GMs will have to decide if the current should increase and apply it manually.

Currency Calculation

This is an easy one. At present, the sheet uses an autocalc to calculate the total value of pounds, shilling, and pence. This is the original code for the section:

<h4 title="click me to reveal valuables">Treasury</h4>
<span>£</span>
<input type="number" name="attr_pounds" value="0" class="no-spinners" title="pounds">
<span>&nbsp;</span>
<input type="number" name="attr_shillings" value="0" class="no-spinners" title="shillings (20/pound)">
<span>/</span>
<input type="number" name="attr_pence" value="0" class="no-spinners" title="pennies (12/shilling)">
<span>d = £</span>
<input type="number" name="attr_money" value="round(250*(@{pounds} +@{shillings}/20 + @{pence}/240))/250" disabled class="no-spinners total" title="total pound value">Code language: HTML, XML (xml)

Notice that it uses 3 inputs, pounds, shillings, and pence, and then in money calculates those values with an autocalc input. Before adding a sheet worker for this calculation, we need to change this input to readonly (sheet workers cant change disabled inputs). We don’t need to change anything, but we change the value for neatness.

<input type="number" name="attr_money" value="0" readonly class="no-spinners total" title="total pound value">Code language: HTML, XML (xml)

We didn’t need to change much here. Now for the sheet worker, we need to grab the three base values, and calculate the new total.

    on('change:pence change:shillings change:pounds sheet:opened', function() {
        getAttrs(['pence', 'shillings', 'pounds'], function(values) {
            const pence  = +values.pence || 0;
            const shillings  = +values.shillings || 0;
            const pounds  = +values.pounds || 0;
            const amount = pounds + (shillings/20) + (pence/240);
            const money = Math.round(amount * 100) / 100;
            setAttrs({
                money: money
            });
        });
    });Code language: JavaScript (javascript)

The code here is a lot more verbose than the autocalc field. Part of that is because I labelled every aspect of the calculation. This could have been done by combining as much as possible in one line:

    on('change:pence change:shillings change:pounds sheet:opened', function() {
        getAttrs(['pence', 'shillings', 'pounds'], function(values) {
            setAttrs({
                money: Math.round(100*((+values.pounds || 0) + ((+values.shillings || 0)/20) + ((+values.pence || 0)/240)))/100
            });
        });
    });Code language: JavaScript (javascript)

Some people do write their sheet workers this way, but I think the former sheet worker is a lot more readable.

We added sheet:opened in the event line. This isn’t really needed, but this sheet will already be in use by different groups, and without it, the money attribute won’t update until players change their money. The extra lag caused by a single sheet worker is negligible, so we include it here.

The Final Script Block

So after this work, our entire script block looks like this:

<script type="text/worker">
    on('change:wounds change:wounds_max', function() {
        getAttrs(['wounds', 'wounds_max'], function(values) {
            const current = +values.wounds || 0;
            const max  = +values.wounds_max || 0;
            if (current > max || max < current) {
                setAttrs({
                    wounds: wounds_max,
                    silent: true
                });
            }
        });
    });
    on('change:pence change:shillings change:pounds sheet:opened', function() {
        getAttrs(['pence', 'shillings', 'pounds'], function(values) {
            const pence  = +values.pence || 0;
            const shillings  = +values.shillings || 0;
            const pounds  = +values.pounds || 0;
            const amount = pounds + (shillings/20) + (pence/240);
            const money = Math.round(amount* 100) / 100;
            setAttrs({money});
        });
    });
</script>Code language: JavaScript (javascript)
Series Navigation

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.