From 03452b64841e7a5372b50d6c40c7c76fc410edb5 Mon Sep 17 00:00:00 2001 From: Anthony Vadala Date: Tue, 26 May 2020 18:24:35 -0400 Subject: [PATCH] Added new macros to packs --- packs/macros-actor.db | 3 +++ packs/macros-item.db | 1 + packs/macros-token.db | 1 + 3 files changed, 5 insertions(+) diff --git a/packs/macros-actor.db b/packs/macros-actor.db index 40f56b6..589c310 100644 --- a/packs/macros-actor.db +++ b/packs/macros-actor.db @@ -1,9 +1,12 @@ {"name":"Random Cutting Words","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"script","flags":{},"scope":"global","command":"// Courtesy of @Zarek\n// Selected target receives a random cutting word from a table called \"Mockeries\" along with the roll reduction.\n\nif (!actor) {\n ui.notifications.warn(\"You must have an actor selected.\");\n return\n}\n\n// Setup variables\nlet actorLevels = actor.data.data.levels || 1;\nlet tableName = \"Mockeries\";\nlet table = game.tables.entities.find(t => t.name == tableName);\nlet mockery = \"Now go away or I shall taunt you a second time-a!\";\n\n// Get Targets name\nconst targetId = game.user.targets.ids[0];\nconst targetToken = canvas.tokens.get(targetId);\nif (!targetToken) {\n ui.notifications.warn(\"You must target a token.\");\n return\n}\nconst targetName = targetToken.name;\n\n// Roll the result, and mark it drawn\nif (table) {\n if (checkTable(table)) {\n let roll = table.roll();\n let result = roll.results[0];\n mockery = result.text;\n table.updateEmbeddedEntity(\"TableResult\", {\n _id: result._id,\n drawn: true\n });\n }\n}\n\nfunction checkTable(table) {\n let results = 0;\n for (let data of table.data.results) {\n if (!data.drawn) {\n results++;\n }\n }\n if (results < 1) {\n table.reset();\n ui.notifications.notify(\"Table Reset\")\n return false\n }\n return true\n}\n\nlet dieType = 'd6';\nif (actorLevels >= 15) {\n dieType = 'd12';\n} else if (actorLevels >= 10) {\n dieType = 'd10';\n} else if (actorLevels >= 5) {\n dieType = 'd8';\n}\n\nlet messageContent = `

${targetName} Reduce your roll by: [[1${dieType}]].

`\nmessageContent += `

${token.name} exclaims \"${mockery}\"

`\nmessageContent += `
Cutting Words\n

When a creature that you can see within 60 feet of you makes an Attack roll, an ability check, or a damage roll, you can use your Reaction to expend one of your uses of Bardic Inspiration,\nrolling a Bardic Inspiration die and subtracting the number rolled from the creature’s roll.

\n

You can choose to use this feature after the creature makes its roll, but before the GM determines whether the Attack roll or ability check succeeds or fails, or before the creature deals its damage. \nThe creature is immune if it can’t hear you or if it’s immune to being Charmed.

`\n\n// create the message\nif (messageContent !== '') {\n let chatData = {\n user: game.user._id,\n speaker: ChatMessage.getSpeaker(),\n content: messageContent,\n };\n ChatMessage.create(chatData, {});\n}\n","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[],"_id":"Fa1wGSaq5J1GArjB"} +{"name":"Sharpshooter","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"script","flags":{},"scope":"global","command":"/*\nCreated Monkan#8752 with guidance from the Rage macro in the FVTT Community Macros\n\nTips to make it work\n 1 - Have a feature called 'Sharpshooter' for your character.\n 2 - Make sure you have your weapons with Ranged Weapon Attack. \n 3 - if you make any changes to your damage or attack calculations, make sure you toggle it off.\n As it stores the old values to replace once you disable the feat. It could undo your changes.\n*/\n\nlet ss='';\nlet chatMsg='';\n\n\nif (actor !== undefined && actor !== null) {\n // find the feat Sharpshooter\n ss = actor.items.find(i => i.name === 'Sharpshooter');\n if (ss == undefined) { \n ui.notifications.warn(\"Please select a single token with the Sharpshooter feat.\"); \n }\n\n if (ss !== undefined && ss !== null) {\n\t\tchatMsg = '';\n\t\tlet enabled = false;\n\t\t// store the state of the Sharpshooter toggle in flags\n\t\tif (actor.data.flags.ssMacro !== null && actor.data.flags.ssMacro !== undefined) {\n\t\t\tenabled = true;\n\t\t}\n\t\t// if Sharpshooter is active, disable it\n\t\tif (enabled) {\n chatMsg = `${actor.name} is aiming Normally now.`;\n \n let obj = {};\n\t\t\tobj['flags.ssMacro'] = null;\t\t\t\n\t\t\tactor.update(obj);\n\n\t\t\t// reset items\n\t\t\tfor (let item of actor.items) {\n\t\t\t\tif (item.data.flags.ssMacro !== null && item.data.flags.ssMacro !== undefined) {\n\t\t\t\t\t// restoring the old value from flags\n let oldDmg = item.data.flags.ssMacro.oldDmg;\n let oldAtk = item.data.flags.ssMacro.oldAtk;\n\t\t\t\t\tlet obj = {};\n obj['data.damage.parts'] = oldDmg;\n obj['data.attackBonus'] = oldAtk;\n\t\t\t\t\tobj['flags.ssMacro'] = null;\n\t\t\t\t\titem.update(obj);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t// if Sharpshooter is disabled, enable it\n\t\t} else {\n chatMsg = `${actor.name} is aiming very carefully!`;\n \n let obj = {};\n\t\t\tobj['flags.ssMacro.enabled'] = true;\n\t\t\tactor.update(obj);\n\n // update items\n let ssAtk = -5;\n\t\t\tlet ssDmg = 10;\n\t\t\tfor (let item of actor.items) {\n let isRanged = getProperty(item, 'data.data.actionType') === 'rwak'; \n\t\t\t\tif (isRanged && item.data.data.damage.parts.length > 0) {\n\t\t\t\t\tconsole.log('updating ' + item);\n let obj = {};\n let atk = item.data.data.attackBonus;\n let dmg = item.data.data.damage.parts;\n // Save old attack and damage values\n obj['flags.ssMacro.oldDmg'] = JSON.parse(JSON.stringify(dmg));\n obj['flags.ssMacro.oldAtk'] = JSON.parse(JSON.stringify(atk));\n // Set the new attack and damage values\n if (atk !== null) {\n atk += '' + ssAtk;\n } else {\n atk = ssAtk;\n }\n\t\t\t\t\tdmg[0][0] = `${dmg[0][0]} + ${ssDmg}`;\n obj['data.damage.parts'] = dmg;\n obj['data.attackBonus'] = atk;\n\t\t\t\t\titem.update(obj);\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n }\n\n} else ui.notifications.warn(\"Please select a token.\");\n\n// write to chat if needed:\nif (chatMsg !== '') {\n\tlet chatData = {\n\t\tuser: game.user._id,\n\t\tspeaker: ChatMessage.getSpeaker(),\n\t\tcontent: chatMsg\n };\n\tChatMessage.create(chatData, {});\n}","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[],"_id":"La6FnFrqIgommZor"} {"_id":"USJZMHU93aFklWYM","name":"Change Disposition","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"script","flags":{},"scope":"global","command":"let applyChanges = false;\nnew Dialog({\n title: `Token Disposition Changer`,\n content: `\n
\n
\n \n \n
\n
\n `,\n buttons: {\n yes: {\n icon: \"\",\n label: `Apply Changes`,\n callback: () => applyChanges = true\n },\n no: {\n icon: \"\",\n label: `Cancel Changes`\n },\n },\n default: \"yes\",\n close: html => {\n if (applyChanges) {\n for ( let token of canvas.tokens.controlled ) {\n let dispoType = html.find('[name=\"dispo-type\"]')[0].value || \"none\";\n switch (dispoType) {\n case \"hostile\":\n token.update({\"disposition\": -1});\n break;\n case \"friendly\":\n token.update({\"disposition\": 1});\n break;\n case \"neutral\":\n token.update({\"disposition\": 0});\n break;\n case \"nochange\":\n default:\n }\n }\n }\n }\n}).render(true);\n","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[]} +{"name":"Great Weapon Master","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"script","flags":{},"scope":"global","command":"/*\nCreated Monkan#8752 with guidance from the Rage macro in the FVTT Community Macros\n\nTips to make it work\n 1 - Have a feature called 'Great Weapon Master' for your character.\n 2 - Make sure you have your weapons with Heavy property filled out. \n 3 - if you make any changes to your damage or attack calculations, make sure you toggle it off.\n As it stores the old values to replace once you disable the feat. It could undo your changes.\n*/\n\nlet gwm='';\nlet chatMsg='';\n\n\nif (actor !== undefined && actor !== null) {\n // find the feat Great Weapon Master\n gwm = actor.items.find(i => i.name === 'Great Weapon Master');\n if (gwm == undefined) { \n ui.notifications.warn(\"Please select a single token with the Great Weapon Master feat.\"); \n }\n\n if (gwm !== undefined && gwm !== null) {\n\t\tchatMsg = '';\n\t\tlet enabled = false;\n\t\t// store the state of the GWM toggle in flags\n\t\tif (actor.data.flags.gwmMacro !== null && actor.data.flags.gwmMacro !== undefined) {\n\t\t\tenabled = true;\n\t\t}\n\t\t// if GWM is active, disable it\n\t\tif (enabled) {\n chatMsg = `${actor.name} is swinging Normally now.`;\n \n let obj = {};\n\t\t\tobj['flags.gwmMacro'] = null;\t\t\t\n\t\t\tactor.update(obj);\n\n\t\t\t// reset items\n\t\t\tfor (let item of actor.items) {\n\t\t\t\tif (item.data.flags.gwmMacro !== null && item.data.flags.gwmMacro !== undefined) {\n\t\t\t\t\t// restoring the old value from flags\n let oldDmg = item.data.flags.gwmMacro.oldDmg;\n let oldAtk = item.data.flags.gwmMacro.oldAtk;\n\t\t\t\t\tlet obj = {};\n obj['data.damage.parts'] = oldDmg;\n obj['data.attackBonus'] = oldAtk;\n\t\t\t\t\tobj['flags.gwmMacro'] = null;\n\t\t\t\t\titem.update(obj);\n\t\t\t\t}\n\t\t\t}\n\t\t\t\n\t\t// if GWM is disabled, enable it\n\t\t} else {\n chatMsg = `${actor.name} is swinging Harder!`;\n \n let obj = {};\n\t\t\tobj['flags.gwmMacro.enabled'] = true;\n\t\t\tactor.update(obj);\n\n // update items\n let gwmAtk = -5;\n\t\t\tlet gwmDmg = 10;\n\t\t\tfor (let item of actor.items) {\n let isMelee = getProperty(item, 'data.data.actionType') === 'mwak';\n let isHeavy = getProperty(item, 'data.data.properties.hvy')\n\t\t\t\tif (isMelee && isHeavy && item.data.data.damage.parts.length > 0) {\n\t\t\t\t\tconsole.log('updating ' + item);\n let obj = {};\n let atk = item.data.data.attackBonus;\n let dmg = item.data.data.damage.parts;\n // Save old attack and damage values\n obj['flags.gwmMacro.oldDmg'] = JSON.parse(JSON.stringify(dmg));\n obj['flags.gwmMacro.oldAtk'] = JSON.parse(JSON.stringify(atk));\n // Set the new attack and damage values\n if (atk !== null) {\n atk += '' + gwmAtk;\n } else {\n atk = gwmAtk;\n }\n\t\t\t\t\tdmg[0][0] = `${dmg[0][0]} + ${gwmDmg}`;\n obj['data.damage.parts'] = dmg;\n obj['data.attackBonus'] = atk;\n\t\t\t\t\titem.update(obj);\n\t\t\t\t}\n\t\t\t}\n\n\t\t}\n }\n\n} else ui.notifications.warn(\"Please select a token.\");\n\n// write to chat if needed:\nif (chatMsg !== '') {\n\tlet chatData = {\n\t\tuser: game.user._id,\n\t\tspeaker: ChatMessage.getSpeaker(),\n\t\tcontent: chatMsg\n };\n\tChatMessage.create(chatData, {});\n}","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[],"_id":"XGhD5LFKknPzy7ar"} {"name":"Divine Smite","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"script","flags":{},"scope":"global","command":"/*\n * The Smite macro emulates the Divine Smite feature of Paladins in DnD 5e. A spell slot level to use\n * can be selected, which increases the number of damage dice, and smiting a fiend or undead\n * will also increase the number of damage dice.\n * \n * First, select a token to perform the smite, then target an enemy to be smitten. Make your regular \n * attack and then if you choose to use Divine Smite, run this macro.\n */\n\nlet confirmed = false;\n\n// Create a dialogue box to select spell slot level to use when smiting.\nnew Dialog({\n title: \"Divine Smite Damage\",\n content: `\n

Spell Slot level to use Divine Smite with.

\n
\n
\n \n \n
\n
\n `,\n buttons: {\n one: {\n icon: '',\n label: \"SMITE!\",\n callback: () => confirmed = true\n },\n two: {\n icon: '',\n label: \"Cancel\",\n callback: () => confirmed = false\n }\n },\n default: \"Cancel\",\n close: html => {\n if (confirmed) {\n let slotLevel = parseInt(html.find('[name=slot-level]')[0].value);\n smite(slotLevel);\n }\n }\n}).render(true);\n\n/**\n * Gives the spell slot information for a particular actor and spell slot level.\n * @param {Actor5e} actor - the actor to get slot information from.\n * @param {integer} level - the spell slot level to get information about. level 0 is deprecated.\n * @returns {object} contains value (number of slots remaining), max, and override.\n */\nfunction getSpellSlots(actor, level) {\n let spells = actor.data.data.spells;\n switch (level) {\n case 1:\n return spells.spell1;\n case 2:\n return spells.spell2;\n case 3:\n return spells.spell3;\n case 4:\n return spells.spell4;\n case 5:\n return spells.spell5;\n }\n}\n\n/**\n * Use the controlled token to smite the targeted token.\n * @param {integer} slotLevel - the spell slot level to use when smiting.\n */\nfunction smite(slotLevel) {\n let targets = game.user.targets;\n let suseptible = [\"fiend\", \"undead\"];\n let controlledActor = canvas.tokens.controlled[0].actor;\n let chosenSpellSlots = getSpellSlots(controlledActor, slotLevel);\n\n if (chosenSpellSlots.value < 1) {\n ui.notifications.error(\"No spell slots of the required level available.\");\n return;\n }\n if (targets.size !== 1) {\n ui.notifications.error(\"You must target exactly one token to Smite.\");\n return;\n }\n\n targets.forEach(target => {\n let numDice = slotLevel + 1;\n let type = target.actor.data.data.details.type.toLocaleLowerCase();\n if (suseptible.includes(type)) numDice += 1;\n new Roll(`${numDice}d8`).roll().toMessage({ flavor: \"Macro Divine Smite - Damage Roll (Radiant)\", speaker })\n })\n\n chosenSpellSlots.value -= 1;\n}","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[],"_id":"YTCLwzzucNLqs9u1"} {"_id":"ZvtYrzlv9dPpq9Pu","name":"Random Mockeries","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"script","flags":{},"scope":"global","command":"// Courtesy of @Zarek\n// Selected target receives a random mockery from a table called \"Mockeries\" along with the DC and damage.\n\nif (!actor) {\n ui.notifications.warn(\"You must have an actor selected.\");\n return\n}\n\n// Setup variables\nlet actorLevels = actor.data.data.levels || 1;\nlet tableName = \"Mockeries\";\nlet table = game.tables.entities.find(t => t.name == tableName);\nlet mockery = \"Now go away or I shall taunt you a second time-a!\";\n\n// Get Targets name\nconst targetId = game.user.targets.ids[0];\nconst targetToken = canvas.tokens.get(targetId);\nif (!targetToken) {\n ui.notifications.warn(\"You must target a token.\");\n return\n}\nconst targetName = targetToken.name;\n\n// Roll the result, and mark it drawn\nif (table) {\n if (checkTable(table)) {\n let roll = table.roll();\n let result = roll.results[0];\n mockery = result.text;\n table.updateEmbeddedEntity(\"TableResult\", {\n _id: result._id,\n drawn: true\n });\n }\n}\n\nfunction checkTable(table) {\n let results = 0;\n for (let data of table.data.results) {\n if (!data.drawn) {\n results++;\n }\n }\n if (results < 1) {\n table.reset();\n ui.notifications.notify(\"Table Reset\")\n return false\n }\n return true\n}\n\n// Add a message with damage roll\nlet numDie = 1;\nif (actorLevels >= 17) {\n numDie = 4;\n} else if (actorLevels >= 11) {\n numDie = 3;\n} else if (actorLevels >= 5) {\n numDie = 2;\n}\n\nlet messageContent = `

${targetName} Roll WIS save DC [[8+${actor.data.data.abilities.cha.mod}+@attributes.prof]] or take [[${numDie}d4]] damage and have disadvantage.

`\nmessageContent += `

${token.name} exclaims \"${mockery}\"

`\nmessageContent += `
Vicious Mockery

You unleash a string of insults laced with subtle enchantments at a creature you can see within range. If the target can hear you (though it need not understand you), it must succeed on a Wisdom saving throw or take 1d4 psychic damage and have disadvantage on the next attack roll it makes before the end of its next turn.

\n

This spell’s damage increases by 1d4 when you reach 5th level ([[/r 2d4]]), 11th level ([[/r 3d4]]), and 17th level ([[/r 4d4]]).

`\n\n// create the message\nif (messageContent !== '') {\n let chatData = {\n user: game.user._id,\n speaker: ChatMessage.getSpeaker(),\n content: messageContent,\n };\n ChatMessage.create(chatData, {});\n}\n","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[]} {"_id":"cVkN7qB4m1mRauBE","name":"Remove Conditions","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"script","flags":{},"scope":"global","command":"for ( let token of canvas.tokens.controlled ){\n await token.update({\"effects\": []});\n}","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[]} {"name":"Random Inspiration","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"script","flags":{},"scope":"global","command":"// Courtesy of @Zarek\n// Selected target receives a random inspiration from a table called \"Inspirations\".\n\nif (!actor) {\n ui.notifications.warn(\"You must have an actor selected.\");\n return\n}\n\n// Get Targets name\nlet actorLevels = actor.data.data.levels || 1;\nconst targetId = game.user.targets.ids[0];\nconst targetToken = canvas.tokens.get(targetId);\nif (!targetToken) {\n ui.notifications.warn(\"You must target a token.\");\n return\n}\nconst targetName = targetToken.name;\n\n// Setup variables\nlet tableName = \"Inspirations\";\nlet table = game.tables.entities.find(t => t.name == tableName);\n//let inspiration = \"Cowards die many times before their deaths; the valiant never taste death but once.\";\nlet inspiration = `I don't know what effect ${targetName} will have upon the enemy, but, by God, he terrifies me.`;\n// Roll the result, and mark it drawn\nif (table) {\n if (checkTable(table)) {\n // let result = table.roll()[1];\n let roll = table.roll();\n let result = roll.results[0];\n inspiration = result.text;\n table.updateEmbeddedEntity(\"TableResult\", {\n _id: result._id,\n drawn: true\n });\n }\n}\n\nfunction checkTable(table) {\n let results = 0;\n for (let data of table.data.results) {\n if (!data.drawn) {\n results++;\n }\n }\n if (results < 1) {\n table.reset();\n ui.notifications.notify(\"Table Reset\")\n return false\n }\n return true\n}\n\nlet dieType = 'd6';\nif (actorLevels >= 15) {\n dieType = 'd12';\n} else if (actorLevels >= 10) {\n dieType = 'd10';\n} else if (actorLevels >= 5) {\n dieType = 'd8';\n}\n\nlet messageContent = '';\nmessageContent += `

${token.name} exclaims \"${inspiration}\"

`\nmessageContent += `

${targetName} is inspired.

`\nmessageContent += `
Bardic Inspiration

${targetName} gains one Bardic Inspiration die, a ${dieType}.
Once within the next 10 minutes, ${targetName} can roll the die and add the number rolled to one ability check, attack roll, or saving throw. ${targetName} can wait until after it rolls the d20 before deciding to use the Bardic Inspiration die, but must decide before the DM says whether the roll succeeds or fails. Once the Bardic Inspiration die is rolled, it is lost.

`\n\n// create the message\nif (messageContent !== '') {\n let chatData = {\n user: game.user._id,\n speaker: ChatMessage.getSpeaker(),\n content: messageContent,\n };\n ChatMessage.create(chatData, {});\n}","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[],"_id":"devQi2BcIDhI0z1o"} +{"name":"Hit Die","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"script","flags":{},"scope":"global","command":"// Requires furnace to work correctly.\n// args[0] === name of character\n// args[1] === \"add\",\"sub\", or \"use\" \n//\t\t\"add\" : adds 1 hit die if able to\n//\t\t\"sub\" : removes 1 hit die if able to\n//\t\t\"use\" : removes 1 hit die and heals actor for rolled amount\n\n(async () => {\n\tconst actor = game.actors.find(i => i.name === args[0]); \n if (!actor) return ui.notifications.warn(`No Actor by that name available.`);\n const classItems = actor.data.items.filter(it => it.type === \"class\")\n if (!classItems.length) return ui.notifications.warn(`Actor has no class!`);\n if (classItems.length > 1) return ui.notifications.warn(`Actor has multiple classes! This is not (yet) supported.`);\n const classItem = classItems[0];\n\t\n\tif(args[1] === \"add\")\n\t{\n\t\tif (classItem.data.hitDiceUsed <= 0) return ui.notifications.warn(`You are at maximum Hitdie!`);\n\n\t\tconst classItemUpdate = {\n\t\t\t_id: classItem._id,\n\t\t\tdata: {\n\t\t\t\thitDiceUsed: classItem.data.hitDiceUsed - 1,\n\t\t\t},\n\t\t};\n\n\t\tawait actor.updateEmbeddedEntity(\"OwnedItem\", classItemUpdate);\n\t}\n\t\n\tif(args[1] === \"sub\")\n\t{\n\t\tif (classItem.data.hitDiceUsed >= classItem.data.levels) return ui.notifications.warn(`You have no remaining hit dice to spend!`);\n\n\t\tconst classItemUpdate = {\n\t\t\t_id: classItem._id,\n\t\t\tdata: {\n\t\t\t\thitDiceUsed: classItem.data.hitDiceUsed + 1,\n\t\t\t},\n\t\t};\n\n\t\tawait actor.updateEmbeddedEntity(\"OwnedItem\", classItemUpdate);\n\t}\n\t\n\tif(args[1] === \"use\")\n\t{\n\t\tif (classItem.data.hitDiceUsed >= classItem.data.levels) return ui.notifications.warn(`You have no remaining hit dice to spend!`);\t\t\n\t\tconst classItemUpdate = {\n\t\t\t_id: classItem._id,\n\t\t\tdata: {\n\t\t\t\thitDiceUsed: classItem.data.hitDiceUsed + 1,\n\t\t\t},\n\t\t};\n\t\tawait actor.updateEmbeddedEntity(\"OwnedItem\", classItemUpdate);\n\t\t\n\t\tconst hitDieRoll = new Roll(`1${classItem.data.hitDice} + ${actor.data.data.abilities.con.mod}`);\n\t\thitDieRoll.roll();\n\t\thitDieRoll.toMessage({\n\t\t\tuser : game.user._id,\n\t\t\tspeaker : speaker,\n\t\t\tflavor : \"Roll Hit Dice\"\n\t\t});\n\t\t\n\t\tconst actorUpdate = {\n\t\t\tdata: {\n\t\t\t\tattributes: {\n\t\t\t\t\thp: {\n\t\t\t\t\t\tvalue: Math.clamped(\n\t\t\t\t\t\t\tactor.data.data.attributes.hp.value + hitDieRoll.total,\n\t\t\t\t\t\t\tactor.data.data.attributes.hp.min,\n\t\t\t\t\t\t\tactor.data.data.attributes.hp.max\n\t\t\t\t\t\t)\n\t\t\t\t\t},\n\t\t\t\t},\n\t\t\t},\n\t\t};\n\t\tawait actor.update(actorUpdate);\n\t} \n})();\n","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[],"_id":"eAl2Dc1HLYp2sUeG"} {"name":"Get Passive Perception","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"script","flags":{},"scope":"global","command":"// pull each player's passive perception then whisper the GM with the results.\n// author @Erogroth#7134\n\nlet actors = game.actors.entities.filter(e=> e.data.type==='character');\nlet messageContent = '';\nlet messageHeader = 'Passive Perception
';\nfor(let actor of actors) {\n let modifier = actor.data.data.skills.prc.mod; // this is total bonus for perception (abilitie mod + proficiency)\n let result = 10 + modifier; // this gives the passive perception\n messageContent += `${actor.name} ${result}
`; // creating the output string\n}\n\n// create the message\nif(messageContent !== '') {\n let chatData = {\n user: game.user._id,\n speaker: ChatMessage.getSpeaker(),\n content: messageHeader + messageContent,\n whisper: game.users.entities.filter(u => u.isGM).map(u => u._id)\n };\n ChatMessage.create(chatData, {});\n}\n","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[],"_id":"h7QwZjOWiLiQ4emI"} {"_id":"hW29VmM09DenDXNz","name":"Rage","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"script","flags":{},"scope":"global","command":"// \tDISCLAIMER: This macro is a slightly modified version of the original masterwork written by Felix#6196.\n//\t\t\t\tOriginal version is on the wiki here: \n//\t\t\t\thttps://github.com/foundry-vtt-community/wiki/wiki/Script-Macros#rage-toggle-for-inhabited-character\n//\n// \tDifferences in my version (Norc#5108, 05/02/2020):\n//\n//\t\tBiggest change: Changed macro to work for selected token, NOT the user's official character (game.user.character)\n// \t \tThis eliminated an error I was getting as a GM that prevented me from using the script.\n//\n//\t\tOther changes: 1. Fixed Rage icon toggling, for me it was backwards.\n// \t \t2. Added error messages for trying to rage with no token or no barbarian selected\n//\t\t\t\t\t \t3. Added auto-bear totem detection, with a minor edit to character sheet required.\n//\n//\tChangelog: _6 05/15/2020: 1. Removed an explicit definition of Token that caused an error inside a script macro and added comments\n//\t\t\t\t explaining how \"token\" and \"actor\" work in script macros.\n//\t\t\t\t 2. Changed \"magic words\" of the Bear Totem Spirit feature from \"Totem Spirit (Bear)\"\n//\t\t\t\t to \"Totem Spirit: Bear\" to match VTTA importer's new support for the feature.\n\n//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n//!!!\tBonus Tip 1: !!!\n//!!!\tIf you chose the Spirit Seeker Primal path, and you chose the Bear totem spirit (resistance to all non-psychic damage), !!!\n//!!!\tin your 5E character sheet, edit the name of your Totem Spirit feature to EXACTLY \"Totem Spirit: Bear\"\t\t\t\t !!!\n//!!! if it isn't already named that by VTTA Beyond Importer Module. This allows you to automatically gain the extra Bear Totem Spirit !!!\n//!!! resistances. \t\t\t\t\t\t\t\t !!!\n//!!! !!!\n//!!! \tBonus Tip 2: !!!\n//!!!\tIf you use the Combat Utility Belt module's Condition Lab, add a condition called Raging with the same icon as the optional rage !!!\n//!!!\ticon overlay, 'icons/svg/explosion.svg' by default. See OPTIONAL RAGE ICON section below. !!!\n//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n\t//declarations\n\tlet barb='';\n\tlet chatMsg='';\n\tlet bear = '';\n\tlet rageIconPath = '';\n\n//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n//!!! \tOPTIONAL RAGE ICON - Adds this icon to your character when raging only. Comment out following line to disable (add // before) !!!\n\n\t\trageIconPath = 'icons/svg/explosion.svg'\n\n//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\n\n\n\n//check to see if Actor exists and is a barbarian\n\n\t\t\t//Script macros automagically define \"token\" and \"actor\" for you. If you did need to manually\n\t\t\t//define it, this is how you would do so: \n\t\t\t//let actor = game.user.character;\n\nif (actor !== undefined && actor !== null) {\n // get the barbarian class item\n barb = actor.items.find(i => i.name === 'Barbarian');\n if (barb == undefined) { \n ui.notifications.warn(\"Please select a single barbarian token.\");\n }\n \n\tif (barb !== undefined && barb !== null) {\n\t\tchatMsg = '';\n\t\tlet enabled = false;\n\t\t// store the state of the rage toggle in flags\n\t\tif (actor.data.flags.rageMacro !== null && actor.data.flags.rageMacro !== undefined) {\n\t\t\tenabled = true;\n\t\t}\n\t\t// if rage is active, disable it\n\t\tif (enabled) {\n\t\t\tchatMsg = `${actor.name} is no longer raging.`;\n\n\t\t\t// reset resistances\n\t\t\tlet obj = {};\n\t\t\tobj['flags.rageMacro'] = null;\n\t\t\tobj['data.traits.dr'] = actor.data.flags.rageMacro.oldResistances;\n\t\t\tactor.update(obj);\n\n\t\t\t// reset items\n\t\t\tfor (let item of actor.items) {\n\t\t\t\tif (item.data.flags.rageMacro !== null && item.data.flags.rageMacro !== undefined) {\n\t\t\t\t\t// restoring the old value from flags\n\t\t\t\t\tlet oldDmg = item.data.flags.rageMacro.oldDmg;\n\t\t\t\t\tlet obj = {};\n\t\t\t\t\tobj['data.damage.parts'] = oldDmg;\n\t\t\t\t\tobj['flags.rageMacro'] = null;\n\t\t\t\t\titem.update(obj);\n\t\t\t\t}\n\t\t\t}\n\n\n\t\t// if rage is disabled, enable it\n\t\t} else {\n\t\t\tchatMsg = `${actor.name} is RAAAAAGING!`;\n\n\t\t\t// update resistance\n\t\t\tlet obj = {};\n\t\t\t// storing old resistances in flags to restore later\n\t\t\tobj['flags.rageMacro.enabled'] = true;\n\t\t\tobj['flags.rageMacro.oldResistances'] = JSON.parse(JSON.stringify(actor.data.data.traits.dr));\n\n\t\t\t// add bludgeoning, piercing and slashing resistance\n\t\t\tlet newResistance = actor.data.data.traits.dr;\n\t\t\tif (newResistance.value.indexOf('bludgeoning') === -1) newResistance.value.push('bludgeoning');\n\t\t\tif (newResistance.value.indexOf('piercing') === -1) newResistance.value.push('piercing');\n\t\t\tif (newResistance.value.indexOf('slashing') === -1) newResistance.value.push('slashing');\n\n\n\t\t\t\n\t\t\t//If bear totem, add bear totem resistances.\n\t\t\tbear = actor.items.find(i => i.name === \"Totem Spirit: Bear\")\n\t\t\tif (bear !== undefined && bear !== null ) {\n\t\t\t\tif (newResistance.value.indexOf('acid') === -1) newResistance.value.push('acid');\n\t\t\t\tif (newResistance.value.indexOf('cold') === -1) newResistance.value.push('cold');\n\t\t\t\tif (newResistance.value.indexOf('fire') === -1) newResistance.value.push('fire');\n\t\t\t\tif (newResistance.value.indexOf('force') === -1) newResistance.value.push('force');\n\t\t\t\tif (newResistance.value.indexOf('lightning') === -1) newResistance.value.push('lightning');\n\t\t\t\tif (newResistance.value.indexOf('necrotic') === -1) newResistance.value.push('necrotic');\n\t\t\t\tif (newResistance.value.indexOf('poison') === -1) newResistance.value.push('poison');\n\t\t\t\tif (newResistance.value.indexOf('radiant') === -1) newResistance.value.push('radiant');\n\t\t\t\tif (newResistance.value.indexOf('thunder') === -1) newResistance.value.push('thunder');\n\t\t\t}\n\t\t\t\n\t\t\tobj['data.traits.dr'] = newResistance;\n\t\t\tactor.update(obj);\n\n\t\t\t// update items\n\t\t\t// determining the barbarian level\n\t\t\tlet barblvl = barb.data.data.levels;\n\t\t\t// the formula to determin the rage bonus damage depending on barbarian level\n\t\t\tlet ragedmg = 2 + Math.floor(barblvl / 9) - (barblvl === 8 ? 1 : 0);\n\t\t\tfor (let item of actor.items) {\n\t\t\t\tlet isMelee = getProperty(item, 'data.data.actionType') === 'mwak';\n\t\t\t\tif (isMelee && item.data.data.damage.parts.length > 0) {\n\t\t\t\t\tconsole.log('updating ' + item);\n\t\t\t\t\tlet obj = {};\n\t\t\t\t\tlet dmg = item.data.data.damage.parts;\n\t\t\t\t\tobj['flags.rageMacro.oldDmg'] = JSON.parse(JSON.stringify(dmg));\n\t\t\t\t\tdmg[0][0] = `${dmg[0][0]} + ${ragedmg}`;\n\t\t\t\t\tobj['data.damage.parts'] = dmg;\n\t\t\t\t\titem.update(obj);\n\t\t\t\t}\n\t\t\t}\t\n\t\t}\n\t// toggle rage icon\n\t// - this is optional and requires you to set the path for the token icon you want to use for rage\n\t\t\t\t//Script macros automagically define \"token\" and \"actor\" for you. If you did need to manually\n\t\t\t\t//define it, this is how you would do so: \n\t\t\t\t//let token = canvas.tokens.controlled.find(t => t.actor.id === actor.id);\n\ttoken.toggleEffect(rageIconPath);\n\t}\n\n} else ui.notifications.warn(\"Please select a token.\");\n\n// write to chat if needed:\nif (chatMsg !== '') {\n\tlet chatData = {\n\t\tuser: game.user._id,\n\t\tspeaker: ChatMessage.getSpeaker(),\n\t\tcontent: chatMsg\n };\n\tChatMessage.create(chatData, {});\n}\n","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[]} {"_id":"mwiBoYVqZgJtyv9E","name":"Set Name and Bars","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"script","flags":{},"scope":"global","command":"// Update all tokens on the map so that the name shows on hover and the bars always show.\n// Display Modes: ALWAYS, CONTROL, HOVER, NONE, OWNER, OWNER_HOVER\n\nconst tokens = canvas.tokens.placeables.map(token => {\n return {\n _id: token.id,\n \"bar1.attribute\": \"attributes.hp\",\n \"bar2.attribute\": \"attributes.ac.value\",\n \"displayName\": CONST.TOKEN_DISPLAY_MODES.OWNER_HOVER,\n \"displayBars\": CONST.TOKEN_DISPLAY_MODES.OWNER\n };\n});\n\ncanvas.scene.updateEmbeddedEntity('Token', tokens)","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[]} diff --git a/packs/macros-item.db b/packs/macros-item.db index 7886b55..dce8c1d 100644 --- a/packs/macros-item.db +++ b/packs/macros-item.db @@ -1 +1,2 @@ {"_id":"D38Cw70PsNaaQicv","name":"Tool Proficiency","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"script","flags":{},"scope":"global","command":"/**\n * Grab a list of tools in the selected player's inventory, then all the user to make a roll on the tool.\n * Will take into consideration if the player is proficient in using the tool.\n */\n\n// get the first entry from the array of currently selected tokens. Works best/exclusively with one selected token\nconst target = canvas.tokens.controlled[0].actor;\n// get the abilities of the selected token for ease of access later\nconst { abilities } = target.data.data;\n// Only items set as \"tools\" will be included!\n// get all held and equipped Tools/Kits/Supplies. Might want to replace with /[tT]ools|[kK]it|[sS]upplies|[sS]et$/ if gaming sets should be included\nconst toolsInInventory = target.items.filter( item => item.name.match(/[tT]ools|[kK]it|[sS]upplies$/) && item.data.data.hasOwnProperty(\"proficient\"));\n// const toolProficiencies = target.data.data.traits.toolProf; // Tools have proficiency mod in the object under .data.data.proficient. \nlet tool = undefined;\n\n// Choose ability mod dialog\nconst abilityDialog = (async () => {\n let template = `\n
\n
\n \n \n
\n
`\n\n\n new Dialog({\n title: tool.name,\n content: template,\n buttons: {\n ok: {\n icon: '',\n label: \"OK\",\n callback: async (html) => {\n const selection = html.find(\"#selectedAbility\")[0].value;\n console.log(tool, target);\n let prof = tool.data.data.proficient * target.data.data.attributes.prof; // target might be half or doubly proficient. This will make sure it is accounted for\n\n let messageContent = `${target.name} rolled a [[1d20+${abilities[selection].mod}(${abilities[selection].name})+${prof}(Proficiency)]] for the ${tool.name} check.
`;\n let chatData = {\n user: game.user.id,\n speaker: ChatMessage.getSpeaker(),\n content: messageContent,\n // uncomment the line below to always whisper the roll to the GM\n // whisper: game.users.entities.filter(u => u.isGM).map(u => u._id)\n };\n ChatMessage.create(chatData, {});\n }\n },\n cancel: {\n icon: '',\n label: 'Cancel'\n }\n },\n default: \"cancel\"\n }).render(true);\n})\n\n// Choose tool dialog\nif (toolsInInventory.length) {\n (async () => {\n let template = `\n
\n
\n \n \n
\n
`;\n\n new Dialog({\n title: 'Which tool?',\n content: template,\n buttons: {\n ok: {\n icon: '',\n label: \"OK\",\n callback: async (html) => {\n let selection = html.find(\"#selectedTool\")[0].value;\n tool = toolsInInventory.find( item => item.name === selection )\n abilityDialog();\n }\n },\n cancel: {\n icon: '',\n label: 'Cancel'\n }\n },\n default: \"cancel\"\n }).render(true);\n })() \n}\n\nelse {\n new Dialog({\n title: 'No Tools!',\n content: '

You don\\'t seem to have any tool with you.

',\n buttons: {\n ok: {\n icon: '',\n label: \"OK\"\n }\n },\n default: \"ok\"\n }).render(true);\n}","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[]} +{"name":"Foundry Item Permission","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"script","flags":{},"scope":"global","command":"var folderName = \"Test Deeper\";\nvar desiredPermission = 0; // 0=None, 1=Limited, 2=Observer, 3=Owner\nvar applyInSubfolders = true;\n\n/*****\nSource: https://gist.github.com/janssen-io/50c1990ce7cf31da90fae7e7fb45cf53\n\nWARNING: This will overwrite the permissions of the items in the folder !\n That is, it will not keep the player permissions!\n \n Tested on FoundryVTT 0.5.5 & 0.5.7\n \n* * * * * * * * * * * * * * * * * * * * * *\n \nWARNING: Make sure the folder name is unique across actors, scenes, items, journals and roll tables!\n This script will apply the desired permission on the first folder it finds with that name.\n******/\n\nfunction repermission(currentFolder) {\n console.log(\"Repermissioning: \", currentFolder.name);\n\n if (currentFolder.content){\n currentFolder.content.map(item => {\n let newPermissions = duplicate(item.data.permission);\n newPermissions.default = desiredPermission;\n console.log(\" Item:\", item.data.name);\n item.update({permission: newPermissions});\n });\n }\n \n if (currentFolder.children && applyInSubfolders) {\n currentFolder.children.map(({data}) => {\n repermission(game.folders.entities.filter(f => f.data._id == data._id)[0]);\n });\n }\n}\n\nfunction findFolder(parent) {\n if (parent.data.name === folderName) {\n return parent;\n }\n \n for (let child of parent.children) {\n let foundFolder = findFolder(child);\n if (foundFolder) {\n return foundFolder;\n }\n }\n \n return null;\n}\n\nif (game.folders.entities.length == 0) {\n\tconsole.error(\"Your world does not have any folders.\");\n}\n\nvar root = { data: {}, children: game.folders.entities };\n\nvar folder = findFolder(root);\nif (!folder) {\n console.error(`Your world does not have any folders named '${folderName}'.`);\n}\nelse {\n repermission(folder);\n console.log(\"Repermissioning finished successfully!\");\n}","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[],"_id":"JGpakxFCcEhZGIVZ"} diff --git a/packs/macros-token.db b/packs/macros-token.db index 98681f9..1c9468b 100644 --- a/packs/macros-token.db +++ b/packs/macros-token.db @@ -4,3 +4,4 @@ {"_id":"fnMfRlpMvuk92hU0","name":"Switch Images","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"script","flags":{},"scope":"global","command":"// Allows swapping between two different .png images.\n// Token sides should have \"a\" and \"b\" at the end of the name like \"name-a.png\" and \"name-b.png\".\n// If you have a different ending, change aName and bName respectively.\n// Author: Phenomen\n\n// IMPORTANT. These two values MUST be the same length.\nlet aName = 'a.png'\nlet bName = 'b.png'\n\nlet tok = canvas.tokens.controlled[0];\nlet img = tok.data.img;\nvar currentSide = img[img.length - aName.length];\nimg = img.slice(0,-Math.abs(aName.length)) + (currentSide == 'a' ? bName: aName);\ntok.update({ img });","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[]} {"_id":"i4DFVd2HhEOreW2x","name":"Token Vision Config - About Time","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"script","flags":{},"scope":"global","command":"// A macro for the Foundry virtual tabletop that lets a user configure their token's vision and lighting settings, based on lighting sources from D&D 5e. Has a dependency on About Time by Tim Posney.\n\nif (canvas.tokens.controlled.length === 0)\n ui.notifications.error(\"Please select a token\");\n\nlet namedfields = (...fields) => {\n return (...arr) => {\n var obj = {};\n fields.forEach((field, index) => {\n obj[field] = arr[index];\n });\n return obj;\n };\n};\n\n// Very ugly automated construction below. DRY, but at what cost?\nlet VisionType = namedfields('name', 'dim', 'bright');\nvar visions = (() => {\n return [\n VisionType('Leave Unchanged', null, null),\n VisionType('Self', 5, 0),\n VisionType('Devil\\'s Sight', 0, 120)\n ].concat(...[...Array(6).keys()].map(x => (x+1)*30).map(n => {\n return VisionType(`Darkvision (${n} feet)`, n, 0);\n }));\n})();\n\nlet LightSource = namedfields('name', 'dim', 'bright', 'angle', 'lockRotation')\nvar lightSources = [\n LightSource('Leave Unchanged', null, null, null, null),\n LightSource('None', 0, 0, 360, null),\n LightSource('Candle', 10, 5, 360, null),\n LightSource('Torch / Light Cantrip', 40, 20, 360, null),\n LightSource('Lamp', 45, 15, 360, null),\n LightSource('Hooded Lantern', 60, 30, 360, null),\n LightSource('Hooded Lantern (Dim)', 5, 0, 360, null),\n LightSource('Bullseye Lantern', 120, 60, 52.5, false)\n];\n\nlet applyChanges = false;\nnew Dialog({\n title: `Token Vision Configuration`,\n content: `\n
\n
\n \n \n
\n
\n \n \n
\n
\n \n \n
\n
\n`,\n buttons: {\n yes: {\n icon: \"\",\n label: `Apply Changes`,\n callback: () => applyChanges = true\n },\n no: {\n icon: \"\",\n label: `Cancel Changes`\n },\n },\n default: \"yes\",\n close: html => {\n if (applyChanges) {\n for ( let token of canvas.tokens.controlled ) {\n let visionIndex = parseInt(html.find('[name=\"vision-type\"]')[0].value) || 0;\n let lightIndex = parseInt(html.find('[name=\"light-source\"]')[0].value) || 0;\n let duration = parseInt(html.find('[name=\"duration\"]')[0].value) || 0;\n\n if (duration > 0) {\n if (game.modules.get(\"about-time\").active != true) {\n ui.notifications.error(\"About Time isn't loaded\");\n } else {\n ((backup) => {\n game.Gametime.doIn({minutes:Math.floor(3 * duration / 4)}, () => {\n ChatMessage.create({\n user: game.user._id,\n content: \"The fire burns low...\",\n speaker: speaker\n }, {});\n });\n })(Object.assign({}, token.data));\n ((backup) => {\n game.Gametime.doIn({minutes:duration}, () => {\n ChatMessage.create({\n user: game.user._id,\n content: \"The fire goes out, leaving you in darkness.\",\n speaker: speaker\n }, {});\n token.update({\n vision: true,\n dimSight: backup.dimSight,\n brightSight: backup.brightSight,\n dimLight: backup.dimLight,\n brightLight: backup.brightLight,\n lightAngle: backup.lightAngle,\n lockRotation: backup.lockRotation\n });\n });\n })(Object.assign({}, token.data));\n }\n }\n\n // Configure new token vision\n let dimSight = visions[visionIndex].dim ?? token.data.dimSight;\n let brightSight = visions[visionIndex].bright ?? token.data.brightSight;\n let dimLight = lightSources[lightIndex].dim ?? token.data.dimLight;\n let brightLight = lightSources[lightIndex].bright ?? token.data.brightLight;\n let lightAngle = lightSources[lightIndex].angle ?? token.data.lightAngle;\n let lockRotation = lightSources[lightIndex].lockRotation ?? token.data.lockRotation;\n\n // Update Token\n console.log(token);\n token.update({\n vision: true,\n dimSight: dimSight,\n brightSight: brightSight,\n dimLight: dimLight,\n brightLight: brightLight,\n lightAngle: lightAngle,\n lockRotation: lockRotation\n });\n }\n }\n }\n}).render(true);\n","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[]} {"name":"Token Vision Configuration","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"chat","flags":{},"scope":"global","command":"// A macro for the Foundry virtual tabletop that lets a user configure their token's vision and lighting settings. This script is taken from Sky's foundry repo here: https://github.com/Sky-Captain-13/foundry/blob/master/scriptMacros/tokenVision.js.\n\nlet applyChanges = false;\nnew Dialog({\n title: `Token Vision Configuration`,\n content: `\n
\n
\n \n \n
\n
\n \n \n
\n
\n `,\n buttons: {\n yes: {\n icon: \"\",\n label: `Apply Changes`,\n callback: () => applyChanges = true\n },\n no: {\n icon: \"\",\n label: `Cancel Changes`\n },\n },\n default: \"yes\",\n close: html => {\n if (applyChanges) {\n for ( let token of canvas.tokens.controlled ) {\n let visionType = html.find('[name=\"vision-type\"]')[0].value || \"none\";\n let lightSource = html.find('[name=\"light-source\"]')[0].value || \"none\";\n let dimSight = 0;\n let brightSight = 0;\n let dimLight = 0;\n let brightLight = 0;\n let lightAngle = 360;\n let lockRotation = token.data.lockRotation;\n // Get Vision Type Values\n switch (visionType) {\n case \"dim0\":\n dimSight = 0;\n brightSight = 0;\n break;\n case \"dim30\":\n dimSight = 30;\n brightSight = 0;\n break;\n case \"dim60\":\n dimSight = 60;\n brightSight = 0;\n break;\n case \"dim90\":\n dimSight = 90;\n brightSight = 0;\n break;\n case \"dim120\":\n dimSight = 120;\n brightSight = 0;\n break;\n case \"dim150\":\n dimSight = 150;\n brightSight = 0;\n break;\n case \"dim180\":\n dimSight = 180;\n brightSight = 0;\n break;\n case \"bright120\":\n dimSight = 0;\n brightSight= 120;\n break;\n case \"nochange\":\n default:\n dimSight = token.data.dimSight;\n brightSight = token.data.brightSight;\n }\n // Get Light Source Values\n switch (lightSource) {\n case \"none\":\n dimLight = 0;\n brightLight = 0;\n break;\n case \"candle\":\n dimLight = 10;\n brightLight = 5;\n break;\n case \"lamp\":\n dimLight = 45;\n brightLight = 15;\n break;\n case \"bullseye\":\n dimLight = 120;\n brightLight = 60;\n lockRotation = false;\n lightAngle = 52.5;\n break;\n case \"hooded-dim\":\n dimLight = 5;\n brightLight = 0;\n break;\n case \"hooded-bright\":\n dimLight = 60;\n brightLight = 30;\n break;\n case \"light\":\n dimLight = 40;\n brightLight = 20;\n break;\n case \"torch\":\n dimLight = 40;\n brightLight = 20;\n break;\n case \"nochange\":\n default:\n dimLight = token.data.dimLight;\n brightLight = token.data.brightLight;\n lightAngle = token.data.lightAngle;\n lockRotation = token.data.lockRotation;\n }\n // Update Token\n console.log(token);\n token.update({\n vision: true,\n dimSight: dimSight,\n brightSight: brightSight,\n dimLight: dimLight,\n brightLight: brightLight,\n lightAngle: lightAngle,\n lockRotation: lockRotation\n });\n }\n }\n }\n}).render(true);\n","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[],"_id":"jBcKwGUwHS2V6nat"} +{"name":"Token Multi Select","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"script","flags":{},"scope":"global","command":"/*\nSwap the selected token with another of similar name via a\ndrop-down menu in a dialog box.\n\nTokens for each character should be named similarly but end with\n'_walking.png', '_fighting.png', and '_sneaking.png'. For example,\n'talion_walking.png', 'talion_fighting.png', and 'talion_sneaking.png'\n\nIf a token does not exist, mystery man will be automatically selected.\n*/\n\nif (actor !== undefined && actor !== null) {\n let d = new Dialog({\n title: 'Token Mogrifier',\n content: \"

Select a new token

\" +\n \"\",\n buttons: {\n ok: {\n icon: '',\n label: \"Do it!\",\n callback: () =>\n token.update({\n img: token.data.img.slice(0, token.data.img.lastIndexOf('_')) + document.getElementById(\"token\").value\n })\n },\n cancel: {\n icon: '',\n label: \"Nevermind\",\n callback: () => {}\n }\n }\n });\n d.render(true);\n} else {\n ui.notifications.warn(\"Please select a token.\");\n}\n","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[],"_id":"p8daoiwkQPAnOJNm"}