KayelGee / token-attacher

MIT License
11 stars 18 forks source link

Request: More information about programatically linking Templates to tokens. #26

Closed Waldleufer closed 3 years ago

Waldleufer commented 3 years ago

I am trying to set up a ItemMacro that should be called via DAE Macro Execute.

I create a MeasuredTamplate (range). To this point everything works fine, but then when trying to attach the template to the token I don't have a clue what I am doing wrong:

//DAE Macro Execute, Effect Value = "Macro Name" @target 
const lastArg = args[args.length - 1];
let tactor;
if (lastArg.tokenId) tactor = canvas.tokens.get(lastArg.tokenId).actor;
else tactor = game.actors.get(lastArg.actorId);
const target = canvas.tokens.get(lastArg.tokenId) || token;

//Debug Info ;)
//ChatMessage.create({ content: `${args[0]} ${args[1]} ${args[2]} ${args[3]}  ${args.length}` })

if (args[0] === "on") {
    (async () => {
        let range = MeasuredTemplate.create({
            t: "circle",
            user: game.user._id,
            x: target.x + canvas.grid.size / 2,
            y: target.y + canvas.grid.size / 2,
            direction: 0,
            distance: 30,
            borderColor: "#44975C",
            fillColor: "#44975C",
            flags: {
                DAESRD: {
                    PassWithoutTrace: {
                        ActorId: tactor.id
                    }
                }
            }
        });

        console.log(token);

        // tokenAttacher.attachElementToToken(range, target_token, let suppresNotification=false);
        tokenAttacher.attachElementToToken(range, target, false);
    })();

}

if (args[0] === "off") {
    (async () => {
        let removeTemplates = canvas.templates.placeables.filter(i => i.data.flags.DAESRD?.PassWithoutTrace?.ActorId === tactor.id);
        await target.update({ x: template.x, y: template.y })
        await canvas.templates.deleteMany([removeTemplates[0].id]);
        await tactor.deleteEmbeddedEntity("ActiveEffect", lastArg.effectId); 
    })();

}

Maybe you could provide a minimal example how to add a Template to a token. That would be highly appreciated!

Cheers, Waldleufer

KayelGee commented 3 years ago

What you're doing looks right except you're not awaiting the creation of the template let range = await MeasuredTemplate.create({

Waldleufer commented 3 years ago

First of all: Thank you for the help! 🙇

I added the missing await and now the MeasuredTemplate gets created properly, and I can also programmatically delete it.

I now also get the notification "Selected Objects attached to Tokens"

however this happens, image when I move the Token afterwards.

When creating a template with the Foundry UI the template neatly follows the target, so I assume I did forget some step in the creation of the MeasuredTemplate.

This is how the Macro looks like after said change.

//DAE Macro Execute, Effect Value = "Macro Name" @target 
const lastArg = args[args.length - 1];
let tactor;
if (lastArg.tokenId) tactor = canvas.tokens.get(lastArg.tokenId).actor;
else tactor = game.actors.get(lastArg.actorId);
const target = canvas.tokens.get(lastArg.tokenId) || token;

//Debug Info ;)
//ChatMessage.create({ content: `${args[0]} ${args[1]} ${args[2]} ${args[3]}  ${args.length}` })

if (args[0] === "on") {
    (async () => {
        let range = await MeasuredTemplate.create({
            t: "circle",
            user: game.user._id,
            x: target.x + canvas.grid.size / 2,
            y: target.y + canvas.grid.size / 2,
            direction: 0,
            distance: 30,
            borderColor: "#44975C",
            fillColor: "#44975C",
            flags: {
                DAESRD: {
                    PassWithoutTrace: {
                        ActorId: tactor.id
                    }
                }
            }
        });

        console.log(token);
        console.log(range);

        // tokenAttacher.attachElementToToken(range, target_token, let suppresNotification=false);
        tokenAttacher.attachElementToToken(range, token, false);
    })();
}

if (args[0] === "off") {
    (async () => {
        let removeTemplates = canvas.templates.placeables.filter(i => i.data.flags.DAESRD?.PassWithoutTrace?.ActorId === tactor.id);
        await canvas.templates.deleteMany([removeTemplates[0].id]);
        await tactor.deleteEmbeddedEntity("ActiveEffect", lastArg.effectId); 
    })();
}

let template = canvas.templates.get(args[0].templateId);
let effects = args[0].item.effects;
let templateEffectData = [];
for( let effect of effects){
   let data = { data: duplicate(effect), parentActorId: false, parentActorLink: false, entityType: "template", entityId:template.id, }
   templateEffectData.push(data)
}
await template.setFlag("ActiveAuras", "IsAura", templateEffectData);
ActiveAuras.CollateAuras(canvas.scene._id, true, false, "spellCast");
return  {haltEffectsApplication: true}

Cheers, Waldleufer

Waldleufer commented 3 years ago

@KayelGee sorry for the ping, but you closed this issue already so it might slip your attention 😄 sorry for the late reply 😉

KayelGee commented 3 years ago

Don't worry I still get a notification on closed issues, I'm just not looking at my emails that often ^^'. I usually suggest to ping me in discord if you need my attention. Why did you swap range and token in tokenAttacher.attachElementToToken(token, range, false);? This way you're trying to attach the token the the template, which isn't possible.

Waldleufer commented 3 years ago

Oh 🤔 well it wasn’t working beforehand, so I tried it the other way as well but I will look into that again and drop further information here.

Waldleufer commented 3 years ago

So I updated the comment up there, turns out, that the part of the code works flawlessly:

//DAE Macro Execute, Effect Value = "Macro Name" @target 
const lastArg = args[args.length - 1];
let tactor;
if (lastArg.tokenId) tactor = canvas.tokens.get(lastArg.tokenId).actor;
else tactor = game.actors.get(lastArg.actorId);
const target = canvas.tokens.get(lastArg.tokenId) || token;

//Debug Info ;)
//ChatMessage.create({ content: `${args[0]} ${args[1]} ${args[2]} ${args[3]}  ${args.length}` })

if (args[0] === "on") {
    (async () => {
        let range = await MeasuredTemplate.create({
            t: "circle",
            user: game.user._id,
            x: target.x + canvas.grid.size / 2,
            y: target.y + canvas.grid.size / 2,
            direction: 0,
            distance: 30,
            borderColor: "#44975C",
            fillColor: "#44975C",
            flags: {
                DAESRD: {
                    PassWithoutTrace: {
                        ActorId: tactor.id
                    }
                }
            }
        });

        console.log(token);
        console.log(range);

        // tokenAttacher.attachElementToToken(range, target_token, let suppresNotification=false);
        tokenAttacher.attachElementToToken(range, token, false);
    })();
}

if (args[0] === "off") {
    (async () => {
        let removeTemplates = canvas.templates.placeables.filter(i => i.data.flags.DAESRD?.PassWithoutTrace?.ActorId === tactor.id);
        await canvas.templates.deleteMany([removeTemplates[0].id]);
        await tactor.deleteEmbeddedEntity("ActiveEffect", lastArg.effectId); 
    })();
}

So the problem lies in the code that I appended below to apply a active effect to the template I just created ;)

Waldleufer commented 3 years ago

I figured it out.

Feel free to include this working version of the Macro somewhere in your Module if you want to.

// DAE Macro Execute: Attribute Key - Change Mode - Effect Value
//                  macro.itemMacro -   Custom    - @item @target
// Requires MidiQOL, DAE, Item Macros, ActiveEffects and TokenAttacher
// Created by Waldleufer 

const lastArg = args[args.length - 1];
let tactor;
if (lastArg.tokenId) tactor = canvas.tokens.get(lastArg.tokenId).actor;
else tactor = game.actors.get(lastArg.actorId);
const target = canvas.tokens.get(lastArg.tokenId) || token;
let item = args[3];
console.log(item);

//Debug Info ;)
//ChatMessage.create({ content: `${args[0]} ${args[1]} ${args[2]} ${args[3]}  ${args.length}` })

if (args[0] === "on") {
    (async () => {
        let range = await MeasuredTemplate.create({
            t: "circle",
            user: game.user._id,
            x: target.x + canvas.grid.size / 2,
            y: target.y + canvas.grid.size / 2,
            direction: 0,
            distance: 30,
            borderColor: "#44975C",
            fillColor: "#44975C",
            flags: {
                DAESRD: {
                    PassWithoutTrace: {
                        ActorId: tactor.id
                    }
                }
            }
        });

        // console.log(token);
        // console.log(range);

        // tokenAttacher.attachElementToToken(range, target_token, let suppresNotification=false);
        tokenAttacher.attachElementToToken(range, token, false);

        let templates = await canvas.templates.placeables.filter(i => i.data.flags.DAESRD?.PassWithoutTrace?.ActorId === tactor.id);
        let template = templates[0]; //We can safeley assume that this is the first and only template in the Array.
        let effects = item.efData.changes[0].value[0].effects;
        let disposition = token.disposition
        let templateEffectData = [];
        for( let effect of effects){
            // console.log(effect);
            if(effect.changes[0].key === "macro.itemMacro") {
                // Avoide inifinity loop, only aply actual effects, no macro.itemMacro effect.
            } else {
                let data = { data: duplicate(effect), parentActorId: false, parentActorLink: false, entityType: "template", entityId:template.id, casterDisposition: disposition,castLevel: 1} //args[0].spellLevel}
                templateEffectData.push(data)
            }
        }
        console.log(template);
        await template.setFlag("ActiveAuras", "IsAura", templateEffectData);
        console.log(template);
        ActiveAuras.CollateAuras(canvas.scene._id, true, false, "spellCast")
        return  {haltEffectsApplication: true}
    })();
}

if (args[0] === "off") {
    (async () => {
        let removeTemplates = canvas.templates.placeables.filter(i => i.data.flags.DAESRD?.PassWithoutTrace?.ActorId === tactor.id);
        await canvas.templates.deleteMany([removeTemplates[0].id]);
        await tactor.deleteEmbeddedEntity("ActiveEffect", lastArg.effectId); 
    })();
}
Waldleufer commented 3 years ago

It creates a template and applies any DAE that are on the item (except the one that is calling the Macro) to the template. And due to your awesome Template Attaching this works out as an improved "aura" effect 😄

Thank you for your help with that again!

Cheers, Waldleufer

KayelGee commented 3 years ago

No problem. I'm not sure I should include your macro as it has a few dependencies and is also system specific because of midi qol as I understand. But I can point to this issue in the readme.

Waldleufer commented 3 years ago

Sounds good to me 😊