diff --git a/InitiativeAssistant/InitiativeAssistant.js b/InitiativeAssistant/InitiativeAssistant.js
new file mode 100644
index 0000000000..4ac227822f
--- /dev/null
+++ b/InitiativeAssistant/InitiativeAssistant.js
@@ -0,0 +1,347 @@
+// 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.2',
+ 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();
+});
diff --git a/InitiativeAssistant/package.json b/InitiativeAssistant/package.json
new file mode 100644
index 0000000000..2e190df1b8
--- /dev/null
+++ b/InitiativeAssistant/package.json
@@ -0,0 +1,17 @@
+{
+ "name": "InitiativeAssistant",
+ "version": "0.1.2",
+ "description": "Provides an easy interface to adding players to the inititaive order.",
+ "authors": "The Aaron",
+ "roll20userid": "104025",
+ "dependencies": {
+ },
+ "modifies": {
+ "state.InitiativeAssistant": "read,write",
+ "campaign.turnorder": "read,write",
+ "character.name": "read",
+ "token.represents": "read"
+ },
+ "conflicts": [
+ ]
+}