From a6977f9312097f552b7364dac02588310f9c574a Mon Sep 17 00:00:00 2001 From: Mike Bloy Date: Fri, 22 Apr 2022 18:43:18 -0500 Subject: [PATCH] fix boost/lower trait macro --- macros/warpgate_spells/boost-lower-warpgate.js | 14 +++++++------- packs/macros.db | 2 +- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/macros/warpgate_spells/boost-lower-warpgate.js b/macros/warpgate_spells/boost-lower-warpgate.js index 5ff908c..74cbde5 100644 --- a/macros/warpgate_spells/boost-lower-warpgate.js +++ b/macros/warpgate_spells/boost-lower-warpgate.js @@ -109,9 +109,9 @@ function getDottedPart(obj, key) { } async function createEffect(tokens, trait, direction, buttons) { - const raise = buttons; - const effectName = `${raise == 'raise' ? "Major" : "Minor"} ${direction} ${trait.name}`; - const effectId = `${raise == 'raise' ? "Major" : "Minor"}${direction}${trait.name}`; + const raise = (buttons == 'raise'); + const effectName = `${raise ? "Major" : "Minor"} ${direction} ${trait.name}`; + const effectId = `${raise ? "Major" : "Minor"}${direction}${trait.name}`; const effectIcon = (direction == 'Boost' ? UPICON : DOWNICON) for (const token of tokens) { let tokenDoc = token.document; @@ -174,13 +174,13 @@ async function createEffect(tokens, trait, direction, buttons) { }; let mode = foundry.CONST.ACTIVE_EFFECT_MODES.ADD; if (diemod != 0) { - effectData.changes.push({key: trait.diekey, mode: mode, value: diemod, priority: 0}); + effectData.changes.push({ key: trait.diekey, mode: mode, value: diemod, priority: 0 }); } if (modmod != 0) { - effectData.changes.push({key: trait.modkey, mode: mode, value: modmod, priority: 0}); + effectData.changes.push({ key: trait.modkey, mode: mode, value: modmod, priority: 0 }); } if (direction == "Boost") { - effectData.duration = {rounds: 5}; + effectData.duration = { rounds: 5 }; } let mutate = { embedded: { @@ -190,7 +190,7 @@ async function createEffect(tokens, trait, direction, buttons) { }; mutate.embedded.ActiveEffect[effectName] = effectData; let mutateOptions = { - comparisonKeys: {'ActiveEffect': 'label'}, + comparisonKeys: { 'ActiveEffect': 'label' }, name: effectName, permanent: false, description: effectName, diff --git a/packs/macros.db b/packs/macros.db index a947919..b9a6abc 100644 --- a/packs/macros.db +++ b/packs/macros.db @@ -17,7 +17,7 @@ {"_id":"Unwe07YlxhFhjXlJ","name":"#[CF_tempEntity]","type":"chat","author":"ygiRButlaf23fX9p","img":"icons/svg/dice-target.svg","scope":"global","command":"","folder":null,"sort":0,"permission":{"default":0,"ygiRButlaf23fX9p":3},"flags":{"cf":{"id":"temp_ocr9zgcmo7","folderPath":[],"color":"#000000","fontColor":"#FFFFFF","name":"Shape Change Macros for AE","children":["T2zPslXg2KNLoUGI","ed7YiOqkaqkGx0CR"],"icon":""}}} {"name":"Stunned CUB","type":"script","author":"g5E84yQWEXKWBl9L","img":"systems/swade/assets/icons/status/status_stunned.svg","scope":"global","command":"async function tokenEffect(token) {\n if (token.actor.data.data.status.isStunned) {\n let result = await token.actor.rollAttribute('vigor');\n let msg = \"\" + token.data.name + \" \";\n let flavor = \"\";\n if (result.total >= 4) {\n await token.actor.update({\"data.status.isStunned\": false})\n msg += \"is no longer Stunned and will not be Vulnerable at the end of \";\n flavor = \"Shaking it off\";\n if (result.total >= 8) {\n msg += \"THIS turn (raise).\";\n } else {\n msg += \"NEXT turn.\";\n }\n } else {\n msg += \"remains Stunned\";\n flavor = \"Still Stunned\";\n }\n ChatMessage.create({\n user: game.user._id,\n emote: true,\n flavor: flavor,\n speaker: ChatMessage.getSpeaker({token: token}),\n content: msg});\n } else {\n game.cub.addCondition(\"Prone\", token);\n await token.actor.update({\n \"data.status.isStunned\": true,\n \"data.status.isDistracted\": true,\n \"data.status.isVulnerable\": true})\n }\n}\n\nasync function main() {\n if (canvas.tokens.controlled.length == 0) {\n ui.notifications.error(\"No tokens selected\");\n return;\n }\n canvas.tokens.controlled.forEach(token => tokenEffect(token));\n}\n\nmain()","folder":null,"sort":0,"permission":{"default":0,"g5E84yQWEXKWBl9L":3},"flags":{"combat-utility-belt":{"macroTrigger":""},"advanced-macros":{"runAsGM":false},"core":{"sourceId":"Macro.QtQtq20VkzGUeP5F"}},"_id":"d3GjZnYn8tuJ2J7j"} {"_id":"ed7YiOqkaqkGx0CR","name":"shapeshift_AE_form","type":"script","author":"ygiRButlaf23fX9p","img":"icons/svg/dice-target.svg","scope":"global","command":"let summon = args[0].summon;\nlet duplicates = args[0].duplicates;\nlet assignedActor = args[0].assignedActor;\n\nlet data = {\n actor: {},\n token: {},\n embedded: {\n ActiveEffect: {\n \"override\": {\n icon: assignedActor.data.img,\n label: `${assignedActor.data.name} Override`,\n changes: []\n }\n },\n Item: {}\n }\n};\n\nconst name = `${assignedActor.data.token.name} (${summon.data.token.name})`;\n\nconst actorElements = ['wildcard', 'bennies', 'fatigue', 'wounds'];\nconst keptAttributes = ['smarts', 'spirit']\n\nfor (const elem of actorElements) {\n data.actor[`data.${elem}`] = assignedActor.data.data[elem];\n}\n\ndata.actor['name'] = name;\ndata.token['name'] = name;\n\nfor (const attr of keptAttributes) {\n let attrData = assignedActor.data.data.attributes[attr];\n data.embedded.ActiveEffect.override.changes.push({\n key: `data.attributes.${attr}.die.sides`,\n value: assignedActor.data.data.attributes[attr].die.sides,\n mode: foundry.CONST.ACTIVE_EFFECT_MODES.OVERRIDE\n });\n data.embedded.ActiveEffect.override.changes.push({\n key: `data.attributes.${attr}.die.modifier`,\n value: assignedActor.data.data.attributes[attr].die.modifier,\n mode: foundry.CONST.ACTIVE_EFFECT_MODES.OVERRIDE\n });\n let skills = assignedActor.items.filter(\n i => i.type === 'skill' && i.data.data.attribute === attr);\n for(const skill of skills) {\n data.embedded.ActiveEffect.override.changes.push({\n \"key\": `@Skill{${skill.name}}[data.die.sides]`,\n \"value\": skill.data.data.die.sides,\n \"mode\": foundry.CONST.ACTIVE_EFFECT_MODES.OVERRIDE\n });\n data.embedded.ActiveEffect.override.changes.push({\n \"key\": `@Skill{${skill.name}}[data.die.modifier]`,\n \"value\": skill.data.data.die.modifier,\n \"mode\": foundry.CONST.ACTIVE_EFFECT_MODES.OVERRIDE\n });\n }\n}\nconst otherItems = assignedActor.items.filter(\n i => i.type === 'edge' || i.type === 'hindrance')\nfor(const item of otherItems) {\n data.embedded['Item'][item.name] = item.data;\n}\n\nreturn data;","folder":null,"sort":0,"permission":{"default":0,"ygiRButlaf23fX9p":3},"flags":{"combat-utility-belt":{"macroTrigger":""},"advanced-macros":{"runAsGM":false},"core":{"sourceId":"Macro.WzTbhEUdD90hJLnX"},"scene-packer":{"sourceId":"Macro.Iaez53kAVbNCn1FZ","hash":"b2834198d9a69c1b7418e5437e963ba12f9b61ce"},"cf":{"id":"temp_ocr9zgcmo7","color":"#000000","path":"Shape Change Macros for AE"}}} -{"_id":"fzkUWlTKCJ68nEzL","name":"Boost/Lower Trait","type":"script","author":"HXnQ3GTDyHZ7E1ev","img":"icons/magic/movement/chevrons-down-yellow.webp","scope":"global","command":"const UPICON = 'icons/magic/life/cross-embers-glow-yellow-purple.webp'\nconst DOWNICON = 'icons/magic/movement/chevrons-down-yellow.webp'\n\nlet tokens = [];\nlet targets = Array.from(game.user.targets);\nif (targets.length > 0) {\n tokens = targets;\n} else if (canvas.tokens.controlled.length > 0) {\n tokens = canvas.tokens.controlled;\n}\nif (tokens.length > 0) {\n main(tokens);\n} else {\n ui.notifications.error(\"Please select or target a token\");\n}\n\nasync function main(tokens) {\n let traitOptions = [\n \"Agility\",\n \"Smarts\",\n \"Spirit\",\n \"Strength\",\n \"Vigor\"\n ];\n let allSkills = [];\n let traits = {\n \"Agility\": {\n type: \"attribute\",\n name: \"Agility\",\n modkey: \"data.attributes.agility.die.modifier\",\n diekey: \"data.attributes.agility.die.sides\"\n },\n \"Smarts\": {\n type: \"attribute\",\n name: \"Smarts\",\n modkey: \"data.attributes.smarts.die.modifier\",\n diekey: \"data.attributes.smarts.die.sides\"\n },\n \"Spirit\": {\n type: \"attribute\",\n name: \"Spirit\",\n modkey: \"data.attributes.spirit.die.modifier\",\n diekey: \"data.attributes.spirit.die.sides\"\n },\n \"Strength\": {\n type: \"attribute\",\n name: \"Strength\",\n modkey: \"data.attributes.strength.die.modifier\",\n diekey: \"data.attributes.strength.die.sides\"\n },\n \"Vigor\": {\n type: \"attribute\",\n name: \"Vigor\",\n modkey: \"data.attributes.vigor.die.modifier\",\n diekey: \"data.attributes.vigor.die.sides\"\n }\n };\n let tokenList = tokens.map(t => t.name).join(\", \");\n for (const token of tokens) {\n let skills = token.actor.items.filter(e => e.type == \"skill\");\n for (const skill of skills) {\n let name = skill.data.name\n traits[name] = {\n type: \"skill\",\n name: name,\n modkey: `@Skill{${name}}[data.die.modifier]`,\n diekey: `@Skill{${name}}[data.die.sides]`\n };\n if (name != 'Unskilled' && !allSkills.find(v => v == name)) {\n allSkills.push(name);\n }\n }\n }\n traitOptions = traitOptions.concat(allSkills.sort());\n let menuOptions = {\n title: 'Boost/Lower Trait',\n defaultButton: \"Cancel\",\n options: {}\n };\n let menuData = {\n inputs: [\n {type: 'header', label: 'Boost/Lower Trait'},\n {type: 'info', label: `Affected Tokens: ${tokenList}`}, \n {type: 'select', label: 'Trait', options: traitOptions},\n {type: 'info', label: \"Boost or Lower?\"},\n {type: 'radio', label: 'Boost', options: ['boostlower', true]},\n {type: 'radio', label: 'Lower', options: ['boostlower', false]},\n ],\n buttons: [\n {label: \"Apply\", value: \"apply\"},\n {label: \"Apply with raise\", value: \"raise\"},\n {label: \"Cancel\", value: \"cancel\"}\n ]\n }\n let {buttons, inputs} = await warpgate.menu(menuData, menuOptions);\n if (buttons != \"cancel\") {\n let trait = inputs[2];\n let direction = inputs[4] || inputs[5];\n createEffect(tokens, traits[trait], direction, buttons);\n }\n}\n\nfunction getDottedPart(obj, key) {\n let value = obj;\n for (const part of key.split(\".\")) {\n value = value[part];\n }\n return value;\n}\n\nasync function createEffect(tokens, trait, direction, buttons) {\n const raise = buttons;\n const effectName = `${raise == 'raise' ? \"Major\" : \"Minor\"} ${direction} ${trait.name}`;\n const effectId = `${raise == 'raise' ? \"Major\" : \"Minor\"}${direction}${trait.name}`;\n const effectIcon = (direction == 'Boost' ? UPICON : DOWNICON)\n for (const token of tokens) {\n let tokenDoc = token.document;\n let currentDie = 0;\n let currentMod = 0;\n if (trait.type == 'attribute') {\n currentDie = getDottedPart(token.actor.data, trait.diekey);\n currentMod = getDottedPart(token.actor.data, trait.modkey);\n } else {\n let skill = token.actor.items.filter(s => s.type == 'skill').find(\n s => s.data.name == trait.name)\n if (skill) {\n currentDie = skill.data.data.die.sides;\n currentMod = skill.data.data.die.modifier;\n } else {\n currentDie = 4;\n currentMod = -2;\n }\n }\n if (currentDie == 0) {\n continue;\n }\n if (currentDie == 4 && direction == \"Lower\") {\n continue;\n }\n let diemod = 2;\n let modmod = 0;\n if (direction == \"Lower\") {\n diemod = -2;\n }\n if (currentDie == 6 && direction == \"Lower\" && raise) {\n diemod = -1\n } else if (currentDie == 12 && direction == \"Boost\") {\n diemod = 0;\n modmod = 1;\n }\n if (raise) {\n diemod *= 2;\n modmod *= 2;\n }\n if (currentDie == 10 && direction == \"Boost\" && raise) {\n diemod = 2;\n modmod = 1;\n }\n if (currentDie == 4 && currentMod == -2 && direction == \"Boost\") {\n diemod = (raise ? 2 : 0);\n modmod = 2;\n }\n let effectData = {\n icon: effectIcon,\n id: effectId,\n label: effectName,\n flags: {\n swade: {\n expiration: 3,\n loseTurnOnHold: true\n }\n },\n changes: []\n };\n let mode = foundry.CONST.ACTIVE_EFFECT_MODES.ADD;\n if (diemod != 0) {\n effectData.changes.push({key: trait.diekey, mode: mode, value: diemod, priority: 0});\n }\n if (modmod != 0) {\n effectData.changes.push({key: trait.modkey, mode: mode, value: modmod, priority: 0});\n }\n if (direction == \"Boost\") {\n effectData.duration = {rounds: 5};\n }\n let mutate = {\n embedded: {\n ActiveEffect: {\n }\n }\n };\n mutate.embedded.ActiveEffect[effectName] = effectData;\n let mutateOptions = {\n comparisonKeys: {'ActiveEffect': 'label'},\n name: effectName,\n permanent: false,\n description: effectName,\n }\n if (trait.type == 'skill' && direction == 'Boost' && !token.actor.items.getName(trait.name)) {\n let itemmutate = { embedded: { Item: {} } }\n itemmutate.embedded.Item[trait.name] = {\n \"name\": trait.name,\n \"type\": \"skill\",\n \"img\": \"systems/swade/assets/icons/skills/uncertainty.svg\",\n \"data\": {\n \"description\": \"See SWADE. Auto added as untrained for Boost Trait.\",\n \"notes\": \"\",\n \"additionalStats\": {},\n \"attribute\": trait.attribute,\n \"isCoreSkill\": false,\n \"die\": {\n \"sides\": 4,\n \"modifier\": -2\n },\n \"wild-die\": {\n \"sides\": 6\n }\n }\n }\n await warpgate.mutate(token.document, itemmutate, {}, mutateOptions);\n }\n mutateOptions.permanent = true;\n await warpgate.mutate(token.document, mutate, {}, mutateOptions);\n }\n}","folder":null,"sort":0,"permission":{"default":0,"ygiRButlaf23fX9p":3},"flags":{"scene-packer":{"hash":"de40818571bebaf7d7b661be5880490654328fb3","sourceId":"Macro.ETjGUe4hbN0D9kV3"},"cf":{"id":"temp_g9ptj9b0b4s","path":"SWADE Spell Effects (WarpGate)","color":"#000000"}}} +{"_id":"fzkUWlTKCJ68nEzL","name":"Boost/Lower Trait","type":"script","author":"HXnQ3GTDyHZ7E1ev","img":"icons/magic/movement/chevrons-down-yellow.webp","scope":"global","command":"const UPICON = 'icons/magic/life/cross-embers-glow-yellow-purple.webp'\nconst DOWNICON = 'icons/magic/movement/chevrons-down-yellow.webp'\n\nlet tokens = [];\nlet targets = Array.from(game.user.targets);\nif (targets.length > 0) {\n tokens = targets;\n} else if (canvas.tokens.controlled.length > 0) {\n tokens = canvas.tokens.controlled;\n}\nif (tokens.length > 0) {\n main(tokens);\n} else {\n ui.notifications.error(\"Please select or target a token\");\n}\n\nasync function main(tokens) {\n let traitOptions = [\n \"Agility\",\n \"Smarts\",\n \"Spirit\",\n \"Strength\",\n \"Vigor\"\n ];\n let allSkills = [];\n let traits = {\n \"Agility\": {\n type: \"attribute\",\n name: \"Agility\",\n modkey: \"data.attributes.agility.die.modifier\",\n diekey: \"data.attributes.agility.die.sides\"\n },\n \"Smarts\": {\n type: \"attribute\",\n name: \"Smarts\",\n modkey: \"data.attributes.smarts.die.modifier\",\n diekey: \"data.attributes.smarts.die.sides\"\n },\n \"Spirit\": {\n type: \"attribute\",\n name: \"Spirit\",\n modkey: \"data.attributes.spirit.die.modifier\",\n diekey: \"data.attributes.spirit.die.sides\"\n },\n \"Strength\": {\n type: \"attribute\",\n name: \"Strength\",\n modkey: \"data.attributes.strength.die.modifier\",\n diekey: \"data.attributes.strength.die.sides\"\n },\n \"Vigor\": {\n type: \"attribute\",\n name: \"Vigor\",\n modkey: \"data.attributes.vigor.die.modifier\",\n diekey: \"data.attributes.vigor.die.sides\"\n }\n };\n let tokenList = tokens.map(t => t.name).join(\", \");\n for (const token of tokens) {\n let skills = token.actor.items.filter(e => e.type == \"skill\");\n for (const skill of skills) {\n let name = skill.data.name\n traits[name] = {\n type: \"skill\",\n name: name,\n modkey: `@Skill{${name}}[data.die.modifier]`,\n diekey: `@Skill{${name}}[data.die.sides]`\n };\n if (name != 'Unskilled' && !allSkills.find(v => v == name)) {\n allSkills.push(name);\n }\n }\n }\n traitOptions = traitOptions.concat(allSkills.sort());\n let menuOptions = {\n title: 'Boost/Lower Trait',\n defaultButton: \"Cancel\",\n options: {}\n };\n let menuData = {\n inputs: [\n {type: 'header', label: 'Boost/Lower Trait'},\n {type: 'info', label: `Affected Tokens: ${tokenList}`}, \n {type: 'select', label: 'Trait', options: traitOptions},\n {type: 'info', label: \"Boost or Lower?\"},\n {type: 'radio', label: 'Boost', options: ['boostlower', true]},\n {type: 'radio', label: 'Lower', options: ['boostlower', false]},\n ],\n buttons: [\n {label: \"Apply\", value: \"apply\"},\n {label: \"Apply with raise\", value: \"raise\"},\n {label: \"Cancel\", value: \"cancel\"}\n ]\n }\n let {buttons, inputs} = await warpgate.menu(menuData, menuOptions);\n if (buttons != \"cancel\") {\n let trait = inputs[2];\n let direction = inputs[4] || inputs[5];\n createEffect(tokens, traits[trait], direction, buttons);\n }\n}\n\nfunction getDottedPart(obj, key) {\n let value = obj;\n for (const part of key.split(\".\")) {\n value = value[part];\n }\n return value;\n}\n\nasync function createEffect(tokens, trait, direction, buttons) {\n const raise = (buttons == 'raise');\n const effectName = `${raise ? \"Major\" : \"Minor\"} ${direction} ${trait.name}`;\n const effectId = `${raise ? \"Major\" : \"Minor\"}${direction}${trait.name}`;\n const effectIcon = (direction == 'Boost' ? UPICON : DOWNICON)\n for (const token of tokens) {\n let tokenDoc = token.document;\n let currentDie = 0;\n let currentMod = 0;\n if (trait.type == 'attribute') {\n currentDie = getDottedPart(token.actor.data, trait.diekey);\n currentMod = getDottedPart(token.actor.data, trait.modkey);\n } else {\n let skill = token.actor.items.filter(s => s.type == 'skill').find(\n s => s.data.name == trait.name)\n if (skill) {\n currentDie = skill.data.data.die.sides;\n currentMod = skill.data.data.die.modifier;\n } else {\n currentDie = 4;\n currentMod = -2;\n }\n }\n if (currentDie == 0) {\n continue;\n }\n if (currentDie == 4 && direction == \"Lower\") {\n continue;\n }\n let diemod = 2;\n let modmod = 0;\n if (direction == \"Lower\") {\n diemod = -2;\n }\n if (currentDie == 6 && direction == \"Lower\" && raise) {\n diemod = -1\n } else if (currentDie == 12 && direction == \"Boost\") {\n diemod = 0;\n modmod = 1;\n }\n if (raise) {\n diemod *= 2;\n modmod *= 2;\n }\n if (currentDie == 10 && direction == \"Boost\" && raise) {\n diemod = 2;\n modmod = 1;\n }\n if (currentDie == 4 && currentMod == -2 && direction == \"Boost\") {\n diemod = (raise ? 2 : 0);\n modmod = 2;\n }\n let effectData = {\n icon: effectIcon,\n id: effectId,\n label: effectName,\n flags: {\n swade: {\n expiration: 3,\n loseTurnOnHold: true\n }\n },\n changes: []\n };\n let mode = foundry.CONST.ACTIVE_EFFECT_MODES.ADD;\n if (diemod != 0) {\n effectData.changes.push({ key: trait.diekey, mode: mode, value: diemod, priority: 0 });\n }\n if (modmod != 0) {\n effectData.changes.push({ key: trait.modkey, mode: mode, value: modmod, priority: 0 });\n }\n if (direction == \"Boost\") {\n effectData.duration = { rounds: 5 };\n }\n let mutate = {\n embedded: {\n ActiveEffect: {\n }\n }\n };\n mutate.embedded.ActiveEffect[effectName] = effectData;\n let mutateOptions = {\n comparisonKeys: { 'ActiveEffect': 'label' },\n name: effectName,\n permanent: false,\n description: effectName,\n }\n if (trait.type == 'skill' && direction == 'Boost' && !token.actor.items.getName(trait.name)) {\n let itemmutate = { embedded: { Item: {} } }\n itemmutate.embedded.Item[trait.name] = {\n \"name\": trait.name,\n \"type\": \"skill\",\n \"img\": \"systems/swade/assets/icons/skills/uncertainty.svg\",\n \"data\": {\n \"description\": \"See SWADE. Auto added as untrained for Boost Trait.\",\n \"notes\": \"\",\n \"additionalStats\": {},\n \"attribute\": trait.attribute,\n \"isCoreSkill\": false,\n \"die\": {\n \"sides\": 4,\n \"modifier\": -2\n },\n \"wild-die\": {\n \"sides\": 6\n }\n }\n }\n await warpgate.mutate(token.document, itemmutate, {}, mutateOptions);\n }\n mutateOptions.permanent = true;\n await warpgate.mutate(token.document, mutate, {}, mutateOptions);\n }\n}","folder":null,"sort":0,"permission":{"default":0,"ygiRButlaf23fX9p":3},"flags":{"scene-packer":{"hash":"de40818571bebaf7d7b661be5880490654328fb3","sourceId":"Macro.ETjGUe4hbN0D9kV3"},"cf":{"id":"temp_g9ptj9b0b4s","path":"SWADE Spell Effects (WarpGate)","color":"#000000"},"core":{"sourceId":"Macro.ETjGUe4hbN0D9kV3"}}} {"name":"#[CF_tempEntity]","permission":{"default":0,"mrhsZpAiXth4sLah":3},"type":"chat","flags":{"cf":{"id":"temp_natl1zonf8","folderPath":[],"color":"#000000","fontColor":"#FFFFFF","name":"Cards","children":[],"icon":""}},"scope":"global","command":"","author":"mrhsZpAiXth4sLah","img":"icons/svg/dice-target.svg","actorIds":[],"_id":"hnicuEhZlfMF2upA"} {"name":"Sanctuary CUB","type":"script","author":"g5E84yQWEXKWBl9L","img":"icons/svg/holy-shield.svg","scope":"global","command":"const CONDITION = \"Sanctuary\";\n\n\nasync function tokenEffect(token) {\n console.log(token);\n let message = \"\" + token.data.name;\n if (game.cub.hasCondition(CONDITION, token)) {\n message += \" is no longer under Sanctuary.\";\n game.cub.removeCondition(CONDITION, token);\n } else {\n game.cub.addCondition(CONDITION, token);\n message += \" is under @Compendium[swpf-core-rules.swpf-powers.H82NWO4VNEYTqciG]{Sanctuary}.\";\n }\n ChatMessage.create({\n user: game.user._id,\n emote: true,\n flavor: \"Sanctuary!\",\n speaker: ChatMessage.getSpeaker({token: token}),\n content: message});\n}\n\nasync function main() {\n if (canvas.tokens.controlled.length == 0) {\n ui.notifications.error(\"No tokens selected\");\n return;\n }\n canvas.tokens.controlled.forEach(token => tokenEffect(token));\n}\n\nmain()","folder":null,"sort":0,"permission":{"default":0,"g5E84yQWEXKWBl9L":3},"flags":{"combat-utility-belt":{"macroTrigger":""},"advanced-macros":{"runAsGM":false},"core":{"sourceId":"Macro.T7GXMuVq2JNMne2g"}},"_id":"jAPMvsQemX2LnSWp"} {"_id":"lm51dm7e9yhTx4os","name":"ApplySpellEffect","type":"script","author":"ygiRButlaf23fX9p","img":"icons/svg/sun.svg","scope":"global","command":"let effect = args[0];\nlet targets = args[1];\nlet extra = args[2];\nif (!extra) {\n extra = {};\n}\nif (!extra.name) { extra.name = effect.label }\nif (!extra.duration) { extra.duration = effect.duration?.rounds }\nif (!extra.startMessage) {\n extra.startMessage = `${effect.label}'s effects start`\n}\nif (!extra.endMessage) {\n extra.endMessage = `${effect.label}'s effects end`\n}\nif (!extra.fadeMessage) {\n extra.fadeMessage = `${effect.label}'s effects start to fade`\n}\n\nif (canvas.tokens.controlled.length == 0) {\n ui.notifications.error(\"No tokens selected\");\n return;\n}\nfor (let tgt of targets) {\n let actor = tgt.actor;\n let active = actor.effects.find(i => i.data.label === effect.label);\n let chatData = {\n speaker: ChatMessage.getSpeaker(tgt),\n type: CONST.CHAT_MESSAGE_TYPES.OTHER,\n emote: true\n }\n if (extra.flavor) {\n chatData.flavor = extra.flavor;\n }\n if (active) {\n await tgt.toggleEffect(effect, { active: false })\n chatData.content = extra.endMessage;\n } else {\n await tgt.toggleEffect(effect, { active: true })\n chatData.content = extra.startMessage;\n }\n if (chatData.content) {\n ChatMessage.create(chatData);\n }\n}\nif (game.modules.get(\"turnAlert\")?.active) {\n if (game.combat && extra.duration) {\n let alertData = {\n round: extra.duration - 1,\n roundAbsolute: false,\n turnId: game.combat.combatant._id,\n message: extra.fadeMessage\n }\n await TurnAlert.create(alertData);\n\n const targetIds = targets.map(t => t.id);\n alertData = {\n round: extra.duration - 1,\n roundAbsolute: false,\n turnId: game.combat.combatant._id,\n endOfTurn: true,\n message: extra.endMessage,\n macro: \"CancelSpellEffect\",\n args: [effect, targetIds]\n }\n await TurnAlert.create(alertData);\n }\n} else if (game.modules.get(\"about-time\")?.active && extra.duration) {\n let duration = extra.duration * 6;\n let preDuration = duration - 6;\n console.log(\"effects end in duration:\", duration, preDuration)\n Gametime.doIn({ seconds: preDuration }, () => {\n let chatData = {\n type: CONST.CHAT_MESSAGE_TYPES.OTHER,\n emote: true,\n content: extra.fadeMessage\n }\n if (extra.flavor) {\n chatData.flavor = extra.flavor;\n }\n ChatMessage.create(chatData);\n });\n const targetIds = targets.map(t => t.id);\n Gametime.doIn({ seconds: duration }, () => {\n let macro = game.macros.getName(\"CancelSpellEffect\")\n macro.execute(effect, targetIds)\n })\n}","folder":null,"sort":0,"permission":{"default":0,"ygiRButlaf23fX9p":3},"flags":{"combat-utility-belt":{"macroTrigger":""},"advanced-macros":{"runAsGM":false},"scene-packer":{"sourceId":"Macro.OB9FF0mpgWSYEryu"},"cf":{"id":"temp_p20tzfcm449","path":"Spell Effect Macros","color":"#000000"}}}