-
Notifications
You must be signed in to change notification settings - Fork 78
Helpful Foundry Macros
laialex501 edited this page Nov 30, 2020
·
4 revisions
- Create Critical Injury Roll Table from Critical Injury Items (non-compendium Critical Injury Items with valid min/max values)
let critdamagevalues = game.items.filter(item => item.data.type === "criticalinjury");
let sorted = critdamagevalues.sort((a,b) => { return a.data.data.min < b.data.data.min ? -1 : a.data.data.min > b.data.data.min ? 1 : 0});
let rollresults = sorted.map(item => { return { type: 1, img: item.data.img, collection: "Item", weight: 1, range: [item.data.data.min, item.data.data.max], resultId: item.data._id, text: item.data.name }});
RollTable.create({ name: "Critical Injuries", results: rollresults, formula: "1d100" })
- Create Critical Damage Roll Table from Critical Damage Items (non-compendium Critical Damage Items with valid min/max values)
let critdamagevalues = game.items.filter(item => item.data.type === "criticaldamage");
let sorted = critdamagevalues.sort((a,b) => { return a.data.data.min < b.data.data.min ? -1 : a.data.data.min > b.data.data.min ? 1 : 0});
let rollresults = sorted.map(item => { return { type: 1, img: item.data.img, collection: "Item", weight: 1, range: [item.data.data.min, item.data.data.max], resultId: item.data._id, text: item.data.name }});
RollTable.create({ name: "Critical Damage", results: rollresults, formula: "1d100" })
- Roll Critical Hit From Existing Roll Table
const tables = game.tables.map(table => {
return `<option value="${table.data._id}">${table.data.name}</option>`
})
let d = new Dialog({
title: "Critical Roll",
content: `<p>Select table and modifier</p>
<div class="grid grid-2col">
<div>Modifier:
<input name="modifier" class="modifier" style="width:50%" type="text" placeholder="0" data-dtype="String" />
</div>
<div>
Table: <select class="crittable">${tables.join("")}</select>
</div>
</div>`,
buttons: {
one: {
icon: '<i class="fas fa-check"></i>',
label: "Roll Critical",
callback: (html) => {
let modifier;
modifier = parseInt(html.find(".modifier").val(), 10);
if(isNaN(modifier)) {
modifier = 0;
}
const table = html.find(".crittable :selected").val();
const critRoll = new Roll(`1d100 + ${modifier}`);
const tableResult= game.tables.get(table).draw({roll: critRoll, displayChat: true});
}
},
two: {
icon: '<i class="fas fa-times"></i>',
label: "Cancel",
callback: () => console.log("Chose Two")
}
},
default: "two",
close: () => console.log("This always is logged no matter which option is chosen")
});
d.render(true);
- RollItem code, but with some tweaks to automatically apply a boost die for aiming, a couple of ability upgrades for True Aim ranks, and a damage bonus for his Deadly Accuracy talent (which increases damage based on Ranged: Heavy ranks) (NOTE: It's worth noting though that the ability upgrades and the +1 boost are not dynamic in any way unlike the damage modifier, so there is a need to update the macro whenever ranks change (or to remove the aiming boost bonus which is situational)
const actor = game.actors.get("x8vKm1uIO4U1xp7q");
const actorSheet = actor.sheet.getData();
const item = actor.getOwnedItem("Kj5b3Fq9aI0S2GXv").data;
// ADD DAMAGE DUE TO DEADLY ACCURACY FROM RANGED HEAVY RANKS
item.data.damage.adjusted += actor.data.data.skills["Ranged: Heavy"].rank;
const skill = actor.data.data.skills[item.data.skill.value];
const characteristic = actor.data.data.characteristics[skill.characteristic];
const dicePool = new DicePoolFFG({
ability: Math.max(characteristic.value, skill.rank),
boost: skill.boost + 1,
setback: skill.setback,
force: skill.force,
difficulty: 2, // default to average difficulty
});
dicePool.upgrade(Math.min(characteristic.value, skill.rank));
// THIS SHOULD APPLY THE 2 TRUE AIM UPGRADES
dicePool.upgrade(2);
game.ffg.DiceHelpers.displayRollDialog(actorSheet, dicePool, `${game.i18n.localize("SWFFG.Rolling")} ${skill.label}`, skill.label, item);
- A modified version of the above macro that uses names instead of id's and does not create permanent changes to items when adjusting damage because of talents.
// Set config values
const actor_name = "<Actor_Name_Here>"; // Must exactly match actor name
const item_name = "<Item_Name_Here>"; // Must exactly match item name
const skill_to_use = "Ranged: Heavy";
const display_name = "Light Repeating Blaster"; // Can be anything
const aims = 2;
// Acquire actor
const actor = game.actors.getName(actor_name);
const actorSheet = actor.sheet.getData();
// Acquire a copy of the item to allow temporary changes
let item = actor.data.items.find(n => n.name === item_name);
item = JSON.parse(JSON.stringify(item));
// Acquire skill and characteristic
const skill = actor.data.data.skills[skill_to_use];
const characteristic = actor.data.data.characteristics[skill.characteristic];
// Construct dice pool
const dicePool = new DicePoolFFG({
ability: Math.max(characteristic.value, skill.rank),
boost: skill.boost+aims,
setback: skill.setback,
force: skill.force,
difficulty: 2, // default to average difficulty
});
// Use skill and characteristic to create dice pool
dicePool.upgrade(Math.min(characteristic.value, skill.rank));
// Check for talents that modify the roll or result
const talents = actorSheet.data.talentList;
talents.forEach((talent) => {
if (talent.name === "True Aim") {
// Upgrade once for every rank in true aim
dicePool.upgrade(talent.rank);
}
if (talent.name === "Deadly Accuracy") {
// Add damage from deadly accuracy due to ranged: heavy ranks
item.data.damage.adjusted += actor.data.data.skills["Ranged: Heavy"].rank;
}
});
// Display roll dialogue using given attack_name and item
game.ffg.DiceHelpers.displayRollDialog(actorSheet, dicePool, `${game.i18n.localize("SWFFG.Rolling")} ${display_name}`, display_name, item);
- An advanced macro for playing audio upon clicking "Roll" in a roll dialog. Can be used to add sound effects to dice rolls. Extends the previous macro that uses names over id's and avoids unintended modifications to the item.
// Custom roll dialog that allows for audio
async function displayRollDialogWithAudio(data, dicePool, description, skillName, item, audio) {
const id = randomID();
const dicesymbols = {
advantage: "<span class='dietype starwars advantage'>a</span>",
success: "<span class='dietype starwars failure'>f</span>",
threat: "<span class='dietype starwars success'>s</span>",
failure: "<span class='dietype starwars threat'>t</span>",
};
const content = await renderTemplate("systems/starwarsffg/templates/roll-options.html", {
dicePool,
id,
dicesymbols
});
new Dialog(
{
title: description || game.i18n.localize("SWFFG.RollingDefaultTitle"),
content,
buttons: {
one: {
icon: '<i class="fas fa-check"></i>',
label: game.i18n.localize("SWFFG.ButtonRoll"),
callback: () => {
const container = document.getElementById(id);
const finalPool = DicePoolFFG.fromContainer(container);
const roll = new game.ffg.RollFFG(finalPool.renderDiceExpression(), item, finalPool);
roll.toMessage({
user: game.user._id,
speaker: data,
flavor: `${game.i18n.localize("SWFFG.Rolling")} ${skillName}...`,
});
AudioHelper.play(audio)
},
},
two: {
icon: '<i class="fas fa-times"></i>',
label: game.i18n.localize("SWFFG.Cancel"),
},
},
},
{
classes: ["dialog", "starwarsffg"],
}
).render(true);
}
// Set config values
const actor_name = "<Actor_Name_Here>"; // Must exactly match actor name
const item_name = "<Item_Name_Here>"; // Must exactly match item name
const skill_to_use = "Ranged: Heavy";
const display_name = "Light Repeating Blaster"; // Can be anything
const aims = 2;
// src must denote the filepath from foundrydata/data, volume is a value between 0 and 1, autoplay is true/false, loop is true/false
const audio = {src: "audio/Sound%20Effects/Melee/knife_tr_secondary_impact_flesh.mp3", volume: 0.4, autoplay: true, loop: false}
// Acquire actor
const actor = game.actors.getName(actor_name);
const actorSheet = actor.sheet.getData();
// Create copy of item so that changes are only temporary
const item = JSON.parse(JSON.stringify(actor.data.items.find(n => n.name === item_name)));
// Acquire skill and characteristic
const skill = actor.data.data.skills[skill_to_use];
const characteristic = actor.data.data.characteristics[skill.characteristic];
// Construct dice pool
const dicePool = new DicePoolFFG({
ability: Math.max(characteristic.value, skill.rank),
boost: skill.boost,
setback: skill.setback,
force: skill.force,
advantage: 0, // default to zero automatic advantages
difficulty: 2, // default to average difficulty
});
// Use skill and characteristic to create initial pool
dicePool.upgrade(Math.min(characteristic.value, skill.rank));
// Check for talents that modify the roll or result
const talents = actorSheet.data.talentList;
talents.forEach((talent) => {
if (talent.name === "True Aim") {
// Upgrade once for every rank in true aim
dicePool.upgrade(talent.rank);
}
if (talent.name === "Deadly Accuracy") {
// Add damage from deadly accuracy due to ranged: heavy ranks
item.data.damage.adjusted += actor.data.data.skills["Ranged: Heavy"].rank;
}
});
// Display roll dialogue using given attack_name and item
displayRollDialogWithAudio(actorSheet, dicePool, `${game.i18n.localize("SWFFG.Rolling")} ${display_name}`, display_name, item, audio);
- Getting started
- Helpful resources
- Frequently Asked Questions
- New feature walkthrough
- Genesys