diff --git a/images/fly/2biyKFk.png b/images/fly/2biyKFk.png new file mode 100644 index 0000000..3d431fa Binary files /dev/null and b/images/fly/2biyKFk.png differ diff --git a/images/fly/3PCV7YP.png b/images/fly/3PCV7YP.png new file mode 100644 index 0000000..c97eca5 Binary files /dev/null and b/images/fly/3PCV7YP.png differ diff --git a/images/fly/9iqdmjZ.png b/images/fly/9iqdmjZ.png new file mode 100644 index 0000000..389e778 Binary files /dev/null and b/images/fly/9iqdmjZ.png differ diff --git a/images/fly/A5DAUp3.png b/images/fly/A5DAUp3.png new file mode 100644 index 0000000..7f911c9 Binary files /dev/null and b/images/fly/A5DAUp3.png differ diff --git a/images/fly/Sac1174.png b/images/fly/Sac1174.png new file mode 100644 index 0000000..039e05d Binary files /dev/null and b/images/fly/Sac1174.png differ diff --git a/images/fly/VotClWQ.png b/images/fly/VotClWQ.png new file mode 100644 index 0000000..dbc61e5 Binary files /dev/null and b/images/fly/VotClWQ.png differ diff --git a/images/fly/atlIrtl.png b/images/fly/atlIrtl.png new file mode 100644 index 0000000..e7c1254 Binary files /dev/null and b/images/fly/atlIrtl.png differ diff --git a/images/fly/cBF4IIR.png b/images/fly/cBF4IIR.png new file mode 100644 index 0000000..8f27d0e Binary files /dev/null and b/images/fly/cBF4IIR.png differ diff --git a/images/fly/fgzxRd0.png b/images/fly/fgzxRd0.png new file mode 100644 index 0000000..1c64078 Binary files /dev/null and b/images/fly/fgzxRd0.png differ diff --git a/images/fly/g2GK7NW.png b/images/fly/g2GK7NW.png new file mode 100644 index 0000000..dfcf129 Binary files /dev/null and b/images/fly/g2GK7NW.png differ diff --git a/images/fly/hfzupc7.png b/images/fly/hfzupc7.png new file mode 100644 index 0000000..bc236f2 Binary files /dev/null and b/images/fly/hfzupc7.png differ diff --git a/images/fly/q82GHFf.png b/images/fly/q82GHFf.png new file mode 100644 index 0000000..43bacbc Binary files /dev/null and b/images/fly/q82GHFf.png differ diff --git a/images/fly/rO2JCPz.png b/images/fly/rO2JCPz.png new file mode 100644 index 0000000..dea4e06 Binary files /dev/null and b/images/fly/rO2JCPz.png differ diff --git a/images/fly/sR4Ur8h.png b/images/fly/sR4Ur8h.png new file mode 100644 index 0000000..7f7b6d6 Binary files /dev/null and b/images/fly/sR4Ur8h.png differ diff --git a/images/fly/uN33sO6.png b/images/fly/uN33sO6.png new file mode 100644 index 0000000..42f0bf4 Binary files /dev/null and b/images/fly/uN33sO6.png differ diff --git a/images/fly/xAmFxhW.png b/images/fly/xAmFxhW.png new file mode 100644 index 0000000..a9b814b Binary files /dev/null and b/images/fly/xAmFxhW.png differ diff --git a/lang/en.json b/lang/en.json index c766bb2..ba74b4f 100644 --- a/lang/en.json +++ b/lang/en.json @@ -47,7 +47,9 @@ "SAT.Weapons.Derringer": "Derringer", "SAT.Weapons.Carabine": "Carabine", "SAT.Weapons.ProtonStream": "Proton Stream", - + "SAT.Weapons.Dynamite": "Dynamite", + "SAT.Weapons.Club": "Club", + "SAT.Effect.ArcaneProtectionNormal": "Arcane Protection (Normal)", "SAT.Effect.ArcaneProtectionRaise": "Arcane Protection (Raise)", "SAT.Effect.ProtectionNormal": "Protection (Normal)", diff --git a/scripts/ManagerAnimation.js b/scripts/ManagerAnimation.js index 622331e..db78803 100644 --- a/scripts/ManagerAnimation.js +++ b/scripts/ManagerAnimation.js @@ -53,7 +53,7 @@ export async function playMeAnAnimation(SwadeItem,source,rolls) { } if(itemData.isValid && itemData.animation.length > 0) { - if(itemData.animationType == ANIMATIONTYPE.RANGED || itemData.animationType == ANIMATIONTYPE.MELEE) { + if(itemData.animation[0].type == ANIMATIONTYPE.RANGED || itemData.animation[0].type == ANIMATIONTYPE.MELEE) { debug("Ranged or Melee animated"); let notWait = false; if(rolls.targets.length > 0) { @@ -66,7 +66,7 @@ export async function playMeAnAnimation(SwadeItem,source,rolls) { await playRangedOrMeele(source,rolls.targets[i].token,itemData.animation[0],itemData.sound[0],rolls.targets[i].result,animationName,notWait); } - } else if(itemData.animationType == ANIMATIONTYPE.TARGET) { + } else if(itemData.animation[0].type == ANIMATIONTYPE.TARGET) { let notWait = false; if(rolls.targets.length > 1) { notWait = true; @@ -75,7 +75,7 @@ export async function playMeAnAnimation(SwadeItem,source,rolls) { debug("playMeAnAnimation onToken",itemData); await playOnToken(rolls.targets[i].token,itemData.animation[0],itemData.sound[0],animationName,notWait); } - } else if(itemData.animationType == ANIMATIONTYPE.TEMPLATE) { + } else if(itemData.animation[0].type == ANIMATIONTYPE.TEMPLATE) { debug("TEMPLATE: ",getNTemplate()); if(getNTemplate()==0) { for(let i = 0; i < rolls.targets.length; i++) { @@ -88,7 +88,7 @@ export async function playMeAnAnimation(SwadeItem,source,rolls) { } setNTemplate(0); - } else if(itemData.animationType == ANIMATIONTYPE.SPECIAL) { + } else if(itemData.animation[0].type == ANIMATIONTYPE.SPECIAL) { let notWait = false; if(SwadeItem.name.toLowerCase().includes("fly")) { for(let i = 0; i < rolls.targets.length; i++) { @@ -106,7 +106,7 @@ export async function playMeAnAnimation(SwadeItem,source,rolls) { await shape_change(rolls.targets[i].token,itemData.animation[0],itemData.sound[0],animationName,notWait); } } - } else if(itemData.animationType == ANIMATIONTYPE.STREAM) { + } else if(itemData.animation[0].type == ANIMATIONTYPE.STREAM) { debug("PLAY STREAM") for(let i = 0; i < rolls.targets.length; i++) { debug("playMeAnAnimation Shape Change",itemData); @@ -121,7 +121,7 @@ export async function playMeAnAnimation(SwadeItem,source,rolls) { applyEffect(itemData,rolls.targets[j],SwadeItem,animationName,source); } if(itemData.animationEffect.length > 0) { - if(itemData.animationType == ANIMATIONTYPE.TEMPLATE) { + if(itemData.animation[0].type == ANIMATIONTYPE.TEMPLATE) { setNTemplate(0); } } @@ -205,7 +205,7 @@ export async function applyEffect(item,target,SwadeItem,animationName,source) { if(item.animation.length == 0) { EFFECTSOUND = item.sound[0]; } - if(item.animationType == ANIMATIONTYPE.SPECIAL) { + if(item.animationEffect[0].type == ANIMATIONTYPE.SPECIAL) { if(TMFXEffectsList.includes(effectName) && item.animationEffect.length > 0) { applyEffectTMFX(target.token,item.animationEffect[0]); } else if(SwadeItem.name.toLowerCase().includes("fly")) { @@ -217,7 +217,7 @@ export async function applyEffect(item,target,SwadeItem,animationName,source) { debug("playMeAnAnimation Shape Change"); await shape_change(target.token,item.animationEffect[0],item.sound[0],animationName,true); } - } else if(item.animationType == ANIMATIONTYPE.TEMPLATE) { + } else if(item.animationEffect[0].type == ANIMATIONTYPE.TEMPLATE) { debug("TEMPLATES: ",getNTemplate()); if(getNTemplate()==0) { debug("playMeAnAnimation onToken",item); @@ -226,9 +226,9 @@ export async function applyEffect(item,target,SwadeItem,animationName,source) { debug("playMeAnAnimation onTemplate",item); playOnTemplate(item.animationEffect[0],EFFECTSOUND, ROLLRESULT.HIT, animationName,target.token); } - } else if(item.animationType == ANIMATIONTYPE.RANGED) { + } else if(item.animationEffect[0].type == ANIMATIONTYPE.RANGED) { playRangedOrMeele(source,target.token,item.animationEffect[0],EFFECTSOUND,ROLLRESULT.HIT,animationName,true) - } else if(item.animationType == ANIMATIONTYPE.STREAM) { + } else if(item.animationEffect[0].type == ANIMATIONTYPE.STREAM) { await playStream(target.token, source, item.animationEffect[0],item.sound[0],animationName); } else { if(item.animationEffect[0].attachTo) { diff --git a/scripts/animations.js b/scripts/animations.js index c02fcf7..ce38750 100644 --- a/scripts/animations.js +++ b/scripts/animations.js @@ -4,6 +4,12 @@ import { ROLLRESULT } from './constants.js'; +//Select Wing Speed: Default = 0, Max = 2499 +let wingSpeed = 0; +let wingHeight = 0; +//Define Wing Image +let wingDefinition = []; + export async function playOnToken(token, animation, sound,animationName, notWait=false) { animationName = animationName +","+animation.label+","+token.id; debug("playOnToken: ",animation,sound); @@ -223,62 +229,231 @@ export async function burrowOn(token,animation,sound,animationName) { .play(); } +//Fly Animation +//Author: EskieMoh#2969 +//Tweaked by: BashfulBob#8687 +//Select Wing Type: Celestial, Infernal, Avian, Dragon + export async function stopFly(token) { - //await Sequencer.EffectManager.endEffects({ name: "Fly", object: token }); - await new Sequence() - .animation() - .on(token) - .opacity(1) - .play(); + endFlying(token) } -export function fly(token,animation,sound,animationName,notWait) { + +let wingType = ""; + +export function fly(token,animation,sound,animationName,notWait) { animationName = animationName +","+animation.label+","+token.id; + wingHeight = 0.9-(token.document.width*0.05); debug("fly: ",token,animation,sound,animationName); - new Sequence() - .sound() - .file(sound.file) - .delay(sound.delay) - .volume(sound.volume) - .duration(sound.duration) - .fadeOutAudio(500) - .effect() - .file(animation.file) - .size(animation.size, { gridUnits: true }) - .atLocation(token) - //.scaleToObject(1.75) - .belowTokens() - //.waitUntilFinished() - .animation() - .on(token) - .opacity(0) + assignWingType(animation.label) + var wingSequence = new Sequence(); + wingDefinition.forEach(wingType => { AddWing(wingSequence, wingType[0], wingType[1], wingType[2], wingType[3], wingType[4], token,animationName); }); // img, wingId, side + AddFloating(wingSequence, token, animation, sound, animationName); + wingSequence.play(); +} +function assignWingType(wingType) { + wingDefinition = []; + + switch(wingType) { + + case "Celestial": + wingSpeed = 0; + wingDefinition.push([`2biyKFk.png`,1,'left',-10,1]); + wingDefinition.push([`2biyKFk.png`,1,'right',-10,1]); + wingDefinition.push([`uN33sO6.png`,2,'left',-10,1]); + wingDefinition.push([`uN33sO6.png`,2,'right',-10,1]); + break; + case "Infernal": + wingSpeed = 250; + wingDefinition.push([`rO2JCPz.png`,1,'left',-10,1]); + wingDefinition.push([`rO2JCPz.png`,1,'right',-10,1]); + wingDefinition.push([`cBF4IIR.png`,2,'left',-10,1]); + wingDefinition.push([`cBF4IIR.png`,2,'right',-10,1]); + break; + case "Avian": + wingSpeed = 0; + wingDefinition.push([`sR4Ur8h.png`,1,'left',-10,1]); + wingDefinition.push([`sR4Ur8h.png`,1,'right',-10,1]); + wingDefinition.push([`9iqdmjZ.png`,2,'left',-10,1]); + wingDefinition.push([`9iqdmjZ.png`,2,'right',-10,1]); + break; + case "Red Dragon": + wingSpeed = 0; + wingDefinition.push([`xAmFxhW.png`,1,'left',-10, 1.5]); + wingDefinition.push([`xAmFxhW.png`,1,'right',-10, 1.5]); + wingDefinition.push([`3PCV7YP.png`,2,'left',-10, 1.5]); + wingDefinition.push([`3PCV7YP.png`,2,'right',-10, 1.5]); + break; + case "Blue Dragon": + wingSpeed = 1000; + wingDefinition.push([`A5DAUp3.png`,1,'left',-10, 1.5]); + wingDefinition.push([`A5DAUp3.png`,1,'right',-10, 1.5]); + wingDefinition.push([`atlIrtl.png`,2,'left',-10, 1.5]); + wingDefinition.push([`atlIrtl.png`,2,'right',-10, 1.5]); + break; + case "Green Dragon": + wingSpeed = 0; + wingDefinition.push([`q82GHFf.png`,1,'left',-10, 1.5]); + wingDefinition.push([`q82GHFf.png`,1,'right',-10, 1.5]); + wingDefinition.push([`g2GK7NW.png`,2,'left',-10, 1.5]); + wingDefinition.push([`g2GK7NW.png`,2,'right',-10, 1.5]); + break; + case "White Dragon": + wingSpeed = 0; + wingDefinition.push([`Sac1174.png`,1,'left',-10, 1.5]); + wingDefinition.push([`Sac1174.png`,1,'right',-10, 1.5]); + wingDefinition.push([`hfzupc7.png`,2,'left',-10, 1.5]); + wingDefinition.push([`hfzupc7.png`,2,'right',-10, 1.5]); + break; + case "Black Dragon": + wingSpeed = 0; + wingDefinition.push([`VotClWQ.png`,1,'left',-10, 1.5]); + wingDefinition.push([`VotClWQ.png`,1,'right',-10, 1.5]); + wingDefinition.push([`fgzxRd0.png`,2,'left',-10, 1.5]); + wingDefinition.push([`fgzxRd0.png`,2,'right',-10, 1.5]); + break; - .effect() - .from(token) - .name( String(getHashName(animationName)) ) - .atLocation(token) - .opacity(1) - .duration(800) - .anchor({ x: 0.55, y: 0.9 }) - .animateProperty("sprite", "position.y", { from: 50, to: 0, duration: 500}) - .loopProperty("sprite", "position.y", { from:0 ,to:-50, duration: 2500, pingPong: true, delay:500}) - .attachTo(token, {bindAlpha: false}) - .zIndex(2) - .persist() - .effect() - .from(token, { offset: { y: 0 } }) - .name(String(getHashName(animationName))) - .atLocation(token) - .scaleToObject(0.9) - .duration(1000) - .opacity(0.5) - .belowTokens() - .filter("ColorMatrix", { brightness: -1 }) - .filter("Blur", { blurX: 5, blurY: 10 }) - .attachTo(token, {bindAlpha: false}) - .zIndex(1) - .persist() - .play(); + default: // No Wings + break; + } +} + +function AddFloating(Sequence, token, animation, sound, animationName) { + + Sequence + .effect() + .file(animation.file) + .atLocation(token) + .scaleToObject(1.75) + .belowTokens() + + .animation() + .on(token) + .opacity(0) + .rotate(0); + + // Shadow + Sequence + .effect() + .from(token) + .name(String(getHashName(animationName))) + .atLocation(token) + .scaleToObject(token.document.texture.scaleX-0.1) + .duration(1000) + .opacity(0.5) + .belowTokens() + .filter("ColorMatrix", { brightness: -1 }) + .filter("Blur", { blurX: 5, blurY: 10 }) + .attachTo(token, {bindAlpha: false}) + .zIndex(1) + .persist() + .private() + + // Float + Sequence + .effect() + .from(token) + .name(String(getHashName(animationName))) + .atLocation(token) + .opacity(1) + .duration(800) + .anchor({ x: 0.55, y: 0.9 }) + .loopProperty("sprite", "position.y", { from:0 ,to:-0.25, duration: 2500-wingSpeed, pingPong: true, delay:500-wingSpeed, ease: "easeInOutCubic", gridUnits:true}) + .attachTo(token, {bindAlpha: false, followRotation: false}) + .zIndex(10) + .persist() + .waitUntilFinished() + //.thenDo(endFlying); +} + +async function endFlying(token) { + new Sequence() + + .animation() + .on(token) + .opacity(1) + + .effect() + .file("jb2a.extras.tmfx.border.circle.outpulse.01.fast") + .atLocation(token) + .scaleToObject(2) + .opacity(0.15) + + + .play(); +} + +function AddWing(Sequence, fileWingImg, wingId, sideId, rotationVal, wingSize, token,animationName) { + // wingId = 1 -> Inner wing pivot, ie shoulder + // wingId = 2 -> Outer wing pivot, ie pinfeathers + // wingId = 3 -> Lower wing pivot, ie tail + // sideId = 'left', 'right' + + let wingImg = 'modules/swade-animated/images/fly/' + fileWingImg; + let anchorScaleX = (sideId == 'left') ? token.document.texture.scaleX-0.15 : -token.document.texture.scaleX+1.25; + let tokenAlignment = (sideId == 'left') ? "top-left" : "top-right"; + let mirrorVal = (sideId == 'left') ? 1 : -1; + + let durationVal = (wingId==2) ? 10 : 10000; + let rotationAdj = (wingId==2) ? 3 : 1; + // from: (42 + rotationAdj)*mirrorVal, + // to: ((-15 * rotationAdj)*mirrorVal), + + let rotateFrom = rotationVal*rotationAdj*-1*mirrorVal; + let rotateTo = rotationVal*rotationAdj*mirrorVal; + let wingHeightAdj = (wingId==3) ? -1*wingHeight : wingHeight; + let size = wingSize*(token.document.texture.scaleX*0.8) + + var SeqEffect = Sequence + .effect() + .name(String(getHashName(animationName))) + .file(wingImg) + .persist() + .atLocation(token) + .scaleToObject(size) + .duration(durationVal) + .anchor({ x: anchorScaleX, y: wingHeightAdj-((wingSize-1)/2)}) + .rotate(rotationVal*mirrorVal) + .attachTo(token, {align: tokenAlignment, bindAlpha: false, bindVisibility: false, followRotation: false}); + + if(sideId == 'right') { SeqEffect.mirrorX(); } + + if(wingId==2) { + SeqEffect + .loopProperty("sprite", "position.x", { + from: -0.0, + to: 0.17*(token.w / canvas.grid.size)*mirrorVal, + duration: 2500-wingSpeed, + ease: "easeInOutCubic", + pingPong: true, + gridUnits:true}) + } + + SeqEffect + //Flying Movement + .loopProperty("sprite", "position.y", { + from:0 , + to:-0.25, + duration: 2500-wingSpeed, + pingPong: true, + delay:500-wingSpeed, + gridUnits: true}) + //Wing Flap + .loopProperty("sprite", "rotation", { + from: (42 + rotationAdj)*mirrorVal, + to: ((-15 * rotationAdj)*mirrorVal), + duration: 2500-wingSpeed, + ease: "easeInOutCubic", + pingPong: true}) + .loopProperty("sprite", "position.y", { + from: 0, + to: 0.25, + duration: 2500-wingSpeed, + ease: "easeInOutCubic", + pingPong: true, + gridUnits:true}) + .zIndex(8+rotationAdj) + .private(); } export function playOnTemplate(animation,sound, _missed, animationName="nonPersistent", token) { diff --git a/scripts/init.js b/scripts/init.js index 38aa372..32f96ee 100644 --- a/scripts/init.js +++ b/scripts/init.js @@ -60,7 +60,8 @@ Hooks.once('ready', () => { */ Hooks.on('swadeAction', (swadeActor, swadeItem, actionType, roll, id) => { - debug("Hooks on swadeAction"); + if(actionType != 'formula') return; + debug("Hooks on swadeAction",actionType); debug(swadeItem); const token = swadeActor.parent?.token || canvas.tokens.placeables.find(token => token.actor?.items?.get(swadeItem.id)) let targets =Array.from(game.user.targets); @@ -123,6 +124,7 @@ async function disableEffect(effect,token_item) { } } if(effect.label.toLowerCase().includes("fly")) { + await Sequencer.EffectManager.endEffects({ name: String(effect.flags.swadeanimated.animation)}); stopFly(token_item); } else if(effect.label.toLowerCase().includes("burrow")) { burrowOff(token_item); diff --git a/scripts/items.js b/scripts/items.js index 63db40e..7f357d1 100644 --- a/scripts/items.js +++ b/scripts/items.js @@ -45,6 +45,13 @@ export function iniIt() { initConsumables(); } +const escapeRegExpMatch = function(s) { + return s.replace(/[-\/\\^$*+?.()|[\]{}]/g, '\\$&'); +}; +const isExactMatch = function(str, match) { + return new RegExp(`\\b${escapeRegExpMatch(match)}\\b`).test(str) +} + export function getItem(item) { debug("GETITEM"); debug(item); @@ -66,29 +73,45 @@ export function getItem(item) { } } } else if(item.type == "weapon") { - console.log("WEAPON"); - for(let i=0;i 0) { + for(let i=0;i word.toLowerCase()); - if(lowercaseWords.includes(item.name.trim().toLocaleLowerCase())) { - debug("Alternative Weapon",WeaponList[i]); - itemData = WeaponList[i]; - } - } - if(Object.keys(itemData).length) { + if(new RegExp("(\\s|\\(|,)\\b"+WeaponList[i].name.trim().toLowerCase()+"\\b(\\s|\\)|,)").test(" "+item.name.trim().toLowerCase()+" ")) { + debug("Weapon",WeaponList[i]); + itemData = WeaponList[i]; break; } - } + } + + if(Object.keys(itemData).length === 0) { + debug("SEARCH BY ALTERNATIVES") + for(let i=0;i