Hi all, I used this script during a previous campaign using the 2014 D&D character sheet and it worked great. It doesn't seem to work for 2024 (I'm guessing something to do with the names of the attributes changing.) Can it work for the 2024 sheet by simply updating the attribute names? If so, can someone provide guidance on what specifically needs to be changed? Thanks in advance. -Adam /*jshint esversion: 9 */ // OPen and Blind Checks for the 5th Edition OGL by Roll20 // Create a token action macro called "OpenChecks" with the action "!OpenChecks" // Create a token action macro called "BlindChecks" with the action "!BlindChecks" // Give all your players access to both. const OpenBlindChecks = (() => { const buildTable = (values) => { let getMod = (g) => { return g ? g.mod : -5; }; let s = { div: `display: block; ` + `min-height:60px; ` + `margin: 5px 0px 0px -30px; ` + `padding:0px 5px 0px 5px; ` + `border: 0px none; ` + `border-radius: 6px 6px 6px 6px; ` + `box-shadow: 2px 2px 4px 2px #000; ` + `background-color: #fff; ` + `background-image: url('${values.blind ? " <a href="https://i.imgur.com/UCIUXyr.jpg" rel="nofollow">https://i.imgur.com/UCIUXyr.jpg</a> " : " <a href="https://i.imgur.com/vjL1blE.jpg" rel="nofollow">https://i.imgur.com/vjL1blE.jpg</a> " }'); ` + // <a href="https://i.imgur.com/UCIUXyr.jpg" rel="nofollow">https://i.imgur.com/UCIUXyr.jpg</a> <a href="https://i.imgur.com/vjL1blE.jpg" rel="nofollow">https://i.imgur.com/vjL1blE.jpg</a> `text-align: left; ` + `white-space: pre-wrap;`, tbl_top: `width: 90%; margin: auto;`, img: `background-color: transparent; ` + `border: none ;` + `max-height: 60px; ` + `padding: 5px; ` + `margin: auto; !important`, name: `font-weight: bold; ` + `font-size: 120%; ` + `font-style: italic; ` + `text-align: center; ` + `line-height: 18px; ` + `padding: 0px 5px 0px;`, blurb: `font-style: italic; ` + `text-align: center; ` + `line-height:18px; ` + `padding: 0px 5px 0px;`, rolls: `text-align: center; ` + `line-height:18px; ` + `padding: 0px 5px 0px;`, inlinestyle: `display: inline-block; ` + `min-width:18px; ` + `min-height:18px; ` + `background: white; ` + `border: 1px solid black; ` + `font-style: normal; ` + `text-align: center; ` + `line-height:18px; ` + `padding: 0px:` + `color: black;`, inlineclass: `inlinerollresult showtip tipsy-n-right`, tbl_abl: `width: 90%; margin: auto;`, th: `font-weight: bold; ` + `text-align: center; ` + `line-height:18px; ` + `padding: 0px 5px 0px;`, td: `text-align: center; ` + `line-height:18px; ` + `padding: 0px 5px 0px;"`, tbl_skl: `width: 90%; margin: auto;`, tr_even: `background-color: ${values.blind ? "#cfd2d0" : "#e0e5c1" };`, //cfd2d0 //e0e5c1 ${values.blind ? "cfd2d0" : "e0e5c1" } tr_odd: `background-color: ${values.blind ? "#eeeeee" : "#ffffff" };` //transparent #ffffff ${values.blind ? "#eeeeee" : "#ffffff" } }; let passive = `Passive Wisdom:&nbsp;` + `<span class="${s.inlineclass}" style="${s.inlinestyle}" title="10 + ${getMod(values.mods.perception_bonus)}">` + `${10 + getMod(values.mods.perception_bonus)}` + `</span>`; let inlineRoll = (props) => { return `<span class="${s.inlineclass}" style="${s.inlinestyle}" title="${props.t1}">${props.r1}</span>&#171;-&#187;<span class="${s.inlineclass}" style="${s.inlinestyle}" title="${props.t2}">${props.r2}</span>`; }; let rawRoll = inlineRoll({ t1: `Rolling 1d20(${values.frst})`, r1: values.frst, t2: `Rolling 1d20(${values.scnd})`, r2: values.scnd}); let abilityRow = (oe, l, m, sa) => { return `<tr style="${oe}">` + `<td style="${s.td}">` + `${l}` + `</td>` + `<td style="${s.rolls}">` + `${inlineRoll({ t1: `Rolling 1d20(${values.frst})+${m}`, r1: values.frst + m, t2: `Rolling 1d20(${values.scnd})+${m}`, r2: values.scnd + m })}` + `</td>` + `<td style="${s.rolls}">` + `${inlineRoll({ t1: `Rolling 1d20(${values.frst})+${sa}`, r1: values.frst + sa, t2: `Rolling 1d20(${values.scnd})+${sa}`, r2: values.scnd + sa })}` + `</td>` + `</tr>`; }; let abilityList = [ {oddeven: s.tr_even, label: 'Strength', mod: getMod(values.mods.strength_mod), save: getMod(values.mods.strength_save_bonus)}, {oddeven: s.tr_odd, label: 'Dexterity', mod: getMod(values.mods.dexterity_mod), save: getMod(values.mods.dexterity_save_bonus)}, {oddeven: s.tr_even, label: 'Constitution', mod: getMod(values.mods.constitution_mod), save: getMod(values.mods.constitution_save_bonus)}, {oddeven: s.tr_odd, label: 'Intelligence', mod: getMod(values.mods.intelligence_mod), save: getMod(values.mods.intelligence_save_bonus)}, {oddeven: s.tr_even, label: 'Wisdom', mod: getMod(values.mods.wisdom_mod), save: getMod(values.mods.wisdom_save_bonus)}, {oddeven: s.tr_odd, label: 'Charisma', mod: getMod(values.mods.charisma_mod), save: getMod(values.mods.charisma_save_bonus)} ]; let skillRow = (oe, l, m, sa) => { return `<tr style="${oe}">` + `<td style="${s.td}">` + `${l}` + `</td>` + `<td style="${s.rolls}">` + `${inlineRoll({ t1: `Rolling 1d20(${values.frst})+${m}`, r1: values.frst + m, t2: `Rolling 1d20(${values.scnd})+${m}`, r2: values.scnd + m })}` + `</td>` + `</tr>`; }; let skillList = [ {oddeven: s.tr_even, label: 'Athletics', mod: getMod(values.mods.athletics_bonus)}, {oddeven: s.tr_odd, label: 'Acrobatics', mod: getMod(values.mods.acrobatics_bonus)}, {oddeven: s.tr_even, label: 'Animal Handling', mod: getMod(values.mods.animal_handling_bonus)}, {oddeven: s.tr_odd, label: 'Arcana', mod: getMod(values.mods.arcana_bonus)}, {oddeven: s.tr_even, label: 'Deception', mod: getMod(values.mods.deception_bonus)}, {oddeven: s.tr_odd, label: 'History', mod: getMod(values.mods.history_bonus)}, {oddeven: s.tr_even, label: 'Insight', mod: getMod(values.mods.insight_bonus)}, {oddeven: s.tr_odd, label: 'Intimidation', mod: getMod(values.mods.intimidation_bonus)}, {oddeven: s.tr_even, label: 'Investigation', mod: getMod(values.mods.investigation_bonus)}, {oddeven: s.tr_odd, label: 'Medicine', mod: getMod(values.mods.medicine_bonus)}, {oddeven: s.tr_even, label: 'Nature', mod: getMod(values.mods.nature_bonus)}, {oddeven: s.tr_odd, label: 'Perception', mod: getMod(values.mods.perception_bonus)}, {oddeven: s.tr_even, label: 'Performance', mod: getMod(values.mods.performance_bonus)}, {oddeven: s.tr_odd, label: 'Persuasion', mod: getMod(values.mods.persuasion_bonus)}, {oddeven: s.tr_even, label: 'Religion', mod: getMod(values.mods.religion_bonus)}, {oddeven: s.tr_odd, label: 'Sleight of Hand', mod: getMod(values.mods.sleight_of_hand_bonus)}, {oddeven: s.tr_even, label: 'Stealth', mod: getMod(values.mods.stealth_bonus)}, {oddeven: s.tr_odd, label: 'Survival', mod: getMod(values.mods.survival_bonus)} ]; values.message = `` + `<div style="${s.div}">` + `<table style="${s.tbl_top}">` + `<tr>` + `<td rowspan="3">` + `<img style="${s.img}" src="${values.url}">` + `</td>` + `<td style="${s.name}">` + `${values.name}` + `</td>` + `</tr>` + `<tr>` + `<td style="${s.blurb}">` + `${passive}` + `</td>` + `</tr>` + `<tr>` + `<td style="${s.rolls}">` + `${rawRoll}` + `</td>` + `</tr>` + `</table>` + `<br>` + `<table style="${s.tbl_abl}">` + `<tr>` + `<td style="${s.th}">` + `Ability` + `</td><td style="${s.th}">` + `Check` + `</td>` + `<td style="${s.th}">` + `Save` + `</td>` + `</tr>`; abilityList.forEach( (row) => { values.message = values.message + abilityRow(row.oddeven, row.label, row.mod, row.save); }); values.message = values.message + `</table>` + `<br>` + `<table style="${s.tbl_abl}">` + `<tr>` + `<td style="${s.th}">` + `Ability` + `</td><td style="${s.th}">` + `Check` + `</td>` + `</tr>`; skillList.forEach( (row) => { values.message = values.message + skillRow(row.oddeven, row.label, row.mod); }); values.message = values.message + `</table>` + `<br>` + `</div>`; return values.message; }; const getAttributes = (values) => { let attrNames = [ 'strength_mod', 'dexterity_mod', 'constitution_mod', 'intelligence_mod', 'wisdom_mod', 'charisma_mod', 'strength_save_bonus', 'dexterity_save_bonus', 'constitution_save_bonus', 'intelligence_save_bonus', 'wisdom_save_bonus', 'charisma_save_bonus', 'athletics_bonus', 'acrobatics_bonus', 'animal_handling_bonus', 'arcana_bonus', 'deception_bonus', 'history_bonus', 'insight_bonus', 'intimidation_bonus', 'investigation_bonus', 'medicine_bonus', 'nature_bonus', 'perception_bonus', 'performance_bonus', 'persuasion_bonus', 'religion_bonus', 'sleight_of_hand_bonus', 'stealth_bonus', 'survival_bonus', 'passive_wisdom' ]; values.attr = filterObjs( (a) => { if ( a.get('characterid') == values.cid && a.get('type') === 'attribute' && attrNames.includes(a.get('name')) ) { return true; } else { return false; } }); values.mods = {}; values.attr.forEach( (a) => { let key = a.get('name'); let mod = a.get('current'); let lbl = a.get('name') .replace(/_mod/gi,'') .replace(/_bonus/gi,'') .replace(/_/g, ' '); values.mods[a.get('name')] = { key: a.get('name'), mod: (Number(mod)||~~mod) || 0, lbl: lbl }; }); sendChat('QuantumRoll', '[[2d20]]', function(qr) { values.frst = qr[0].inlinerolls[0].results.rolls[0].results[0].v; values.scnd = qr[0].inlinerolls[0].results.rolls[0].results[1].v; buildTable(values); if (values.blind) { sendChat(values.who, `/w gm ${values.message}`); sendChat('API - QuantumRoll', `/w "${values.who}" Secret roll sent to GM. I'm sure its fine.`); }else{ sendChat(values.who, values.message); } }); }; const handleInput = (msg) => { let values = {}; values.msg = msg; values.tok = getObj( values.msg.selected[0]._type, values.msg.selected[0]._id); values.cha = getObj( 'character', values.tok.get('represents')); if (values.cha) { values.cid = values.cha.get('id'); let imgsrc = values.tok.get('imgsrc'); values.url = imgsrc === '/images/character.png' ? ' <a href="https://i.imgur.com/MpqETqe.png" rel="nofollow">https://i.imgur.com/MpqETqe.png</a> ' : imgsrc; values.name = values.cha.get('name'); values.blind = msg.content.startsWith("!BlindChecks"); values.who = values.msg.who .substring(0, values.msg.who.indexOf(' (GM)')); } getAttributes(values); }; on("ready",() => { on('chat:message', (msg_orig) => { if (msg_orig.type === 'api' && (msg_orig.content.startsWith("!OpenChecks") || msg_orig.content.startsWith("!BlindChecks")) && msg_orig.selected && msg_orig.selected.length == 1 ) { handleInput(_.clone(msg_orig)); } }); }); return { }; })();