Roll20 uses cookies to improve your experience on our site. Cookies enable you to enjoy certain features, social sharing functionality, and tailor message and display ads to your interests on our site and others. They also help us understand how our site is being used. By continuing to use our site, you consent to our use of cookies. Update your cookie preferences .
×
Create a free account

What am I doing wrong? !delay script is not working to delay !cfx

I have both the !delay and !cfx scripts,but when I use:

!delay 3 --!cfx glow-blood @{selected|character_id} @{selected|token_id}

the fx does not happen. But, when using:

!cfx glow-blood @{selected|character_id} @{selected|token_id} the fx does happen...

January 24 (3 years ago)
The Aaron
Roll20 Production Team
API Scripter

I'd have to look at the CFX script, but probably it does something like checks if a player is a gm, which would fail if it gets called from a script. 


The Aaron said:

I'd have to look at the CFX script, but probably it does something like checks if a player is a gm, which would fail if it gets called from a script. 


Here is the script I have installed:

on('ready',()=>{

  const isBuiltinFx = (name) => /(beam|bomb|breath|bubbling|burn|burst|explode|glow|missile|nova|splatter)-(acid|blood|charm|death|fire|frost|holy|magic|slime|smoke|water)/.test(name);

  const getPageForPlayer = (playerid) => {
    let player = getObj('player',playerid);
    if(playerIsGM(playerid)){
      return player.get('lastpage');
    }

    let psp = Campaign().get('playerspecificpages');
    if(psp[playerid]){
      return psp[playerid];
    }

    return Campaign().get('playerpageid');
  };


  on('chat:message',(msg)=>{
    if('api' !== msg.type ) {
      return;
    }

    let args = msg.content.split(/\s+/);

    switch(args.shift().toLowerCase()){
      case '!cfx': {
        if (args.length < 3){
          sendChat("CFX", `/w "${who}" Use <code>!cfx [effect] [source id] [destination id ...]</code><br><code>id</code>s can be token or character ids.  You can specify as many destination ids as you like to target multiple tokens or creatures.`);
          return;
        }

        let who = (getObj('player',msg.playerid)||{get:()=>'API'}).get('_displayname');
        let srcToken = getObj('graphic',args[1]);
        let pageid = getPageForPlayer(msg.playerid);
        if(!srcToken) {
          let character = getObj('character',args[1]);
          if(character){
            let ts = findObjs({
              type: 'graphic',
              represents: character.id,
              pageid: pageid
            });
            if(ts.length){
              srcToken = ts[0];
            }
          }
        }

        let destTokens = args.slice(2)
          .map((id)=>getObj('graphic',id) || findObjs({type:'graphic', represents:id, pageid}))
          .reduce((m,o)=>[...m,...(Array.isArray(o) ? o : [o])],[])
          ;

        if(!srcToken){
          sendChat("CFX", `/w "${who}" No matching tokens source character or token ID on your current page.`);
          return;
        }
        if(0 === destTokens.length){
          sendChat("CFX", `/w "${who}" No destination tokens found for supplied IDs.`);
          return;
        }
        let srcPt = {
          x: srcToken.get('left'),
          y: srcToken.get('top')
        };

        let targeted = false;
        let effect = args[0];
        if(!isBuiltinFx(effect)){
          let custfx = findObjs({type: 'custfx', name: effect}, {caseInsensitive: true})[0];
          if(!custfx){
            sendChat("CFX", `/w "${who}" Not a built in or custom effect: <code>${effect}</code>`);
            return;
          }
          targeted = (-1 === parseInt((custfx.get('definition')||{}).angle));
          effect = custfx.id;
        } else {
          targeted = /^(beam|breath|splatter)-/.test(effect);
        }

        let spawner = targeted
          ? (s,d,e,p) => spawnFxBetweenPoints(s,d,e,p)
          : (s,d,e,p) => spawnFx(d.x,d.y,e,p)
          ;


        destTokens.forEach((t)=>{
          let destPt = {
            x: t.get('left'),
            y: t.get('top')
          };
          spawner(srcPt,destPt,effect,t.get('pageid'));
        });
      }
      break;
    }
  });
  log("-=> CFX command loaded (!cfx) <=-");
});

January 24 (3 years ago)
timmaugh
Forum Champion
API Scripter

Yep... I *think* I see what is going on and it is a problem with message coming from an API, like Aaron said. Since the delay script is issuing your command, your message is coming from the API. Because of that, when CFX calls getPageForPlayer (line 5), the pageid that is returned isn't player-specific, but the Campaign default.

Later, it looks for a token (which you haven't fed; you've fed a character id). That means it gets into the alternate check for a character ID, and it tries to find a token that represents that character on the given pageid... which may result in no token found since you're not guaranteed that the Campaign's default page will be correct.

If I'm right, you can fix this by installing SelectManager and configuring it to give the playerid back to API-generated messages.

!smconfig +playerid



timmaugh said:

Yep... I *think* I see what is going on and it is a problem with message coming from an API, like Aaron said. Since the delay script is issuing your command, your message is coming from the API. Because of that, when CFX calls getPageForPlayer (line 5), the pageid that is returned isn't player-specific, but the Campaign default.

Later, it looks for a token (which you haven't fed; you've fed a character id). That means it gets into the alternate check for a character ID, and it tries to find a token that represents that character on the given pageid... which may result in no token found since you're not guaranteed that the Campaign's default page will be correct.

If I'm right, you can fix this by installing SelectManager and configuring it to give the playerid back to API-generated messages.

!smconfig +playerid



To make sure I understand...
In layman's terms: The !delay script is deselecting my selected token and the !cfx is looking for the selected token that is no longer selected?

January 24 (3 years ago)
The Aaron
Roll20 Production Team
API Scripter

The deselecting isn't an issue as the values are passed in to the command.  The issue is that since the player that is issuing the command is effectively the API, it doesn't know where to show the effects if you aren't on the ribbon page.


The Aaron said:

The deselecting isn't an issue as the values are passed in to the command.  The issue is that since the player that is issuing the command is effectively the API, it doesn't know where to show the effects if you aren't on the ribbon page.


Now that makes sense: If I have the Player ribbon on the page I'm working, it will play the effect. I just tested that and it worked. 

THANK YOU!

January 24 (3 years ago)
The Aaron
Roll20 Production Team
API Scripter

It also will not be able to report errors because the user it will whisper to will be the API user, effectively...

January 24 (3 years ago)
The Aaron
Roll20 Production Team
API Scripter

Cool, all the thanks go to Tim for figuring that out!  =D


timmaugh said:

Yep... I *think* I see what is going on and it is a problem with message coming from an API, like Aaron said. Since the delay script is issuing your command, your message is coming from the API. Because of that, when CFX calls getPageForPlayer (line 5), the pageid that is returned isn't player-specific, but the Campaign default.

Later, it looks for a token (which you haven't fed; you've fed a character id). That means it gets into the alternate check for a character ID, and it tries to find a token that represents that character on the given pageid... which may result in no token found since you're not guaranteed that the Campaign's default page will be correct.

If I'm right, you can fix this by installing SelectManager and configuring it to give the playerid back to API-generated messages.

!smconfig +playerid



Thank you Tim!

January 24 (3 years ago)
timmaugh
Forum Champion
API Scripter

W00t!

Yeah, I should have pointed out that if the ribbon page and your current page aligned, it would work, and that the SelectManager fix would work in the cases where the 2 were not aligned -- if that were important.

Either way, glad it's working!

Tim or Aaron,

Related but not specific to this topic:

Some of the wiki instructions for the meta toolbox are a bit over my head. I only know enough about this stuff to stumble through it aimlessly til I get it right. So, I hope it's OK for me to ask you this on this thread:

Correct me if I'm wrong: I think the meta tools will allow to do the following but I don't know which one or how:

Take a variable input (ie chat query/targeted token) that's used in one macro and carry it to another macro.


If not, is there a way to do that?


timmaugh said:

W00t!

Yeah, I should have pointed out that if the ribbon page and your current page aligned, it would work, and that the SelectManager fix would work in the cases where the 2 were not aligned -- if that were important.

Either way, glad it's working!




January 24 (3 years ago)
timmaugh
Forum Champion
API Scripter

Andrew E. said:

Correct me if I'm wrong: I think the meta tools will allow to... Take a variable input (ie chat query/targeted token) that's used in one macro and carry it to another macro.


Yes, you can do that with Muler.

!firstmacro ...other args... set.YourVariable = ?{What was the question?}/set{&mule MuleCharacter.MuleName}

...that would expect a Mule (an ability setup in rows of a=b) of the name "MuleName" on a character named "MuleCharacter", and it would store the result of the roll query in a variable called "YourVariable". Effectively, that Mule would have a new line (if the variable hadn't existed, before), that would read:

YourVariable=...whatever the result of the query was...

Later, you can recall that by loading the same Mule and using a "get" statement:

!secondmacro ...other args... get.MuleCharacter.MuleName.YourVariable/get {&mule MuleCharacter.MuleName}

This can be helpful to keep some piece of data around between macro commands, but it is also helpful to use the same result of a query/roll to give you multiple different outputs (by using the thing you store as the variable, elsewhere). For instance, designating a condition on a character like "exhausted" can, in some places mean a modifier to a roll. In another place it could be text you need to append to an output.

If you have a more specific question, start a new thread and we'll tackle what you're trying to do, there. =D


timmaugh said:

Andrew E. said:

Correct me if I'm wrong: I think the meta tools will allow to... Take a variable input (ie chat query/targeted token) that's used in one macro and carry it to another macro.


Yes, you can do that with Muler.

!firstmacro ...other args... set.YourVariable = ?{What was the question?}/set{&mule MuleCharacter.MuleName}

...that would expect a Mule (an ability setup in rows of a=b) of the name "MuleName" on a character named "MuleCharacter", and it would store the result of the roll query in a variable called "YourVariable". Effectively, that Mule would have a new line (if the variable hadn't existed, before), that would read:

YourVariable=...whatever the result of the query was...

Later, you can recall that by loading the same Mule and using a "get" statement:

!secondmacro ...other args... get.MuleCharacter.MuleName.YourVariable/get {&mule MuleCharacter.MuleName}

This can be helpful to keep some piece of data around between macro commands, but it is also helpful to use the same result of a query/roll to give you multiple different outputs (by using the thing you store as the variable, elsewhere). For instance, designating a condition on a character like "exhausted" can, in some places mean a modifier to a roll. In another place it could be text you need to append to an output.

If you have a more specific question, start a new thread and we'll tackle what you're trying to do, there. =D


Thank you!