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

[Help] Script help with secret rolls and initiative rolls using Earthdawn Step system

1425417176

Edited 1425417520
I got the following code from another thread and made some minor modifications: on("chat:message", function(msg) { // looks for !~ and converts it to Earthdawn Step dice. if(msg.type == "api" && msg.content.indexOf("!step") !== -1) { var stepNum = eval(msg.content.replace("!step", " ")); if (stepNum < 2){ sendChat(msg.who, "Step 1"); sendChat(msg.who, "/r 1d4!-2"); } else if (stepNum === 2){ sendChat(msg.who, "Step 2"); sendChat(msg.who, "/r 1d4!-1"); } else if (stepNum === 3){ sendChat(msg.who, "Step 3"); sendChat(msg.who, "/r 1d4!"); } ... else { sendChat(msg.who, "Step Number " + stepNum + " is not valid"); } } }); Essentially in Earthdawn you roll a set of exploding dice depending on a step number. The code goes to step 40 but I just cut out the middle. It works great for standard rolls. I'll probably clean up the code a bit more but it is functional. From here I can throw it into macros if I want. Easy enough. But I want two more versions of this basic idea and I really don't know where to start. First I want a version where the result is shown only to me (the GM). I don't need to see the full die roll laid out, just the resulting number. More specifically I want players to initiate the roll but have the result only visible to the GM. I think /gmroll displays to the player and GM so that isn't quite what I want. I'm guessing that I need to store the result in a variable instead of using sendChat and then "/w gm "+result but perhaps that is the dumb way to do things and it isn't clear to me how to store the result of an exploding die roll in a variable without going to the chat window. Second I want to roll the step die and use that for initiative. Adding &{tracker} to the end of the roll didn't work. I've looked at more complex initiative scripts but they seem to be doing a lot of stuff so I'm not sure where the initiative piece is happening. It seems like I need to again store the result in a variable and pass that variable into a function. But which function and how to store that variable I don't know. I don't know javascript at all but I am familiar with scripting in general but I am having a hard time figuring out what functions form the API I should be employing to do this stuff. Any help would be greatly appreciated!
1425418679

Edited 1425418749
The Aaron
Pro
API Scripter
For 1), I'd probably use inline syntax, so your sendChat() would look like: sendChat(msg.who, "/w gm [[ 1d4!-2]]"); For 2), initiative, you can just add the &tracker in: sendChat(msg.who, "Initiative: [[ 1d4!-2 &tracker]]"); There are probably quite a few optimizations we could help you make to your script if you post the full one. For example, it looks like the progression of steps is pretty linear, so you might be able to replace all the if/elses with something like: sendChat(msg.who, 'Step '+ stepNum); sendChat(msg.who, ' [[ 1d4! + (' + (parseInt(stepNum,10)-3) + ') ]]"); Then you could check which command was executed: on('ready',function(){ "use strict"; on('chat:message', function(msg){ var args = msg.content.split(/\s+/), prefix = '', postfix = '', stepNum; if('api' !== msg.type) { return; } switch(args.shift()) { case '!step': break; case '!gstep': prefix='/w gm '; break; case '!istep': postfix=' &{tracker}'; break; default: return; } stepNum=parseInt(args.shift(),10); if(stepNum >= 1 && stepNum <= 40) { sendChat(msg.who, prefix+'Step '+ stepNum + '<br>' +' [[ 1d4! + (' + (stepNum-3) + ') '+postfix+']]'); } else { sendChat(msg.who, prefix+'<b>Error:</b> Step Number '+stepNum+' is not valid!'); } }); }); Something vaguely like that. That gets you all three commands with limited lines of code, assuming the formula proceeds linearly as it seems to. Note, it's a good idea to avoid eval() when you have alternatives (and you pretty much always do). Also, it's best to check if a message is an API message before continuing to process it. That avoids processing when you type some like "/w newguy You need to use '!step 3' to do your exploding rolls."
1425419252
The Aaron
Pro
API Scripter
Chris W. said: I think /gmroll displays to the player and GM so that isn't quite what I want. Just wanted to point out that /gmroll does display to the player and the GM when the player initiates it, but I'm pretty sure when the API initiates it, only the GM sees it because the "player" in question is the API.
Nice, looking at your code there I definitely see a better way to do it even if I can't figure out how to determine the exact die roll with an algorithm. Unfortunately the step system isn't terribly linear, it does eventually hit a repeating pattern, here's the full code: on("chat:message", function(msg) { // looks for !~ and converts it to Earthdawn Step dice. if(msg.type == "api" && msg.content.indexOf("!step") !== -1) { var stepNum = eval(msg.content.replace("!step", " ")); if (stepNum < 2){ sendChat(msg.who, "Step 1"); sendChat(msg.who, "/r 1d4!-2"); } else if (stepNum === 2){ sendChat(msg.who, "Step 2"); sendChat(msg.who, "/r 1d4!-1"); } else if (stepNum === 3){ sendChat(msg.who, "Step 3"); sendChat(msg.who, "/r 1d4!"); } else if (stepNum === 4){ sendChat(msg.who, "Step 4"); sendChat(msg.who, "/r 1d6!"); } else if (stepNum === 5){ sendChat(msg.who, "Step 5"); sendChat(msg.who, "/r 1d8!"); } else if (stepNum === 6){ sendChat(msg.who, "Step 6"); sendChat(msg.who, "/r 1d10!"); } else if (stepNum === 7){ sendChat(msg.who, "Step 7"); sendChat(msg.who, "/r 1d12!"); } else if (stepNum === 8){ sendChat(msg.who, "Step 8"); sendChat(msg.who, "/r 2d6!"); } else if (stepNum === 9){ sendChat(msg.who, "Step 9"); sendChat(msg.who, "/r 1d8!+1d6!"); } else if (stepNum === 10){ sendChat(msg.who, "Step 10"); sendChat(msg.who, "/r 2d8!"); } else if (stepNum === 11){ sendChat(msg.who, "Step 11"); sendChat(msg.who, "/r 1d10!+1d8!"); } else if (stepNum === 12){ sendChat(msg.who, "Step 12"); sendChat(msg.who, "/r 2d10!"); } else if (stepNum === 13){ sendChat(msg.who, "Step 13"); sendChat(msg.who, "/r 1d12!+1d10!"); } else if (stepNum === 14){ sendChat(msg.who, "Step 14"); sendChat(msg.who, "/r 2d12!"); } else if (stepNum === 15){ sendChat(msg.who, "Step 15"); sendChat(msg.who, "/r 1d12!+2d6"); } else if (stepNum === 16){ sendChat(msg.who, "Step 16"); sendChat(msg.who, "/r 1d12!+1d8!+1d6!"); } else if (stepNum === 17){ sendChat(msg.who, "Step 17"); sendChat(msg.who, "/r 1d12!+2d8!"); } else if (stepNum === 18){ sendChat(msg.who, "Step 18"); sendChat(msg.who, "/r 1d12!+1d10!+1d8!"); } else if (stepNum === 19){ sendChat(msg.who, "Step 19"); sendChat(msg.who, "/r 1d20!+2d6!"); } else if (stepNum === 20){ sendChat(msg.who, "Step 20"); sendChat(msg.who, "/r 1d20!+1d8!+1d6!"); } else if (stepNum === 21){ sendChat(msg.who, "Step 21"); sendChat(msg.who, "/r 1d20!+2d8!"); } else if (stepNum === 22){ sendChat(msg.who, "Step 22"); sendChat(msg.who, "/r 1d20!+1d10!+1d8!"); } else if (stepNum === 23){ sendChat(msg.who, "Step 23"); sendChat(msg.who, "/r 1d20!+2d10!"); } else if (stepNum === 24){ sendChat(msg.who, "Step 24"); sendChat(msg.who, "/r 1d20!+1d12!+1d10!"); } else if (stepNum === 25){ sendChat(msg.who, "Step 25"); sendChat(msg.who, "/r 1d20!+2d12!"); } else if (stepNum === 26){ sendChat(msg.who, "Step 26"); sendChat(msg.who, "/r 1d20!+1d12!+2d6!"); } else if (stepNum === 27){ sendChat(msg.who, "Step 27"); sendChat(msg.who, "/r 1d20!+1d12!+1d8!+1d6!"); } else if (stepNum === 28){ sendChat(msg.who, "Step 28"); sendChat(msg.who, "/r 1d20!+1d12!+2d8!"); } else if (stepNum === 29){ sendChat(msg.who, "Step 29"); sendChat(msg.who, "/r 1d20!+1d12!+1d10!+1d8!"); } else if (stepNum === 30){ sendChat(msg.who, "Step 30"); sendChat(msg.who, "/r 2d20!+2d6!"); } else if (stepNum === 31){ sendChat(msg.who, "Step 31"); sendChat(msg.who, "/r 2d20!+1d8!+1d6!"); } else if (stepNum === 32){ sendChat(msg.who, "Step 32"); sendChat(msg.who, "/r 2d20!+2d8!"); } else if (stepNum === 33){ sendChat(msg.who, "Step 33"); sendChat(msg.who, "/r 2d20!+1d10!+1d8!"); } else if (stepNum === 34){ sendChat(msg.who, "Step 34"); sendChat(msg.who, "/r 2d20!+2d10!"); } else if (stepNum === 35){ sendChat(msg.who, "Step 35"); sendChat(msg.who, "/r 2d20!+1d12!+1d10!"); } else if (stepNum === 36){ sendChat(msg.who, "Step 36"); sendChat(msg.who, "/r 2d20!+2d12!"); } else if (stepNum === 37){ sendChat(msg.who, "Step 37"); sendChat(msg.who, "/r 2d20!+1d12!+2d6!"); } else if (stepNum === 38){ sendChat(msg.who, "Step 38"); sendChat(msg.who, "/r 2d20!+1d12!+1d8!+1d6!"); } else if (stepNum === 39){ sendChat(msg.who, "Step 39"); sendChat(msg.who, "/r 2d20!+1d12!+2d8!"); } else if (stepNum === 40){ sendChat(msg.who, "Step 40"); sendChat(msg.who, "/r 1d20!+1d12!+1d10!+1d8!"); } else { sendChat(msg.who, "Step Number " + stepNum + " is not valid"); } } });
1425420589
Gen Kitty
Forum Champion
I know the 'only to the gm' stuff works, because Honeybadger's 'Powercards' script has that functionality. You might go peer at his code and see how he does it. Or someone might drop by and explain how it works. In the meantime, check out "JavaScript: The Good Parts", a book by Douglas Crockford. Good luck with your scripting!
1425420661
Gen Kitty
Forum Champion
I knew I should have reloaded this tab before replying. I still snuck in the book reference before T'he Aaron, so that's something ^_-
1425423397
The Aaron
Pro
API Scripter
Hahaha, yeah, I usually wait a few posts befor I throw that in. :)
1425438335
The Aaron
Pro
API Scripter
So, to handle those multiple formats, it's probably easiest to use an array of possible rows and index into it with the step number. I had a "Duh" moment earlier when I realized that &{tracker} won't work from the API for almost the same reason that /groll doesn't. That means it's significantly more complicated to get initiative rolls working... ... ok, I'd do it like this (Don't tell GenKitty...): on('ready',function(){ "use strict"; var stepRolls = [ '1d4!-2' , '1d4!-1' , '1d4!' , '1d6!' , '1d8!' , '1d10!' , '1d12!' , '2d6!' , '1d8!+1d6!' , '2d8!' , '1d10!+1d8!' , '2d10!' , '1d12!+1d10!' , '2d12!' , '1d12!+2d6' , '1d12!+1d8!+1d6!' , '1d12!+2d8!' , '1d12!+1d10!+1d8!' , '1d20!+2d6!' , '1d20!+1d8!+1d6!' , '1d20!+2d8!' , '1d20!+1d10!+1d8!' , '1d20!+2d10!' , '1d20!+1d12!+1d10!' , '1d20!+2d12!' , '1d20!+1d12!+2d6!' , '1d20!+1d12!+1d8!+1d6!' , '1d20!+1d12!+2d8!' , '1d20!+1d12!+1d10!+1d8!' , '2d20!+2d6!' , '2d20!+1d8!+1d6!' , '2d20!+2d8!' , '2d20!+1d10!+1d8!' , '2d20!+2d10!' , '2d20!+1d12!+1d10!' , '2d20!+2d12!' , '2d20!+1d12!+2d6!' , '2d20!+1d12!+1d8!+1d6!' , '2d20!+1d12!+2d8!' , '1d20!+1d12!+1d10!+1d8!' ], ch = function (c) { var entities = { '<' : 'lt', '>' : 'gt', "'" : '#39', '@' : '#64', '{' : '#123', '|' : '#124', '}' : '#125', '[' : '#91', ']' : '#93', '"' : 'quot', '-' : 'mdash', ' ' : 'nbsp' }; if(_.has(entities,c) ){ return ('&'+entities[c]+';'); } return ''; }, getFormatForDice = function (dice) { var maxroll = 0, minroll = 0, dicePart = _.chain(dice.results.rolls) .map(function(r){ return '(' + _.map(r.results, function(r2) { maxroll += ( r.sides === r2.v ? 1 : 0 ); minroll += ( 1 === r2.v ? 1 : 0 ); return r2.v; }).join('+')+')'; }) .reject(function(r){ return '()'===r; }) .value().join('+'), rollOut = '<span style="text-align: center; vertical-align: text-middle; display: inline-block; min-width: 1.75em; border-radius: 5px; padding: 0px 2px; border-width: 2px; border-color: ' + ( maxroll && minroll ? '#4A57ED' : ( maxroll ? '#3FB315' : (minroll ? '#B31515' : '') ) ) + '" title="Rolling '+dice.expression+' = ' + dicePart + '" class="a inlinerollresult showtip tipsy-n ' + ( maxroll && minroll ? 'importantroll' : ( maxroll ? 'fullcrit' : (minroll ? 'fullfail' : '') ) ) + '">' + dice.results.total + '</span>'; return rollOut; }; on('chat:message', function(msg){ var args = msg.content.split(/\s+/), turnorder, stepNum; if('api' !== msg.type) { return; } switch(args.shift()) { case '!step': stepNum=parseInt(args.shift(),10); if(stepNum >= 1 && stepNum <= 40) { sendChat(msg.who, 'Step '+ stepNum + '<br>' +' [['+stepRolls[stepNum-1]+']]'); } else { stepNum = stepNum || '<blank>'; sendChat(msg.who, '<b>Error:</b> Step Number '+stepNum+' is not valid!'); } break; case '!gstep': stepNum=parseInt(args.shift(),10); if(stepNum >= 1 && stepNum <= 40) { sendChat(msg.who, '/w gm Step '+ stepNum + '<br>' +' [['+stepRolls[stepNum-1]+']]'); } else { stepNum = stepNum || '<blank>'; sendChat(msg.who, '/w gm <b>Error:</b> Step Number '+stepNum+' is not valid!'); } break; case '!istep': stepNum=parseInt(args.shift(),10); if(stepNum >= 1 && stepNum <= 40) { sendChat('', '[['+stepRolls[stepNum-1]+']]',function(msgs) { var msg2 = msgs.pop(), idx = msg2.content.match(/\$\[\[(\d+)\]\]/)[1], rolls=msg2.inlinerolls[idx]; if(rolls) { turnorder = Campaign().get('turnorder'); turnorder = ('' === turnorder) ? [] : JSON.parse(turnorder); Campaign().set({ turnorder: JSON.stringify( turnorder.concat( _.chain(msg.selected) .map(function(s){ return getObj(s._type,s._id); }) .reject(_.isUndefined) .reject(function(s){ return _.contains(_.pluck(turnorder,'id'),s.id); }) .map(function(s){ return { token: s, character: getObj('character',s.get('represents')) }; }) .map(function(s){ return { id: s.token.id, pr: rolls.results.total, custom: '' }; }) .value() ) ) }); sendChat(msg.who, '/direct Inititative roll: '+getFormatForDice(rolls)); } }); } else { stepNum = stepNum || '<blank>'; sendChat(msg.who, '<b>Error:</b> Step Number '+stepNum+' is not valid!'); } break; } }); }); (See.. it's not in Git, so I didn't write another script without working on GroupInitiative... really... =D )
Wow. It will take me a bit to figure out exactly what you did, particularly in the initiative stuff, but thanks very much!
1425449059
The Aaron
Pro
API Scripter
No worries, I enjoy the problem solving. :)
1425451241
Gen Kitty
Forum Champion
(See.. it's not in Git, so I didn't write another script without working on GroupInitiative... really... =D ) Whatever helps you sleep at night ^_-
1425460460
Lithl
Pro
Sheet Author
API Scripter
GenKitty said: (See.. it's not in Git, so I didn't write another script without working on GroupInitiative... really... =D ) Whatever helps you sleep at night ^_- Sleep? What's that?
1425475290
The Aaron
Pro
API Scripter
Brian said: GenKitty said: (See.. it's not in Git, so I didn't write another script without working on GroupInitiative... really... =D ) Whatever helps you sleep at night ^_- Sleep? What's that? Man, where's the Like/+1 button....
1425478367
Lithl
Pro
Sheet Author
API Scripter
The Aaron said: Brian said: GenKitty said: (See.. it's not in Git, so I didn't write another script without working on GroupInitiative... really... =D ) Whatever helps you sleep at night ^_- Sleep? What's that? Man, where's the Like/+1 button.... Wait! sleep() is that threading function, right? JavaScript doesn't have sleep() though, so I'm not sure how it's relevant... or why you would only want to call sleep() during the nighttime...