Action Buttons and the MacroBar

The following useful tip (which is more and more useful with action buttons becoming more common thanks to custom roll parsing) was created by roll20 forum member Scott C, who is a Roll20 creator par excellence. I’ve tweaked the code a little bit, but the original concept is his.

A common thing to do with frequently used abilities is to add them to the macro bar so they are never more than a single click away. You can drag roll buttons there so you don’t have to open up a character sheet just to use a specific ability.

But you can’t drag action buttons to that macro bar. With the advent of custom roll parsing, action buttons are far more powerful and flexible than roll buttons – so it would be very useful to drag them to the macro bar.

There are work arounds for players. You could create an ability that launches the action button, and place that on the macro bar. You need to remember to include a character identifier, so an action button named attack on Malador’s sheet can be launched with %{malador|attack} or %{selected|attack}.

Sheet authors can make this unnecessary, by following these steps:

  • Hide the action button
  • Create a hidden Attribute with value=””
  • Create a visible roll button, which points to that hiddent attribute.
  • Create a sheet worker that runs whenever the character sheet name changes, and sets the name of that attribute to point to the hidden ability.

This is fairly convoluted. You can’t launch an action button without specifying which character it belongs to (like the aforementioned Malador|attack macro). Players or GMs can change the name of their character sheet, and that would break any existing buttons pointign to that character, so the sheet worker fixes that that. (This is why the attribute is needed as an intermediate – sheet workers can’t change roll button values, but can change attributes).

Naming The Elements

You can set this up for many action buttons, but each one has an attribute and a rolled button.

  • Each set of three items must have a standardised name sequence for the sheet worker.
  • The roll button name should be kept short, because it might be dragged to the macrobar.
  • Action buttons shouldn’t have extra underscores in the name- if they are inside a repeating section, this stops them working.

Let’s say you have actions named attack, talk, and sneak. For each of those, you need an action button (that performs the action), a roll button that runs that action button when clicked, and an attribute that is empty now, but later will contain the address of the action button. That might look like this:

<button type="roll" name="roll_attack" class="skill" value="@{attack}">
   <span class="skill">Attack</span>
</button>
<input type="hidden" name="attr_attack" value="">
<button type="action" name="act_attack-button" class="hidden"></button>

<button type="roll" name="roll_talk" class="skill" value="@{talk}">
   <span class="skill">Talk</span>
</button>
<input type="hidden" name="attr_talk" value="">
<button type="action" name="act_talk-button" class="hidden"></button>

<button type="roll" name="roll_sneak" class="skill" value="@{sneak}">
   <span class="skill">Sneak</span>
</button>
<input type="hidden" name="attr_sneak" value="">
<button type="action" name="act_sneak-button" class="hidden"></button>Code language: HTML, XML (xml)

Attributes and buttons can have identical names. They are in different sets thanks to the different prefixes of attr_, act_ and roll_.

However, roll and action buttons should have different names. If someone creates an ability or macro targetting an ability, roll20 won’t know whether you want to use the roll button or the action button.

The Sheet Worker

Now you need a sheet worker that updates the attributes. You also need an array containing the root name of every button set. Here’s a sheet worker you can drop into your character sheet, changing only the first line and leaving everything else unchanged.

const skillset = ['attack', 'talk', 'sneak']; // add the names of relevant buttons here.
    on('change:character_name sheet:opened', () => {
        getAttrs(['character_name'], value => {
            const attribute_values = skillset.reduce((all, one) => {
                return {...all, [one]: 
                   `%{${value.character_name}|${one}-button}`}}, {});
            setAttrs(attribute_values, {silent:true});
        });
    });Code language: JavaScript (javascript)

That reduce function is likely to be very confusing. It is basically doing a loop through the skillset, and creating an attribute_values object. Here’s an illustration of what it’s doing:

const character_name = 'Me';
const skillset = ['attack', 'talk', 'sneak'];
const attribute_values = {};
skillset.forEach(skill => {
   attribute_values[skill] = `%{`${character_name}|${skill}-button}`;
});
setAttrs(attribute_values, {silent:true});Code language: JavaScript (javascript)

This code is just for illustration – it won’t actually work. A key part is this line:

attribute_values[skill] = `%{`${character_name}|${skill}-button}`;

so if you a character called Me and a skill called Talk, it will use attribute_values.talk = ${Me|talk-button}. In other words, the attribute named talk will now have a value of the ability call to launch the hidden attribute button.

If you set your attributes and buttons up this way you can use this sheet worker with no changes. All you need to do is supply a list of the attribute names in the skillset array and your set.

Series Navigation<< Callbacks and Promises with startRoll

Leave a Reply

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