Skip to content

Instantly share code, notes, and snippets.

@johnstcn
Created May 21, 2022 15:58
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save johnstcn/8d468932fd89113ac46d7e3ea73be6e5 to your computer and use it in GitHub Desktop.
Save johnstcn/8d468932fd89113ac46d7e3ea73be6e5 to your computer and use it in GitHub Desktop.
Foundry VTT Macro for Starfinder RPG -- Mass Ability, Save, or Skill Roll
/*
* Foundry VTT Macro for Starfinder RPG -- Mass Ability, Save, or Skill Roll
*/
let targetActors = getTargetActors().filter(a => a != null);
function checkForActors(){
if (targetActors.length == 0)
throw new Error('You must designate at least one token as the roll target');
}
checkForActors();
// Choose roll type dialog
let rollTypeTemplate = `
<div>
<div class="form-group">
<label>Choose roll type</label>
<select id="selectedType">
<option value="save">Saving Throw</option>
<option value="ability">Ability Check</option>
<option value="skill">Skill Check</option>
</select>
</div>
</div>`;
let chooseCheckType = new Dialog({
title: "Choose check type",
content: rollTypeTemplate,
buttons: {
ok: {
icon: '<i class="fas fa-check"></i>',
label: "OK",
callback: async (html) => {
let checkType = html.find("#selectedType")[0].value;
selectedCheckDialog(checkType).render(true);
}
},
cancel: {
icon: '<i class="fas fa-times"></i>',
label: 'Cancel'
}
},
default: "cancel"
});
// Choose ability mod dialog
function selectedCheckDialog(checkType) {
let dialogTitle = getCheckDialogTitle(checkType);
let dialogContent = getCheckTemplate(checkType);
return new Dialog({
title: dialogTitle,
content: dialogContent,
buttons: {
ok: {
icon: '<i class="fas fa-check"></i>',
label: "OK",
callback: async (html) => {
let id = html.find("#selectedAbility")[0].value;
let flavor = ``;
let messageContent = ``;
for (let a of targetActors) {
let name = a.name;
let mod = 0;
switch (checkType) {
case "save":
mod = a.data.data.attributes[id].bonus;
flavor = `<h2>Everybody give me a ${game.sfrpg.config.saves[id]} save</h2>`;
messageContent += `<h3><b>${name}:&nbsp;</b><code>d20+${mod}</code> &rarr; [[1d20+${mod}]]</h3>`;
break;
case "ability":
mod = a.data.data.abilities[id].mod + a.data.data.abilities[id].abilityCheckBonus;
flavor = `<h2>Roll a very important ${game.sfrpg.config.abilities[id]} check</h2>`;
messageContent += `<h3><b>${name}:&nbsp;</b><code>d20+${mod}</code> &rarr; [[1d20+${mod}]]</h3>`;
break;
case "skill":
mod = a.data.data.skills[id].mod;
flavor = `<h2>Go ahead and roll ${game.sfrpg.config.skills[id]}</h2>`;
messageContent += `<h3><b>${name}:&nbsp;</b><code>d20+${mod}</code> &rarr; [[1d20+${mod}]]</h3>`;
break;
default:
objects = game.sfrpg.config.skills;
break;
}
}
let chatData = {
flavor: flavor,
user: game.user.id,
speaker: game.user,
content: messageContent,
// Uncomment the following line if you want the results whispered to the GM.
whisper: game.users.filter(u => u.isGM).map(u => u._id)
};
ChatMessage.create(chatData, {});
}
},
cancel: {
icon: '<i class="fas fa-times"></i>',
label: 'Cancel'
}
},
default: "cancel"
});
}
// Gets list of selected tokens, or if no tokens are selected then the user's character.
function getTargetActors() {
const character = game.user.character;
const controlled = canvas.tokens.controlled;
let actors = [];
if (controlled.length === 0) return [character] || null;
if (controlled.length > 0) {
let actors = [];
for (let i = 0; i < controlled.length; i++) {
actors.push(controlled[i].actor);
}
return actors;
}
throw new Error('You must designate at least one token as the roll target');
}
// Gets a template of abilities or skills, based on the type of check chosen.
function getCheckTemplate(checkType) {
let objects = {};
switch (checkType) {
case "save":
objects = game.sfrpg.config.saves;
break;
case "ability":
objects = game.sfrpg.config.abilities;
break;
case "skill":
objects = game.sfrpg.config.skills;
break;
default:
objects = game.sfrpg.config.skills;
break;
}
let template = `
<div>
<div class="form-group">
<label>Choose check</label>
<select id="selectedAbility">`;
for (let [checkId, check] of Object.entries(objects)) {
template += `<option value="${checkId}">${check}</option>`;
}
template += `</select>
</div>
</div>`;
return template;
}
function getCheckDialogTitle(checkType) {
switch (checkType) {
case "save":
return "Saving Throw";
case "ability":
return "Ability Check";
case "skill":
return "Skill Check";
default:
return "Unknown Check";
}
}
chooseCheckType.render(true);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment