Hi there, I'm hoping some of you wonderful scriptomancers might be able to help me here. I have a Wild Magic sorcerer in my game and we have a bespoke wild magic surge rule. So i began to create a script (with the aid of ChatGPT as i'm very new to this) and i've managed to get the following output which works fine, until the DC isn't met and it has to roll against the WildMagicSurge table. Maybe i've missed something or there's something there i'm not understanding (or it's not possible). but would someone mind casting an eye over this for me and letting me know what i'm missing/need to change please. // === ROLL20 Wild Magic Surge API Script ===
// Usage: !wildmagic <spellsCast>
// Requires:
// - A token selected
// - Character sheet with a "level" attribute
// - Rollable table named "WildMagicSurge"
const dcTable = {
1: [1,6,12,18],
2: [1,5,10,15,18,18],
3: [1,3,6,9,12,15,18,18,18,18],
4: [1,3,6,9,12,15,18,18,18,18,18,18],
5: [1,2,4,6,8,10,12,14,16,18,18,18,18,18,18],
6: [1,2,4,6,8,10,12,14,15,16,18,18,18,18,18,18,18],
7: [1,2,4,6,8,10,12,14,15,16,17,18,18,18,18,18,18,18,18],
8: [1,2,4,6,8,10,12,13,14,15,16,17,18,18,18,18,18,18,18,18,18],
9: [1,1,2,3,4,5,7,7,9,10,11,12,14,16,18,18,18,18,18,18,18,18,18,18],
10: [1,1,2,3,4,5,7,7,9,10,11,12,13,14,16,18,18,18,18,18,18,18,18,18],
11: [1,1,2,3,4,5,7,7,9,10,11,12,13,14,15,16,18,18,18,18,18,18,18,18],
12: [1,1,2,3,4,5,7,7,9,10,11,12,13,14,15,16,18,18,18,18,18,18,18,18],
13: [1,1,2,3,4,5,7,7,9,10,11,12,13,14,15,16,17,18,18,18,18,18,18,18],
14: [1,1,2,3,4,5,7,7,9,10,11,12,13,14,15,16,17,18,18,18,18,18,18,18],
15: [1,1,2,3,4,5,7,7,9,10,11,12,13,14,15,16,17,18,18,18,18,18,18,18],
16: [1,1,2,3,4,5,7,7,9,10,11,12,13,14,15,16,17,18,18,18,18,18,18,18],
17: [1,1,2,3,4,5,7,7,9,10,11,12,13,14,15,16,17,18,18,18,18,18,18,18],
18: [1,1,2,3,4,5,7,7,9,10,11,12,13,14,15,16,17,18,18,18,18,18,18,18],
19: [1,1,2,3,3,4,4,5,5,6,6,7,7,8,9,10,11,12,13,14,15,16,18,18],
20: [1,1,2,3,3,3,4,4,5,5,6,6,7,7,8,9,8,11,12,13,14,15,16,18]
};
// Get DC from table with level and spell slot safety checks
function getDC(level, spellsCast) {
const cappedLevel = Math.min(Math.max(level, 1), 20);
const row = dcTable[cappedLevel];
const spellIndex = Math.min(spellsCast, row.length - 1);
return {
levelBand: cappedLevel,
dc: row[spellIndex]
};
}
on('chat:message', function(msg) {
if (msg.type !== 'api' || !msg.content.startsWith('!wildmagic')) return;
const args = msg.content.trim().split(' ');
// --- Token must be selected
if (!msg.selected || msg.selected.length === 0) {
sendChat('Wild Magic', `/w ${msg.who} ⚠️ Please select your token before running this command.`);
return;
}
const token = getObj('graphic', msg.selected[0]._id);
if (!token) {
sendChat('Wild Magic', `/w ${msg.who} ❌ Couldn't find selected token.`);
return;
}
const characterId = token.get('represents');
if (!characterId) {
sendChat('Wild Magic', `/w ${msg.who} ❌ This token isn't linked to a character sheet.`);
return;
}
const levelStr = getAttrByName(characterId, 'level');
const level = parseInt(levelStr, 10);
if (isNaN(level)) {
sendChat('Wild Magic', `/w ${msg.who} ❌ No valid 'level' attribute found on sheet.`);
return;
}
// --- Spell count input required
if (args.length < 2) {
sendChat('Wild Magic', `/w ${msg.who} ⚠️ Usage: !wildmagic <spellsCast>`);
return;
}
const spellsCast = parseInt(args[1], 10);
if (isNaN(spellsCast)) {
sendChat('Wild Magic', `/w ${msg.who} ❌ Invalid number for spells cast.`);
return;
}
const roll = randomInteger(20);
const { levelBand, dc } = getDC(level, spellsCast);
// --- Prepare output using &{template:default}
const header = `&{template:default} ` +
`{{name= Wild Magic Check}}` +
`{{Character=${token.get('name')}}}` +
`{{Level=${level}}}` +
`{{Spells Cast=${spellsCast}}}` +
`{{DC=${dc}}}` +
`{{d20 Roll=${roll}}}`;
// --- Surge triggered
if (roll < dc) {
sendChat('Wild Magic', `[[1t[WildMagicSurge]]]`, (ops) => {
try {
const inlineRoll = ops?.[0]?.inlinerolls?.[0];
const surgeResult = inlineRoll?.results?.[0]?.tableItem?.name;
const surgeOutput = surgeResult
? `{{ Surge=**Triggered!**}} {{Effect=${surgeResult}}}`
: `{{⚠️ Surge=Triggered, but table may be empty or missing.}}`;
sendChat('Wild Magic', `/w ${msg.who} ${header} ${surgeOutput}`);
} catch (e) {
sendChat('Wild Magic', `/w ${msg.who} ${header} {{❌ Error=Rolling surge failed: ${e.message}}}`);
}
});
} else {
// --- No surge
const noSurgeOutput = `{{✅ Result=No surge triggered}}`;
sendChat('Wild Magic', `/w ${msg.who} ${header} ${noSurgeOutput}`);
}
});