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 an API event listener for changes to character's attributes like in a Sheet Worker?

It seems like you can only detect changes in graphics.  I'm trying to trigger Token-Mod when an attribute is changed on the character sheet but I'm not making any progress.  Essentially want the equivalent of this where attr_locked is a checkbox: on("change:locked", function() {     sendChat('', '!token-mod --set statusmarkers|!padlock'); });
It's not as easy as through a sheetworker, but it is possible. You need to listen for any attribute to change and then filter it down to your specific instance. on("change:attribute", function(obj, prev) { if(obj.get("name") == "locked") { sendChat('', '!token-mod --set statusmarkers|!padlock'); } });
1536026110
GiGs
Pro
Sheet Author
API Scripter
You'll also need to set which character that applies to, as well.
I tried sending token-mod the token id but I'm not doing it right.  What's the correct way to get the token id? on("change:attribute", function(obj, prev) { if(obj.get("name") == "locked") { let charid = obj.get('_characterid'); let token = findObjs({ type: 'graphic', represents: charid}); let tokenid = token.get('_id'); sendChat('', '!token-mod --ids ' + tokenid + ' --set statusmarkers|!padlock'); } }); });
whoops, had an extra bracket in there but taking it out didn't change anything
1536031979

Edited 1536032067
GiGs
Pro
Sheet Author
API Scripter
I'm not too familiar with manipulating tokens in this way, but i see a potential problem here. let token = findObjs({ type: 'graphic', represents: charid}); I don't know if the synatx here is correct, but if it works, this will be an array, which might only have one member, but you cant be sure of that. It's very easy to accidentally end up with multiple tokens of the same character on a map or scattered among multiple maps. So you need to account for that. And there might be zero tokens, too. Imagine you have cleaned up the map of tokens, and then the player accidentally altered the locked attribute, and there are no tokens to find. You'll have an error and crash the sandbox. Also I'd recommend using log statements after each line of your script, to figure out exactly what is being stored in your variables.
1536035426

Edited 1536035454
GiGs
Pro
Sheet Author
API Scripter
Looking again at your code it looks like you have too many brackets at the end. Thinking about what you need, a couple of things occur to me: What if the status marker is already set? Shouldnt you be looking at the  value  of the locked attribute, and adding the status marker if its true/1, and removing it if 0? You dont need to sendchat to tokenmod. You can simply set the statusmarker directly in your script, using the api commands to do that. Setting a statusmarker looks something like this: token. set (markerName, true); token. set (markerName, false); So, maybe this script (untested) will work.  on("change:attribute:current", function(obj, prev) { if(obj.get("name") === "locked") { const markername = 'status_padlock'; let charid = obj.get('_characterid');         let value = obj.get("current"); let tokens = findObjs({ type: 'graphic', represents: charid});         for ( i = 0 ; i < tokens . length ; ++ i ) {             tokens[i]. set (markerName, (value === "1" ? true: false) ); } } }); This line tokens[i]. set (markerName, (value ==="1" ? true: false) ); Might be wrong. Maybe it should be if (value === "1") { tokens[i]. set (markerName, true); } else { tokens[i]. set (markerName, false); } Also, I have assumed your locked attribute will only have two values, "1" and "0". I'm not too familiar with this type of code, but maybe this will help.
1536035530

Edited 1536035691
The Aaron
Pro
API Scripter
Try this: on("change:attribute", function(obj, prev) { if(obj.get("name") == "locked") { let charid = obj.get('characterid'); sendChat('', `!token-mod --set statusmarkers|!padlock --ids ${charid}`); } }); TokenMod’s --ids will take a character id and find all tokens associated with it. !padlock will flip the state of the padlock status marker. You may want - or perhaps to base it on the value of locked?
1536035761
The Aaron
Pro
API Scripter
And as G G points out, you probably don’t need to call to TokenMod at all.  =D
1536036794
GiGs
Pro
Sheet Author
API Scripter
The Aaron said: And as G G points out, you probably don’t need to call to TokenMod at all.  =D Then again, your code is a lot shorter :)
Yes G G that is what I was eventually trying to work towards.  I'll have to look through that code to understand it better. Aaron for some reason that code isn't working for me.  I had already tried doing this a different way but am getting a weird result.  If I take out the ! and just send the message as text and then add back the ! in the chat window it works.  But sending it like this doesn't work. on("change:attribute", function(obj, prev) {     if(obj.get("name") == "locked") {         charid = obj.get('_characterid');         arrtoken = findObjs({ type: 'graphic', represents: charid});         if (typeof arrtoken !== 'undefined' && arrtoken.length > 0) {             token = arrtoken[0];             tokenid = token.get('id');             sendChat('', '!token-mod --ids ' + tokenid + ' --set statusmarkers|!padlock');         }     }; });
Thanks G G!  First script worked.  Just had to fix a typo in markerName.  I missed the part where you could set statusmarkers in the API wiki but I see it now. 
1536094107
GiGs
Pro
Sheet Author
API Scripter
Oops, I see that typo now. Congrats on getting it working. I cant explain why the token-mod version didnt work, but i have seen that situation where you manually copy and paste a string to chat and it works, but sending the exact same string through sendChat doesn't. There can be some finicky behaviour with API scripts.
It's possible that TokenMod checks to see if the message was sent by a user and if a message is sent by the API then it is ignored.
1536101959
GiGs
Pro
Sheet Author
API Scripter
It's possible, but given that Aaron suggested using that approach above, it seems unlikely. But what would he know, anyway. ;)
1536104534
The Aaron
Pro
API Scripter
Nah, TokenMod doesn't care if the caller is the API.  It only uses the player data to determine if the command is being executed by a player or a GM.  That said, I've not really tried to do much with calling TokenMod with API scripts, other than the OnMyTurn script, and it works fine for that.
Just in case anyone else finds this later I'll post my final code.  I made it so you can control multiple checkboxes.  Just go into the case select part and change the attributes and status markers.  I also made it so you can call this with a macro instead.  Format is !toggle locked @{selected|character_id} where 'locked' is whatever attribute you want to change with that macro.  It will toggle the checkbox on your character sheet and also toggle the status marker. Just want to thank everyone on here.  The people who help out on this board are amazing.  This is the first script I've made from scratch and I didn't know any javascript a few months ago. on('change:attribute:current', function(obj) {     toggle(obj); }); function toggle(obj) {     var marker = '';     switch (obj.get('name')) {         case 'locked':             marker = 'status_padlock';             break;         case 'acquired':             marker = 'status_flying-flag';             break;         case 'aimed':             marker = 'status_archery-target';             break;         case 'loaded':             marker = 'status_sentry-gun';             break;     }     let char_id = obj.get('_characterid');     let value = obj.get('current');     let tokens = findObjs({ type: 'graphic', represents: char_id});     for (i = 0; i < tokens.length; ++i) {         tokens[i].set(marker, (value === '1' ? true: false) );    } }; on('chat:message', function(msg) {     if(msg.type == 'api' && msg.content.indexOf('!toggle') !== -1) {         let args = msg.content.split(' ');         let attr_name = args[1];         let char_id = args[2];         let obj = findObjs({ type: 'attribute', _characterid: char_id, name: attr_name, })[0];         let value = obj.get('current');                  if (value == 0) {             obj.set("current", '1');             toggle(obj);         }         else {             obj.set("current", '0');             toggle(obj);         }     } });
1536124761
GiGs
Pro
Sheet Author
API Scripter
Nicely done!