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

Trouble with Ammo Tracking from 5e OGL Companion and Macros while using sendChat();

I'm working on a script that constructs and sends a macro to chat using something like: sendChat('character|' + character.id, macroString) When I create the macro with an API command and sendChat(), the ammo tracking doesn't work (though the rest of the output is formatted correctly). If I simply paste 'macroString' into chat, it does properly deduct ammo (and also still formats correctly). Some initial points: 1. 'macroString' is a formatted macro, using an atkdmg template and including roll information. The ammo section is formatted like: {{ammo=' + getAttrByName(character.id, 'custom_resource') + ' @{' + character.get('name') + '|charname_output}}} 2. For the ammo I'd like to use, I'm manually copying the resource ID from an already created ammo resource tracker, so the value of the custom_resource I'm passing looks something like 'Arrows|-OaWjCykKAarqfvyWXeR' I've looked over the Companion source code for handleammo() and I'm guessing the issue is that sendChat() isn't satisfying the 'player' object, so handleammo() returns nothing - as opposed to manually sending 'macroString' myself. All this said, I'm coming to you fine people to see if I'm missing something. Is there a way to get the Companion ammo tracking to trigger in a macro that was created using sendChat()?
Here's a simple example. For a character named 'Patches' with an ammo resource set up as 'Arrows|-OaWjCykKAarqfvyWXeR', the following macro will deduct an arrow from that resource: &{template:atkdmg} {{r1=[[1d20]]}} {{ammo=Arrows|-OaWjCykKAarqfvyWXeR @{Patches|charname_output}}} Using the following script, you can use the '!sendMacro' command to send exactly this macro to chat. on ( 'chat:message' , function ( msg ){ if ( msg . type == 'api' && msg . content . indexOf ( '!sendMacro' )== 0 ){ sendChat ( 'Patches' , '&{template:atkdmg} {{r1=[[1d20]]}} {{ammo=Arrows|-OaWjCykKAarqfvyWXeR @{Patches|charname_output}}}' ); }; return ; }); You'll see that the ammo tracking doesn't work.
1759433039

Edited 1759435307
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
Hi based patches! Without more details, it is possible that you might be running into the problem that the API cannot actually execute another API call. It can only send the text of a macro command to chat that can be clicked on to run (i.e. a formatted button). This is a safeguard agains infinite loops. EDIT: Apparently, the API can send API calls that execute. In the past, I have been thwarted because the API doesn't select anything like a player does, and thus they always failed.
1759434242

Edited 1759434310
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
I would try replacing the attribute call with the actual character name (or whatever the output of that attribute is). The way that sendChat parses attribute/ability calls is a little different from how manual messages are parsed if I recall correctly. However, note that the ammunition tracking of the 5e companion script might be relying on information that is passed as part of the chat message when it is sent from a character; I can't remember the exact details of how that script works.
Thanks very much, both of you. I tried directly inserting the character name directly and it has the same behavior.  I took a minute to inspect the Companion source and I think Keith is exactly correct. The roll listener that would catch the call explicitly forbids api calls. See: // ROLL LISTENERS else if ( msg . playerid . toLowerCase () != "api" && msg . rolltemplate ) { If the message is sent by the api, it doesn't get through. I'll try to find another way around this, but thanks so far.
1759437144

Edited 1759437160
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
Interesting. If you are building your own script to interact with the Companion, you could download the companion source code and alter that line for your game use.
1759437219

Edited 1759437240
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
ah, yep. It's been explicitly coded to ignore api messages. The companion script isn't actively developed, so you could just use the raw code in your game and modify it to allow the api messages (might need to put additional guards in to protect from it seeing it's own messages though). Heh, sniped by Keith
Heh, I removed the restriction. It's just immediately thwarted by sending the undefined playerid from sendChat(); into handleammo(), where it then tries to .get('displayname'), crashing the sandbox.  The 'player' issue comes about from how the added functionality of the companion script allows different whisper types - which is written to require the playerid. The script I'm writing is for personal use - is it ok to simply take parts of the companion code and use it in my script?
1759444094
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
yep, definitely ok to take. Everything in the roll20 public repos is released under the MIT license.
1759456911
timmaugh
Forum Champion
API Scripter
Just an FYI about this issue... this is exactly what SelectManager was built to help with. (SelectManager is a metascript, and part of the MetascriptToolbox.) Basically, when a script sends a message, there are 3 things that are different: 1) no selected tokens 2) playerid = API 3) who = API SM tracks these properties as they exist on the message associated with the last user-initiated command... typically, this is the command that would initiate a script to take action including sending a message of its own. So when the human initiates the call, SelectManager tracks these properties. Then SelectManager watches for a script-generated message (like what your script is outputting), and restores the properties you've configured it to restore (any or all of the 3 just mentioned). Interestingly, it doesn't look like the outbound message is an API command (it isn't a bangsy message). That would seem to indicate that the Companion Script is watching normal messages for the template type, and then parsing it for the proper field to do its thing (I could read it to be sure, but that also comports to what you were describing). I say this is interesting because this is a gray area of message manipulation: The outbound message is NOT an API call, which means that it is going to hit the chat output. Typically, metascripts can't alter a message that is NEVER an API call and therefore only intended to hit the chat output. This is because when a normal (non-api) message is sent, one copy is sent to the chat output, and another is sent to the sandbox. The metascripts will take action on the sandbox message, but since that never makes it to chat (and it was never an API message to begin with), the changes are for nothing, because they don't go anywhere. However, the Companion script is, itself acting on the message... it's watching for the template type and reading the appropriate property. So which message is it reading? It's ALSO reading the message that is sent to the sandbox (the only copy of the 2 that it has access to). That means that even in this case, SelectManager's manipulation of the message should work... I'd have to check. It could be that I set it up to only affect script messages (bangsy messages) because I hadn't thought of this particular gray area of script/template interaction. If it works, you could accomplish what you want just by installing the MetascriptToolbox and then configuring SelectManager to give back all properties: !smconfig +playerid +who If it doesn't work, it's something I could probably alter in SelectManager to open up the avenue of meta-assistance.
This is amazingly insightful. Thank you. I (swapped back to my unmodified companion script and) installed, SelectManager and MetascriptToolbox + dependencies - I then successfully ran the chat command. Unfortunately, the behavior is the same for the macro sent to chat with sendChat; For my specific case, it will be easy for me to simply include what I need from the companion in my own script. This is really interesting otherwise. I have several new mods to read through.
1759491068

Edited 1759491138
timmaugh
Forum Champion
API Scripter
Thanks for the report back about that. I will have to go lift the prohibition on the MetascriptToolbox acting on non-api messages. No, the changes the Toolbox performs will never make it to chat, but they WILL affect the sandbox message that will potentially be acted upon by other scripts! For instance, if you send: &{template:default}{{name=Proof of Concept}}{{Token Location=@(selected.top),@(selected.left)}} ...through chat, what you'll get will be the unprocessed text: However, if the Toolbox is opened up so that it will act on non-api messages, then the message object that reaches other scripts will have selected tokens (SelectManager), and the content property will have those Fetch constructions processed out: &{template:default}{{name=Proof of Concept}}{{Token Location=427,1200}}
I resolved my issue by simply calling handleammo() in my own script, since it is globally available from the companion script.  I fed the function what it wanted and my constructed macro now properly tracks the resource. I have not modified the companion script. Here's a simple example. sendChat ( 'Patches' , '{{ammo= Arrows|-OaWjCykKAarqfvyWXeR @{Patches |charname_output}}}' , function ( msg ){ handleammo ( msg [ 0 ], character , player ); //defined in the 5e OGL Companion script }, { noarchive : true }) The actual script is taking the character name and the listed custom resource, but this is similar to the example given a few posts up.