';
chatMessage += getImgSrcChooserButtons(playerName);
chatMessage += '';
chatMessage += makeButton("Toggle Inherit Light Settings", '!LightCrumb-config INHERIT_CHARACTER_LIGHTING 1');
chatMessage += '';
chatMessage += '';
chatMessage += makeButton("Light Radius", '!LightCrumb-config LIGHT_RADIUS ?'+ch('{')+ 'LIGHT_RADIUS?' +ch('|')+ config.LIGHT_RADIUS +ch('}'));
chatMessage += '';
chatMessage += '';
chatMessage += makeButton("Dim Start", '!LightCrumb-config DIM_RADIUS ?'+ch('{')+ 'DIM_RADIUS?' +ch('|')+ config.DIM_RADIUS +ch('}'));
chatMessage += '';
chatMessage += '';
chatMessage += makeButton("Crumb Seperation", '!LightCrumb-config DROP_DISTANCE ?'+ch('{')+ 'DROP_DISTANCE In feet' +ch('|')+ config.DROP_DISTANCE +ch('}'));
chatMessage += '';
chatMessage += '';
chatMessage += makeButton("Toggle Drop Location", '!LightCrumb-config DROP_AT_PREVIOUS_LOCATION 1');
chatMessage += '';
chatMessage += '';
chatMessage += makeButton("Offset Distance", '!LightCrumb-config OFFSET_DISTANCE ?'+ch('{')+ 'OFFSET_DISTANCE In pixels' +ch('|')+ config.OFFSET +ch('}'));
chatMessage += '';
/*
chatMessage += '';
chatMessage += makeButton("Show Help on Load", '!LightCrumb-config SHOW_HELP_ON_READY ?'+ch('{')+ 'SHOW_HELP_ON_READY: 0 or 1' +ch('|')+ config.SHOW_HELP_ON_READY +ch('}'));
chatMessage += '';
*/
chatMessage += '';
chatMessage += makeButton("Toggle Shared Vision", '!LightCrumb-config SHARED_VISION 1');
chatMessage += '';
chatMessage += '';
chatMessage += makeButton("Toggle Aura", '!LightCrumb-config SHOW_AURA 1');
chatMessage += '';
chatMessage += '';
chatMessage += makeButton("Toggle Names", '!LightCrumb-config SHOW_NAMES 1');
chatMessage += '';
chatMessage += '';
chatMessage += makeButton("Reload Default Config", '!LightCrumb-config LOAD_DEFAULT 1');
chatMessage += '';
chatMessage += '
';
// log("===> LightConfigButtons are whispering to playerName: " + playerName);
whisper(playerName, chatMessage);
};
/*
ooooo ooooo o888
888 888 ooooooooo8 888 ooooooooo
888ooo888 888oooooo8 888 888 888
888 888 888 888 888 888
o888o o888o 88oooo888 o888o 888ooo88
o888
*/
var showDetailedHelp = function showDetailedHelpTextInChat(playerName) {
if (debugDEFCON < 2) { log("entering showDetailedHelp("+playerName+")"); }
if (!playerName) { playerName = "gm";}
var exampleStyle = '"background-color: #eee; font-size: smaller; margin-left: 40px;"';
var warningStyle = '"background-color: AntiqueWhite; font-size: smaller;"';
var exampleTokenSelect = ch('@') + ch('{') + 'selected' + ch('|') + 'token_id' + ch('}');
var helpText = '';
helpText += '
';
helpText += 'LightCrumb is a script to leave lit torches in a trail behind characters.';
helpText += "This lets them see where they've been on maps with dynamic lighting enabled.";
helpText += "Useful for hex-crawls and dungeon-crawls.";
helpText += "
';
helpText += "To start, enter !LightCrumb in the chat window.";
helpText += "
";
helpText += "In addition to the gui buttons, you can make macros to activate the features. Here are some commands to play with.";
helpText += '
!LightCrumb-drop ' + exampleTokenSelect + '
';
helpText += '
!LightCrumb-register ' + exampleTokenSelect + '
';
helpText += '
!LightCrumb-deregister ' + exampleTokenSelect + '
';
helpText += '
!LightCrumb-clear parentTokenID' + '
';
helpText += '
!LightCrumb-gui
';
//whisper(playerName, helpText );
var helpHandouts;
helpHandouts = findObjs({
_type: "handout",
name: "LightCrumb Help"
});
var helpHandout = helpHandouts[0];
//log("helpHandout = " + helpHandout);
if (!helpHandout) { // create it
helpHandout = createObj('handout', {
name: 'LightCrumb Help',
inplayerjournals: 'all'
});
helpHandout.set("notes", helpText);
} else { // it exists, set it's contents to match the latest version of the script
helpHandout.set("notes", helpText);
}
var handoutID = helpHandout.get("_id");
var chatMessage = "";
var buttonStyle = "'background-color: OrangeRed;'";
chatMessage += "
";
// getClickyButtons(playerName);
if (debugDEFCON < 2) { log("exiting showDetailedHelp. Whispered message to chat. No return value."); }
return(chatMessage);
};
/*
ooooo o8
888 oo oooooo ooooooooo oooo oooo o888oo
888 888 888 888 888 888 888 888
888 888 888 888 888 888 888 888
o888o o888o o888o 888ooo88 888o88 8o 888o
o888
*/
var handleInput = function inputHandler(msg) {
// FYI: Expected msg looks like this:
// content, playerid, selected, type, who
// where content is: !LightCrumb token_id
// {"content":"!LightCrumb -K_D89bE8mmN0VEBmdjt","playerid":"-K_D5Ng6YOcQ3VnAEsNh","selected":[{"_id":"-K_D89bE8mmN0VEBmdjt","_type":"graphic"}],"type":"api","who":"plexsoup (GM)"}
if (msg.type == "api" && msg.content.indexOf("!LightCrumb") !== -1 ) {
var argsFromUser,
who,
errors=[],
// playerPage, // useful for status message where no token is selected
tokenPage, // used for dropping new lightCrumbs
LightCrumbMakerSupply,
token,
tokenCoords,
tokenID,
playerID,
playerName,
pageID,
statusMessage,
parentTokenID,
lastPage;
playerName = msg.who;
playerID = msg.playerid;
pageID = getCurrentPage(playerID);
if (debugDEFCON < 5) {
log("PlayerName = " + playerName);
// log("PlayerID = " + playerID);
log("msg.content = " + msg.content);
}
argsFromUser = msg.content.split(/ +/);
if (debugDEFCON < 2) {log("handleInput got a message: " + argsFromUser);}
switch(argsFromUser[0]) {
case '!LightCrumb-clear':
// remove all the light-crumbs
parentTokenID = argsFromUser[1];
if (parentTokenID == "all") {
reset(pageID, "all", "soft");
} else {
reset(pageID, parentTokenID, "soft");
}
break;
case '!LightCrumb-destroy':
// destroy the LightCrumbs permanently. Nothing left on GM Layer.
parentTokenID = argsFromUser[1];
if (parentTokenID == "all") {
reset(pageID, "all", "hard");
} else {
reset(pageID, parentTokenID, "hard");
}
break;
case '!LightCrumb-register':
if (debugDEFCON < 2) { log("Trying to register a new token"); }
// Add tokenIDs to the list of tokens registered to produce light-trails automatically
tokenID = argsFromUser[1];
registerMapper(tokenID, playerName);
break;
case '!LightCrumb-deregister':
if (debugDEFCON < 5 ) { log("==> !LightCrumb-deregister " + argsFromUser[1]); }
tokenID = argsFromUser[1];
deregisterMapper(tokenID, playerName);
break;
case '!LightCrumb-status':
// print out some variables to get more info and help with debugging
statusMessage += getLightCrumbStatus(pageID);
whisper(playerName, statusMessage);
break;
case '!LightCrumb-drop': // drop a single LightCrumb torch
token = getTokenObjectFromID(argsFromUser[1]);
if (token === undefined) {
whisper(playerName, "Error: undefined token");
} else {
if(debugDEFCON < 5) {
log("Token ID: " + token.get("_id"));
log("Page ID: " + token.get("_pageid"));
log("Coords: [" + token.get("left") + "," + token.get("top") + "]");
}
tokenPage = token.get("_pageid");
tokenCoords = [token.get("left"), token.get("top")];
var controllingPlayerID = playerID;
if ( config.SHARED_VISION === true ) {
controllingPlayerID += ",all";
}
var displayName = getDisplayName(token.get("name"));
var customLightCrumbSettings = {
left: tokenCoords[0],
top: tokenCoords[1],
pageid: tokenPage,
controlledby: controllingPlayerID,
name: displayName
};
if (config.INHERIT_CHARACTER_LIGHTING) {
customLightCrumbSettings[light_radius] = token.get("light_radius");
customLightCrumbSettings[light_dimradius] = token.get("light_dimradius");
}
var currentLightCrumb = dropLightCrumb(customLightCrumbSettings, token.get("_id")); //manual drop
if (debugDEFCON < 4) {log("dropped LightCrumb from !LightCrumb-drop: [" + tokenCoords + "], " + tokenPage);}
}
break;
case '!LightCrumb-gui': // show some clicky buttons in the chat window
if (debugDEFCON <3) {log("received !LightCrumb-gui: "+argsFromUser);}
var requestedCommand = argsFromUser[1];
if (requestedCommand !== undefined) {
if (requestedCommand == "chooseImage") {
getImgSrcChooserButtons(playerName);
} else if (requestedCommand == "getLightConfig" || requestedCommand == "config") {
getLightConfigButtons(playerName);
}
} else {
getClickyButtons(playerName);
}
break;
case '!LightCrumb-image': // change the appearance of the token that drops
var requestedIcon = argsFromUser[1];
if (requestedIcon !== undefined) {
if (requestedIcon == "torch") {
config.IMAGE = ICONS.torch;
} else if (requestedIcon == "transparent") {
config.IMAGE = ICONS.transparent;
} else if (requestedIcon == "scifi") {
config.IMAGE = ICONS.scifi;
}
state.LightCrumb.config = _.clone(config);
var requestedSettings = {imgsrc: config.IMAGE};
convertCrumbsToNewSettings(pageID, requestedSettings);
}
break;
case '!LightCrumb-config': // set any the configurable values.
if (debugDEFCON < 4) { log('!LightCrumb-config received: ' + argsFromUser); }
var requestedParameter = argsFromUser[1];
var requestedValue = argsFromUser[2];
var requestedLightCrumbSettings = { layer:"objects" } ;
var needBatchConversion = false;
if (requestedParameter === undefined || requestedValue === undefined) {
// abort.. something went wrong
whisper(playerName, "Error: didn't receive proper values for !LightCrumb-config.");
} else {
if (requestedParameter == "LIGHT_RADIUS" ) {
config.LIGHT_RADIUS = requestedValue;
requestedLightCrumbSettings.light_radius = requestedValue;
needBatchConversion = true;
whisperSmall(playerName, "LIGHT_RADIUS set to: " + config.LIGHT_RADIUS);
} else if (requestedParameter == "DIM_RADIUS") {
config.DIM_RADIUS = requestedValue;
whisperSmall(playerName, "DIM_RADIUS set to: " + config.DIM_RADIUS);
needBatchConversion = true;
requestedLightCrumbSettings.light_dimradius = requestedValue;
} else if (requestedParameter == "DROP_DISTANCE") {
config.DROP_DISTANCE = requestedValue;
whisperSmall(playerName, "DROP_DISTANCE set to: " + config.DROP_DISTANCE);
} else if (requestedParameter == "OFFSET_DISTANCE") {
config.OFFSET = requestedValue;
whisperSmall(playerName, "OFFSET set to: " + config.OFFSET);
} else if (requestedParameter == "SHOW_HELP_ON_READY") {
config.SHOW_HELP_ON_READY = requestedValue;
whisperSmall(playerName, "SHOW_HELP_ON_READY set to: " + config.SHOW_HELP_ON_READY);
} else if (requestedParameter == "DROP_AT_PREVIOUS_LOCATION") {
config.DROP_AT_PREVIOUS_LOCATION = !config.DROP_AT_PREVIOUS_LOCATION;
whisperSmall(playerName, "DROP_AT_PREVIOUS_LOCATION set to: " + config.DROP_AT_PREVIOUS_LOCATION);
} else if (requestedParameter == "SHARED_VISION") {
config.SHARED_VISION = !config.SHARED_VISION; // toggle
whisperSmall(playerName, "Shared Vision set to " + config.SHARED_VISION);
needBatchConversion = true;
} else if (requestedParameter == "SHOW_AURA") {
config.SHOW_AURA = !config.SHOW_AURA; // toggle true false
// whisper(playerName, "SHOW_AURA set to " + config.SHOW_AURA);
requestedLightCrumbSettings.showplayers_aura1 = config.SHOW_AURA;
if (config.SHOW_AURA === false) {
requestedLightCrumbSettings.aura1_radius = "";
} else {
requestedLightCrumbSettings.aura1_radius = config.AURA_RADIUS;
}
needBatchConversion = true;
} else if (requestedParameter == "SHOW_NAMES") {
config.SHOW_NAMES = !config.SHOW_NAMES; // toggle true false
requestedLightCrumbSettings.showname = config.SHOW_NAMES;
requestedLightCrumbSettings.showplayers_name = config.SHOW_NAMES;
needBatchConversion = true;
// whisper(playerName, "SHOW_NAMES set to " + config.SHOW_NAMES);
} else if (requestedParameter == "INHERIT_CHARACTER_LIGHTING") {
config.INHERIT_CHARACTER_LIGHTING = !config.INHERIT_CHARACTER_LIGHTING;
needBatchConversion = true;
whisperSmall(playerName, "INHERIT_CHARACTER_LIGHTING set to " + config.INHERIT_CHARACTER_LIGHTING);
} else if (requestedParameter == "LOAD_DEFAULT") {
config = _.clone(defaultConfig);
state.LightCrumb.config = _.clone(defaultConfig);
requestedLightCrumbSettings = {
imgsrc: config.IMAGE,
showname: config.SHOW_NAMES,
showplayers_name: config.SHOW_NAMES
};
whisperSmall(playerName, getLightCrumbStatus(pageID) );
if (config.SHOW_AURA === false) {
requestedLightCrumbSettings.aura1_radius = "";
} else {
requestedLightCrumbSettings.aura1_radius = config.AURA_RADIUS;
}
needBatchConversion = true;
}
}
if( debugDEFCON < 2 ) { log("trying to clone config into state.LightCrumb.config.. here's what I have in config" + config ); }
// **** TODO **** Fix this.. it converts a lot of settings which the user didn't ask for.
state.LightCrumb.config = _.clone(config);
if (needBatchConversion) {
convertCrumbsToNewSettings(pageID, requestedLightCrumbSettings);
}
// still need to go through all the old lightCrumbs and set their token values.
break;
case '!LightCrumb-help': // explain script and pop up a few buttons in the chat for player to click on.
showDetailedHelp(playerName);
break;
case '!LightCrumb': // explain script and pop up a few buttons in the chat for player to click on.
getClickyButtons(playerName);
break;
}
}
};
var getLightCrumbStatus = function (pageID) {
var statusMessage = "";
statusMessage = "
"+activeLightCrumbMappers.length + " Active Mappers
";
statusMessage += "
";
var currentMapperName;
_.each(activeLightCrumbMappers, function loopToListMappers(currentMapperID) {
statusMessage += "- ";
currentMapperName = getObj('graphic', currentMapperID).get("name");
if (currentMapperName !== "" ) {
statusMessage += currentMapperName;
} else {
statusMessage += currentMapperID;
}
statusMessage += "
";
});
statusMessage += "
";
statusMessage += "
"+getLightCrumbsFromLayer("objects", pageID).length + " Active LightCrumbs
";
statusMessage += "
Config Options
";
var configMessage = JSON.stringify(config);
var prettyConfigMessage = "";
_.each(configMessage.split(","), function loopToBuildMessage(currentOption) {
prettyConfigMessage += "
" + currentOption + "
";
});
statusMessage += prettyConfigMessage;
return statusMessage;
};
/*
.
.o8
oooo d8b .ooooo. .oooo.o .ooooo. .o888oo
`888""8P d88' `88b d88( "8 d88' `88b 888
888 888ooo888 `"Y88b. 888ooo888 888
888 888 .o o. )88b 888 .o 888 .
d888b `Y8bod8P' 8""888P' `Y8bod8P' "888"
*/
var reset = function resetter(pageID, parentTokenID, resetMode) {
if (resetMode === undefined ) {
resetMode = "soft";
}
if (debugDEFCON < 4) { log("entering reset with " + pageID); }
//state.LightCrumb.count=0;
// test pageID.
if (!getObj("page", pageID) ) { // this pageID is not valid.
log("==> Error: This pageID is not valid: " + pageID);
return -1;
} else {
if (debugDEFCON < 2 ) { log(" in reset: pageID is valid: " + pageID); }
}
if (pageID === undefined) {
log("==> Error: reset(pageID, parentTokenID, resetMode) didn't receive a pageID");
pageID = getCurrentPage("gm");
}
if (parentTokenID !== "all") {
// Check to see if you grabbed a torch or a character
var gmNotesOnToken = getObj("graphic", parentTokenID).get("gmnotes");
if (getObj("graphic", gmNotesOnToken) ) { // for some reason the gmnotes contains the _id of a token... maybe it's a torch
var foundInActiveList = activeLightCrumbMappers.indexOf(gmNotesOnToken);
parentTokenID = gmNotesOnToken;
}
whisperSmall("gm", "Removing trail belonging to " + getObj("graphic", parentTokenID).get("name"));
}
_.each(ICONS, function loopToGrabAllTheTorchIcons(imageUrl) {
_.each(findObjs({
_pageid: pageID,
_type: 'graphic',
_subtype: 'token',
imgsrc: imageUrl,
}), function loopToHideLightCrumbs(currentLightCrumbToken){
if ( parentTokenID == currentLightCrumbToken.get("gmnotes") || parentTokenID == "all") {
if (resetMode == "soft") {
currentLightCrumbToken.set({ // hide the lightcrumb token, but keep it available for later reuse - saves html lookups
layer: 'gmlayer',
width: 70,
height: 70,
top: 35,
left: 35,
imgsrc: config.IMAGE,
gmnotes: "",
aura1_color: "#ffffff",
name: "LightCrumb"
});
} else { // resetMode == "hard"
currentLightCrumbToken.remove(); // destroy it!
}
}
}
);
});
};
var getAuraColor = function auraColorGetter(parentTokenID) {
if (parentTokenID === undefined || parentTokenID === "" ) {
// log("==> Error in getAuraColor. No token provided")
return "#ffffff";
}
if (config.SHARED_VISION === true) {
return config.SHARED_AURA_COLOR;
}
// log("entering getAuraColor with " + parentTokenID);
var colors = ["#ff0000", "#ff9900", "#ffcc66", "#ff3300", "#ff6600", "#cc9900", "#ffff99"];
var mappers = activeLightCrumbMappers;
// log("activeLightCrumbMappers = " + JSON.stringify(activeLightCrumbMappers) );
var mapperNum;
var counter = 0;
var color;
mapperNum = mappers.indexOf(parentTokenID);
// log("mapperNum: " + mapperNum);
if (mapperNum !== -1) {
var colorNum = mapperNum % colors.length;
// log("colorNum = " + colorNum);
color = colors[ colorNum ]; // cycle through colors in array with modulo operator
} else {
color = "#ffffff";
}
// log("exiting getAuraColor with " + color);
// log("token: " + parentTokenID + ", called: " + getObj("graphic", parentTokenID).get("name") + " has color: " + color);
return color;
};
/*
.
.o8
.ooooo. .ooooo. ooo. .oo. oooo ooo .ooooo. oooo d8b .o888oo
d88' `"Y8 d88' `88b `888P"Y88b `88. .8' d88' `88b `888""8P 888
888 888 888 888 888 `88..8' 888ooo888 888 888
888 .o8 888 888 888 888 `888' 888 .o 888 888 .
`Y8bod8P' `Y8bod8P' o888o o888o `8' `Y8bod8P' d888b "888"
*/
var convertCrumbsToNewSettings = function crumbsResetter(pageID, requestedOptions) {
if (requestedOptions === undefined) {
requestedOptions = {light_otherplayers: config.SHARED_VISION};
}
if (debugDEFCON < 5) {log("entering convertCrumbsToNewSettings with " + JSON.stringify(requestedOptions) ); }
if (pageID === undefined ) {
log("==> Error: convertCrumbsToNewSettings didn't receive a pageID");
pageID = getCurrentPage("gm");
}
if (!requestedOptions || requestedOptions.size === 0 ) { // figure out what needs resetting, exactly.
log("==> didn't see any options for the conversion.. what's up?");
}
_.each(ICONS, function(imageUrl) { // note: this won't find anything where the user passed their own url to !LightCrumb-image
if (debugDEFCON < 4) {log("checking for: " + imageUrl);}
_.each(findObjs({
_pageid: pageID,
_type: 'graphic',
_subtype: 'token',
imgsrc: imageUrl
}), function convertCrumbToNewSettings(currentCrumb){ // do this stuff once for every torch icon
if (debugDEFCON < 2 ) { log("converting lightcrumb token: " + currentCrumb.get("_id")); }
// figure out who owns it.
var currentCrumbID = currentCrumb.get("_id");
if (debugDEFCON < 4) { log("currentCrumbID = " + currentCrumbID); }
var parentTokenID = getParentTokenID(currentCrumbID);
if (debugDEFCON < 4) { log("in convertCrumbsToNewSettings: parentTokenID = " + parentTokenID); }
// remove "all" from the list of controlling tokens
var controlledByArray = currentCrumb.get("controlledby").split(",");
controlledByArray = _.without(controlledByArray, "all");
var controlledByString = controlledByArray.join(",");
log("==> controlledByString: " + controlledByString);
if (debugDEFCON < 4) { log("in convertCrumbToNewSettings: controlledByString = " + controlledByString); }
// then add it back if it's needed.
if (config.SHARED_VISION === true) { // add "all" to controlledby
controlledByString += ",all";
requestedOptions.light_otherplayers = true;
} else {
requestedOptions.light_otherplayers = false;
if (controlledByString == "") { // looks like a character is set to all players instead of a specific character
controlledByString = "all";
}
}
requestedOptions.controlledby = controlledByString;
if (config.SHARED_VISION === false) { // modify the aura so it's obvious who can see the torch
if (controlledByString !== "all") {
requestedOptions.aura1_color = getAuraColor(currentCrumb.get("gmnotes"));
} else { // this character is set to be controlled by all players.
requestedOptions.aura1_color = config.SHARED_AURA_COLOR;
}
} else {
requestedOptions.aura1_color = config.SHARED_AURA_COLOR;
}
if (!_.has(requestedOptions, "showplayers_aura1") ) {
requestedOptions.showplayers_aura1 = config.SHOW_AURA;
}
if (!_.has(requestedOptions, "aura1_radius") ) {
if (config.SHOW_AURA === true) {
requestedOptions.aura1_radius = config.AURA_RADIUS;
} else {
requestedOptions.aura1_radius = "";
}
}
if(config.INHERIT_CHARACTER_LIGHTING === false ) {
requestedOptions.light_radius = config.LIGHT_RADIUS;
requestedOptions.light_dimradius = config.DIM_RADIUS;
} else { // get the correct light radius from the parent token for each lightcrumb
var parentToken = getObj("graphic", parentTokenID);
if (!parentToken) {
log("==> Error. no parent token matching: " + parentTokenID);
log("here's the list of mappers" + JSON.stringify(activeLightCrumbMappers));
} else {
requestedOptions.light_radius = parentToken.get("light_radius");
requestedOptions.light_dimradius = parentToken.get("light_dimradius");
}
}
// **** TODO **** fix this: if a player requests a new image, it shouldn't change all the light_radii.
if (_.size(requestedOptions) > 0 ) {
for (var propertyName in requestedOptions) {
// log("setting property: " + propertyName + ", value: " + requestedOptions[propertyName]);
currentCrumb.set(propertyName, requestedOptions[propertyName]);
}
}
});
});
if (debugDEFCON < 5) {log("leaving convertCrumbToNewImage. Nothing to return."); }
};
var getTokenObjectFromID = function tokenConverter(requestedTokenID) {
var errors = [];
var targetToken;
// **** TODO **** What happens if you get/need more than one token id?
if (debugDEFCON < 5) {
log("function getTokenObjectsFromIDList(" + requestedTokenID + ")");
}
targetToken = getObj('graphic',requestedTokenID);
if(! targetToken) {
return undefined;
} else {
return targetToken;
}
};
var getParentTokenID = function parentIDGetter(lightCrumbID) {
if (debugDEFCON < 4 ) { log("entering getParentTokenID with " + lightCrumbID); }
var lightCrumbObj = getObj("graphic", lightCrumbID );
if (!lightCrumbObj) {
log("==> Error: couldn't find object matching id: " + lightCrumbID);
return -1;
} else {
var parentTokenID = lightCrumbObj.get("gmnotes");
if (debugDEFCON < 4) { log("exiting getParentTokenID: returning " + parentTokenID); }
return parentTokenID;
}
};
var getLightCrumbsFromLayer = function lightCrumbFinder(layer, pageID) {
// expects "objects" or "gmlayer" and a valid page_id
if (!pageID) {
log("==> Error: getLightCrumbsFromLayer expected a pageID but didn't receive one");
pageID = getCurrentPage("gm");
}
if (debugDEFCON < 5) {
log("entered getLightCrumbsFromLayer(" + layer + ", " + pageID + ")");
}
var LightCrumbMakerSupply;
LightCrumbMakerSupply = findObjs({
type: 'graphic',
subtype: 'token',
imgsrc: config.IMAGE,
layer: layer,
pageid: pageID
});
if (debugDEFCON < 5) {
log("leaving getLightCrumbsFromLayer: returning LightCrumbMakerSupply = " + LightCrumbMakerSupply);
}
return(LightCrumbMakerSupply);
};
var deregisterMapper = function mapperDeregistrar(tokenID, playerName) {
if (debugDEFCON < 5) { log("entering deregisterMapper with " + tokenID + "," + playerName );}
if (playerName === undefined || tokenID == "all") { // clear all mappers
activeLightCrumbMappers = [];
state.LightCrumb.activeMappers = [];
} else { // We got a tokenID. Remove it from the list of active mappers
// rearrange the colors list so other mappers can keep their existing color
var mapperNum = activeLightCrumbMappers.indexOf(tokenID);
var mapperColor = COLORS[mapperNum];
// log("COLORS before: " + COLORS);
COLORS = _.without(COLORS, mapperColor);
COLORS.push(mapperColor);
// log("COLORS after: " + COLORS);
state.LightCrumb.colors = _.clone(COLORS);
// remove the mapper from the list
// log("activeLightCrumbMappers before: " + activeLightCrumbMappers);
activeLightCrumbMappers = _.without(activeLightCrumbMappers, tokenID);
state.LightCrumb.activeMappers = _.clone(activeLightCrumbMappers);
// log("activeLightCrumbMappers after: " + activeLightCrumbMappers);
}
};
var registerMapper = function mapperRegistrar(tokenID, playerName) {
if (debugDEFCON < 2) { log("entered registerMapper with: " + tokenID + ", " + playerName); }
if (playerName === undefined) { playerName = "gm"; }
var statusMessage = "";
var targetToken = getTokenObjectFromID(tokenID);
var tokenOwner = targetToken.get("controlledby");
var tokenCoords = [targetToken.get("left"), targetToken.get("top")];
var tokenName = targetToken.get("name");
var currentPage = targetToken.get("_pageid");
if (!tokenName) { tokenName = ""; }
if ( activeLightCrumbMappers.indexOf(tokenID) == -1 ) { // you're not yet registered
activeLightCrumbMappers.push(tokenID);
state.LightCrumb.activeMappers.push(tokenID); // save this in the Roll20 state object so it's persistent between sessions.
statusMessage = 'Added ' + tokenName + ' to the list of active mappers.';
statusMessage += '
(ID: '+ tokenID + ')
';
whisper(playerName, statusMessage);
/* Removed: not needed because we don't drop a crumb on register anymore
var controllingPlayerID = tokenOwner;
if ( config.SHARED_VISION === true ) {
controllingPlayerID += ",all";
}
*/
var displayName = getDisplayName(tokenName);
if (debugDEFCON < 4) {
log("In registerMapper: added " + tokenID + " to list of Active mappers" + activeLightCrumbMappers);
log("in registerMapper: dropped LightCrumb: [" + tokenCoords + "], " + currentPage);
}
}
};
var getOffsetLocation = function offsetLocationGetter(currentLocation, lastLocation) { // expect two points [x,y], [x1,y1]
var offsetUnitVector = plexUtils.NormalizeVector(currentLocation, lastLocation);
if (debugDEFCON < 2) {log("offsetUnitVector = " + offsetUnitVector);}
var offsetScaledVector = plexUtils.ScaleVector(offsetUnitVector, config.OFFSET);
if (debugDEFCON < 2) {log("offsetScaledVector = " + offsetScaledVector);}
var offsetLocation = plexUtils.AddVectors([currentLocation, offsetScaledVector]);
if (debugDEFCON < 2) {log("offsetLocation = " + offsetLocation);}
if (offsetLocation == []) {
log("Couldn't find an offset location. Setting it to currentLocation");
offsetLocation = currentLocation;
}
if (debugDEFCON < 2 ) { log("offsetVector = " + offsetUnitVector); }
if (debugDEFCON < 2 ) { log("offsetLocation = " + offsetLocation); }
// normalizeVector is expecting two points
return offsetLocation;
};
/*
ooooooooo
888 88o oo oooooo ooooooo ooooooooo
888 888 888 888 888 888 888 888
888 888 888 888 888 888 888
o888ooo88 o888o 88ooo88 888ooo88
o888
*/
var dropLightCrumb = function lightCrumbDropper(customLightCrumbSettings, parentToken) { // expects an object with properties matching roll20 graphic objects
if (debugDEFCON < 5) { log("entered dropLightCrumb with " + JSON.stringify(customLightCrumbSettings)); }
// **** TODO: go through this list of variables and clear unused ones out
var LightCrumbMakerSupply,
currentLightCrumb,
size,
auraRadius,
auraColor,
showName,
showPlayersName,
showPlayersAura1,
targetLocation,
offsetLocation,
lastLocation = [],
currentPageID;
var defaultLightCrumbSettings = {
imgsrc: config.IMAGE,
subtype: 'token',
pageid: getCurrentPage("gm"),
width: 70 * config.ICON_RELATIVE_SIZE,
height: 70 * config.ICON_RELATIVE_SIZE,
left: 70,
top: 70,
layer: 'objects',
light_radius: config.LIGHT_RADIUS,
light_dimradius: config.DIM_RADIUS,
light_hassight: true,
light_otherplayers: true,
controlledby: "all",
isdrawing: true,
name: "Default LightCrumb",
gmnotes: parentToken
};
for (var propertyName in defaultLightCrumbSettings) { // compare custom settings with default and fill them out where needed.
if ( customLightCrumbSettings.hasOwnProperty(propertyName) === false ) {
customLightCrumbSettings[propertyName] = defaultLightCrumbSettings[propertyName];
}
}
currentPageID = customLightCrumbSettings.pageid;
LightCrumbMakerSupply = getLightCrumbsFromLayer("gmlayer", currentPageID);
currentLightCrumb = LightCrumbMakerSupply.pop();
if(currentLightCrumb) {
if (debugDEFCON < 2) { log("Found existing lightCrumb on GM Layer" + currentLightCrumb); }
currentLightCrumb.set(customLightCrumbSettings);
// log( "dropped old, salvaged currentLightCrumb: " + JSON.stringify(currentLightCrumb) );
} else { // no existing lightcrumb found. Make a new one.
if (debugDEFCON < 5) { log("No existing lightcrumb. About to make one."); }
currentLightCrumb = createObj('graphic',customLightCrumbSettings);
if (debugDEFCON < 4) {log( "dropped brand new currentLightCrumb: " + JSON.stringify(currentLightCrumb) );}
}
if (currentLightCrumb) {
// **** ! Clean this section up. It's a mess.
// Move it into or before the customLightCrumbSettings object gets built.
if (customLightCrumbSettings.controlledby.indexOf('all')) {
if (config.SHOW_AURA ) {
if (config.SHARED_VISION === false) {
auraColor = getAuraColor(currentLightCrumb.get("gmnotes"));
} else {
auraColor = config.SHARED_AURA_COLOR;
}
currentLightCrumb.set({
aura1_radius: config.AURA_RADIUS,
aura1_color: auraColor,
showplayers_aura1: true
});
} else {
currentLightCrumb.set("showplayers_aura1", false);
}
if (config.SHOW_NAMES) {
currentLightCrumb.set({
// name: "all",
showname: true,
showplayers_name: true
});
} else { // hide the name
currentLightCrumb.set({
// name: "all",
showname: false,
showplayers_name: false
});
}
} else { // "all" does not appear in the list: controlledby for the token.
if (config.SHOW_NAMES ) {
currentLightCrumb.set({
showname: true,
showplayers_name: true
});
} else { // hide the name
currentLightCrumb.set({
showname: false,
showplayers_name: false
});
}
if (config.SHOW_AURA) {
currentLightCrumb.set({
aura1_radius: config.AURA_RADIUS,
aura1_color: getAuraColor(currentLightCrumb.get("gmnotes")),
showplayers_aura1: true
});
} else { // hide the aura
currentLightCrumb.set({
showplayers_aura1: false
});
}
}
toBack(currentLightCrumb);
} else {
log("==> Something seems wrong. dropLightCrumb Tried to set the Z-order to back, but there was no LightCrumb object to move.");
}
if (debugDEFCON < 2) {
log( "Dropped a LightCrumb with the following properties: " + JSON.stringify(currentLightCrumb) );
var allLightCrumbsOnPlayerLayer = getLightCrumbsFromLayer("objects", currentPageID);
log("There are " + allLightCrumbsOnPlayerLayer.length + " known torch tokens on object layer: ");
}
if ( debugDEFCON<5 ) { log("leaving dropLightCrumb. Returning currentLightCrumb." + JSON.stringify(currentLightCrumb)); }
return currentLightCrumb;
};
var getGameMasterID = function gmIDGetter() {
if (debugDEFCON < 4) { log("entering getGameMasterID with no parameters"); }
var players = findObjs({
_type: "player",
});
var gmID;
var gmObj;
var currentPlayerID;
_.each(players, function loopToFindGM(player) {
if (debugDEFCON < 4) { log("evaluating player: " + JSON.stringify(player) ); }
currentPlayerID = player.get("_id");
if ( playerIsGM(currentPlayerID) ) {
gmID = currentPlayerID;
// ??? what happens if there's 2 GMs? We're only delivering up the last one found.
if (debugDEFCON < 2) {log("found a GM: " + gmID);}
}
});
if (debugDEFCON < 4) { log("exiting getGameMasterID. Returning " + gmID); }
return gmID;
};
/*
ooooooooo ooooooo oooooooo8 ooooooooo8
888 888 ooooo888 888 88o 888oooooo8
888 888 888 888 888oo888o 888
888ooo88 88ooo88 8o 888 888 88oooo888
o888 888ooo888
*/
var getCurrentPage = function currentPageGetter(tokenObjOrPlayerID) { // expects token, playerID, or string=="gm"
// **** TODO **** This isn't working as expected. Go through it and check assertions.
if ( debugDEFCON < 5) { log( "entering getCurrentPage with " + tokenObjOrPlayerID ); }
var currentPage;
var playerID;
var playerObj;
var gmID = getGameMasterID();
if ( debugDEFCON < 5) {
log(" gmID = " + gmID);
}
if (tokenObjOrPlayerID === undefined ) { // getCurrentPage received bad parameters, but we'll take care of it.
log("==> Error in getCurrentPage. tokenObjOrPlayerID == undefined");
return Campaign().get("playerpageid");
} else if ( tokenObjOrPlayerID == "gm") {
tokenObjOrPlayerID = gmID;
if (gmID) {
// currentPage = getObj("player", gmID).get("lastpage");
return Campaign().get("playerpageid");
} else {
return Campaign().get("playerpageid");
}
} else if ( _.isString(tokenObjOrPlayerID) ) { // it's a player ID
if (debugDEFCON < 4) { log(" tokenObjOrPlayerID was a string. Assume player_id: " + tokenObjOrPlayerID); }
playerID = tokenObjOrPlayerID;
playerObj = getObj("player", playerID);
if (playerIsGM(playerID)) { // it's the GM, use the lastpage property to find their page
if (debugDEFCON < 4) {
log(" player_id is a GM");
log(" playerObj.get('lastpage') returns " + playerObj.get("lastpage") );
//log(" Campaign().get('playerpageid') returns " + Campaign().get("playerpageid") );
}
currentPage = playerObj.get("lastpage"); // NOTE: there's no lastpage unless the GM has been on another page
if (!currentPage) {
currentPage = Campaign().get("playerpageid");
}
} else if ( Campaign().get("playerspecificpages")[playerID] ) {
if ( debugDEFCON < 4 ) {
log(" player_id is not a GM, and the players are seperated onto different pages");
log(" playerspecificpages = " + Campaign().get("playerspecificpages") );
}
// Note: there's no playerspecificpages unless a single player name is dragged onto another map
currentPage = Campaign().get("playerspecificpages")[playerID];
} else { // it's a player and the players are all on one page.
if (debugDEFCON < 4) { log(" player_id is not a GM, but there's only one page"); }
currentPage = Campaign().get("playerpageid");
}
} else if ( _.isObject(tokenObjOrPlayerID) ) { // it's a token
if (debugDEFCON < 4) { log(" tokenObjOrPlayerID was an object. Assume token: " + JSON.stringify(tokenObjOrPlayerID) ); }
var token = tokenObjOrPlayerID;
currentPage = token.get("page_id");
}
if (debugDEFCON < 4) { log("exiting getCurrentPage. Returning " + currentPage ); }
return currentPage;
};
var handlePlayerPageChange = function pageChangeHandler() {
// Nothing to be done. I'm not exactly sure why I have this yet.
return;
};
var getDisplayName = function displayNameGetter(tokenName) {
var words = tokenName.split(" ");
var initials= "";
_.each(words, function loopToBuildName(word) {
initials += word.charAt(0);
});
return initials;
};
var findShortestDistance = function shortestDistancetoTokenFinder(listOfGraphicObjectsToCompare, referenceLocation, tokenMoved ) {
if (debugDEFCON < 5) { log("entering findShortestDistance with: " + listOfGraphicObjectsToCompare + ", " + referenceLocation + ", " + tokenMoved); }
var shortestDistance = -1;
/*
var referenceLocation = [];
if ( _.isArray(referenceObject) ) { // check isArray first. Arrays pass as objects for underscore.js
referenceLocation = referenceObject;
} else if ( _.isObject(referenceObject) ) {
referenceLocation = [referenceObject.get("left"), referenceObject.get("top")];
} else { // something's wrong. didn't get object or array for reference object
log("==> Error in findShortestDistance: received " + referenceObject + " but expected token object or location array");
return -1;
} */
_.each(listOfGraphicObjectsToCompare, function loopToFindClosest(specificObjectToConsider) {
var targetLocation = [specificObjectToConsider.get("left"), specificObjectToConsider.get("top")];
var currentDistance = plexUtils.GetDistance(targetLocation, referenceLocation);
if ( shortestDistance == -1 || currentDistance < shortestDistance ) {
shortestDistance = currentDistance;
}
});
if (debugDEFCON < 5) { log("leaving findShortestDistance: returning shortestDistance = " + shortestDistance); }
return shortestDistance;
};
/*
oooo oooo
8888o 888 ooooooo oooo oooo ooooooooo8
88 888o8 88 888 888 888 888 888oooooo8
88 888 88 888 888 888 888 888
o88o 8 o88o 88ooo88 888 88oooo888
*/
var getLastLocation = function lastLocationGetter(token) {
if (debugDEFCON < 3) { log("lastmove for " + token.get("name") + ", " + token.get("_id") + " = " + token.get("lastmove") ); }
var movementPath = token.get("lastmove").split(",");
var lastLocation = [];
/*
if (_.isString(movementPath[0]) ) {
log("might have found your bug. token.get('lastmove').split(',') produces an array of strings. You need to convert them to numbers.");
} else if (_.isNumber(movementPath[0]) ) {
log("token.get('lastmove').split(',') seems to produce an array of numbers");
}
*/
lastLocation[0] = Number(movementPath[0]); // important to type convert them into numbers
lastLocation[1] = Number(movementPath[1]);
return lastLocation;
};
var handleTokenMove = function tokenMoveHandler(tokenMoved) {
if (debugDEFCON < 4 ) { log("entering handleTokenMoved with: " + tokenMoved); }
var tokenLocation = [],
tokenID = tokenMoved.get("_id"),
tokenPageID = tokenMoved.get("_pageid"),
tokenPageObj = getObj("page", tokenPageID),
parentTokenID = tokenMoved.get("_id"),
tokenName = tokenMoved.get("name"),
shortestDistanceToExistingCrumb = -1,
currentLocation,
lastLocation,
referenceLocation;
lastLocation = getLastLocation(tokenMoved);
currentLocation = [tokenMoved.get("left"), tokenMoved.get("top")];
if (!lastLocation) { // this token hasn't ever moved.. just use the current location.
lastLocation = [tokenMoved.get("left"), tokenMoved.get("top")];
}
if ( config.DROP_AT_PREVIOUS_LOCATION === true ) {
referenceLocation = lastLocation;
} else {
referenceLocation = getOffsetLocation(currentLocation, lastLocation);
}
if (activeLightCrumbMappers.indexOf(tokenID) !== -1) { // you're authorized to leave a trail of light.. continue
if(debugDEFCON < 4) {log("in handleTokenMove. About to get tokenLocation");}
// tokenLocation = [tokenMoved.get("left"), tokenMoved.get("top")];
// figure out which lightcrumbs you own.
var crumbsToConsider = getLightCrumbsFromLayer("objects", tokenPageID);
if (debugDEFCON < 4 ) { log("crumbsToConsider before SHARED_VISION test: " + _.size(crumbsToConsider) ); }
if ( config.SHARED_VISION === false || config.INHERIT_CHARACTER_LIGHTING === true ) { // filter the list of crumbsToConsider for crumbs owned by the token
var allCrumbsInConsideration = crumbsToConsider;
crumbsToConsider = _.filter( allCrumbsInConsideration, function removeOtherPlayersCrumbs(crumbInQuestion) {
if (crumbInQuestion.get("gmnotes") == tokenID ) { // ownership is designated by the parentToken's ID in the gmnotes field on lightcrumb objects
return true;
} else {
return false;
}
});
}
if (debugDEFCON < 4 ) { log("crumbsToConsider after SHARED_VISION test: " + _.size(crumbsToConsider + ", " + JSON.stringify(crumbsToConsider)) ); }
shortestDistanceToExistingCrumb = findShortestDistance(crumbsToConsider, referenceLocation, tokenMoved);
if (debugDEFCON < 4) { log("config.DROP_DISTANCE: " + config.DROP_DISTANCE + ", Current Distance: " + shortestDistanceToExistingCrumb); }
// figure out how far between crumbs is ok, so you can drop another one.
var minSeperation = config.DROP_DISTANCE;
var pixelsPerFoot = 70 / tokenPageObj.get("scale_number");
if (config.INHERIT_CHARACTER_LIGHTING === true) { // use light_radius from parentToken
// minSeperation = tokenMoved.get("light_radius") * pixelsPerFoot * 0.75; // **** TODO **** change this to use dynamic grid-size data from page object.
minSeperation = config.DROP_DISTANCE * pixelsPerFoot;
} else {
minSeperation = config.DROP_DISTANCE * pixelsPerFoot;
}
if ( shortestDistanceToExistingCrumb == -1 || shortestDistanceToExistingCrumb > minSeperation ) {
if (debugDEFCON < 4) { log("LightCrumb.handleTokenMove: registered token, "+ tokenID +", moved. dropping light token"); }
// var controllingPlayerID = tokenMoved.get("controlledby"); // fails
var activeCharacter = getObj("character", tokenMoved.get("represents"));
var controllingPlayerID
if (activeCharacter !== undefined) {
var controllingPlayersList = activeCharacter.get("controlledby");
var controllingPlayersArray = controllingPlayersList.split(",");
var actualPlayersArray = _.without(controllingPlayersArray, "all");
var firstPlayerListed = actualPlayersArray[0];
controllingPlayerID = firstPlayerListed;
if (controllingPlayerID === undefined) {
controllingPlayerID = "all";
}
// figure out the first one that's not "all players"
} else { // there's no one assigned to the token
controllingPlayerID = "all";
whisper("gm", "Be aware: There's no player assigned to that token. Things might get weird.");
}
// **** NOTE: you might have problems if characters have multiple owners
if (debugDEFCON < 4) { log(" in handleTokenMove: controllingPlayerID = " + controllingPlayerID ); }
if ( config.SHARED_VISION === true ) {
controllingPlayerID += ",all";
}
var displayName = getDisplayName(tokenName);
var customLightCrumbSettings = {
left: referenceLocation[0],
top: referenceLocation[1],
pageid: tokenPageID,
controlledby: controllingPlayerID,
name: displayName,
aura1_color: getAuraColor(parentTokenID)
};
if (config.SHARED_VISION) {
customLightCrumbSettings.light_otherplayers = true;
} else {
customLightCrumbSettings.light_otherplayers = false;
}
if (config.INHERIT_CHARACTER_LIGHTING) {
customLightCrumbSettings.light_radius = tokenMoved.get("light_radius");
customLightCrumbSettings.light_dimradius = tokenMoved.get("light_dimradius");
}
var currentLightCrumb = dropLightCrumb(customLightCrumbSettings, tokenMoved.get("_id")); //movementDrop
if (debugDEFCON < 4) { log(" in handleTokenMove: dropped LightCrumb [" + lastLocation + "], "+ tokenPageID); }
}
}
if (debugDEFCON < 4) { log("leaving handleTokenMove. Nothing to return."); }
return;
};
/*
ooooo . oooo oooo
`888' .o8 `888 `888
888 ooo. .oo. .oooo.o .o888oo .oooo. 888 888
888 `888P"Y88b d88( "8 888 `P )88b 888 888
888 888 888 `"Y88b. 888 .oP"888 888 888
888 888 888 o. )88b 888 . d8( 888 888 888
o888o o888o o888o 8""888P' "888" `Y888""8o o888o o888o
*/
var checkInstall = function () {
log("/===-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-===/");
log(" Starting LightCrumb Script ");
log(" current time is: " + Date.now() + " ");
log(" ");
log(" To use, enter !LightCrumb in chat. ");
log("/===-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-===/");
// Roll20 allows scripters to store persistent data in their "state" object.
// We'll use the LightCrumb property in state to store persistent info about this script for each campaign.
// Notably: who's registered to leave automatic LightCrumb trails.
if( ! _.has(state,'LightCrumb') ) { // first time running the LightCrumb script for this Roll20 campaign. It needs a state.
log('-=> LightCrumb v'+version+' <=- ['+(new Date(lastUpdate))+']');
state.LightCrumb = {
version: schemaVersion,
activeMappers: [],
colors: COLORS,
config: config
};
} else { // a LightCrumb object already exists in the Roll20 persistent "state" object.
var lengthOfStateConfig = _.size(state.LightCrumb.config);
var lengthOfLightCrumbConfig = _.size(config);
if (debugDEFCON < 2) { log("state.LightCrumb.config = " + JSON.stringify(state.LightCrumb.config) ); }
if (debugDEFCON < 2) { log("config = " + JSON.stringify(config) ); }
if ( state.LightCrumb.version !== schemaVersion || lengthOfLightCrumbConfig !== lengthOfStateConfig ) {
log("Seems like the script got updated: " + state.LightCrumb.version);
log("Updating state.LightCrumb.version to reflect current script: "+schemaVersion);
state.LightCrumb.version = schemaVersion;
/*
for (var propertyName in config) {
if (state.LightCrumb.config.hasOwnProperty(propertyName)) {
log("found property: " + propertyName + ": " + state.LightCrumb.config[propertyName]);
} else {
log("missing property: " + propertyName + ": " + config[propertyName]);
state.LightCrumb.config[propertyName] = config[propertyName];
}
}
*/
/* Reset to Default Settings for this campaign? */
state.LightCrumb.config = _.clone(config);
}
if (_.has(state.LightCrumb, 'activeMappers')) {
activeLightCrumbMappers = _.clone(state.LightCrumb.activeMappers);
} else {
state.LightCrumb.activeMappers = _.clone(activeLightCrumbMappers);
}
if (_.has(state.LightCrumb, 'config')) {
config = _.clone(state.LightCrumb.config);
} else {
state.LightCrumb.config = _.clone(config);
}
if (_.has(state.LightCrumb, 'colors')) {
COLORS = _.clone(state.LightCrumb.colors);
} else {
state.LightCrumb.colors = _.clone(COLORS);
}
}
if (_.has(state.LightCrumb.config) && state.LightCrumb.config.SHOW_HELP_ON_READY == 1) {
LightCrumb.ShowDetailedHelp('gm');
}
};
/* ---------------------------------------------------------------------------- */
/* --------------------- */
// IN CONSTRUCTION //
/* --------------------- */
var checkGlobalConfig = function globalConfigChecker() {
// Set the theme from the useroptions.
var useroptions = globalconfig && globalconfig.LightCrumb;
if(useroptions) {
state.LightCrumb.config.SHOW_HELP_ON_READY = useroptions.SHOW_HELP_ON_READY;
state.LightCrumb.userOptions = {
SHOW_HELP_ON_READY: useroptions.SHOW_HELP_ON_READY
};
}
};
/* ---------------------------------------------------------------------------- */
var registerEventHandlers = function() {
if (debugDEFCON < 5) {
log("LightCrumb registered event handlers");
}
on('chat:message', handleInput );
on('change:graphic', handleTokenMove );
};
return {
RegisterEventHandlers: registerEventHandlers,
CheckInstall: checkInstall,
Reset: reset,
ShowDetailedHelp: showDetailedHelp
};
}());
/*
ooo ooooo . oooo .o.
`88. .888' .o8 `888 888
888b d'888 .oooo. .o888oo 888 .oo. 888
8 Y88. .P 888 `P )88b 888 888P"Y88b Y8P
8 `888' 888 .oP"888 888 888 888 `8'
8 Y 888 d8( 888 888 . 888 888 .o.
o8o o888o `Y888""8o "888" o888o o888o Y8P
*/
var plexUtils = plexUtils || (function plexsoupAwesomeMaths() {
// Another module. This one for fun math. Adding and subtracting vectors, Distance, etc.
var debugDEFCON = 5; // 5 = AOK: log nothing. 1 = FUBAR: log everything
var getLongestVectorLength = function longestVectorGetter(vectorList) {
// **** why is this returning a length of 3 for two dimensional vectors?
if (debugDEFCON < 2) { log("entering getLongestVectorLength with: " + vectorList); }
if (vectorList.length == 2) {
if ( _.isNumber(vectorList[0]) ) {
log("aborting getLongestVectorLength(" + vectorList + "). I think we got one vector (a single x,y location) instead of a list of vectors.");
return(2);
}
} else {
if (debugDEFCON<2) {log("vectorList.length = " + vectorList);}
}
var longestVectorLength = 0;
_.each(vectorList, function loopToFindLongest(vector) {
if (vector.length > longestVectorLength) {
longestVectorLength = vector.length;
}
});
if (debugDEFCON < 3) {
log("getLongestVectorLength returning with: " + longestVectorLength);
}
return longestVectorLength;
};
var initializeVector = function vectorInitialiser(lengthRequired) {
if (debugDEFCON < 2) { log("initializeVector called with " + lengthRequired); }
var newVector = [];
var elementID;
for(elementID = 0; elementID < lengthRequired; elementID++) {
newVector.push(0);
}
if (debugDEFCON < 2) { log("initializeVector returning with " + newVector); }
return newVector;
};
var addVectors = function vectorAdder(listOfVectors) { // expects a 2d array.. [[point1, point2, ... pointN], ..., [pn1, pn2, ... pnN]]
// assumes the input vectors are the same length: eg 2 coordinates each: X and Y
if (listOfVectors.length == 2 ) { // make sure you're adding 2 vectors and not 2 points
if (_.isNumber(listOfVectors[0])) {
log("Aborting addVectors(" + listOfVectors + "). I think it contains one vector instead of two or more.");
return listOfVectors; // bail out.. something went wrong. You got a point instead of 2 vectors
}
}
if ( debugDEFCON < 2 ) { log("addVectors called with: " + listOfVectors); }
var longestVectorLength = getLongestVectorLength(listOfVectors);
var sumVector = initializeVector(longestVectorLength);
var elementID = 0;
var vectorNumber = 0;
for(elementID=0; elementID
0) {
unitVector = scaleVector(translatedVector, 1/distance );
} else { // abort. can't divide by 0. Make something up instead.
unitVector = translatedVector;
if ( debugDEFCON<2) {log("trying to normalize a vector where the distance is zero. Can't divide by zero.");}
}
if (debugDEFCON < 2) { log("unitVector is: " + unitVector); }
if (debugDEFCON < 2) { log("leaving normalizeVector with: " + unitVector); }
return unitVector;
};
var getDistance = function distanceGetter(point1, point2) {
// distance is squareroot of the squared sum of each side
//if (debugDEFCON < 2) { log("entering getDistance with " + point1 + ", " + point2); }
var xDist = Math.abs(point2[0] - point1[0]);
var xDistSquared = Math.pow(xDist, 2);
var yDist = Math.abs(point2[1] - point1[1]);
var yDistSquared = Math.pow(yDist, 2);
var distance = Math.sqrt(xDistSquared + yDistSquared);
//if (debugDEFCON < 2) { log("returning from getDistance with " + distance); }
return distance;
};
return {
AddVectors: addVectors,
ScaleVector: scaleVector,
GetDistance: getDistance,
NormalizeVector: normalizeVector
};
}()); // End of Module: plexUtils
/*
ooo ooooo o8o
`88. .888' `"'
888b d'888 .oooo. oooo ooo. .oo.
8 Y88. .P 888 `P )88b `888 `888P"Y88b
8 `888' 888 .oP"888 888 888 888
8 Y 888 d8( 888 888 888 888
o8o o888o `Y888""8o o888o o888o o888o
*/
on("ready",function(){
// this stuff happens when the script loads.
// Note: you have to use Caps to refer to the left side of the function declarations in "return"
LightCrumb.CheckInstall(); // instantiate all the function expressions
LightCrumb.RegisterEventHandlers(); // instantiate all the listeners
});