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

Simple API Script for player switching maps

1586161251

Edited 1586558041
Hi, I wanted to make something simple to allow players to switch from one map to another. While I saw a few scripts that did just that, they had a bunch of features that wouldn't really work for my campaign.Their code was difficult to read and some required a bunch of dependencies. I managed to script my own from scratch and figured if anyone else comes looking to do the same, my less than 100 lines of code might be easier to read. I've also commented the code for someone relatively new to scripting, sorry if it's a bit much. Constructive criticism is always welcome, but keep in mind that I want to avoid bloat and so far I'm not running any other scripts. There's probably a whole bag of exceptions that the script can't handle, but we'll take that as it comes. If anyone finds this useful, let me know. /* The following script allows players to switch to various maps without the GM's interaction. While there are a few scripts out there that do this and more, they were quite complex with more options and tweaks. If you want to just pop in a script and have it work without needing to look under the hood, grab one of the other ones out there. On the otherhand, if you're looking to scripting something yourself and want a barebones script to edit or work off of this one might give you an easier time. */ /* This is the callback that waits for the right trigger before proceeding. For some reason the 'msg' object doesn't get passed on if a temporary function isn't defined in the callback. I defined the main function elsewhere for readability */ on('chat:message', function(msg){ if(msg.type === 'api' && msg.content.startsWith('!map')){ movePlayer(msg) } }) /* This is the main function */ function movePlayer(msg){ /*the "playerspecificpages" holds the information for when one player is on a different map than the player banner, in essence, modifying it and putting it back is the purpose of the script*/ let pageFile = Campaign().get('playerspecificpages') /*msg.playerid is a unique id for the player who sent the message*/ let playerID = msg.playerid let mapID let backToBanner /*If you want to quickly adapt my script, just add to or modify the cases below basically, it checks to see what map it needs to send the player to and assigns the right mapID. The toMapID function is defined further on*/ switch(msg.content){ case '!map map1': mapID = toMapID('map1') log('case 1') break case '!map map2': mapID = toMapID('map2') log('case 2') break /*This case will signal to throw the player back with the player banner*/ case '!map Return': backToBanner = true log('case 3') break /*Things shouldn't get this far without catching, but it might if you spell name of the destination map wrong*/ default: log('switch default error') log(msg.content) } /*This puts the player's id and destination map id together, based on the player sending the msg and the destination map sorted out in the switch above*/ if(pageFile === false){ pageFile = {playerID : mapID } } else { pageFile[playerID] = mapID } /*the "playerspecificpages" property comes out false if everyone is with the banner this verifies that if the player returns to the banner, the file won't be left empty at the same time, just setting the property to false might screw other players if they're also seperate*/ if(backToBanner === true && Object.keys(pageFile).length < 2){ pageFile = false } /*if the player returns to the banner, but he's not the only one to be seperate, this will simply remove him from the list*/ else if (backToBanner === true){ delete pageFile[playerID] } /*This is an important part, the "playerspecificpages" property won't properly update if it's not set to false first, and the maps won't update*/ Campaign().set('playerspecificpages', false) /*the whole purpose of the script leads to the following line which updates the Campaign's "playerspecificpages" property*/ Campaign().set('playerspecificpages', pageFile) } /*These are two simple functions that I refractored out of the main one, since I find it easier to use names rather than the clunky and unreadable "_id"s*/ function toMapID(name){ let mapID = findObjs({ type: 'page', name: name})[0].get('_id'); log('returning mapID: '+ mapID) return mapID } function toMapName(mapID){ let mapName = findObjs({ type: 'page', _id: mapID})[0].get('name'); log('returning mapName: '+ mapName) return mapName }
1586163809
GiGs
Pro
Sheet Author
API Scripter
That's a great idea. I'll check it out when i can, but it sounds useful to me.
1586184197
keithcurtis
Forum Champion
Marketplace Creator
API Scripter
As a low-level scripter, I appreciate the thorough commenting. Thanks!
1586185316
GiGs
Pro
Sheet Author
API Scripter
One drawback with this script is it looks like you have to define the maps yourself. Using an id-based approach, you can autogenerate the map list and dont need to configure that part. It;ll keep working if you delete maps or add new ones. You can also build a chat button that lets people choose which map to jump to (though you might not want to do that - maybe only show maps theyve actually visited before).
1586206052

Edited 1586219491
GiGs said: One drawback with this script is it looks like you have to define the maps yourself. Using an id-based approach, you can autogenerate the map list and dont need to configure that part. It;ll keep working if you delete maps or add new ones. You can also build a chat button that lets people choose which map to jump to (though you might not want to do that - maybe only show maps theyve actually visited before). That's the next step, but part of me posting this now was to get the basic code out before adding too much to it.
I've got some games going where such a feature would be very useful. Thanks for sharing.
1586234935

Edited 1586235352
As a note, I've fixed a few bugs. Notably, the previous script didn't work if at least one person isn't with the player banner. Also, if someone wants to have a little more flexibility for choosing which maps the players get pushed to, a simple function like this can search for a specifically named token hidden on the GM layer, and send players to that map. Just add the function and update the switch cases to use this rather than a static mapID or mapName. function findMap(marker){ let token = findObjs({ type: 'graphic', layer: 'gmlayer', name: marker })[0]; return token.get('_pageid') Example of a modified case to include the findMap() function case '!map map2': mapID = findMap('mySecondMap') break
I'm not familiar with programming language, so I freely admit I'm probably missing something obvious. I replaced "map1", "map2", etc. with the names of a few of my maps, like so: switch(msg.content){ case '!map Breachill': mapID = toMapID('Breachill') break case '!map Goblinblood Caves': mapID = toMapID('Goblinblood Caves') break All my players are currently on the same map, with the Player Ribbon. I asked one of them to type !map Breachill in chat. No visible change occurred, neither on his end nor mine. The API sandbox output the following, however: "returning mapID: -LotwxbJZEOijD16vPoz" Any idea what I'm doing wrong?
1586559377

Edited 1586560260
I'd have to see the whole script to compare with my current one, you can pm me if you don't want to add another wall of text to this discussion (I updated it again in my original post to avoid others in the future getting stuck on bugs I've fixed) That said, one of my previous bugs was something that made it so the script didn't work if at least one person wasn't split from the party. You can verify this by splitting yourself from the party and trying the buttons. It won't switch the map for a GM but it'll move the miniature portrait of you around as if you were on those pages separately from the other players. Also the console printing that out is normal. It could be removed, but it just shows the mapID of the map the player is being sent to.