Stendarpaval / mob-attack-tool

A module for Foundry VTT that offers a tool for handling mob attacks in the dnd5e system.
GNU General Public License v3.0
7 stars 14 forks source link

On Use Macro (like MidiQOL) #26

Closed asimone closed 3 years ago

asimone commented 3 years ago

This is obviously not even remotely "core" or an MVP feature, but on use macros like MIDQOL doeswould open up the doors for some interesting use cases.

Imagine a group of archers firing at an actor each using the JB2A arrow animation (you can see it here) to get that "volley of arrows" effect.

This really is a fantastic module. I don't expect to see my enhancement soon (or even ever), but figured I'd mention it.

Stendarpaval commented 3 years ago

This sounded like a really interesting feature to add, so I experimented with it and after poring over Midi-QOL's codebase was able to make most of it work. You can update to v0.2.18 to give it a try. The only limitation seems to be that On Use macros that use MidiQOL.DamageOnlyWorkflow might overwrite the damage rolls that Mob Attack Tool creates if you have "merge rolls to one card" enabled in Midi's settings. I've added a setting to Mob Attack Tool to help prevent that from happening, though.

At any rate, thanks for suggesting to add this feature! I wouldn't have thought of doing so without this issue you made, and that would've been unfortunate because it seems like a really useful feature. This is exactly why I always ask people to create issues for feature requests, so don't hesitate to make another. (Of course, I can't guarantee that I'll work on it as quickly as I did this time.)

Before I forget, could you download the new release and tell me if you run into any bugs? Just to make sure I didn't miss anything :)

asimone commented 3 years ago

Ooh, I'll definitely play with this today and let you know if I discover any bugs or weird edge cases.

I think the next step in developing the feature would be to directly hook into Automated Animations which does a lot of the "on use macro" like elements for you (I don't know if Otigon uses On Macro directly, tbh) and will even automate the use of animation based on item names on a character sheet in many instances.

Also, I totally understand if you can't get to any new features very quickly if I suggest more. I'm a product/project manager for a software company so I definitely know how this works. 😅

asimone commented 3 years ago

Okay, so this is a cool feature. Minor bug or, at least, a behavior that isn't ideal.

See video for above description https://user-images.githubusercontent.com/575279/122679728-9ab67f00-d1b1-11eb-90e6-fc122f8cb6ef.mp4

Ideal behavior: different tokens fire the animations on multiple hits on the same target

Stendarpaval commented 3 years ago

In the macro you used, can you check if it includes the following line?

let myToken = canvas.tokens.controlled [0];

If it does, could you replace it with the following line and try it again? Please let me know if that fixes it for you.

let myToken = canvas.tokens.get(args[0].tokenId);

This is exactly what I did in the example in the release notes, so that should work. Here's a video of it:

https://user-images.githubusercontent.com/17188192/122794940-15b88c00-d2bd-11eb-946d-8f010af6607c.mov

Changing the macro in this way shouldn't affect how it works outside of Mob Attack Tool, by the way, if you use Midi-QOL. Having said that, I think I need to improve the algorithm that determines how often macros are executed. It is currently mostly focused on making sure JB2A animations would originate from random tokens, but other macros may have different needs. So expect some improvements on that front in a later release. (Don't have time this week to code, though :( )

Edit: I somehow overlooked your second to last message. Thanks for the tip, I'll take a look how Automated Animations triggers such animations.

asimone commented 3 years ago

Apologies for the delay, my week went sideways at work and was focused on other stuff. The Macro I was using in full at the bottom, it's an compendium macro JB2A provides. It looks like it is using:

let myToken = canvas.tokens.controlled [0];

That fix didn't work, but the macros appear to be broken now, even the original isn't working, and I can't tell if it's an update I did or something else, so I'll need to investigate more. I'll update this ticket as I figure out the problem

/// This macro pulls from the JB2A list of Magic Missiles to throw 1 random path at targeted tokens

//folder01 targets the Magic Missile Folder
let folder01 = "modules/jb2a_patreon/Library/1st_Level/Magic_Missile/";
//Each file is then defined as a variable that will be stored in an array and then chose at random
let mmA = `${folder01}MagicMissile_01_Regular_Purple_30ft_01_1600x400.webm`;
let mmB = `${folder01}MagicMissile_01_Regular_Purple_30ft_02_1600x400.webm`;
let mmC = `${folder01}MagicMissile_01_Regular_Purple_30ft_03_1600x400.webm`;
let mmD = `${folder01}MagicMissile_01_Regular_Purple_30ft_04_1600x400.webm`;
let mmE = `${folder01}MagicMissile_01_Regular_Purple_30ft_05_1600x400.webm`;
let mmF = `${folder01}MagicMissile_01_Regular_Purple_30ft_06_1600x400.webm`;
let mmG = `${folder01}MagicMissile_01_Regular_Purple_30ft_07_1600x400.webm`;
let mmH = `${folder01}MagicMissile_01_Regular_Purple_30ft_08_1600x400.webm`;
let mmI = `${folder01}MagicMissile_01_Regular_Purple_30ft_09_1600x400.webm`;

let mmAA = `${folder01}MagicMissile_01_Regular_Purple_60ft_01_2800x400.webm`;
let mmBB = `${folder01}MagicMissile_01_Regular_Purple_60ft_02_2800x400.webm`;
let mmCC = `${folder01}MagicMissile_01_Regular_Purple_60ft_03_2800x400.webm`;
let mmDD = `${folder01}MagicMissile_01_Regular_Purple_60ft_04_2800x400.webm`;
let mmEE = `${folder01}MagicMissile_01_Regular_Purple_60ft_05_2800x400.webm`;
let mmFF = `${folder01}MagicMissile_01_Regular_Purple_60ft_06_2800x400.webm`;
let mmGG = `${folder01}MagicMissile_01_Regular_Purple_60ft_07_2800x400.webm`;
let mmHH = `${folder01}MagicMissile_01_Regular_Purple_60ft_08_2800x400.webm`;
let mmII = `${folder01}MagicMissile_01_Regular_Purple_60ft_09_2800x400.webm`;

///Check if Module dependencies are installed or returns an error to the user
if (!canvas.fxmaster) ui.notifications.error("This macro depends on the FXMaster module. Make sure it is installed and enabled");
if(game.user.targets.size == 0) ui.notifications.error('You must target at least one token');
if(canvas.tokens.controlled.length == 0) ui.notifications.error("Please select your token");

function random_itemA(itemsA)
{
return itemsA[Math.floor(Math.random()*itemsA.length)];
}

var itemsA = [mmA, mmB, mmC, mmD, mmE, mmF, mmG, mmH, mmI];

function random_itemB(itemsB)
{
return itemsB[Math.floor(Math.random()*itemsB.length)];
}

var itemsB = [mmAA, mmBB, mmCC, mmDD, mmEE, mmFF, mmGG, mmHH, mmII];
const wait = (delay) => new Promise((resolve) => setTimeout(resolve, delay))

async function Cast() {
var myStringArray = Array.from(game.user.targets)[0];
var arrayLength = game.user.targets.size;
for (var i = 0; i < arrayLength; i++) {

let mainTarget = Array.from(game.user.targets)[i];
let myToken = canvas.tokens.controlled [0];

let ray = new Ray(myToken.center, mainTarget.center);
let anDeg = -(ray.angle * 57.3);
let anDist = ray.distance;

let anFile = random_itemA(itemsA);
let anFileSize = 1200;
let anchorX = 0.125;
switch(true){
 case (anDist<1800):
    anFileSize = 1200;
    anFile = random_itemA(itemsA);
    anchorX = 0.125;
    break;
 default:
    anFileSize = 2400;
    anFile = random_itemB(itemsB);
    anchorX = 0.071;
    break;
}

let anScale = anDist / anFileSize;
let anScaleY = anScale;
if (anDist<=600){anScaleY = 0.5}
if (anDist>600 && anDist <1000){anScaleY = 0.66}
if (anDist>=1000 && anDist <1800){anScaleY = anScale}
if (anDist>=1800 && anDist <2400){anScaleY = 0.8}
if (anDist>=2400){anScaleY = anScale}

let spellAnim = 
                    {
                     file: anFile,
                      position: myToken.center,
                      anchor: {
                       x: anchorX,
                       y: 0.5
                      },
                      angle: anDeg,
                      scale: {
                       x: anScale,
                       y: anScaleY
                      }
                    }; 

canvas.fxmaster.playVideo(spellAnim);
await wait (80);

game.socket.emit('module.fxmaster', spellAnim);
await wait (50);
}
}
Cast()
Stendarpaval commented 3 years ago

Interestingly, the macro you shared doesn't work for me either. However, it seems to be identical to JB2A's macro that I used. I think something may have gone wrong while copying. I don't have much time today either, but I can share the macro that I positively know works. This already has the changed line to make it work with Mob Attack Tool. Let me know if it works for you! And good luck with that work issue, of course.

/// This macro pulls from the JB2A list of Magic Missiles to throw 1 random path at targeted tokens

//folder01 targets the Magic Missile Folder
let folder01 = "modules/JB2A_DnD5e/Library/1st_Level/Magic_Missile/";
//Each file is then defined as a variable that will be stored in an array and then chose at random
let mmA = `${folder01}MagicMissile_01_Regular_Purple_30ft_01_1600x400.webm`;
let mmB = `${folder01}MagicMissile_01_Regular_Purple_30ft_02_1600x400.webm`;
let mmC = `${folder01}MagicMissile_01_Regular_Purple_30ft_03_1600x400.webm`;
let mmD = `${folder01}MagicMissile_01_Regular_Purple_30ft_04_1600x400.webm`;
let mmE = `${folder01}MagicMissile_01_Regular_Purple_30ft_05_1600x400.webm`;
let mmF = `${folder01}MagicMissile_01_Regular_Purple_30ft_06_1600x400.webm`;
let mmG = `${folder01}MagicMissile_01_Regular_Purple_30ft_07_1600x400.webm`;
let mmH = `${folder01}MagicMissile_01_Regular_Purple_30ft_08_1600x400.webm`;
let mmI = `${folder01}MagicMissile_01_Regular_Purple_30ft_09_1600x400.webm`;

let mmAA = `${folder01}MagicMissile_01_Regular_Purple_60ft_01_2800x400.webm`;
let mmBB = `${folder01}MagicMissile_01_Regular_Purple_60ft_02_2800x400.webm`;
let mmCC = `${folder01}MagicMissile_01_Regular_Purple_60ft_03_2800x400.webm`;
let mmDD = `${folder01}MagicMissile_01_Regular_Purple_60ft_04_2800x400.webm`;
let mmEE = `${folder01}MagicMissile_01_Regular_Purple_60ft_05_2800x400.webm`;
let mmFF = `${folder01}MagicMissile_01_Regular_Purple_60ft_06_2800x400.webm`;
let mmGG = `${folder01}MagicMissile_01_Regular_Purple_60ft_07_2800x400.webm`;
let mmHH = `${folder01}MagicMissile_01_Regular_Purple_60ft_08_2800x400.webm`;
let mmII = `${folder01}MagicMissile_01_Regular_Purple_60ft_09_2800x400.webm`;

///Check if Module dependencies are installed or returns an error to the user
if (!canvas.fxmaster) ui.notifications.error("This macro depends on the FXMaster module. Make sure it is installed and enabled");
if(game.user.targets.size == 0) ui.notifications.error('You must target at least one token');
if(canvas.tokens.controlled.length == 0) ui.notifications.error("Please select your token");

function random_itemA(itemsA)
{
return itemsA[Math.floor(Math.random()*itemsA.length)];
}

var itemsA = [mmA, mmB, mmC, mmD, mmE, mmF, mmG, mmH, mmI];

function random_itemB(itemsB)
{
return itemsB[Math.floor(Math.random()*itemsB.length)];
}

var itemsB = [mmAA, mmBB, mmCC, mmDD, mmEE, mmFF, mmGG, mmHH, mmII];
const wait = (delay) => new Promise((resolve) => setTimeout(resolve, delay))

async function Cast() {
var myStringArray = Array.from(game.user.targets)[0];
var arrayLength = game.user.targets.size;
for (var i = 0; i < arrayLength; i++) {

let mainTarget = Array.from(game.user.targets)[i];
let myToken = canvas.tokens.get(args[0].tokenId);

let ray = new Ray(myToken.center, mainTarget.center);
let anDeg = -(ray.angle * 57.3);
let anDist = ray.distance;

let anFile = random_itemA(itemsA);
let anFileSize = 1200;
let anchorX = 0.125;
switch(true){
 case (anDist<1800):
    anFileSize = 1200;
    anFile = random_itemA(itemsA);
    anchorX = 0.125;
    break;
 default:
    anFileSize = 2400;
    anFile = random_itemB(itemsB);
    anchorX = 0.071;
    break;
}

let anScale = anDist / anFileSize;
let anScaleY = anScale;
if (anDist<=600){anScaleY = 0.5}
if (anDist>600 && anDist <1000){anScaleY = 0.66}
if (anDist>=1000 && anDist <1800){anScaleY = anScale}
if (anDist>=1800 && anDist <2400){anScaleY = 0.8}
if (anDist>=2400){anScaleY = anScale}

let spellAnim = 
                    {
                     file: anFile,
                      position: myToken.center,
                      anchor: {
                       x: anchorX,
                       y: 0.5
                      },
                      angle: anDeg,
                      scale: {
                       x: anScale,
                       y: anScaleY
                      }
                    }; 

canvas.fxmaster.playVideo(spellAnim);
await wait (80);

game.socket.emit('module.fxmaster', spellAnim);
await wait (50);
}
}
Cast()
asimone commented 3 years ago

That macro works! But with one tweak...apparently, the newest build of FXMaster broke all the JBA2 macros. I had to dig through some discord channels to figure this out, but it should work with this hack which Otigon, the Automated Animations dev, suggested.

Replace:

canvas.fxmaster.playVideo(/stuff)

with

canvas.specials.playVideo(/stuff)

Gazkhan commented 3 years ago

Nice ! I'll hop into the conversation to say that Otigon's Automated Animations module Github describes how to call for animations like so : image Here is the link to the Github : https://github.com/otigon/automated-jb2a-animations And the link to our JB2A Discord where you can ping @Otigon for further details if needed : https://discord.gg/gmd8MAPX4m Thanks for doing this, it's awesome !

Stendarpaval commented 3 years ago

As of the freshly released version 0.2.19, Mob Attack Tool supports Automated Animations. It's really cool to trigger dozens of animations at once (if your computer can handle it 😅 )!

I've also fixed the number of times that On Use Macro's are called. It now matches the number of successful attacks. Could you please update to v0.2.19 and tell me if you run into any bugs related to this? That'd be great :)

asimone commented 3 years ago

I'll need to play around with it a bit more, but my initial quick testing suggests it's working as intended!

https://user-images.githubusercontent.com/575279/124028795-05d63180-d9ba-11eb-9558-3427d176bc55.mp4

asimone commented 3 years ago

Me, just pushing the limits a little bit.

https://user-images.githubusercontent.com/575279/124059054-143f4000-d9f0-11eb-9fa7-24a5ff6dc637.mp4

Stendarpaval commented 3 years ago

That looks great! My poor Macbook Air would be burning a hole in my lap if I tried that too often, haha. In any case, I think this issue is ready to be closed. If related bugs do pop up in the future, please reopen this issue again. Cheers!