First pass version: Also supports whispering You run it with: !wd <number> So for 4: !wd 4 If you don't supply a number (or supply something that doesn't look like a number), it assumes 2. You can also use an inline roll to determine the number of dice to roll: !wd [[@{selected|strength}+@{selected|endurance}]] You whisper by prefacing with a w: !wwd 3 The whisper goes to the player, but I could make it go to player and gm, or just gm (or add options for that. Script: on('ready',()=>{
const cr = /^!(w)?wd(?:\b\s|$)/i;
const times = (n,f)=>Array(n).fill(n).map(f);
const d10 = ()=>randomInteger(10);
const explode = (n)=>[n, ...(10===n?explode(d10()):[])];
const css = (o)=>Object.keys(o).reduce((m,k)=>`${m}${k}:${o[k]};`,'');
const s = {
box: css({
["font-weight"] : "bold",
["border-bottom"] : "2px solid #0F3DA0",
["border-top"] : "4px solid #0F3DA0",
["background-color"] : "#AEB6C6"
}),
heading: css({
["font-weight"] : "bold",
["font-size"] : "1.3em"
}),
title: css({
["font-weight"] : "bold"
}),
row: css({
["margin"] : ".1em",
["border-bottom"] : "1px solid #0F3DA0"
}),
die: css({
["display"] : "inline-block",
["font-size"] : "1.3em",
["padding"] : ".25em .5em",
["border"] : "1px solid black",
["border-radius"] : "100%",
["background-color"] : "white",
["color"] : "black"
}),
one: css({
["color"] : "#990000"
}),
ten: css({
["color"] : "#009900"
}),
sum: css({
["display"] : "inline-block",
["font-size"] : "1.3em",
["padding"] : ".1em .25em",
["border"] : "1px solid red",
["border-radius"] : ".2em",
["background-color"] : "#333",
["color"] : "white"
}),
clear: css({
["clear"] : "both"
})
};
const f = {
content: (t,c) => `<div style="${s.content}">${f.heading(t)}${c}</div>`,
heading: (t) => `<div style="${s.heading}">${t}</div>`,
box: (t) => `<div style="${s.box}">${t}</div>`,
title: (t) => `<div style="${s.title}">${t}</div>`,
clear: () => `<div style="${s.clear}"></div>`,
die: (n) => `<div style="${s.die}${n<0?s.one:(10===n?s.ten:'')}">${n}</div>`,
sum: (n) => `<div style="${s.sum}">${n}</div>`,
row: (...o) => `<div style="${s.row}">${o.join(' ')}${f.clear()}</div>`
};
const processInlinerolls = (msg) => {
if(_.has(msg,'inlinerolls')){
return _.chain(msg.inlinerolls)
.reduce(function(m,v,k){
let ti=_.reduce(v.results.rolls,function(m2,v2){
if(_.has(v2,'table')){
m2.push(_.reduce(v2.results,function(m3,v3){
m3.push(v3.tableItem.name);
return m3;
},[]).join(', '));
}
return m2;
},[]).join(', ');
m['$[['+k+']]']= (ti.length && ti) || v.results.total || 0;
return m;
},{})
.reduce(function(m,v,k){
return m.replace(k,v);
},msg.content)
.value();
} else {
return msg.content;
}
};
on('chat:message',msg=>{
if('api'===msg.type && cr.test(msg.content) && playerIsGM(msg.playerid)){
let who = (getObj('player',msg.playerid)||{get:()=>'API'}).get('_displayname');
let whisper = ("w"===cr.exec(msg.content)[1]);
let args = processInlinerolls(msg).split(/\s+/).slice(1);
let diceCount = parseInt(args[0])||2;
let rolls = times(diceCount,d10)
.reduce((m,n)=>{
if(1 === n){
return [...m,-d10()];
}
return [...m,...explode(n)];
},[]);
let sum = rolls.reduce((m,n)=>m+n);
sendChat(who,`${whisper ? `/w "${who}" `:''}${f.content(`Rolling ${diceCount}d10`,f.box(
f.row(rolls.map(n=>f.die(n)).join(' + '), ' = ', f.sum(sum))
))}`);
}
});
});