-
Notifications
You must be signed in to change notification settings - Fork 167
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
194f855
commit 314818a
Showing
3 changed files
with
4 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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"}}} |
Oops, something went wrong.