// Github: https://github.com/shdwjk/Roll20API/blob/master/InitiativeAssistant/InitiativeAssistant.js
// By: The Aaron, Arcane Scriptomancer
// Contact: https://app.roll20.net/users/104025/the-aaron
var InitiativeAssistant = InitiativeAssistant || (function() {
'use strict';
var version = '0.1.3',
lastUpdate = 1429545338,
schemaVersion = 0.2,
sorters = {
'None': function(to) {
return to;
},
'Ascending': function(to){
return _.sortBy(to,function(i){
return (i.pr);
});
},
'Descending': function(to){
return _.sortBy(to,function(i){
return (-i.pr);
});
}
},
checkInstall = function() {
log('-=> InitiativeAssistant v'+version+' <=- ['+(new Date(lastUpdate*1000))+']');
if( ! _.has(state,'InitiativeAssistant') || state.InitiativeAssistant.version !== schemaVersion) {
log(' > Updating Schema to v'+schemaVersion+' <');
state.InitiativeAssistant = {
version: schemaVersion,
config: {
sortOption: 'None'
}
};
}
},
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 '';
},
getConfigOption_SortOptions = function() {
var text = state.InitiativeAssistant.config.sortOption;
return '
'+
'Sort Options is currently
'+
text+
'.'+
'
'+
_.map(_.keys(sorters),function(so){
return '
'+
so+
'';
}).join(' ')+
'
'+
'
';
},
showHelp = function(who) {
sendChat('','/w '+who+' '
+''
+'
'
+'InitiativeAssistant v'+version
+'
'
+'
'
+'
Provides an easy interface to adding players into the initiative, particularly if they are manually rolling.
'
+'
'
+'
Commands'
+'
'
+'
!init-assist [ [--'+ch('<')+'name fragment'+ch('>')+'|'+ch('<')+'number'+ch('>')+'] ...] | --help'
+'
'
+'
Adds one or more characters to the initiative order.
'
+'
'
+'- '
+''+ch('<')+'name fragment'+ch('>')+' '+ch('-')+' A part of the name of the character to add. This can be the full name, or just a few letters. Case-insensitive.'
+'
'
+'- '
+''+ch('<')+'number'+ch('>')+' '+ch('-')+' A number or inline roll representing the character'+ch("'")+'s initiative score.'
+'
'
+'
'
+'
'
+'
'
+getConfigOption_SortOptions()
+'
'
);
},
keyFormat = function(text) {
return text.toLowerCase().replace(/\s+/,'');
},
handleInput = function(msg_orig) {
var msg = _.clone(msg_orig),
output='',
redos={},
keys=[],
lookup,
chars,
args,
who,
to;
if (msg.type !== "api" || !playerIsGM(msg.playerid)) {
return;
}
who=getObj('player',msg.playerid).get('_displayname').split(' ')[0];
if(_.has(msg,'inlinerolls')){
msg.content = _.chain(msg.inlinerolls)
.reduce(function(m,v,k){
m['$[['+k+']]']=v.results.total || 0;
return m;
},{})
.reduce(function(m,v,k){
return m.replace(k,v);
},msg.content)
.value();
}
args = msg.content
.replace(/
\n/g, ' ')
.replace(/(\{\{(.*?)\}\})/g," $2 ")
.split(/\s+--/);
switch(args.shift()) {
case '!init-assist':
if( !args.length || _.contains(args,'--help')) {
showHelp(who);
return;
}
lookup = _.reduce(args,function(m,p){
var parts=p.split(/\|/),
key=keyFormat(parts[0]);
keys.push(key);
m[key]={
key: key,
input: parts[0],
init: parts[1]
};
return m;
},{});
chars = _.reduce(
filterObjs(function(obj){
return ('character' === obj.get('type')) && (_.reduce(keys,function(m,k){
return m || (-1 !== keyFormat(obj.get('name')||'').indexOf(k));
},false));
}),
function(m,c){
var ckey=keyFormat(c.get('name')||''),
key=_.find(keys,function(k){
return (-1 !== ckey.indexOf(k));
});
m[key] = (m[key] ? m[key].push(c) && m[key] : [c]);
return m;
},
{}
);
to=JSON.parse(Campaign().get('turnorder')) || [];
_.each(keys, function(k){
var char;
if(chars[k]) {
if(1 === chars[k].length) {
char = findObjs({
type: 'graphic',
pageid: Campaign().get('playerpageid'),
subtype: 'token',
represents: chars[k][0].id
})[0];
if(char) {
to = _.reject(to, function(i){
return char.id === i.id;
});
to.push({
id: char.id,
pr: lookup[k].init
});
} else {
lookup[k].matches=chars[k];
redos.NT=(redos.NT ? redos.NT.push(lookup[k]) && redos.NT : [lookup[k]]);
}
} else {
lookup[k].matches=chars[k];
redos.DUP=(redos.DUP ? redos.DUP.push(lookup[k]) && redos.DUP : [lookup[k]]);
}
} else {
redos.NM=(redos.NM ? redos.NM.push(lookup[k]) && redos.NM : [lookup[k]]);
}
});
Campaign().set({
turnorder: JSON.stringify(sorters[state.InitiativeAssistant.config.sortOption](to))
});
_.each(redos,function(rs,k){
var params=[];
switch(k){
case 'NT':
output+=
''+
'
Please Add Tokens
'+
'
'+
_.map(rs, function(r){
var c = r.matches[0];
params.push('--'+r.key+'|'+r.init);
return '
'+
'

'+
'
'+c.get("name")+''+
'
'+
'
';
}).join(' ')+
'
'+
'
After adding tokens for the above characters: Add Turn(s)
'+
'
';
break;
case 'DUP':
output+=
''+
'
Which One?
'+
'
'+
_.map(rs, function(r){
return '
'+
r.input+
''+
''+
_.map(r.matches,function(c){
var button='
Pick';
return '
'+
'

'+
button+
'
'+c.get("name")+''+
'
'+
'
';
}).join('')+
'
';
}).join(' ')+
'
'+
'
';
break;
case 'NM':
output+=
''+
'
No Matching Characters
'+
'
'+
_.map(rs, function(r){
return '
'+
r.input+
'
';
}).join(' ')+
'
'+
'
';
break;
}
});
if(output){
sendChat('Initiative Assistant','/w '+who+' '+output);
}
break;
case '!init-assist-config':
if(_.contains(args,'--help')) {
showHelp(who);
return;
}
if(!args.length) {
sendChat('','/w '+who+' '
+''
+'
'
+'InitiativeAssistant v'+version
+'
'
+getConfigOption_SortOptions()
+'
'
);
return;
}
_.each(args,function(a){
var opt=a.split(/\|/),
msg='';
switch(opt.shift()) {
case 'sort-option':
if(sorters[opt[0]]) {
state.InitiativeAssistant.config.sortOption=opt[0];
} else {
msg='Error: Not a valid sort method: '+opt[0]+'
';
}
sendChat('','/w '+who+' '
+''
+msg
+getConfigOption_SortOptions()
+'
'
);
break;
default:
sendChat('','/w '+who+' '
+'Unsupported Option:
'+a+''
);
}
});
break;
}
},
registerEventHandlers = function() {
on('chat:message', handleInput);
};
return {
CheckInstall: checkInstall,
RegisterEventHandlers: registerEventHandlers
};
}());
on('ready',function() {
'use strict';
InitiativeAssistant.CheckInstall();
InitiativeAssistant.RegisterEventHandlers();
});