// Github: https://github.com/shdwjk/Roll20API/blob/master/WildDice/WildDice.js // By: The Aaron, Arcane Scriptomancer // Contact: https://app.roll20.net/users/104025/the-aaron const WildDice = (() => { // eslint-disable-line no-unused-vars const version = '0.3.5'; const lastUpdate = 1585662581; const ch = (c) => { const entities = { '<' : 'lt', '>' : 'gt', "'" : '#39', '@' : '#64', '{' : '#123', '|' : '#124', '}' : '#125', '[' : '#91', ']' : '#93', '"' : 'quot', '*' : 'ast', '/' : 'sol', ' ' : 'nbsp' }; if( entities.hasOwnProperty(c) ){ return `&${entities[c]};`; } return ''; }; const checkInstall = () => { log('-=> WildDice v'+version+' <=- ['+(new Date(lastUpdate*1000))+']'); }; const showHelp = (who) => { sendChat('','/w "'+who+'" '+ '
'+ '
'+ 'WildDice v'+version+ '
'+ '
'+ '

WildDice implements the rolling mechanics for WildDice systems.

'+ '
'+ 'Commands'+ '
'+ '!wd '+ch('[')+ch('<')+'Dice Expression'+ch('>')+ch('|')+'--help'+ch(']')+''+ '
'+ '

Rolls the WildDice expression and diplays the results. !wwd can be used in place of !wd to whisper the results to the GM.

'+ '
    '+ '
  • '+ ''+ch('<')+'Dice Expression'+ch('>')+' '+ch('-')+' An inline dice expression, something akin to '+ch('[')+ch('[')+'5d6+8'+ch(']')+ch(']')+' which will then be parsed for the roll result.'+ '
  • '+ '
  • '+ '--help '+ch('-')+' Shows the Help screen'+ '
  • '+ '
'+ '
'+ '
'+ '
' ); }; const getDiceCounts = (rolls) => (rolls || []) .reduce((m,r) => { m[r]=(m[r]||0)+1; return m; },{}); const s = { failsum: "float:left; background: red; margin-left: 10px; border: 1px solid black; padding: 1px 3px; color: white; font-weight: bold;", diceblock: "background: white; border: 1px solid black; padding: 1px 3px; color: black; font-weight: bold;", clear: "clear: both;", result: "" }; const f = { outer: (...t) => `
${t.join('')}
`, diceblock: (t) => `
Dice:
${t}
${f.clear()}
`, result: (t) => `
${t}
`, clear: () => `
`, failsum: (n) => `
${n} Crit Fail
` }; const handleInput = (msg) => { if (msg.type !== "api") { return; } let who=(getObj('player',msg.playerid)||{get:()=>'API'}).get('_displayname'); let parts = msg.content.split(/\s+--/); let args = parts[0].split(/\s+/); let w = false; switch(args[0]) { case '!wwd': w=true; /* break; // intentional dropthrough */ /* falls through */ case '!wd': { if(!msg.inlinerolls || _.contains(args,'--help')){ showHelp(who); return; } let rDice = _.pluck( (msg.inlinerolls && msg.inlinerolls[0].results.rolls[0].results) || [], 'v'); let pips = ((msg.inlinerolls && msg.inlinerolls[0].results.total-_.reduce(rDice,function(m,r){return m+r;},0)) || 0); let wildDie = rDice.pop(); let hasFail = false; let markFirstMax = false; let sumFail = 0; let bonusDice = []; switch(wildDie) { case 1: { // critical failure let critFailDice = getDiceCounts(rDice); hasFail = Object.keys(critFailDice).length>0; if(hasFail){ --critFailDice[`${_.max(rDice)}`]; } sumFail = Object.keys(critFailDice).reduce((m,k) => (m + parseInt(k,10)*critFailDice[k]), 0) + pips; markFirstMax = true; } break; case 6: { // explode! let errorDie = 6; while(6 === errorDie) { errorDie = randomInteger(6); bonusDice.push(errorDie); } } break; } let sum = _.reduce(rDice.concat(bonusDice),function(m,r){return m+r;},0) + wildDie + pips; let wrapper = (t)=>t; if(/^template\b\s/.test(parts[1]||"")){ let template = `&{template:${msg.rolltemplate}}${parts[1].replace(/^template\s+/i,'')}`; wrapper = (t) => template.replace(/%%ROLL%%/i,t); } sendChat( `player|${msg.playerid}`, `${w ? '/w gm ' : ''}${wrapper(f.outer(f.diceblock( _.map(rDice,function(d){ var c = 'white'; if( markFirstMax && d === _.max(rDice) ) { c = '#666666'; markFirstMax = false; } return '
'+d+'
'; }).join('')+ '
'+wildDie+'
'+ _.map(bonusDice,function(d){ return '
'+d+'
'; }).join('')+ (pips ? '
+ '+pips+'
' : '') ), f.result( ( hasFail ? f.failsum(sumFail) : '') + '
'+sum+(hasFail ? ' Complication' : ' Total')+'
'+ '
' ) ))}`); } break; } }; const registerEventHandlers = () => { on('chat:message', handleInput); }; on('ready', () => { checkInstall(); registerEventHandlers(); }); return { }; })();