Hello,
I want to commission a PF2 system macro that allows to automate "procedural checks" for dungeon crawl and similar games where players stop at regular intervals (doors, rooms) and do the same checks, with predefined characters rolling predefined basic actions (i.e. Seek, Pick a Lock, Force Open).
An example default for a "Door" macro
An example default for "Rummage a Room" macro
The macro will be run by the DM, forcing each character to make the defined rolls. The results could be triggers of the standard posts in chat, though in a perfect would they would fit in their own pretty UI (for that I would pay extra) that makes it very compact for the DM
The macro's functionality
Quality of Life functionality
// Dialog's Title
const title = 'Door Checks';
// List of actors you want to list in the Dropdown Menu
const party = ['5YCNP4CvPp6hw7WN', '8A5qtayUjkhqfoYi','Cy3njyMAB5K3eUxm','T9tSdOoarQBOsTz5'];
// Actions you want to take
const actions = [{ name: 'Seek', default: 'T9tSdOoarQBOsTz5' },{ name: 'Seek', default: '5YCNP4CvPp6hw7WN' },{ name: 'Pick a Lock', default: '8A5qtayUjkhqfoYi' },{ name: 'Force Open', default: 'Cy3njyMAB5K3eUxm' }];
const actors = party.map((a) => game.actors.get(a));
if (window.actionDialog?.rendered) {
return window.actionDialog.close();
}
/*
* Default Icon to be given in case there is no icon parameter in an Action
*/
const defaultIcon = 'systems/pf2e/icons/actions/craft/unknown-item.webp';
/**
* This is the list of actions, wich can de edited
*
* Action Interface:
* @param {string} name Name shown as the button text;
* @param {string} skill Name of the skill, to get the bonus in parenthesis from;
* @param {function|string} action Function or Macro ID (in case of a string) to call;
* The call passes an {actors: [actor]} object as argument;
* @param {string|undefined} icon The icon to be shown in the button. If undefined, will
* return the defaultIcon;
*/
const actionList = [
{
name: 'Aid',
skill: '',
action: 'y1rDU9gTz6GVobwf',
icon: 'systems/pf2e/icons/spells/efficient-apport.webp',
},
{
name: 'Avoid Notice',
skill: 'Stealth',
action: game.pf2e.actions.avoidNotice,
icon: 'systems/pf2e/icons/features/classes/surprice-attack.webp',
},
{
name: 'Balance',
skill: 'Acrobatics',
action: game.pf2e.actions.balance,
icon: '<https://i.imgur.com/q9zXci0.png>',
},
{
name: 'Climb',
skill: 'Athletics',
action: game.pf2e.actions.climb,
icon: 'icons/sundries/misc/ladder.webp',
},
{
name: 'Coerce',
skill: 'Intimidation',
action: game.pf2e.actions.coerce,
icon: '<https://i.imgur.com/iIDYVQL.png>',
},
{
name: 'Command an Animal',
skill: 'Nature',
action: game.pf2e.actions.commandAnAnimal,
icon: '<https://i.imgur.com/5EqnTIS.png>',
},
{
name: 'Craft',
skill: 'Crafting',
action: game.pf2e.actions.craft,
icon: '<https://i.imgur.com/McuTUGb.png>',
},
{
name: 'Create a Diversion - Gesture',
skill: 'Deception',
action: "game.pf2e.actions.createADiversion({ event: event, variant: 'gesture' });",
icon: '<https://i.imgur.com/Rc9vnMX.png>',
},
{
name: 'Create a Diversion - Trick',
skill: 'Deception',
action: "game.pf2e.actions.createADiversion({ event: event, variant: 'trick' });",
icon: '<https://i.imgur.com/u9Pt7q1.png>',
},
{
name: 'Demoralize',
skill: 'Intimidation',
action: game.pf2e.actions.demoralize,
icon: 'icons/skills/social/intimidation-impressing.webp',
},
{
name: 'Disarm',
skill: 'Athletics',
action: game.pf2e.actions.disarm,
icon: 'icons/skills/melee/sword-damaged-broken-glow-red.webp',
},
{
name: 'Feint',
skill: 'Deception',
action: game.pf2e.actions.feint,
icon: '<https://i.imgur.com/EIRuIFp.png>',
},
{
name: 'Follow an Expert',
skill: '',
action: 'eHtbauiO3n075GUu',
icon: 'systems/pf2e/icons/spells/favorable-review.webp',
},
{
name: 'Force Open',
skill: 'Athletics',
action: game.pf2e.actions.forceOpen,
icon: '<https://i.imgur.com/BkwG0cZ.png>',
},
{
name: 'Gather Information',
skill: 'Diplomacy',
action: game.pf2e.actions.gatherInformation,
icon: 'icons/skills/social/diplomacy-handshake.webp',
},
{
name: 'Grapple',
skill: 'Athletics',
action: game.pf2e.actions.grapple,
icon: 'icons/skills/melee/unarmed-punch-fist.webp',
},
{
name: 'Hide',
skill: 'Stealth',
action: game.pf2e.actions.hide,
icon: 'icons/magic/nature/stealth-hide-eyes-green.webp',
},
{
name: 'Impersonate',
skill: 'Deception',
action: game.pf2e.actions.impersonate,
},
{
name: 'Jump - High',
skill: 'Athletics',
action: game.pf2e.actions.highJump,
icon: '<https://i.imgur.com/Ot4sbDt.png>',
},
{
name: 'Jump - Long',
skill: 'Athletics',
action: game.pf2e.actions.longJump,
icon: '<https://i.imgur.com/Ot4sbDt.png>',
},
{
name: 'Lie',
skill: 'Deception',
action: game.pf2e.actions.lie,
icon: 'icons/magic/control/mouth-smile-deception-purple.webp',
},
{
name: 'Make an Impression',
skill: 'Diplomacy',
action: game.pf2e.actions.makeAnImpression,
icon: 'icons/environment/people/commoner.webp',
},
{
name: 'Maneuver in Flight',
skill: 'Acrobatics',
action: game.pf2e.actions.maneuverInFlight,
icon: 'icons/commodities/biological/wing-bird-white.webp',
},
{
name: 'Pick a Lock',
skill: 'Thievery',
action: game.pf2e.actions.pickALock,
icon: '<https://i.imgur.com/cb7ejb2.png>',
},
{
name: 'Raise a Shield',
skill: '',
action: game.pf2e.actions.raiseAShield,
icon: 'systems/pf2e/icons/actions/raise-a-shield.webp',
},
{
name: 'Recall Knowledge',
skill: '',
action: 'EBdLzeLZyUju18Af',
icon: 'systems/pf2e/icons/features/classes/imperial.webp',
},
{
name: 'Repair',
skill: 'Crafting',
action: game.pf2e.actions.repair,
icon: '<https://i.imgur.com/McuTUGb.png>',
},
{
name: 'Request',
skill: 'Diplomacy',
action: game.pf2e.actions.request,
icon: 'icons/skills/social/thumbsup-approval-like.webp',
},
{
name: 'Seek',
skill: 'Perception',
action: game.pf2e.actions.seek,
icon: '<https://i.imgur.com/7mTBOrS.png>',
},
{
name: 'Sense Direction',
skill: 'Survival',
action: game.pf2e.actions.senseDirection,
icon: 'icons/tools/navigation/compass-brass-blue-red.webp',
},
{
name: 'Sense Motive',
skill: 'Perception',
action: game.pf2e.actions.senseMotive,
icon: '<https://i.imgur.com/7mTBOrS.png>',
},
{
name: 'Shove',
skill: 'Athletics',
action: game.pf2e.actions.shove,
icon: '<https://i.imgur.com/Expmoz8.png>',
},
{
name: 'Sneak',
skill: 'Stealth',
action: game.pf2e.actions.sneak,
icon: 'icons/magic/nature/stealth-hide-eyes-green.webp',
},
{
name: 'Squeeze',
skill: 'Acrobatics',
action: game.pf2e.actions.squeeze,
icon: '<https://i.imgur.com/sQ6eUA4.png>',
},
{
name: 'Swim',
skill: 'Athletics',
action: game.pf2e.actions.swim,
icon: 'icons/creatures/fish/fish-shark-swimming.webp',
},
{
name: 'Take Cover',
skill: '',
action: 'PC0y5A6tHrtJhqVL',
icon: '<https://i.imgur.com/5TgWEZF.png>',
},
{
name: 'Track',
skill: 'Survival',
action: game.pf2e.actions.track,
icon: '<https://i.imgur.com/RgHVtlC.png>',
},
{
name: 'Treat Disease',
skill: 'Medicine',
action: game.pf2e.actions.treatDisease,
icon: 'icons/magic/nature/root-vine-caduceus-healing.webp',
},
{
name: 'Treat Poison',
skill: 'Medicine',
action: game.pf2e.actions.treatPoison,
icon: 'systems/pf2e/icons/effects/treat-poison.webp',
},
{
name: 'Treat Wounds',
skill: 'Medicine',
action: 'BO2iFo14pFYHEIGa',
icon: 'icons/magic/nature/root-vine-caduceus-healing.webp',
},
{
name: 'Trip',
skill: 'Athletics',
action: game.pf2e.actions.trip,
icon: '<https://i.imgur.com/Sr2Gu19.png>',
},
{
name: 'Tumble Through',
skill: 'Acrobatics',
action: game.pf2e.actions.tumbleThrough,
icon: '<https://i.imgur.com/33UF9Ok.png>',
},
].sort((a, b) => -(a.name < b.name));
const getSkills = (actor) => {
return { perception: actor.attributes.perception, ...actor.skills };
};
const createMenu = (actionName) => {
const action = actionList.find((a) => a.name === actionName.name);
const idx = actionList.indexOf(action);
const options = actors.map((actor) => `<option value="${actor.id}" ${actor.id === actionName.default ? 'selected' : ''}>${actor.name}</option>`).join('');
return `
<div class="form-group">
<label class="centered"><img src="${action.icon ?? defaultIcon}" height="24"/> ${action.name}</label>
<select name="${action.name}">
${options}
</select>
<button class="small" data-action="${idx}">
<i class="fas fa-dice-d6"></i>
Roll
</button>
</div>
`;
};
const content = `
<style>
label.centered {
display: flex;
justify-content: flex-start;
}
label.centered img {
margin-right: 10px;
}
button.small {
flex: 1;
margin-left: 5px;
}
</style>
<form autocomplete="off" spellcheck="off">
${actions.map((action) => createMenu(action)).join('')}
</form>
`;
window.actionDialog = new Dialog(
{
title,
content,
buttons: {
rollAll: {
icon: `<i class="fas fa-dice"></i>`,
label: 'Roll All',
callback: (html) => {
const buttons = html.querySelectorAll('form button');
if (game.user.getFlag('pf2e', 'settings.showRollDialogs')) {
for (let i = buttons.length; i > 0; i--) buttons[i - 1].click();
return;
}
buttons.forEach((btn) => btn.click());
},
},
},
default: 'rollAll',
render: (html) => {
actionDialog.submit = function (button, event) {
try {
if (button.callback) button.callback(this.options.jQuery ? this.element : this.element[0], event);
} catch (err) {
ui.notifications.error(err);
throw new Error(err);
}
};
const action = (button) => {
const idx = button.dataset.action;
const action = actionList[idx];
const actor = actors[party.indexOf(button.parentElement.querySelector('select').value)];
if (typeof action.action === 'string') game.macros.get(action.action)?.execute();
else action.action({ actors: [actor] });
};
html.querySelectorAll('form button').forEach((button) => button.addEventListener('click', () => action(button)));
},
},
{ jQuery: false }
).render(true);
Action Name | Skill | PF2 System Function that can be called as a macro |
---|---|---|
Avoid Notice | Stealth | game.pf2e.actions.avoidNotice({ event: event }); |
Balance | Acrobatics | game.pf2e.actions.balance({ event: event }); |
Climb | Athletics | game.pf2e.actions.climb({ event: event }); |
Coerce | Intimidation | game.pf2e.actions.coerce({ event: event }); |
Command an Animal | Nature | game.pf2e.actions.commandAnAnimal({ event: event }); |
Craft | Crafting | game.pf2e.actions.craft({ event: event }); |
Create a Diversion - Gesture | Deception | game.pf2e.actions.createADiversion({ event: event, variant: 'gesture' }); |
Create a Diversion - Trick | Deception | game.pf2e.actions.createADiversion({ event: event, variant: 'trick' }); |
Demoralize | Intimidation | game.pf2e.actions.demoralize({ event: event }); |
Disarm | Athletics | game.pf2e.actions.disarm({ event: event }); |
Feint | Deception | game.pf2e.actions.feint({ event: event }); |
Force Open | Athletics | game.pf2e.actions.forceOpen({ event: event }); |
Gather Information | Diplomacy | game.pf2e.actions.gatherInformation({ event: event }); |
Grapple | Athletics | game.pf2e.actions.grapple({ event: event }); |
Hide | Stealth | game.pf2e.actions.hide({ event: event }); |
Impersonate | Deception | game.pf2e.actions.impersonate({ event: event }); |
Jump - High | Athletics | game.pf2e.actions.highJump({ event: event }); |
Jump - Long | Athletics | game.pf2e.actions.longJump({ event: event }); |
Lie | Deception | game.pf2e.actions.lie({ event: event }); |
Make an Impression | Diplomacy | game.pf2e.actions.makeAnImpression({ event: event }); |
Maneuver in Flight | Acrobatics | game.pf2e.actions.maneuverInFlight({ event: event }); |
Pick a Lock | Thievery | game.pf2e.actions.pickALock({ event: event }); |
Raise a Shield | Macro | game.pf2e.actions.raiseAShield({ actors: [token?.actor ?? actor ?? game.user.character].filter((actor) => actor) }) |
Recall Knowledge | Macro | see Recall Knowledge macro |
Repair | Crafting | game.pf2e.actions.repair({ event: event }); |
Request | Diplomacy | game.pf2e.actions.request({ event: event }); |
Seek | Perception | game.pf2e.actions.seek({ event: event }); |
Sense Direction | Survival | game.pf2e.actions.senseDirection({ event: event }); |
Sense Motive | Perception | game.pf2e.actions.senseMotive({ event: event }); |
Shove | Athletics | game.pf2e.actions.shove({ event: event }); |
Sneak | Stealth | game.pf2e.actions.sneak({ event: event }); |
Squeeze | Acrobatics | game.pf2e.actions.squeeze({ event: event }); |
Swim | Athletics | game.pf2e.actions.swim({ event: event }); |
Take Cover | Macro | see Take Cover macro |
Track | Survival | game.pf2e.actions.track({ event: event }); |
Treat Disease | Medicine | game.pf2e.actions.treatDisease({ event: event }); |
Treat Poison | Medicine | game.pf2e.actions.treatPoison({ event: event }); |
Treat Wounds | Macro | see Treat Wounds macro |
Trip | Athletics | game.pf2e.actions.trip({ event: event }); |
Tumble Through | Acrobatics | game.pf2e.actions.tumbleThrough({ event: event }); |