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

Getting an attribute number from a token controlled by a player

I am trying to come up with a script to manage the turnorder for my homebrew. I am working on a simple function which allow me to select a bunch of token and add it to the turnorder. I manage to add the selected token to the turnorder but I would like the initiative number to be based on a specific formula which utilises the character attributes. Is there a simple way for me to get for each token included in the selection the said token initiative attribute which correspond to the character ? I have tried to look a the group initiative script but I could not make sense of it.
1589065030
GiGs
Pro
Sheet Author
API Scripter
Asking a question on how to get Group Initiative working is probably the easiest solution - plenty of people use it and would be able to help you. Failing that, you can get the attributes of a character from their token, if the token is linked to a character of course. What is the code for your script at the moment? Actually, the simplest possible solution - since you're making a homebrew - would be to create an initiative attribute. Are you using a character sheet of your own creation? 
1589065882

Edited 1589066149
It's a custom charactersheet that I am building myself. I have created an attribute called "Initiative". This is the code I have come up so far var ProcessScript = function(argv, who, select) { if (argv[0]=="!add") { var turnorder; var ids=[]; ids = [...ids, ...select.map(o=>o._id)]; if(Campaign().get("turnorder") == "") turnorder = []; else turnorder = JSON.parse(Campaign().get("turnorder")); for(i in ids){ turnorder.push({ id: ids[i], pr: 15, custom: who }); Campaign().set("turnorder", JSON.stringify(turnorder)); } } } on("chat:message", function(msg) { // returns the chat window command entered, all in lowercase. var chatCommand = msg.content; chatCommand = chatCommand.toLowerCase(); var argv = chatCommand.split(' '); if (msg.type != 'api') { return; } return ProcessScript(argv, msg.who, msg.selected); }); When I select a bunch of token representing characters and I type !add, they get added to the turnorder.  select.map(o=>o._id  gives me the unique ID code for each token. Is it possible to use this to get the attribute Initiative instead of my hard coded "15" ?
1589069431
The Aaron
Roll20 Production Team
API Scripter
To get the value of an attribute for a character from a token, you would do something like: let initValue = getAttrByName(token.get('represents'),'initiative'); If you want the full blown attribute object, you could do: let initAttr = findObj({type:'attribute',name:'initiative',characterid:token.get('represents')})[0]; getAttrByName() is simpler and will always return a value (probably an empty string) even if the attribute doesn't exist. If you want to get GroupInitiative working with your game, it should be pretty easy.  You just need to configure it for the attribute to add and any dice you need to roll.  If you're rolling a d20 and adding the contents of initiative, you should just need to do: !group-init --add-group --bare initiative And then you just select them and run: !group-init Let me know if you need any help.
1589101252

Edited 1589110323
GiGs
Pro
Sheet Author
API Scripter
I notice a few issues in your script, so here's a version that should work. It's not as good as using group initiative, and requires you to manually enter how the initiative roll is made (tell us how you roll that, and I can tell you what needs changing). Launch it by typing !addturn , and you can add either sort  or sort+  if you want it sorted descending or ascending. /* Syntax     select a bunch of tokens, then type one of:     !addturn      !addturn sort     !addturn sort+          The first just adds the selected tokens to the turn tracker     the second does that, and sorts them from high to low     the last sorts from low to high */ on('ready', function () {     'use strict';     log('======= ADDTURN READY======');     const makeInitRoll = function(init) {         // we know init is a number, but roll20 thinks its a string, so convert it.         const initscore = +init;         // enter a roll function here, using randomInteger         const roll = randomInteger(20) + initscore;                  // return value to loop         return roll;     };     const buildTurnOrder = function (selected, sort = '') {         let turnorder= Campaign().get('turnorder') ? JSON.parse(Campaign().get('turnorder')) : [];         selected.forEach(obj => {             // check the current object is a token, who is linked to a character             const token = getObj(obj._type, obj._id);             const init = (!token.get('represents')) ? '' : getAttrByName(token.get('represents'),'initiative');             // for each character token found, where initiative is a number, add to turnorder             if('' !== init && !isNaN(init)) {                 // get actual initiative roll                 const initRoll = makeInitRoll(init);                 // need to check if current token is already in turn order                 const found = turnorder.findIndex(turn => turn.id == token.id);                 if(-1 === found) {                     turnorder.push({                         id: token.id,                         pr: initRoll                     });                 } else {                     turnorder[found] = {                         id: token.id,                          pr: initRoll                     };                 }             }         });                  // sort turnorder if needed         if(sort) {             turnorder = ('+' === sort.slice(-1)) ? turnorder.sort((a,b) => { return a.pr - b.pr; }) : turnorder.sort((a,b) => { return b.pr - a.pr; });         }          Campaign().set('turnorder', JSON.stringify(turnorder));              };     on('chat:message', function (msg) {         // returns the chat window command entered, all in lowercase.         if (!msg.type === 'api') return;         let args = msg.content.split(/\s+/); // handle if people accidentally enter two or more spaces         if (args[0].toLowerCase() === '!addturn') {             const selected = msg.selected;             if (!selected) {                 sendChat('Add Turn', '/w GM No Tokens selected.');                 return; //quit if nothing selected             }             const sort = args.findIndex(arg => arg.slice(0,4).toLowerCase() === 'sort');                          buildTurnOrder(selected, (sort > -1 ? args[sort] : ''));             sendChat('Add Turn', `/w GM Turn Order Updated.` );         }     }); });
Wow... thank you so much
1589110232
GiGs
Pro
Sheet Author
API Scripter
You're welcome. By the way, this line     log('======= ADDTURN READY======'); is only there because of how laggy the API is at the moment. While testing it, I kept thinking it wasnt working, but the sandbox was taking forever to start up. With that line, i can see in the log when it's ready :)
Thank you so much for this code...it has clarified so many thing for me. One addtional question: if  getAttrByName(token.get('represents'),'initiative');  gets you the value of an attribute, is there a way to change that value from the script directy ? The Aaron mentioned findObjs. How would that work ?
1589145542
GiGs
Pro
Sheet Author
API Scripter
You cant change it using getAttrByName: that just reads the data from the sheet. But there are functions like findObjs which give you an attribute object you can manipulate.  What's the use case? When would you change initiative score, and does it affect the turn order? I';ll show some code later (havent had breakfast yet!), but it would help to know the context you'll be using it.
Ultimately, what I am planing is going to be quite complex and that is why I cannot use group initiative. One thing I would like to try to do is to swap initative between caracters. As a proof of concept, the first step would be to change the initiative attribute of a character.
  Could someone give me a bit of a tutorial when it comes to using the findObjs function to extract the value of an attribute from a selected token ?   I have taken the code written by GiGs and modified it by replacing const init = (!token.get('represents')) ? '' : getAttrByName(token.get('represents'),'initiative'); by const init = (!token.get('represents')) ? '' : findObjs({type:'attribute', characterid:token.get('represents') , name:'initiative' }  [0]);   When I run it, I get an error. What am I doing wrong ?  How do you extract or set the value once you have found the object using FindObjs ?
1589301875

Edited 1589301916
The Aaron
Roll20 Production Team
API Scripter
Your array dereference is in the wrong spot: const init = (!token.get('represents')) ? '' : findObjs({type:'attribute', characterid:token.get('represents'), name:'initiative'}) [0] ; findObjs() returns an array, so this gets the 0th element of that array.  That means that init will either be the empty string '' or a Roll20 Attribute Object.  You can follow up the above with: if(init){ /* do something with roll20 attribute object */ } or if you just want to default it to the value 0, you could do: const init = (!token.get('represents')) ? 0 : (findObjs({type:'attribute', characterid:token.get('represents'), name:'initiative'})[0]||{get:()=>0}).get('current');
1589332508
GiGs
Pro
Sheet Author
API Scripter
Sorry I forgot about this Dungeon Master. notifications have been pretty overwhelming lately!