I had answered a question like this before, so just needed to tweak an earlier script first created by The Aaron, then modified by me. Copy the script at the end of this post into your API Scripts page, and make a macro or button using the following layout: !modroll [[nd20]] attribute_name|attribute_value skill_name|skill_value optional_label Some example rolls - the last one is cribbed from your button example in an earlier post: !modroll [[3d20]] Strength|7 Athletics|3 Frodo makes a roll !modroll [[?{Dice|2}d20]] ?{StatName}|?{StatValue|1} ?{SkillName|?{SkillValue|1} A title goes here !modroll [[?{Dice|2}d20]] Strength|@{Strength} Athletics|[[@{Athletics_Rank}+@{Athletics_Modifier}]] Athletics Roll It uses the default template to print out, and will only show the complications count if a complication is rolled. If you want to copy the rolltemplate from that start trek sheet, adding it to your sheet, it will be pretty easy to adapt the output. Heres the script. // wait till the ready event before registering a chat handler
on('ready', () => {
// register a function to run for chat messages
on('chat:message', (msg_orig) => {
// make sure the message is an api command, then verify it starts with !modroll
if ('api' === msg_orig.type && /^!modroll\b/i.test(msg_orig.content)) {
function processInlinerolls(msg) {
if (_.has(msg, 'inlinerolls')) {
return _.chain(msg.inlinerolls)
.reduce(function(previous, current, index) {
previous['$[[' + index + ']]'] = current.results.total || 0;
return previous;
},{})
.reduce(function(previous, current, index) {
return previous.replace(index, current);
}, msg.content)
.value();
} else {
return msg.content;
}
}
const msg = processInlinerolls(msg_orig);
const template = (labels, dice, hits, complications) =>
`&{template:default} {{name=${labels.label}}} {{${labels.statname}=${labels.statvalue} }} {{${labels.skillname}=${labels.skillvalue} }} {{dice=${dice.join('-')} }} {{successes=${hits}}} ${complications ? `{{complications=${complications}}}` : ''}`;
// break into an array of arguments on spaces
log(msg);
const args = msg.split(/\s+/);
//const
const labels = {};
const stat = args[2].split('|') || [];
const skill = args[3].split('|') || [];
if(stat.length < 2 || skill.length < 2) {
sendChat('ModRoll',`Check your ${stat.length < 2 ? `stat` : `skill`} parameter; it isn't formatted correctly.`);
return;
}
labels.statname = stat[0];
labels.statvalue = parseInt(stat[1]) || 0;
labels.skillname = skill[0]
labels.skillvalue = parseInt(skill[1]) || 0;
labels.label = args.slice(4).join(' ') || '';
if(labels.statvalue <= 0 || labels.skillvalue < 2) {
sendChat('ModRoll',`Check your ${labels.statvalue === 0 ? `stat` : `skill`} value.`);
return;
}
const success = labels.skillvalue + labels.statvalue;
const complication = 20;
// accumulators for successes, crits, and complications
let hits = 0;
let complications = 0;
let dice = [];
// walk the inline roll structure grabbing the dice and comparing vs success and crit
(msg_orig.inlinerolls || []).forEach(r => {
((r.results || {}).rolls || []).forEach(r2 => {
(r2.results || []).forEach(r3 => {
hits += ((r3.v || 0) <= success ? 1 : 0);
hits += ((r3.v || 0) <= labels.skillvalue ? 1 : 0); // only adding 1 here, because it gets the success bonus as well.
complications += ((r3.v || 0) >= complication ? 1 : 0);
dice.push(r3.v || 0);
});
});
});
dice.sort((a, b) => a - b);
// output the rolls, and hits
sendChat('', template(labels,dice,hits,complications));
}
});
});