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

Using a macro or token action to send @selected and @target to an api script. I'm stuck, and what theAaron wrote I don't understand!

August 30 (10 months ago)
GM
Pro

I've seen the great guru himself TheAaron described a solution to this problem, but I cannot decipher his code.

I simply want to write something like this as a token action:
!torpedo --selected @{selected|token_id} --target @{target|token_id}

The code inside my script can and should work beautifully, but I cannot get the API to understand that I'm passing both values to it.
TheAaron wrote some code in this forum that seems to handle this, but I do not understand it at all.
That code is here: https://app.roll20.net/forum/post/8998098/can-you-pass-both-a-selected-and-target-tokenid-to-an-api-script

It's ancient Sanskrit to me. I don't know what to put where, nor how to use it. Help!

"I am but a simple caveman attorney. Your ways frighten and confuse me."

August 31 (10 months ago)
keithcurtis
Forum Champion
Marketplace Creator
API Scripter

Hi GM!

Can you post your own code? It's hard to analyze where things might be breaking down. It might be an internal parsing error. For instance, assuming token ids of -12312312312312 and -45645645645 does this command work?

!torpedo --selected -12312312312312 --target -45645645645


September 01 (10 months ago)

Edited September 02 (10 months ago)
GM
Pro

The MACRO / Token Action

!torpedo --selected @{selected|token_id} --target @{target|token_id}

__________________

The SCRIPT

//spawn torpedo

on('chat:message', function(msg) {

    if (msg.type !== 'api' || !msg.content.startsWith('!torpedo')) return;


    const args = msg.content.split(' ');

    if (args.length !== 3) {

        sendChat('System', '/w ' + msg.who + ' Invalid arguments. Usage: !torpedo casterTokenId targetTokenId');

        return;

    }


    const casterTokenId = args[1];

    const targetTokenId = args[2];


    const casterToken = getObj('graphic', casterTokenId);

    const targetToken = getObj('graphic', targetTokenId);


    if (!casterToken || !targetToken) {

        sendChat('System', 'Invalid token IDs provided.');

        return;

    }


    const casterCharacter = getObj('character', casterToken.get('represents'));


    if (!casterCharacter) {

        sendChat('System', 'This token does not represent a character.');

        return;

    }


    // Check current player page

    const currentPageId = Campaign().get('playerpageid');

    const currentPage = getObj('page', currentPageId);

    const pageName = currentPage.get('name');


    if (!['GHUD', 'PlanetaryNav', 'SystemNav'].includes(pageName)) {

        sendChat('System', 'Ship to ship weapons cannot be fired from this screen.');

        return;

    }


    // Check if character has "Torpedo Launcher"

    const torpedoWeapon = findObjs({

        _type: 'attribute',

        _characterid: casterCharacter.id,

        name: 'repeating_inventory_$X_itemname',

        current: 'Torpedo Launcher'

    })[0];


    if (!torpedoWeapon) {

        sendChat('System', 'This token does not have a torpedo launcher.');

        return;

    }


    // Check ammo

    const ammoAttribute = findObjs({

        _type: 'attribute',

        _characterid: casterCharacter.id,

        name: 'repeating_inventory_$X_resource'

    }).find(attr => attr.get('current') > 0);


    if (!ammoAttribute || ammoAttribute.get('current') <= 0) {

        sendChat('System', 'This token is out of torpedoes.');

        return;

    }


    // Deduct ammo

    ammoAttribute.set('current', ammoAttribute.get('current') - 1);


    // Get locations

    const casterLocation = {

        left: casterToken.get('left'),

        top: casterToken.get('top')

    };


    const targetLocation = {

        left: targetToken.get('left'),

        top: targetToken.get('top')

    };


    // Instantiate a token at caster location representing the torpedo

    const torpedoToken = createObj('graphic', {

        _pageid: casterToken.get('_pageid'),

        imgsrc: 'https://s3.amazonaws.com/files.d20.io/images/366403456/xvVdL5KBgB6TMpyNb6-jTQ/med.webm?1699199637',

        layer: 'objects',

        left: casterLocation.left,

        top: casterLocation.top,

        width: 24,  // Assuming the hex size corresponds to 24

        height: 24,

        name: 'weapon_torpedo',

        bar2_value: targetTokenId,

        bar2_max: JSON.stringify(targetLocation),  // Store the target location in bar2_max

        gmnotes: '20'  // Adds “20” to gmnotes

    });


    // Send a red ping to the caster location

    sendPing(casterLocation.left, casterLocation.top, casterToken.get('_pageid'), null, true, 'red');


    // Play sound using !roll20AM

    //sendChat('System', `!roll20AM --audio,play|${randomTrackFromPlaylist('GloriaTorpedoIncoming')}`);

});


// Helper function to randomly select a track from a playlist

function randomTrackFromPlaylist(playlistName) {

    const playlist = findObjs({

        _type: 'jukeboxtrack',

        playlist: playlistName

    });


    if (playlist.length > 0) {

        const track = playlist[Math.floor(Math.random() * playlist.length)];

        return track.get('title');

    }


    return '';

}

September 02 (10 months ago)
GM
Pro


keithcurtis said:

Hi GM!

Can you post your own code? It's hard to analyze where things might be breaking down. It might be an internal parsing error. For instance, assuming token ids of -12312312312312 and -45645645645 does this command work?

!torpedo --selected -12312312312312 --target -45645645645



The more i think about it, I think I'll just make an easier script that instantiates a token representing the character weapon_torpedo at the selected token's location, on top. 
Then, as a token action on the torpedo itself, I'll pass the target token's location to a script that puts that value in the bar 2 value.

I already have a script I can run that moves all the torpedoes 5 spaces toward their target in the bar 2 value.

September 02 (10 months ago)

Edited September 02 (10 months ago)
keithcurtis
Forum Champion
Marketplace Creator
API Scripter

It looks like your script wants:

!torpedo casterTokenId targetTokenId

but you are sending:

!torpedo --selected -1234567890abcde -098765432edcba

so instead of the script separating into three parts with parts 2 and 3 being the tokenids, you are getting "!torpedo", "--selected" and "-1234567890abcde" as args.


const casterTokenId = args[1];
const targetTokenId = args[2];

would assign 

casterTokenId = "--selected"

targetTokenId = "-1234567890abcde"

But that's a quick takeaway from me, a pure dilettante coder. Possibly one of the regular real coders can spot something else

September 02 (10 months ago)
GM
Pro

That’s an interesting observation. So I can’t just pass prompted values as api args like that?

Is that the issue, or do I need to be working from the 3rd and 5th args?

September 02 (10 months ago)
timmaugh
Forum Champion
API Scripter

You need to settle on what sort of command line you are going to support, and then build around that. It isn't terribly sustainable to work with the nth and the xth argument. You CAN do it, but chances are good that if you walk away from the script and come back to it in several months, you won't remember what order the arguments need to come in to make the whole thing work. Here is a post where I talk about thinking through how to build your command line, with an eye toward making it user-friendly.

Here's what's going on in your script...

You split on a single space, so when you take a line like:

!torpedo --selected @{selected|token_id} --target @{target|token_id}

...and you split it on a space, you end up with an array like:

[
  !torpedo,
  --selected,
  / the token id of your selected token /,
  --target,
  / the token id of your targeted token /
]

If you wanted to work with a line like this and you didn't want to write up more robust line-parsing, you would be looking to work with the 2nd and the 4th argument, since arrays are 0-based.

But if you read the link, above, you could easily split on a regex for "any amount of white space followed by two hyphens", then you could test for the first part of the argument (for either "selected" or "target") to know which argument you were currently working on. This would make your command line more forgiving and more readable. You could use the arguments in any order, because your parser would know how to break them down and what to look for.

September 02 (10 months ago)
keithcurtis
Forum Champion
Marketplace Creator
API Scripter

Yes, second and fourth (I missed that you had used "--target" as well.


Just change your macro to:

!torpedo -1234567890abcde -098765432edcba
and the values should be assigned correctly, without changing the script.


Or you can go Timmaugh's route above if you want the --selected, --target to be in the macro, to work with the 2nd and 4th.

September 04 (10 months ago)
GM
Pro

I fixed it by changing the structure of the token action / macro.  

Timmaugh’s suggestion gives me food for thought for when I do a full rewrite one of these days.