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

Is there a game state or heartbeat object that is accessible through the API?

Just as the title says, is there a game state or heartbeat object that is accessible through the API? I'm wondering if it's possible by using setTimeout or setInterval to delay any input during the Timeout/Interval to be delayed. That's why I'm asking if there is a game state object or heartbeat object of some sort - so that I can use it as the callback function in setTimeout or setInterva
1529757909
The Aaron
Pro
API Scripter
Those functions work fine in the API. What problem are you trying to solve?
I'm trying to write a script so say I have the following macro: !delay 5 /desc Bob waves to you. So running !delay will prevent any further commands to be executed until the duration of the delay is over.
1529759995
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
You can't (Aaron may correct me on this) stop the API from accepting and reacting to commands, let alone the chat itself. You can delay the execution of a command by a specific script.
1529760443
The Aaron
Pro
API Scripter
Yeah.  What you could do would be something like: !delay 5 -- /desc Bob waves to you. The API is event based and Asynchronous.  It responds to events as they occur.  If one event (the !delay in your example) gets suspended (say by a setTimeout() call), it will move on to processing other events as they occur.  If you want to delay an event, you must deal with the event and reschedule it somehow (by setTimeout() or setInterval(), etc)
1529766013

Edited 1529766192
Victor B.
Pro
Sheet Author
API Scripter
Something like this: timer = setInterval(function(){ log("New Volume:" + level) level = level + levelChange*1; if (+level <= +target){     jbTrack.set({volume:level}); }else{     log('Clearing Timeout')     clearTimeout(timer)     outputConfig('playlists',who); } }, 1500 ); The above will delay execution for 1 1/2 seconds and CONTINUE to repeat the same function until the timer is cleared out.  You put your command under the setInterval and then immediately clear out the timer.   
Thanks Victor and The Aaron. I figured as much but it doesn't hurt to ask. The Aaron said: !delay 5 -- /desc Bob waves to you. This will basically solve what I want to accomplish. I just want to delay chat commands for NPC macros.
1529780518
The Aaron
Pro
API Scripter
You'll likely need to deal with some aspects of the message ahead of time, like subbing in for inline rolls and such.
This is what I got working for delaying commands for my NPC macros: function delayFunction(msg) {     return function() {         sendChat('', msg.trim());     } }      on("chat:message", function(msg) {     var cmdName = "!delay";     var msgTxt = msg.content;     if(msg.type == "api" && msgTxt.indexOf(cmdName) !== -1) {         var command = msg.content.split('--')[1];         var seconds = msg.content.split(' ')[1];              if (!isNaN(seconds))            var delay_length = seconds * 1000;         else            return;                  setTimeout(delayFunction(command), delay_length);     }; }); on('ready',function(){     log("-=> Delay command loaded (!delay) <=-"); }); Seems to do the trick. Though since I'm not specifying a character or NPC here: sendChat('', msg.trim()); It makes it limited to /desc, calling macros and such and cannot be used with /em or just regular chat unless I add in functionality to specify a user for the sendChat function.
1529781813
The Aaron
Pro
API Scripter
Not bad. Might work with /emas though I don’t remember if the API can issue those. 
The Aaron said: Not bad. Might work with /emas though I don’t remember if the API can issue those.  Nope just tested and it doesn't work with "/emas" or "/as" - I can always put the character's name in /desc for speaking and emoting I suppose.
1529846879

Edited 1529847112
MyRoll20Stuffs
API Scripter
Just tried with /fx hoping that might work but it doesn't seem to work either. {"who":"error","type":"error","content":"Unrecognized command: /fx bomb-smoke -LFCP1M4hCfTYDa_gSVv -LFCP1M4hCfTYDa_gSVv"}
1529848259

Edited 1529848900
MyRoll20Stuffs
API Scripter
I get the same error with "/ooc" as I get with "/fx: {"who":"error","type":"error","content":"Unrecognized command: /ooc Testing OOC"} I've modified it to take a "speaker" optionally. !delay [seconds to delay] | [optional speaker] -- [command or chat message] function delayFunction(speaker, msg) {     return function() {         sendChat(speaker.trim(), msg.trim());     } }      on("chat:message", function(msg) {     var cmdName = "!delay";     var msgTxt = msg.content;     if(msg.type == "api" && msgTxt.indexOf(cmdName) !== -1) {         var speaking = msg.content.split('|')[1];         var command = msg.content.split('--')[1];         var seconds = msg.content.split(' ')[1];              if (speaking)             speaking = speaking.split('--')[0];         else             speaking = "";              if (!isNaN(seconds) && command)            var delay_length = seconds * 1000;         else            return;         setTimeout(delayFunction(speaking, command), delay_length);     }; }); on('ready',function(){     log("-=> Delay command loaded (!delay) <=-"); }); I've only tested and been able to use it with: /desc /em /w /roll /gmroll normal chat @TheAaron : Are there any other chat functions you think would work with this? If I do an inline roll like [[1d20]] it returns $[[0]] to the chat. How can I get inline rolls working with this?
What are some characters not commonly used by most API scripts? With this delay script I can delay other API scripts if they have commands like so: !delay 5 -- !sfx song:Explosion action:play unique:true volume:100 But the reason I ask is because pipes and double dashes are commonly used characters across most API scripts and I want to be able to delay commands that use those characters without any major changes to the existing script.
1529850853

Edited 1529850919
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
Take a look at my crl for an alternate syntax. I used \\ in place of --my my question is why do you want to delay npc messages/commands?
Scott C. said: Take a look at my crl for an alternate syntax. I used \\ in place of --my my question is why do you want to delay npc messages/commands? Plenty of reasons. Example: A Phantom, Looking for a Sapphire Pendant is hiding on a path the PCs are going down: An "Ambush" macro that is a token action: !token-mod --set layer|objects --ids @{selected|token_id} !sfx song:Appear1 action:play unique:true volume:100 /fx bomb-smoke @{selected|token_id} @{selected|token_id} !delay 5 | Phantom -- SAPPH... !delay 5 -- !sfx song:Scream action:play unique:true volume:100 !delay 8 | Phantom -- ...PHIRE.... !delay 10 -- !sfx song:DrawSword action:play unique:true volume:100 !delay 15 | Phantom -- ...GIVE ME.... !delay 20 | Phantom -- ...SAPPH...IRE... I'd like to be able to delay the !token-mod command (and others) so I can play SFX or do some kind of VFX prior to making the token visible to the players by moving it to the objects layer.
1529857633
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
I had a situation last night that wold have been well served by a generic delay command. I had the players on a dark map with limited DL sight range (They were in a sand storm). They were attack by lightning-throwing giant scorpions (because reasons). I had API buttons attached to their lightning attack so that every time they used it, the would briefly illuminate a large section of the battlefield. Button 1 - Turn light on Button 2 - Play thunder sound Button 3 - Turn light off A delay would have been nice to allow the whole thing to be done with one press, but allow the light to stay on for a full second.
1529864242
The Aaron
Pro
API Scripter
Kastion said: @TheAaron : Are there any other chat functions you think would work with this? If I do an inline roll like [[1d20]] it returns $[[0]] to the chat. How can I get inline rolls working with this? If you don't care about the mouse overs and just want the values, you can use this function:&nbsp; <a href="https://wiki.roll20.net/API:Cookbook#processInline" rel="nofollow">https://wiki.roll20.net/API:Cookbook#processInline</a>... If you want the mouse overs... good luck. =D&nbsp; You could rewrite that function to put the formula back together in the inline roll and let it roll again on being sent to the chat (I think that's what PowerCards does, or did at one point). Kastion said: What are some characters not commonly used by most API scripts? With this delay script I can delay other API scripts if they have commands like so: !delay 5 -- !sfx song:Explosion action:play unique:true volume:100 But the reason I ask is because pipes and double dashes are commonly used characters across most API scripts and I want to be able to delay commands that use those characters without any major changes to the existing script. Actually, it doesn't matter what other scripts use, that's the common reason for using -- by itself in something like this.&nbsp; If you simply replace everything up to the first --, you&nbsp; can be assured that whatever formatting is used in the rest of the message is preserved: function delayFunction(speaker, msg) { &nbsp; &nbsp; return function() { &nbsp; &nbsp; &nbsp; &nbsp; sendChat(speaker.trim(), msg.trim()); &nbsp; &nbsp; } } &nbsp; &nbsp;&nbsp; on("chat:message", function(msg) { &nbsp; &nbsp; var cmdName = "!delay"; &nbsp; &nbsp; var msgTxt = msg.content; &nbsp; &nbsp; if(msg.type == "api" && msgTxt.indexOf(cmdName) !== -1) { &nbsp; &nbsp; &nbsp; &nbsp; var speaking = msg.content.split('|')[1]; &nbsp; &nbsp; &nbsp; &nbsp; var command = msg.content .replace(/^.*?\s+--\s+/,''); &nbsp; &nbsp; &nbsp; &nbsp; var seconds = msg.content.split(' ')[1]; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (speaking) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; speaking = speaking.split('--')[0]; &nbsp; &nbsp; &nbsp; &nbsp; else &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; speaking = ""; &nbsp; &nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (!isNaN(seconds) && command) &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;var delay_length = seconds * 1000; &nbsp; &nbsp; &nbsp; &nbsp; else &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;return; &nbsp; &nbsp; &nbsp; &nbsp; setTimeout(delayFunction(speaking, command), delay_length); &nbsp; &nbsp; }; }); on('ready',function(){ &nbsp; &nbsp; log("-=&gt; Delay command loaded (!delay) &lt;=-"); });
Thanks so much The Aaron. Such a simple change for a big fix. Also I found a post of yours here: <a href="https://app.roll20.net/forum/post/6504953/manual-token-targeting/?pageforid=6505095#post-6505095" rel="nofollow">https://app.roll20.net/forum/post/6504953/manual-token-targeting/?pageforid=6505095#post-6505095</a> I think I can get around not being able to delay "/fx" by creating the effects with the above linked script.
Kastion said: Also I found a post of yours here: <a href="https://app.roll20.net/forum/post/6504953/manual-token-targeting/?pageforid=6505095#post-6505095" rel="nofollow">https://app.roll20.net/forum/post/6504953/manual-token-targeting/?pageforid=6505095#post-6505095</a> @TheAaron: I'm having some issues getting this to work for me. When I select a token and run: !cfx bomb-smoke @{selected|character_id} @{selected|token_id} No effect is executed and there are no error messages in the chat or the API log. Is this an issue with me being a GM?
1529875160

Edited 1529878098
MyRoll20Stuffs
API Scripter
I've put in checkpoints at various parts of the script and it's making it all the way down the script and running this: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; spawnFx( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {x:t.get('left'),y:t.get('top')}, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; destPt, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; args[0], &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pageid &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ); I'm not seeing any FX at all and that's with selecting a PC or NPC and running this: !cfx bomb-smoke @{selected|character_id} @{selected|token_id} I'm not sure what I'm doing wrong here. EDIT: Changing this: spawnFx( &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {x:t.get('left'),y:t.get('top')}, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; destPt, &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; args[0], &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pageid &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ); To this: spawnFx(t.get('left'), t.get('top'), args[0], pageid); Fixed the issues I was having with it. I think the original code was meant to be used with the " spawnFxBetweenPoints " function not the " spawnFx " function. EDIT AGAIN: I changed the function to spawnFxBetweenPoints and it seems to work like intended.
1529877291

Edited 1529879339
MyRoll20Stuffs
API Scripter
I got CFX working but when trying to "!delay" with it I get an error. For example when I run the following: !delay 5 --!cfx bomb-smoke @{selected|character_id} @{selected|token_id} I get TypeError: Cannot read property 'get' of undefined Do I have to wrap @ variables in something so they are not parsed until !cfx gets to it? EDIT: var command = msg.content.replace(/^.*?\s+--\s+/,''); Doesn't seem to be splitting the content for some reason. When I output "command" to the API log I get: !delay 5 --!cfx bomb-smoke -LCHOOUU2ifnX2nbPepd -LChddyvLqm0JJV8TYYk
1529878126
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
Hmm. I'm getting inconsistent behavior. This command works, using the delay and then executing: !delay 5 -- !roll20AM --play|Lightning SFX by J This command does nothing, however: !delay 5 --!token-mod --set light_radius|0 light_dimradius|0 In both cases, if I eliminate "!delay 5 --" the remaining code functions. Am I missing something?
keithcurtis said: In both cases, if I eliminate "!delay 5 --" the remaining code functions. Am I missing something? I'm in the same boat as you. I'm trying at this moment to fix the issue.
1529886207

Edited 1529886291
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
This is most likely due to how the scripts in question are setup to respond to messages. Roll20AM is specifically designed to accept messages from other apis. Not all scripts are, and some require information that a message sent from the API won't have. I would guess that cfx gets the player object of the person sending the command and then checks some things about it using .get. however because the cfx command was sent by an api script,there is no player object to get and that means an undefined variable that you are trying to do say player.get('name') on. token mod doesn't respond for similar reasons, but Aaron has most likely properly gated his response functions so that the script properly checks to make sure it has everything it needs before attempting a .get or similar. edited for DYAC.
1529888458
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
That makes sense, at least in the "you didn't get the magic incantation right" manner :).
1529905076
The Aaron
Pro
API Scripter
Kastion said: keithcurtis said: In both cases, if I eliminate "!delay 5 --" the remaining code functions. Am I missing something? I'm in the same boat as you. I'm trying at this moment to fix the issue. Make sure the -- has space on either side and it should work.&nbsp; !delay 5 -- !some command here
1529907807

Edited 1529908808
Victor B.
Pro
Sheet Author
API Scripter
FYI, delay has been removed from roll20AM for the time being.&nbsp; I needed to sort through the script and get the functionality working.&nbsp; If requested, I can add it to feature requests.&nbsp;&nbsp;
1529907829
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
No variation of 0, 1 or more spaces on either side of the first "--" seems to make any difference.
keithcurtis said: No variation of 0, 1 or more spaces on either side of the first "--" seems to make any difference. This fixes the issue with "--" not splitting correctly: /* Delay Function / Command by Kastion the Scriptomancer Profile: <a href="https://app.roll20.net/users/3173313/kastion" rel="nofollow">https://app.roll20.net/users/3173313/kastion</a> Syntax: !delay [seconds] \\ [speaker] -- [command] */ function delayFunction(speaker, msg) { &nbsp;&nbsp;&nbsp; return function() { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sendChat(speaker.trim(), msg.trim()); &nbsp;&nbsp;&nbsp; } } &nbsp;&nbsp; &nbsp; on("chat:message", function(msg) { &nbsp;&nbsp;&nbsp; var cmdName = "!delay"; &nbsp;&nbsp;&nbsp; var msgTxt = msg.content; &nbsp;&nbsp;&nbsp; if(msg.type == "api" && msgTxt.indexOf(cmdName) !== -1) { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var seconds = msg.content.split(' ')[1]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var speaking = msg.content.split('\\')[1]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var command = msg.content.substring(msg.content.indexOf('--')+2); &nbsp;&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (speaking) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; speaking = speaking.split('--')[0]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; speaking = ""; &nbsp;&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!isNaN(seconds) && command) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var delay_length = seconds * 1000; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setTimeout(delayFunction(speaking, command), delay_length); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp;&nbsp;&nbsp; }; }); on('ready',function(){ &nbsp;&nbsp;&nbsp; log("-=&gt; Delay command loaded (!delay) &lt;=-"); }); However I can still only get it to work with some API commands. !token-mod and !cfx for example give this error when ran wrapped in the !delay command: TypeError: Cannot read property 'get' of undefined Commands that don't take a character_id or token_id such as !sfx work fine with delay but I'm having issues getting it to work with commands that take IDs. @TheAaron: I was hoping since you wrote both !token-mod and !cfx that perhaps you could explain what is causing this API error and maybe know how to resolve this issue?
I think I've figured out why it errors out in some functions. In CFX for example there is this line: const who = getObj('player',msg.playerid).get('_displayname'); That is trying to get the player from msg.playerid - the problem is that !delay (The API) is the "player" using the sendChat function to execute the command so there is no msg.playerid being passed along to the delayed function. I've read that you can pass a player id through the sendChat command here: <a href="https://wiki.roll20.net/API:Chat" rel="nofollow">https://wiki.roll20.net/API:Chat</a> In this format: player|-Abc123 And I'm trying to preserve the playerid. Here is the script: /* Delay Function / Command by Kastion the Scriptomancer Profile: <a href="https://app.roll20.net/users/3173313/kastion" rel="nofollow">https://app.roll20.net/users/3173313/kastion</a> Syntax: !delay [seconds] \\ [speaker] -- [command] */ function delayFunction(speaker, output, pid) { &nbsp;&nbsp;&nbsp; return function() { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (output.indexOf("!") !== -1) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sendChat("player|" + pid, output.trim()); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sendChat(speaker.trim(), output.trim()); &nbsp;&nbsp;&nbsp; } } &nbsp;&nbsp; &nbsp; on("chat:message", function(msg) { &nbsp;&nbsp;&nbsp; var cmdName = "!delay"; &nbsp;&nbsp;&nbsp; var msgTxt = msg.content; &nbsp;&nbsp;&nbsp; if(msg.type == "api" && msgTxt.indexOf(cmdName) !== -1) { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var seconds = msg.content.split(' ')[1]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var speaking = msg.content.split('\\')[1]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var command = msg.content.substring(msg.content.indexOf('--')+2); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var pid = msg.playerid; &nbsp;&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (speaking) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; speaking = speaking.split('--')[0]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; speaking = ""; &nbsp;&nbsp; &nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!isNaN(seconds) && command) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; var delay_length = seconds * 1000; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; setTimeout(delayFunction(speaking, command, pid), delay_length); &nbsp;&nbsp;&nbsp; }; }); on('ready',function(){ &nbsp;&nbsp;&nbsp; log("-=&gt; Delay command loaded (!delay) &lt;=-"); }); When I output "pid" to the log in the delay command's script it outputs: "-L8dGoF0vNWip8COLBX6" But when I output msg.playerid in the command I'm trying to delay (CFX) it outputs this: "-L8dGoF0vNWip8COLBX6" "API" I'm really at loss on what to do. Will I have to edit any command I want to delay to strip out the "API" msg ID text? How would I go about just getting the player ID from this variable and omit the "API" part?
1529937666

Edited 1529938126
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
Kastion said: But when I output msg.playerid in the command I'm trying to delay (CFX) it outputs this: "-L8dGoF0vNWip8COLBX6" "API" I'm really at loss on what to do. Will I have to edit any command I want to delay to strip out the "API" msg ID text? How would I go about just getting the player ID from this variable and omit the "API" part? See my post above . This isn't something that you can do from your delay script's side of things. It's something that depends on the scripts your delay script is commanding. So, unless you want to edit every script you use to work with delay, it's not possible. You can't (reliably) edit the msg object before a given script gets it. EDIT: long story short, api messages always have a playerid of API, regardless of what the who attribute used in sendchat is.
1529940109
The Aaron
Pro
API Scripter
CFX was just a simple example script I threw together and never tested.&nbsp; Token mod uses: &nbsp; &nbsp; &nbsp; &nbsp; who=(getObj('player',id)||{get:()=&gt;'API'}).get('_displayname'); to get the player name, so should account for it coming from the API. It's entirely possible there are other scripts that get the player name and break no matter what the command is.&nbsp; try: !delay 20 --!doesnotexist and see if it still crashes.
The Aaron said: CFX was just a simple example script I threw together and never tested.&nbsp; Token mod uses: &nbsp; &nbsp; &nbsp; &nbsp; who=(getObj('player',id)||{get:()=&gt;'API'}).get('_displayname'); to get the player name, so should account for it coming from the API. It's entirely possible there are other scripts that get the player name and break no matter what the command is.&nbsp; try: !delay 20 --!doesnotexist and see if it still crashes. Yeah running that crashes it. I'm not sure at what part though. TypeError: Cannot read property 'get' of undefined Do you have any idea where I'm going wrong with my script?
1529943569
The Aaron
Pro
API Scripter
You'd need to look through all the scripts you have installed and see which one is accessing the displayname.
The Aaron said: You'd need to look through all the scripts you have installed and see which one is accessing the displayname. CFX const who = getObj('player',msg.playerid).get('_displayname'); Which is also the script I generally have been trying to delay.
1529943978
The Aaron
Pro
API Scripter
Yeah, change that to what TokenMod uses above. Sorry, thought you did that already. =D
The Aaron said: Yeah, change that to what TokenMod uses above. Sorry, thought you did that already. =D I ended up just flat out removing that line and modifying CFX to not use the variable. However, now when I run: !delay 5 -- !cfx bomb-smoke @{selected|character_id} @{selected|token_id} Nothing happens at all.
1529956237
The Aaron
Pro
API Scripter
I suggest having your script log what the command is, then copy/paste that into the chat and verify it works.
1529958462

Edited 1529958669
Victor B.
Pro
Sheet Author
API Scripter
Yes, log every step in your process.&nbsp; Pull down CFX code and add logs to that.&nbsp; Display input command, every variable that's getting set or used in an IF statement, whether you are correctly getting into an IF, etc..This is how I unwound the Roll20AM process.&nbsp;&nbsp; For example if(msg.type == "api" && msgTxt.indexOf(cmdName) !== -1) isn't api capitalized?&nbsp; API.&nbsp;&nbsp;
Victor B. said: Yes, log every step in your process.&nbsp; Pull down CFX code and add logs to that.&nbsp; Display input command, every variable that's getting set or used in an IF statement, whether you are correctly getting into an IF, etc..This is how I unwound the Roll20AM process.&nbsp;&nbsp; For example if(msg.type == "api" && msgTxt.indexOf(cmdName) !== -1) isn't api capitalized?&nbsp; API.&nbsp;&nbsp; For whatever reason lower case api works. I did what you and TheAaron suggested. I created checkpoints after every variable being set or function being ran and output everything to the log. The reason I couldn't get !cfx to work was because it was using msg.playerid which when an API script runs a second script through sendChat it gives a msg.playerid of "API". I did the following: function delayFunction(speaker, output, pid) { &nbsp;&nbsp;&nbsp; return function() { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (output.indexOf("!") !== -1) &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sendChat("player|" + pid, output.trim()); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sendChat(speaker.trim(), output.trim()); &nbsp;&nbsp;&nbsp; } } As specified here in the chat API docs to pass a playerid with sendChat But when I get the msg.playerid on the command the API ran it gives back 2 playerid's "-L8dGoF0vNWip8COLBX6" "API" I haven't programmed anything in about 3 years+ until I started using Roll20 so I'm a little rusty and I can't remember how to get the first playerid from the 2 strings. Even so if I did it that way I would have to edit each script that uses msg.playerid so it works with delays. The Aaron said: I suggest having your script log what the command is, then copy/paste that into the chat and verify it works. I did this with CFX and all my problems revolved around msg.playerid. I changed this: &nbsp;&nbsp;&nbsp; const getPageForPlayer = (playerid) =&gt; { &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; let player = getObj('player',playerid); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(playerIsGM(playerid)){ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return player.get('lastpage'); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; let psp = Campaign().get('playerspecificpages'); &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(psp[playerid]){ &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return psp[playerid]; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return Campaign.get('playerpageid'); &nbsp;&nbsp;&nbsp; }; To this: let pageid = Campaign().get("playerpageid"); And that fixed my issues with CFX and it now works with !delay. Right now I'm trying to get it to work with !token-mod Here is the output from !delay, the playerid and command sent to sendChat: "PID: -L8dGoF0vNWip8COLBX6 Command: !token-mod --set layer|gmlayer --ids -LBOyktq-VWzBplvzTU7" I can paste the following directly into the chat and it works: !token-mod --set layer|gmlayer --ids -LBOyktq-VWzBplvzTU7 But it won't run from the !delay command. I went into token-mod and on line 2328 at the start of handleInput I added: log("PID: " + msg.playerid); And it outputs this when running the "!token-mod --help" command wrapped in the !delay command "PID: -L8dGoF0vNWip8COLBX6" "PID: API" {"who":"error","type":"error","content":"Unable to find a player or character with name: API"} How do I get it to use the first PID or remove the second "API" PID? Is there any workaround for this that doesn't involve editing every single script that uses msg.playerid?
1529966150
Victor B.
Pro
Sheet Author
API Scripter
for (var i = 0, I &gt; 0, i++){ &lt;save first id then loop ends&gt; } That's old school way to do it.&nbsp; There may be new java functions that accomplish the same thing
1529966191
The Aaron
Pro
API Scripter
Specifying the Player ID is only used for determining 3d dice color. It doesn't change the originator of the message as far as the API is concerned.&nbsp; Probably you'll need to change !cfx to take a player ID as an argument, possibly as the 3rd argument, and use it instead of msg.playerid if it is specified.
1529966273
The Aaron
Pro
API Scripter
Or you can have it take a page id, which is what it used the player id for anyway.&nbsp; Or just write a function to do the spawning of the FX without an API command as part of the interval.
The Aaron said: Specifying the Player ID is only used for determining 3d dice color. It doesn't change the originator of the message as far as the API is concerned.&nbsp; Probably you'll need to change !cfx to take a player ID as an argument, possibly as the 3rd argument, and use it instead of msg.playerid if it is specified. The Aaron said: Or you can have it take a page id, which is what it used the player id for anyway.&nbsp; Or just write a function to do the spawning of the FX without an API command as part of the interval. I already got CFX working by removing references to msg.playerid and getting the page id in a different way (see above post). The only problem I'm having now is with !token-mod's uses of msg.playerid and the sendChat command in !delay passing 2 playerid's: "PID: -L8dGoF0vNWip8COLBX6" "PID: API" {"who":"error","type":"error","content":"Unable to find a player or character with name: API"} Victor B. said: for (var i = 0, I &gt; 0, i++){ &lt;save first id then loop ends&gt; } That's old school way to do it.&nbsp; There may be new java functions that accomplish the same thing When I tried to get the first string (assuming is was an array of 2 strings) like so: msg.playerid[0] all it returned was the first character in the first string. I'll have to try to mess with it again and see what I can come up with.
1529968718
Victor B.
Pro
Sheet Author
API Scripter
msg.playerid isn't an array.&nbsp; It's a string.&nbsp; So you told JS to pull out first byte in the string.&nbsp; From what you posted above PID[0] should work.&nbsp;&nbsp;
1529969032
The Aaron
Pro
API Scripter
The only place TokenMod looks like it will cause issues is if you're trying to use the --current-page restriction.
1529971215

Edited 1529971347
MyRoll20Stuffs
API Scripter
I managed to fix the issues I was having with !token-mod Victor B. said: msg.playerid isn't an array.&nbsp; It's a string.&nbsp; So you told JS to pull out first byte in the string.&nbsp; From what you posted above PID[0] should work.&nbsp;&nbsp; I figured that out when I tried to get the first "element" in the "array" haha. PID that I had shown in my above comment wasn't actually an array with 2 strings. It was a single string being overwritten. The sendChat function was passing the ID I gave it, then overwriting my ID with the "API" ID. I think so anyways but I'm not exactly sure. The handleInput function on token-mod was being called twice, once for !delay and a second time for !token-mod that was being delayed. I managed to fix it by adding the following code to the very start of handleInput in token-mod: &nbsp;if (!state.tokenmod_pid) &nbsp;&nbsp;&nbsp;&nbsp; state.tokenmod_pid = "API"; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp;if (msg.playerid !== "API") &nbsp; &nbsp;&nbsp; state.tokenmod_pid = msg.playerid; &nbsp;else &nbsp; &nbsp;&nbsp; msg.playerid = state.tokenmod_pid; I suspect I will have to use the above code with other scripts if I want to be able to delay them.
1529982576
Victor B.
Pro
Sheet Author
API Scripter
Try this, it had nothing to do with two PIDs.&nbsp; Your parsing of the command wasn't correct.&nbsp; Instead of !delay 5 --!token-mod &lt;whatever&gt; try !delay --5 --!token-mod so if you have one too many or too few spaces somewhere it won't mess anything up.&nbsp; This invokes token-mod.&nbsp;&nbsp; function delayFunction(speaker, output, pid) { return function() { sendChat("player|" + pid, output.trim()); } } on("chat:message", function(msg) { var cmdName = "!delay"; var msgTxt = msg.content; if(msg.type == "api" && msgTxt.indexOf(cmdName) !== -1) { var cmdSep = msg.content.split('--') var seconds = cmdSep[1].trim(); var command = cmdSep[2]+' --'+cmdSep[3] var pid = msg.playerid; if (seconds && command){ var delay_length = seconds * 1000; log(delay_length) }else{ return; } setTimeout(delayFunction(pid, command, pid), delay_length); }; });
1529982640

Edited 1529982677
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
Would that break any other behavior in token-mod? I think there are some great things I could do with delay, but token-mod is my workhorse.
1529982773
Victor B.
Pro
Sheet Author
API Scripter
Another option is to do !delay,5,!token-mod -- whatever.&nbsp; This is a bit more straight forward but requires a bit of changes to the above code.&nbsp;&nbsp;