Here's a quick and dirty thing I threw together. Note: It requires your sandbox to be set to Experimental, it won't work on Default because it relies on the new `getSheetItem` function. Note 2: Unfortunately there's a bug with the experimental sandbox that doesn't allow me to use the roll commands, so it's doing a "pseudo roll"... but looking into the companion script you were using previous I think it was doing the same basic thing. (function() {
'use strict';
const VERSION = '0.1';
const SCRIPT_NAME = '5e2024_rollhp';
const beaconAttr = 'npc_hpformula';
const sendError = function(who, msg) {
sendChat(SCRIPT_NAME, '/w "' + who + '" ' + msg);
};
const isExperimentalSandbox = function() {
try {
const sv = Campaign().sandboxVersion || '';
return (String(sv).toLowerCase() === 'experimental');
} catch (e) {
return false;
}
};
const processFormula = function(formula) {
if (!formula) return undefined;
formula = `${formula}`.trim();
const diceRE = /[+-]?\s*\d*d\d+(?:\s*[+-]\s*\d+)?/i;
const match = formula.match(diceRE);
if (match) return match[0].replace(/\s+/g,'');
const num = parseInt(formula, 10);
if (!isNaN(num)) return `${num}`;
return undefined;
};
const localRoll = function(expression) {
if (!expression) return 0;
let expr = `${expression}`.replace(/\s+/g,'');
expr = expr.replace(/^-/, '0-');
expr = expr.replace(/-/g, '+-');
const parts = expr.split('+').filter(Boolean);
let total = 0;
for (const p of parts) {
if (!p) continue;
const m = p.match(/^(-?\d*)d(\d+)$/i);
if (m) {
let n = m[1] === '' || m[1] === '+' ? 1 : parseInt(m[1],10);
if (m[1] === '-') n = -1;
const sides = parseInt(m[2],10);
const count = Math.abs(n);
let sign = n < 0 ? -1 : 1;
for (let i=0;i<count;i++) {
const r = Math.floor(Math.random()*sides)+1;
total += sign*r;
}
continue;
}
const k = parseInt(p,10);
if (!isNaN(k)) { total += k; continue; }
}
return total;
};
const rollAndApply = function(token, expression, who) {
if (!token || !expression) return;
const bar = 'bar1';
// Experimental sandbox; inline sendChat rolls are unreliable here. Use local roll.
const hp = Math.max(Math.round(localRoll(expression)), 0);
const sets = {};
sets[bar + '_value'] = `${hp}`;
sets[bar + '_max'] = `${hp}`;
token.set(sets);
sendChat(SCRIPT_NAME, '/w "' + who + '" Rolled (local) and set HP for token "' + token.get('name') + '" to ' + hp);
};
const handleSelection = async function(selected, who) {
if (!selected || selected.length === 0) {
sendChat(SCRIPT_NAME, '/w "' + who + '" No tokens selected.');
return;
}
if (!isExperimentalSandbox() || typeof getSheetItem !== 'function') {
sendChat(SCRIPT_NAME, '/w "' + who + '" Error: This minimal Beacon-only script requires the Experimental API sandbox and Beacon sheet support (getSheetItem).');
return;
}
let total = 0;
let skipped = 0;
for (const sel of selected) {
const token = getObj('graphic', sel._id);
if (!token || token.get('isdrawing') || token.get('subtype') !== 'token') { skipped++; continue; }
const charId = token.get('represents');
if (!charId) { skipped++; continue; }
if ('' !== token.get('bar1_link')) { skipped++; continue; }
let formula = undefined;
try {
const val = await getSheetItem(charId, beaconAttr, 'current');
if (val !== null && val !== undefined && `${val}`.trim() !== '') { formula = val; }
} catch (e) {
log(`${SCRIPT_NAME} getSheetItem error: ${e}`);
}
if (!formula) { skipped++; continue; }
const expression = processFormula(formula);
if (!expression) { skipped++; continue; }
rollAndApply(token, expression, who);
total++;
}
sendChat(SCRIPT_NAME, '/w "' + who + '" Rolled HP for ' + total + ' token(s), skipped ' + skipped + '.');
};
const handleInput = async function(msg_orig) {
if (msg_orig.type !== 'api') return;
const content = msg_orig.content;
if (!/^!5e2024-rollhp(\b|$)/i.test(content)) return;
const who = (getObj('player', msg_orig.playerid) || { get: () => 'API' }).get('_displayname');
if (!playerIsGM(msg_orig.playerid)) { sendError(who, 'Only GM may run this command.'); return; }
await handleSelection(msg_orig.selected, who);
};
const registerEventHandlers = function() { on('chat:message', handleInput); };
on('ready', function() { log('-=> ' + SCRIPT_NAME + ' v' + VERSION + ' <=-'); registerEventHandlers(); });
})();
To use, from your mod/api scripts settings click "New Script" and name it whatever you want, then copy and paste the above code into the script and click save. Once the sandbox is restarted, in game you can select a group of NPC tokens and type `!5e2024-rollhp` in chat. I noticed in the OGL companion api script it looks like it also creates a token when you roll HP from the NPC sheet... I can look into doing something similar with this one. Anyways it's very quick and dirty but if you notice any issues let me know and I can see about giving it a fix. Seems to work fine in my basic quick testing though. *disclaimer* I am tired and didn't spend much time on this :P