// 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(); });