Skip to content

Commit

Permalink
Added and updated macros
Browse files Browse the repository at this point in the history
  • Loading branch information
AnthonyVadala committed Jun 1, 2021
1 parent 194f855 commit 314818a
Show file tree
Hide file tree
Showing 3 changed files with 4 additions and 3 deletions.
2 changes: 1 addition & 1 deletion packs/macros-pf1e.db
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{"_id":"DqPNZUhidTtAtczn","name":"Channel Positive Healing","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"script","flags":{},"scope":"global","command":"// CONFIGURATION\n// Leave casterName as null to channel positive as the currently-selected character\n// Example `const casterName = \"Bob Bobbington\";`\nconst casterName = null;\n\nconst tokens = canvas.tokens.controlled;\nlet caster = tokens.map((o) => o.actor)[0];\nif (!caster && !!casterName) {\n caster = game.actors.entities.filter((o) => o.name.includes(casterName))[0];\n}\n\nfunction channelPositive() {\n if (!caster.data.data.classes.cleric) {\n ui.notifications.warn(\"You're not a cleric!\");\n return;\n }\n const clericLevel = caster.data.data.classes.cleric.level;\n const rollString = `${Math.floor((clericLevel + 1) / 2)}d6`;\n\n const roll = new Roll(rollString);\n roll.roll();\n roll.toMessage({\n flavor: \"Channeling positive energy\",\n });\n}\n\nif (!caster || caster === undefined) {\n ui.notifications.warn(\"You need to be controlling someone to channel!\")\n} else {\n channelPositive();\n}","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[]}
{"name":"Roll Knowledge Skill Check","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"script","flags":{},"scope":"global","command":"const tokens = canvas.tokens.controlled;\nconst caster = tokens[0];\n\nif (tokens.length !== 1) {\n ui.notifications.warn(\"Please select a token\");\n} else {\n const knowledgeTypes = [\n \"Arcana\",\n \"Dungeoneering\",\n \"Engineering\",\n \"Geography\",\n \"History\",\n \"Local\",\n \"Nature\",\n \"Nobility\",\n \"Planes\",\n \"Religion\",\n ];\n\n const knowledgeData = [];\n knowledgeTypes.forEach((type) => {\n const knowledgeDatum =\n caster.actor.data.data.skills[`k${type.toLowerCase().substring(0, 2)}`];\n knowledgeDatum.name = type;\n knowledgeData.push(knowledgeDatum);\n });\n\n const knownKnowledge = knowledgeData.filter((datum) => datum.rank > 0);\n\n if (knownKnowledge.length < 1) {\n ui.notifications.warn(\"You know nothing.\");\n } else {\n const buttons = {};\n knownKnowledge.forEach((type) => {\n buttons[type.name] = {\n label: type.name,\n callback: () => {\n rollCheck(type.name, type.mod);\n },\n };\n });\n\n new Dialog({\n title: \"Roll Knowledge!\",\n content: `<p>Choose a knowledge skill</p>`,\n buttons: buttons,\n }).render(true);\n }\n}\n\nfunction rollCheck(name, mod) {\n const roll = new Roll(`1d20 + ${mod}`);\n roll.roll();\n roll.toMessage({\n flavor: `Knowledge ${name} check`,\n speaker: { alias: token.actor.data.name },\n });\n}\n","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[],"_id":"JSZ1MvLeM0nFLU8f"}
{"_id":"cGbvJGOYy8MFDSpJ","name":"Wand of Cure Light Wounds","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"script","flags":{},"scope":"global","command":"// this script attempts to heal X points of damage by repeatedly using charges of wands of cure light wounds\n\nfunction hitTarget(target) {\n if (target > 250) {\n ui.notifications.warn(\n \"Too much healing! No one needs that much healing! Max 250.\"\n );\n return;\n }\n let current = 0;\n let chargesUsed;\n\n const rolls = [];\n for (chargesUsed = 0; current < target; chargesUsed += 1) {\n const roll = new Roll(\"1d8 + 1\");\n roll.roll();\n current += roll.total;\n rolls.push({ roll: roll.total - 1 });\n }\n\n const roll = new Roll(`${chargesUsed}d8 + ${chargesUsed}`);\n const msg = roll.toMessage(\n { flavor: `Casting <i>cure light wounds</i> ${chargesUsed} times` },\n { create: false }\n );\n\n const fakeRoll = {\n class: \"Roll\",\n formula: `${chargesUsed}d8 + ${chargesUsed}`,\n dice: [\n {\n class: \"Die\",\n faces: 8,\n rolls: rolls,\n formula: `${chargesUsed}d8`,\n options: {},\n },\n ],\n parts: [\"_d0\", \"+\", `${chargesUsed}`],\n result: `${current - chargesUsed} + ${chargesUsed}`,\n total: current,\n };\n\n msg.roll = JSON.stringify(fakeRoll);\n msg.content = String(current);\n\n const tokens = canvas.tokens.controlled;\n if (tokens.length !== 1) {\n ui.notifications.warn(\"Please select a token.\");\n return;\n }\n const token = tokens[0];\n msg.speaker = {alias: token.actor.data.name}\n\n ChatMessage.create(msg);\n}\n\nnew Dialog({\n title: \"Cast until heal a set amount\",\n content:\n \"<p>Enter the amount you want to heal</p><center><input type='number' id='amountInput'></center><br>\",\n buttons: {\n submit: {\n label: \"Heal\",\n icon: '<i class=\"fas fa-medkit\"></i>',\n callback: () => {\n const healTarget = parseInt(\n eval(\n $(\"#amountInput\")\n .val()\n .match(/[0-9]*/g)\n )\n );\n hitTarget(healTarget);\n },\n },\n },\n}).render(true);\n","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[]}
{"name":"Award XP","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"script","flags":{"core":{"sourceId":"Macro.ewQYDTKiqLCs17NT"}},"scope":"global","command":"// CONFIGURATION\n// If there are PCs you always want to exclude from showing on the checklist to award to, enter in \"ignorePCs\"\n// If there are NPCs that you want to ignore awarding XP for from the combat tracker, enter in \"ignoreNPCs\"\nconst c = {\n ignorePCs: [],\n ignoreNPCs: []\n};\n// END CONFIGURATION\n\nconst tokens = canvas.tokens.controlled;\nlet actorsSelected = tokens.map(o => o.actor);\nconsole.log(actorsSelected);\nlet actors = [];\nif (!actors.length && c.ignorePCs.length > 0) actors = game.actors.entities.filter(o => !c.ignorePCs.includes(o.name));\nif (!actors.length) actors = game.actors.entities.filter(o => o.hasPlayerOwner);\nactors = actors.filter(o => o.hasPerm(game.user, \"OWNER\") && !c.ignorePCs?.includes(o.name));\n\nif (!actors.length) ui.notifications.warn(\"No applicable actor(s) found\");\nelse {\n const _action = function(xp, checkedArray, distributed, pcCount, originalXp) {\n var targets=[];\n if (!isNaN(xp)) {\n for ( let actor of actors ) {\n for (let element of checkedArray) {\n if (element.name == actor.name){\n targets.push(actor);\n }\n }\n }\n \n let msg = `<div class=\"pf1 chat-card\">\n <header class=\"card-header flexrow\">\n <h3 class=\"actor-name\">${originalXp} XP Awarded</h3>\n </header>\n <div class=\"result-text\">`;\n if (distributed) {\n msg += `<p style=\"font-size: 14px; margin: .1em 0\">${originalXp} xp distributed among ${pcCount} characters (${xp} each).</p>`;\n }\n else {\n msg += `<p style=\"font-size: 14px; margin: .1em 0\">${xp} xp each awarded to ${pcCount} characters.</p>`;\n }\n \n targets.forEach(o => {\n let curXP = getProperty(o.data, \"data.details.xp.value\") || 0;\n let levelXP = getProperty(o.data, \"data.details.xp.max\");\n if (typeof curXP === \"string\") curXP = parseInt(curXP);\n o.update({ \"data.details.xp.value\": curXP + xp });\n msg += `<p style=\"font-size: 14px; margin: .1em 0\"><strong>${o.name}:</strong> ${curXP} xp updated to ${(curXP + xp)} (next level at ${levelXP})</p>`;\n });\n \n msg += `</div>`;\n \n ChatMessage.create({\n content: msg,\n speaker: ChatMessage.getSpeaker({alias: \"XP Awarded\"})\n });\n }\n };\n \n let thisCombat = game.combat?.combatants;\n let npcChecklist = \"\";\n let hasNPCs = false;\n let npcXpTotal = 0;\n \n if (thisCombat && thisCombat.length > 0) {\n let combatNPCs = thisCombat.filter(o => !o.actor.hasPlayerOwner && o.actor.data.type === \"npc\" && !c.ignoreNPCs.includes(o.actor.name));\n hasNPCs = (combatNPCs.length > 0);\n if (hasNPCs) {\n combatNPCs.forEach(combatant => {\n npcChecklist += `\n <input type=\"checkbox\" name=\"${combatant.actor.name}\" value=\"${combatant.actor.data.data.details.xp.value}\" checked class=\"npcXPCheckbox\">\\n\n <label for=\"${combatant.actor.name}\">${combatant.actor.name} (CR ${combatant.actor.data.data.details.cr.total}, ${combatant.actor.data.data.details.xp.value} xp)</label><br>`\n npcXpTotal += combatant.actor.data.data.details.xp.value;\n });\n }\n }\n \n let checkPlayerOptions = \"\";\n // Build checkbox list for all active players\n actors.forEach(actor => {\n let checked = '';\n if (actor.data.type === \"npc\") return;\n if (actor.hasPlayerOwner) checked = 'checked';\n if (actorsSelected.length && !actorsSelected.includes(actor)) checked = '';\n checkPlayerOptions+=`\n <br>\n <input type=\"checkbox\" class=\"awardedPC\" name=\"${actor.name}\" value=\"${actor.name}\" ${checked}>\\n\n <label for=\"${actor.name}\">${actor.name}</label>\n `\n });\n \n const msg = `\n Award XP to the following actors: ${checkPlayerOptions}\n <br>\n ${hasNPCs ? `<br>Award XP for the following: <br>${npcChecklist}` : ``}\n `;\n const field = `<input type=\"text\" id=\"xpAwardEntry\" name=\"xp\" placeholder=\"XP amount\" style=\"margin-bottom: 8px;\" />`;\n const xpDisplay = `<h3>Total XP: <span id=\"xpAwardTotal\">${npcXpTotal}</span></h3>`;\n\n new Dialog({\n title: \"Roll saving throw\",\n content: `<p>${msg}</p>${field}${xpDisplay}`,\n buttons: {\n ok: {\n label: \"Give All\",\n callback: html => {\n let checkedArray = html.find('input[class=\"awardedPC\"]:checked');\n let checkedCount = checkedArray.length;\n let xp = parseInt(html.find('span[id=\"xpAwardTotal\"]')[0].innerHTML);\n _action(xp, checkedArray, false, checkedCount, xp);\n },\n },\n distribute: {\n label: \"Distribute\",\n callback: html => {\n let checkedArray = html.find('input[class=\"awardedPC\"]:checked');\n let checkedCount = checkedArray.length;\n let originalXp = parseInt(html.find('span[id=\"xpAwardTotal\"]')[0].innerHTML);\n let xp = Math.floor(originalXp / checkedCount);\n _action(xp, checkedArray, true, checkedCount, originalXp);\n }\n }\n },\n render: (htm) => {\n htm.find('.npcXPCheckbox').click(updateChecked.bind(this, htm.find('span[id=\"xpAwardTotal\"]'), htm.find('input[id=\"xpAwardEntry\"]')));\n htm.find('#xpAwardEntry').on('input', updateValue.bind(this, htm.find('span[id=\"xpAwardTotal\"]'), htm.find('input[id=\"xpAwardEntry\"]')))\n },\n }).render(true);\n\n let updateChecked = function(xpSpan, xpInput, event) {\n let checkbox = event.target;\n npcXpTotal = checkbox.checked ? (npcXpTotal + parseInt(checkbox.value)) : (npcXpTotal - parseInt(checkbox.value));\n \n let inputXP = parseInt(xpInput.val());\n if (isNaN(inputXP)) inputXP = 0;\n let newXP = npcXpTotal + inputXP;\n xpSpan[0].innerHTML = newXP;\n }\n \n let updateValue = function(xpSpan, xpInput, event) {\n let inputXP = parseInt(xpInput.val());\n if (isNaN(inputXP)) inputXP = 0;\n let newXP = npcXpTotal + inputXP;\n xpSpan[0].innerHTML = newXP;\n }\n \n}","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[],"_id":"j0oo3IFNe29T21UA"}
{"_id":"j0oo3IFNe29T21UA","name":"Award XP","type":"script","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","scope":"global","command":"// CONFIGURATION\n// If there are PCs you always want to exclude from showing on the checklist to award to, enter in \"ignorePCs\"\n// If there are NPCs that you want to ignore awarding XP for from the combat tracker, enter in \"ignoreNPCs\"\nconst c = {\n ignorePCs: [],\n ignoreNPCs: []\n};\n// END CONFIGURATION\n\nconst tokens = canvas.tokens.controlled;\nlet actorsSelected = tokens.map(o => o.actor);\nconsole.log(actorsSelected);\nlet actors = [];\nif (!actors.length && c.ignorePCs.length > 0) actors = game.actors.entities.filter(o => !c.ignorePCs.includes(o.name));\nif (!actors.length) actors = game.actors.entities.filter(o => o.hasPlayerOwner);\nactors = actors.filter(o => o.hasPerm(game.user, \"OWNER\") && !c.ignorePCs?.includes(o.name));\n\nif (!actors.length) ui.notifications.warn(\"No applicable actor(s) found\");\nelse {\n const _action = function(xp, checkedArray, distributed, pcCount, originalXp) {\n var targets=[];\n if (!isNaN(xp)) {\n for ( let actor of actors ) {\n for (let element of checkedArray) {\n if (element.name == actor.name){\n targets.push(actor);\n }\n }\n }\n \n let msg = `<div class=\"pf1 chat-card\">\n <header class=\"card-header flexrow\">\n <h3 class=\"actor-name\">${originalXp} XP Awarded</h3>\n </header>\n <div class=\"result-text\">`;\n if (distributed) {\n msg += `<p style=\"font-size: 14px; margin: .1em 0\">${originalXp} xp distributed among ${pcCount} characters (${xp} each).</p>`;\n }\n else {\n msg += `<p style=\"font-size: 14px; margin: .1em 0\">${xp} xp each awarded to ${pcCount} characters.</p>`;\n }\n \n targets.forEach(o => {\n let curXP = getProperty(o.data, \"data.details.xp.value\") || 0;\n let levelXP = getProperty(o.data, \"data.details.xp.max\");\n if (typeof curXP === \"string\") curXP = parseInt(curXP);\n o.update({ \"data.details.xp.value\": curXP + xp });\n msg += `<p style=\"font-size: 14px; margin: .1em 0\"><strong>${o.name}:</strong> ${curXP} xp updated to ${(curXP + xp)} (next level at ${levelXP})</p>`;\n });\n \n msg += `</div>`;\n \n ChatMessage.create({\n content: msg,\n speaker: ChatMessage.getSpeaker({alias: \"XP Awarded\"})\n });\n }\n };\n \n let thisCombat = game.combat?.combatants;\n let npcChecklist = \"\";\n let hasNPCs = false;\n let npcXpTotal = 0;\n \n if (thisCombat && thisCombat.length > 0) {\n let combatNPCs = thisCombat.filter(o => !o.actor.hasPlayerOwner && o.actor.data.type === \"npc\" && !c.ignoreNPCs.includes(o.actor.name));\n hasNPCs = (combatNPCs.length > 0);\n if (hasNPCs) {\n combatNPCs.forEach(combatant => {\n npcChecklist += `\n <div class=\"form-group\">\n <input type=\"checkbox\" id=\"check${combatant.actor.name}\" name=\"${combatant.actor.name}\" value=\"${combatant.actor.data.data.details.xp.value}\" checked class=\"npcXPCheckbox\">\n <label for=\"check${combatant.actor.name}\">${combatant.actor.name} (CR ${combatant.actor.data.data.details.cr.total}, ${combatant.actor.data.data.details.xp.value} xp)</label>\n </div>`;\n npcXpTotal += combatant.actor.data.data.details.xp.value;\n });\n }\n }\n \n let checkPlayerOptions = \"\";\n // Build checkbox list for all active players\n actors.forEach(actor => {\n let checked = '';\n if (actor.data.type === \"npc\") return;\n if (actor.hasPlayerOwner) checked = 'checked';\n if (actorsSelected.length && !actorsSelected.includes(actor)) checked = '';\n checkPlayerOptions+=`\n <div class=\"form-group\">\n <input type=\"checkbox\" class=\"awardedPC\" id=\"check${actor.name}\" name=\"${actor.name}\" value=\"${actor.name}\" ${checked}><label for=\"check${actor.name}\">${actor.name}</label>\n </div>`;\n });\n \n const msg = `\n Award XP to the following actors: ${checkPlayerOptions}\n <hr>Award XP for the following: \n ${hasNPCs ? `${npcChecklist}` : ``}\n `;\n \n let xpLevels = CONFIG.PF1.CR_EXP_LEVELS.slice(1).map((o, index) => {\n let object = {xp: \"\", cr: 0};\n object.cr = index + 1;\n object.xp = o;\n return object;\n });\n \n xpLevels = [{cr: \"1/8\", xp: 50}, {cr: \"1/6\", xp: 65}, {cr: \"1/4\", xp: 100}, {cr: \"1/3\", xp: 135}, {cr: \"1/2\", xp: 200}].concat(xpLevels);\n \n const field = `\n <div class=\"form-group\">\n <label for=\"crSelect\">Award for CR: </label><select id=\"crSelect\"><option value=\"0\">Select CR</option>` + xpLevels.map(o => `<option value='${o.xp}'>${o.cr}: ${o.xp} XP</option>`) + `</select>\n </div>\n <div class=\"form-group\">\n <label for=\"xpAwardEntry\">Award Static XP:</label><input type=\"text\" id=\"xpAwardEntry\" name=\"xp\" placeholder=\"XP amount\" style=\"margin-bottom: 8px;\" />\n </div>`;\n const xpDisplay = `<h3>Total XP: <span id=\"xpAwardTotal\">${npcXpTotal}</span></h3>`;\n\n new Dialog({\n title: \"Roll saving throw\",\n content: `<form class=\"flexcol\">${msg}${field}${xpDisplay}</form>`,\n buttons: {\n ok: {\n label: \"Give All\",\n callback: html => {\n let checkedArray = html.find('input[class=\"awardedPC\"]:checked');\n let checkedCount = checkedArray.length;\n let xp = parseInt(html.find('span[id=\"xpAwardTotal\"]')[0].innerHTML);\n _action(xp, checkedArray, false, checkedCount, xp);\n },\n },\n distribute: {\n label: \"Distribute\",\n callback: html => {\n let checkedArray = html.find('input[class=\"awardedPC\"]:checked');\n let checkedCount = checkedArray.length;\n let originalXp = parseInt(html.find('span[id=\"xpAwardTotal\"]')[0].innerHTML);\n let xp = Math.floor(originalXp / checkedCount);\n _action(xp, checkedArray, true, checkedCount, originalXp);\n }\n }\n },\n render: (htm) => {\n htm.find('.npcXPCheckbox').click(updateChecked.bind(this, htm.find('span[id=\"xpAwardTotal\"]'), htm.find('input[id=\"xpAwardEntry\"]')));\n htm.find('#xpAwardEntry').on('input', updateValue.bind(this, htm.find('span[id=\"xpAwardTotal\"]'), htm.find('input[id=\"xpAwardEntry\"]')));\n htm.find('#crSelect').on('change', updateValue.bind(this, htm.find('span[id=\"xpAwardTotal\"]'), htm.find('select[id=\"crSelect\"]')));\n },\n }).render(true);\n\n let updateChecked = function(xpSpan, xpInput, event) {\n let checkbox = event.target;\n npcXpTotal = checkbox.checked ? (npcXpTotal + parseInt(checkbox.value)) : (npcXpTotal - parseInt(checkbox.value));\n \n let inputXP = parseInt(xpInput.val());\n if (isNaN(inputXP)) inputXP = 0;\n let newXP = npcXpTotal + inputXP;\n xpSpan[0].innerHTML = newXP;\n };\n \n let updateValue = function(xpSpan, xpInput, event) {\n console.log(xpInput.val());\n let inputXP = parseInt(xpInput.val());\n if (isNaN(inputXP)) inputXP = 0;\n let newXP = npcXpTotal + inputXP;\n xpSpan[0].innerHTML = newXP;\n };\n \n}","folder":null,"sort":0,"permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"flags":{"core":{"sourceId":"Macro.ewQYDTKiqLCs17NT"}}}
Loading

0 comments on commit 314818a

Please sign in to comment.