Skip to content

Instantly share code, notes, and snippets.

@Kurohyou
Last active July 29, 2016 02:16
Show Gist options
  • Save Kurohyou/b6d8022c70b133ac408f272d5faac690 to your computer and use it in GitHub Desktop.
Save Kurohyou/b6d8022c70b133ac408f272d5faac690 to your computer and use it in GitHub Desktop.
// Github: https://github.com/shdwjk/Roll20API/blob/master/RecursiveTable/RecursiveTable.js
// By: The Aaron, Arcane Scriptomancer
// Contact: https://app.roll20.net/users/104025/the-aaron
var RecursiveTable = RecursiveTable || (function() {
'use strict';
var version = '0.1.2',
lastUpdate = 1453302547,
schemaVersion = 0.1,
maxParseSec = 50,
checkInstall = function() {
log('-=> RecursiveTable v'+version+' <=- ['+(new Date(lastUpdate*1000))+']');
if( ! _.has(state,'RecursiveTable') || state.RecursiveTable.version !== schemaVersion) {
log(' > Updating Schema to v'+schemaVersion+' <');
state.RecursiveTable = {
version: schemaVersion
};
}
},
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 '';
},
showHelp = function(who) {
sendChat('','/w "'+who+'" '
+'<div style="border: 1px solid black; background-color: white; padding: 3px 3px;">'
+'<div style="font-weight: bold; border-bottom: 1px solid black;font-size: 130%;">'
+'RecursiveTable v'+version
+'</div>'
+'<div style="padding-left:10px;margin-bottom:3px;">'
+'<p>RecursiveTable provides a way to expand the results of Rollable Tables which have inline rolls within them.</p>'
+'</div>'
+'<b>Commands</b>'
+'<div style="padding-left:10px;">'
+'<b><span style="font-family: serif;">!rt [--help| ... ]</span></b>'
+'<div style="padding-left: 10px;padding-right:20px">'
+'<p>Performs all inline rolls, then continues to expand inline rolls (to a maximum depth of around 10).</p>'
+'<ul>'
+'<li style="border-top: 1px solid #ccc;border-bottom: 1px solid #ccc;">'
+'<b><span style="font-family: serif;">--help</span></b> '+ch('-')+' Shows the Help screen'
+'</li> '
+'<li style="border-top: 1px solid #ccc;border-bottom: 1px solid #ccc;">'
+'<b><span style="font-family: serif;">...</span></b> '+ch('-')+' Anything following !rt will be expanded, then sent to to the chat. Tables can be rolled '
+'with a modifier by calling the table like this: '+ch('[')+ch('[')+'1t'+ch('[')+'tableName'+ch(']')+'+3'+ch(']')+ch(']')+'. The roll mod can be a'
+'number or an inline dice roll'
+'</li> '
+'</ul>'
+'</div>'
+'</div>'
+'</div>'
);
},
extractInlineRolls = function(str){
"use strict";
let rolls=[],
bracketCount=0,
rollStart=0,
accumulator='';
for(let position = 0; position < str.length; ++position) {
if('[' === str[position]) {
if(bracketCount){
accumulator='[';
rollStart=position-1;
while(bracketCount>0 && position<str.length){
switch(str[position]){
case '[': ++bracketCount; break;
case ']': --bracketCount; break;
}
accumulator+=str[position];
++position;
}
if(!bracketCount){
rolls.push(accumulator);
}
} else {
++bracketCount;
}
} else {
bracketCount=0;
}
}
return rolls;
},
getTableItem = function(tableName,currentRoll,mod){
var table = findObjs({
type:'rollabletable',
name: tableName
})[0],
items,
weight,
list =[],
text = '',
rollMod;
items = findObjs({
type:'tableitem',
rollabletableid: table.id
});
_.each(items,function(obj){
weight = parseInt(obj.get('weight'));
for(var i = 0; i < weight; i++){
list.push(obj.get('name'));
};
});
_.each(currentRoll,function(r){
rollMod = eval(mod)+r.tableidx;
if(rollMod>(list.length - 1)){
text += list[list.length- 1] + ' ';
}else if(rollMod<0){
text += list[0] + ' ';
}else{
text += list[rollMod] + ' ';
};
});
return text;
},
rollChat = function(toChat){
return new Promise(function(resolve,reject){
sendChat('',toChat,function(obj){
resolve(parseMessage(obj[0]));
});
});
},
recursiveParse = function(iRoll){
var table,
result,
inlines,
rollResult = [];
if(_.has(iRoll.results.rolls[0],'table')){
if(iRoll.results.rolls.length>1){
result = getTableItem(iRoll.results.rolls[0].table, iRoll.results.rolls[0].results, iRoll.results.rolls[1].expr);
}else{//this needs to be dynamic based on number of calls.
result = getTableItem(iRoll.results.rolls[0].table, iRoll.results.rolls[0].results, '+0');
};
result = result.replace(/\[\[\[/g, "[[ [");
inlines = extractInlineRolls(result);
for(var i = 0; i < inlines.length; i++){
result = result.replace(inlines[i],'$||'+i+'||');
};
}else{
result = iRoll.results.total;
};
if(inlines){
return Promise.all(inlines.map(rollChat)).then(function(text){
for(var i = 0;i<text.length;i++){
result = result.replace('$||'+i+'||',text[i]);
};
return (result);
});
}else{
return result;
};
},
parseMessage = function(msg){
return Promise.all(msg.inlinerolls.map(recursiveParse)).then(function(rolltext){
for(var i = 0;i<rolltext.length;i++){
msg.content = msg.content.replace('$[['+i+']]',rolltext[i]);
};
return msg.content;
})
},
handleInput = function(msg_orig) {
var msg = _.clone(msg_orig),
args, who;
if (msg.type !== "api") {
return;
}
who=getObj('player',msg.playerid).get('_displayname');
args = msg.content.split(/\s+/);
switch(args[0]) {
case '!rt':
if('--help' === args[1]){
showHelp(who);
} else {
msg.content = msg.content.replace(/^!rt\s+/,'').replace(/\{\{/,'&{template:'+msg.rolltemplate+'} {{');
parseMessage(msg).then(function(chat){
sendChat(msg.who,chat);
},function(err){
sendChat(msg.who,'/w "'+msg.who+'" '+err);
}).catch(function(oErr){
log('An unanticiapted error occurred:');
log(oErr);
});
};
break;
}
},
registerEventHandlers = function() {
on('chat:message', handleInput);
};
return {
CheckInstall: checkInstall,
RegisterEventHandlers: registerEventHandlers
};
}());
on('ready',function() {
'use strict';
RecursiveTable.CheckInstall();
RecursiveTable.RegisterEventHandlers();
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment