Character Vault
Any Concept / Any System
Compendium
Your System Come To Life
Roll20 for Android
Streamlined for your Tablet
Roll20 for iPad
Streamlined for your Tablet

Personal tools

zachary p.

From Roll20 Wiki

Revision as of 02:57, 16 August 2018 by zachary p. (Talk | contribs)

(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search

Skip to content Features Business Explore Marketplace Pricing

Search

Sign in or Sign up 12 29 19 shdwjk/Roll20API

Code  Issues 9  Pull requests 1  Projects 0  Insights

Join GitHub today GitHub is home to over 28 million developers working together to host and review code, manage projects, and build software together.

Roll20API/GroupInitiative/GroupInitiative.js df85eb5 on Mar 13 @shdwjk shdwjk Updated 1 Scripts

1709 lines (1576 sloc) 83.9 KB // Github: https://github.com/shdwjk/Roll20API/blob/master/GroupInitiative/GroupInitiative.js // By: The Aaron, Arcane Scriptomancer // Contact: https://app.roll20.net/users/104025/the-aaron

var GroupInitiative = GroupInitiative || (function() {

   'use strict';
   var version = '0.9.29',
       lastUpdate = 1520955646,
       schemaVersion = 1.1,
       bonusCache = {},
       observers = {
               turnOrderChange: []
           },
       sorters = {
           'None': function(to) {
               return to;
           },
           'Ascending': function(to){
               var last=0;
               return _.sortBy(to,function(i){
                   let val=(parseFloat(i.pr));
                   val = _.isNaN(val) ? last : val;
                   last=val;
                   return val;
               });
           },
           'Descending': function(to){
               var last=100000;
               return _.sortBy(to,function(i){
                   let val=(-(parseFloat(i.pr)));
                   val = _.isNaN(val) ? last : val;
                   last=val;
                   return val;
               });
           }
       },
       esRE = function (s) {
         var escapeForRegexp = /(\\|\/|\[|\]|\(|\)|\{|\}|\?|\+|\*|\||\.|\^|\$)/g;
         return s.replace(escapeForRegexp,"\\$1");
       },
       HE = (function(){
         var entities={
                 //' ' : '&'+'nbsp'+';',
                 '<' : '&'+'lt'+';',
                 '>' : '&'+'gt'+';',
                 "'" : '&'+'#39'+';',
                 '@' : '&'+'#64'+';',
                 '{' : '&'+'#123'+';',
                 '|' : '&'+'#124'+';',
                 '}' : '&'+'#125'+';',
                 '[' : '&'+'#91'+';',
                 ']' : '&'+'#93'+';',
                 '"' : '&'+'quot'+';'
             },
             re=new RegExp('('+_.map(_.keys(entities),esRE).join('|')+')','g');
         return function(s){
           return s.replace(re, function(c){ return entities[c] || c; });
         };
       }()),
       observeTurnOrderChange = function(handler){
           if(handler && _.isFunction(handler)){
               observers.turnOrderChange.push(handler);
           }
       },
       notifyObservers = function(event,obj,prev){
           _.each(observers[event],function(handler){
               handler(obj,prev);
           });
       },
       formatDieRoll = function(rollData) {
           var critFail = _.reduce(rollData.rolls,function(m,r){
                       return m || _.contains(r.rolls,1);
                   },false),
               critSuccess = _.reduce(rollData.rolls,function(m,r){
                       return m || _.contains(r.rolls,r.sides);
                   },false),
               highlight = ( (critFail && critSuccess) ?
                   '#4A57ED' :
                   ( critFail ?
                       '#B31515' :
                       ( critSuccess ?
                           '#3FB315' :
                           '#FEF68E'
                       )
                   )
               ),
               dicePart = _.reduce(rollData.rolls, function(m,r){
                   _.reduce(r.rolls,function(dm,dr){
                       var dielight=( 1 === dr ?
                           '#ff0000' :
                               ( r.sides === dr ?
                                   '#00ff00' :
                                   'white'
                               )
                           );
                       dm.push(''+dr+'');
                       return dm;
                   },m);
                   return m;
               },[]).join(' + ');
           return '<span class="inlinerollresult showtip tipsy" style="min-width:1em;display: inline-block; border: 2px solid '+
               highlight+
               '; background-color: #FEF68E;color: #404040; font-weight:bold;padding: 0px 3px;cursor: help"'+
               ' title="'+
               HE(HE(
                   ''+
                       dicePart+' [init] '+
                       (rollData.bonus>=0 ? '+' :'-')+' '+Math.abs(rollData.bonus)+' [bonus]'+
                   ''
               ))+'">'+
                   rollData.total+
               '</span>';
       },
       buildAnnounceGroups = function(l) {
           var groupColors = {
               npc: '#eef',
               character: '#efe',
               gmlayer: '#aaa'
           };
           return _.reduce(l,function(m,s){
               var type= ('gmlayer' === s.token.get('layer') ?
                   'gmlayer' : (
                       (s.character && _.filter(s.character.get('controlledby').split(/,/),function(c){ 
                           return 'all' === c || ( !== c && !playerIsGM(c) );
                       }).length>0) || false ?
                           'character' :
                           'npc'
                   ));
               if('graphic'!==s.token.get('type') || 'token' !==s.token.get('subtype')) {
                   return m;
               }
m[type].push('
'+ '
'+
                       '<img src="'+(s.token && s.token.get('imgsrc'))+'" style="height: 2.5em;float:left;margin-right:2px;">'+
                       ((s.token && s.token.get('name')) || (s.character && s.character.get('name')) || '(Creature)')+
'
'+ '
'+
                       formatDieRoll(s.rollResults)+
'
'+ '
'+ '
');
               return m;
           },{npc:[],character:[],gmlayer:[]});
       },
       announcers = {
           'None': function() {
           },
           'Hidden': function(l) {
               var groups=buildAnnounceGroups(l);
               if(groups.npc.length || groups.character.length || groups.gmlayer.length){
                   sendChat('GroupInit','/w gm '+
'
'+
                           groups.character.join()+
                           groups.npc.join()+
                           groups.gmlayer.join()+
'
'+ '
');
               }
           },
           'Partial': function(l) {
               var groups=buildAnnounceGroups(l);
               if(groups.character.length){
                   sendChat('GroupInit','/direct '+
'
'+
                           groups.character.join()+
'
'+ '
');
               }
               if(groups.npc.length || groups.gmlayer.length){
                   sendChat('GroupInit','/w gm '+
'
'+
                           groups.npc.join()+
                           groups.gmlayer.join()+
'
'+ '
');
               }
           },
           'Visible': function(l) {
               var groups=buildAnnounceGroups(l);
               if(groups.npc.length || groups.character.length){
                   sendChat('GroupInit','/direct '+
'
'+
                           groups.character.join()+
                           groups.npc.join()+
'
'+ '
');
               }
               if(groups.gmlayer.length){
                   sendChat('GroupInit','/w gm '+
'
'+
                           groups.gmlayer.join()+
'
'+ '
');
               }
           }
       },
       statAdjustments = {
           'stat-dnd': {
               func: function(v) {
                   return 'floor((('+v+')-10)/2)';
               },
               desc: 'Calculates the bonus as if the value were a DnD Stat.'
           },
           'negative': {
               func: function(v) {
                   return '(-1*('+v+'))';
               },
               desc: 'Returns the negative version of the stat'
           },
           'bare': {
               func: function(v) {
                   return v;
               },
               desc: 'No Adjustment.'
           },
           'floor': {
               func: function(v) {
                   return 'floor('+v+')';
               },
               desc: 'Rounds down to the nearest integer.'
           },
           'tie-breaker': {
               func: function(v) {
                   return '(0.01*('+v+'))';
               },
               desc: 'Adds the accompanying attribute as a decimal (0.01)'
           },
           'ceiling': {
               func: function(v) {
                   return 'ceil('+v+')';
               },
               desc: 'Rounds up to the nearest integer.'
           },
           'bounded': {
               func: function(v) {
                   return v;
               },
               desc: 'DEPREICATED - will not work with expresions.'
           }
       },
       buildInitDiceExpression = function(s){
           var stat=(!== state.GroupInitiative.config.diceCountAttribute && s.character && getAttrByName(s.character.id, state.GroupInitiative.config.diceCountAttribute, 'current'));
           if(stat ) {
               stat = (_.isString(stat) ? stat : stat+);
               if('0' !== stat) {
                   stat = stat.replace(/@\{([^|]*?|[^|]*?\|max|[^|]*?\|current)\}/g, '@{'+(s.character.get('name'))+'|$1}');
                   return '('+stat+')d'+state.GroupInitiative.config.dieSize;
               }
           } 
           return state.GroupInitiative.config.diceCount+'d'+state.GroupInitiative.config.dieSize;
       },
       rollers = {
           'Least-All-Roll':{
               mutator: function(l){
                   var min=_.reduce(l,function(m,r){
                       if(!m || (r.total < m.total)) {
                           return r;
                       } 
                       return m;
                   },false);
                   return _.times(l.length, function(){
                       return min;
                   });
               },
               func: function(s){
                   return buildInitDiceExpression(s);
               },
               desc: 'Sets the initiative to the lowest of all initiatives rolled for the group.'
           },
           'Mean-All-Roll':{
               mutator: function(l){
                   var mean = l[Math.round((l.length/2)-0.5)];
                   return _.times(l.length, function(){
                       return mean;
                   });
               },
               func: function(s){
                   return buildInitDiceExpression(s);
               },
               desc: 'Sets the initiative to the mean (average) of all initiatives rolled for the group.'
           },
           'Individual-Roll': {
               mutator: function(l){
                   return l;
               },
               func: function(s){
                   return buildInitDiceExpression(s);
               },
               desc: 'Sets the initiative individually for each member of the group.'
           },
           'Constant-By-Stat': {
               mutator: function(l){
                   return l;
               },
               func: function(){
                   return '0';
               },
               desc: 'Sets the initiative individually for each member of the group to their bonus with no roll.'
           }
       },
   checkInstall = function() {    
       log('-=> GroupInitiative v'+version+' <=-  ['+(new Date(lastUpdate*1000))+']');
       if( ! _.has(state,'GroupInitiative') || state.GroupInitiative.version !== schemaVersion) {
           log('  > Updating Schema to v'+schemaVersion+' <');
           switch(state.GroupInitiative && state.GroupInitiative.version) {
               case 0.5:
                   state.GroupInitiative.replaceRoll = false;
                   /* break; // intentional dropthrough */ /* falls through */
               case 0.6:
                   state.GroupInitiative.config = {
                       rollType: state.GroupInitiative.rollType,
                       replaceRoll: state.GroupInitiative.replaceRoll,
                       dieSize: 20,
                       autoOpenInit: true,
                       sortOption: 'Descending'
                   };
                   delete state.GroupInitiative.replaceRoll;
                   delete state.GroupInitiative.rollType;
                   /* break; // intentional dropthrough */ /* falls through */
               case 0.7:
                   state.GroupInitiative.config.announcer = 'Partial';
                   /* break; // intentional dropthrough */ /* falls through */
               case 0.8:
                   state.GroupInitiative.config.diceCount = 1;
                   state.GroupInitiative.config.maxDecimal = 2;
                   /* break; // intentional dropthrough */ /* falls through */
                   
               case 0.9:
                   state.GroupInitiative.config.diceCountAttribute = ;
                   /* break; // intentional dropthrough */ /* falls through */
               case 0.10:
                   if(_.has(state.GroupInitiative.config,'dieCountAttribute')){
                       delete state.GroupInitiative.config.dieCountAttribute;
                       state.GroupInitiative.config.diceCountAttribute = ;
                   }
                   if(_.has(state.GroupInitiative.config,'dieCount')){
                       delete state.GroupInitiative.config.dieCount;
                       state.GroupInitiative.config.diceCount = 1;
                   }
                   /* break; // intentional dropthrough */ /* falls through */
               case 1.0:
                   state.GroupInitiative.savedTurnOrders =[];
                   /* break; // intentional dropthrough */ /* falls through */
               case 'UpdateSchemaVersion':
                   state.GroupInitiative.version = schemaVersion;
                   break;
               default:
                   state.GroupInitiative = {
                       version: schemaVersion,
                       bonusStatGroups: [
                           [
                               {
                                   attribute: 'dexterity'
                               }
                           ]
                       ],
                       savedTurnOrders: [],
                       config: {
                           rollType: 'Individual-Roll',
                           replaceRoll: false,
                           dieSize: 20,
                           diceCount: 1,
                           maxDecimal: 2,
                           diceCountAttribute: ,
                           autoOpenInit: true,
                           sortOption: 'Descending',
                           announcer: 'Partial'
                       }
                   };
                   break;
           }
       }
   },
   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 ;
   },


   buildBonusStatGroupRows = function() {
       return _.reduce(state.GroupInitiative.bonusStatGroups, function(memo,bsg){
return memo + '
  • '+_.chain(bsg) .map(function(s){ var attr=s.attribute+'|'+( _.has(s,'type') ? s.type : 'current' ); if(_.has(s,'adjustments')) { attr=_.reduce(s.adjustments, function(memo2,a) { return a+'( '+memo2+' )'; }, attr); } return attr; }) .value() .join(' + ') + '</li>'; },""); }, buildStatAdjustmentRows = function() { return _.reduce(statAdjustments,function(memo,r,n){ return memo+"
  • "+n+" — "+r.desc+"</li>"; },""); }, getConfigOption_SortOptions = function() { var text = state.GroupInitiative.config.sortOption; return '
    '+
               'Sort Options is currently '+
                   text+
               '.'+
    
    '
    '+
                   _.map(_.keys(sorters),function(so){
                       return '<a href="!group-init-config --sort-option|'+so+'">'+
                           so+
                       '</a>';
                   }).join(' ')+
    
    '
    '+ '
    ';
       },
       getConfigOption_DieSize = function() {
    
    return '
    '+
               'Initiative Die size is currently '+
                   state.GroupInitiative.config.dieSize+
               ' '+
               '<a href="!group-init-config --set-die-size|?{Number of sides the initiative die has:|'+state.GroupInitiative.config.dieSize+'}">'+
                   'Set Die Size'+
               '</a>'+
    
    '
    ';
       },
    
       getConfigOption_DiceCount = function() {
    
    return '
    '+
               'Initiative Dice Count is currently '+
                   state.GroupInitiative.config.diceCount+
               ' '+
               '<a href="!group-init-config --set-dice-count|?{Number of initiative dice to roll:|'+state.GroupInitiative.config.diceCount+'}">'+
                   'Set Dice Count'+
               '</a>'+
    
    '
    ';
       },
    
       getConfigOption_MaxDecimal = function() {
    
    return '
    '+
               'Max decimal places '+
                   state.GroupInitiative.config.maxDecimal+
               ' '+
               '<a href="!group-init-config --set-max-decimal|?{Maximum number of decimal places:|'+state.GroupInitiative.config.maxDecimal+'}">'+
                   'Set Max Decimal'+
               '</a>'+
    
    '
    ';
       },
    
       getConfigOption_DiceCountAttribute = function() {
           var text = (state.GroupInitiative.config.diceCountAttribute.length ? state.GroupInitiative.config.diceCountAttribute : 'DISABLED');
    
    return '
    '+
               'Dice Count Attribute: '+
                   text+
               ' '+
               '<a href="!group-init-config --set-dice-count-attribute|?{Attribute to use for number of initiative dice to roll (Blank to disable):|'+state.GroupInitiative.config.diceCountAttribute+'}">'+
                   'Set Attribute'+
               '</a>'+
    
    '
    ';
       },
    
       getConfigOption_AutoOpenInit = function() {
           var text = (state.GroupInitiative.config.autoOpenInit ? 'On' : 'Off' );
    
    return '
    '+
               'Auto Open Init is currently '+
                   text+
               ' '+
               '<a href="!group-init-config --toggle-auto-open-init">'+
                   'Toggle'+
               '</a>'+
    
    '
    ';
       },
    
       getConfigOption_ReplaceRoll = function() {
           var text = (state.GroupInitiative.config.replaceRoll ? 'On' : 'Off' );
    
    return '
    '+
               'Replace Roll is currently '+
                   text+
               ' '+
               '<a href="!group-init-config --toggle-replace-roll">'+
                   'Toggle'+
               '</a>'+
    
    '

    Sets whether initative scores for selected tokens replace their current scores.

    '+ '
    ';
       },
       getConfigOption_RollerOptions = function() {
           var text = state.GroupInitiative.config.rollType;
    
    return '
    '+
               'Roller is currently '+
                   text+
               '.'+
    
    '
    '+
                   _.map(_.keys(rollers),function(r){
                       return '<a href="!group-init-config --set-roller|'+r+'">'+
                           r+
                       '</a>';
                   }).join(' ')+
    
    '
    '+ '
    ';
       },
       getConfigOption_AnnounceOptions = function() {
           var text = state.GroupInitiative.config.announcer;
    
    return '
    '+
               'Announcer is currently '+
                   text+
               '.'+
    
    '
    '+
                   _.map(_.keys(announcers),function(an){
                       return '<a href="!group-init-config --set-announcer|'+an+'">'+
                           an+
                       '</a>';
                   }).join(' ')+
    
    '
    '+ '
    ';
       },
    
       getAllConfigOptions = function() {
           return getConfigOption_RollerOptions() +
               getConfigOption_SortOptions() +
               getConfigOption_DieSize() +
               getConfigOption_DiceCount() +
               getConfigOption_DiceCountAttribute() +
               getConfigOption_MaxDecimal() +
               getConfigOption_AutoOpenInit() +
               getConfigOption_ReplaceRoll() +
               getConfigOption_AnnounceOptions();
       },
    
       showHelp = function() {
           var rollerRows=_.reduce(rollers,function(memo,r,n){
               var selected=((state.GroupInitiative.config.rollType === n) ? 
    
    '
    Selected
    '
               :  ),
               selectedStyleExtra=((state.GroupInitiative.config.rollType === n) ? ' style="border: 1px solid #aeaeae;background-color:#8bd87a;"' : );
    
    return memo+selected+"
  • "+n+" - "+r.desc+"</li>"; },""), statAdjustmentRows = buildStatAdjustmentRows(), bonusStatGroupRows = buildBonusStatGroupRows(); sendChat(, '/w gm '+ '
    '+ '
    '+
                       'GroupInitiative v'+version+
    
    '
    '+ '
    '+ '

    Rolls initiative for the selected tokens and adds them '+ 'to the turn order if they don'+ch("'")+'t have a turn yet.

    '+ '

    The calculation of initiative is handled by the '+ 'combination of Roller (See Roller Options below) and '+ 'a Bonus. The Bonus is determined based on an ordered list '+ 'of Stat Groups (See Bonus Stat Groups below). Stat '+ 'Groups are evaluated in order. The bonus computed by the first '+ 'Stat Group for which all attributes exist and have a '+ 'numeric value is used. This allows you to have several '+ 'Stat Groups that apply to different types of characters. '+ 'In practice you will probably only have one, but more are '+ 'there if you need them.

    '+ '
    '+
                   'Commands'+
    
    '
    '+
                       '!group-init'+
    
    '
    '+ '

    This command uses the configured Roller to '+ 'determine the initiative order for all selected '+ 'tokens.

    '+ '
    '+ '
    '+ '
    '+
                       '!group-init --help'+
    
    '
    '+ '

    This command displays the help.

    '+ '
    '+ '
    '+ '
    '+
                       '!group-init --promote '+ch('<')+'index'+ch('>')+''+
    
    '
    '+ '

    Increases the importance the specified Bonus Stat Group.

    '+
                           'This command requires 1 parameter:'+
    
    '
      '+ '
    • '+ 'index -- The numeric index of the Bonus Stat Group to promote. See Bonus Stat Groups below.'+ '
    • '+ '
    '+ '
    '+ '
    '+ '
    '+
                       '!group-init --del-group '+ch('<')+'index'+ch('>')+''+
    
    '
    '+ '

    Deletes the specified Bonus Stat Group.

    '+
                           'This command requires 1 parameter:'+
    
    '
      '+ '
    • '+ 'index -- The numeric index of the Bonus Stat Group to delete. See Bonus Stat Groups below.'+ '
    • '+ '
    '+ '
    '+ '
    '+ '
    '+
                       '!group-init --add-group --'+ch('<')+'adjustment'+ch('>')+' [--'+ch('<')+'adjustment'+ch('>')+'] '+ch('<')+'attribute name[|'+ch('<')+'max|current'+ch('>')+']'+ch('>')+' [--'+ch('<')+'adjustment'+ch('>')+' [--'+ch('<')+'adjustment'+ch('>')+'] '+ch('<')+'attribute name[|'+ch('<')+'max|current'+ch('>')+']'+ch('>')+' ...]  '+
    
    '
    '+ '

    Adds a new Bonus Stat Group to the end of the list. Each adjustment operation can be followed by another adjustment operation, but eventually must end in an attriute name. Adjustment operations are applied to the result of the adjustment operations that follow them.

    '+ '

    For example: --Bounded:-2:2 --Stat-DnD wisdom|max would first computer the DnD Stat bonus for the max field of the wisdom attribute, then bound it between -2 and +2.

    '+
                           'This command takes multiple parameters:'+
    
    '
      '+ '
    • '+ 'adjustment -- One of the Stat Adjustment Options. See Stat Adjustment Options below.'+ '
    • '+ '
    • '+ 'attribute name -- The name of an attribute. You can specify |max or |current on the end to target those specific fields (defaults to |current).'+ '
    • '+ '
    '+ '
    '+ '
    '+ '
    '+
                       '!group-init --reroll '+ch('[')+'bonus'+ch(']')+''+
    
    '
    '+ '

    Rerolls all the tokens in the turn order as if they were selected when you executed the bare !group-init command.

    '+
                           'This command has 1 optional parameter:'+
    
    '
      '+ '
    • '+ 'bonus -- The value to be added to all the rolls. This can be positive or negative and can have decimal places.'+ '
    • '+ '
    '+ '
    '+ '
    '+ '
    '+
                       '!group-init --toggle-turnorder '+ch('[')+'bonus'+ch(']')+''+
    
    '
    '+ '

    Opens or closes the Turnorder window.

    '+ '
    '+ '
    '+ '
    '+
                       '!group-init --sort'+
    
    '
    '+ '

    Applies the configured sort operation to the current turn order.

    '+ '
    '+ '
    '+ '
    '+
                       '!group-init --clear'+
    
    '
    '+ '

    Removes all tokens from the turn order. If Auto Open Init is enabled it will also close the turn order box.

    '+ '
    '+ '
    '+ '
    '+
                       '!group-init --bonus '+ch('<')+'number'+ch('>')+''+
    
    '
    '+ '

    Rolls the selected tokens and adds a bonus to the roll.

    '+
                           'This command requires 1 parameter:'+
    
    '
      '+ '
    • '+ 'number -- The value to be added to all the rolls. This can be positive or negative and can have decimal places.'+ '
    • '+ '
    '+ '
    '+ '
    '+ '
    '+
                       '!group-init --adjust '+ch('<')+'adjustment'+ch('>')+' '+ch('[')+'minimum'+ch(']')+''+
    
    '
    '+ '

    Applies an adjustment to all the current turnorder tokens (Custom entries ignored)

    '+
                           'This command requires 1 parameter and has 1 optional parameter:'+
    
    '
      '+ '
    • '+ 'adjustment -- The value to be added to all the current initiative values. This can be positive or negative and can have decimal places.'+ '
    • '+ '
    • '+ 'minimum -- (optional) The minimum value for all initiative scores. This can be positive or negative and can have decimal places.
      Note: this can raise initiative scores if it is higher than their current score.'+ '
    • '+ '
    '+ '
    '+ '
    '+ '
    '+
                       '!group-init --adjust-current '+ch('<')+'adjustment'+ch('>')+' '+ch('[')+'minimum'+ch(']')+''+
    
    '
    '+ '

    Applies an adjustment to the current token'+ch("'")+'s turn (Custom entries ignored)

    '+
                           'This command requires 1 parameter and has 1 optional parameter:'+
    
    '
      '+ '
    • '+ 'adjustment -- The value to be added to the current initiative value. This can be positive or negative and can have decimal places.'+ '
    • '+ '
    • '+ 'minimum -- (optional) The minimum value for the initiative score. This can be positive or negative and can have decimal places.
      Note: this can raise initiative scores if it is higher than their current score.'+ '
    • '+ '
    '+ '
    '+ '
    '+ '
    '+
                       '!group-init --stack '+ch('[')+'operation'+ch(']')+' '+ch('[')+'label'+ch(']')+''+
    
    '
    '+ '

    Manages the saved turn orders.

    '+
                           'Operations'+
    
    '
      '+ '
    • '+ 'list -- Displays the stack of saved turn orders. (default)'+ '
    • '+ '
    • '+ 'clear -- Clears the stack of saved turn orders.'+ '
    • '+ '
    • '+ 'copy'+ch('|')+'dup '+ch('[')+'label'+ch(']')+' -- Adds a copy of the current turn order to the stack.'+ '
    • '+ '
    • '+ 'push '+ch('[')+'label'+ch(']')+' -- Adds a copy of the current turn order to the stack and clears the turn order. Anything after the command will be used as a label for the entry.'+ '
    • '+ '
    • '+ 'pop -- Replaces the current turn order with the last entry in the stack removing it from the stack.'+ '
    • '+ '
    • '+ 'apply -- Replaces the current turn order with the last entry in the stack leaving it on the stack.'+ '
    • '+ '
    • '+ 'swap '+ch('[')+'label'+ch(']')+' -- Swaps the current turn order with the last entry in the stack. Anything after the command will be used as a label for the entry placed in the stack.'+ '
    • '+ '
    • '+ 'tswap'+ch('|')+'tail-swap '+ch('[')+'label'+ch(']')+' -- Swaps the current turn order with the first entry in the stack. Anything after the command will be used as a label for the entry placed in the stack.'+ '
    • '+ '
    • '+ 'merge -- Removes the last entry in the stack and adds it to the current turn order and sorts the new turn order with the configured sort method.'+ '
    • '+ '
    • '+ 'apply-merge'+ch('|')+'amerge -- Merges the last entry in the stack with the current turn order and sorts the new turn order with the configured sort method, leaving the stack unchanged.'+ '
    • '+ '
    • '+ 'rotate'+ch('|')+'rot '+ch('[')+'label'+ch(']')+' -- Pushes the current turn order onto the end of the stack and restores the first entry from the stack to the turn order. Anything after the command will be used as a label for the entry placed in the stack.'+ '
    • '+ '
    • '+ 'reverse-rotate'+ch('|')+'rrot '+ch('[')+'label'+ch(']')+' -- Pushes the current turn order onto the beginning of the stack and restores the last entry from the stack to the turn order. Anything after the command will be used as a label for the entry placed in the stack.'+ '
    • '+ '
    '+ '
    '+ '
    '+


                   'Roller Options'+
    
    '
    '+ '
      '+ rollerRows+ '
    '+ '
    '+
                   'Stat Adjustment Options'+
    
    '
    '+ '
      '+ statAdjustmentRows+ '
    '+ '
    '+
                   'Bonus Stat Groups'+
    
    '
    '+ '
      '+ bonusStatGroupRows+ '
    '+ '
    '+
                   getAllConfigOptions()+
    
    '
    '
           );
       },
    
       parseEmbeddedStatReferences = function(stat,charObj){
           let charName=charObj.get('name'),
               stext=(stat+).replace(/@{[^}]*}/g,(s)=>{
                   let parts=_.rest(s.match(/@{([^|}]*)\|?([^|}]*)\|?([^|}]*)}/)),
                       statName,modName;
                   if(parts[2].length){
                       statName=parts[1];
                       modName=parts[2];
                   } else if(parts[1].length){
                       if(_.contains(['max','current'],parts[1])){
                           statName=parts[0];
                           modName=parts[1];
                       } else {
                           statName=parts[1];
                       }
                   } else {
                       statName=parts[0];
                   }
                   
                   return `@{${charName}|${statName}${modName?`|${modName}`:}}`;
               })
               .replace(/&{tracker}/,);
           return stext;
       },
    
       findInitiativeBonus = function(charObj,/*eslint-disable no-unused-vars*/token/*eslint-enable no-unused-vars*/) {
           var bonus = ;
           if(_.has(bonusCache,charObj.id)) {
               return bonusCache[charObj.id];
           }
           _.find(state.GroupInitiative.bonusStatGroups, function(group){
               bonus = _.chain(group)
                   .map(function(details){
                       
                       var stat=getAttrByName(charObj.id,details.attribute, details.type||'current');
                       if( ! _.isUndefined(stat) && !_.isNull(stat) && 
                           _.isNumber(stat) || (_.isString(stat) && stat.length)
                       ) {
                           stat = parseEmbeddedStatReferences(stat,charObj);
                           stat = _.reduce(details.adjustments || [],function(memo,a){
                               var args,adjustment,func;
                               if(memo) {
                                   args=a.split(':');
                                   adjustment=args.shift().toLowerCase();
                                   args.unshift(memo);
                                   func=statAdjustments[adjustment].func;
                                   if(_.isFunction(func)) {
                                       memo =func.apply({},args);
                                   }
                               }
                               return memo;
                           },stat);
                           return stat;
                       }
                       return undefined;
                   })
                   .value();
    
               if(_.contains(bonus,undefined) || _.contains(bonus,null) || _.contains(bonus,NaN)) {
                   bonus=;
                   return false;
               }
               bonus = bonus.join('+');
               return true;
           });
           bonusCache[charObj.id]=bonus;
           return bonus;
       },
    
       handleInput = function(msg_orig) {
           var msg = _.clone(msg_orig),
               prev=Campaign().get('turnorder'),
               args,
               cmds,
               workgroup,
               workvar,
               turnorder,
               pageid=false,
               error=false,
               initFunc,
               rollSetup,
               initRolls,
               cont=false,
               manualBonus=0,
               manualBonusMin=0,
               turnEntries,
               finalize,
               isReroll=false
               ;
    
           if (msg.type !== "api" ) {
               return;
           }
    
           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.split(/\s+--/);
           switch(args.shift()) {
               case '!group-init':
                   if(args.length > 0) {
                       cmds=args.shift().split(/\s+/);
    
                       switch(cmds[0]) {
                           case 'help':
                               if(!playerIsGM(msg.playerid)){
                                   return;
                               }
                               showHelp();
                               break;
    
                           case 'add-group':
                               if(!playerIsGM(msg.playerid)){
                                   return;
                               }
                               workgroup=[];
                               workvar={};
    
                               _.each(args,function(arg){
                                   var argParts=arg.split(/\s+(.+)/),
                                   adjustmentName,
                                   parameter=argParts[0].split(/:/);
                                   parameter[0]=parameter[0].toLowerCase();
    
                                   if(_.has(statAdjustments,parameter[0])) {
                                       if('bare' !== parameter[0]) {
                                           if(!_.has(workvar,'adjustments')) {
                                               workvar.adjustments=[];
                                           }
                                           workvar.adjustments.unshift(argParts[0]);
                                       }
                                       if(argParts.length > 1){
                                           adjustmentName=argParts[1].split(/\|/);
                                           workvar.attribute=adjustmentName[0];
                                           if('max'===adjustmentName[1]) {
                                               workvar.type = 'max';
                                           }
                                           workgroup.push(workvar);
                                           workvar={};
                                       }
                                   } else {
                                       sendChat('!group-init --add-group', '/w gm ' +
    
    '
    '+
                                               'Unknown Stat Adjustment: '+parameter[0]+'
    '+ 'Use one of the following:'+
    '
      '+ buildStatAdjustmentRows()+ '
    '+ '
    '
                                       );
                                       error=true;
                                   }
                               });
                               if(!error) {
                                   if(!_.has(workvar,'adjustments')){
                                       state.GroupInitiative.bonusStatGroups.push(workgroup);
                                       sendChat('GroupInitiative', '/w gm ' +
    
    '
    '+
                                               'Updated Bonus Stat Group Ordering:'+
    
    '
      '+ buildBonusStatGroupRows()+ '
    '+ '
    '
                                       );
                                   } else {
                                       sendChat('!group-init --add-group', '/w gm ' +
    
    '
    '+
                                               'All Stat Adjustments must have a final attribute name as an argument.  Please add an attribute name after --'+args.pop()+
    
    '
    '
                                       );
                                   }
                               }
                               break;
    
                           case 'stack': {
                               if(!playerIsGM(msg.playerid)){
                                   return;
                               }
                               cmds.shift();
                               let operation=cmds.shift(),
                                   showdate=function(ms){
                                       let ds=Math.round((_.now()-ms)/1000),
                                           str=[];
    
                                       if(ds>86400){
                                           str.push(`${Math.round(ds/86400)}d`);
                                           ds%=86400;
                                       }
                                       if(ds>3600){
                                           str.push(`${Math.round(ds/3600)}h`);
                                           ds%=3600;
                                       }
    
                                       if(ds>60){
                                           str.push(`${Math.round(ds/60)}m`);
                                           ds%=60;
                                       }
                                       str.push(`${Math.round(ds)}s`);
                                       
                                       return str.join(' ');
                                   },
                                   stackrecord=function(label){
                                       let toRaw=Campaign().get('turnorder'),
                                           to=JSON.parse(toRaw)||[],
                                           summary=_.chain(to)
                                               .map((o)=>{
                                                   return {
                                                       entry: o,
                                                       token: getObj('graphic',o.id)
                                                   };
                                               })
                                               .map((o)=>{
                                                   return {
                                                       img: (o.token ? o.token.get('imgsrc') : ), 
                                                       name: (o.token ? o.token.get('name') : o.entry.custom), 
                                                       pr: o.entry.pr
                                                   };
                                               })
                                               .value();
    
                                       return {
                                           label: label || (to.length ? `{${to.length} records}`: '{empty}'),
                                           date: _.now(),
                                           summary: summary,
                                           turnorder: toRaw
                                       };
                                   },
                                   toMiniDisplay=function(summary){
    
    return '
    '+
                                           _.map(summary,(sume)=>{
    
    return `
    ${sume.pr}
    <img style="max-height:1.5em;float:left;" src="${sume.img}">${sume.name||'&'+'nbsp;'}
    `;
                                           }).join()+
    
    '
    ';
                                   },
                                   stacklist=function(){
                                       sendChat(, '/w gm ' +
    
    '
      '+ _.map(state.GroupInitiative.savedTurnOrders,(o)=>`
    1. ${o.label} [${showdate(o.date)}]${toMiniDisplay(o.summary)}
    2. `).join()+ '
    '
                                       );
    
                                   };
                               switch(operation){
                                   case 'dup':
                                   case 'copy':
                                       // take current turn order and put it on top.
                                       state.GroupInitiative.savedTurnOrders.push(stackrecord(cmds.join(' ')));
                                       stacklist();
                                       break;
                                   case 'push':
                                       // take current turn order and put it on top.
                                       state.GroupInitiative.savedTurnOrders.push(stackrecord(cmds.join(' ')));
                                       Campaign().set('turnorder','[]');
                                       notifyObservers('turnOrderChange',Campaign().get('turnorder'),prev);
                                       stacklist();
                                       break;
                                   case 'pop':
                                       if(state.GroupInitiative.savedTurnOrders.length){
                                           let sto=state.GroupInitiative.savedTurnOrders.pop();
                                           Campaign().set('turnorder',sto.turnorder);
                                           notifyObservers('turnOrderChange',Campaign().get('turnorder'),prev);
                                           stacklist();
                                       } else {
                                           sendChat('!group-init --stack pop', '/w gm ' +
    
    '
    '+
                                                   'No Saved Turn Orders to restore!'+
    
    '
    '
                                           );
                                       }
                                       break;
                                   case 'apply':
                                       if(state.GroupInitiative.savedTurnOrders.length){
                                           let sto=state.GroupInitiative.savedTurnOrders[0];
                                           Campaign().set('turnorder',sto.turnorder);
                                           notifyObservers('turnOrderChange',Campaign().get('turnorder'),prev);
                                           stacklist();
                                       } else {
                                           sendChat('!group-init --stack pop', '/w gm ' +
    
    '
    '+
                                                   'No Saved Turn Orders to apply!'+
    
    '
    '
                                           );
                                       }
                                       break;
                                   case 'rot':
                                   case 'rotate':
                                       if(state.GroupInitiative.savedTurnOrders.length){
                                           let sto=state.GroupInitiative.savedTurnOrders.shift();
                                           state.GroupInitiative.savedTurnOrders.push(stackrecord(cmds.join(' ')));
                                           Campaign().set('turnorder',sto.turnorder);
                                           notifyObservers('turnOrderChange',Campaign().get('turnorder'),prev);
                                           stacklist();
                                       }
                                       break;
                                   case 'rrot':
                                   case 'reverse-rotate':
                                       if(state.GroupInitiative.savedTurnOrders.length){
                                           let sto=state.GroupInitiative.savedTurnOrders.pop();
                                           state.GroupInitiative.savedTurnOrders.unshift(stackrecord(cmds.join(' ')));
                                           Campaign().set('turnorder',sto.turnorder);
                                           notifyObservers('turnOrderChange',Campaign().get('turnorder'),prev);
                                           stacklist();
                                       }
                                       break;
                                   case 'swap':
                                       
                                       if(state.GroupInitiative.savedTurnOrders.length){
                                           let sto=state.GroupInitiative.savedTurnOrders.shift();
                                           state.GroupInitiative.savedTurnOrders.unshift(stackrecord(cmds.join(' ')));
                                           Campaign().set('turnorder',sto.turnorder);
                                           notifyObservers('turnOrderChange',Campaign().get('turnorder'),prev);
                                           stacklist();
                                       }
                                       break;
                                   case 'tswap':
                                   case 'tail-swap':
                                       if(state.GroupInitiative.savedTurnOrders.length){
                                           let sto=state.GroupInitiative.savedTurnOrders.pop();
                                           state.GroupInitiative.savedTurnOrders.push(stackrecord(cmds.join(' ')));
                                           Campaign().set('turnorder',sto.turnorder);
                                           notifyObservers('turnOrderChange',Campaign().get('turnorder'),prev);
                                           stacklist();
                                       }
                                       break;
                                   case 'amerge':
                                   case 'apply-merge':
                                       if(state.GroupInitiative.savedTurnOrders.length){
                                           let sto=state.GroupInitiative.savedTurnOrders[0];
                                           
                                           Campaign().set('turnorder', JSON.stringify(
                                               sorters[state.GroupInitiative.config.sortOption](
                                                   _.union(
                                                       JSON.parse(Campaign().get('turnorder'))||[],
                                                       JSON.parse(sto.turnorder)||[]
                                                   )
                                               )
                                           ));
    
                                           notifyObservers('turnOrderChange',Campaign().get('turnorder'),prev);
                                           stacklist();
                                       }
                                       break;
                                   case 'merge':
                                       if(state.GroupInitiative.savedTurnOrders.length){
                                           let sto=state.GroupInitiative.savedTurnOrders.pop();
                                           
                                           Campaign().set('turnorder', JSON.stringify(
                                               sorters[state.GroupInitiative.config.sortOption](
                                                   _.union(
                                                       JSON.parse(Campaign().get('turnorder'))||[],
                                                       JSON.parse(sto.turnorder)||[]
                                                   )
                                               )
                                           ));
    
                                           notifyObservers('turnOrderChange',Campaign().get('turnorder'),prev);
                                           stacklist();
                                       }
                                       break;
    
                                   case 'clear':
                                       state.GroupInitiative.savedTurnOrders=[];
                                       break;
    
                                   default:
                                   case 'list':
                                       stacklist();
                                       break;
                               }
                               }
                               break;
    
                           case 'promote':
                               if(!playerIsGM(msg.playerid)){
                                   return;
                               }
                               cmds[1]=Math.max(parseInt(cmds[1],10),1);
                               if(state.GroupInitiative.bonusStatGroups.length >= cmds[1]) {
                                   if(1 !== cmds[1]) {
                                       workvar=state.GroupInitiative.bonusStatGroups[cmds[1]-1];
                                       state.GroupInitiative.bonusStatGroups[cmds[1]-1] = state.GroupInitiative.bonusStatGroups[cmds[1]-2];
                                       state.GroupInitiative.bonusStatGroups[cmds[1]-2] = workvar;
                                   }
    
                                   sendChat('GroupInitiative', '/w gm ' +
    
    '
    '+
                                           'Updated Bonus Stat Group Ordering:'+
    
    '
      '+ buildBonusStatGroupRows()+ '
    '+ '
    '
                                   );
                               } else {
                                   sendChat('!group-init --promote', '/w gm ' +
    
    '
    '+
                                           'Please specify one of the following by number:'+
    
    '
      '+ buildBonusStatGroupRows()+ '
    '+ '
    '
                                   );
                               }
                               break;
    
                           case 'del-group':
                               if(!playerIsGM(msg.playerid)){
                                   return;
                               }
                               cmds[1]=Math.max(parseInt(cmds[1],10),1);
                               if(state.GroupInitiative.bonusStatGroups.length >= cmds[1]) {
                                   state.GroupInitiative.bonusStatGroups=_.filter(state.GroupInitiative.bonusStatGroups, function(v,k){
                                       return (k !== (cmds[1]-1));
                                   });
    
                                   sendChat('GroupInitiative', '/w gm ' +
    
    '
    '+
                                           'Updated Bonus Stat Group Ordering:'+
    
    '
      '+ buildBonusStatGroupRows()+ '
    '+ '
    '
                                   );
                               } else {
                                   sendChat('!group-init --del-group', '/w gm ' +
    
    '
    '+
                                           'Please specify one of the following by number:'+
    
    '
      '+ buildBonusStatGroupRows()+ '
    '+ '
    '
                                   );
                               }
                               break;
    
                           case 'toggle-turnorder':
                               if(!playerIsGM(msg.playerid)){
                                   return;
                               }
                               if(false !== Campaign().get('initiativepage') ){
                                   Campaign().set({
                                       initiativepage: false
                                   });
                               } else {
                                   let player = (getObj('player',msg.playerid)||{get: ()=>true});
                                   Campaign().set({
                                       initiativepage: player.get('_lastpage')
                                   });
                               }
                               break;
                           case 'reroll':
                               isReroll=true;
                               if(cmds[1] && cmds[1].match(/^[-+]?\d+(\.\d+)?$/)){
                                   manualBonus=parseFloat(cmds[1])||0;
                               }
                               msg.selected= _.chain(JSON.parse(Campaign().get('turnorder'))||[])
                                   .filter(function(e){
                                       return '-1' !== e.id;
                                   })
                                   .map(function(e){
                                       return {_type: 'graphic', _id: e.id};
                                   })
                                   .value();
                               cont=true;
                               notifyObservers('turnOrderChange',Campaign().get('turnorder'),prev);
                               break;
    
                           case 'sort':
                               if(!playerIsGM(msg.playerid)){
                                   return;
                               }
                               Campaign().set('turnorder', JSON.stringify(
                                   sorters[state.GroupInitiative.config.sortOption](
                                       JSON.parse(Campaign().get('turnorder'))||[]
                                   )
                               ));
                               notifyObservers('turnOrderChange',Campaign().get('turnorder'),prev);
                               break;
    
                           case 'adjust':
                               if(!playerIsGM(msg.playerid)){
                                   return;
                               }
                               if(cmds[1] && cmds[1].match(/^[-+]?\d+(\.\d+)?$/)){
                                   manualBonus=parseFloat(cmds[1]);
                                   manualBonusMin=parseFloat(cmds[2]);
                                   manualBonusMin=_.isNaN(manualBonusMin)?-10000:manualBonusMin;
                                   
                                   Campaign().set({
                                       turnorder: JSON.stringify(
                                           _.map(JSON.parse(Campaign().get('turnorder'))||[], function(e){
                                               if('-1' !== e.id){
                                                   e.pr=Math.max((_.isNaN(parseFloat(e.pr))?0:parseFloat(e.pr))+manualBonus,manualBonusMin).toFixed(state.GroupInitiative.config.maxDecimal);
                                               }
                                               return e;
                                           })
                                       )
                                   });
                                   notifyObservers('turnOrderChange',Campaign().get('turnorder'),prev);
                               } else {
                                   sendChat('GroupInitiative', '/w gm ' +
    
    '
    '+
                                           'Not a valid adjustment: '+cmds[1]+''+
    
    '
    '
                                   );
                               }
                               break;
    
                           case 'adjust-current':
                               if(!playerIsGM(msg.playerid)){
                                   return;
                               }
                               if(cmds[1] && cmds[1].match(/^[-+]?\d+(\.\d+)?$/)){
                                   manualBonus=parseFloat(cmds[1]);
                                   manualBonusMin=parseFloat(cmds[2]);
                                   manualBonusMin=_.isNaN(manualBonusMin)?-10000:manualBonusMin;
                                   
                                   Campaign().set({
                                       turnorder: JSON.stringify(
                                           _.map(JSON.parse(Campaign().get('turnorder'))||[], function(e,idx){
                                               if(0===idx && '-1' !== e.id){
                                                   e.pr=Math.max((_.isNaN(parseFloat(e.pr))?0:parseFloat(e.pr))+manualBonus,manualBonusMin).toFixed(state.GroupInitiative.config.maxDecimal);
                                               }
                                               return e;
                                           })
                                       )
                                   });
                                   notifyObservers('turnOrderChange',Campaign().get('turnorder'),prev);
                               } else {
                                   sendChat('GroupInitiative', '/w gm ' +
    
    '
    '+
                                           'Not a valid adjustment: '+cmds[1]+''+
    
    '
    '
                                   );
                               }
                               break;
    


                           case 'clear':
                               if(!playerIsGM(msg.playerid)){
                                   return;
                               }
                               Campaign().set({
                                   turnorder: '[]',
                                   initiativepage: (state.GroupInitiative.config.autoOpenInit ? false : Campaign().get('initiativepage'))
                               });
                               notifyObservers('turnOrderChange',Campaign().get('turnorder'),prev);
                               break;
    
                           case 'bonus':
                               if(cmds[1] && cmds[1].match(/^[-+]?\d+(\.\d+)?$/)){
                                   manualBonus=parseFloat(cmds[1]);
                                   cont=true;
                               } else {
                                   sendChat('GroupInitiative', '/w gm ' +
    
    '
    '+
                                           'Not a valid bonus: '+cmds[1]+''+
    
    '
    '
                                   );
                               }
                               break;
    
                           default:
                               if(!playerIsGM(msg.playerid)){
                                   return;
                               }
                               sendChat('GroupInitiative', '/w gm ' +
    
    '
    '+
                                       'Not a valid command: '+cmds[0]+''+
    
    '
    '
                               );
                               break;
                       }
                   } else {
                       cont=true;
                   }
    
                   if(cont) {
                       if(_.has(msg,'selected')) {
                           bonusCache = {};
                           turnorder = Campaign().get('turnorder');
                           turnorder = ( === turnorder) ? [] : JSON.parse(turnorder);
                           if(state.GroupInitiative.config.replaceRoll || isReroll) {
                               turnorder=_.reject(turnorder,function(i){
                                   return _.contains(_.pluck(msg.selected, '_id'),i.id);
                               });
                           }
    
                           initFunc=rollers[state.GroupInitiative.config.rollType].func;
    
                           rollSetup = _.chain(msg.selected)
                               .map(function(s){
                                   return getObj(s._type,s._id);
                               })
                               .reject(_.isUndefined)
                               .reject(function(s){
                                   return _.contains(_.pluck(turnorder,'id'),s.id);
                               })
                               .map(function(s){
                                   pageid=pageid || s.get('pageid');
                                   return {
                                       token: s,
                                       character: getObj('character',s.get('represents'))
                                   };
                               })
                               .map(function(s){
                                   s.roll=[];
                                   if(s.character) {
                                       let bonus=findInitiativeBonus(s.character,s.token);
                                       bonus = (_.isString(bonus) ? (bonus.trim().length ? bonus : '0') : bonus);
                                       s.roll.push( bonus );
                                   }
                                   if(manualBonus) {
                                       s.roll.push( manualBonus );
                                   }
                                   s.roll.push( initFunc(s) );
                                   return s;
                               })
                               .value();
    
                           initRolls = _.map(rollSetup,function(rs,i){
                                   return {
                                       index: i,
                                       roll: ('[[('+ _.reject(rs.roll,function(r){
                                                   return _.isString(r) && _.isEmpty(r);
                                               })
                                               .join(') + (')+')]]')
                                               .replace(/\[\[\[/g, "[[ [")
                                   };
                               });
    


       turnEntries = [];
       finalize = _.after(initRolls.length,function(){
           turnEntries = _.sortBy(turnEntries,'order');
           turnEntries = rollers[state.GroupInitiative.config.rollType].mutator(turnEntries);
    
           Campaign().set({
               turnorder: JSON.stringify(
                   sorters[state.GroupInitiative.config.sortOption](
                       turnorder.concat(
                           _.chain(rollSetup)
                           .map(function(s){
                               s.rollResults=turnEntries.shift();
                               return s;
                           })
                           .tap(announcers[state.GroupInitiative.config.announcer])
                           .map(function(s){
                               return {
                                   id: s.token.id,
                                   pr: s.rollResults.total,
                                   custom: 
                               };
                           })
                           .value()
                       )
                   )
               )
           });
           notifyObservers('turnOrderChange',Campaign().get('turnorder'),prev);
    
           if(state.GroupInitiative.config.autoOpenInit && !Campaign().get('initativepage')) {
               Campaign().set({
                   initiativepage: pageid
               });
           }
       });
    
       _.each(initRolls, function(ir){
           sendChat(,ir.index+':'+ir.roll.replace(/\[\[\s+/,'[[') ,function(msg){
               var parts = msg[0].content.split(/:/),
                   ird = msg[0].inlinerolls[parts[1].match(/\d+/)],
                   rdata = {
                       order: parseInt(parts[0],10),
                       total: (ird.results.total%1===0 ?
                           ird.results.total :
                               parseFloat(ird.results.total.toFixed(state.GroupInitiative.config.maxDecimal))),
                       rolls: _.reduce(ird.results.rolls,function(m,rs){
                           if('R' === rs.type) {
                               m.push({
                                   sides: rs.sides,
                                   rolls: _.pluck(rs.results,'v')
                               });
                           }
                           return m;
                       },[])
                   };
    
               rdata.bonus = (ird.results.total - (_.reduce(rdata.rolls,function(m,r){
                   m+=_.reduce(r.rolls,function(s,dieroll){
                       return s+dieroll;
                   },0);
                   return m;
               },0)));
    
               rdata.bonus = (rdata.bonus%1===0 ?
                   rdata.bonus :
                   parseFloat(rdata.bonus.toFixed(state.GroupInitiative.config.maxDecimal)));
    
               turnEntries.push(rdata);
    
               finalize();
           });
       });
                       } else {
                           showHelp();
                       }
                   }
                   break;
               case '!group-init-config':
                   if(!playerIsGM(msg.playerid)){
                       return;
                   }
                   if(_.contains(args,'--help')) {
                       showHelp();
                       return;
                   }
                   if(!args.length) {
                       sendChat(,'/w gm '+
    
    '
    '+ '
    '+
                                   'GroupInitiative v'+version+
    
    '
    '+
                               getAllConfigOptions()+
    
    '
    '
                       );
                       return;
                   }
                   _.each(args,function(a){
                       var opt=a.split(/\|/),
                           omsg=;
                       switch(opt.shift()) {
                           case 'sort-option':
                               if(sorters[opt[0]]) {
                                  state.GroupInitiative.config.sortOption=opt[0];
                               } else {
    
    omsg='
    Error: Not a valid sort method: '+opt[0]+'
    ';
                               }
                               sendChat(,'/w gm '+
    
    '
    '+
                                       omsg+
                                       getConfigOption_SortOptions()+
    
    '
    '
                               );
                               break;
                           case 'set-die-size':
                               if(opt[0].match(/^\d+$/)) {
                                  state.GroupInitiative.config.dieSize=parseInt(opt[0],10);
                               } else {
    
    omsg='
    Error: Not a die size: '+opt[0]+'
    ';
                               }
                               sendChat(,'/w gm '+
    
    '
    '+
                                       omsg+
                                       getConfigOption_DieSize()+
    
    '
    '
                               );
                               break;
    
                           case 'set-max-decimal':
                               if(opt[0].match(/^\d+$/)) {
                                  state.GroupInitiative.config.maxDecimal=parseInt(opt[0],10);
                               } else {
    
    omsg='
    Error: Not a valid decimal count: '+opt[0]+'
    ';
                               }
                               sendChat(,'/w gm '+
    
    '
    '+
                                       omsg+
                                       getConfigOption_MaxDecimal()+
    
    '
    '
                               );
                               break;
    


                           case 'set-dice-count':
                               if(opt[0].match(/^\d+$/)) {
                                  state.GroupInitiative.config.diceCount=parseInt(opt[0],10);
                               } else {
    
    omsg='
    Error: Not a valid dice count: '+opt[0]+'
    ';
                               }
                               sendChat(,'/w gm '+
    
    '
    '+
                                       omsg+
                                       getConfigOption_DiceCount()+
    
    '
    '
                               );
                               break;
    
                           case 'set-dice-count-attribute':
                               if(opt[0]) {
                                  state.GroupInitiative.config.diceCountAttribute=opt[0];
                               } else {
                                   state.GroupInitiative.config.diceCountAttribute=;
    
    omsg='
    Cleared Dice Count Attribute.
    ';
                               }
                               sendChat(,'/w gm '+
    
    '
    '+
                                       omsg+
                                       getConfigOption_DiceCountAttribute()+
    
    '
    '
                               );
                               break;
    
                           case 'toggle-auto-open-init':
                               state.GroupInitiative.config.autoOpenInit = !state.GroupInitiative.config.autoOpenInit;
                               sendChat(,'/w gm '+
    
    '
    '+
                                       getConfigOption_AutoOpenInit()+
    
    '
    '
                               );
                               break;
    
                           case 'toggle-replace-roll':
                               state.GroupInitiative.config.replaceRoll = !state.GroupInitiative.config.replaceRoll;
                               sendChat(,'/w gm '+
    
    '
    '+
                                       getConfigOption_ReplaceRoll()+
    
    '
    '
                               );
                               break;
    
                           case 'set-announcer':
                               if(announcers[opt[0]]) {
                                  state.GroupInitiative.config.announcer=opt[0];
                               } else {
    
    omsg='
    Error: Not a valid announcer: '+opt[0]+'
    ';
                               }
                               sendChat(,'/w gm '+
    
    '
    '+
                                       omsg+
                                       getConfigOption_AnnounceOptions()+
    
    '
    '
                               );
                               break;
    
                           case 'set-roller':
                               if(rollers[opt[0]]) {
                                  state.GroupInitiative.config.rollType=opt[0];
                               } else {
    
    omsg='
    Error: Not a valid roller: '+opt[0]+'
    ';
                               }
                               sendChat(,'/w gm '+
    
    '
    '+
                                       omsg+
                                       getConfigOption_RollerOptions()+
    
    '
    '
                               );
                               break;
    
                           default:
                               sendChat(,'/w gm '+
    
    '
    Unsupported Option:</div> '+a+'</div>'
                               );
                       }
                               
                   });
    
                   break;
           }
    
       },
    


       registerEventHandlers = function() {
           on('chat:message', handleInput);
       };
    
       return {
           RegisterEventHandlers: registerEventHandlers,
           ObserveTurnOrderChange: observeTurnOrderChange,
           CheckInstall: checkInstall
       };
    

    }());

    on("ready",function(){

       'use strict';
    
           GroupInitiative.CheckInstall();
           GroupInitiative.RegisterEventHandlers();
    

    });


    © 2018 GitHub, Inc. Terms Privacy Security Status Help Contact GitHub Pricing API Training Blog About Press h to open a hovercard with more details.