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 Dec 6, 2020
1 parent 570b95f commit ba589c5
Show file tree
Hide file tree
Showing 3 changed files with 5 additions and 3 deletions.
1 change: 1 addition & 0 deletions packs/macros-5e.db
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
{"name":"Show Tokens Resistances","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"script","flags":{"core":{"sourceId":"Macro.4WhSSiHXlbcvP7f6"}},"scope":"global","command":"// Prints the condition immunities, damage immunities, damage resistances and damage vulnerabilities of the currently selected token(s).\n// Damage types that appeared in the previous chat message (e.g. due to a roll) are highlighted in red. \n// A DM can call this macro after a player rolled damage to quickly see if they need to apply full, half or double damage.\n//\n// Author: https://github.com/Nijin22\n// Licence: MIT, see https://choosealicense.com/licenses/mit/\n\nconst damageTypes = [\"Acid\", \"Bludgeoning\", \"Cold\", \"Fire\", \"Force\", \"Lightning\", \"Necrotic\", \"Piercing\", \"Non-Magical Physical\",\n \"Piercing\", \"Poison\", \"Psychic\", \"Radiant\", \"Slashing\", \"Thunder\",\n \"Bludgeoning, Piercing, and Slashing from Nonmagical Attacks\"];\n\nlet msg = \"\";\nlet previousMessage;\ntry { \n previousMessage = game.messages.entries[game.messages.entries.length-1].data.content;\n} catch (e) {\n // No previous message in log. Default to an empty string.\n previousMessage = \"\";\n}\n\n// Enable case-insensitive replacements\n// Source: https://stackoverflow.com/a/7313467\nString.prototype.replaceAllCaseInsensitive = function(strReplace, strWith) {\n // See http://stackoverflow.com/a/3561711/556609\n var esc = strReplace.replace(/[-\\/\\\\^$*+?.()|[\\]{}]/g, '\\\\$&');\n var reg = new RegExp(esc, 'ig');\n return this.replace(reg, strWith);\n};\n\n\n// Get traits\nconst traits = new Map();\ntraits.set(\"ci\", \"Condition Immunities\");\ntraits.set(\"di\", \"Damage Immunities (No damage)\");\ntraits.set(\"dr\", \"Damage Resistances (Half damage)\");\ntraits.set(\"dv\", \"Damage Vulnerabilities (Double dmg)\");\ncanvas.tokens.controlled.forEach(token => {\n let name = token.actor.name;\n msg += `<h2>${name}</h2>`;\n \n traits.forEach((traitDescr, traitId, map) => {\n // Clone 'default' 5e trait array\n var allTraits = [...token.actor.data.data.traits[traitId].value];\n \n // Custom traits\n allTraits = allTraits.concat(token.actor.data.data.traits[traitId].custom.split(\";\").map(x => x.trim()));\n \n var printableTraits = allTraits.join(\"; \");\n if (printableTraits.length == 0) {\n printableTraits = \"-\";\n }\n msg += `<h3>${traitDescr}</h3><p>${printableTraits}</p>`;\n });\n});\n\n// highlight words from previous message\nlet damageTypesOfPrevousMsg = [];\ndamageTypes.forEach(damageType => {\n if (previousMessage.toLowerCase().indexOf(damageType.toLowerCase()) != -1){\n damageTypesOfPrevousMsg.push(damageType);\n }\n});\ndamageTypesOfPrevousMsg.forEach(damageType => {\n msg = msg.replaceAllCaseInsensitive(damageType, `<span style=\"color:red; font-weight: bold;\">${damageType}</span>`);\n});\n\n\nif (msg.length === 0) {\n msg = \"No tokens selected.\";\n}\n\nui.notifications.info(msg);\n\n// Post message to self\n/*ChatMessage.create({\n content: msg,\n whisper: [game.user._id]\n});*/","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[],"_id":"2NIoqVnUSV1FgJ9e"}
{"name":"Stealth Check","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"script","flags":{},"scope":"global","command":"// Grabs selected tokens and rolls a stealth check against all other tokens passive perception on the map. Then returns the result.\n\n// getting all actors of selected tokens\nlet actors = canvas.tokens.controlled.map(({ actor }) => actor);\n\n// if there are no selected tokens, roll for the player's character.\nif (actors.length < 1) {\n actors = game.users.entities.map(entity => {\n if (entity.active && entity.character !== null) {\n return entity.character;\n }\n });\n}\nconst validActors = actors.filter(actor => actor != null);\n\nlet messageContent = 'pp = passive perception<br>';\n\n// roll for every actor\nfor (const selectedActor of validActors) {\n const stealthMod = selectedActor.data.data.skills.ste.total; // stealth roll\n const stealth = new Roll(`1d20+${stealthMod}`).roll().total; // rolling the formula\n messageContent += `<hr><h3>${selectedActor.name} stealth roll was a <b>${stealth}</b>.</h3>`; // creating the output string\n\n // grab a list of unique tokens then check their passive perception against the rolled stealth.\n const uniqueActor = {};\n const caughtBy = canvas.tokens.placeables\n .filter(token => !!token.actor)\n .filter(({ actor }) => { // filter out duplicate token names. ie: we assume all goblins have the same passive perception\n if (uniqueActor[actor.name]) {\n return false;\n }\n uniqueActor[actor.name] = true;\n return true;\n })\n .filter(({ actor }) => {\n return selectedActor.id !== actor.id; // Don't check to see if the token sees himself.\n })\n .filter(({ actor }) => actor.data.data.skills.prc.passive >= stealth); // check map tokens passives with roller stealth\n\n if (!caughtBy.length) {\n messageContent += 'Stealth successful!<br>';\n } else {\n messageContent += 'Stealth questionable:<br>';\n caughtBy.map(({ actor }) => {\n messageContent += `<b>${actor.name}</b> pp(${actor.data.data.skills.prc.passive}).<br>`;\n });\n }\n}\n\n// create the message\nconst chatData = {\n user: game.user._id,\n speaker: game.user,\n content: messageContent,\n whisper: game.users.entities.filter((u) => u.isGM).map((u) => u._id),\n};\nChatMessage.create(chatData, {});\n","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[],"_id":"2RitOkKtnQe9pbuF"}
{"name":"Bless","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"script","flags":{},"scope":"global","command":"// new build for bless macro by Penguin#0949 with help from Kotetsushin#7680\n// version beta 3.1.1 for workgroups\n\n// user notes\n// this macro is inteded for use by the recipient of the bless spell in D&D 5e on Forge VTT\n// N.B. every recipient will need to use this macro independantly on their own Actor/token.\n\n//user modifiable declarations CHANGE AT YOUR OWN RISK\nconst blessIconPath = 'icons/svg/regen.svg';\nlet blessMsg = ' is Blessed!';\nlet endblessMsg = ' is no longer Blessed.';\n\n//fixed declarations DO NOT MODIFY\nlet Blessd4 = '+1d4';\nlet bless = '';\nlet chatMsg = '';\nlet macroActor = actor;\nlet macroToken = token;\n\n//identify token\nif (macroToken === undefined || macroToken === null) {\n ui.notifications.warn(\"Please select a token first.\");\n} else {\n// grab curent global states\n\tlet mwak = JSON.parse(JSON.stringify(macroActor.data.data.bonuses.mwak.attack));\n\tlet rwak = JSON.parse(JSON.stringify(macroActor.data.data.bonuses.rwak.attack));\n\tlet msak = JSON.parse(JSON.stringify(macroActor.data.data.bonuses.msak.attack));\n\tlet rsak = JSON.parse(JSON.stringify(macroActor.data.data.bonuses.rsak.attack));\n\tlet abilities = JSON.parse(JSON.stringify(macroActor.data.data.bonuses.abilities.save));\n\tif(mwak.includes(Blessd4) && rwak.includes(Blessd4) && msak.includes(Blessd4) && rsak.includes(Blessd4) && abilities.includes(Blessd4)){\n\t\tbless = true;\n\t}\n// If not already bless\t\n\tif (bless == false || bless === null || bless === undefined || bless == \"\") {\t\n// toggle bless icon\n\t\tmacroToken.toggleEffect(blessIconPath); \n// anounce to chat\n\t\tchatMsg = `${macroActor.name} ${blessMsg}`;\n// add bless bonus\n\t\tconsole.log('adding bless modifiers to global bonuses');\n\t\tlet obj = {};\n\t\tobj['data.bonuses.mwak.attack'] = mwak + Blessd4;\n\t\tobj['data.bonuses.rwak.attack'] = rwak + Blessd4;\n\t\tobj['data.bonuses.msak.attack'] = msak + Blessd4;\n\t\tobj['data.bonuses.rsak.attack'] = rsak + Blessd4;\n\t\tobj['data.bonuses.abilities.save'] = abilities + Blessd4;\n\t\tmacroActor.update(obj);\n// if already bless\t\n\t}\telse if (bless == true) {\n// toggle bless icon\n\t\ttoken.toggleEffect(blessIconPath); \t\t\n// anounce to chat\n\t\tchatMsg = `${macroActor.name} ${endblessMsg}`;\n// remove bless bonus\n\t\tconsole.log('resetting global bonuses for bless');\n\t\tlet obj = {};\n\t\tvar tmp = JSON.parse(JSON.stringify(macroActor.data.data.bonuses.mwak.attack));\n\t\tvar tmpLength = tmp.indexOf(Blessd4);\n tmp = tmp.substring(0, tmpLength) + tmp.substring(tmpLength+4, tmp.length);\n\t\tobj['data.bonuses.mwak.attack'] = tmp;\n\t\ttmp = JSON.parse(JSON.stringify(macroActor.data.data.bonuses.rwak.attack));\n\t\ttmpLength = tmp.indexOf(Blessd4);\n tmp = tmp.substring(0, tmpLength) + tmp.substring(tmpLength+4, tmp.length);\n\t\tobj['data.bonuses.rwak.attack'] = tmp;\n\t\ttmp = JSON.parse(JSON.stringify(macroActor.data.data.bonuses.msak.attack));\n\t\ttmpLength = tmp.indexOf(Blessd4);\n tmp = tmp.substring(0, tmpLength) + tmp.substring(tmpLength+4, tmp.length);\n\t\tobj['data.bonuses.msak.attack'] = tmp;\n\t\ttmp = JSON.parse(JSON.stringify(macroActor.data.data.bonuses.rsak.attack));\n\t\ttmpLength = tmp.indexOf(Blessd4);\n tmp = tmp.substring(0, tmpLength) + tmp.substring(tmpLength+4, tmp.length);\n\t\tobj['data.bonuses.rsak.attack'] = tmp;\n\t\ttmp = JSON.parse(JSON.stringify(macroActor.data.data.bonuses.abilities.save));\n\t\ttmpLength = tmp.indexOf(Blessd4);\n tmp = tmp.substring(0, tmpLength) + tmp.substring(tmpLength+4, tmp.length);\n\t\tobj['data.bonuses.abilities.save'] = tmp;\n\t\tmacroActor.update(obj);\n\t}\n}\n \t\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\t};\n\tChatMessage.create(chatData, {});\n}\n","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[],"_id":"50p0yXEpxXa9aAYJ"}
{"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// You can find a mockeries table in the community table module.\n\nlet cuttingWords = () => {\n // Setup variables\n let tableName = \"Mockeries\";\n let mockery = \"Now go away or I shall taunt you a second time-a!\"; // if table can't be found, use this.\n\n if (!actor) {\n ui.notifications.warn(\"You must have an actor selected.\");\n return\n }\n \n let actorLevels = actor.data.data.levels || 1;\n let table = game.tables.entities.find(t => t.name == tableName);\n // Get Targets name\n const targetId = game.user.targets.ids[0];\n const targetToken = canvas.tokens.get(targetId);\n if (!targetToken) {\n ui.notifications.warn(\"You must target a token.\");\n return\n }\n const targetName = targetToken.name;\n\n // Roll the result, and mark it drawn\n if (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\n function 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 let dieType = 'd6';\n if (actorLevels >= 15) {\n dieType = 'd12';\n } else if (actorLevels >= 10) {\n dieType = 'd10';\n } else if (actorLevels >= 5) {\n dieType = 'd8';\n }\n\n let messageContent = `<p>${targetName} Reduce your roll by: <b>[[1${dieType}]]</b>.</p>`\n messageContent += `<p>${token.name} exclaims <b><i>\"${mockery}\"</i></b></p>`\n messageContent += `<details closed=\"\"><summary><a>Cutting Words</a></summary>\n <p>When a creature that you can see within 60 feet of you makes an <b>Attack roll, an ability check, or a damage roll</b>, you can use your <b>Reaction</b> to expend one of your uses of <b>Bardic Inspiration</b>,\n rolling a Bardic Inspiration die and subtracting the number rolled from the creature’s roll.</p>\n <p>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. \n The creature is immune if it can’t hear you or if it’s immune to being <b>Charmed</b>.</p></details>`\n\n // create the message\n if (messageContent !== '') {\n let chatData = {\n user: game.user._id,\n speaker: ChatMessage.getSpeaker(),\n content: messageContent,\n };\n ChatMessage.create(chatData, {});\n }\n};\n\ncuttingWords();\n","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[],"_id":"AbzZdXi97q8oHOUn"}
Expand Down
Loading

0 comments on commit ba589c5

Please sign in to comment.