From 0461836bfb3798cc1e66ae158c74af1cd2a644a1 Mon Sep 17 00:00:00 2001 From: Faizan Ahmad Date: Tue, 7 Dec 2021 15:39:48 -0500 Subject: [PATCH 1/2] Vicious Mockery --- languages/en.json | 1 + scripts/ASEHandler.js | 5 ++ scripts/apps/aseSettings.js | 11 +++++ scripts/spells/viciousMockery.js | 85 ++++++++++++++++++++++++++++++++ 4 files changed, 102 insertions(+) create mode 100644 scripts/spells/viciousMockery.js diff --git a/languages/en.json b/languages/en.json index fa51e2e..d280e26 100644 --- a/languages/en.json +++ b/languages/en.json @@ -21,6 +21,7 @@ "ASE.LightningBolt": "Lightning Bolt", "ASE.ChainLightning": "Chain Lightning", "ASE.MirrorImage": "Mirror Image", + "ASE.ViciousMockery": "Vicious Mockery", "ASE.SummonAberrantSpirit": "Summon Aberrant Spirit", "ASE.SummonBeast": "Summon Beast", diff --git a/scripts/ASEHandler.js b/scripts/ASEHandler.js index 6781bdd..eaa2088 100644 --- a/scripts/ASEHandler.js +++ b/scripts/ASEHandler.js @@ -18,6 +18,7 @@ import { eldritchBlast } from "./spells/eldritchBlast.js"; import { moonBeam } from "./spells/moonBeam.js"; import { chainLightning } from "./spells/chainLightning.js"; import { mirrorImage } from "./spells/mirrorImage.js"; +import { viciousMockery } from "./spells/viciousMockery.js"; export class ASEHandler { static async handleASE(data) { @@ -119,6 +120,10 @@ export class ASEHandler { const mirrorImageSpell = new mirrorImage(data); mirrorImageSpell.cast(); return; + case game.i18n.localize('ASE.ViciousMockery'): + const viciousMockerySpell = new viciousMockery(data); + viciousMockerySpell.cast(); + return; } if (item.name.includes(game.i18n.localize("ASE.Summon"))) { await summonCreature.doSummon(data); diff --git a/scripts/apps/aseSettings.js b/scripts/apps/aseSettings.js index 8f8bfec..ce6052e 100644 --- a/scripts/apps/aseSettings.js +++ b/scripts/apps/aseSettings.js @@ -17,6 +17,8 @@ import { vampiricTouch } from "../spells/vampiricTouch.js"; import { moonBeam } from "../spells/moonBeam.js"; import { chainLightning } from "../spells/chainLightning.js"; import { mirrorImage } from "../spells/mirrorImage.js"; +import { viciousMockery } from "../spells/viciousMockery.js"; + export class ASESettings extends FormApplication { constructor() { super(...arguments); @@ -44,6 +46,7 @@ export class ASESettings extends FormApplication { this.spellList[game.i18n.localize("ASE.ChainLightning")] = chainLightning; this.spellList[game.i18n.localize("ASE.MirrorImage")] = mirrorImage; this.spellList[game.i18n.localize("ASE.Summon")] = summonCreature; + this.spellList[game.i18n.localize("ASE.ViciousMockery")] = viciousMockery; } static get defaultOptions() { @@ -132,6 +135,14 @@ export class ASESettings extends FormApplication { data.save = { ability: "dex", dc: null, scaling: "spell" }; data.target = { value: 1, width: null, units: "", type: "creature" }; break; + case game.i18n.localize("ASE.ViciousMockery"): + data.level = 0; + data.actionType = "save"; + data.damage.parts.push(["1d4", "psychic"]); + data.save = { ability: "wis", dc: null, scaling: "spell" }; + data.target = { value: 1, width: null, units: "", type: "creature" }; + data.scaling = { mode: "cantrip", formula: "1d4" }; + break; } let updates = { data }; await item.update(updates); diff --git a/scripts/spells/viciousMockery.js b/scripts/spells/viciousMockery.js new file mode 100644 index 0000000..aaaac98 --- /dev/null +++ b/scripts/spells/viciousMockery.js @@ -0,0 +1,85 @@ +import { aseSocket } from "../aseSockets.js"; +import * as utilFunctions from "../utilityFunctions.js"; + +export class viciousMockery { + + constructor(data) { + this.params = data; + this.actor = game.actors.get(this.params.actor.id); + this.token = canvas.tokens.get(this.params.tokenId); + this.item = this.params.item; + this.effectOptions = this.item.getFlag("advancedspelleffects", "effectOptions"); + this.isMidiActive = utilFunctions.isMidiActive(); + this.target = Array.from(this.params.targets)[0]; + this.cussVault = ['!', '@', '#', '$', '%', '&']; + } + + static registerHooks() { + return; + } + + async cast() { + // console.log("Casting ASE Mirror Image..."); + //console.log(this); + await this.playSequence(); + + } + + async playSequence() { + const caster = this.token; + const target = this.target; + const textOptions = { + "dropShadowAngle": 7.6, + "fontFamily": "Impact", + "fontSize": 38, + "fontStyle": "oblique", + "fontVariant": "small-caps", + "fontWeight": "bolder", + "fill": [ + "#f01414", + "#931a1a" + ], + }; + const distance = utilFunctions.getDistanceClassic({ x: caster.x, y: caster.y }, { x: target.x, y: target.y }); + let viciousMockerySeq = new Sequence(); + + for (let i = 0; i < utilFunctions.getRandomInt(5, 8); i++) { + viciousMockerySeq.effect() + .rotateTowards(target) + .moveTowards(target, { ease: "easeInOutElastic" }) + .moveSpeed(distance / 2.5) + .atLocation(caster) + .text(this.makeCussWord(), textOptions) + .animateProperty("sprite", "rotation", { from: 0, to: 720, duration: 1200, ease: "easeInOutCubic" }) + .animateProperty("sprite", "scale.x", { from: 0, to: 1, duration: 1200, ease: "easeInOutCubic" }) + .animateProperty("sprite", "scale.y", { from: 0, to: 1, duration: 1200, ease: "easeInOutCubic" }) + .randomOffset() + .animateProperty("sprite", "scale.x", { from: 1, to: 0, delay: 1250, duration: 600, ease: "easeInOutCubic" }) + .animateProperty("sprite", "scale.y", { from: 1, to: 0, delay: 1250, duration: 600, ease: "easeInOutCubic" }) + .filter("Glow", { color: utilFunctions.rgbToHex(utilFunctions.getRandomInt(0, 155), utilFunctions.getRandomInt(0, 155), utilFunctions.getRandomInt(0, 155)), distance: 35, outerStrength: 2, innerStrength: 0.25 }) + .wait(utilFunctions.getRandomInt(50, 75)) + } + + viciousMockerySeq.play() + } + + makeCussWord() { + let cussWord = `${this.cussVault[utilFunctions.getRandomInt(0, this.cussVault.length - 1)]}${this.cussVault[utilFunctions.getRandomInt(0, this.cussVault.length - 1)]}${this.cussVault[utilFunctions.getRandomInt(0, this.cussVault.length - 1)]}${this.cussVault[utilFunctions.getRandomInt(0, this.cussVault.length - 1)]}`; + //console.log(cussWord); + return cussWord; + } + + static async getRequiredSettings(currFlags) { + if (!currFlags) currFlags = {}; + let spellOptions = []; + let animOptions = []; + let soundOptions = []; + + return { + spellOptions: spellOptions, + animOptions: animOptions, + soundOptions: soundOptions + } + + } +} From 5f4c8bcd7e15538a83956770785316ab5ee38683 Mon Sep 17 00:00:00 2001 From: Faizan Ahmad Date: Fri, 15 Apr 2022 00:21:45 -0400 Subject: [PATCH 2/2] Vicious Mockery --- languages/en.json | 29 +++- scripts/spells/viciousMockery.js | 191 ++++++++++++++++++++++-- scripts/templates/ase-settings-new.html | 15 +- scripts/utilityFunctions.js | 18 +++ 4 files changed, 237 insertions(+), 16 deletions(-) diff --git a/languages/en.json b/languages/en.json index 1cacafd..4821fa5 100644 --- a/languages/en.json +++ b/languages/en.json @@ -472,5 +472,32 @@ "ASE.ThunderShatterEffectSoundDelayLabel": "Thunder Shatter Effect Sound Delay: ", "ASE.ThunderShatterEffectSoundDelayTooltip": "Delay before playing the Thunder Shatter effect sound relative to the Thunder Shatter effect", "ASE.ThunderShatterEffectSoundVolumeLabel": "Thunder Shatter Effect Volume: ", - "ASE.ThunderShatterEffectSoundVolumeTooltip": "Volume of the Thunder Shatter effect sound" + "ASE.ThunderShatterEffectSoundVolumeTooltip": "Volume of the Thunder Shatter effect sound", + + "ASE.EffectSpeedLabel": "Effect Speed: ", + "ASE.EffectSpeedTooltip": "Relative speed of the words flying towards the target, 1 is default, 2 is twice as fast", + "ASE.EffectFontLabel": "Font Family: ", + "ASE.EffectFontTooltip": "Font used for the effect", + "ASE.FontSizeLabel": "Font Size: ", + "ASE.FontSizeTooltip": "Font size used for the effect", + "ASE.EffectFillColorALabel": "Fill Color A: ", + "ASE.EffectFillColorATooltip": "First fill color used for the effect", + "ASE.EffectFillColorBLabel": "Fill Color B: ", + "ASE.EffectFillColorBTooltip": "Second fill color used for the effect", + "ASE.RandomGlowLabel": "Random Glow: ", + "ASE.RandomGlowTooltip": "Randomly select a glow color for the effect", + "ASE.EffectGlowColorLabel": "Glow Color: ", + "ASE.EffectGlowColorTooltip": "Glow color used for the effect", + "ASE.EffectGlowDistanceLabel": "Glow Distance: ", + "ASE.EffectGlowDistanceTooltip": "Distance of the glow from the effect", + "ASE.EffectGlowOuterStrengthLabel": "Glow Outer Strength: ", + "ASE.EffectGlowOuterStrengthTooltip": "Strength of the outer glow", + "ASE.EffectGlowInnerStrengthLabel": "Glow Inner Strength: ", + "ASE.EffectGlowInnerStrengthTooltip": "Strength of the inner glow", + "ASE.ViscousMockerySoundLabel": "Effect Sound: ", + "ASE.ViscousMockerySoundTooltip": "Sound played when the effect is triggered", + "ASE.ViscousMockerySoundDelayLabel": "Effect Sound Delay: ", + "ASE.ViscousMockerySoundDelayTooltip": "Delay before playing the effect sound relative to the effect", + "ASE.ViscousMockerySoundVolumeLabel": "Effect Volume: ", + "ASE.ViscousMockerySoundVolumeTooltip": "Volume of the effect sound" } diff --git a/scripts/spells/viciousMockery.js b/scripts/spells/viciousMockery.js index aaaac98..cfa2e68 100644 --- a/scripts/spells/viciousMockery.js +++ b/scripts/spells/viciousMockery.js @@ -19,8 +19,6 @@ export class viciousMockery { } async cast() { - // console.log("Casting ASE Mirror Image..."); - //console.log(this); await this.playSequence(); } @@ -28,24 +26,41 @@ export class viciousMockery { async playSequence() { const caster = this.token; const target = this.target; + const useRandomGlow = this.effectOptions.randomGlow; + const glowColor = useRandomGlow ? utilFunctions.getRandomColor("0x") : utilFunctions.convertColorHexTo0x(this.effectOptions?.glowColor ?? "#f01414"); + const glowDistance = this.effectOptions?.glowDistance ?? 30; + const glowOuterStrength = this.effectOptions?.glowOuterStrength ?? 2; + const glowInnerStrength = this.effectOptions?.glowInnerStrength ?? 0.25; + const fontFamily = this.effectOptions?.font ?? "Impact"; + const fontSize = this.effectOptions?.size ?? 38; + const fontFillColorA = this.effectOptions?.fillColorA ?? "#f01414"; + const fontFillColorB = this.effectOptions?.fillColorB ?? "#931a1a"; + const soundFile = this.effectOptions?.sound ?? ""; + const soundDelay = this.effectOptions?.soundDelay ?? 0; + const soundVolume = this.effectOptions?.soundVolume ?? 0.5; const textOptions = { "dropShadowAngle": 7.6, - "fontFamily": "Impact", - "fontSize": 38, + "fontFamily": fontFamily, + "fontSize": fontSize, "fontStyle": "oblique", "fontVariant": "small-caps", "fontWeight": "bolder", "fill": [ - "#f01414", - "#931a1a" + fontFillColorA, + fontFillColorB ], }; const distance = utilFunctions.getDistanceClassic({ x: caster.x, y: caster.y }, { x: target.x, y: target.y }); let viciousMockerySeq = new Sequence(); + viciousMockerySeq + .sound() + .file(soundFile) + .delay(soundDelay) + .volume(soundVolume) + .playIf(soundFile && soundFile !== ""); for (let i = 0; i < utilFunctions.getRandomInt(5, 8); i++) { viciousMockerySeq.effect() - .rotateTowards(target) .moveTowards(target, { ease: "easeInOutElastic" }) .moveSpeed(distance / 2.5) .atLocation(caster) @@ -56,16 +71,18 @@ export class viciousMockery { .randomOffset() .animateProperty("sprite", "scale.x", { from: 1, to: 0, delay: 1250, duration: 600, ease: "easeInOutCubic" }) .animateProperty("sprite", "scale.y", { from: 1, to: 0, delay: 1250, duration: 600, ease: "easeInOutCubic" }) - .filter("Glow", { color: utilFunctions.rgbToHex(utilFunctions.getRandomInt(0, 155), utilFunctions.getRandomInt(0, 155), utilFunctions.getRandomInt(0, 155)), distance: 35, outerStrength: 2, innerStrength: 0.25 }) + .filter("Glow", { color: glowColor, distance: glowDistance, outerStrength: glowOuterStrength, innerStrength: glowInnerStrength }) .wait(utilFunctions.getRandomInt(50, 75)) } - - viciousMockerySeq.play() + viciousMockerySeq.play(); } makeCussWord() { - let cussWord = `${this.cussVault[utilFunctions.getRandomInt(0, this.cussVault.length - 1)]}${this.cussVault[utilFunctions.getRandomInt(0, this.cussVault.length - 1)]}${this.cussVault[utilFunctions.getRandomInt(0, this.cussVault.length - 1)]}${this.cussVault[utilFunctions.getRandomInt(0, this.cussVault.length - 1)]}`; - //console.log(cussWord); + let cussWordList = []; + for (let i = 0; i < utilFunctions.getRandomInt(4, 10); i++) { + cussWordList.push(this.cussVault[utilFunctions.getRandomInt(0, this.cussVault.length - 1)]); + } + let cussWord = cussWordList.join(""); return cussWord; } @@ -75,6 +92,156 @@ export class viciousMockery { let animOptions = []; let soundOptions = []; + const effectFontOptions = { + "serif": "Serif", + "Georgia serif": "Georgia", + "Palatino": "Palatino", + "Times New Roman": "Times New Roman", + "Times": "Times", + "sans-serif": "Sans-Serif", + "Arial": "Arial", + "Helvetica": "Helvetica", + "Arial Black": "Arial Black", + "Gadget": "Gadget", + "Comic Sans MS": "Comic Sans MS", + "cursive": "Cursive", + "Impact": "Impact", + "Charcoal": "Charcoal", + "Lucida Sans Unicode": "Lucida Sans Unicode", + "Lucida Grande": "Lucida Grande", + "Tahoma": "Tahoma", + "Geneva": "Geneva", + "Trebuchet MS": "Trebuchet MS", + "Verdana": "Verdana", + "Courier New, monospace": "Courier New", + "Courier": "Courier", + "Monaco": "Monaco", + "MS PGothic": "MS PGothic", + "Indie Flower": "Indie Flower", + }; + + /* animOptions.push({ + label: game.i18n.localize("ASE.EffectSpeedLabel"), + tooltip: game.i18n.localize("ASE.EffectSpeedTooltip"), + type: 'rangeInput', + name: 'flags.advancedspelleffects.effectOptions.speedModifier', + flagName: 'speedModifier', + flagValue: currFlags.speedModifier ?? 1, + min: 0.1, + max: 2, + step: 0.1, + });*/ + + animOptions.push({ + label: game.i18n.localize("ASE.EffectFontLabel"), + tooltip: game.i18n.localize("ASE.EffectFontTooltip"), + type: 'dropdown', + options: effectFontOptions, + name: 'flags.advancedspelleffects.effectOptions.font', + flagName: 'font', + flagValue: currFlags.font ?? 'Impact', + }); + + animOptions.push({ + label: game.i18n.localize("ASE.FontSizeLabel"), + tooltip: game.i18n.localize("ASE.FontSizeTooltip"), + type: 'numberInput', + name: 'flags.advancedspelleffects.effectOptions.size', + flagName: 'size', + flagValue: currFlags.size ?? 38, + }); + + animOptions.push({ + label: game.i18n.localize("ASE.EffectFillColorALabel"), + tooltip: game.i18n.localize("ASE.EffectFillColorATooltip"), + type: 'colorPicker', + name: 'flags.advancedspelleffects.effectOptions.fillColorA', + flagName: 'fillColorA', + flagValue: currFlags.fillColorA ?? '#f01414', + }); + + animOptions.push({ + label: game.i18n.localize("ASE.EffectFillColorBLabel"), + tooltip: game.i18n.localize("ASE.EffectFillColorBTooltip"), + type: 'colorPicker', + name: 'flags.advancedspelleffects.effectOptions.fillColorB', + flagName: 'fillColorB', + flagValue: currFlags.fillColorB ?? '#931a1a', + }); + + animOptions.push({ + label: game.i18n.localize("ASE.RandomGlowLabel"), + tooltip: game.i18n.localize("ASE.RandomGlowTooltip"), + type: 'checkbox', + name: 'flags.advancedspelleffects.effectOptions.randomGlow', + flagName: 'randomGlow', + flagValue: currFlags.randomGlow ?? true, + }); + + animOptions.push({ + label: game.i18n.localize("ASE.EffectGlowColorLabel"), + tooltip: game.i18n.localize("ASE.EffectGlowColorTooltip"), + type: 'colorPicker', + name: 'flags.advancedspelleffects.effectOptions.glowColor', + flagName: 'glowColor', + flagValue: currFlags.glowColor ?? '#f01414', + }); + + animOptions.push({ + label: game.i18n.localize("ASE.EffectGlowDistanceLabel"), + tooltip: game.i18n.localize("ASE.EffectGlowDistanceTooltip"), + type: 'numberInput', + name: 'flags.advancedspelleffects.effectOptions.glowDistance', + flagName: 'glowDistance', + flagValue: currFlags.glowDistance ?? 30, + }); + + animOptions.push({ + label: game.i18n.localize("ASE.EffectGlowOuterStrengthLabel"), + tooltip: game.i18n.localize("ASE.EffectGlowOuterStrengthTooltip"), + type: 'numberInput', + name: 'flags.advancedspelleffects.effectOptions.glowOuterStrength', + flagName: 'glowOuterStrength', + flagValue: currFlags.glowOuterStrength ?? 2, + }); + + animOptions.push({ + label: game.i18n.localize("ASE.EffectGlowInnerStrengthLabel"), + tooltip: game.i18n.localize("ASE.EffectGlowInnerStrengthTooltip"), + type: 'numberInput', + name: 'flags.advancedspelleffects.effectOptions.glowInnerStrength', + flagName: 'glowInnerStrength', + flagValue: currFlags.glowInnerStrength ?? 0.25, + }); + + soundOptions.push({ + label: game.i18n.localize("ASE.ViscousMockerySoundLabel"), + tooltip: game.i18n.localize("ASE.ViscousMockerySoundTooltip"), + type: 'fileInput', + name: 'flags.advancedspelleffects.effectOptions.sound', + flagName: 'sound', + flagValue: currFlags.sound ?? '', + }); + soundOptions.push({ + label: game.i18n.localize("ASE.ViscousMockerySoundDelayLabel"), + tooltip: game.i18n.localize("ASE.ViscousMockerySoundDelayTooltip"), + type: 'numberInput', + name: 'flags.advancedspelleffects.effectOptions.soundDelay', + flagName: 'soundDelay', + flagValue: currFlags.soundDelay ?? 0, + }); + soundOptions.push({ + label: game.i18n.localize("ASE.ViscousMockerySoundVolumeLabel"), + tooltip: game.i18n.localize("ASE.ViscousMockerySoundVolumeTooltip"), + type: 'rangeInput', + name: 'flags.advancedspelleffects.effectOptions.soundVolume', + flagName: 'soundVolume', + flagValue: currFlags.soundVolume ?? 0.5, + min: 0, + max: 1, + step: 0.01, + }); + return { spellOptions: spellOptions, animOptions: animOptions, diff --git a/scripts/templates/ase-settings-new.html b/scripts/templates/ase-settings-new.html index 02b9017..76b5b54 100644 --- a/scripts/templates/ase-settings-new.html +++ b/scripts/templates/ase-settings-new.html @@ -136,7 +136,10 @@ {{/ifCondASE}} {{#ifCondASE this.type '==' 'rangeInput'}} + step="{{this.step}}" + oninput="this.nextElementSibling.value = this.value" + name="{{this.name}}" value={{this.flagValue}}> + {{this.flagValue}} {{/ifCondASE}} {{#ifCondASE this.type '==' 'textInput'}} @@ -220,7 +223,10 @@ {{/ifCondASE}} {{#ifCondASE this.type '==' 'rangeInput'}} + step="{{this.step}}" + oninput="this.nextElementSibling.value = this.value" + name="{{this.name}}" value={{this.flagValue}}> + {{this.flagValue}} {{/ifCondASE}} {{#ifCondASE this.type '==' 'colorPicker'}} @@ -263,7 +269,10 @@ {{#ifCondASE this.type '==' 'rangeInput'}} + step="{{this.step}}" + oninput="this.nextElementSibling.value = this.value" + name="{{this.name}}" value={{this.flagValue}}> + {{this.flagValue}} {{/ifCondASE}} {{#ifCondASE this.type '==' 'checkbox'}} diff --git a/scripts/utilityFunctions.js b/scripts/utilityFunctions.js index 9f30b16..7463055 100644 --- a/scripts/utilityFunctions.js +++ b/scripts/utilityFunctions.js @@ -99,6 +99,24 @@ export function rgbToHex(r, g, b) { return "0x" + componentToHex(r) + componentToHex(g) + componentToHex(b); } +export function getRandomColor(type) { + let color = rgbToHex(getRandomInt(0, 155), getRandomInt(0, 155), getRandomInt(0, 155)); + if (type == "0x") { + return color; + } else if (type == "#") { + return "#" + color.substring(2); + } + return color; +} + +export function convertColorHexTo0x(color) { + return "0x" + color.substring(1); +} + +export function convertColor0xToHex(color) { + return "#" + color.substring(2); +} + export function capitalizeFirstLetter(string) { return string.charAt(0).toUpperCase() + string.slice(1); }