// Github: https://github.com/shdwjk/Roll20API/blob/master/Facing/Facing.js // By: The Aaron, Arcane Scriptomancer // Contact: https://app.roll20.net/users/104025/the-aaron var Facing = Facing || (function() { 'use strict'; var version = '0.1.3', lastUpdate = 1490707181, schemaVersion = 0.1, defaults = { image: 'https://s3.amazonaws.com/files.d20.io/images/9183999/XcViJVf7-cGOXcZq1KWp-A/thumb.png?1430541914', attributeName: 'facing', scale: 2.5 }, checkInstall = function() { log('-=> Facing v'+version+' <=- ['+(new Date(lastUpdate*1000))+']'); if( ! _.has(state,'Facing') || state.Facing.version !== schemaVersion) { log(' > Updating Schema to v'+schemaVersion+' <'); switch(state.Facing && state.Facing.version) { case 0: default: state.Facing = { version: schemaVersion, config: { image: defaults.image, attributeName: defaults.attributeName, relative: true, scale: defaults.scale }, ringed: {} }; 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 ''; }, getCleanImgsrc = function (imgsrc) { var parts = imgsrc.match(/(.*\/images\/.*)(thumb|max)(.*)$/); if(parts) { return parts[1]+'thumb'+parts[3]; } return; }, getRingedPair = function(id) { var ringed; _.find(state.Facing.ringed,function(slaveid,masterid){ if(id === masterid || id === slaveid) { ringed = { master: getObj('graphic',masterid), slave: getObj('graphic',slaveid) }; ringed.attribute = findObjs({ type: 'attribute', name: state.Facing.config.attributeName, characterid: ringed.master && ringed.master.get('represents') })[0] || {set:function(){}}; return true; } return false; }); return ringed; }, getRinged = function(id) { var ringed; _.find(state.Facing.ringed,function(slaveid,masterid){ if(id === masterid){ ringed = getObj('graphic',slaveid); return true; } if(id === slaveid) { ringed = getObj('graphic',masterid); return true; } return false; }); return ringed; }, createRinged = function(id) { // get root obj var master = getObj('graphic',id), slave = getRinged(id), layer, dim; if(!slave && master) { layer=( 'gmlayer' === master.get('layer') ? 'gmlayer' : 'map'); dim=(Math.max(master.get('height'),master.get('width'))*state.Facing.config.scale); slave = createObj('graphic',{ imgsrc: state.Facing.config.image, layer: layer, pageid: master.get('pageid'), top: master.get('top'), left: master.get('left'), height: dim, width: dim, rotation: master.get('rotation') }); master.set({ rotation: 0 }); ( findObjs({ type: 'attribute', name: state.Facing.config.attributeName, characterid: master.get('represents') })[0] || (master.get('represents') && createObj('attribute',{ name: state.Facing.config.attributeName, characterid: master.get('represents') })) || { set: function(){} }).set({ current: slave.get('rotation') }); if('gmlayer' === layer) { toBack(slave); } else { toFront(slave); } state.Facing.ringed[master.id]=slave.id; } }, removeRinged = function(id) { var pair=getRingedPair(id); if(pair) { if(id === pair.master.id ) { pair.slave.remove(); } delete state.Facing.ringed[pair.master.id]; } }, zeroToken = function(id) { var pair=getRingedPair(id); if(pair) { pair.slave.set({ rotation: 0 }); } }, facingToken = function(id) { var pair=getRingedPair(id); if(pair) { removeRinged(id); } else { createRinged(id); } }, handleRemoveToken = function(obj) { // special handling for deleting slaves? removeRinged(obj.id); }, handleTokenChange = function(obj,prev) { var pair = getRingedPair(obj.id), layer, dim, rot; if(pair) { if(pair.master.id === obj.id) { layer=( 'gmlayer' === pair.master.get('layer') ? 'gmlayer' : 'map'); dim=(Math.max(pair.master.get('height'),pair.master.get('width'))*state.Facing.config.scale); rot=pair.master.get('rotation'); if(rot !== prev.rotation ) { if(state.Facing.config.relative) { rot = (pair.slave.get('rotation') + rot + 360) % 360; } } else { rot = pair.slave.get('rotation'); } pair.attribute.set({ current: rot }); pair.slave.set({ layer: layer, top: pair.master.get('top'), left: pair.master.get('left'), height: dim, width: dim, rotation: rot }); pair.master.set({ rotation: 0 }); if('gmlayer' === layer) { toBack(pair.slave); } else { toFront(pair.slave); } } else { pair.slave.set({ width: prev.width, height: prev.height, top: prev.top, left: prev.left, layer: prev.layer, flipv: prev.flipv, fliph: prev.fliph }); pair.attribute.set({ current: pair.slave.get('rotation') }); } } }, getConfigOption_RingImage = function() { var text = state.Facing.config.image; return '
'; }, getConfigOption_AttributeName = function() { var text = state.Facing.config.attributeName; return 'Facing adds a ring below the selected token with a pointer for the direction the token is facing. Rotating the token will rotate the ring and then the token will reset to no rotation. If the token is associated with a character, Facing will maintain an attribute on the character with the current facing stored in it.
' +'Adds or removes the Facing ring below a token.
' +'Aligns the indicator to north.
' +'