// Github: https://github.com/shdwjk/Roll20API/blob/master/FateDots/FateDots.js // By: The Aaron, Arcane Scriptomancer // Contact: https://app.roll20.net/users/104025/the-aaron var FateDots = FateDots || (function(){ 'use strict'; var version = '0.2.2', lastUpdate = 1487692335, schemaVersion = 0.3, regex = { statuses: /^(?:red|blue|green|brown|purple|pink|yellow|skull|sleepy|half-heart|half-haze|interdiction|snail|lightning-helix|spanner|chained-heart|chemical-bolt|death-zone|drink-me|edge-crack|ninja-mask|stopwatch|fishing-net|overdrive|strong|fist|padlock|three-leaves|fluffy-wing|pummeled|tread|arrowed|aura|back-pain|black-flag|bleeding-eye|bolt-shield|broken-heart|cobweb|broken-shield|flying-flag|radioactive|trophy|broken-skull|frozen-orb|rolling-bomb|white-tower|grab|screaming|grenade|sentry-gun|all-for-one|angel-outfit|archery-target)$/ }, 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 ''; }, showHelp = function() { sendChat('', '/w gm '+ '
'+ '
'+ 'FateDots v'+version+ '
'+ '
'+ '
'+ '

Allows statues to be used like Fate stress boxes by repeating them.

'+ '

By default, Blue and Red will be treated specially. Assigning a number to them will cause them to be duplicated that many times, and numbered in decreasing order. Changing the number will change the number of pips that appear.

'+ '
'+ 'Commands'+ '
!fate-dots '+ch('<')+ch('[')+'+'+ch('|')+'-'+ch(']')+'Status Marker'+ch('>')+''+ '
'+ 'Adds or removes a status to be treated as a multibox.'+ '
'+ '

Available Status Markers:

'+ '
red
'+ '
blue
'+ '
green
'+ '
brown
'+ '
purple
'+ '
pink
'+ '
yellow
'+ '
skull
'+ '
sleepy
'+ '
half-heart
'+ '
half-haze
'+ '
interdiction
'+ '
snail
'+ '
lightning-helix
'+ '
spanner
'+ '
chained-heart
'+ '
chemical-bolt
'+ '
death-zone
'+ '
drink-me
'+ '
edge-crack
'+ '
ninja-mask
'+ '
stopwatch
'+ '
fishing-net
'+ '
overdrive
'+ '
strong
'+ '
fist
'+ '
padlock
'+ '
three-leaves
'+ '
fluffy-wing
'+ '
pummeled
'+ '
tread
'+ '
arrowed
'+ '
aura
'+ '
back-pain
'+ '
black-flag
'+ '
bleeding-eye
'+ '
bolt-shield
'+ '
broken-heart
'+ '
cobweb
'+ '
broken-shield
'+ '
flying-flag
'+ '
radioactive
'+ '
trophy
'+ '
broken-skull
'+ '
frozen-orb
'+ '
rolling-bomb
'+ '
white-tower
'+ '
grab
'+ '
screaming
'+ '
grenade
'+ '
sentry-gun
'+ '
all-for-one
'+ '
angel-outfit
'+ '
archery-target
'+ '
'+ch(' ')+'
'+ '

Adding purple and skull, removing blue.

'+ '
'+ '
'+
					'!fate-dots +purple +skull -blue'+
				'
'+ '
'+ '
'+ '
' ); }, handleInput = function(msg) { var args; if ( "api" !== msg.type || !playerIsGM(msg.playerid) ) { return; } args = msg.content.split(/\s+/); switch(args.shift()) { case '!fate-dots': if( !args.length ) { showHelp(); return; } _.each(args,function(s){ var op = s[0], st = s.substring(1); if(st.match(regex.statuses)) { switch(op) { case '+': state.FateDots.statuses=_.union( state.FateDots.statuses,[st] ); break; case '-': state.FateDots.statuses=_.without( state.FateDots.statuses, st ); break; } } }); break; } }, statusmarkersToObject = function(stats) { return _.reduce(stats.split(/,/),function(memo,st){ var parts=st.split(/@/), num=parseInt(parts[1]||'0',10); if(parts[0].length) { memo[parts[0]]=Math.max(num,memo[parts[0]]||0); } return memo; },{}); }, statusChangeHandler = function(obj) { var nstat = statusmarkersToObject(obj.get('statusmarkers')), rstat = _.reduce(nstat,function(m,c,s){ if(_.contains(state.FateDots.statuses,s)) { m.push(_.reduce(_.range(1,c+1),function(m2,n){ m2.push(s+'@'+n); return m2; },[]).join(',')); } else { m.push('dead' === s ? s : s+'@'+c); } return m; },[]).join(','); obj.set({ statusmarkers: rstat }); }, checkInstall = function() { log('-=> FateDots v'+version+' <=- ['+(new Date(lastUpdate*1000))+']'); if( ! _.has(state,'FateDots') || state.FateDots.version !== schemaVersion) { log(' > Updating Schema to v'+schemaVersion+' <'); state.FateDots = { version: schemaVersion, statuses: ['blue','red'] }; } }, registerEventHandlers = function() { on('chat:message', handleInput); on('change:graphic:statusmarkers',statusChangeHandler); }; return { CheckInstall: checkInstall, RegisterEventHandlers: registerEventHandlers }; }()); on("ready",function(){ 'use strict'; FateDots.CheckInstall(); FateDots.RegisterEventHandlers(); });