// Github: https://github.com/shdwjk/Roll20API/blob/master/TokenLock/TokenLock.js
// By: The Aaron, Arcane Scriptomancer
// Contact: https://app.roll20.net/users/104025/the-aaron
var TokenLock = TokenLock || (function() {
'use strict';
var version = '0.2.3',
lastUpdate = 1428859122,
schemaVersion = 0.2,
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 '';
},
getCommandOption_ToggleLock = function() {
var text = (state.TokenLock.locked ? 'Locked' : 'Unlocked' );
return '
';
},
getConfigOption_AllowMoveOnTurn = function() {
var text = (state.TokenLock.config.allowMoveOnTurn ? 'On' : 'Off' );
return '';
},
showHelp = function(who) {
var stateColor = (state.TokenLock.locked) ? ('#990000') : ('#009900'),
stateName = (state.TokenLock.locked) ? ('Locked') : ('Unlocked');
sendChat('',
'/w '+who+' '
+''
+'
'
+'
'+stateName+'
'
+'TokenLock v'+version
+'
'
+'
'
+'
'
+'
TokenLock allows the GM to selectively prevent players from moving their tokens. '
+'Since change:graphic events to not specify who changed the '
+'graphic, determination of player tokens is based on whether that token '
+'has an entry in the controlled by field of either the token or '
+'the character it represents. If controlled by is empty, the '
+'GM can freely move the token at any point. If there is any entry in '
+'controlled by, the token can only be moved when TokenLock is '
+'unlocked.
'
+ '
Moving of player controlled cards is still permissible.
'
+'
'
+'
Commands'
+'
!tl'
+'
'
+'Executing the command with no arguments prints this help. The following arguments may be supplied in order to change the configuration. All changes are persisted between script restarts.'
+'
'
+'- '
+'lock -- Locks the player tokens to prevent moving them.'
+'
'
+'- '
+'unlock -- Unlocks the player tokens allowing them to be moved.'
+'
'
+'
'
+'
'
+'
'
+getCommandOption_ToggleLock()
+'
'
+'
!tl-config ['+ch('<')+'Options'+ch('>')+'|--help]'
+'
'
+'
Swaps the selected Tokens for their counterparts on the other layer.
'
+'
'
+'- '
+'--help '+ch('-')+' Shows the Help screen'
+'
'
+'- '
+'--toggle-allowmoveonturn '+ch('-')+' Sets whether tokens can be moved if they are at the top of the turn order.'
+'
'
+'
'
+'
'
+'
'
+getConfigOption_AllowMoveOnTurn()
+'
'
);
},
handleInput = function(msg) {
var args,who;
if (msg.type !== "api" || !playerIsGM(msg.playerid) ) {
return;
}
who=getObj('player',msg.playerid).get('_displayname').split(' ')[0];
args = msg.content.split(/\s+/);
switch(args.shift()) {
case '!tl':
if(_.contains(args,'--help')) {
showHelp(who);
return;
}
switch(args.shift()) {
case 'lock':
state.TokenLock.locked=true;
sendChat('TokenLock','/w gm '
+getCommandOption_ToggleLock()
);
break;
case 'unlock':
state.TokenLock.locked=false;
sendChat('TokenLock','/w gm '
+getCommandOption_ToggleLock()
);
break;
case '--toggle-lock':
state.TokenLock.locked= !state.TokenLock.locked;
sendChat('TokenLock','/w gm '
+getCommandOption_ToggleLock()
);
break;
default:
showHelp(who);
break;
}
break;
case '!tl-config':
if(_.contains(args,'--help')) {
showHelp(who);
return;
}
if(!args.length) {
sendChat('','/w '+who+' '
+''
+'
'
+'TokenLock v'+version
+'
'
+getConfigOption_AllowMoveOnTurn()
+'
'
);
return;
}
_.each(args,function(a){
var opt=a.split(/\|/);
switch(opt.shift()) {
case '--toggle-allowmoveonturn':
state.TokenLock.config.allowMoveOnTurn = !state.TokenLock.config.allowMoveOnTurn;
sendChat('','/w '+who+' '
+''
+getConfigOption_AllowMoveOnTurn()
+'
'
);
break;
default:
sendChat('','/w '+who+' '
+'Unsupported Option:
'+a+''
);
}
});
break;
}
},
handleMove = function(obj,prev) {
if(state.TokenLock.locked
&& 'token' === obj.get('subtype')
&& ( !state.TokenLock.config.allowMoveOnTurn || (( (JSON.parse(Campaign().get('turnorder'))||[{id:false}])[0].id) !== obj.id) )
&& ( obj.get('left') !== prev.left || obj.get('top') !== prev.top || obj.get('rotation') !== prev.rotation )
) {
if('' !== obj.get('controlledby')) {
obj.set({left: prev.left, top: prev.top, rotation: prev.rotation});
} else if('' !== obj.get('represents') ) {
var character = getObj('character',obj.get('represents'));
if( character && character.get('controlledby') ) {
obj.set({left: prev.left, top: prev.top, rotation: prev.rotation});
}
}
}
},
checkInstall = function() {
log('-=> TokenLock v'+version+' <=- ['+(new Date(lastUpdate*1000))+']');
if( ! _.has(state,'TokenLock') || state.TokenLock.version !== schemaVersion) {
log(' > Updating Schema to v'+schemaVersion+' <');
switch(state.TokenLock && state.TokenLock.version) {
case 0.1:
state.TokenLock.config={
allowMoveOnTurn: false
};
state.TokenLock.version=schemaVersion;
break;
default:
state.TokenLock = {
version: schemaVersion,
config: {
allowMoveOnTurn: false
},
locked: false
};
}
}
},
registerEventHandlers = function() {
on('chat:message', handleInput);
on('change:graphic', handleMove);
};
return {
RegisterEventHandlers: registerEventHandlers,
CheckInstall: checkInstall
};
}());
on("ready",function(){
'use strict';
TokenLock.CheckInstall();
TokenLock.RegisterEventHandlers();
});