diff --git a/macros/BR2_actions.json b/macros/BR2_actions.json
index 6fa7726..1ce78fc 100644
--- a/macros/BR2_actions.json
+++ b/macros/BR2_actions.json
@@ -1,69 +1,70 @@
-{
- "id": "Smite",
- "name": "Smite",
- "button_name": "Smite Bonus",
- "dmgMod": "+2",
- "defaultChecked": true,
- "and_selector": [
- {
- "not_selector": [
- {
- "selector_type": "actor_has_effect",
- "selector_value": "Smite with raise"
- }
- ]
- },
- {
- "selector_type": "actor_has_effect",
- "selector_value": "Smite"
- },
- {
- "or_selector": [
- {
- "selector_type": "skill",
- "selector_value": "Fighting"
- },
- {
- "selector_type": "skill",
- "selector_value": "Athletics"
- },
- {
- "selector_type": "skill",
- "selector_value": "Shooting"
- }
- ]
- }
- ],
- "group": "Spell Effects"
-}
-
-{
- "id": "SmiteRaise",
- "name": "Smite with Raise",
- "button_name": "Smite Bonus",
- "dmgMod": "+4",
- "defaultChecked": true,
- "and_selector": [
- {
- "selector_type": "actor_has_effect",
- "selector_value": "Smite with raise",
- },
- {
- "or_selector": [
- {
- "selector_type": "skill",
- "selector_value": "Fighting"
- },
- {
- "selector_type": "skill",
- "selector_value": "Athletics"
- },
- {
- "selector_type": "skill",
- "selector_value": "Shooting"
- }
- ]
- },
- ],
- "group": "Spell Effects"
-}
+[
+ {
+ "id": "Smite",
+ "name": "Smite",
+ "button_name": "Smite Bonus",
+ "dmgMod": "+2",
+ "defaultChecked": true,
+ "and_selector": [
+ {
+ "not_selector": [
+ {
+ "selector_type": "actor_has_effect",
+ "selector_value": "Smite with raise"
+ }
+ ]
+ },
+ {
+ "selector_type": "actor_has_effect",
+ "selector_value": "Smite"
+ },
+ {
+ "or_selector": [
+ {
+ "selector_type": "skill",
+ "selector_value": "Fighting"
+ },
+ {
+ "selector_type": "skill",
+ "selector_value": "Athletics"
+ },
+ {
+ "selector_type": "skill",
+ "selector_value": "Shooting"
+ }
+ ]
+ }
+ ],
+ "group": "Spell Effects"
+ },
+ {
+ "id": "SmiteRaise",
+ "name": "Smite with Raise",
+ "button_name": "Smite Bonus",
+ "dmgMod": "+4",
+ "defaultChecked": true,
+ "and_selector": [
+ {
+ "selector_type": "actor_has_effect",
+ "selector_value": "Smite with raise"
+ },
+ {
+ "or_selector": [
+ {
+ "selector_type": "skill",
+ "selector_value": "Fighting"
+ },
+ {
+ "selector_type": "skill",
+ "selector_value": "Athletics"
+ },
+ {
+ "selector_type": "skill",
+ "selector_value": "Shooting"
+ }
+ ]
+ }
+ ],
+ "group": "Spell Effects"
+ }
+]
\ No newline at end of file
diff --git a/macros/warpgate_spells/boost-lower-warpgate.js b/macros/warpgate_spells/boost-lower-warpgate.js
new file mode 100644
index 0000000..5ff908c
--- /dev/null
+++ b/macros/warpgate_spells/boost-lower-warpgate.js
@@ -0,0 +1,224 @@
+const UPICON = 'icons/magic/life/cross-embers-glow-yellow-purple.webp'
+const DOWNICON = 'icons/magic/movement/chevrons-down-yellow.webp'
+
+let tokens = [];
+let targets = Array.from(game.user.targets);
+if (targets.length > 0) {
+ tokens = targets;
+} else if (canvas.tokens.controlled.length > 0) {
+ tokens = canvas.tokens.controlled;
+}
+if (tokens.length > 0) {
+ main(tokens);
+} else {
+ ui.notifications.error("Please select or target a token");
+}
+
+async function main(tokens) {
+ let traitOptions = [
+ "Agility",
+ "Smarts",
+ "Spirit",
+ "Strength",
+ "Vigor"
+ ];
+ let allSkills = [];
+ let traits = {
+ "Agility": {
+ type: "attribute",
+ name: "Agility",
+ modkey: "data.attributes.agility.die.modifier",
+ diekey: "data.attributes.agility.die.sides"
+ },
+ "Smarts": {
+ type: "attribute",
+ name: "Smarts",
+ modkey: "data.attributes.smarts.die.modifier",
+ diekey: "data.attributes.smarts.die.sides"
+ },
+ "Spirit": {
+ type: "attribute",
+ name: "Spirit",
+ modkey: "data.attributes.spirit.die.modifier",
+ diekey: "data.attributes.spirit.die.sides"
+ },
+ "Strength": {
+ type: "attribute",
+ name: "Strength",
+ modkey: "data.attributes.strength.die.modifier",
+ diekey: "data.attributes.strength.die.sides"
+ },
+ "Vigor": {
+ type: "attribute",
+ name: "Vigor",
+ modkey: "data.attributes.vigor.die.modifier",
+ diekey: "data.attributes.vigor.die.sides"
+ }
+ };
+ let tokenList = tokens.map(t => t.name).join(", ");
+ for (const token of tokens) {
+ let skills = token.actor.items.filter(e => e.type == "skill");
+ for (const skill of skills) {
+ let name = skill.data.name
+ traits[name] = {
+ type: "skill",
+ name: name,
+ modkey: `@Skill{${name}}[data.die.modifier]`,
+ diekey: `@Skill{${name}}[data.die.sides]`
+ };
+ if (name != 'Unskilled' && !allSkills.find(v => v == name)) {
+ allSkills.push(name);
+ }
+ }
+ }
+ traitOptions = traitOptions.concat(allSkills.sort());
+ let menuOptions = {
+ title: 'Boost/Lower Trait',
+ defaultButton: "Cancel",
+ options: {}
+ };
+ let menuData = {
+ inputs: [
+ {type: 'header', label: 'Boost/Lower Trait'},
+ {type: 'info', label: `Affected Tokens: ${tokenList}`},
+ {type: 'select', label: 'Trait', options: traitOptions},
+ {type: 'info', label: "Boost or Lower?"},
+ {type: 'radio', label: 'Boost', options: ['boostlower', true]},
+ {type: 'radio', label: 'Lower', options: ['boostlower', false]},
+ ],
+ buttons: [
+ {label: "Apply", value: "apply"},
+ {label: "Apply with raise", value: "raise"},
+ {label: "Cancel", value: "cancel"}
+ ]
+ }
+ let {buttons, inputs} = await warpgate.menu(menuData, menuOptions);
+ if (buttons != "cancel") {
+ let trait = inputs[2];
+ let direction = inputs[4] || inputs[5];
+ createEffect(tokens, traits[trait], direction, buttons);
+ }
+}
+
+function getDottedPart(obj, key) {
+ let value = obj;
+ for (const part of key.split(".")) {
+ value = value[part];
+ }
+ return value;
+}
+
+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 effectIcon = (direction == 'Boost' ? UPICON : DOWNICON)
+ for (const token of tokens) {
+ let tokenDoc = token.document;
+ let currentDie = 0;
+ let currentMod = 0;
+ if (trait.type == 'attribute') {
+ currentDie = getDottedPart(token.actor.data, trait.diekey);
+ currentMod = getDottedPart(token.actor.data, trait.modkey);
+ } else {
+ let skill = token.actor.items.filter(s => s.type == 'skill').find(
+ s => s.data.name == trait.name)
+ if (skill) {
+ currentDie = skill.data.data.die.sides;
+ currentMod = skill.data.data.die.modifier;
+ } else {
+ currentDie = 4;
+ currentMod = -2;
+ }
+ }
+ if (currentDie == 0) {
+ continue;
+ }
+ if (currentDie == 4 && direction == "Lower") {
+ continue;
+ }
+ let diemod = 2;
+ let modmod = 0;
+ if (direction == "Lower") {
+ diemod = -2;
+ }
+ if (currentDie == 6 && direction == "Lower" && raise) {
+ diemod = -1
+ } else if (currentDie == 12 && direction == "Boost") {
+ diemod = 0;
+ modmod = 1;
+ }
+ if (raise) {
+ diemod *= 2;
+ modmod *= 2;
+ }
+ if (currentDie == 10 && direction == "Boost" && raise) {
+ diemod = 2;
+ modmod = 1;
+ }
+ if (currentDie == 4 && currentMod == -2 && direction == "Boost") {
+ diemod = (raise ? 2 : 0);
+ modmod = 2;
+ }
+ let effectData = {
+ icon: effectIcon,
+ id: effectId,
+ label: effectName,
+ flags: {
+ swade: {
+ expiration: 3,
+ loseTurnOnHold: true
+ }
+ },
+ changes: []
+ };
+ let mode = foundry.CONST.ACTIVE_EFFECT_MODES.ADD;
+ if (diemod != 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});
+ }
+ if (direction == "Boost") {
+ effectData.duration = {rounds: 5};
+ }
+ let mutate = {
+ embedded: {
+ ActiveEffect: {
+ }
+ }
+ };
+ mutate.embedded.ActiveEffect[effectName] = effectData;
+ let mutateOptions = {
+ comparisonKeys: {'ActiveEffect': 'label'},
+ name: effectName,
+ permanent: false,
+ description: effectName,
+ }
+ if (trait.type == 'skill' && direction == 'Boost' && !token.actor.items.getName(trait.name)) {
+ let itemmutate = { embedded: { Item: {} } }
+ itemmutate.embedded.Item[trait.name] = {
+ "name": trait.name,
+ "type": "skill",
+ "img": "systems/swade/assets/icons/skills/uncertainty.svg",
+ "data": {
+ "description": "See SWADE. Auto added as untrained for Boost Trait.",
+ "notes": "",
+ "additionalStats": {},
+ "attribute": trait.attribute,
+ "isCoreSkill": false,
+ "die": {
+ "sides": 4,
+ "modifier": -2
+ },
+ "wild-die": {
+ "sides": 6
+ }
+ }
+ }
+ await warpgate.mutate(token.document, itemmutate, {}, mutateOptions);
+ }
+ mutateOptions.permanent = true;
+ await warpgate.mutate(token.document, mutate, {}, mutateOptions);
+ }
+}
\ No newline at end of file
diff --git a/macros/warpgate_spells/deflection-warpgate.js b/macros/warpgate_spells/deflection-warpgate.js
new file mode 100644
index 0000000..c38d0fd
--- /dev/null
+++ b/macros/warpgate_spells/deflection-warpgate.js
@@ -0,0 +1,79 @@
+const ICON = 'icons/magic/defensive/shield-barrier-deflect-teal.webp'
+
+let tokens = [];
+let targets = Array.from(game.user.targets);
+if (targets.length > 0) {
+ tokens = targets;
+} else if (canvas.tokens.controlled.length > 0) {
+ tokens = canvas.tokens.controlled;
+}
+if (tokens.length > 0) {
+ main(tokens);
+} else {
+ ui.notifications.error("Please select or target a token");
+}
+
+async function main(tokens) {
+ let tokenList = tokens.map(t => t.name).join(", ");
+ let dialogOptions = {
+ title: "Deflection",
+ content: `Apply Deflection to ${tokenList}`,
+ default: "cancel",
+ buttons: [
+ {label: "Apply (melee)", value: "melee"},
+ {label: "Apply (ranged)", value: "ranged"},
+ {label: "Apply with raise (both)", value: "raise"},
+ {label: "Cancel", value: "cancel"}
+ ]
+ }
+ let choice = await warpgate.buttonDialog(dialogOptions);
+ if (choice != "cancel") {
+ createEffect(tokens, choice);
+ }
+}
+
+async function createEffect(tokens, choice) {
+ let effectName = 'Deflection';
+ let effectId = `deflection${choice}`;
+ let changes = []
+ switch (choice) {
+ case 'melee':
+ effectName = "Melee " + effectName;
+ break
+ case 'ranged':
+ effectName = "Ranged " + effectName;
+ break
+ }
+ const effectIcon = ICON;
+ for (const token of tokens) {
+ let effectData = {
+ icon: effectIcon,
+ id: effectId,
+ label: effectName,
+ duration: {rounds: 5},
+ flags: {
+ swade: {
+ expiration: 3,
+ loseTurnOnHold: true
+ }
+ },
+ changes: [
+ {key: 'data.stats.parry.modifier', mode: foundry.CONST.ACTIVE_EFFECT_MODES.UPGRADE, value: 0, priority: 0}
+ ],
+ };
+ let mutate = {
+ embedded: {
+ ActiveEffect: {
+ }
+ }
+ };
+ mutate.embedded.ActiveEffect[effectName] = effectData;
+ let mutateOptions = {
+ comparisonKeys: {'ActiveEffect': 'label'},
+ name: effectName,
+ permanent: true,
+ description: effectName,
+ }
+ await warpgate.mutate(token.document, mutate, {}, mutateOptions);
+ }
+}
\ No newline at end of file
diff --git a/macros/warpgate_spells/protection-warpgate.js b/macros/warpgate_spells/protection-warpgate.js
new file mode 100644
index 0000000..e69de29
diff --git a/macros/warpgate_spells/smite-warpgate.js b/macros/warpgate_spells/smite-warpgate.js
new file mode 100644
index 0000000..06a04b5
--- /dev/null
+++ b/macros/warpgate_spells/smite-warpgate.js
@@ -0,0 +1,101 @@
+const ICON = 'icons/weapons/swords/sword-flanged-lightning.webp'
+
+let tokens = [];
+let targets = Array.from(game.user.targets);
+if (targets.length > 0) {
+ tokens = targets;
+} else if (canvas.tokens.controlled.length > 0) {
+ tokens = canvas.tokens.controlled;
+}
+if (tokens.length > 0) {
+ main(tokens);
+} else {
+ ui.notifications.error("Please select or target a token");
+}
+
+async function main(tokens) {
+ let tokenList = tokens.map(t => t.name).join(", ");
+ let menuOptions = {
+ title: 'Smite',
+ defaultButton: "cancel",
+ options: {}
+ }
+ let menuData = {
+ inputs: [
+ {type: 'header', label: 'Smite'},
+ {type: 'info', label: `Apply Smite to ${tokenList}`},
+ ],
+ buttons: [
+ {label: "Apply", value: "apply"},
+ {label: "Apply with Raise", value: "raise"},
+ {label: "Cancel", value: "cancel"}
+ ]
+ }
+ let tokenWeapons = {};
+ let index = 1;
+ for (const token of tokens) {
+ index += 2;
+ tokenWeapons[token.id] = index;
+ menuData.inputs.push({type: 'info', label: `
\n
\n
\n
Which Trait?
\n
Boost or Lower?
\n
\n
\n
${traitoptions}
\n
\n \n
\n
\n
\n \n `,\n buttons: {\n apply: {\n label: \"Apply\",\n callback: () => { applyChanges = true; raise }\n },\n raise: {\n label: \"Apply with raise\",\n callback: () => { applyChanges = true; raise = true }\n },\n cancel: {\n label: \"Cancel\"\n }\n },\n default: \"apply\",\n close: html => {\n if (applyChanges) {\n let direction = html.find('[name=\"select-direction\"]')[0].value;\n let trait = html.find('[name=\"select-trait\"]')[0].value;\n createEffect(tokens, traits, direction, trait, raise);\n }\n }\n }).render(true);\n} // end main\n\nasync function createEffect(tokens, traits, direction, trait, raise) {\n trait = traits[trait];\n for (var tokenD of tokens) {\n let currentdie = 0;\n let currentmod = 0;\n if (trait[\"type\"] == \"attribute\") {\n var part;\n let value = tokenD.actor.data;\n for (part of trait[\"diekey\"].split(\".\")) {\n value = value[part];\n }\n currentdie = value\n value = tokenD.actor.data\n for (part of trait[\"modkey\"].split(\".\")) {\n value = value[part];\n }\n currentmod = value;\n } else {\n let skill = tokenD.actor.items.filter(s => s.type == \"skill\").find(s => s.data.name == trait[\"name\"])\n if (skill) {\n currentdie = skill.data.data.die.sides;\n currentmod = skill.data.data.die.modifier;\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 var effectData = {\n label: `${direction} ${trait.name}${raise ? \" with raise\" : \"\"}`,\n id: `${direction}${trait.name}${raise ? \"raise\" : \"\"}`,\n icon: direction == \"Lower\" ? DOWNICON : UPICON,\n changes: [{ \n \"key\": trait[\"diekey\"],\n \"mode\": 2,\n \"value\": diemod,\n \"priority\": 0\n },{\n \"key\": trait[\"modkey\"],\n \"mode\": 2,\n \"value\": modmod,\n \"priority\": 0\n }]\n };\n if (direction == \"Boost\") {\n effectData[\"duration\"] = {rounds: 5}\n }\n let spellEffect = game.macros.getName(\"ApplySpellEffect\");\n spellEffect.execute(effectData, [tokenD])\n }\n}","folder":null,"sort":0,"permission":{"default":0,"ygiRButlaf23fX9p":3},"flags":{"combat-utility-belt":{"macroTrigger":""},"core":{"sourceId":"Macro.dVj0CSN1HF9MwQ6w"},"scene-packer":{"hash":"4e53849e1ce9e5050e333da5e4a1a34156d2766f","sourceId":"Macro.ZdhNwBdfrTf9xgCM"},"cf":{"id":"temp_p20tzfcm449","path":"Spell Effect Macros","color":"#000000"}},"_id":"fzkUWlTKCJ68nEzL"}
+{"_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"}}}
{"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"}}}
-{"_id":"tjaqN9gedJpYFgbu","name":"Smite","type":"script","author":"ygiRButlaf23fX9p","img":"systems/swade/assets/icons/status/status_smite.svg","scope":"global","command":"const targets = canvas.tokens.controlled;\nconst extra = { flavor: \"The weapon seems more powerful\" }\nconst spellEffect = game.macros.getName(\"ApplySpellEffect\");\nconst label = \"Smite\";\nconst id = \"smite\";\nconst icon = \"systems/swade/assets/icons/status/status_smite.svg\";\nconst duration = 5;\n\nmain();\n\nasync function main() {\n let effect = {\n changes: [\n ],\n duration: { rounds: duration },\n icon: icon,\n label: label,\n id: id\n }\n\n let applyChanges = false;\n let d = new Dialog({\n title: `Applying ${label} effects`,\n content: `Apply ${label} with raise?`,\n buttons: {\n raise: {\n icon: '
',\n label: 'With raise',\n callback: () => {\n applyChanges = true;\n effect.label = effect.label + \" with raise\";\n }\n },\n noraise: {\n icon: '
',\n label: 'Normal Success',\n callback: () => { applyChanges = true }\n }\n },\n default: \"noraise\",\n close: html => {\n if (applyChanges) {\n spellEffect.execute(effect, targets, extra);\n }\n }\n });\n d.render(true);\n}","folder":null,"sort":0,"permission":{"default":0,"ygiRButlaf23fX9p":3},"flags":{"advanced-macros":{"runAsGM":false},"combat-utility-belt":{"macroTrigger":""},"core":{"sourceId":"Macro.ZNzOrPKDCN9Lq00t"},"scene-packer":{"sourceId":"Macro.ZNzOrPKDCN9Lq00t"},"cf":{"id":"temp_p20tzfcm449","path":"Spell Effect Macros","color":"#000000"}}}
+{"_id":"p94dkSmOgfuoC28K","name":"Deflection","type":"script","author":"HXnQ3GTDyHZ7E1ev","img":"icons/magic/defensive/shield-barrier-deflect-teal.webp","scope":"global","command":"const ICON = 'icons/magic/defensive/shield-barrier-deflect-teal.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 tokenList = tokens.map(t => t.name).join(\", \");\n let dialogOptions = {\n title: \"Deflection\",\n content: `Apply
Deflection to ${tokenList}`,\n default: \"cancel\",\n buttons: [\n {label: \"Apply (melee)\", value: \"melee\"},\n {label: \"Apply (ranged)\", value: \"ranged\"},\n {label: \"Apply with raise (both)\", value: \"raise\"},\n {label: \"Cancel\", value: \"cancel\"}\n ]\n }\n let choice = await warpgate.buttonDialog(dialogOptions);\n if (choice != \"cancel\") {\n createEffect(tokens, choice);\n }\n}\n\nasync function createEffect(tokens, choice) {\n let effectName = 'Deflection';\n let effectId = `deflection${choice}`;\n let changes = []\n switch (choice) {\n case 'melee':\n effectName = \"Melee \" + effectName;\n break\n case 'ranged':\n effectName = \"Ranged \" + effectName;\n break \n }\n const effectIcon = ICON;\n for (const token of tokens) {\n let effectData = {\n icon: effectIcon,\n id: effectId,\n label: effectName,\n duration: {rounds: 5},\n flags: {\n swade: {\n expiration: 3,\n loseTurnOnHold: true\n }\n },\n changes: [\n {key: 'data.stats.parry.modifier', mode: foundry.CONST.ACTIVE_EFFECT_MODES.UPGRADE, value: 0, priority: 0}\n ],\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: true,\n description: effectName,\n }\n await warpgate.mutate(token.document, mutate, {}, mutateOptions);\n }\n}","folder":null,"sort":0,"permission":{"default":0,"HXnQ3GTDyHZ7E1ev":3},"flags":{"scene-packer":{"hash":"9fef11ff303f385dcc039b421c26212cdee832c2","sourceId":"Macro.p94dkSmOgfuoC28K"},"cf":{"id":"temp_g9ptj9b0b4s","path":"SWADE Spell Effects (WarpGate)","color":"#000000"}}}
+{"_id":"tjaqN9gedJpYFgbu","name":"Smite","type":"script","author":"HXnQ3GTDyHZ7E1ev","img":"icons/weapons/swords/sword-flanged-lightning.webp","scope":"global","command":"const ICON = 'icons/weapons/swords/sword-flanged-lightning.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 tokenList = tokens.map(t => t.name).join(\", \");\n let menuOptions = {\n title: 'Smite',\n defaultButton: \"cancel\",\n options: {}\n }\n let menuData = {\n inputs: [\n {type: 'header', label: 'Smite'},\n {type: 'info', label: `Apply Smite to ${tokenList}`},\n ],\n buttons: [\n {label: \"Apply\", value: \"apply\"},\n {label: \"Apply with Raise\", value: \"raise\"},\n {label: \"Cancel\", value: \"cancel\"}\n ]\n }\n let tokenWeapons = {};\n let index = 1;\n for (const token of tokens) {\n index += 2;\n tokenWeapons[token.id] = index;\n menuData.inputs.push({type: 'info', label: `
${token.name}
`});\n let weapons = token.actor.items.filter(i => i.type == 'weapon').map(i => i.name);\n weapons.unshift(\"\");\n menuData.inputs.push({type: 'select', label: token.name, options: weapons});\n }\n let {buttons, inputs} = await warpgate.menu(menuData, menuOptions);\n for (tokenid in tokenWeapons) {\n tokenWeapons[tokenid] = inputs[tokenWeapons[tokenid]];\n }\n if (buttons != \"cancel\") {\n await createEffect(tokens, tokenWeapons, buttons);\n }\n console.log(buttons, tokenWeapons);\n}\n\nasync function createEffect(tokens, tokenWeapons, choice) {\n const effectIcon = ICON;\n const changeValue = (choice == 'raise' ? \"+4\" : \"+2\");\n for (const token of tokens) {\n const weaponName = tokenWeapons[token.id];\n const weaponId = token.actor.items.getName(weaponName)?.id\n const changeKey = `@Weapon{${weaponName}}[data.damage]`\n if (!weaponId) {\n continue\n }\n const effectName = `Smite (${weaponName})`;\n const effectId = `smite${choice}_${weaponId}`;\n let effectData = {\n icon: effectIcon,\n id: effectId,\n label: effectName,\n duration: {rounds: 5},\n flags: {\n swade: {\n expiration: 3,\n loseTurnOnHold: true\n }\n },\n changes: [\n {\n key: changeKey,\n mode: foundry.CONST.ACTIVE_EFFECT_MODES.ADD,\n value: changeValue,\n priority: 0\n }\n ],\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: true,\n description: effectName,\n }\n await warpgate.mutate(token.document, mutate, {}, mutateOptions);\n }\n}","folder":null,"sort":0,"permission":{"default":0,"ygiRButlaf23fX9p":3},"flags":{"advanced-macros":{"runAsGM":false},"combat-utility-belt":{"macroTrigger":""},"core":{"sourceId":"Macro.MXSe0F5osRtleDV4"},"scene-packer":{"sourceId":"Macro.MXSe0F5osRtleDV4","hash":"a74182d3f48775895d7f8e9b4b0af22194eaa82c"},"cf":{"id":"temp_g9ptj9b0b4s","path":"SWADE Spell Effects (WarpGate)","color":"#000000"}}}
+{"_id":"wa7ZoYUhNcjrNEmN","name":"#[CF_tempEntity]","type":"chat","author":"HXnQ3GTDyHZ7E1ev","img":"icons/svg/dice-target.svg","scope":"global","command":"","folder":null,"sort":0,"permission":{"default":0,"HXnQ3GTDyHZ7E1ev":3},"flags":{"cf":{"id":"temp_g9ptj9b0b4s","path":"SWADE Spell Effects (WarpGate)","color":"#000000","name":"SWADE Spell Effects (WarpGate)","children":["fzkUWlTKCJ68nEzL","p94dkSmOgfuoC28K","tjaqN9gedJpYFgbu"],"folderPath":[]},"scene-packer":{"hash":"3d9a8396d815dcef72c41f01fa0318a9a20c0bb4"}}}
{"_id":"yV3XNCfgHpGrREt0","name":"Sanctuary","type":"script","author":"ygiRButlaf23fX9p","img":"icons/svg/holy-shield.svg","scope":"global","command":"let effect = {\n changes: [\n ],\n duration: {rounds: 5},\n icon: 'icons/svg/holy-shield.svg',\n label: 'Sanctuary',\n id: 'sanctuary'\n}\nconst targets = canvas.tokens.controlled;\nconst extra = { flavor: \"Sanctuary!\" }\nconst spellEffect = game.macros.getName(\"ApplySpellEffect\");\nlet value = await spellEffect.execute(effect, targets, extra);\nreturn value;","folder":null,"sort":0,"permission":{"default":0,"ygiRButlaf23fX9p":3},"flags":{"advanced-macros":{"runAsGM":false},"combat-utility-belt":{"macroTrigger":""},"core":{"sourceId":"Macro.01dTmSPBq0xJQJcm"},"scene-packer":{"sourceId":"Macro.01dTmSPBq0xJQJcm"},"cf":{"id":"temp_p20tzfcm449","path":"Spell Effect Macros","color":"#000000"}}}