[Script] Map Teleporters - Automatic teleporters that can move players between maps

1484042303

Edited 1484070183
I took some concepts from TheWhiteWolves's excellent  MapChange plugin and smashed them together with DarokinB's  Teleporter Without Movement Tracker script, and dubbed the resulting demon love child Map Teleporters. Link:  Map Teleporters It uses the same teleport chain configuration method developed by DarokinB, but has the added benefit of supporting teleportation between map pages, including moving the individual player controlling the token being teleported to the new map as well as hiding the player's token in the GM layer when they teleport out of a map and moving it back to the object layer when they teleport into a map. Couple of quirks to keep in mind: * In order for the player controlling the token to be moved to the new map on teleport, they must be the only player controlling the character represented by the token. * You need a copy of the token being teleported already present on the map to which you're trying to teleport. (It doesn't have to be visible or have the exact same stats, it just needs to represent the same character and have the same display name)
1484070272

Edited 1484073031
I made a small update to the script so that moving a token representing a character only controlled by all players will rejoin the players and move them to the new map. Why you ask?  It's a secret to everyone.
1484071227

Edited 1484072655
The Aaron
Pro
API Scripter
It really IS a secret to everyone... that join link doesn't work. 
1484072284
Stephen L.
Pro
Marketplace Creator
Sheet Author
API Scripter
Nice. You should consider adding this to the Roll20 API script repository and (the One-Click installer). 
1484073064

Edited 1484073075
The Aaron said: It really IS a secret to everyone... that join link doesn't work.  Whoops! Sorry about that. I think it reset the invite code when I kicked the alt I'd been using to test it. Should be fixed now.
1484073857
The Aaron
Pro
API Scripter
Yup, kicking someone changes the join link.
1484074123
The Aaron
Pro
API Scripter
That's very clever and fun!  Great way to demo the script. =D I did notice that dragging the token to the left exit from the start screen causes the transition, but using the keyboard arrow keys to do it does not.  Likely there is some very small math error that causes the position not to match the target.  For exactly that reason, I rewrote the matching function in the original a while back.  Here's what I used:  var findContains = function(obj,layer){     "use strict";     var cx = obj.get('left'),         cy = obj.get('top');     if(obj) {         layer = layer || 'gmlayer';         return _.chain(findObjs({             _pageid: obj.get('pageid'),                                           _type: "graphic",             layer: layer          }))             .reduce(function(m,o){                 var l=o.get('left'),                     t=o.get('top'),                     w=o.get('width'),                     h=o.get('height'),                     ol=l-(w/2),                     or=l+(w/2),                     ot=t-(h/2),                     ob=t+(h/2);                                      if(    ol <= cx && cx <= or                      && ot <= cy && cy <= ob                  ){                     m.push(o);                 }                 return m;             },[])             .value();     }     return [];  };  And the first part of where I called it: on("change:graphic", function(obj) {     "use strict";     if (obj.get("name").indexOf("Teleport") !== -1) {         return; //Do not teleport teleport pads!!     }     if (Teleporter.AUTOTELEPORTER === false) {         return; //Exit if auto Teleport is disabled     }     /*  To use this system, you need to name two Teleportation locations the same     *   with only an A and B distinction. For instance Teleport01A and Teleport01B      *   will be linked together. When a token gets on one location, it will be     *   Teleported to the other automatically */          //Finds the current teleportation location     var CurrName = "";          var location = findContains(obj,'gmlayer');     if (location.length === 0) {         return;     } Cheers!
1484075132
The Aaron said: That's very clever and fun!  Great way to demo the script. =D I did notice that dragging the token to the left exit from the start screen causes the transition, but using the keyboard arrow keys to do it does not.  Likely there is some very small math error that causes the position not to match the target.  For exactly that reason, I rewrote the matching function in the original a while back.  Here's what I used:  var findContains = function(obj,layer){     "use strict";     var cx = obj.get('left'),         cy = obj.get('top');     if(obj) {         layer = layer || 'gmlayer';         return _.chain(findObjs({             _pageid: obj.get('pageid'),                                           _type: "graphic",             layer: layer          }))             .reduce(function(m,o){                 var l=o.get('left'),                     t=o.get('top'),                     w=o.get('width'),                     h=o.get('height'),                     ol=l-(w/2),                     or=l+(w/2),                     ot=t-(h/2),                     ob=t+(h/2);                                      if(    ol <= cx && cx <= or                      && ot <= cy && cy <= ob                  ){                     m.push(o);                 }                 return m;             },[])             .value();     }     return [];  };  And the first part of where I called it: on("change:graphic", function(obj) {     "use strict";     if (obj.get("name").indexOf("Teleport") !== -1) {         return; //Do not teleport teleport pads!!     }     if (Teleporter.AUTOTELEPORTER === false) {         return; //Exit if auto Teleport is disabled     }     /*  To use this system, you need to name two Teleportation locations the same     *   with only an A and B distinction. For instance Teleport01A and Teleport01B      *   will be linked together. When a token gets on one location, it will be     *   Teleported to the other automatically */          //Finds the current teleportation location     var CurrName = "";          var location = findContains(obj,'gmlayer');     if (location.length === 0) {         return;     } Cheers! Thanks for the tip! This is like the third time I've done anything in Javascript, so I'm not surprised there's issues. I'll update the gist when I get back from work.
1484075396
The Aaron
Pro
API Scripter
No worries. =D
1484076086
Stephen L. said: Nice. You should consider adding this to the Roll20 API script repository and (the One-Click installer).  First I want to iron out any bugs, then I want ask TheWhiteWolves and DarokinB for their blessing. This started out as a straight up modification of MapChange until I realized it could function independently (and also compatibly as far as I can tell) and I copied the core teleporter chaining code directly from DarokinB's script. If they have no objections then I'll definitely look into uploading it to the repo.
1484079395

Edited 1484084114
It's too bad there's not any way to detect the player or entity which triggered a change:graphic event or find the last player to manipulate a token. If there was I could move the player who moves a token onto a teleport without forcing GMs to restrict token control to one player (Not a terribly an onerous restriction admittedly, but I've played in some campaigns where it was useful for players to move each other's tokens) It would also let me add multiple public tokens to the demo which can move individual players independently without needing to restrict control to a single specific player. Update: One alternative would be having players link themselves to a particular character token by having them set themselves to it under "Speaking As". Then I can just search for all players with "speakingas" matching the character tied to the token being teleported, then move all those players. This should solve a lot of the frustrations I currently have trying to determine which player corresponds to which character/token. Additionally, I think I can register a handler for "change:player:speakingas" and move the player to the page where the selected character's token is on the object layer when the player changes their "Speaking As" setting between characters. In the context of this demo I could create linked (pun not intended) characters and tokens "Link" and "Zelda", both of which are public and controllable by anyone. In the initial state Zelda and Link are on the starting map and the player starts speaking as themselves. Let's say they move Link to the left map and Zelda to the right. Since they aren't speaking as either character they'd remain on the starting map with no visible tokens. If they change their speaking as to "Link" the script will detect the change and move them to the left map, as that is the only map where the "Link" token is located on the object layer. Similarly they can change their speaking as to "Zelda" and the map will move them to the right map. Can't wait to try this out.
1484083120
The Aaron
Pro
API Scripter
Well.. for the demo, you could catch the on('change:player:_online', ...) event and add a character for each new player...   =D
1484084260

Edited 1484084502
The Aaron said: Well.. for the demo, you could catch the on('change:player:_online', ...) event and add a character for each new player...   =D That would help, but I'd still need to create a new token exclusively representing that new character if I stuck with my current method of mapping players to tokens. Is there an API function to add new tokens to pages? I couldn't find any last time I looked... Edit: Oh hell yes! Just noticed createObj. This gonna be good.