Advertisement Create a free account

Set token values with a script

1523911738

Edited 1523911781
Jedd
KS Backer
Marketplace Creator
I've never made an API script before and don't know very much javascript, so I wanted to see if someone here could point me in the right direction. What I want to achieve with a script is when I create a monster with the SIZE attribute set to "LARGE", to create/update an attribute called MIT set to "d10". The purpose of this is for use within my special initiative system, where monsters move based upon their size. It looks like this: Tiny | d4 Small | d6 Medium | d8 Large | d10 Huge | d12 Gargantuan | d20 Any help would be appreciated!
1523913360

Edited 1523915498
The Aaron
Pro
API Scripter
Ok.  First, you'd need to know when to make/set that attribute, which means an event.  It's best to wrap your scripts in the "ready" event anyway, just to create a separate namespace, but in this case it's vitally important so that your events don't run for every single character on startup as the add events are issued for all those attributes: // ready event happens after the API has loaded all the objects on('ready',()=>{ // function to call on changed/added attributes const checkAttribute = (obj,prev) => { }; // register the above function to be called when an attribute is added or changed. on('add:attribute', checkAttribute); on('change:attribute', checkAttribute); }); That's the bare bones of where to start, now for the actual details of the function: on('ready',()=>{ const checkAttribute = (obj,prev) => { // obj will be the created or modified attribute object. (a Roll20 Object) // prev will be the properties the object had before being changed. (a simple JS object) // Roll20 objects have their properties accessed with the .get() function, // which takes the property name as an argument // /^size$/i is a regular expression that matches (case insensitive) // the word "size" with no leading or trailing whitespace. if(/^size$/i.test(obj.get('name'))){ // In here, we know we have the right object // next we need to get or create the attribute for MIT. // findObjs() will return an array of matching Roll20 Objects or the empty array []. // The one we want will be the first one (index 0). If it wasn't found, this index will // contain undefined, which is "falsy". // || is the Javascript boolean OR, which "short circuits", meaning the second half won't // execute if the first half was "truthy", which the Roll20 object would be. // createObj() will then get executed if we didn't find the object, creating an attribute // named "MIT" and returning it. // The practical upshot being that this will find or create the MIT attribute for the character. let mit = findObjs({type:'attribute',name:'MIT',characterid: obj.get('characterid')})[0] || createObj('attribute',{name:'MIT', characterid: obj.get('characterid')}); // switch() is a nice way to do things for certain values. The case that matches will then // get executed. // obj.get('current') will return the value in the attribute, .toLowerCase() will guarantee it // matches if it somehow ends up capitalized differently. switch(obj.get('current').toLowerCase()){ // if the current is "tiny", it will set mit's current to 'd4', then break out of the switch. // Roll20 objects' properties are set with the .set() function, which comes in two forms: // .set(property, value) -- first argument is what to change, second is what to set it to. // .set({property: value}) -- only argument is a key/value mapping from properties to values, // which is useful if you're changing several properties at once. case 'tiny': mit.set('current','d4'); break; case 'small': mit.set('current','d6'); break; case 'medium': mit.set('current','d8'); break; case 'large': mit.set('current','d10'); break; case 'huge': mit.set('current','d12'); break; case 'gargantuan': mit.set('current','d20'); break; } } }; on('add:attribute', checkAttribute); on('change:attribute', checkAttribute); }); That should be basically it.  Cleared of comments: on('ready',()=>{ const checkAttribute = (obj,prev) => { if(/^size$/i.test(obj.get('name'))){ let mit = findObjs({type:'attribute',name:'MIT',characterid: obj.get('characterid')})[0] || createObj('attribute',{name:'MIT', characterid: obj.get('characterid')}); switch(obj.get('current').toLowerCase()){ case 'tiny': mit.set('current','d4'); break; case 'small': mit.set('current','d6'); break; case 'medium': mit.set('current','d8'); break; case 'large': mit.set('current','d10'); break; case 'huge': mit.set('current','d12'); break; case 'gargantuan': mit.set('current','d20'); break; } } }; on('add:attribute', checkAttribute); on('change:attribute', checkAttribute); }); Hope that helps!  I didn't test this or anything, but it should be right?
1523917440

Edited 1523917590
The Aaron
Pro
API Scripter
Ok, now I have tested it and fixed the only bug.  I'm always leaving the "s" off of findObjs(). =D   BTW, if you're watching the Attributes and Abilities tab, you won't see the MIT attribute get added, but if you close and reopen the character, you can watch it get changed.
1523976527
Jedd
KS Backer
Marketplace Creator
This is more than I was expecting! Thanks Aaron!
1523976914
The Aaron
Pro
API Scripter
No problem, I love teaching the API, so feel free to ask me ANYTHING about it. =D  Well, really I'll talk about just about anything...  =D