diff --git a/GroupInitiative/GroupInitiative.js b/GroupInitiative/GroupInitiative.js index 4b49c969cc..f758728b5d 100644 --- a/GroupInitiative/GroupInitiative.js +++ b/GroupInitiative/GroupInitiative.js @@ -5,10 +5,150 @@ var GroupInitiative = GroupInitiative || (function() { 'use strict'; - var version = '0.8.2', - lastUpdate = 1430695680, - schemaVersion = 0.6, + var version = '0.8.7', + lastUpdate = 1431320918, + schemaVersion = 0.8, bonusCache = {}, + 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); + }); + } + }, + 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; }); + }; + }()), + formatDieRoll = function(die, bonus) { + var highlight = ( 1 === die + ? '#B31515' + : ( state.GroupInitiative.config.dieSize === die + ? '#3FB315' + : '#FEF68E' + ) + ), + dielight=( 1 === die + ? '#ff0000' + : ( state.GroupInitiative.config.dieSize === die + ? '#00ff00' + : 'white' + ) + ); + return ''+ + ''+die+' [init] '+ + (bonus>=0 ? '+' :'-')+' '+Math.abs(bonus)+' [bonus]'+ + '' + ))+'">'+ + (die+bonus)+ + ''; + }, + 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('
'+ + '
'+ + ''+ + ((s.token && s.token.get('name')) || (s.character && s.character.get('name')) || '(Creature)')+ + '
'+ + '
'+ + formatDieRoll(Math.round(s.init-s.bonus),s.bonus)+ + '
'+ + '
'+ + '
'); + return m; + },{npc:[],character:[],gmlayer:[]}); + }, + announcers = { + 'None': function() { + }, + 'Hidden': function(l) { + var groups=buildAnnounceGroups(l); + sendChat('GroupInit','/w gm '+ + '
'+ + groups.character.join('')+ + groups.npc.join('')+ + groups.gmlayer.join('')+ + '
'+ + '
'); + }, + 'Partial': function(l) { + var groups=buildAnnounceGroups(l); + sendChat('GroupInit','/direct '+ + '
'+ + groups.character.join('')+ + '
'+ + '
'); + sendChat('GroupInit','/w gm '+ + '
'+ + groups.npc.join('')+ + groups.gmlayer.join('')+ + '
'+ + '
'); + }, + 'Visible': function(l) { + var groups=buildAnnounceGroups(l); + sendChat('GroupInit','/direct '+ + '
'+ + groups.character.join('')+ + groups.npc.join('')+ + '
'+ + '
'); + sendChat('GroupInit','/w gm '+ + '
'+ + groups.gmlayer.join('')+ + '
'+ + '
'); + } + }, statAdjustments = { 'Stat-DnD': { func: function(v) { @@ -51,7 +191,7 @@ var GroupInitiative = GroupInitiative || (function() { this.init=_.chain(l) .pluck('bonus') .map(function(d){ - return randomInteger(20)+d; + return randomInteger(state.GroupInitiative.config.dieSize)+d; },{}) .min() .value(); @@ -67,7 +207,7 @@ var GroupInitiative = GroupInitiative || (function() { this.init=_.chain(l) .pluck('bonus') .map(function(d){ - return randomInteger(20)+d; + return randomInteger(state.GroupInitiative.config.dieSize)+d; },{}) .reduce(function(memo,r){ return memo+r; @@ -84,7 +224,7 @@ var GroupInitiative = GroupInitiative || (function() { }, 'Individual-Roll': { func: function(s,k,l){ - s.init=randomInteger(20)+s.bonus; + s.init=randomInteger(state.GroupInitiative.config.dieSize)+s.bonus; return s; }, desc: 'Sets the initiative individually for each member of the group.' @@ -104,10 +244,29 @@ var GroupInitiative = GroupInitiative || (function() { if( ! _.has(state,'GroupInitiative') || state.GroupInitiative.version !== schemaVersion) { log(' > Updating Schema to v'+schemaVersion+' <'); switch(state.GroupInitiative && state.GroupInitiative.version) { + case 0.7: + state.GroupInitiative.version = schemaVersion; + state.GroupInitiative.config.announcer = 'Partial'; + break; + + case 0.6: + state.GroupInitiative.version = schemaVersion; + 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; + case 0.5: state.GroupInitiative.version = schemaVersion; state.GroupInitiative.replaceRoll = false; break; + default: state.GroupInitiative = { version: schemaVersion, @@ -118,9 +277,16 @@ var GroupInitiative = GroupInitiative || (function() { } ] ], - rollType: 'Individual-Roll', - replaceRoll: false + config: { + rollType: 'Individual-Roll', + replaceRoll: false, + dieSize: 20, + autoOpenInit: true, + sortOption: 'Descending', + announcer: 'Partial' + } }; + break; } } }, @@ -172,17 +338,75 @@ var GroupInitiative = GroupInitiative || (function() { },""); }, + getConfigOption_SortOptions = function() { + var text = state.GroupInitiative.config.sortOption; + return '
'+ + 'Sort Options is currently '+ + text+ + '.'+ + '
'+ + _.map(_.keys(sorters),function(so){ + return ''+ + so+ + ''; + }).join(' ')+ + '
'+ + '
'; + }, + getConfigOption_DieSize = function() { + return '
' + +'Initiative Die size is currently ' + +state.GroupInitiative.config.dieSize + +' ' + +'' + +'Set Die Size' + +'' + +'
'; + }, + + getConfigOption_AutoOpenInit = function() { + var text = (state.GroupInitiative.config.autoOpenInit ? 'On' : 'Off' ); + return '
' + +'Auto Open Init is currently ' + +text + +' ' + +'' + +'Toggle' + +'' + +'
'; + + }, + getConfigOption_AnnounceOptions = function() { + var text = state.GroupInitiative.config.announcer; + return '
'+ + 'Announcer is currently '+ + text+ + '.'+ + '
'+ + _.map(_.keys(announcers),function(an){ + return ''+ + an+ + ''; + }).join(' ')+ + '
'+ + '
'; + }, + + getAllConfigOptions = function() { + return getConfigOption_SortOptions() + getConfigOption_DieSize() + getConfigOption_AutoOpenInit() + getConfigOption_AnnounceOptions(); + }, + showHelp = function() { var rollerRows=_.reduce(rollers,function(memo,r,n){ - var selected=((state.GroupInitiative.rollType === n) ? + var selected=((state.GroupInitiative.config.rollType === n) ? '
Selected
' : '' ), - selectedStyleExtra=((state.GroupInitiative.rollType === n) ? ' style="border: 1px solid #aeaeae;background-color:#8bd87a;"' : ''); + selectedStyleExtra=((state.GroupInitiative.config.rollType === n) ? ' style="border: 1px solid #aeaeae;background-color:#8bd87a;"' : ''); return memo+selected+"
  • "+n+" - "+r.desc+"
  • "; },""), statAdjustmentRows = buildStatAdjustmentRows(), - bonusStatGroupRows = buildBonusStatGroupRows(); + bonusStatGroupRows = buildBonusStatGroupRows(); sendChat('', '/w gm ' @@ -280,7 +504,7 @@ var GroupInitiative = GroupInitiative || (function() { +'
    ' +'!group-init --toggle-replace' +'
    ' - +'
    '+( state.GroupInitiative.replaceRoll ? 'ON' : 'OFF' )+'
    ' + +'
    '+( state.GroupInitiative.config.replaceRoll ? 'ON' : 'OFF' )+'
    ' +'

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

    ' +'
    ' +'
    ' @@ -306,6 +530,8 @@ var GroupInitiative = GroupInitiative || (function() { +'' +'' + +getAllConfigOptions() + +'' ); }, @@ -349,12 +575,13 @@ var GroupInitiative = GroupInitiative || (function() { HandleInput = function(msg_orig) { var msg = _.clone(msg_orig), args, - cmds, - workgroup, - workvar, - turnorder, - rolls, - error=false, + cmds, + workgroup, + workvar, + turnorder, + rolls, + pageid, + error=false, initFunc, cont=false, manualBonus=0; @@ -504,7 +731,7 @@ var GroupInitiative = GroupInitiative || (function() { case 'set-roller': if(_.has(rollers,cmds[1])) { - state.GroupInitiative.rollType=cmds[1]; + state.GroupInitiative.config.rollType=cmds[1]; sendChat('GroupInitiative', '/w gm ' +'
    ' +'Roller is now set to: '+cmds[1]+'
    ' @@ -526,16 +753,16 @@ var GroupInitiative = GroupInitiative || (function() { break; case 'toggle-replace': - state.GroupInitiative.replaceRoll = !state.GroupInitiative.replaceRoll; + state.GroupInitiative.config.replaceRoll = !state.GroupInitiative.config.replaceRoll; sendChat('GroupInitiative', '/w gm ' +'
    ' - +'Replace Initiative on Roll is now: '+ (state.GroupInitiative.replaceRoll ? 'ON' : 'OFF') +'' + +'Replace Initiative on Roll is now: '+ (state.GroupInitiative.config.replaceRoll ? 'ON' : 'OFF') +'' +'
    ' ); break; case 'bonus': - if(cmds[1].match(/^[\-\+]?\d+$/)){ + if(cmds[1].match(/^[\-\+]?\d+(\.\d+)?$/)){ manualBonus=parseFloat(cmds[1]); cont=true; } else { @@ -564,52 +791,138 @@ var GroupInitiative = GroupInitiative || (function() { bonusCache = {}; turnorder = Campaign().get('turnorder'); turnorder = ('' === turnorder) ? [] : JSON.parse(turnorder); - if(state.GroupInitiative.replaceRoll) { + if(state.GroupInitiative.config.replaceRoll) { turnorder=_.reject(turnorder,function(i){ return _.contains(_.pluck(msg.selected, '_id'),i.id); }); } - initFunc=rollers[state.GroupInitiative.rollType].func; + initFunc=rollers[state.GroupInitiative.config.rollType].func; Campaign().set({ turnorder: JSON.stringify( - turnorder.concat( - _.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){ - return { - token: s, - character: getObj('character',s.get('represents')) - }; - }) - .map(function(s){ - s.bonus=(s.character ? findInitiativeBonus(s.character.id) || 0 : 0)+manualBonus; - return s; - }) - .map(initFunc) - .map(function(s){ - return { - id: s.token.id, - pr: s.init, - custom: '' - }; - }) - .value() + sorters[state.GroupInitiative.config.sortOption]( + turnorder.concat( + _.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.bonus=(s.character ? findInitiativeBonus(s.character.id) || 0 : 0)+manualBonus; + return s; + }) + .map(initFunc) + .tap(announcers[state.GroupInitiative.config.announcer]) + .map(function(s){ + return { + id: s.token.id, + pr: s.init, + custom: '' + }; + }) + .value() + ) ) ) + }); + if(state.GroupInitiative.config.autoOpenInit && !Campaign().get('initativepage')) { + Campaign().set({ + initiativepage: pageid + }); } - ); } else { showHelp(); } } + break; + case '!group-init-config': + 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 'toggle-auto-open-init': + state.GroupInitiative.config.autoOpenInit = !state.GroupInitiative.config.autoOpenInit; + sendChat('','/w gm ' + +'
    ' + +getConfigOption_AutoOpenInit() + +'
    ' + ); + 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; + + default: + sendChat('','/w gm ' + +'
    Unsupported Option:
    '+a+'
    ' + ); + } + + }); + break; } @@ -632,3 +945,6 @@ on("ready",function(){ GroupInitiative.CheckInstall(); GroupInitiative.RegisterEventHandlers(); }); + + + diff --git a/GroupInitiative/package.json b/GroupInitiative/package.json index 5b8732762e..2573b8fa10 100644 --- a/GroupInitiative/package.json +++ b/GroupInitiative/package.json @@ -1,6 +1,6 @@ { "name": "GroupInitiative", - "version": "0.8.2", + "version": "0.8.7", "description": "Adds the selected tokens to the turn order after rolling their initiative + configurable data.", "authors": "The Aaron", "roll20userid": "104025",