Note: This is specific to the OGL sheet. This script runs when the API starts up and creates an ability on every character that has spells. The ability will issue a menu by level of available spells (with number of spell slots) as buttons that activate the spell. Feature Notes: It respects the whisper setting for the character. These abilities are static and do not require the API, so the script can be disabled after generating. Uses the default template Ideally suited for taking characters into games without the API, or setting up Monsters in a Module, or just as a fast way to have spells without digging into the character sheet. For the OGL sheet. Script: on('ready',()=>{
const range = (n) => [...Array(n).keys()];
const spellAbilityName = 'Spells';
const spellProps = ['cantrip','1','2','3','4','5','6','7','8','9'];
const spellLevelNames = {
cantrip: "Cantrips",
1: "1st Level",
2: "2nd Level",
3: "3rd Level",
4: "4th Level",
5: "5th Level",
6: "6th Level",
7: "7th Level",
8: "8th Level",
9: "9th Level"
};
const isSpellSlot = /^lvl(\d)_slots_total$/;
const isSpell = /^repeating_spell-([^_]*)_.*_spellname/;
const makeButton = (l,n) => `[@{selected|repeating_spell-${l}_$${n}_spellname}](~selected|repeating_spell-${l}_$${n}_spell)`;
const makeLevel = (s,l,n) => `{{${spellLevelNames[l]}${s?` (${s} slot${s!==1?'s':''})`:''}=${range(n).map(nn=>makeButton(l,nn)).join('')}}}`; // eslint-disable-line no-irregular-whitespace
const makeSpellSheet = (c) => {
const counts = {};
const slots = {};
// find all spells
findObjs({
type: 'attribute',
characterid: c.id
})
.forEach(a=>{
let n = a.get('name');
if(isSpellSlot.test(n)){
let m = n.match(isSpellSlot);
slots[m[1]]=parseInt(a.get('current'));
} else if(isSpell.test(n)){
let m = n.match(isSpell);
counts[m[1]]=(counts[m[1]]||0)+1;
}
});
let parts = [];
if(Object.keys(counts).length){
spellProps.forEach(k=>{
if(counts.hasOwnProperty(k)){
parts.push(makeLevel(slots[k],k,counts[k]));
}
});
let ability = (findObjs({
type: 'ability',
characterid: c.id,
name: spellAbilityName
})[0] || createObj('ability',{
characterid: c.id,
name: spellAbilityName
}));
ability.set({
action: `@{selected|wtype}&{template:default}{{name=@{selected|character_name} Spells}}${parts.join('')}`,
istokenaction: true
});
}
};
let queue = findObjs({
type: 'character'
});
const burndownQueue = () => {
if(queue.length){
makeSpellSheet(queue.shift());
setTimeout(burndownQueue,0);
} else {
log('Done Updating Spells Ability');
}
};
log(`Considering ${spellAbilityName} Ability on ${queue.length} character${queue.length!==1?'s':''}`);
setTimeout(burndownQueue,100);
});
Support my work on If you use my scripts, want to contribute, and have the spare bucks to do so , go right ahead. However, please don't feel like you must contribute just to use them! I'd much rather have happy Roll20 users armed with my scripts than people not using them out of some sense of shame. Use them and be happy, completely guilt-free! Disclaimer: This Patreon campaign is not affiliated with Roll20; as such, contributions are voluntary and Roll20 cannot provide support or refunds for contributions.