Greetings everyone. I have been waiting for this option for quite some time and given my programming background, I have decided to try and code a front-end solution with a little help from ChatGPT. So how does this work? When your encounter starts, you copy this and paste it into your browser console but do not close it! You can drag it down to minimize it. I know that this isn't user friendly, but I suggest using chatgpt or similar tool to better understand this code and how you can change it to fit your own needs. Here are also some examples of how abilities should be formatted for this to work flawlessly... To activate the script, you have to click on monster name in the initiative order. If you want a statblock as is, you can click beneath the monster name. When you are done, I suggest cleaning local browser storage manually. If you want to "turn off" the script at any time, just hit f5 or close the developer console.
Sanguine_Shield (lvl 1) (3/3/rest). Example text... Bone_Cage (lvl 2) (1/1/round). Example text...
Spell_slots_lvl_1 (4/4/rest).
... spells ...
Code:
// Function to find all elements containing "rest or round" in bolded expressions in the opened monster stat block of the encounter runner.
function findStrongElements() {
var statBlockContents = document.querySelectorAll('.mon-stat-block__description-block-content');
var strongElements = [];
for (let block = 0; block < statBlockContents.length; block++) {
var elements = statBlockContents[block].getElementsByTagName('strong');
for (let e = 0; e < elements.length; e++) {
var element = elements[e];
if (element.textContent.includes('rest') || element.textContent.includes('round')) {
strongElements.push(element);
}
}
}
return strongElements;
}
// Function to generate a unique key name for localStorage - concatenates unique monster name with skill/spell/action name.
// This will work with multiple monsters having the same stat block because encounter builder automatically assings (A) (B) (C) ... to distinguish between multiple monsters of the same name
function generateKeyName(buttonText, fieldName) {
var buttonName = buttonText.trim().replace(/[^a-zA-Z0-9]+/g, '-').toLowerCase();
var fieldNameParts = fieldName.trim().split(' ');
var firstWord = fieldNameParts[0].toLowerCase();
return `${buttonName}-${firstWord}`;
}
// Function to apply the script to all strong elements containing "rest" or "round" keyword.
// This function replaces the bolded starting section of abilities with input field containing the original value and saves changes to local browser storage.
function applyScript(buttonTextValue) {
var implosionElements = findStrongElements();
implosionElements.forEach(implosionElement => {
// Create an input field to replace the static text
var inputField = document.createElement('input');
inputField.type = 'text';
// Retrieve the existing value from the HTML or from localStorage
var fieldName = implosionElement.textContent.match(/(.+rest\))|(.+round\))/)[0];
var keyName = generateKeyName(buttonTextValue, fieldName);
var savedValue = localStorage.getItem(keyName);
var existingValue = savedValue ? savedValue : fieldName;
// Set the input field value to the existing value
inputField.value = existingValue;
// Replace the static text with the input field
implosionElement.textContent = '';
implosionElement.appendChild(inputField);
// Save the input field value to localStorage when it changes
inputField.addEventListener('input', function () {
localStorage.setItem(keyName, inputField.value);
});
});
}
// Click event handler for the combatant summary buttons
function handleClick(event) {
var button = event.target;
var value = button.textContent.trim();
// Add a delay of 1 second before calling applyScript
setTimeout(() => {
applyScript(value);
}, 1000);
}
// Attach event listeners to the combatant summary buttons
var buttons = document.querySelectorAll('.combatant-summary__name');
buttons.forEach(button => {
button.addEventListener('click', handleClick);
});
Tracking spell slots and other abilities in combat tracker