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

Call attributes depending on Rollable Table result

1558369846

Edited 1558375639
New thread since this is way off topic compared to my other one.  Still talking about Infinity RPG though. When you roll damage in this game, a d20 roll decides where on the body that damage is applied. This hit location leads into different Wound Effects, and it also carries a different armor attribute for different parts of the body.  Torso might be 4 Armor, while Head might be 3, Legs 2, etc.  This array could be anything for any character. Before digging into API for this, I made a simple weighted Rollable table that determined hit location, but of course that can’t also fetch something like @{target|Torso_Armor}.  So it seems I need to script the attribute grab. So the end goal would be: !armor t[HitLocation]  outputs the table result, plus the matching armor value for the Target Is anyone able to help with something like that? If it matters, the plan is to have the entire output be conditional on a ${hit} id equalling 1 or more. Hopefully this makes some sense... Thanks!
1558378262
The Aaron
Roll20 Production Team
API Scripter
If the distribution is always the same, you could omit passing the table roll and just calculate it from the API (either by doing a roll on the table asynchronously (annoying), or by loading the table weights in the api and use randomInteger() (how I'd do it)). !armor @{target|character_id} Then you'd just do the lookup in the api script, load the correct attribute, and report the character specific result. 
Okay... it looks like I actually figured it out as intended!  See below.  Uh, one weird thing: all the other results are normal, but Left Arm always outputs with a " :  Left Arm," adding the colon and some spaces.  Anyone know what I missed?  // wait till the ready event before registering a chat handler on('ready',()=>{     // register a function to run for chat messages     on('chat:message',(msg)=>{         // make sure the message is an api command, then verify it starts with !infdice          if('api'===msg.type && /^!infattack\b/i.test(msg.content)) {             // break into an array of arguments on spaces             let args=msg.content.split(/\s+/);             // grab the characger in the 2nd parameter (0 will be !infdice, 1 will be the inline roll, 2 will be the character id)             let c = getObj('character',args[1]);             // verify we got a character             if(c){                                  // get the character's Armor Attributes                 let torso = parseInt((findObjs({                     type: 'attribute',                     characterid: c.id,                     name: 'Torso_Soak'                 })[0]||{get:()=>-1}).get('current'));                                  let head = parseInt((findObjs({                     type: 'attribute',                     characterid: c.id,                     name: 'Head_Soak'                 })[0]||{get:()=>-1}).get('current'));                                  let leftarm = parseInt((findObjs({                     type: 'attribute',                     characterid: c.id,                     name: 'LA_Soak'                 })[0]||{get:()=>-1}).get('current'));                                  let rightarm = parseInt((findObjs({                     type: 'attribute',                     characterid: c.id,                     name: 'RA_Soak'                 })[0]||{get:()=>-1}).get('current'));                                  let leftleg = parseInt((findObjs({                     type: 'attribute',                     characterid: c.id,                     name: 'LL_Soak'                 })[0]||{get:()=>-1}).get('current'));                                  let rightleg = parseInt((findObjs({                     type: 'attribute',                     characterid: c.id,                     name: 'RL_Soak'                 })[0]||{get:()=>-1}).get('current'));                                  //Now to roll the table and match the results                               var x = randomInteger(20)              if (x === 1) location = "Head";               if (x === 2) location = "Head";              if (x === 3) location = "Right Arm";              if (x === 4) location = "Right Arm";              if (x === 5) location = "Right Arm";              if (x === 6) location = "Left Arm";              if (x === 7) location = "Left Arm";              if (x === 8) location = "Left Arm";              if (x === 9) location = "Torso";              if (x === 10) location = "Torso";              if (x === 11) location = "Torso";              if (x === 12) location = "Torso";              if (x === 13) location = "Torso";              if (x === 14) location = "Torso";              if (x === 15) location = "Right Leg";              if (x === 16) location = "Right Leg";              if (x === 17) location = "Right Arm";              if (x === 18) location = "Left Leg";              if (x === 19) location = "Left Leg";              if (x === 20) location = "Left Leg";                            if (location === "Head") armor = head;              if (location === "Torso") armor = torso;              if (location === "Right Arm") armor = rightarm;              if (location === "Left Arm") armor = leftleg;              if (location === "Right Leg") armor = rightleg;               if (location === "Left Leg") armor = leftleg;                             // output the location and attribute                 sendChat('',`${location} ${armor}`);             } else {                 // error for no matching character                 sendChat('',`No character found for id <code>${args[1]}</code>`);             }         }     }); });
1558414336
The Aaron
Roll20 Production Team
API Scripter
The : is probably just following the speaker's name, the first argument to sendChat(). Nice job getting a working script turned out so soon!  You shoukd probably update the comments as they've become stale.  
1558426700

Edited 1558426908
GiGs
Pro
Sheet Author
API Scripter
You've done really well. If you don't mind, I have a couple of suggestions to simplify your code. This section for instance includes some repetition you can remove:  var x = randomInteger(20)              if (x === 1) location = "Head";               if (x === 2) location = "Head";              if (x === 3) location = "Right Arm";              if (x === 4) location = "Right Arm";              if (x === 5) location = "Right Arm";              if (x === 6) location = "Left Arm";              if (x === 7) location = "Left Arm";              if (x === 8) location = "Left Arm";              if (x === 9) location = "Torso";              if (x === 10) location = "Torso";              if (x === 11) location = "Torso";              if (x === 12) location = "Torso";              if (x === 13) location = "Torso";              if (x === 14) location = "Torso";              if (x === 15) location = "Right Leg";              if (x === 16) location = "Right Leg";              if (x === 17) location = "Right Arm";              if (x === 18) location = "Left Leg";              if (x === 19) location = "Left Leg";              if (x === 20) location = "Left Leg";                            if (location === "Head") armor = head;              if (location === "Torso") armor = torso;              if (location === "Right Arm") armor = rightarm;              if (location === "Left Arm") armor = leftleg;              if (location === "Right Leg") armor = rightleg;               if (location === "Left Leg") armor = leftleg; Like so: //Now to roll the table and match the results var x = randomInteger(20) if (x <= 2) { location = "Head"; armor = head; } else if (x <= 5) { location = "Right Arm"; armor = rightarm; } else if (x <= 8) { location = "Left Arm"; armor = leftarm; } else if (x <= 14) { location = "Torso"; armor = torso; } else if (x <= 17) { location = "Right Arm"; armor = rightleg; } else { location = "Left Leg"; armor = leftleg; } Using <, >, <=, and >= can shorten a lot of if statements of this sort, but you have to be careful to build them correctly. Expressions of this form: If {something) else (something) will stop at the first matching result, is if you starting at the bottom of the table use < and if starting at the top of the range use >. By the way, i noticed your code has a typo, look at  if (location === "Left Arm") armor = leftleg; Another tip is when you find yourself doing the same thing over and over, use a function to simplify it. For example this is repeated:             let torso = parseInt((findObjs({                     type: 'attribute',                     characterid: c.id,                     name: 'Torso_Soak'                 })[0]||{get:()=>-1}).get('current')); You can create a function like (this isn't finished, but I;ll walk you through the steps: const getLocation = function() {                   let location = parseInt((findObjs({ type: 'attribute',       characterid: c.id,       name: 'Torso_Soak'   })[0]||{get:()=>-1}).get('current'));   return location; }; If you placed that in your script just after the on('ready') and before on(change) you could then call it later with let torso = getLocation(); The problem is it wont work, because of this line       characterid: c.id, It's using a variable that doesnt exist in that function. So you need a way to pass the c.id value from the main body to it. You do that by changing the function like so: const getLocation = function( id ) {                 // we declare a parameter here, similar to creating variables   let location = parseInt((findObjs({ type: 'attribute',       characterid: id,             // and we use the parameter here.       name: 'Torso_Soak'   })[0]||{get:()=>-1}).get('current'));   return location; }; And then you call it like so let torso = getLocation(c.id); In this way you send the c.id value to the function. The id parameter in that function accepts the c.id value and uses it wherever id is in the function. Now thats not very useful yet. It still only returns the torso location. But we can use the same technique to make it reusable. const getLocation = function(id, choice ) {                   let location = parseInt((findObjs({ type: 'attribute',       characterid: id,       name: choice   })[0]||{get:()=>-1}).get('current'));   return location; }; Here we add a second parameter, choice, which will hold the location we want to get. Now we can call it with let torso = getLocation(c.id, 'Torso_Soak'); let head = getLocation(c.id, 'Head_Soak'); let leftarm = getLocation(c.id, 'LA_Soak'); let rightarm = getLocation(c.id, 'RA_Soak'); let leftleg = getLocation(c.id, 'LL_Soak'); let rightleg = getLocation(c.id, 'RL_Soak'); But there's at least one more optimisation we can do. In the above code we call all 6 location attributes, but we actually only need one of them. The revised code below only calls the one we need.  // wait till the ready event before registering a chat handler on('ready', () => { // create a function to return attribute value, given character id and attribute name. const getLocation = function(id, choice) { let location = parseInt((findObjs({ type: 'attribute', characterid: id, name: choice })[0] || { get: () => -1 }).get('current')); return location; }; // register a function to run for chat messages on('chat:message', (msg) => { // make sure the message is an api command, then verify it starts with !infdice if ('api' === msg.type && /^!infattack\b/i.test(msg.content)) { // break into an array of arguments on spaces let args = msg.content.split(/\s+/); // grab the characger in the 2nd parameter let c = getObj('character', args[1]); // verify we got a character if (c) { //Now to roll the table and match the results // and we grab the location armour only after we know which one we need.                 let location, armor; //initialize these variables, we;ll need them later var x = randomInteger(20) if (x <= 2) { location = "Head"; armor = getLocation(c.id, 'Head_Soak'); } else if (x <= 5) { location = "Right Arm"; armor = getLocation(c.id, 'RA_Soak'); } else if (x <= 8) { location = "Left Arm"; armor = getLocation(c.id, 'LA_Soak'); } else if (x <= 14) { location = "Torso"; armor = getLocation(c.id, 'Torso_Soak'); } else if (x <= 17) { location = "Right Arm"; armor = getLocation(c.id, 'RL_Soak'); } else { location = "Left Leg"; armor = getLocation(c.id, 'LL_Soak'); } // output the location and attribute sendChat('', `${location} ${armor}`); } else { // error for no matching character sendChat('', `No character found for id <code>${args[1]}</code>`); } } }); }); Hope you find this useful in your future coding!
Oh, wow, that's a brain bender... but yes, I think I understand.  I knew it felt silly putting in all those individual results.  Again, thank you so much!