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

Can you call macros in API scripts?

As the topic asks...

I know #macro and %ability will let you call their functions in other macros, but can you use the same syntax when making an API script to call upon a macro or player ability?
May 13 (11 years ago)

Edited May 13 (11 years ago)
Lithl
Pro
Sheet Author
API Scripter
No, not directly. However, the API could find the macro object in question and get its text content, which the script could then output..
May 14 (11 years ago)

Edited May 14 (11 years ago)
I am trying to determine the best way to combine combat rolls and then if successful roll damage. Since I can not use conditional logic in the macros, I was looking at made using the API to just call a attack macro, then if it hits, roll the damage.

I think using the on("chat:message") would be my best bet and just have the macros use the sendchat function to call it. One thing I am still unsure of, if I do it this way, will the script still be able to use the @{selected} and @{target} functions? I am assuming so since global macros can, but again, I am unsure.

EDIT:

AH, looking here at https://wiki.roll20.net/API:Chat I see near the bottom: "Note that you can also use the "token_id" attribute with @selected and @target variables in your API commands to pass in the token ID of a selected or targeted token."

Am I correct in assume I must use token_id in the initial part of the script so it will know what token to draw any variables from? maybe I can use a var to store the token ID that called the script and then just use it to get any attributes needed to modify a roll or damage. Am I over thinking this?
May 14 (11 years ago)
Lithl
Pro
Sheet Author
API Scripter

If you use @{selected|token_id} or @{target|token_id} in an API command, they'll be substituted with the appropriate unique id for the token. It'll look something like -Abc123. You can then use that value with the getObj, findObjs, or filterObjs functions to find a reference to the token object. (getObj is the most efficient, but it requires that you know the object id and the type of object.)

That hasn't been my experience with the API thus far, but I really haven't been delving into it that deep. So far the simple script I wrote was a sendChat to emote that the selected token was attack another token, but it didn't parse their token_names to the chat window. Is this because they first need to be referenced and stored in a variable? Looks like I will need to use findObjs to the token references then.

Would it be better to just keep the emote portion in the macro followed with the API call? Something like this:

/emas @{selected|token_name} attacks @{target|token_name}!
!script

Forgive my ignorance but what would I use to reference those two tokens in the script?

I am thinking var Attacker and var Target as the two variables. I can see how I would do this if I already knew the IDs of the entities, but that doesn't help me at all as this is meant to be a globally accessible function.
May 14 (11 years ago)

Edited May 14 (11 years ago)
Dang... token_id. I've been using _name. so would it be something like...

var Attacker = @{selected|token_id}
var Target = @{target|token_id}

Then I can just use those _id to then pull their Hit and AC attributes? I have to get back to the API lab stat!
May 14 (11 years ago)
Lithl
Pro
Sheet Author
API Scripter

You would have to pass the names or ids to the script, not simply emote them prior to calling the API command.

For example, your macro might be:

/emas @{selected|token_name} attacks @{target|token_name}!
!script @{selected|token_id} @{target|token_id}

Then, your script might be:

on('chat:message', function(msg) {
// Do nothing for messages which aren't API commands
if (msg.type != 'api') return;

// Each parameter in the API command is separated by a space, and the first part is the command itself
var parts = msg.content.split(' ');
// I like to remove the exclamation point at the start of the command name, but it's not required
var command = parts.shift().substring(1);

// Don't run your API command logic if some other command was sent!
if (command == 'script') {
// Make sure enough parameters were sent, to avoid index out of bounds
if (parts.length < 2) {
sendChat('SYSTEM', 'You must provide a selected token id and a target token id.');
return;
}

// Assume the first two parameters are object IDs
var selectedId = parts[0];
var targetId = parts[1];

// Attempt to get the objects as graphics
var selectedToken = getObj('graphic', selectedId);
var targetToken = getObj('graphic', targetId);

// If the objects *aren't* graphics, or the parameters weren't IDs, fail gracefully
if (!selectedToken) {
sendChat('SYSTEM', 'Selected token id not provided.');
return;
}
if (!targetToken) {
sendChat('SYSTEM', 'Target token id not provided.');
return;
}

// Get a variable to use as the "who" for sendChat
var who = getObj('character', selectedToken.get('represents'));
if (!who) {
who = selectedToken.get('name');
} else {
who = 'character|' + who.id;
}

// Add script logic here. If the selected token represents a character in the journal, using `who'
// as the first parameter to sendChat will post as that character. Otherwise, the chat will simply
// use the token's name.
sendChat(who, '/me does a thing to ' + targetToken.get('name') + '!');
}
});

I hope that helps.

May 14 (11 years ago)

Edited May 14 (11 years ago)
Does the line !script @{selected|token_id} @{target|token_id} in the macro pass the _ids to the array? If so I followed all that.

So now if I wanted to grab attributes off those characters I would use a getObj() function? Guessing I would need to make a variable for each stat I want to grab then as well and do a similar exchange?

This would be soooo much easier if we could just do if/then/else statements in the macro space. I would really never have to touch the API level if I could do that.

May 14 (11 years ago)

Edited May 14 (11 years ago)
I think I get it now.... the macro would need to pass all of the data to the script first. Half that script there is just error prevention. Now it is just a matter of making sure I am putting the data into the right variables...

Thank you Brian, that example helped me in so many ways.
May 15 (11 years ago)
Lithl
Pro
Sheet Author
API Scripter

Michael P. said:

Does the line !script @{selected|token_id} @{target|token_id} in the macro pass the _ids to the array? If so I followed all that.

So now if I wanted to grab attributes off those characters I would use a getObj() function? Guessing I would need to make a variable for each stat I want to grab then as well and do a similar exchange?

This would be soooo much easier if we could just do if/then/else statements in the macro space. I would really never have to touch the API level if I could do that.

Yes, the line in the macro is just passing token ids to the script.

getObj requires knowing the object's type and the object's unique id. It would be difficult to already know the unique id for attributes; instead, you'd probably want to use findObjs like so:

var strength = findObjs({
_type: 'attribute',
_characterid: myCharacter.id, // assuming `myCharacter' is a reference to a character object
name: 'Strength'
})[0];

This would find the attribute named "Strength" which is attached to the character referenced by the variable myCharacter. Alternatively, if all you wanted to know was the current or maximum value of some attribute, you could pass it as a parameter to the script (much like I passed the selected id and target id). Finding the attribute object would be useful if you have a bunch of attributes to pick up (which would make for an awkward macro) or if you need to alter the value of the attribute with the script, for example.

Thanks Brian, I found it was easier to just pass all the stats needed in the script like the token_id into the array. It is a little less coding, but I think this way you just posted is less error prone. Thanks for all your help, the script is coming along nicely. I almost have an all in one script to calculate any basic attack, either melee of ranged, using Pathfinder settings. I also have the damage rolls in there, and now I am working on the last bit which is the damage resolve to the characters them selves. This is going to make the game really stream line for basic attacks! I love it, I will be sharing it shortly.