I needed to have a script that would allow automatic resizing of a rollable table token, for when a Druid used his Wild Shape, but could find nothing that would do it. So, using The Aaron's format as a template for this, I wrote this up. It's probably not very elegant in the coding itself, but this is my first script written from scratch. The command to set parameters, including turning on and off of automatic resizing, is !tr. This script allows a GM to let his players resize tokens, instead of forcing the GM to spend the time doing it. A GM can turn the function for manual resizing off, which then allows only a GM to use that function. The script uses isGM to determine whether someone is a GM for purposes of this. By default, this option is set to Locked. To resize manually, a person would use the following format: !tr <token_id> # When using the targeting function, one can use @{target|token_id} and select the target to resize, or @{selected|token_id} when targeting is turned off. The numerical value is the number of grid squares across/high the new size should be. For example, if resizing to a large size (10ftx10ft), the area covered would be 2x2, so the scale factor would be 2. The full context would then be for a large creature that can be targeted: !tr @{target|token_id} 2 Additionally, this script allows tokens that use rollable tables to automatically resize based upon the value of the weight field. The script identifies the value, and uses it as the scale factor. This is useful for a Druid who has the ability to change shapes into larger creatures than himself/herself, as well as when using rollable tables for a mounted/dismounted setup (horses are large creatures, PCs are generally medium). In both the automatic, and the manual resizing, the token is resized to the appropriate size, then placed where the original size's top-left corner was. The grid size can be changed to fit the grid size for the campaign. We use a 140 pixel grid size because we have some older people with bad eyes. I make my own 3D figure tokens, so to be able to see this clearly for those with bad eyes, we increased the size. Shameless token design plug... I'll be fine tuning some things here and there for this. I just figured I can't be the only person who really needed, or has, a use for this script, so I wanted to share it with the community at large. Below is a screen shot of the Help chat output, able to be called by either !tr --help or else having less than 2 arguments after !tr. If anyone has any problems, don't hesitate to let me know. If there is a way to also streamline this, let me know as well, so I can learn some more in fixing it. //
var TokenResize = TokenResize || (function() {
'use strict';
var version = '0.2.0',
lastUpdate = 1440332940,
schemaVersion = 0.7,
gridSize = 70,
CheckInstall = function() {
log('-=> TokenResize v'+version+' <=- ['+(new Date(lastUpdate*1000))+']');
if( ! _.has(state,'TokenResize') || state.TokenResize.version !== schemaVersion) {
log(' > Updating Schema to v'+schemaVersion+' <');
switch(state.TokenResize && state.TokenResize.version) {
case 0.1:
state.TokenResize.config.AutoResize = false;
state.TokenResize.version = schemaVersion;
break;
default:
state.TokenResize = {
version: schemaVersion,
config: {
PlayerResize: false,
isSelected: true,
AutoResize: false
},
};
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 '';
},
getConfigOption_AutoResize = function() {
var text = (state.TokenResize.config.AutoResize ? 'On' : 'Off' );
return '<div>'
+'<b>Auto Resize:</b> '
+'<a href="!tr --auto-resize">'
+text
+'</a>'
+'</div>';
},
getConfigOption_PlayerResize = function() {
var text = (state.TokenResize.config.PlayerResize ? 'On' : 'Off' );
return '<div>'
+'<b>Player Resize:</b> '
+'<a href="!tr --player-resize">'
+text
+'</a>'
+'</div>';
},
getConfigOption_isSelected = function() {
var text = (state.TokenResize.config.isSelected ? 'Off' : 'On' );
return '<div>'
+'<b>Selection Required:</b> '
+'<a href="!tr --is-selected">'
+text
+'</a>'
+'</div>';
},
getAllConfigOptions = function() {
return getConfigOption_AutoResize() + getConfigOption_PlayerResize() + getConfigOption_isSelected();
},
showHelp = function(who) {
sendChat('','/w '+who+' '
+'<div style="border: 1px solid black; background-color: white; padding: 3px 3px;">'
+'<div style="font-weight: bold; border-bottom: 1px solid black;font-size: 130%;">'
+'TokenResize v'+version
+'<div style="clear: both"></div>'
+'</div>'
+'<div style="padding-left:10px;margin-bottom:10px;margin-top:10px;">'
+'<p>TokenResize allows players to resize their tokens when unlocked.'
+'</div>'
+'<b>Commands</b>'
+'<div style="padding-left:10px;">'
+'<div style="padding-left: 10px;padding-right:20px">'
+'<b><span style="font-family: serif;"> !tr</span></b> '+ch('-')+' Command to activate script. Used in conjunction with the following options:'
+'<ul>'
+'<li><b><span style="font-family: serif;">--help</span></b> '+ch('-')+' Shows the Help screen</li>'
+'<li><b><span style="font-family: serif;">--auto-resize</span></b> '+ch('-')+' Sets whether TokenResize will auto resize based upon a token'+ch("'")+'s weight size on its rollable table.</li>'
+'<li><b><span style="font-family: serif;">--player-resize</span></b> '+ch('-')+' Sets whether TokenResize allows for players to resize.</li>'
+'<li><b><span style="font-family: serif;">--is-selected</span></b> '+ch('-')+' Sets whether TokenResize requires selection.</li>'
+'</ul>'
+'</div>'
+'</div>'
+getAllConfigOptions()
+'</div>'
);
},
autoChange = function(obj, prev) {
if ('card' !== obj.get("subtype") && obj.get("sides") && '' !== obj.get("represents")) {
var aid = obj.get("imgsrc"),
tid = findObjs({
type: 'tableitem',
avatar: aid
}, { caseInsensitive: true })[0],
weight,
pheight;
if(tid) {
weight = tid.get("weight");
pheight = obj.get("height");
if(tid.get("weight") <= 0 || !state.TokenResize.config.AutoResize) {
//showHelp();
return; // Even though we use weight for the tile size, let's make sure there is something there to avoid errors.
};
if ((gridSize * weight) !== obj.get('width')) {
obj.set({
width: (gridSize * weight),
height: (gridSize * weight)
});
if ((gridSize * weight) > gridSize) {
obj.set({
top: (prev.top + ((gridSize / 2) * (weight - (pheight / gridSize)))),
left: (prev.left + ((gridSize / 2) * (weight - (pheight / gridSize))))
})
} else {
obj.set({
top: (prev.top - ((gridSize / 2) * ((pheight / gridSize) - weight))),
left: (prev.left - ((gridSize / 2) * ((pheight / gridSize) - weight)))
})
}
} else {
return;
}
}
}
},
handleInput = function(msg) {
var args, who, obj, prev;
if (msg.type !== "api") {
return;
}
var selected = msg.selected;
who=getObj('player',msg.playerid).get('_displayname').split(' ')[0];
args = msg.content.split(" ");
switch(args[0]) {
case '!tr':
switch(args[1]) {
case '--auto-resize':
state.TokenResize.config.AutoResize=!state.TokenResize.config.AutoResize;
sendChat('','/w '+who+' '
+'<div style="border: 1px solid black; background-color: white; padding: 3px 3px;">'
+getConfigOption_AutoResize()
+'</div>'
);
break;
case '--player-resize':
state.TokenResize.config.PlayerResize=!state.TokenResize.config.PlayerResize;
sendChat('','/w '+who+' '
+'<div style="border: 1px solid black; background-color: white; padding: 3px 3px;">'
+getConfigOption_PlayerResize()
+'</div>'
);
break;
case '--is-selected':
state.TokenResize.config.isSelected=!state.TokenResize.config.isSelected;
sendChat('','/w '+who+' '
+'<div style="border: 1px solid black; background-color: white; padding: 3px 3px;">'
+getConfigOption_isSelected()
+'</div>'
);
break;
case '--help':
showHelp(who);
break;
}
if( args[2] && !state.TokenResize.config.PlayerResize && !playerIsGM(msg.playerid) ) {
sendChat("", "/desc Check player resize.");
return;
} else if ( args[2] && !state.TokenResize.config.isSelected && !selected ) { // Only allows a token to be resized if selected. This prevents players from resizing tokens that don't belong to them.
sendChat("", "/desc Select token and try again.");
return; // quit if nothing selected
} else {
if(args[2]){
var obj = getObj("graphic", args[1]),
ptop = obj.get('top'),
pleft = obj.get('left'),
pheight = obj.get('height'),
weight = args[2];
if( (gridSize * weight) !== obj.get('width') ) {
obj.set({
width: (gridSize * weight),
height: (gridSize * weight)
})
if( (gridSize * weight) > gridSize ) {
obj.set({
top: (ptop + ((gridSize / 2) * (weight - (pheight / gridSize)))),
left: (pleft + ((gridSize / 2) * (weight - (pheight / gridSize))))
})
} else {
obj.set({
top: (ptop - ((gridSize / 2) * ((pheight / gridSize) - weight))),
left: (pleft - ((gridSize / 2) * ((pheight / gridSize) - weight)))
})
}
}
}
}
break;
}
},
RegisterEventHandlers = function() {
on('change:graphic', autoChange);
on('chat:message', handleInput);
};
return {
RegisterEventHandlers: RegisterEventHandlers,
CheckInstall: CheckInstall
};
}());
on("ready",function(){
'use strict';
TokenResize.CheckInstall();
TokenResize.RegisterEventHandlers();
});