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

Custom Roll Parsing - identifying nth highest value

Not sure of the best approach and keep going back and forth trying find one I can make work. I have the following sheetworker to perform a roll from an action button: on(`clicked:roll`, () => {     getAttrs(['ndice'], v=> {             startRoll(`&{template:roll} {{PC=@{character_name}}} {{roll=[[4d12]]}} {{no=[[0]]}}`, (roller) => {                 const dice = roller.results.roll.result                 finishRoll(                     roller.rollId,                     {                         no: (+v.ndice || 0)                     }                 );                 setAttrs({                     low:                      mid:                      high:                  });             });         });     }); The button is called 'roll' and 'ndice' is always a number from 1 to 4. 'no' is just the number of dice to be outputted in the rolltemplate and not relevant to this query. So what I need it to do is: – identify the lowest value rolled and set the 'low' attribute to this value – identify the second lowest value rolled and set the 'mid' attribute to this value – identify the third lowest value rolled and set the 'high' attribute to this value However, it should only look at as many values as 'ndice' is set to and disregard the others. E.g. If the values rolled were 7, 6, 3, 9 and 'ndice' was set to 2 then low = 6 because the 3 and the 9 are irrelevant. If there aren't enough dice being rolled to have a second or third lowest then it doesn't matter what 'mid' and 'high' get set to. How can I go about this? I set the roller to always roll four dice because I thought it would be harder (or maybe impossible) to write code that could cope with referring to dice values that aren't there. Would would it actually be more feasible to have the roller only roll the required number of dice? I also wondered if it might be easier to have four separate rolls of 1d12 each.
1674851269

Edited 1674859516
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
The dice results are just an array, so you can use ordering and sorting to handle this (untested): on(`clicked:roll`, () => { getAttrs(['ndice'], v => { startRoll(`&{template:roll} {{PC=@{character_name}}} {{roll=[[4d12]]}} {{no=[[0]]}}`, (roller) => { const dice = roller.results.roll.dice; //Extract the dice array v.ndice = +v.ndice || 1; //convert ndice to a number type const validDice = dice .slice(0,v.ndice - 1) //Get the first ndice dice .sort((a,b) => a - b);//Sort the array lowest - highest finishRoll( roller.rollId, { no: (+v.ndice || 0) } ); setAttrs({ // Assign the values based on their index // lowest is first, etc. // Put a fallback of an empty string in for if there is no number at that index. low:validDice[0] || '', mid:validDice[1] || '', high: validDice[2] || '' }); }); }); }); Edit: fixed error in the Alice that would have grabbed to many dice.
1674852632

Edited 1674852994
GiGs
Pro
Sheet Author
API Scripter
Ignore this post - I miread and answered the wrong question. See the next post. I would have done it slightly differently with the same result. One of the beauties of programming is that you can reach the same result in multiple ways usually.This is not a disagreement with Scott, just showing a different method. I will point out that you can use any number of dice - you aren't limited to 4. But the tricky part is getting the middle value. lets say you have dice rolls of 1, 5, 6, 10 - which one is the middle value? I'd start almost the same way as Scott: const dice = roller.results.roll.dice; //Extract the dice array const ndice = +v.ndice || 1; //convert ndice to a number type The key here is to get the dice array out of the roll, not the result. To get the high and low values is easy:      const low = Math . min (... dice );     const high = Math . max (... dice ); The middle value is the tricky part. The way I first thought of doing it:      const sorted = dice . sort ( ( a , b ) => a - b );     const index = Math . floor ( sorted . length / 2 );     const middle = dice [ index ] But this does have an inbuilt bias for even numbers of dice. In the above examol4e [1,5,6,10] it would report the middle result as 5. Scott's suggestion of putting empty strings - or something  - in there to acount for invalid dice arrays is a good idea too.
1674852918

Edited 1674967525
GiGs
Pro
Sheet Author
API Scripter
I just reread the question and realised I answered the wrong question. This is how I'd do it (with the proviso that again, you can account for any number of dice, but need to handle what happens if you have fewer than 3 dice):      const dice = roller . results . roll . dice ;     const sorted = dice . sort (( a , b ) => a - b );     const low = sorted [ 0 ];     const middle = sorted [ 1 ];     const high = sorted [ 2 ];
1674859723

Edited 1674859920
Scott C.
Forum Champion
Sheet Author
API Scripter
Compendium Curator
Also, I just saw your final question. If you don't have to always roll 4 dice, then yes, I'd recommend having it roll just what is needed. Doing that would look like: on(`clicked:roll`, () => {   getAttrs(['ndice'], v => {     startRoll(`&{template:roll} {{PC=@{character_name}}} {{roll=[[${v.ndice}d12]]}} {{no=[[0]]}}`, (roller) => {       const dice = roller.results.roll.dice; //Extract the dice array       v.ndice = +v.ndice || 1; //convert ndice to a number type       const validDice = dice         .sort((a,b) => a - b);//Sort the array lowest - highest       finishRoll(         roller.rollId,         {           no: (+v.ndice || 0)         }       );       setAttrs({         // Assign the values based on their index         // lowest is first, etc.         // Put a fallback of an empty string in for if there is no number at that index.         low:validDice[0] || '',         mid:validDice[1] || '',         high: validDice[2] || ''       });     });   }); });
Fantastic, works perfectly. Thanks both!!