Roll20 uses cookies to improve your experience on our site. Cookies enable you to enjoy certain features, social sharing functionality, and tailor message and display ads to your interests on our site and others. They also help us understand how our site is being used. By continuing to use our site, you consent to our use of cookies. Update your cookie preferences .
×
Create a free account

More Questions From a New DM!

Alright guys! So my campaign is looking really good so far. I even bought a map pack and a token pack to make sure i'm really giving it my all! I made a sweet, kicking tavern all by myself, and was wonderful if there was a way to save it. I know you can print screen, post it to paint, and save it that way, but I was hoping for some sort of template saver that would save it square-by-square, that I can just pull up later. Also, is there a way to have a script running where if a player enters a certain square, something happens? For example, if I put stairs in my tavern to lead to the upstairs floor, can I have it so that way when a token lands on the square, it's instantly teleported to a square of my choosing (And even better if it's reverse able!) Thanks for the help again!
1432360016
The Aaron
Roll20 Production Team
API Scripter
For archiving maps you've created, I'd suggest creating a second campaign and using the Transmogriphier to copy the map to that campaign as a storage area. I often do this for NPCs and Monsters I've set up, as well as Maps. There are quite a few options for API scripts that do things when PCs enter a square, there is even one that does exactly what you mentioned. I'm not sure where the current thread is for it, but here's the most recent copy I have laying about: /* ************ TELEPORTING SCRIPT ************************** * The intention of this script is to allow the DM to teleport * one or all characters to a location based on a token placed * on the DM layer of the map. * To activate the script, type "!Teleport " and add the name * of the teleport location (must not contrain spaces) and then * the name of the party member to teleport there. They must be * seperated by commas. If you want all to teleport, type all. * ie. !Teleport teleport01, all - teleports all players to teleport01 * * 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: * Two way doors: XXXXXXXX2A, XXXXXXXXX2B * Three way dooes: XXXXXXXX3A, XXXXXXXXX3B, XXXXXXXXX3C * (in the case of one way doors, dont create a 3C) * This system can handle up to 9 way doors (9I max). ****************************************************************/ var Teleporter = Teleporter || {}; Teleporter.AUTOTELEPORTER = true; //Set to true if you want teleports to be linked Teleporter.Teleport = function (CharName, TargetName) { "use strict"; var LocX = 0; var LocY = 0; //find the target location var location = findObjs({ _pageid: Campaign().get("playerpageid"), _type: "graphic", layer: "gmlayer", //target location MUST be on GM layer name: TargetName }); if (location.length === 0) { return; //exit if invalid target location } LocX = location[0].get("left"); LocY = location[0].get("top"); //if all are indicated, it lists all //finds all tokens with the name var targets = findObjs({ _pageid: Campaign().get("playerpageid"), _type: "graphic" }); //Move characters to target location _.each(targets, function(obj) { //Only player tokens if (CharName === "all") { if (obj.get("represents") !== "") { log("Setting all"); obj.set("left", LocX + 1); obj.set("top", LocY); } } else { if (obj.get("name").indexOf(CharName) !== -1) { if (obj.get("represents") !== "") { obj.set("left", LocX + 1); obj.set("top", LocY); } } } }); }; on("chat:message", function(msg) { "use strict"; var cmdName = "!Teleport "; if (msg.type === "api" && msg.content.indexOf(cmdName) !== -1 && playerIsGM(msg.playerid)) { var cleanedMsg = msg.content.replace(cmdName, ""); var commands = cleanedMsg.split(", "); var targetName = commands[0]; var i = 1; while ( i < commands.length ) { Teleporter.Teleport(commands[i], targetName); i = i + 1; } } }); var findContains = function(obj,layer){ "use strict"; var cx = obj.get('left')+(obj.get('width')/2), cy = obj.get('top')+(obj.get('height')/2); if(obj) { layer = layer || 'gmlayer'; return _.chain(findObjs({ _pageid: obj.get('pageid'), _type: "graphic", layer: layer })) .reduce(function(m,o){ if( o.get('left') <= cx && cx <= ( o.get('left') + o.get('width' ) ) && o.get('top') <= cy && cy <= ( o.get('top') + o.get('height') ) ){ m.push(o); } return m; },[]) .value(); } return []; }; 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; } CurrName = location[0].get("name"); var Letters = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L"]; //Number of doors in the cycle (second to last character) var doorCount = CurrName.substr(CurrName.length - 2, 1); //Current Letter of the Door var currDoor = CurrName.substr(CurrName.length - 1, 1); //Finds the pair location and moves target to that location var i = 0; if( CurrName.match(/^R:/) ) { i = randomInteger(doorCount)-1; } else { i = Letters.indexOf(currDoor); if (i === doorCount - 1) { i = 0; } else { i = i + 1; } } var NewName = CurrName.substr(0,CurrName.length - 2) + doorCount + Letters[i]; var NewX = 0; var NewY = 0; var newLocation = findObjs({ _pageid: Campaign().get("playerpageid"), _type: "graphic", layer: "gmlayer", //target location MUST be on GM layer name: NewName }); _.each(newLocation, function(Loc){ //Get the new Location NewX = Loc.get("left"); NewY = Loc.get("top"); }); if (NewX === 0 ) { return; } obj.set("left", NewX); obj.set("top", NewY); }); on("chat:message", function(msg) { "use strict"; if (msg.content.indexOf("!AUTOTELEPORTER") !== -1 && playerIsGM(msg.playerid)) { if ( Teleporter.AUTOTELEPORTER === true) { sendChat("System", "Autoteleporting Disabled."); Teleporter.AUTOTELEPORTER = false; } else { sendChat("System", "Autoteleporting Enabled."); Teleporter.AUTOTELEPORTER = true; } } });
Oh holy god...Ok. I should probably refer to the wiki on how to add scripts. Thanks!
1432362747
The Aaron
Roll20 Production Team
API Scripter
Click API Scripts on your Campaign Details page, paste that in a tab (give it a good name) and click save script. Introduction to the API: <a href="https://wiki.roll20.net/API:Introduction" rel="nofollow">https://wiki.roll20.net/API:Introduction</a>
The Aaron said: Click API Scripts on your Campaign Details page, paste that in a tab (give it a good name) and click save script. Introduction to the API: <a href="https://wiki.roll20.net/API:Introduction" rel="nofollow">https://wiki.roll20.net/API:Introduction</a> Alright, done and done! Now how do I impliment it into my campaign? Sorry, i'm reading as I post, so i'm not trying to be helpless, but this is all going way over my head.
1432363199
The Aaron
Roll20 Production Team
API Scripter
Create two tokens on the GM layer named "Teleport 1 2A" and "Teleport 1 2B". When a token on the Objects layer is moved on one, it will be moved to the other. Naming the teleporters is a bit strict, it must contain the word "Teleport" and end in a number from 2-9 and a letter from A-I. the numbers tell the script how many teleporters are in this set, and the letters set the order. so you could name them "Stairs 1 Teleport 2A" and "Stairs 1 Teleport 2B" and the like.
1432363221
The Aaron
Roll20 Production Team
API Scripter
Also, the teleporting only happens on the page the player ribbon is on.
So token on the GM overlay on the stairs (example), name it Teleport 1 2A token on the GM overlay on the OTHER stairs, name it Teleport 1 2B. Then when a player on the objects/tokens layer moves to said token, they're teleported?
Oh my god oh my god oh my god, it worked. That's awesome. Thank you so much! I'm so glad I support this site!
1432367101
The Aaron
Roll20 Production Team
API Scripter
:). Glad to hear you got it working! Be sure to browse the API forum for more goodies. :)
I tried using this script on a campaign in which I'm using John C.'s inventory manager script, and the two don't seem to play well together. Is there another teleport script that I could try? What I'm doing is creating a "loot" area at the bottom of the map, where players could send their chosen items to their inventory area without having to drag them across the (rather large) map. Any suggestions? EDIT: Posted this same question on a different thread in API: <a href="https://app.roll20.net/forum/post/1987947/help-inv" rel="nofollow">https://app.roll20.net/forum/post/1987947/help-inv</a>...
1433167563
The Aaron
Pro
API Scripter
I can jump in your campaign later tonight and try and figure it out. PM me a join (or link to the campaign if I'm already a member).
PM sent.
1433189809
Ziechael
Forum Champion
Sheet Author
API Scripter
Took a look earlier today, i think there must be some sort of conflict with the gm layer-object layer relationship as like Gozer said it forces graphics on those layers to act according to the inventory script (ie. the numbered dot for multiple items, name tags on show etc). I checked it against my test script which has teleports up and running fine and there was no discernible difference and the test teleports i put in to mirror my set up refused to work also... again with no error in the API console. Aaron, it's over to you =D
1433332782
The Aaron
Pro
API Scripter
I tracked down the teleport issue. It was related to the size of the landing pad and the math I put in the contains function (whoops!). I really should write that new teleport script at some point... Updated Teleport: /* ************ TELEPORTING SCRIPT ************************** * The intention of this script is to allow the DM to teleport * one or all characters to a location based on a token placed * on the DM layer of the map. * To activate the script, type "!Teleport " and add the name * of the teleport location (must not contrain spaces) and then * the name of the party member to teleport there. They must be * seperated by commas. If you want all to teleport, type all. * ie. !Teleport teleport01, all - teleports all players to teleport01 * * 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: * Two way doors: XXXXXXXX2A, XXXXXXXXX2B * Three way dooes: XXXXXXXX3A, XXXXXXXXX3B, XXXXXXXXX3C * (in the case of one way doors, dont create a 3C) * This system can handle up to 9 way doors (9I max). ****************************************************************/ var Teleporter = Teleporter || {}; Teleporter.AUTOTELEPORTER = true; //Set to true if you want teleports to be linked Teleporter.Teleport = function (CharName, TargetName) { "use strict"; var LocX = 0; var LocY = 0; //find the target location var location = findObjs({ _pageid: Campaign().get("playerpageid"), _type: "graphic", layer: "gmlayer", //target location MUST be on GM layer name: TargetName }); if (location.length === 0) { return; //exit if invalid target location } LocX = location[0].get("left"); LocY = location[0].get("top"); //if all are indicated, it lists all //finds all tokens with the name var targets = findObjs({ _pageid: Campaign().get("playerpageid"), _type: "graphic" }); //Move characters to target location _.each(targets, function(obj) { //Only player tokens if (CharName === "all") { if (obj.get("represents") !== "") { log("Setting all"); obj.set("left", LocX + 1); obj.set("top", LocY); } } else { if (obj.get("name").indexOf(CharName) !== -1) { if (obj.get("represents") !== "") { obj.set("left", LocX + 1); obj.set("top", LocY); } } } }); }; on("chat:message", function(msg) { "use strict"; var cmdName = "!Teleport "; if (msg.type === "api" && msg.content.indexOf(cmdName) !== -1 && playerIsGM(msg.playerid)) { var cleanedMsg = msg.content.replace(cmdName, ""); var commands = cleanedMsg.split(", "); var targetName = commands[0]; var i = 1; while ( i &lt; commands.length ) { Teleporter.Teleport(commands[i], targetName); i = i + 1; } } }); 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 &lt;= cx && cx &lt;= or && ot &lt;= cy && cy &lt;= ob ){ m.push(o); } return m; },[]) .value(); } return []; }; 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; } CurrName = location[0].get("name"); var Letters = ["A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L"]; //Number of doors in the cycle (second to last character) var doorCount = CurrName.substr(CurrName.length - 2, 1); //Current Letter of the Door var currDoor = CurrName.substr(CurrName.length - 1, 1); //Finds the pair location and moves target to that location var i = 0; if( CurrName.match(/^R:/) ) { i = randomInteger(doorCount)-1; } else { i = Letters.indexOf(currDoor); if (i === doorCount - 1) { i = 0; } else { i = i + 1; } } var NewName = CurrName.substr(0,CurrName.length - 2) + doorCount + Letters[i]; var NewX = 0; var NewY = 0; var newLocation = findObjs({ _pageid: Campaign().get("playerpageid"), _type: "graphic", layer: "gmlayer", //target location MUST be on GM layer name: NewName }); _.each(newLocation, function(Loc){ //Get the new Location NewX = Loc.get("left"); NewY = Loc.get("top"); }); if (NewX === 0 ) { return; } obj.set("left", NewX); obj.set("top", NewY); }); on("chat:message", function(msg) { "use strict"; if (msg.content.indexOf("!AUTOTELEPORTER") !== -1 && playerIsGM(msg.playerid)) { if ( Teleporter.AUTOTELEPORTER === true) { sendChat("System", "Autoteleporting Disabled."); Teleporter.AUTOTELEPORTER = false; } else { sendChat("System", "Autoteleporting Enabled."); Teleporter.AUTOTELEPORTER = true; } } });