diff --git a/packs/macros-pf2e.db b/packs/macros-pf2e.db index 469ed22..25539b0 100644 --- a/packs/macros-pf2e.db +++ b/packs/macros-pf2e.db @@ -5,7 +5,6 @@ {"name":"Strike Damage","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"script","flags":{"core":{"sourceId":"Macro.ZTsdXtAhtr4ZF5nO"}},"scope":"global","command":"//Script for macro that rolls the damage of a \"strike\"\n//Must select a character with the associated \"strike\" for macro to work\n//Replace the weapon 'Throwing Knife' with the name of the strike you want to attack with\n //ex 'Fist' or 'Dagger\nlet weapon = 'Throwing Knife';\nlet bonusdice = '';\n(actor.data.data.actions ?? []).filter(action => action.type === 'strike').find(strike => strike.name === weapon)?.damage(event, [bonusdice]);","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[],"_id":"Aiqt0tV5jpFwpU2U"} {"name":"Apply Spell Effect","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"script","flags":{"core":{"sourceId":"Macro.pza93dBmwvhYvMBr"}},"scope":"global","command":"//allows bulk adding and removing of Spell Effects to tokens\n\nlet applyChanges = false;\nconst compendiumName=\"pf2e.spell-effects\";\nconst effectCompendium = game.packs.get(compendiumName);\nlet effectList=[];\n\nasync function getEffectList(){\n if(effectList.length<=0){\n let effects = await effectCompendium.getContent();\n for(let count=0;count'+ list[count].Name + '';\n }\n return optionlist;\n}\n\nasync function applyEffect(effectid)\n{\n let effectItem=effectList[effectid];\n \n const item = await fromUuid(effectItem.UUID);\n for (const token of canvas.tokens.controlled) {\n let existing = token.actor.items.filter(i => i.type === item.type).find(e => e.name === item.name);\n if (existing) {\n await token.actor.deleteOwnedItem(existing._id);\n } else {\n let owneditemdata = await token.actor.createOwnedItem(item);\n owneditemdata.data.start.value=game.time.worldTime;\n }\n }\n}\n\nnew Dialog({\n title: `Apply Effect`,\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 let effectid = html.find('[name=\"effectChoice\"]')[0].value;\n //console.log(effectItem);\n applyEffect(effectid);\n\n }\n }\n}).render(true);","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[],"_id":"AwVUlYzC4Nwgp1xv"} {"name":"Strike Attack","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"script","flags":{"core":{"sourceId":"Macro.fRwIQcsqEvcSsN4n"}},"scope":"global","command":"//Script for macro that rolls the attack of a \"strike\"\n//Must select a character with the associated \"strike\" for macro to work\n//Replace the weapon 'Throwing Knife' with the name of the strike you want to attack with\n //ex 'Fist' or 'Dagger'\nlet weapon = 'Throwing Knife';\n(actor.data.data.actions ?? []).filter(action => action.type === 'strike').find(strike => strike.name === weapon)?.attack(event);","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[],"_id":"BbUHj4WFU3S3CY1k"} -{"name":"Rest for the Night","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"script","flags":{"core":{"sourceId":"Macro.i9ec6DeZChkiqimD"}},"scope":"global","command":"const toChat = (actorName, content) => {\n const chatData = {\n user: game.user.id,\n content,\n speaker: { alias: actorName }\n };\n ChatMessage.create(chatData, {});\n};\n\nconst recover = () => {\n const entryTypePattern = /^(Focus|Prepared|Spontaneous|Innate)[\\w ]+Spells$/;\n const Character = CONFIG.PF2E.Actor.entityClasses.character;\n const Condition = CONFIG.PF2E.Item.entityClasses.condition;\n const tokens = canvas.tokens.controlled.filter((token) => token.actor instanceof Character);\n\n if (tokens.length === 0) {\n ui.notifications.warning(\"Select at least one token.\");\n }\n\n for (const token of tokens) {\n const actor = token.actor;\n const actorData = duplicate(actor.data);\n const items = Array.from(actor.items.values());\n const abilities = actorData.data.abilities;\n const attributes = actorData.data.attributes;\n\n // Hit points\n const conModifier = abilities.con.mod;\n const level = actorData.data.details.level.value;\n const maxRestored = Math.max(conModifier, 1) * level;\n const hpLost = attributes.hp.max - attributes.hp.value;\n const hpRestored = hpLost >= maxRestored ? maxRestored : hpLost;\n attributes.hp.value += hpRestored;\n\n // Conditions\n const conditions = items.filter((item) => (item.type === \"condition\" &&\n item.getFlag(\"pf2e\", \"condition\")));\n const conditionChanges = { };\n\n // Fatigued condition\n const fatigued = conditions.find((item) => item.name === \"Fatigued\");\n if (fatigued instanceof Condition) {\n PF2eConditionManager.removeConditionFromToken(fatigued.id, token);\n conditionChanges.Fatigued = null;\n }\n\n // Doomed and Drained conditions\n for (const conditionName of [\"Doomed\", \"Drained\"]) {\n const doomedOrDrained = conditions.find((condition) => condition.name === conditionName);\n if (doomedOrDrained === undefined) {\n continue;\n }\n const value = doomedOrDrained.data.data.value.value;\n if (value === 1) {\n PF2eConditionManager.removeConditionFromToken(doomedOrDrained.id, token);\n conditionChanges[conditionName] = null;\n } else {\n const newValue = value - 1;\n PF2eConditionManager.updateConditionValue(doomedOrDrained.id, token, newValue);\n conditionChanges[conditionName] = newValue;\n }\n }\n\n // Spellcasting entries\n const restoredList = [ ];\n const entries = items.filter(\n (item) => item.type === \"spellcastingEntry\" && entryTypePattern.test(item.name)\n );\n const entriesUpdateData = entries.flatMap((entry) => {\n const entryType = entry.name.match(entryTypePattern)[1];\n\n // Focus spells\n if (entryType === \"Focus\") {\n const focusPool = duplicate(entry.data.data.focus);\n if (focusPool.points < focusPool.pool) {\n focusPool.points = focusPool.pool;\n restoredList.push(\"Focus Pool\");\n return { _id: entry.id, \"data.focus\": focusPool };\n }\n\n return [];\n }\n\n // Innate, Spontaneous, and Prepared spells\n const slots = entry.data.data.slots;\n let updated = false;\n for (const slot of Object.values(slots)) {\n if ([\"Innate\", \"Spontaneous\"].includes(entryType)) {\n if (slot.value < slot.max) {\n slot.value = slot.max;\n updated = true;\n }\n } else {\n for (const preparedSpell of Object.values(slot.prepared)) {\n if (preparedSpell.expended) {\n preparedSpell.expended = false;\n updated = true;\n }\n }\n }\n }\n\n if (updated) {\n restoredList.push(entry.name);\n return { _id: entry.id, \"data.slots\": slots };\n }\n return [];\n });\n\n // Stamina points\n const staminaEnabled = Boolean(\n parseInt(game.settings.storage.get(\"world\").get(\"pf2e.staminaVariant\").replace(/\"/g, \"\"), 10)\n );\n if (staminaEnabled) {\n const stamina = attributes.sp;\n const keyAbility = actorData.data.details.keyability.value;\n if (stamina.value < stamina.max) {\n stamina.value = stamina.max;\n restoredList.push(\"Stamina\");\n }\n const resolve = attributes.resolve;\n const maxResolve = abilities[keyAbility].mod;\n if (resolve.value < maxResolve) {\n resolve.value = maxResolve;\n restoredList.push(\"Resolve\");\n }\n }\n\n // Updated actor with the sweet fruits of rest\n if (hpRestored > 0 || restoredList.length > 0) {\n actor.update({ \"data.attributes\": attributes });\n }\n if (entriesUpdateData.length > 0) {\n actor.updateOwnedItem(entriesUpdateData);\n }\n\n // Construct messages\n const messages = [`${token.name} awakens fully rested.`];\n\n // Hit-point restoration\n messages.push(\n hpRestored > 0 ? `${hpRestored} hit points restored.` : \"Already at full hit points.\"\n );\n\n // Attribute restoration\n const restoredString = restoredList.length === 0 ? \"\" :\n restoredList.length === 1 ? `${restoredList[0]}` :\n restoredList.length === 2 ? `${restoredList.join(\" and \")}` :\n (`${restoredList.slice(0, -1).join(\", \")}, and ` +\n `${restoredList.slice(-1)[0]}`);\n messages.push(restoredList.length > 0 ? `${restoredString} fully restored.` : null);\n\n // Condition removal\n const removedConditions = Object.keys(conditionChanges)\n .filter((key) => conditionChanges[key] === null);\n const removedString = removedConditions.length === 0 ? \"\" :\n removedConditions.length === 1 ? `${removedConditions[0]}` :\n removedConditions.length === 2 ? `${removedConditions.join(\" or \")}` :\n (`${restoredList.slice(0, -1).join(\", \")}, or ` +\n `${restoredList.slice(-1)[0]}`);\n messages.push(removedConditions.length > 0 ? `No longer ${removedString}.` : null);\n\n // Condition value reduction\n const reducedConditions = Object.keys(conditionChanges)\n .filter((key) => Number.isInteger(conditionChanges[key]));\n const reducedString = reducedConditions.length === 0 ? \"\" :\n reducedConditions.length === 1 ? `${reducedConditions[0]} condition` :\n `${reducedConditions.join(\" and \")} conditions`;\n messages.push(reducedConditions.length > 0 ? `${reducedString} reduced by 1.` : null);\n\n toChat(token.name, messages.join(\" \"));\n }\n};\n\nnew Dialog({\n title: \"Rest\",\n content: \"

Rest for the night?

\",\n buttons: {\n yes: {\n icon: '',\n label: \"Rest\",\n callback: recover\n },\n no: {\n icon: '',\n label: \"Cancel\"\n },\n },\n default: \"yes\"\n}).render(true);","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[],"_id":"CvcyNlWIiHyG9ckr"} {"_id":"DXBTE7OkjH7JeQ6X","name":"Dreams","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"script","flags":{"core":{"sourceId":"Macro.RWgZjwTzstHuEVzm"}},"scope":"global","command":"//rolltable by u/DougTheDragonborn from https://www.reddit.com/r/BehindTheTables/comments/fgdrq0/omens_from_dreams_an_all_dice_table/\n\nlet setting = [\n\t`You find yourself on a ship at night with rain pelting your face. `,\n\t`You find yourself in a seemingly peaceful grove full of flowers. `,\n\t`You find yourself at the top of a wizard's tower, looking over the ledge. `,\n\t`You find yourself sitting at a the bar of a familiar inn. `,\n\t`You find yourself face down in the sand with no structure in sight. `,\n\t`You find yourself falling from the sky and crashing into a body of water. `,\n\t`You find yourself on a battlefield lined with dead soldiers and common folk alike. `,\n\t`You find yourself in a cemetery covering all sides of a city-sized sphere floating in the darkness. `,\n\t`You find yourself as small as an insect, lost in the grass of a field. `,\n\t`You find yourself looking down upon your own body, laying where you slept this night. `,\n\t`You find yourself feasting with loved ones in a grand mansion. `,\n\t`You find yourself bound to a strangers back as they walk through a swamp. `,\n\t`You find yourself rising from slumber in the same spot you fell asleep, but you see your body still sleeping; you are a spirit. `,\n\t`You find yourself losing an arm wrestling contest to a king, and the court laughs and points. `,\n\t`You find yourself swimming in an endless ocean. `,\n\t`You find yourself telling a joke to a monarch, and nobody laughs. `,\n\t`You find yourself furiously running from something chasing you. `,\n\t`You find yourself aboard a ship far out to sea. `,\n\t`You find yourself at the gates of eternity; a choir of divine beings float around you as far as you can see. `,\n\t`You find yourself in the dilapidated temple of a religion you despise. However, a feeling of failure weighs heavy on your mind. `];\n\nlet being = [\n`A three-headed being looks down upon you from the sky, one face scowling, one crying, and one smiling. `,\n`Your deity manifests in front of you after crashing down from the heavens; they are worn from battle. `,\n`A serpent slithers toward you, it's body growing longer as it moves as to never leaves an area it once occupied. `,\n`A sickly frog uses its broken limbs to move toward you. `,\n`A figure made solely of familiar faces stares at you. `,\n`The person you care for most walks up behind you and places their hands gently around your neck. `,\n`Bones rise and form the skeleton of an unrecognizable creature. `,\n`Your skin tears from your muscle, forming a swirl of a face in front of you. `,\n`A swarm of maggots overtake your surroundings becoming a being standing 20 feet tall. `,\n`A mass of red clouds shroud the sky. A tear allows you to see something approaching from far beyond the stars. `,\n`Four versions of you appear, each one from an important moment in your life. `,\n`An oval eye nearly as tall as you stares at you, following you wherever you go. `];\n\nlet action = [\n`The being looks left quickly, and scrambles around before disappearing, but you can faintly make out`,\n`It creates a plume of fire; you feel the heat against your face. A vision of what to come:`,\n`A pool forms at your feet, swirling with otherworldly power, which glistens with the image of`,\n`It calls out your name but its voice fades from existence. Then you see`,\n`It tears open, revealing a single word in a language you do not understand along with the image of`,\n`You destroy it, but it wails and dies revealing`,\n`A wave of teeth and bones wash everything away, and in its wake, you see`,\n`It kneels before you, arms stretched out as if waiting to receive something. `,\n`Its mouth opens, a haunting chorus of laughter erupting forth; its cackles turn to streams of light which manifest as`,\n`It splits the ground open before you, exposing the depths of the world. `];\n\nlet omen = [\n`your hometown, burning, absolutely orange with smoke and flame. `,\n`those you love turning the back on you, shame is clear in their eyes. `,\n`a devilish form laughing before being consumed in brimstone. `,\n`your eyes pull themselves from your body, moving toward a collection of colors you cannot look away from. `,\n`all material items you treasure are taken, destroyed, or dissolve. `,\n`a foreign vessel with a crew that have no solid form sinking at an incredible rate. `,\n`cracks forming along the sea bed, draining the waters, and then a horde of monstrous limbs climbing out. `,\n`a terrible screech and then complete and utter silence. `];\n\nlet feeling = [\n`You feel a great sense of dread about how real it all felt, but shake it off quickly. `,\n`You feel a bit perplexed on why this being came to you of all people. `,\n`You feel like this is something you need to tell your party members, but can barely find the words to describe the experience. `,\n`You feel like this matter will weigh on you for the days to come. `,\n`You feel the matter would be a complete waste of time to investigate. `,\n`You feel unsettled at the events that unfolded before you. `];\n\nlet waking = [\n`You awaken in a cold sweat. `,\n`When you awake, you find yourself sleepwalking about 20 feet from where you fell asleep. `,\n`When you awaken, you still see the last image of your dream when you shut your eyes until you flush them with water. `,\n`You jump up, a scream rising in your throat for a moment, but you are able to silence yourself before anyone notices. `];\n\nfunction random(arr) {\n\treturn Math.floor(Math.random() * (arr.length))\n}\n\nlet message = setting[random(setting)]+being[random(being)]+action[random(action)]+omen[random(omen)]+feeling[random(feeling)]+waking[random(waking)];\n\nconsole.log(message)\n\n ChatMessage.create({\n\tuser : game.user._id,\n\tcontent: message,\n\twhisper : ChatMessage.getWhisperRecipients(\"test\")\n});","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[]} {"name":"Consume Arrow","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"script","flags":{"core":{"sourceId":"Macro.fqDgesPgNXs3txJw"}},"scope":"global","command":"if (!actor) {\n ui.notifications.warn(\"You must select yourself.\");\n}\n\nlet updates = [];\nlet consumed = \"\";\n// Use Arrows\n(async () => {\nlet item = actor.items.find(i=> i.name===\"Arrows\");\n\nif(item === null) return\n\nif (item.data.data.quantity.value < 1) {\n\n ui.notifications.warn(`${game.user.name} not enough ${name} remaining`);\n} else {\n\n updates.push({\"_id\": item._id, \"data.quantity.value\": item.data.data.quantity.value - 1});\nconsumed += `${item.data.data.quantity.value - 1} arrows left
`;\n}\n\nif (updates.length > 0) {\n actor.updateEmbeddedEntity(\"OwnedItem\", updates);\n}\nChatMessage.create({\n user: game.user._id,\nspeaker: { actor: actor, alias: actor.name },\n content: consumed,\n type: CONST.CHAT_MESSAGE_TYPES.OTHER\n});\n })();","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[],"_id":"DpkWavQfjx27DGd8"} {"name":"Spell Damage","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"script","flags":{"core":{"sourceId":"Macro.bd7LYTwB0lbdY4eW"}},"scope":"global","command":"//Spell Damage: This will roll the damage of your spell. \n //Simply replace the name with whatever spell you want to roll damage for. \n //Also be sure to change the text in the message.\n\nlet name= 'Acid Splash';const damage = (actor.data.items).find(item => item.name\n == name).data.damage.value;\n\nconst roll = new Roll(damage);\n\nroll.roll();\n\nroll.toMessage({ flavor: \"Acid Splash Damage\", speaker: ChatMessage.getSpeaker({actor: actor})});","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[],"_id":"FTvjmy7WQHYBwnwz"} @@ -23,7 +22,7 @@ {"name":"Hunted Shot","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"script","flags":{"core":{"sourceId":"Macro.coXc0B18sVhgtEf0"}},"scope":"global","command":"//Created by u/Griff4218\n\n//------------------Functions begin------------------------\nlet toChat = (content, rollString) => {\n let chatData = {\n user: game.user.id,\n content,\n speaker: ChatMessage.getSpeaker(),\n }\n ChatMessage.create(chatData, {})\n if (rollString) {\n let roll = new Roll(rollString).roll();\n chatData = {\n ...chatData,\n flavor: \"Hunted Shot Damage\",\n type: CONST.CHAT_MESSAGE_TYPES.ROLL,\n roll\n }\n ChatMessage.create(chatData, {})\n }\n \n}\n\nconst handleCrits = (roll) => roll === 1 ? -10 : (roll === 20 ? 10 : 0);\n\nlet RollAttacks = (args) => {\n\tlet {targetAC, bonus, name, weapon} = args;\n\t\n\tvar message = '';\n\tvar damage = '';\n\t\n\tconst roll1 = new Roll('d20').roll().total;\n\tconst roll2 = new Roll('d20').roll().total;\n\t\n\tconst crit1 = handleCrits(roll1)\n\tconst crit2 = handleCrits(roll2)\n\n\tif(map === \"\"){\n\t\tmap = 5;\n\n\t\tweapon.data.traits.value.forEach(element => {\n\t\t\tif(element === \"agile\"){\n\t\t\t\tmap = 4;\n\t\t\t}\n\t\t});\n\t}\n\t\n\t//A lot of If statements to change messages displayed based on the results of each attack roll\n\tif(targetAC === 0){ //targetAC is set to 0 by default, if it stays 0 we assume that no target is selected and do not compare to any AC\n\t\tmessage = name + ' Rolls a ' + (roll1 + bonus);\n\t\t\tif(crit1 === 10){\n\t\t\t\tmessage += '[Natural 20]';\n\t\t\t}else if(crit1 === -10){\n\t\t\t\tmessage += '[Natural 1]';\n\t\t\t}else{\n\t\t\t\tmessage += \"[\" + roll1 + \"+\" + bonus + \"]\";\n\t\t\t}\t\n\t\tmessage += ' on their first attack and a ' + (roll2 + bonus - map);\n\t\t\tif(crit2 === 10){\n\t\t\t\tmessage += '[Natural 20]';\n\t\t\t}else if(crit2 === -10){\n\t\t\t\tmessage += '[Natural 1]';\n\t\t\t}else{\n\t\t\t\tmessage += \"[\" + roll2 + \"+\" + bonus + \"-\" + map + \"]\";\n\t\t\t}\n\t\tmessage += ' on their scond attack.';\n\t\tdamage += weaponDamage + \"+\" + weaponDamage;\n\t}else{\n\t\tif(roll1 + crit1 + bonus >= targetAC+10){//Different messages display on a Crit, Hit, and Miss for each attack, and the damage rolls are set accordingly\n\t\t\tmessage += (name + ' Crits on the First attack with a ' + (roll1 + bonus));\n\t\t\tdamage += weaponDamage+'*2';\n\t\t\tweaponTraits.forEach(element => {\n\t\t\t\tif(element.includes(\"deadly\")){\n\t\t\t\t\tvar deadly = element.split('-');\n\t\t\t\t\tdamage += \"+\" + deadlyDamage + deadly[1];\n\t\t\t\t}\n\t\t\t});\n\t\t}else if(roll1 + crit1 + bonus >= targetAC){\n\t\t\tmessage += (name + ' Hits on the First attack with a ' + (roll1 + bonus));\n\t\t\tdamage += weaponDamage;\n\t\t}else{\n\t\t\tmessage += (name + ' Misses the First attack with a ' + (roll1 + bonus));\n\t\t\tdamage += '0';\n\t\t}\n\t\tif(crit1 === 10){\n\t\t\tmessage += '[Natural 20]';\n\t\t}else if(crit1 === -10){\n\t\t\tmessage += '[Natural 1]';\n\t\t}else{\n\t\t\tmessage += \"[\" + roll1 + \"+\" + bonus + \"]\";\n\t\t}\t\n\t\t\n\t\tif(roll2 + crit2 + bonus - map >= targetAC+10){\n\t\t\tmessage += (' and Crits on the Second attack with a ' + (roll2 + bonus - map));\n\t\t\tdamage += '+'+weaponDamage+'*2';\n\t\t\tweaponTraits.forEach(element => {\n\t\t\t\tif(element.includes(\"deadly\")){\n\t\t\t\t\tvar deadly = element.split('-');\n\t\t\t\t\tdamage += \"+\" + deadlyDamage + deadly[1];\n\t\t\t\t}\n\t\t\t});\n\t\t}else if(roll2 + crit2 + bonus - map >= targetAC){\n\t\t\tmessage += (' and Hits on the Second attack with a ' + (roll2 + bonus - map));\n\t\t\tdamage += \"+\" + weaponDamage;\n\t\t}else{\n\t\t\tmessage += (' and Misses the Second attack with a ' + (roll2 + bonus - map));\n\t\t\tdamage += '+0';\n\t\t}\n\t\tif(crit2 === 10){\n\t\t\tmessage += '[Natural 20]';\n\t\t}else if(crit2 === -10){\n\t\t\tmessage += '[Natural 1]';\n\t\t}else{\n\t\t\tmessage += \"[\" + roll2 + \"+\" + bonus + \"-\" + map + \"]\";\n\t\t}\t\n\t}\n\t\n\t//display message and Rolls\n\ttoChat(message, damage);\n}\n\n//Determines if the Actor selected as the user has the requisite feat to use the ability, returns true if it does and false if it does not\nfunction CheckFeat() {\n\tvar items = token.actor.data.items;\n\tvar hasFeat = false;\n\n\tfor(var i = 0; i < items.length; i++){\n\t\tif(items[i].name === \"Hunted Shot\"){\n\t\t\t\thasFeat = true;\n\t\t\t\treturn true;\n\t\t}\n\t}\n\t\n\tif(!hasFeat){\n\t\tui.notifications.error('This Creature does not have the Feat required to use this ability');\n\t\treturn false;\n\t}\n}\n\n//Creates and returns an array of all items that can be used for Hunted Shot (Ranged weapons with Reload 0)\nfunction GetEligableItems(inv){\n\tvar EligableItems = [];\n\tvar f = 0;\n\t\n\tfor(var i = 0; i < inv.length; i++){\n\t\t\n\t\tif(inv[i].data.range && inv[i].data.range.value > 10 && inv[i].data.reload && (inv[i].data.reload.value === \"\" || inv[i].data.reload.value === \"0\")){\n\t\t\tEligableItems[f] = inv[i];\n\t\t\tf++;\n\t\t}\n\t}\n\t\n\treturn EligableItems;\n}\n\n//Actually executes most of the script\n//In charge of Creating a dialouge for the user to select a weapon to use, setting attack variables to what they should be based on the selected weapon, and calling the RollAttacks function\n//Should probably clean up this entire function but eh\nfunction SelectWeapon(){\n\t\n\t//if there is more than 1 item that is viable to be used, create a dialouge for the user to select which one to use\n\tif(weapons.length > 1){\n\t\tvar options = '';\n\t\t\n\t\t//automatically propegates the selection menu for the dialouge with the available weapons\n\t\tfor(var i = 0; i < weapons.length; i++){\n\t\t\toptions += \"\";\n\t\t}\n\t\t\n\t\t//Dialouge control\n\t\tlet applyChanges = false;\n\t\tnew Dialog({\n\t\t title: \"Weapon Selection\",\n\t\t content: `\n\t\t\t
Please select the weapon you are using for these attacks
\n\t\t\t
\n\t\t\t
\n\t\t\t
\n\t\t\t\t\n\t\t\t\t\n\t\t\t
\n\t\t\t
\n\t\t\t`,\n\t\t buttons: {\n\t\t\tyes: {\n\t\t\t icon: \"\",\n\t\t\t label: `Select Weapon`,\n\t\t\t callback: () => applyChanges = true\n\t\t\t},\n\t\t\tno: {\n\t\t\t icon: \"\",\n\t\t\t label: `Cancel`\n\t\t\t},\n\t\t },\n\t\t default: \"yes\",\n\t\t close: html => {\n\t\t\tif (applyChanges) {\n\t\t\t for ( let token of canvas.tokens.controlled ) {\n\n\t\t\t\t//begin spaghetti code\n\t\t\t\t//set the selected weapon to that chosen by the dialouge\n\t\t\t\tvar sel = html.find('[name=\"Weapon-List\"]')[0].value || 0;\n\t\t\t\tvar selectedWeapon = weapons[sel];\n\n\t\t\t\tfor(var i = 0; i < selectedWeapon.data.traits.value.length; i++){\n\t\t\t\t\t\t\t\t\tweaponTraits[i] = selectedWeapon.data.traits.value[i];\n\t\t\t\t\t\t\t\t}\n\t\t\t\t//set the number of dice for the attack roll equal to the number set in the items data sheet\n\t\t\t\tvar diceNumber = selectedWeapon.data.damage.dice;\n\t\t\t\tif(selectedWeapon.data.strikingRune.value != \"\"){\n\t\t\t\t\t//modify the number of dice based on the weapons striking rune\n\t\t\t\t\tswitch(selectedWeapon.data.strikingRune.value){\n\t\t\t\t\t\tcase \"striking\": diceNumber += 1; deadlyDamage = 1;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase \"greaterStriking\": diceNumber += 2; deadlyDamage = 2;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t\tcase \"majorStriking\": diceNumber += 3; deadlyDamage = 3;\n\t\t\t\t\t\t\tbreak;\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\t//set the weaponDamage string equal to the diceNumber plus the die size, format is \"XdY\" where X is the number of dice and Y is the size of the die such as d6\n\t\t\t\tweaponDamage = diceNumber + selectedWeapon.data.damage.die;\n\t\t\t\tweaponTraits.forEach(element => {\n\t\t\t\t\tif(element === \"propulsive\"){\n\t\t\t\t\t\tweaponDamage += \"+\";\n\t\t\t\t\t\tif(token.actor.data.data.abilities.str.mod > 0){\n\t\t\t\t\t\t\tweaponDamage += Math.ceil(token.actor.data.data.abilities.str.mod/2);\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t});\n\t\t\t\t//set the Multiple Attack Penalty equal to that found on the weapons data sheet\n\t\t\t\tmap = selectedWeapon.data.MAP.value;\n\t\t\t\t//determines the weapons attack modifier\n\t\t\t\tAttackMod = 0;\n\t\t\t\tif(selectedWeapon.data.ability.value === \"dex\"){\n\t\t\t\t\tAttackMod += token.actor.data.data.abilities.dex.mod;\n\t\t\t\t}else{\n\t\t\t\t\tAttackMod += token.actor.data.data.abilities.str.mod;\n\t\t\t\t}\n\t\t\t\tif(selectedWeapon.data.weaponType.value === \"martial\"){//Note: if your character has a differnt prficiency in specific weapon groups (like a fighter would) this script will not accurately calculate your proficiency\n\t\t\t\t\tAttackMod += token.actor.data.data.martial.martial.value;\n\t\t\t\t}else{\n\t\t\t\t\tAttackMod += token.actor.data.data.martial.simple.value;\n\t\t\t\t}\n\t\t\t\tif(selectedWeapon.data.potencyRune.value != \"\"){\n\t\t\t\t\tAttackMod += parseInt(selectedWeapon.data.potencyRune.value);\n\t\t\t\t}\n\t\t\t\t\n\t\t\t\tfor(var i = 0; i < selectedWeapon.data.traits.value.length; i++){\n\t\t\t\t\tweaponTraits[i] = selectedWeapon.data.traits.value[i];\n\t\t\t\t}\n\t\t\t\t//\n\t\t\t\tif(targetSelected){\n\t\t\t\t\ttargetAC = target.data.attributes.ac.value;\n\t\t\t\t}\n\t\t\t\tconsole.log(selectedWeapon)\n\t\t\t\tRollAttacks({targetAC: targetAC, bonus: AttackMod, name: token.actor.data.name, weapon: selectedWeapon});\n\n\t\t\t }\n\t\t\t}\n\t\t }\n\t\t}).render(true);\n\t}else{\n\n\t\t//same as the similar above section should probably make this a function\n\t\tvar selectedWeapon = weapons[0];\n\n\t\tvar diceNumber = selectedWeapon.data.damage.dice;\n\t\tif(selectedWeapon.data.strikingRune.value != \"\"){\n\n\t\t\tswitch(selectedWeapon.data.strikingRune.value){\n\t\t\t\tcase \"striking\": diceNumber += 1; \n\t\t\t\t\tbreak;\n\t\t\t\tcase \"greaterStriking\": diceNumber += 2;\n\t\t\t\t\tbreak;\n\t\t\t\tcase \"majorStriking\": diceNumber += 3; \n\t\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\n\t\tweaponDamage = diceNumber + selectedWeapon.data.damage.die;\n\t\tmap = selectedWeapon.data.MAP.value;\n\t\tAttackMod = 0;\n\t\tif(selectedWeapon.data.ability.value === \"dex\"){\n\t\t\tAttackMod += token.actor.data.data.abilities.dex.mod;\n\t\t}else{\n\t\t\tAttackMod += token.actor.data.data.abilities.str.mod;\n\t\t}\n\t\tif(selectedWeapon.data.weaponType.value === \"martial\"){//Note: if your character has a differnt prficiency in specific weapon groups (like a fighter would) this script will not accurately calculate your proficiency\n\t\t\tAttackMod += token.actor.data.data.martial.martial.value;\n\t\t}else{\n\t\t\tAttackMod += token.actor.data.data.martial.simple.value;\n\t\t}\n\t\tif(selectedWeapon.data.potencyRune.value != \"\"){\n\t\t\tAttackMod += parseInt(selectedWeapon.data.potencyRune.value);\n\t\t}\n\t\t\t\t\n\t\tif(targetSelected){\n\t\t\ttargetAC = target.data.attributes.ac.value;\n\t\t}\n\t\tconsole.log(selectedWeapon)\n\t\t//Check if the user has the feat\n\t\tRollAttacks({targetAC: targetAC, bonus: AttackMod, name: token.actor.data.name, weapon: selectedWeapon});\n\t}\n}\n//-----------------Functions End----------------\n\n//if no token is selected, show an error\nif(!token){\n\tui.notifications.error(\"No token selected, please select the token that will use this ability\");\n}else{\n\t\n\t//Variable Declaration\n\tvar weaponDamage = '1d4'\n\tvar map = 5\n\tvar AttackMod = 0\n\tvar weaponTraits = [];\n\tvar deadlyDamage = 1;\n\t\n\tvar targetAC = 0;\n\t\n\tvar targetSelected = false;\n\tvar targetArray = Array.from(game.user.targets);\n\t\n\t//if no target selected show a info notification\n\tif(targetArray[0]){\n\t\tvar target = targetArray[0].actor.data;\n\t\ttargetSelected = true;\n\t}else{\n\t\tui.notifications.info(\"Tip: You can target another creature to automatically compare your attacks to its AC\");\n\t}\n\n\tvar weapons = GetEligableItems(token.actor.data.items);\n\t//check if the actor has any weapons that meet the requirements\n\tif(weapons[0]){\n\t\tif(CheckFeat()){\n\t\t\tSelectWeapon();\n\t\t}\n\t}else{\n\t\tui.notifications.error(\"This actor has no weapons which meet the requirements for this ability\");\n\t}\n}","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[],"_id":"Tg3LI0vO2htGscT2"} {"name":"Print Spell DC","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"script","flags":{"core":{"sourceId":"Macro.3fcBbpvGrXEeesoo"}},"scope":"global","command":"//Spell DC: This will print to the chat the spell DC. \n //Replace the name with your character's Spellcasting Entry.\n\nlet name = 'Spontaneous Primal Spells';\n\nlet dc= (actor.data.items).find(item => item.name\n == name).data.spelldc.dc;\n\nlet string = 'DC is ' + dc;\n\nChatMessage.create({content: string, speaker: ChatMessage.getSpeaker({actor: actor})});","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[],"_id":"Txaxyuz3Qxm32Mvs"} {"name":"Fury Instinct Rage","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"script","flags":{"core":{"sourceId":"Macro.IYF41W576eV2slFl"}},"scope":"global","command":"const RAGE_DAMAGE = 2; // increase for giant instinct or higher levels\n\n(async () => {\n if (actor) {\n for (let token of canvas.tokens.controlled) {\n if (\n (token.actor.data.data.customModifiers[\"ac\"] || []).some(\n (modifier) => modifier.name === \"Rage\"\n )\n ) {\n await actor.removeCustomModifier(\"ac\", \"Rage\");\n await actor.removeCustomModifier(\"damage\", \"Rage\");\n /// Remove the line below if you do not wish for your character to lose all temp hp when toggled \"off\".\n await actor.update({ \"data.attributes.hp.temp\": 0 });\n /// Remove the line above if you do not wish for your character to lose all temp hp when toggled \"off\".\n await actor.update({ \"data.attributes.speed.value\": 25 }); \n if (\n token.data.effects.includes(\n \"https://i.imgur.com/VFOwIY0.png\"\n )\n ) {\n token.toggleEffect(\"https://i.imgur.com/VFOwIY0.png\");\n }\n } else {\n const tmpHP =\n token.actor.data.data.details.level.value +\n token.actor.data.data.abilities.con.mod;\n if (token.actor.data.data.attributes.hp.temp < tmpHP) {\n await actor.update({ \"data.attributes.hp.temp\": tmpHP });\n }\n await actor.addCustomModifier(\"ac\", \"Rage\", -1, \"untyped\");\n await actor.update({ \"data.attributes.speed.value\": 35 }); \n await actor.addCustomModifier(\"damage\", \"Rage\", RAGE_DAMAGE, \"status\");\n if (\n !token.data.effects.includes(\n \"https://i.imgur.com/VFOwIY0.png\"\n )\n ) {\n token.toggleEffect(\"https://i.imgur.com/VFOwIY0.png\");\n }\n }\n }\n } else {\n ui.notifications.warn(\"You must have an actor selected.\");\n }\n})();","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[],"_id":"UYnLO4PslykOyhl9"} -{"name":"Double Slice","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"script","flags":{"core":{"sourceId":"Macro.jJcpndozj4xNGJVF"}},"scope":"global","command":"//Created by Drental, based on a macro by u/Griff4218 \n\n// ------------------ damage output ------------------\n\nconst handleCrits = (roll) => roll.terms[0].results[0] === 1 ? -1 : (roll.terms[0].results[0] === 20 ? 1 : 0);\n\nconst DoubleSliceDamage = (roll, strike, dos, targetAC) => {\n const crit = handleCrits(roll);\n var success = 1;\n\n if (roll._total >= targetAC + 10) {\n success = 3;\n } else if (roll._total >= targetAC) {\n success = 2;\n } else if (roll._total <= targetAC - 10) {\n success = 0;\n }\n dos.value =Math.max(3,Math.min(success+crit,0));\n if(dos.value === 2) {\n strike.damage({event: event});\n }\n if(dos.value === 3) {\n strike.critical({event: event});\n }\n}\n\n// ------------------ hit calculation ------------------\nfunction DoubleSliceStrike(weapon1, weapon2) {\n let targetAC = 0;\n var strike1 = actor.data.data.actions.find(a => a.type === 'strike' && a.item === weapon1._id);\n var strike2 = actor.data.data.actions.find(a => a.type === 'strike' && a.item === weapon2._id);\n if(targetSelected) {\n targetAC = target.data.attributes.ac.value;\n }\n var useAgile = (strike1.traits.find(i => i.name === 'agile') || strike2.traits.find(i => i.name === 'agile'));\n\n var options = actor.getRollOptions(['all','attack']);\n\n const dc = {value: targetAC};\n\n var dosFirst = {value: 0};\n var dosSecond = {value: 0};\n\n if (useAgile) {\n if (targetSelected) {\n strike1.attack({event: event, options: options, callback: (roll) => {DoubleSliceDamage(roll, strike1, dosFirst, targetAC)}});\n strike2.attack({event: event, options: options, callback: (roll) => {DoubleSliceDamage(roll, strike2, dosSecond, targetAC)}});\n } else {\n strike1.attack({event: event, options: options});\n strike2.attack({event: event, options: options});\n }\n } else {\n (async () => {\n if (targetSelected) {\n strike1.attack({event: event, options: options, callback: (roll) => {DoubleSliceDamage(roll, strike1, dosFirst, targetAC)}});\n } else {\n strike1.attack({event: event, options: options});\n }\n await actor.addCustomModifier(\n \"attack\",\n \"Double Slice\",\n -2,\n \"untyped\"\n );\n // get a new strike with the modifier\n if (targetSelected) {\n actor.data.data.actions.find(a => a.type === 'strike' && a.item === weapon2._id)\n .attack({event: event, options: options, callback: (roll) => {DoubleSliceDamage(roll, strike2, dosSecond, targetAC)}});\n } else {\n actor.data.data.actions.find(a => a.type === 'strike' && a.item === weapon2._id)\n .attack({event: event, options: options});\n }\n await actor.removeCustomModifier(\n \"attack\",\n \"Double Slice\"\n );\n\n // apply special feats\n if(CheckFeat('dual-onslaught', false)) {\n if (Math.max(dosFirst.value, dosSecond.value) === 1) {\n let content = 'Dual Onslaught Damage'\n let chatData = {\n user: game.user.id,\n content,\n speaker: ChatMessage.getSpeaker(),\n }\n ChatMessage.create(chatData, {})\n strike1.damage({event: event})\n }\n\n }\n if(CheckFeat('flensing-slice', false)) {\n if (dosFirst.value > 1 && dosSecond.value > 1) {\n let content = 'Flensing Slice available'\n let chatData = {\n user: game.user.id,\n content,\n speaker: ChatMessage.getSpeaker(),\n }\n ChatMessage.create(chatData, {})\n }\n }\n })();\n }\n}\n\n// ------------------ sanity check ------------------\nconst DoubleSliceCheck = ($html) => {\n var sel1 = parseInt($html.find('[name=\"Weapon-ListA\"]')[0].value) || 0;\n var sel2 = parseInt($html.find('[name=\"Weapon-ListB\"]')[0].value) || 0;\n if (sel1 !== sel2) {\n DoubleSliceStrike(weapons[sel1], weapons[sel2]);\n }\n}\n\n// ------------------ dialog function ------------------\n\n//Query all user choices\n//In charge of creating a dialog for the user to select the weapons to use\nfunction DoubleSliceUI() {\n //if there is more than 2 item that is viable to be used, create a dialouge for the user to select which ones to use\n if(weapons.length > 2){\n var options = '';\n \n // create selection entries for weapon selection\n weapons.forEach((value,key,map) => {\n options += \"\";\n });\n \n //Dialouge control\n let applyChanges = false;\n const dialogEditor = new Dialog({\n title: \"Weapon Selection\",\n content: `\n
Please select the weapons you are using for these attacks
\n
\n
\n
\n \n \n
\n
\n \n \n
\n
\n `,\n buttons: {\n yes: {\n icon: \"\",\n label: `Select Weapon`,\n callback: DoubleSliceCheck\n },\n no: {\n icon: \"\",\n label: `Cancel`\n },\n },\n default: \"yes\",\n })\n dialogEditor.render(true);\n }else{\n // it's exactly two weapons here\n DoubleSliceStrike(weapons[\"0\"], weapons[\"1\"]);\n }\n}\n\n// ------------------ helper functions ------------------\n\n//Determines if the Actor selected as the user has the requisite feat to use the ability, returns true if it does and false if it does not\nfunction CheckFeat(slug, required) {\n\n if(token.actor.items.find(i => i.data.data.slug === slug && i.type === 'feat')){\n return true;\n } else if (required) {\n ui.notifications.error('This Creature does not have the Feat required to use this ability');\n return false;\n }\n return false;\n}\n\n//Creates and returns an array of all items that can be used for Hunted Shot (Ranged weapons with Reload 0)\nfunction GetWeapons(){\n let weapons\n \n weapons = actor.items.filter(i => i.type === 'weapon' \n && i.data.data.equipped.value === true);\n \n return weapons;\n}\n\n// ------------------ execution ------------------\n\n//if no token is selected, show an error\nif(!token){\n ui.notifications.error(\"No token selected, please select the token that will use this ability\");\n}else{\n \n //Variable Declaration\n \n var targetSelected = false;\n var targetArray = Array.from(game.user.targets);\n \n //if no target selected show a info notification\n if(targetArray[0]){\n var target = targetArray[0].actor.data;\n targetSelected = true;\n }else{\n ui.notifications.info(\"Tip: You can target another creature to automatically compare your attacks to its AC\");\n }\n\n var weapons = GetWeapons();\n //check if the actor has two melee weapons equipped\n if(weapons[1]){\n if(CheckFeat('double-slice', true)){\n DoubleSliceUI();\n }\n }else{\n ui.notifications.error(\"This actor has no weapons which meet the requirements for this ability\");\n }\n}","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[],"_id":"VgRiPGG3EPKIwY6M"} +{"_id":"VgRiPGG3EPKIwY6M","name":"Double Slice","type":"script","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","scope":"global","command":"// Heavily Refactored by willvk, based on macro by Drental, u/Griff4218 \n\n// ------------------ damage output ------------------\nconst DoubleSliceDamage = (roll, strike, dos) => {\n\tdos.value = roll.data.degreeOfSuccess;\n\n if(roll.data.degreeOfSuccess === 2) {\n strike.damage({event: event});\n }\n if(roll.data.degreeOfSuccess === 3) {\n strike.critical({event: event});\n }\n\tpusher(dos);\n}\n\n// ------------------- result q ------------------------\nfunction pusher(dos){\n\tresultQ.push(dos);\n\tif (resultQ.length == 2) {\n\t\tresulter();\n\t}\n}\t\n\t\n// ------------------- check for followups -------------\nfunction resulter(){\n\n\tif(CheckFeat('dual-onslaught', false)) {\n\t\tif (Math.max(resultQ[0].value, resultQ[1].value) === 1) {\n\t\t\tgetContent('dual-onslaught');\n\t\t}\n\t}\n\tif(CheckFeat('flensing-slice', false)) {\n\t\tif (resultQ[0].value > 1 && resultQ[1].value > 1) {\n\t\t\tgetContent('flensing-slice');\n\t\t}\n\t}\n}\n\n// ------------------ hide the filthy chat card ---------\nfunction getContent(slug){\n\tlet stuff = token.actor.items.find(i => i.data.data.slug === slug && i.type === 'feat').data\n\tlet content = \n\t`
\n\t

${stuff.name}

${stuff.data.description.value}`\n\n\tlet chatData = {\n\t\tuser: game.user.id,\n\t\tcontent,\n\t\tspeaker: ChatMessage.getSpeaker(),\n\t}\n\tChatMessage.create(chatData, {})\n}\n\t\n// ------------------ hit calculation ------------------\nasync function DoubleSliceStrike(weapon1, weapon2) {\n let targetAC = 0;\n var strike1 = actor.data.data.actions.filter(a => a.type === 'strike').find(b => b.item === weapon1.data._id);\n var strike2 = actor.data.data.actions.filter(a => a.type === 'strike').find(b => b.item === weapon2.data._id);\n if(targetSelected) {\n targetAC = target.data.attributes.ac.value;\n }\n var useAgile = (strike1.traits.find(i => i.name === 'agile') || strike2.traits.find(i => i.name === 'agile'));\n\n var options = actor.getRollOptions(['all','attack']);\n\n const dc = {value: targetAC};\n\n var dosFirst = {value: 0};\n var dosSecond = {value: 0};\n\n if (useAgile) {\n if (targetSelected) {\n strike1.attack({event: event, options: options, callback: (roll) => {DoubleSliceDamage(roll, strike1, dosFirst)}, dc: dc});\n strike2.attack({event: event, options: options, callback: (roll) => {DoubleSliceDamage(roll, strike2, dosSecond)}, dc: dc});\n } else {\n strike1.attack({event: event, options: options});\n strike2.attack({event: event, options: options});\n }\n } else {\n\t\t// first strike normal\n\t\tif (targetSelected) {\n\t\t\tstrike1.attack({event: event, options: options, callback: (roll) => {DoubleSliceDamage(roll, strike1, dosFirst)}, dc: dc});\n\t\t} else {\n\t\t\tstrike1.attack({event: event, options: options});\n\t\t}\n\t\t// second strike with the negative modifier\n\t\tawait actor.addCustomModifier(\n\t\t\t\"attack\",\n\t\t\t\"Double Slice\",\n\t\t\t-2,\n\t\t\t\"untyped\"\n\t\t);\n\t\tstrike3 = actor.data.data.actions.filter(a => a.type === 'strike').find(b => b.item === weapon2.data._id)\n\t\tif (targetSelected) {\n\t\t\tstrike3.attack({event: event, options: options, callback: (roll) => {DoubleSliceDamage(roll, strike3, dosSecond)}, dc: dc});\n\t\t} else {\n\t\t\tstrike3.attack({event: event, options: options});\n\t\t}\n\t\tawait token.actor.removeCustomModifier('attack', 'double-slice');\n\t}\n}\n\n// ------------------ sanity check ------------------\nconst DoubleSliceCheck = ($html) => {\n var sel1 = parseInt($html.find('[name=\"Weapon-ListA\"]')[0].value) || 0;\n var sel2 = parseInt($html.find('[name=\"Weapon-ListB\"]')[0].value) || 0;\n if (sel1 !== sel2) {\n DoubleSliceStrike(weapons[sel1], weapons[sel2]);\n }\n}\n\n// ------------------ dialog function ------------------\n\n//Query all user choices\n//In charge of creating a dialog for the user to select the weapons to use\nfunction DoubleSliceUI() {\n //if there is more than 2 item that is viable to be used, create a dialouge for the user to select which ones to use\n if(weapons.length > 2){\n var options = '';\n \n // create selection entries for weapon selection\n weapons.forEach((value,key,map) => {\n options += \"\";\n });\n \n //Dialouge control\n let applyChanges = false;\n const dialogEditor = new Dialog({\n title: \"Weapon Selection\",\n content: `\n
Please select the weapons you are using for these attacks
\n
\n
\n
\n \n \n
\n
\n \n \n
\n
\n `,\n buttons: {\n yes: {\n icon: \"\",\n label: `Select Weapon`,\n callback: DoubleSliceCheck\n },\n no: {\n icon: \"\",\n label: `Cancel`\n },\n },\n default: \"yes\",\n })\n dialogEditor.render(true);\n }else{\n // it's exactly two weapons here\n DoubleSliceStrike(weapons[\"0\"], weapons[\"1\"]);\n }\n}\n\n// ------------------ helper functions ------------------\n\n//Determines if the Actor selected as the user has the requisite feat to use the ability, returns true if it does and false if it does not\nfunction CheckFeat(slug, required) {\n\n if(token.actor.items.find(i => i.data.data.slug === slug && i.type === 'feat')){\n return true;\n } else if (required) {\n ui.notifications.error('This Creature does not have the Feat required to use this ability');\n return false;\n }\n return false;\n}\n\n//Creates and returns an array of all items that can be used for Hunted Shot (Ranged weapons with Reload 0)\nfunction GetWeapons(){\n let weapons\n \n weapons = actor.items.filter(i => i.type === 'weapon' \n && i.data.data.equipped.value === true);\n \n return weapons;\n}\n\n// ------------------ execution ------------------\n\n//if no token is selected, show an error\nif(!token){\n ui.notifications.error(\"No token selected, please select the token that will use this ability\");\n}else{\n \n //Variable Declaration\n \n var targetSelected = false;\n var targetArray = Array.from(game.user.targets);\n\tvar resultQ = [];\n \n //if no target selected show a info notification\n if(targetArray[0]){\n var target = targetArray[0].actor.data;\n targetSelected = true;\n }else{\n ui.notifications.info(\"Tip: You can target another creature to automatically compare your attacks to its AC\");\n }\n\n var weapons = GetWeapons();\n //check if the actor has two melee weapons equipped\n if(weapons[1]){\n if(CheckFeat('double-slice', true)){\n DoubleSliceUI();\n }\n }else{\n ui.notifications.error(\"This actor has no weapons which meet the requirements for this ability\");\n }\n}","folder":null,"sort":0,"permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"flags":{"core":{"sourceId":"Macro.jJcpndozj4xNGJVF"}}} {"name":"Consume Bolt","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"script","flags":{"core":{"sourceId":"Macro.nw7UyrE3hBq5zTcA"}},"scope":"global","command":"if (!actor) {\n ui.notifications.warn(\"You must select yourself.\");\n}\n\nlet updates = [];\nlet consumed = \"\";\n// Use Bolts\n(async () => {\nlet item = actor.items.find(i=> i.name===\"Bolts\");\n\nif(item === null) return\n\nif (item.data.data.quantity.value < 1) {\n\n ui.notifications.warn(`${game.user.name} not enough ${name} remaining`);\n} else {\n\n updates.push({\"_id\": item._id, \"data.quantity.value\": item.data.data.quantity.value - 1});\nconsumed += `${item.data.data.quantity.value - 1} arrows left
`;\n}\n\nif (updates.length > 0) {\n actor.updateEmbeddedEntity(\"OwnedItem\", updates);\n}\nChatMessage.create({\n user: game.user._id,\nspeaker: { actor: actor, alias: actor.name },\n content: consumed,\n type: CONST.CHAT_MESSAGE_TYPES.OTHER\n});\n })();","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[],"_id":"Yns0FUCSbfIu1xiZ"} {"name":"Repair Item","type":"script","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","scope":"global","command":"/**\n * Author: github.com/elizeuangelo\n */\n\nfunction checkDegreeOfSuccess(check, dc) {\n\t// Returns the degree of success of a check, according to PF2e rules\n\tconst diff = check - dc;\n\tlet res = 0;\n\tif (diff > -10) res++;\n\tif (diff > -1) res++;\n\tif (diff > 9) res++;\n\treturn res;\n}\nfunction rollRepair(dc, assurance) {\n\t// Rolls the repair test and returns the result\n\tif (assurance) {\n\t\tconst prof = actor.data.data.skills.cra.modifiers.find((mod) => mod.type === 'proficiency');\n\t\tconst total = 10 + prof.modifier;\n\t\treturn { total, data: { degreeOfSuccess: checkDegreeOfSuccess(total, dc) } };\n\t}\n\tconst options = actor.getRollOptions(['all', 'skill-check', 'craft']);\n\treturn new Promise((resolve) => {\n\t\tactor.data.data.skills.cra.roll({\n\t\t\tdc: { value: dc },\n\t\t\tevent,\n\t\t\toptions,\n\t\t\tcallback: (roll) => resolve(roll),\n\t\t});\n\t\tsetTimeout(() => resolve(undefined), 30000);\n\t});\n}\nfunction getRollTooltip(roll) {\n\t// Returns a message's roll tooltip\n\treturn `\n ${roll.total}`;\n}\nfunction note(msg) {\n\t// Returns a note styled message\n\treturn `

${msg}

`;\n}\n// If no token is selected, notify and return\nif (!token) {\n\tui.notifications.warn('No token is selected');\n\treturn;\n}\nlet repairKits = false,\n\treparableItems = [],\n\tassurance = false;\n// Gathers all the actor items and feats only once\nactor.items.forEach((i) => {\n\tif (i.data.data.hp?.value && i.data.data.hp.value < i.data.data.maxHp?.value) {\n\t\treparableItems.push(i);\n\t}\n\tif (/repair kit/i.exec(i.name)) {\n\t\trepairKits = true;\n\t}\n\tif (i.type === 'feat' && i.slug === 'assurance-crafting') {\n\t\tassurance = true;\n\t}\n});\n// If there are no Repair Kits in inventory, notify and return\nif (!repairKits) {\n\tui.notifications.warn('There are no repair kits on the selected token');\n\treturn;\n}\n// Sort the Reparable Items by descending order according to the damage (max - current hp)\nreparableItems = reparableItems.sort((a, b) => b.data.data.maxHp.value - b.data.data.hp.value - (a.data.data.maxHp.value - a.data.data.hp.value));\n// Adds a Generic Item Option\nreparableItems.push({ name: 'Any Item', type: 'generic', data: { data: { hp: { value: NaN }, maxHp: { value: NaN } } } });\nconst heal = 5 * (1 + actor.data.data.skills.cra.rank);\nconst itemLevels = [];\nfor (let i = 0; i < 21; i++) {\n\titemLevels.push(~~((i + 1) * 1.33) + 13);\n}\n// Creates the dropdown menus selection\nconst itemNames = reparableItems.map((i) => i.name + ` (${i.data.data.hp.value || '??'}/${i.data.data.maxHp.value || '??'})`);\nconst html = `\n
\n
\n Select the repair kit you are using, the item you repairing and a target DC.\n Destroyed items (0 HP) cant be repaired and are not shown in the list.\n
\n
\n

A success repairs ${heal} HP (${heal * 2} on a critical).

\n
\n \n \n
\n
\n \n \n
\n
\n \n \n
\n
\n \n \n
\n
\n`;\nconst dialog = new Dialog(\n\t{\n\t\ttitle: 'Repair Item',\n\t\tcontent: Handlebars.compile(html)({ itemLevels, itemNames, assurance: !assurance }),\n\t\tbuttons: {\n\t\t\tyes: {\n\t\t\t\ticon: ``,\n\t\t\t\tlabel: 'Repair',\n\t\t\t\tcallback: async (html) => {\n\t\t\t\t\t// First get the data\n\t\t\t\t\tconst item = reparableItems[html.querySelector('#item').value];\n\t\t\t\t\tconst dcLevel = html.querySelector('#dc-level').value;\n\t\t\t\t\tconst modifier = html.querySelector('#modifier').value;\n\t\t\t\t\tconst assurance = html.querySelector('#assurance').checked;\n\t\t\t\t\tconst dc = itemLevels[dcLevel] + +modifier;\n\t\t\t\t\t// Roll\n\t\t\t\t\tconst result = await rollRepair(dc, assurance);\n\t\t\t\t\tif (!result) return;\n\t\t\t\t\tconst success = result.data.degreeOfSuccess;\n\t\t\t\t\tconst successText = {\n\t\t\t\t\t\t0: 'Critical Failure',\n\t\t\t\t\t\t1: 'Failure',\n\t\t\t\t\t\t2: 'Success',\n\t\t\t\t\t\t3: 'Critical Success',\n\t\t\t\t\t};\n\t\t\t\t\t// Header\n\t\t\t\t\tconst content = [];\n\t\t\t\t\tconst tags = [`DC ${dc}`, `Item Level ${dcLevel}`, `${item.name} (${item.data.data.hp.value}/${item.data.data.maxHp.value})`];\n\t\t\t\t\tif (item.data.data.hardness?.value) tags.push(`Hardness ${item.data.data.hardness.value}`);\n\t\t\t\t\tif (assurance) tags.push(`Assurance ${result.total}`);\n\t\t\t\t\tcontent.push(\n\t\t\t\t\t\t`F ${\n\t\t\t\t\t\t\tassurance ? 'Assured ' : ''\n\t\t\t\t\t\t}Repair

(${successText[success]})

${tags\n\t\t\t\t\t\t\t.map((b) => `${b}`)\n\t\t\t\t\t\t\t.join('')}

`\n\t\t\t\t\t);\n\t\t\t\t\t// Proceed the results\n\t\t\t\t\tlet newHp;\n\t\t\t\t\tif (!success) {\n\t\t\t\t\t\t// If it is a critical failure\n\t\t\t\t\t\tconst dmgRoll = Roll.create(`2d6 - ${item.data.data.hardness?.value || 0}`).roll();\n\t\t\t\t\t\tnewHp = Math.max(item.data.data.hp.value - dmgRoll.total, 0);\n\t\t\t\t\t\tconst rollTooltip = getRollTooltip(dmgRoll);\n\t\t\t\t\t\tif (dmgRoll.total > 0) {\n\t\t\t\t\t\t\t// If the item is damaged\n\t\t\t\t\t\t\tcontent.push(\n\t\t\t\t\t\t\t\tnote(\n\t\t\t\t\t\t\t\t\t`You fail miserably to repair ${item.name} (${newHp}/${item.data.data.maxHp.value}) and you accidentaly damage it for ${rollTooltip} damage.`\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t\tif (newHp === 0) {\n\t\t\t\t\t\t\t\tcontent.push(note(`${item.name} is destroyed.`));\n\t\t\t\t\t\t\t}\n\t\t\t\t\t\t} else {\n\t\t\t\t\t\t\t// If damage is 0\n\t\t\t\t\t\t\tcontent.push(\n\t\t\t\t\t\t\t\tnote(\n\t\t\t\t\t\t\t\t\t`You fail miserably to repair ${item.name} (${newHp}/${item.data.data.maxHp.value}) but the item resists taking damage ${rollTooltip}.`\n\t\t\t\t\t\t\t\t)\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t} else if (success === 1) {\n\t\t\t\t\t\t// If its a failure\n\t\t\t\t\t\tcontent.push(note(`You fail to repair ${item.name} (${item.data.data.hp.value}/${item.data.data.maxHp.value}).`));\n\t\t\t\t\t} else {\n\t\t\t\t\t\t// If its a success or critical success\n\t\t\t\t\t\tconst repair = heal * (success - 1);\n\t\t\t\t\t\tnewHp = Math.min(item.data.data.hp.value + repair, item.data.data.maxHp.value);\n\t\t\t\t\t\tcontent.push(\n\t\t\t\t\t\t\tnote(`You repair ${item.name} for +${repair} HP (${newHp}/${item.data.data.maxHp.value}).`)\n\t\t\t\t\t\t);\n\t\t\t\t\t}\n\t\t\t\t\tif (success === 3) content.push(note('Golden Hands'));\n\t\t\t\t\tif (item.type !== 'generic' && newHp !== undefined) item.update({ 'data.hp.value': newHp });\n\t\t\t\t\tChatMessage.create({ flavor: content.join('').replaceAll('NaN', '??'), speaker: { alias: actor.name } });\n\t\t\t\t},\n\t\t\t},\n\t\t\tno: {\n\t\t\t\ticon: ``,\n\t\t\t\tlabel: 'Cancel',\n\t\t\t},\n\t\t},\n\t\tdefault: 'yes',\n\t\trender: (html) => {\n\t\t\tconst dcLevel = html.querySelector('#dc-level');\n\t\t\thtml.querySelector('#item')?.addEventListener('change', (ev) => {\n\t\t\t\tconst item = reparableItems[+ev.target.value];\n\t\t\t\tif (item.type === 'generic') {\n\t\t\t\t\tdcLevel.disabled = false;\n\t\t\t\t\treturn;\n\t\t\t\t}\n\t\t\t\tdcLevel.disabled = true;\n\t\t\t\tdcLevel.value = item.data.data.level.value;\n\t\t\t});\n\t\t\tif (reparableItems[0].type !== 'generic') {\n\t\t\t\tdcLevel.disabled = true;\n\t\t\t\tdcLevel.value = reparableItems[0].data.data.level.value;\n\t\t\t}\n\t\t},\n\t},\n\t{ jQuery: false }\n);\ndialog.render(true);","folder":null,"sort":0,"permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"flags":{"core":{"sourceId":"Macro.RgSZ8j6sqEYmTNA4"}},"_id":"atc7EE1Z1WftfKGI"} {"name":"Apply Condition","permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"type":"script","flags":{"core":{"sourceId":"Macro.YQONuFJApe7CdYns"}},"scope":"global","command":"// apply/raise/lower/remove conditions on multiple tokens at the same time (great for things like dirge of doom). Use with\n// selective-select to quickly select enemies/friendlies\n\nlet applyChanges = false;\nconst compendiumName=\"pf2e.conditionitems\";\nconst conditionCompendium = game.packs.get(compendiumName);\nlet conditionList=[];\n\nasync function getConditionList(){\n if(conditionList.length<=0){\n let compendiumEntries = await conditionCompendium.getContent();\n console.log(compendiumEntries);\n for(let count=0;count'+ list[count].Name + '';\n }\n console.log(optionlist);\n return optionlist;\n}\n\nasync function applyCondition(conditionId, applytype)\n{\n let conditionItem=conditionList[conditionId];\n const item = await fromUuid(conditionItem.UUID);\n for (const token of canvas.tokens.controlled) {\n let existing = token.actor.items.filter(i => i.type === item.type).find(e => e.name === item.name);\n if(applytype==\"subtractive\" && existing){ \n if(existing.data.data.value.isValued && existing.data.data.value.value>1){\n const update = duplicate(existing);\n update.data.value.value--;\n await token.actor.updateEmbeddedEntity('OwnedItem', update);\n }\n else{\n await token.actor.deleteOwnedItem(existing._id);\n }\n }\n else if(existing && applytype==\"additive\" && existing.data.data.value.isValued){\n const update = duplicate(existing);\n update.data.value.value++;\n await token.actor.updateEmbeddedEntity('OwnedItem', update);\n } else if(!existing && applytype==\"additive\") {\n const newCondition = PF2eConditionManager.getCondition(conditionItem.Name);\n newCondition.data.sources.hud = !0,\n await PF2eConditionManager.addConditionToToken(newCondition, token);\n }\n await PF2eConditionManager.processConditions(token);\n }\n}\n\nnew Dialog({\n title: `Apply Condition`,\n content: `\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 var applytype=\"additive\";\n let conditionid = html.find('[name=\"conditionChoice\"]')[0].value;\n const radios=html.find('[name=\"applyType\"]');\n for(var count=0;count token.update(data));\n}\n\nconst isGM = game.user.isGM;\n\nlet color = \"#ffffff\";\nlet alpha = 1.0;\nlet tokens = canvas.tokens.controlled;\nif (tokens.length === 1) {\n color = tokens[0].data.lightColor;\n alpha = tokens[0].data.lightAlpha;\n}\n\nconst torchAnimation = {type: \"torch\", speed: 1, intensity: 1};\nconst energyShield = {type: \"energy\", speed: 1, intensity: 1};\nconst lights = {\n none: {\n label: \"None\",\n data: {dimLight: null, brightLight: null, lightAngle: 360}\n },\n torch: {\n label: \"Torch\",\n data: {dimLight: 40, brightLight: 20, lightAngle: 360, lightAnimation: torchAnimation}\n },\n light: {\n label: \"Light cantrip\",\n data: {dimLight: 40, brightLight: 20, lightAngle: 360, lightAnimation: {type: \"none\"}}\n },\n lamp: {\n label: \"Lamp\",\n data: {dimLight: 45, brightLight: 15, lightAngle: 360, lightAnimation: torchAnimation}\n },\n shield: {\n label: \"Shield\",\n data: {dimLight: 0.5, brightLight: 0, lightAngle: 360, lightAnimation: energyShield}\n },\n bullseye: {\n label: \"Bullseye Lantern\",\n data: {dimLight: 120, brightLight: 60, lightAngle: 45, lightAnimation: torchAnimation}\n }\n};\n\nfunction getLights() {\n let lightButtons = {};\n Object.entries(lights).forEach(([key, light]) => {\n lightButtons[key] = {\n label: light.label,\n callback: (html) => {\n const newColor = html.find(\"#color\").val();\n const newAlpha = Number(html.find(\"#alpha\").val());\n var data = light.data;\n tokenUpdate(Object.assign(data, {lightColor: newColor, lightAlpha: newAlpha}));\n }\n }\n });\n\n lightButtons = Object.assign(lightButtons, {\n close: {\n icon: \"\",\n label: `Close`\n }\n });\n\n return lightButtons;\n}\n\nnew Dialog({\n title: `Token Light Picker`,\n content: `\n
\n
\n \n \n ${isGM ? '' : ''}\n \n
\n
`,\n buttons: getLights(),\n default: \"close\",\n close: () => {}\n}).render(true);","folder":null,"sort":0,"permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"flags":{"core":{"sourceId":"Macro.BDiFqNriafOCkqJv"}}} {"_id":"d7GncKN4hQNl2XLd","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)\n","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[]} -{"_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 });\n","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[]} +{"_id":"fnMfRlpMvuk92hU0","name":"Switch Images","type":"script","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","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.document.update({ img });","folder":null,"sort":0,"permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"flags":{}} {"_id":"jBcKwGUwHS2V6nat","name":"Token Vision Configuration","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. 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 let lightAnimation = token.data.lightAnimation;\n let lightAlpha = token.data.lightAlpha;\n let lightColor = token.data.lightColor;\n const colorFire = \"#f8c377\";\n const colorWhite = \"#ffffff\";\n const colorMoonGlow = \"#f4f1c9\";\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 lightAnimation = {type: \"none\"};\n break;\n case \"candle\":\n dimLight = 10;\n brightLight = 5;\n lightAnimation = {type: \"torch\", speed: 2, intensity: 2};\n lightColor = colorFire;\n lightAlpha = 0.15;\n break;\n case \"lamp\":\n dimLight = 45;\n brightLight = 15;\n lightAnimation = {type: \"torch\", speed: 2, intensity: 2};\n lightColor = colorFire;\n lightAlpha = 0.15;\n break;\n case \"bullseye\":\n dimLight = 120;\n brightLight = 60;\n lockRotation = false;\n lightAngle = 52.5;\n lightAnimation = {type: \"torch\", speed: 2, intensity: 2};\n lightColor = colorFire;\n lightAlpha = 0.15;\n break;\n case \"hooded-dim\":\n dimLight = 5;\n brightLight = 0;\n lightAnimation = {type: \"torch\", speed: 2, intensity: 2};\n lightColor = colorFire;\n lightAlpha = 0.15;\n break;\n case \"hooded-bright\":\n dimLight = 60;\n brightLight = 30;\n lightAnimation = {type: \"torch\", speed: 2, intensity: 2};\n lightColor = colorFire;\n lightAlpha = 0.15;\n break;\n case \"light\":\n dimLight = 40;\n brightLight = 20;\n lightAnimation = {type: \"none\"};\n lightColor = colorWhite;\n lightAlpha = 0.15;\n break;\n case \"torch\":\n dimLight = 40;\n brightLight = 20;\n lightAnimation = {type: \"torch\", speed: 2, intensity: 2};\n lightColor = colorFire;\n lightAlpha = 0.15;\n break;\n case \"moon-touched\":\n dimLight = 30;\n brightLight = 15;\n lightAnimation = {type: \"none\"};\n lightColor = colorMoonGlow;\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 lightAnimation = token.data.lightAnimation;\n lightAlpha = token.data.lightAlpha;\n lightColor = token.data.lightColor;\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 lightAnimation: lightAnimation,\n lightAlpha: lightAlpha,\n lightColor: lightColor\n });\n }\n }\n }\n}).render(true);","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","actorIds":[]} {"_id":"kxwqZGDHqfbGbsiG","name":"Clone Token Actor","type":"script","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","scope":"global","command":"// Clones actor details from the selected token(s) into a new Actor in the item list.\n// Useful if you made changes to the actor associated with the token, but want to save that\n// updated Actor for later use or into a Compendium.\n// Created Actor will default to the name of the token with the actorNameSuffix (default: '_cloned')\n\n// WORKS ONLY FOR LINKED ACTORS\n\nconst actorNameSuffix = \"_cloned\";\n\ncanvas.tokens.controlled.forEach(o => {\n o.actor.clone({ name: o.name + actorNameSuffix }, {save: true});\n});","folder":null,"sort":0,"permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"flags":{"core":{"sourceId":"Macro.ihQwEYrlVdc0FiGQ"}}} {"name":"Unlink Tokens From Actor","type":"script","author":"y5gmtwxmW3A5ZuOP","img":"icons/svg/dice-target.svg","scope":"global","command":"// Unlinks all currently-selected tokens from their actors. This is useful if you're running\n// combat with several copies of the same enemy, as if they're all linked to the same actor,\n// applying damage to one applies damage to all. Select all the baddies and apply this macro\n// to be able to track their HP individually.\n\ncanvas.tokens.updateAll(\n t => ({ actorLink: false }),\n t => t._controlled\n);","folder":null,"sort":0,"permission":{"default":0,"y5gmtwxmW3A5ZuOP":3},"flags":{"core":{"sourceId":"Macro.y84Ws6nzEYw30hPm"}},"_id":"ljBriIrT5YMZmrQO"}