Here's an API script that should (hopefully) work. It'll trigger on a roll from an NPC sheet that contains at least {{r1}}, is whispered to the GM, and is on a template with 'npc' in the name (npcaction, npcatk, npcfullatk): const npcRollInfo = (() => { // eslint-disable-line no-unused-vars const handleInput = (msg) => { if (msg.target === 'gm' && msg.inlinerolls && msg.rolltemplate && msg.content.match(/r1=\$\[\[(\d+)\]\]/i)) { if (!msg.rolltemplate.match(/npc/i) || msg.inlinerolls.length < 1) return; let attack1_index = msg.content.match(/r1=\$\[\[(\d+)\]\]/i)[1] let attack2_index = (msg.content.match(/r2=\$\[\[(\d+)\]\]/i)) ? msg.content.match(/r2=\$\[\[(\d+)\]\]/i)[1] : null; let attack1_total = (msg.inlinerolls[attack1_index].results.total > 0) ? msg.inlinerolls[attack1_index].results.total : null; let attack2_total = (attack2_index && msg.inlinerolls[attack2_index].results.rolls[0].dice > 0) ? msg.inlinerolls[attack2_index].results.total : null; let attack_string; if (attack1_total) { if (attack2_total) { let advantage = (msg.content.match(/\{\{advantage=1\}\}/i)) ? 1 : (msg.content.match(/\{\{disadvantage=1\}\}/i)) ? -1 : 0; if (advantage !== 0) { if ((attack1_total >= attack2_total && advantage === 1) || (attack1_total <= attack2_total && advantage === -1)) { attack_string = `**Attack Roll 1: ${attack1_total}**<br>Attack Roll 2: ${attack2_total}`; } else attack_string = `Attack Roll 1: ${attack1_total}<br>**Attack Roll 2: ${attack2_total}**`; } else attack_string = `Attack Roll 1: ${attack1_total}`; } else attack_string = `Attack Roll 1: ${attack1_total}`; let npcName = (msg.content.match(/\{\{name=([^}]+)/i)) ? msg.content.match(/\{\{name=([^}]+)/i)[1] : 'NPC'; let npcAttackName = msg.content.match(/\{rname=([^}]+)/i) ? msg.content.match(/\{rname=([^}]+)/i)[1] : 'Attack'; if (npcAttackName.match(/\(~.+\)/g)) npcAttackName = npcAttackName.replace(/\(~.+\)/g, '(#" style="color:darkred)'); let output = `&{template:npcaction} {{rname=${npcAttackName}}} {{name=${npcName}}} {{description=${attack_string}}}` sendChat(``, output); } return; } }; const registerEventHandlers = () => { on('chat:message', handleInput); }; on('ready', () => { registerEventHandlers(); }); return { }; })(); If there is no Advantage/Disadvantage, it only shows roll 1. It should also boldify the relevant roll when Advantage/Disadvantage is used. It currently picks up the {{advantage}} property from the template, if you're using any custom macros with some 2d20kh1 rolls in there, it might need some tweaking. Let me know if anything breaks, it might need some extra error checking in there.