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

Looking for someone to write a relatively simple API script for my game

I use some custom critical hit rules for my 5e campaigns. The way it works is that a natural 18 and a 19 can also critically hit if the attack roll passes the targets AC by 10. This obviously requires all attack rolls that roll high to be mouse-over hovered to check what the natural die roll was to calculate if it qualifies as a critical hit or not.  What I'm looking for is an API script that would globally cause all attack rolls (spells and attacks) with a natural 18 or 19 on the die to be colored in a custom, third color in addition to the critical success green and critical failure red. As far as I've understood, this should be relatively simple to do, but I'm very clueless with any script writing, so I'm looking for some help here. Would anyone be able to do this?
1595267240
The Aaron
Roll20 Production Team
API Scripter
This isn't quite as simple as it might sound.   First off, the API can only directly manipulate it's own output, not other things like Dice Rolls or Roll Templates.  The API reacts to input, so it only knows about those things after they've already been displayed.  The second thing is that even the rolls it's creating, unless it's taking over the entirety of output, can't be colored outside what is available to the standard dice formulas.  For example, you could make the dice roll show red for crit failure, green for crit, and blue for 18 and 19 using this sort of construct: [[1d20cf1cf18cf19cs>18]]   You'd need to change all the places you roll a d20 for attacks to use that formula.  I'm not sure how practical that will be for you, it would probably require modifying the character sheet. What you COULD do from the API is detect attack rolls by inspecting the output Roll Template, then if there was an 18 or 19 rolled, output a message that says "Potential Critical on an 18" or some such.
The Aaron said: What you COULD do from the API is detect attack rolls by inspecting the output Roll Template, then if there was an 18 or 19 rolled, output a message that says "Potential Critical on an 18" or some such. This suggestion definitely sounds like the best option to me, would you have any instructions on how to do this?
1595270363
The Aaron
Roll20 Production Team
API Scripter
What character sheet are you using?
The D&D 5E by Roll20.
1595271998
The Aaron
Roll20 Production Team
API Scripter
Ok, that should be pretty easy, I can take a look tonight after work.
1595272193
The Aaron
Roll20 Production Team
API Scripter
Output something like: Potential Critical Hit (18) — Was AC 15 or lower?
The Aaron said: Output something like: Potential Critical Hit (18) — Was AC 15 or lower? If you're referring to the message that would be output, I think something really short, like: "Potential Crit" would suffice.
1595272947
The Aaron
Roll20 Production Team
API Scripter
Ok!
Looking forward to it, thank you in advance! :)
1595338240
The Aaron
Roll20 Production Team
API Scripter
Here's a first pass version.  Not 100% sold on the styling, but that's something you can play with or I can adjust for you: If the attack is whispered, the message will be also. Script: on('ready',()=>{ const sread = (o,p) => { let v = o; while(undefined !== v && p.length) { v = v[p.shift()]; } return v; }; const s = { box: `line-height: 1em; background-color: rgba(255,0,0,.2);color: red;font-weight: bold;border-bottom: 2px solid red;border-top: 4px solid red;font-variant: small-caps;left: -5em;position: relative;padding: 0 5em;width: 100%;right: 6em;`, die: `display: inline-block;border: 1px solid #999;background-color: white;padding: .2em;border-radius: 1em;min-width:1.2em;text-align:center;` }; const f = { box: (t) => `<div style="${s.box}">${t}</div>`, die: (n) => `<span style="${s.die}">${n}</span>` }; on('chat:message',msg=>{ if(['general','whisper'].includes( msg.type) && ['npcatk','atk'].includes(msg.rolltemplate)){ if(msg.inlinerolls){ let rtf = msg.content .replace(/^.*?{{/,'') .split(/{{/) .map(t=>t.replace(/}}.*$/,'')) .reduce((m,t)=>({...m,[t.replace(/=.*$/,'')]:t.replace(/^[^=]*=/,'')}),{}); let r1i = parseInt(rtf.r1.replace(/[^0-9]/g,'')); let r2i = parseInt(rtf.r2.replace(/[^0-9]/g,'')); let r1 = sread(msg.inlinerolls,[r1i,'results','rolls',0,'results',0,'v'])||0; let r2 = sread(msg.inlinerolls,[r2i,'results','rolls',0,'results',0,'v'])||0; if([18,19].includes(r1) ||[18,19].includes(r2)){ let w=''; if('whisper'===msg.type){ w =`/w "${msg.target_name}" `; } sendChat('',`${w}${f.box(`Possible Critical (${f.die(r1)},${f.die(r2)})`)}`); } } } }); });
Thank you very much, I think something like this is probably the best solution for my needs! I would as well probably prefer a few adjustments to the style, I could probably get some of them done my self but: - Could the colon that appears on top of the message be removed? - Since it's normal to always roll at advantage, the message obviously also always shows the natural die amount for both rolls. Would it be possible to maybe gray out or somehow hide the number that isn't an 18 or 19, while also still keeping it there for clarity? - The color I was thinking of was blue, so could the color theme be changed to that? None of these are necessary and just personal preference on how I would like it to look. I could probably do some of these on my own, but you would probably be much more effective with it, if it wouldn't be too much to to ask.
1595354229
The Aaron
Roll20 Production Team
API Scripter
I can do all of those but the Colon.  That's from Roll20 and I don't have control over it.  However, I might be able to cover it with the output div.  That's what I was trying to do, but I ran out of time before work.  I'll see what I can do about it today after I'm done working for the day.  The rest of that is trivial and not a problem to take care of. =D
Okay, sounds good.
1595373753

Edited 1595373867
The Aaron
Roll20 Production Team
API Scripter
How about this: Script: on('ready',()=>{ const sread = (o,p) => { let v = o; while(undefined !== v && p.length) { v = v[p.shift()]; } return v; }; const css = (o)=>Object.keys(o).reduce((m,k)=>`${m}${k}:${o[k]};`,''); const s = { box: css({ ["line-height"] : "1em", ["display"] : "inline", ["background-color"] : "#4973CB", ["color"] : "#99B3EB", ["font-weight"] : "bold", ["border-bottom"] : "2px solid #0F3DA0", ["border-top"] : "4px solid #0F3DA0", ["font-variant"] : "small-caps", ["left"] : "0em", ["position"] : "absolute", ["padding-left"] : "5em", ["width"] : "100%", ["z-index"] : "100000" }), die: css({ ["display"] : "inline-block", ["border"] : "1px solid #999", ["background-color"] : "white", ["padding"] : ".2em", ["border-radius"] : "1em", ["min-width"] : "1.2em", ["text-align"] : "center" }), highlight: css({ ["color"] : "#0F3DA0" }), subdued: css({ ["color"] : "#99B3EB", ["background-color"] : "#6B8FDB" }) }; const f = { box: (t) => `<div style="${s.box}">${t}</div>`, die: (n,is) => `<span style="${s.die}${is?s.highlight:s.subdued}">${n}</span>` }; on('chat:message',msg=>{ if(['general','whisper'].includes( msg.type) && ['npcatk','atk'].includes(msg.rolltemplate)){ if(msg.inlinerolls){ let rtf = msg.content .replace(/^.*?{{/,'') .split(/{{/) .map(t=>t.replace(/}}.*$/,'')) .reduce((m,t)=>({...m,[t.replace(/=.*$/,'')]:t.replace(/^[^=]*=/,'')}),{}); let r1i = parseInt(rtf.r1.replace(/[^0-9]/g,'')); let r2i = parseInt(rtf.r2.replace(/[^0-9]/g,'')); let r1 = sread(msg.inlinerolls,[r1i,'results','rolls',0,'results',0,'v'])||0; let r2 = sread(msg.inlinerolls,[r2i,'results','rolls',0,'results',0,'v'])||0; if([18,19].includes(r1) ||[18,19].includes(r2)){ let w=''; if('whisper'===msg.type){ w =`/w "${msg.target_name}" `; } sendChat('',`${w}${f.box(`Possible Critical (${f.die(r1,[18,19].includes(r1))},${f.die(r2,[18,19].includes(r2))})`)}`); } } } }); });
This looks very good, thank you!