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 API to Edit Attribute Values

1380907860
Stephen Koontz
Forum Champion
Marketplace Creator
Sheet Author
API Scripter
Compendium Curator
Alright, I’m stuck on syntax. I pulled the below nuggets right off the API: Objects page and tweaked some names for my use. I’m trying to pull the character journal associated with the currently selected token so that I can reference and update an attribute. But every time I use it I get the following error [ReferenceError: obj is not defined at Sandbox.<anonymous> (evalmachine.<anonymous>:74:42) at eval (] Code that is failing: var oCharacter = getObj("character", obj.get("represents")); var oHealth = findObjs({_type: "attribute", name: "Bashing", _characterid: oCharacter.id}); Also, once I have the reference above working, what syntax do I use to change that attribute? Can I just say: oHealth.set("current", damage); Thank you for your help.
var oCharacter = getObj("character", obj.get("represents")); var oHealth = findObjs({name: "Bashing",_type: "attribute",_characterid: Character.id}, {caseInsensitive: true})[0]; The key is the [0]; at the end.
1380910444
Stephen Koontz
Forum Champion
Marketplace Creator
Sheet Author
API Scripter
Compendium Curator
Ok. I copied and pasted it exactly and am still getting the same error. Does the [0] default the value to 0 if no value is returned? Is that what that does? Either way I'm still getting the same error. Here is the whole of my code. It runs as intended if I comment everything in between my TEST_TEST_TEST area. However, when I uncomment the 2 var lines I get the error. on('chat:message', function(msg) { if(msg.type != 'api') return; var parts = msg.content.toLowerCase().split(' '); var command = parts.shift().substring(1); var selected = msg.selected; if(command != 'b' || !selected) return; // use the !b command, and have one or more things selected var damage = +parts[0]; if(!damage) damage = 0; // if no damage is returned, treat as 0 //TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST var oCharacter = getObj("character", obj.get("represents")); var oHealth = findObjs({name: "Bashing",_type: "attribute",_characterid: Character.id}, {caseInsensitive: true})[0]; //if (oBashing.current !== "") {oBashing.current == damage}; //sendChat(msg.who, "" + oCharacter) //sendChat(msg.who, "" + oHealth) //sendChat(msg.who, "" + damage); //TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST _.each(selected, function(obj) { if(obj._type != 'graphic') return; // only damage graphics var tok = getObj('graphic', obj._id); if(tok.get('subtype') != 'token') return; // don't try to damage cards tok.set('status_fist', false); var dmgicon = ''; while(damage > 0) { // get current digit, starting from ones var digit = damage / 10; digit -= Math.floor(digit); digit = Math.round(digit * 10); // shift damage damage = Math.floor(damage / 10); dmgicon += 'fist@'+digit+','; } if(dmgicon.length > 0) dmgicon = dmgicon.substring(0, dmgicon.length - 1); // trim trailing comma var markers = tok.get('statusmarkers'); if(markers != '') markers += ','; markers += dmgicon; tok.set('statusmarkers', markers); }); });
You're not defining what obj is when you do obj.get("represents").
1380910914
Stephen Koontz
Forum Champion
Marketplace Creator
Sheet Author
API Scripter
Compendium Curator
Two questions. In your first snippet of code. Shouldn't the line: var oHealth = findObjs({name: "Bashing",_type: "attribute",_characterid: Character.id}, {caseInsensitive: true})[0]; Actually be: var oHealth = findObjs({name: "Bashing",_type: "attribute",_characterid: o Character.id}, {caseInsensitive: true})[0]; And as for defining obj.get("represents"), can you give me an example. I think I'm failing to conceptually understand. I thought get obj.get was defined by the object selected in roll20.
Yeah, it should have been oCharacter. I just forgot to add that o in front. obj has to be defined by you or a function. It's not just automatically defined. For example, when you do: _.each(selected, function(obj) { ...you're defining obj.
1380912670
Stephen Koontz
Forum Champion
Marketplace Creator
Sheet Author
API Scripter
Compendium Curator
Ok. Thanks for the info. I think I understand. I moved my test region inside _.each(selected, function(obj) { which I'm assuming is designating every object select in roll20 as obj. However, it spits out the following error: TypeError: Object [object Object] has no method 'get' at evalmachine. :74:46 at Array.forEach (native) at Function._.each._.forEach (/home/symbly/www/d20-api-server/sandcastle/node_modules/underscore/underscore.js:78:11) at Sandbox. (evalmachine. :69:7) at eval ( It's saying the obj can't .get. I'm not sure what I'm missing because the object selected is a token and should be .get-able. Code: on('chat:message', function(msg) { if(msg.type != 'api') return; var parts = msg.content.toLowerCase().split(' '); var command = parts.shift().substring(1); var selected = msg.selected; if(command != 'b' || !selected) return; // use the !b command, and have one or more things selected var damage = +parts[0]; if(!damage) damage = 0; // if no damage is returned, treat as 0 _.each(selected, function(obj) { if(obj._type != 'graphic') return; // only damage graphics var tok = getObj('graphic', obj._id); if(tok.get('subtype') != 'token') return; // don't try to damage cards //TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST var oCharacter = getObj("character", obj.get("represents")); var oHealth = findObjs({name: "Bashing",_type: "attribute",_characterid: oCharacter.id}, {caseInsensitive: true})[0]; //if (oBashing.current !== "") {oBashing.current == damage}; //sendChat(msg.who, "" + damage); //TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST_TEST tok.set('status_fist', false); var dmgicon = ''; while(damage > 0) { // get current digit, starting from ones var digit = damage / 10; digit -= Math.floor(digit); digit = Math.round(digit * 10); // shift damage damage = Math.floor(damage / 10); dmgicon += 'fist@'+digit+','; } if(dmgicon.length > 0) dmgicon = dmgicon.substring(0, dmgicon.length - 1); // trim trailing comma var markers = tok.get('statusmarkers'); if(markers != '') markers += ','; markers += dmgicon; tok.set('statusmarkers', markers); }); });
This works... you can figure it out from here I think: _.each(selected, function(obj) { if(obj._type != "graphic") return; var oToken = getObj("graphic", obj._id); var oCharacter = getObj("character", oToken.get("represents")); var oHealth = findObjs({name: "Bashing",_type: "attribute", _characterid: oCharacter.id}, {caseInsensitive: true})[0]; log(oToken); log(oCharacter); log(oHealth); }); });
1380923270
Lithl
Pro
Sheet Author
API Scripter
Stephen K. said: Ok. I copied and pasted it exactly and am still getting the same error. Does the [0] default the value to 0 if no value is returned? Is that what that does? No. The findObjs function returns an array. [0] selects the first element in the array. Presumably, a given character will only have one attribute named Bashing, so there's no reason to loop through all of the results; you're only expecting one result. Stephen K. said: Ok. Thanks for the info. I think I understand. I moved my test region inside _.each(selected, function(obj) { which I'm assuming is designating every object select in roll20 as obj. However, it spits out the following error: TypeError: Object [object Object] has no method 'get' at evalmachine.:74:46 at Array.forEach (native) at Function._.each._.forEach (/home/symbly/www/d20-api-server/sandcastle/node_modules/underscore/underscore.js:78:11) at Sandbox. (evalmachine.:69:7) at eval ( It's saying the obj can't .get. I'm not sure what I'm missing because the object selected is a token and should be .get-able. The problem is that the variable `obj' defined as the anonymous function parameter in the each function call is not , in fact, a reference to a token. The `selected' array contains objects which each have two properties: `_id' and `_type'. You need to use getObj (as in HB's code above) in order to get a token object, which you can then call get on.
1380997177

Edited 1380998198
Stephen Koontz
Forum Champion
Marketplace Creator
Sheet Author
API Scripter
Compendium Curator
@Brian, thanks for the information. Does that mean in my example, that my array is all selected objects and the [0] would just use whichever one was placed in the array first? @Honey Badger, You're kind of a bad ass. I was able to get it to work and change the attributes in conjunction with the token. Your examples really helped me figure it out conceptually and syntactically. Thank you for all your help.
1381011314
Lithl
Pro
Sheet Author
API Scripter
Stephen K. said: @Brian, thanks for the information. Does that mean in my example, that my array is all selected objects and the [0] would just use whichever one was placed in the array first? No. findObjs in your code is giving you an array of all objects with the name "Bashing", the type "attribute", and which are attached to the character represented by `oCharacter'. That should be an array of length 1, because a character shouldn't have multiple attributes named Bashing. "[0]" returns the first element of the array returned by findObjs , which is then set to `oHealth'. The array of selected objects is being looped through using the each function. You use the array indexer earlier in your code, too, with the `parts' array. "parts[0]" gives you the first argument to your API call (since you called shift earlier, removing the API command from the array and shifting all of the other elements of the array towards the front).