diff --git a/packs/macros-actor.db b/packs/macros-actor.db index 0d6841a..6a6c2d7 100644 --- a/packs/macros-actor.db +++ b/packs/macros-actor.db @@ -5,3 +5,10 @@ {"name":"Rage (shawndibble)","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"chat","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\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)\" instead. !!!\n//!!!\tThis allows you to automatically gain the extra Bear Totem Spirit resistances. !!!\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\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) {\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\ttoken = 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":"hW29VmM09DenDXNz"} {"name":"Set Name and Bars (shawndibble)","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"chat","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":[],"_id":"mwiBoYVqZgJtyv9E"} {"name":"Link Actors (Reaver01)","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"chat","flags":{},"scope":"global","command":"const scene = game.scenes.active;\nconst unlinked = canvas.scene.data.tokens.map(t => {\n const actor = game.actors.entities.find(a => a.name === t.name);\n if (actor) {\n return {\n _id: t._id,\n actorId: actor.id\n }\n } else {\n console.log(t.name);\n return {\n _id: t._id,\n actorId: \"\"\n }\n }\n});\nconst updates = duplicate(unlinked);\n\nscene.updateEmbeddedEntity(\"Token\", updates);\n\nui.notifications.info('Tokens linked to actors.');\nconsole.log(updates);","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[],"_id":"p0KlDQ5Ab2IIsNJY"} +{"_id":"USJZMHU93aFklWYM","name":"Change Disposition","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"chat","flags":{},"scope":"global","command":"let applyChanges = false;\nnew Dialog({\n title: `Token Disposition Changer`,\n content: `\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":[]} +{"_id":"p0KlDQ5Ab2IIsNJY","name":"Link Actors","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"chat","flags":{},"scope":"global","command":"const scene = game.scenes.active;\nconst unlinked = canvas.scene.data.tokens.map(t => {\n const actor = game.actors.entities.find(a => a.name === t.name);\n if (actor) {\n return {\n _id: t._id,\n actorId: actor.id\n }\n } else {\n console.log(t.name);\n return {\n _id: t._id,\n actorId: \"\"\n }\n }\n});\nconst updates = duplicate(unlinked);\n\nscene.updateEmbeddedEntity(\"Token\", updates);\n\nui.notifications.info('Tokens linked to actors.');\nconsole.log(updates);","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[]} +{"_id":"hW29VmM09DenDXNz","name":"Rage","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"chat","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\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)\" instead. !!!\n//!!!\tThis allows you to automatically gain the extra Bear Totem Spirit resistances. !!!\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\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) {\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\ttoken = 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":"ZvtYrzlv9dPpq9Pu","name":"Random Mockeries","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"chat","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\n// Setup variables\nlet tableName = \"Mockeries\";\nlet table = game.tables.entities.find(t => t.name == tableName);\nlet mockery = '';\n// Roll the result, and mark it drawn\nif (table)\n{\n let result = table.roll()[1];\n if (result === null)\n {\n table.reset();\n result = table.roll()[1];\n }\n mockery = result.text;\n markDrawn(table, result);\n}\n\nfunction markDrawn(table, result){\n for (let data of table.data.results){\n if (result._id == data._id)\n {\n //console.log(result.text)\n data.drawn = true;\n }\n } \n}\n\n// Get Targets name\nconst targetId = game.user.targets.ids[0];\nconst targetToken = canvas.tokens.get(targetId);\nconst targetName = targetToken.name;\n\n// Add a message with damage roll\nlet messageContent = '';\nlet result = new Roll(`1d4`).roll().total;\nmessageContent += `${targetName} Roll WIS save DC 14 or take ${result} damage.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":[],"_id":"D38Cw70PsNaaQicv"} +{"_id":"D38Cw70PsNaaQicv","name":"Tool Proficiency","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"chat","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 underYou 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":[]} diff --git a/packs/macros-misc.db b/packs/macros-misc.db index fc517e9..d17febd 100644 --- a/packs/macros-misc.db +++ b/packs/macros-misc.db @@ -11,3 +11,16 @@ {"name":"Move Walls (Gen Kitty)","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"chat","flags":{},"scope":"global","command":"/* From: @(Busy) Gen Kitty (she/her)\nTo move each node on both axes, you need all 4 parameters listed. \nIn this case, he wanted to move all the walls up and to the left and \nthe foundry grid is sorta vertically flipped to what you'd expect, \nwhich is why all of the operators are \"-=\" If you wanted to move them \nin different directions it'd just be a matter of changing the operator \nnext to the equals sign.\nEach argument is a node's X or Y position, and each wall segment has two nodes. \n0 = Node 1 X \n1 = Node 1 Y \n2 = Node 2 X \n3 = Node 2 Y\n*/\n\nlet walls = canvas.scene.data.walls.map(w => {\n w = duplicate(w);\n w.c[0] -= 50;\n w.c[1] -= 50;\n w.c[2] -= 50;\n w.c[3] -= 50;\n return w;\n});\ncanvas.scene.update({walls: walls});","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[],"_id":"r8G0g61ikT9mJJwF"} {"name":"Token Light Picker (bekriebel)","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"chat","flags":{},"scope":"global","command":"let dialogEditor = new Dialog({\n title: `Token Light Picker`,\n content: `Pick the light source the selected token is holding.`,\n buttons: {\n none: {\n label: `None`,\n callback: () => {\n token.update({\"dimLight\": 0, \"brightLight\": 0, \"lightAngle\": 360,});\n dialogEditor.render(true);\n }\n },\n torch: {\n label: `Torch`,\n callback: () => {\n token.update({\"dimLight\": 40, \"brightLight\": 20, \"lightAngle\": 360,});\n dialogEditor.render(true);\n }\n },\n lamp: {\n label: `Lamp`,\n callback: () => {\n token.update({\"dimLight\": 45, \"brightLight\": 15, \"lightAngle\": 360,});\n dialogEditor.render(true);\n }\n },\n bullseye: {\n label: `Bullseye Lantern`,\n callback: () => {\n token.update({\"dimLight\": 120, \"brightLight\": 60, \"lightAngle\": 45,});\n dialogEditor.render(true);\n }\n },\n hoodedOpen: {\n label: `Hooded Lantern (Open)`,\n callback: () => {\n token.update({\"dimLight\": 60, \"brightLight\": 30, \"lightAngle\": 360,});\n dialogEditor.render(true);\n }\n },\n hoodedClosed: {\n label: `Hooded Lantern (Closed)`,\n callback: () => {\n token.update({\"dimLight\": 5, \"brightLight\": 0, \"lightAngle\": 360,});\n dialogEditor.render(true);\n }\n },\n close: {\n icon: \"\",\n label: `Close`\n },\n },\n default: \"close\",\n close: () => {}\n});\n\ndialogEditor.render(true)","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[],"_id":"vrwyRRA6XPMGfv9G"} {"name":"Ambient Light Quick Edit (yoman987)","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"chat","flags":{},"scope":"global","command":"let macroName = \"AmbientLight QuickEditor\"\nlet macroEndLog = \"---------------------------------------------\"\n\nlet i=0;\nlet lights = canvas.lighting.objects.children;\nlet lightSelected = lights[0];\nlet selectOptions = \"\";\nlet lightSelectedAngle = 0;\nlet lightSelectedBright = 0;\nlet lightSelectedDim = 0;\nlet lightSelectedRotation = 0;\nlet lightSelectedTintAlpha = 1;\nlet lightSelectedTintColor = \"\";\n\nconsole.log(\"---------------------------------------------\");\nconsole.log(`${macroName} by PaperPunk`);\nconsole.log(\"---------------------------------------------\");\nconsole.log(`${macroName} | Start`);\n\nconst drawingDetails = {\n author: game.user._id,\n fillAlpha: 0,\n fillColor: \"#808080\",\n fillType: 1,\n fontFamily: \"FontAwesome\",\n fontSize: 24,\n height: 48,\n hidden: false,\n locked: false,\n rotation: 0,\n strokeAlpha: 1,\n strokeColor: \"#000000\",\n strokeWidth: 2,\n text: i,\n textAlpha: 1,\n textColor: \"#ffffff\",\n type: \"r\",\n width: 48,\n //x: 250,\n x: lightSelected.x-24,\n //y: 250\n y: lightSelected.y+25\n};\n\n//let d = Drawing.create(drawingDetails);\n//d.update({\"x\": lights[i].x-24, \"y\": lights[i].y+25, \"text\": i});\n\nfor (i= 0; i< lights.length; i++) {\n selectOptions += ``;\n}\n\nconst htmlLightSelection = `\n \n `;\n\nlet dialogSelector = new Dialog({\n title: `${macroName}`,\n content: htmlLightSelection,\n buttons: {\n confirm: {\n icon: \"\",\n label: `Confirm`,\n callback: htmlLightSelection => { \n lightSelected = (htmlLightSelection.find('[name=\"light-selector\"]')[0].value)\n lightSelectedAngle = lights[lightSelected].data.angle;\n lightSelectedBright = lights[lightSelected].data.bright;\n lightSelectedDim = lights[lightSelected].data.dim;\n lightSelectedRotation = lights[lightSelected].data.rotation;\n lightSelectedTintAlpha = lights[lightSelected].data.tintAlpha;\n lightSelectedTintColor = lights[lightSelected].data.tintColor;\n //console.log(`${macroName} | lightSelected = ${lightSelected}`);\n //console.log(`${macroName} | lightSelectedBright = ${lightSelectedBright}`);\n dialogEditor.render(true);\n }\n },\n cancel: {\n icon: \"\",\n label: `Cancel`,\n callback: () => {\n console.log(`${macroName} | Goodbye`);\n console.log(macroEndLog);\n }\n },\n },\n default: \"cancel\",\n //close: () => console.log(\"AmbientLight QuickEditor | Dialog Window Closed\")\n});\n\nlet dialogEditor = new Dialog({\n title: `${macroName}`,\n content: `Emission Angle: ${lightSelectedAngle}
\nBright light distance: ${lightSelectedBright}
\nDim light distance: ${lightSelectedDim}
\nRotation CW from down: ${lightSelectedRotation}
\nTint Alpha: ${lightSelectedAngle}
\nTint Color HexCode: ${lightSelectedAngle}
`,\n buttons: {\n rot5cw: {\n icon: \"\",\n label: `Rotate 5* CW`,\n callback: () => { \n let rot = lights[lightSelected].data.rotation;\n lights[lightSelected].update({\"rotation\":rot+5});\n dialogEditor.render(true);\n }\n },\n rot15cw: {\n icon: \"\",\n label: `Rotate 15* CW`,\n callback: () => { \n let rot = lights[lightSelected].data.rotation;\n lights[lightSelected].update({\"rotation\":rot+15});\n dialogEditor.render(true);\n }\n },\n rot45cw: {\n icon: \"\",\n label: `Rotate 45* CW`,\n callback: () => { \n let rot = lights[lightSelected].data.rotation;\n lights[lightSelected].update({\"rotation\":rot+45});\n dialogEditor.render(true);\n }\n },\n rot5ccw: {\n icon: \"\",\n label: `Rotate 5* CCW`,\n callback: () => { \n let rot = lights[lightSelected].data.rotation;\n lights[lightSelected].update({\"rotation\":rot-5});\n dialogEditor.render(true);\n }\n },\n rot15ccw: {\n icon: \"\",\n label: `Rotate 15* CCW`,\n callback: () => { \n let rot = lights[lightSelected].data.rotation;\n lights[lightSelected].update({\"rotation\":rot-15});\n dialogEditor.render(true);\n }\n },\n rot45ccw: {\n icon: \"\",\n label: `Rotate 45* CCW`,\n callback: () => { \n let rot = lights[lightSelected].data.rotation;\n lights[lightSelected].update({\"rotation\":rot-45});\n dialogEditor.render(true);\n }\n },\n brightup: {\n icon: \"\",\n label: `Increase Bright by 5`,\n callback: () => { \n let bright = lights[lightSelected].data.bright;\n lights[lightSelected].update({\"bright\":bright+5});\n dialogEditor.render(true);\n }\n },\n brightdown: {\n icon: \"\",\n label: `Decrease Bright by 5`,\n callback: () => { \n let bright = lights[lightSelected].data.bright;\n lights[lightSelected].update({\"bright\":bright-5});\n dialogEditor.render(true);\n }\n },\n brightoff: {\n icon: \"\",\n label: `Remove Bright Light`,\n callback: () => { \n lights[lightSelected].update({\"bright\":0});\n dialogEditor.render(true);\n }\n },\n dimup: {\n icon: \"\",\n label: `Increase Dim by 5`,\n callback: () => { \n let dim = lights[lightSelected].data.dim;\n lights[lightSelected].update({\"dim\":dim+5});\n dialogEditor.render(true);\n }\n },\n dimdown: {\n icon: \"\",\n label: `Decrease Dim by 5`,\n callback: () => { \n let dim = lights[lightSelected].data.dim;\n lights[lightSelected].update({\"dim\":dim-5});\n dialogEditor.render(true);\n }\n },\n dimoff: {\n icon: \"\",\n label: `Remove Dim Light`,\n callback: () => { \n lights[lightSelected].update({\"dim\":0});\n dialogEditor.render(true);\n }\n },\n emit15: {\n icon: \"\",\n label: `Emission Angle 15*`,\n callback: () => { \n lights[lightSelected].update({\"angle\":15});\n dialogEditor.render(true);\n }\n },\n emit45: {\n icon: \"\",\n label: `Emission Angle 45*`,\n callback: () => { \n lights[lightSelected].update({\"angle\":45});\n dialogEditor.render(true);\n }\n },\n emit90: {\n icon: \"\",\n label: `Emission Angle 90*`,\n callback: () => { \n lights[lightSelected].update({\"angle\":90});\n dialogEditor.render(true);\n }\n },\n emit180: {\n icon: \"\",\n label: `Emission Angle 180*`,\n callback: () => { \n lights[lightSelected].update({\"angle\":180});\n dialogEditor.render(true);\n }\n },\n emit270: {\n icon: \"\",\n label: `Emission Angle 270*`,\n callback: () => { \n lights[lightSelected].update({\"angle\":270});\n dialogEditor.render(true);\n }\n },\n emit360: {\n icon: \"\",\n label: `Emission Angle 360*`,\n callback: () => { \n lights[lightSelected].update({\"angle\":360});\n dialogEditor.render(true);\n }\n },\n back: {\n icon: \"\",\n label: `Back`,\n callback: () => dialogSelector.render(true)\n },\n close: {\n icon: \"\",\n label: `Close`\n },\n },\n default: \"close\",\n close: () => {\n console.log(`${macroName} | Goodbye`);\n console.log(macroEndLog);\n }\n});\n\ndialogSelector.render(true);\n","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[],"_id":"wosXzUFEMQLD84so"} +{"_id":"wosXzUFEMQLD84so","name":"Ambient Light Quick Edit","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"chat","flags":{},"scope":"global","command":"let macroName = \"AmbientLight QuickEditor\"\nlet macroEndLog = \"---------------------------------------------\"\n\nlet i=0;\nlet lights = canvas.lighting.objects.children;\nlet lightSelected = lights[0];\nlet selectOptions = \"\";\nlet lightSelectedAngle = 0;\nlet lightSelectedBright = 0;\nlet lightSelectedDim = 0;\nlet lightSelectedRotation = 0;\nlet lightSelectedTintAlpha = 1;\nlet lightSelectedTintColor = \"\";\n\nconsole.log(\"---------------------------------------------\");\nconsole.log(`${macroName} by PaperPunk`);\nconsole.log(\"---------------------------------------------\");\nconsole.log(`${macroName} | Start`);\n\nconst drawingDetails = {\n author: game.user._id,\n fillAlpha: 0,\n fillColor: \"#808080\",\n fillType: 1,\n fontFamily: \"FontAwesome\",\n fontSize: 24,\n height: 48,\n hidden: false,\n locked: false,\n rotation: 0,\n strokeAlpha: 1,\n strokeColor: \"#000000\",\n strokeWidth: 2,\n text: i,\n textAlpha: 1,\n textColor: \"#ffffff\",\n type: \"r\",\n width: 48,\n //x: 250,\n x: lightSelected.x-24,\n //y: 250\n y: lightSelected.y+25\n};\n\n//let d = Drawing.create(drawingDetails);\n//d.update({\"x\": lights[i].x-24, \"y\": lights[i].y+25, \"text\": i});\n\nfor (i= 0; i< lights.length; i++) {\n selectOptions += ``;\n}\n\nconst htmlLightSelection = `\n \n `;\n\nlet dialogSelector = new Dialog({\n title: `${macroName}`,\n content: htmlLightSelection,\n buttons: {\n confirm: {\n icon: \"\",\n label: `Confirm`,\n callback: htmlLightSelection => { \n lightSelected = (htmlLightSelection.find('[name=\"light-selector\"]')[0].value)\n lightSelectedAngle = lights[lightSelected].data.angle;\n lightSelectedBright = lights[lightSelected].data.bright;\n lightSelectedDim = lights[lightSelected].data.dim;\n lightSelectedRotation = lights[lightSelected].data.rotation;\n lightSelectedTintAlpha = lights[lightSelected].data.tintAlpha;\n lightSelectedTintColor = lights[lightSelected].data.tintColor;\n //console.log(`${macroName} | lightSelected = ${lightSelected}`);\n //console.log(`${macroName} | lightSelectedBright = ${lightSelectedBright}`);\n dialogEditor.render(true);\n }\n },\n cancel: {\n icon: \"\",\n label: `Cancel`,\n callback: () => {\n console.log(`${macroName} | Goodbye`);\n console.log(macroEndLog);\n }\n },\n },\n default: \"cancel\",\n //close: () => console.log(\"AmbientLight QuickEditor | Dialog Window Closed\")\n});\n\nlet dialogEditor = new Dialog({\n title: `${macroName}`,\n content: `Emission Angle: ${lightSelectedAngle}
\nBright light distance: ${lightSelectedBright}
\nDim light distance: ${lightSelectedDim}
\nRotation CW from down: ${lightSelectedRotation}
\nTint Alpha: ${lightSelectedAngle}
\nTint Color HexCode: ${lightSelectedAngle}
`,\n buttons: {\n rot5cw: {\n icon: \"\",\n label: `Rotate 5* CW`,\n callback: () => { \n let rot = lights[lightSelected].data.rotation;\n lights[lightSelected].update({\"rotation\":rot+5});\n dialogEditor.render(true);\n }\n },\n rot15cw: {\n icon: \"\",\n label: `Rotate 15* CW`,\n callback: () => { \n let rot = lights[lightSelected].data.rotation;\n lights[lightSelected].update({\"rotation\":rot+15});\n dialogEditor.render(true);\n }\n },\n rot45cw: {\n icon: \"\",\n label: `Rotate 45* CW`,\n callback: () => { \n let rot = lights[lightSelected].data.rotation;\n lights[lightSelected].update({\"rotation\":rot+45});\n dialogEditor.render(true);\n }\n },\n rot5ccw: {\n icon: \"\",\n label: `Rotate 5* CCW`,\n callback: () => { \n let rot = lights[lightSelected].data.rotation;\n lights[lightSelected].update({\"rotation\":rot-5});\n dialogEditor.render(true);\n }\n },\n rot15ccw: {\n icon: \"\",\n label: `Rotate 15* CCW`,\n callback: () => { \n let rot = lights[lightSelected].data.rotation;\n lights[lightSelected].update({\"rotation\":rot-15});\n dialogEditor.render(true);\n }\n },\n rot45ccw: {\n icon: \"\",\n label: `Rotate 45* CCW`,\n callback: () => { \n let rot = lights[lightSelected].data.rotation;\n lights[lightSelected].update({\"rotation\":rot-45});\n dialogEditor.render(true);\n }\n },\n brightup: {\n icon: \"\",\n label: `Increase Bright by 5`,\n callback: () => { \n let bright = lights[lightSelected].data.bright;\n lights[lightSelected].update({\"bright\":bright+5});\n dialogEditor.render(true);\n }\n },\n brightdown: {\n icon: \"\",\n label: `Decrease Bright by 5`,\n callback: () => { \n let bright = lights[lightSelected].data.bright;\n lights[lightSelected].update({\"bright\":bright-5});\n dialogEditor.render(true);\n }\n },\n brightoff: {\n icon: \"\",\n label: `Remove Bright Light`,\n callback: () => { \n lights[lightSelected].update({\"bright\":0});\n dialogEditor.render(true);\n }\n },\n dimup: {\n icon: \"\",\n label: `Increase Dim by 5`,\n callback: () => { \n let dim = lights[lightSelected].data.dim;\n lights[lightSelected].update({\"dim\":dim+5});\n dialogEditor.render(true);\n }\n },\n dimdown: {\n icon: \"\",\n label: `Decrease Dim by 5`,\n callback: () => { \n let dim = lights[lightSelected].data.dim;\n lights[lightSelected].update({\"dim\":dim-5});\n dialogEditor.render(true);\n }\n },\n dimoff: {\n icon: \"\",\n label: `Remove Dim Light`,\n callback: () => { \n lights[lightSelected].update({\"dim\":0});\n dialogEditor.render(true);\n }\n },\n emit15: {\n icon: \"\",\n label: `Emission Angle 15*`,\n callback: () => { \n lights[lightSelected].update({\"angle\":15});\n dialogEditor.render(true);\n }\n },\n emit45: {\n icon: \"\",\n label: `Emission Angle 45*`,\n callback: () => { \n lights[lightSelected].update({\"angle\":45});\n dialogEditor.render(true);\n }\n },\n emit90: {\n icon: \"\",\n label: `Emission Angle 90*`,\n callback: () => { \n lights[lightSelected].update({\"angle\":90});\n dialogEditor.render(true);\n }\n },\n emit180: {\n icon: \"\",\n label: `Emission Angle 180*`,\n callback: () => { \n lights[lightSelected].update({\"angle\":180});\n dialogEditor.render(true);\n }\n },\n emit270: {\n icon: \"\",\n label: `Emission Angle 270*`,\n callback: () => { \n lights[lightSelected].update({\"angle\":270});\n dialogEditor.render(true);\n }\n },\n emit360: {\n icon: \"\",\n label: `Emission Angle 360*`,\n callback: () => { \n lights[lightSelected].update({\"angle\":360});\n dialogEditor.render(true);\n }\n },\n back: {\n icon: \"\",\n label: `Back`,\n callback: () => dialogSelector.render(true)\n },\n close: {\n icon: \"\",\n label: `Close`\n },\n },\n default: \"close\",\n close: () => {\n console.log(`${macroName} | Goodbye`);\n console.log(macroEndLog);\n }\n});\n\ndialogSelector.render(true);\n","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[]} +{"_id":"5XA28twwaRBUFEjC","name":"Breathing Lights","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"chat","flags":{},"scope":"global","command":"// Courtesy of @ohporter\n// Cause lightsources to \"breathe,\" expanding and contracting.\n(async () => {\n let min = 5;\n let max = 10;\n if (game.pulsatingLights) {\n game.pulsatingLights = false;\n } else {\n game.pulsatingLights = true;\n let glyphLights = [];\n let glyphColor = \"#5940b5\"\n let scene = game.scenes.active;\n \n canvas.lighting.placeables.forEach(l => { if (l.data.tintColor === glyphColor && l.scene === scene) glyphLights.push(l.id) })\n \n const updates = []\n \n let radius = min;\n let increment = true;\n let interval = setInterval(async () => {\n glyphLights.forEach(id => {\n updates.push({ _id: id, dim: radius, bright: radius/2});\n })\n await scene.updateEmbeddedEntity(\"AmbientLight\", updates);\n \n if (increment) {radius += 1} else {radius -= 1};\n if (radius === max) {increment = false};\n if (radius === min) {increment = true};\n if (!scene.active || !game.pulsatingLights) {\n // Reset to default glow\n glyphLights.forEach(id => {\n updates.push({ _id: id, dim: min, bright: 0});\n })\n await scene.updateEmbeddedEntity(\"AmbientLight\", updates);\n clearInterval(interval);\n }\n }, 200);\n }\n })()","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[]} +{"_id":"8iEx21HSVOmkbBFE","name":"Combat Tracker AC HP","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"chat","flags":{},"scope":"global","command":"// Adds the actor's AC to the combat tracker. Then toggles between HP and AC\nconst a = \"attributes.ac.value\";\nconst b = \"attributes.hp.value\";\n\nif (game.combat.settings.resource == a) {\n game.settings.set('core', 'combatTrackerConfig', {resource: b, skipDefeated: true});\n} else {\n game.settings.set('core', 'combatTrackerConfig', {resource: a, skipDefeated: true});\n}\nui.combat.updateTrackedResources();","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[]} +{"_id":"qlx6N8QD6QliPQbu","name":"Create Ambient Light","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"chat","flags":{},"scope":"global","command":"// Create a (pre-configured) lightsource on the current scene. \n// This example is a blue light for \"activating a stargate.\"\n\nAmbientLight.create({\n t: \"l\", // l for local. The other option is g for global.\n x: 1100, // horizontal positioning\n y: 1150, // vertical positioning\n dim: 20.50, // the total radius of the light, including where it is dim.\n bright: 19.00, // the bright radius of the light\n angle: 360, // the coverage of the light. (Try 30 for a \"spotlight\" effect.)\n rotation: 0, // the beam direction of the light in degrees (if its angle is less than 360 degrees.) \n // Oddly, degrees are counted from the 6 o'clock position.\n tintColor: \"#0080FF\", // Light coloring.\n tintAlpha: 0.5 // Light opacity (or \"brightness,\" depending on how you think about it.) \n});","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[]} +{"_id":"bRBhm24NyQELbDti","name":"Create Chat Message","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"chat","flags":{},"scope":"global","command":"// Courtesy of @errational\n// Creates a chat message.\nconst content = `Monster attacks ${controlledToken.name}
`;\n\nChatMessage.create({\n speaker: ChatMessage.getSpeaker(controlledToken),\n content: content,\n type: CONST.CHAT_MESSAGE_TYPES.OTHER\n});","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[]} +{"_id":"dgSOPUXWUK1701PV","name":"Find Lights By Color","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"chat","flags":{},"scope":"global","command":"// Courtesy of @FloRad\n// Right here's a macro that looks for lights of a certain color, \n// sets a different color and then logs out the ids of the \n// lights it previously found using the marker color\n(async () => {\n let foundLights = [];\n let markingColor = \"#00ff00\"\n let newColor = \"#bbb\"\n let scene = game.scenes.active;\n\n canvas.lighting.placeables.forEach(l => { if (l.data.tintColor === markingColor && l.scene === scene) foundLights.push(l.id) })\n\n const updates = []\n foundLights.forEach(id => {\n updates.push({ _id: id, tintColor: newColor });\n })\n\n await scene.updateEmbeddedEntity(\"AmbientLight\", updates);\n\n console.log(foundLights)\n})()","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[]} +{"_id":"SPZ5TLx2gSYjFPus","name":"Flip Token Image","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"chat","flags":{},"scope":"global","command":"// Flips the selected token image along the Y axis.\n// Change mirrorY to mirrorX to flip across the X axis\nfor ( let token of canvas.tokens.controlled ) {\n let flip = !token.data.mirrorY || false;\n token.update({mirrorY: flip});\n};","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[]} +{"_id":"vrwyRRA6XPMGfv9G","name":"Token Light Picker","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"chat","flags":{},"scope":"global","command":"let dialogEditor = new Dialog({\n title: `Token Light Picker`,\n content: `Pick the light source the selected token is holding.`,\n buttons: {\n none: {\n label: `None`,\n callback: () => {\n token.update({\"dimLight\": 0, \"brightLight\": 0, \"lightAngle\": 360,});\n dialogEditor.render(true);\n }\n },\n torch: {\n label: `Torch`,\n callback: () => {\n token.update({\"dimLight\": 40, \"brightLight\": 20, \"lightAngle\": 360,});\n dialogEditor.render(true);\n }\n },\n lamp: {\n label: `Lamp`,\n callback: () => {\n token.update({\"dimLight\": 45, \"brightLight\": 15, \"lightAngle\": 360,});\n dialogEditor.render(true);\n }\n },\n bullseye: {\n label: `Bullseye Lantern`,\n callback: () => {\n token.update({\"dimLight\": 120, \"brightLight\": 60, \"lightAngle\": 45,});\n dialogEditor.render(true);\n }\n },\n hoodedOpen: {\n label: `Hooded Lantern (Open)`,\n callback: () => {\n token.update({\"dimLight\": 60, \"brightLight\": 30, \"lightAngle\": 360,});\n dialogEditor.render(true);\n }\n },\n hoodedClosed: {\n label: `Hooded Lantern (Closed)`,\n callback: () => {\n token.update({\"dimLight\": 5, \"brightLight\": 0, \"lightAngle\": 360,});\n dialogEditor.render(true);\n }\n },\n close: {\n icon: \"\",\n label: `Close`\n },\n },\n default: \"close\",\n close: () => {}\n});\n\ndialogEditor.render(true)","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[]} +{"_id":"525JVjJGyjIH5gv2","name":"Log Troubleshooting MSG To Console","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"chat","flags":{},"scope":"global","command":"// Courtesy of @fohswe\n// Logs a troubleshooting message to the browser console.\n// (You can usually view the browser console using F12.)\n\nconst gl = canvas.app.renderer.context.gl;\n\nconsole.log(\n`=== Start of troubleshooting ===\nBackground image: ${canvas.background.img.width}x${canvas.background.img.height}\nNumber of walls: ${canvas.scene.data.walls.length}\nNumber of selected vision sources: ${canvas.sight.sources.vision.size}\nNumber of light sources: ${canvas.sight.sources.lights.size}\nWebGL MAX_TEXTURE_SIZE: ${gl.getParameter(gl.MAX_TEXTURE_SIZE)}\n`\n);","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[]} +{"_id":"e25oI8hASMY8bgu6","name":"Hex Crawler Helper","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"chat","flags":{},"scope":"global","command":"/*\nRequired Rollable Tables:\n*Wilderness Encounters*\n coast\n jungle1\n jungle2\n jungle3\n mountains\n rivers\n ruins\n swamp\n wasteland\n\n*Other Tables*\n weather\n directions\n\n cache\n deadexplorers\n\nCache and Deadexplorers are not mandatory, but if you don't want them search the file for // CACHE LINES or // DEAD EXPLORER LINES and comment out the 2 lines below the comments\n\nExplanation of those tables:\nIf you have an encounter table that has the word cache in it, the cache table will be rolled automatically.\n