Last active
December 29, 2018 05:01
-
-
Save SplenectomY/58c2e74a062e140d11c988abeb963496 to your computer and use it in GitHub Desktop.
Performance and functionality improvements for a popular Roll20 script
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* ************ Splen's Easy Doors and Stairs ***************** | |
* AUTOTELEPORTING: This feature allows you to place a token on | |
one square (for example stairs) and it will auto move a token | |
to the linked location and back again should you choose. | |
* Linked locations need to be tokens placed on the GMLayer. | |
* Naming conventions: | |
* ex: Two way doors: XXXXXXX02A, XXXXXXXX02B | |
In this example, "2" refers to the amount of stops. | |
This number must always match the total amount of | |
Stops for stairs. See the next example. | |
* ex: Three floor staircase: stairs03A, stairs03B, stairs03C | |
Now that same number is "3" since there are three stops. | |
"A" is the bottom floor, "B" is a middle floor and | |
"C" is the top floor. The "0" in either example | |
can be changed if multiple systems with similar names | |
are used. Everything else except for the last letter | |
must match in each destination token's name. | |
* To change the name of a stop (door, stairs, portal, ladder) | |
Just put the name in the gmnotes of the token. | |
* This system can handle up to a 9 floor staircase (9I max). | |
* When a token lands on a teleporter, whoever controls that | |
token will receive a whisper message in chat with buttons | |
to either use the object (door, 1-way stairs) or choose | |
to go up or down (two-way stairs). This is to prevent | |
unwanted auto-teleporting | |
* Use the in-game command !AUTOTELEPORTER to toggle this script. | |
Your settings are saved and should persist across restarts. | |
****************************************************************/ | |
state.SplY_Teleporter = state.SplY_Teleporter || {}; | |
// Config | |
state.SplY_Teleporter.Debug = false; | |
// Verbose logging to console | |
// End Config | |
(function() // Begin localization | |
{ | |
let Teleporter = state.SplY_Teleporter; | |
Teleporter.GMs = {}; | |
Teleporter.AUTOTELEPORTER = Teleporter.AUTOTELEPORTER || true; | |
// use the in-game command !AUTOTELEPORTER to toggle this bool | |
const debug = Teleporter.Debug; | |
const IsOnTeleporter = function(token, teleporter) | |
{ | |
var maxLeft = teleporter.get("width") / 2; | |
var maxTop = teleporter.get("height") / 2; | |
if (token.get("left") <= teleporter.get("left") + maxLeft | |
&& token.get("left") >= teleporter.get("left") - maxLeft | |
&& token.get("top") <= teleporter.get("top") + maxTop | |
&& token.get("top") >= teleporter.get("top") - maxTop) | |
return true; | |
return false; | |
} | |
const SendPlayerMessage = function(player, message) | |
{ | |
if (debug) | |
{ | |
log("Player = " + player); | |
log("Displayname =" + player.get("_displayname")); | |
log("Narrator: /w " + player.get("_displayname") + ' Options: ' + message); | |
} | |
if (player.get("_displayname").includes('"')) | |
{ | |
sendChat("AutoTeleporter", "/w gm Player " + player.get("_displayname") | |
+ ' has quotation marks (") in their name, which is interefering with ' | |
+ "the AutoTeleport script's functionality. Consider using single quotes (') for this character's name instead!"); | |
sendChat("Narrator", 'A token controlled by ' + player.get("_displayname") + ' has some options: ' + message, null, { noarchive: true }); | |
} | |
else | |
sendChat("Narrator", '/w "' + player.get("_displayname") + '" Options: ' + message, null, { noarchive: true }); | |
} | |
Teleporter.Teleport = function (tokenId, TargetName, pageid, initialTokenId, who) | |
{ | |
try | |
{ | |
var location = findObjs( | |
{ | |
_type: "graphic", | |
_pageid: pageid, | |
layer: "gmlayer", //target location MUST be on GM layer | |
name: TargetName | |
}); | |
if (location.length == 0) | |
{ // exit if invalid target location | |
log("Teleport destination "+ TargetName +" not found for token "+ tokenId) | |
return; | |
} | |
var LocX = location[0].get("left"); | |
var LocY = location[0].get("top"); | |
var tokenToMove = getObj("graphic", tokenId); | |
if (tokenToMove == undefined || tokenToMove == null) | |
return; | |
var initialToken = getObj("graphic", initialTokenId); | |
if (initialToken == undefined || initialToken == null) | |
return; | |
if (!IsOnTeleporter(tokenToMove, initialToken)) | |
{ | |
var player = getObj("player", who); | |
log("AUTOTELEPORT: Token " + tokenToMove.get("name") | |
+ " has been moved off the teleporter since the chat buttons were sent. Aborting."); | |
sendChat("Narrator", '/w "' + player.get("_displayname") | |
+ '" Your token ' + tokenToMove.get("name") | |
+ " has moved too far and cannot use that object."); | |
return; | |
} | |
log("Teleporting token "+ tokenToMove.get("name") +" to destination "+ TargetName); | |
tokenToMove.set("left", LocX); | |
tokenToMove.set("top", LocY); | |
} | |
catch(e) | |
{ | |
sendChat("Autoteleporter", "/w gm An error occurred. Check the log."); | |
log(e.message); | |
} | |
}; | |
var teleporterLogic = function(obj) | |
{ | |
if (Teleporter.AUTOTELEPORTER == false || obj.get("layer") != "objects") | |
return; | |
var location = findObjs( | |
{ | |
_pageid: obj.get("_pageid"), | |
_type: "graphic", | |
layer: "gmlayer" | |
}); | |
if (location.length == 0) | |
return; | |
var initialToken = null; | |
_.each(location, function(tok) | |
{ | |
if (IsOnTeleporter(obj, tok) && tok.get("name") != "") | |
initialToken = tok; | |
}); | |
if (initialToken == null) | |
return; | |
var CurrName = initialToken.get("name"); | |
const Letters = new Array("A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L"); | |
var doorCount = CurrName.substr(CurrName.length - 2, 1); | |
var currDoor = CurrName.substr(CurrName.length - 1, 1); | |
var tokenName = CurrName.substr(0, CurrName.length - 3); | |
var namePlusNumber = CurrName.substr(0, CurrName.length - 2); | |
if (debug) | |
log("doorCount is NaN = " + isNaN( parseInt(doorCount) ) ); | |
if (currDoor == "" || doorCount == "" || isNaN( parseInt(doorCount) ) ) | |
return; | |
var i = Letters.indexOf(currDoor); | |
var choices = 0; | |
var type = initialToken.get("gmnotes") != "" ? FixGmNotes(initialToken.get("gmnotes")) : tokenName; | |
var message = ""; | |
var matchingTokens = []; | |
_.each(location, function(t) | |
{ | |
var nameToTest = t.get("name").substr(0, CurrName.length - 2); | |
if (namePlusNumber === nameToTest && t.get("name") != CurrName) | |
matchingTokens.push(t); | |
}); | |
if (debug) | |
log("matchingTokens amount = " + matchingTokens.length); | |
if (matchingTokens.length < 1) | |
return; | |
if (i == 0) | |
choices = 1; // bottom of the staircase, can only go up | |
else if (i == doorCount - 1) | |
choices = -1; // Top of the staircase, can only go down | |
else | |
choices = 0; // Can choose to go up or down | |
let targName = CurrName.substr(0, CurrName.length - 2) + doorCount; | |
let msgEnd = ", " + obj.id + ", " + obj.get("_pageid") + ", " + initialToken.id + ")"; | |
if (choices == 0) | |
{ | |
const dirSelector = | |
{ | |
"up" : targName + Letters[i + 1], | |
"down" : targName + Letters[i - 1] | |
} | |
_.each(["up","down"], function(direction) | |
{ message += " [Go " + direction + " the " + type + "](!Teleport " + dirSelector[direction] + msgEnd; }); | |
} | |
else | |
message += " [Use the "+ type +"](!Teleport " + targName + Letters[i + choices] + msgEnd; | |
// Who do we send the message to? | |
var playersString = obj.get("controlledby"); | |
if (debug) | |
log("Controlledby = " + obj.get("controlledby")); | |
var playersArray = playersString.split(","); | |
var players = []; | |
if (playersArray.length === 0) | |
{ | |
log("Couldn't send auto-teleport buttons to token " + obj.get("name") + " because it was assigned control to nobody."); | |
return; | |
} | |
_.each(playersArray, function(p) | |
{ | |
if (p != "") | |
{ | |
var player = getObj("player", p); | |
if (player != null || player != undefined) | |
players.push(player); | |
} | |
}); | |
if (debug) | |
{ | |
log("players = " + players); | |
log("players.length = " + players.length); | |
} | |
if (players.length > 0) | |
{ // found some player(s) who control the token. Send the message to them | |
_.each(players, function(player) | |
{ SendPlayerMessage(player, message); }); | |
} | |
else if (obj.get("represents") != null && obj.get("represents") != undefined && obj.get("represents") != "") | |
{ | |
if (debug) | |
{ | |
log("AUTOTELEPORT: Token "+ obj.get("name") +" represented by character sheet."); | |
log("Attempting to find valid player owner of character sheet for messaging ..."); | |
} | |
var character = getObj("character", obj.get("represents")); | |
var playersString2 = character.get("controlledby"); | |
if (debug) | |
log("Character sheet is controlled by: " + playersString2); | |
var playersArray2 = playersString2.split(","); | |
var players2 = []; | |
if (playersArray2.length < 1) | |
{ | |
log("Could not find any player controllers of the character sheet. Aborting.") | |
return; | |
} | |
_.each(playersArray2, function(p) | |
{ | |
if (p != "") | |
{ | |
var player = getObj("player", p); | |
if (player != null || player != undefined) | |
players2.push(player); | |
} | |
}); | |
_.each(players2, function(player) | |
{ SendPlayerMessage(player, message); }); | |
} | |
else // No players who control the token and no represented character sheets. Send the message to a GM | |
sendChat("AutoTeleport Script", "/w gm A token '" + obj.get("name") + "' can use a nearby " | |
+ type + ". Options: " + message, null, { noarchive: true }); | |
log("Sent auto-teleport buttons to token " + obj.get("name")); | |
} | |
on("ready", function() | |
{ | |
var players = findObjs({ _type: "player" }); | |
_.each(players, function(p) | |
{ | |
if (playerIsGM(p.id)) | |
Teleporter.GMs[p.id] = p; | |
}); | |
on ("change:graphic:lastmove", function(obj) | |
{ | |
try | |
{teleporterLogic(obj);} | |
catch(e) | |
{ | |
log(e.message); | |
sendChat("Autoteleporter", "/w gm An error occurred. Check the log."); | |
} | |
}); | |
on ("chat:message", function(msg) | |
{ | |
if (msg.type != "api") | |
return; | |
const cmdName = "!Teleport "; | |
if (msg.content.indexOf(cmdName) !== -1) | |
{ | |
const cleanedMsg = msg.content.replace(cmdName, ""); | |
const commands = cleanedMsg.split(", "); | |
const targetName = commands[0]; | |
const pageid = commands[commands.length - 2]; | |
const initialToken = commands[commands.length - 1]; | |
var i = 1; | |
while (i < commands.length - 2) | |
{ | |
try | |
{ | |
log("Attempting to teleport token " + commands[i] + " to " + targetName + initialToken + " on page " + pageid); | |
Teleporter.Teleport(commands[i], targetName, pageid, initialToken, msg.playerid); | |
i++; | |
} | |
catch(e) | |
{ | |
log(e.message); | |
sendChat("Autoteleporter", "/w gm An error occurred. Check the log."); | |
} | |
} | |
} | |
else if (msg.content.indexOf("!AUTOTELEPORTER") !== -1 && playerIsGM(msg.playerid) ) | |
{ | |
if (Teleporter.AUTOTELEPORTER) | |
{ | |
sendChat("Autoteleporter", "Autoteleporting Disabled."); | |
Teleporter.AUTOTELEPORTER = false; | |
} | |
else | |
{ | |
sendChat("Autoteleporter", "Autoteleporting Enabled."); | |
Teleporter.AUTOTELEPORTER = true; | |
} | |
} | |
}); | |
}); | |
const FixGmNotes = string=>{ | |
const fixNotes = (match, offset, string)=>{ | |
return { | |
"%20" : " ", | |
"%21" : "!", | |
"%28" : "(", | |
"%29" : ")", | |
"%3A" : ":", | |
"%2C" : ",", | |
"%3Cbr" : "", // <br> line break | |
"%3E" : "", | |
"%3Cp" : "", // <p> paragraph | |
"%3C/p" : "", // </p> | |
"%22" : '"', | |
"%27" : "'", | |
"%3F" : "?", | |
"%3Cstrong" : "<b>", | |
"%3C/strong" : "</b>", | |
"%3Cem" : "<i>", | |
"%3C/em" : "</i>", | |
"%3Cul" : "<ul>", | |
"%3C/ul" : "</ul>", | |
"%3Cli" : "<li>", | |
"%3C/li" : "</li>", | |
"%25" : "%" | |
}[match] | |
} | |
, re = /(%20|%21|%28|%29|%27|%25|%3(?:Cbr|(?:E)%3A|A|E|F|C(?:(?:\/)?strong|(?:\/)?em|(?:\/)?p|(?:\/)?ul|(?:\/)?li|))|%22|%2C)/g; | |
return string.replace(re, fixNotes); | |
} | |
})(); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment