Last active
March 31, 2018 23:22
-
-
Save goblinHordes/6894547 to your computer and use it in GitHub Desktop.
CommandDoors for Roll20 API
Use CommandTokens to toggle open/closed states for doors, including wall modification for dynamic lighting.
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
/* | |
CommandDoors | |
Use CommandTokens to toggle open/closed states for doors, including wall modification for dynamic lighting. | |
Requires: CommandTokens.js | |
Once configured, doors are easy to use - simply move the associated CommandToken to toggle the door from open | |
to closed and back again. Configuring the doors takes a bit of work, but there is a helper function to | |
make the process pretty easy. | |
Before configuring a door, first look at the components of a CommandDoor. A CommandDoor consists of three tokens | |
and an optional Polyline. The first token is a CommandToken that will be used to trigger the door toggle. The | |
other two tokens are the openDoor and closedDoor graphics for the door, and should be the same size as each other. | |
The optional Polyline path is used for blocking on the dynamic lighting layer. Toggling the door via the | |
ControlToken will cause the active door graphic to be shrunk, the new door graphic to be enlarged to its native | |
size, and the path to be switched beween 'wall' and 'gmlayers' depending if the door is closing or opening, | |
respectively. | |
The name of each of these tokens is very important. The CommandToken is configured to call the toggleDoor function | |
with two parameters, the door group ID and, optionally, the path ID. This follows the standard CommandToken naming | |
convention, please see CommandTokens.js for more details. The door images need to be named _door_open_X_ and | |
_door_closed_X_ where 'X' is a unique ID for that door group. Finally, the path doesn't need any special naming, | |
but its ID is used in the CommandToken. Here is an example of a complete door set by name/id: | |
openDoor: _door_open_01_ | |
closedDoor: _door_closed_01_ | |
path (id): -J5Glj9y-cipFNgrV141 | |
CommandToken: __toggleDoor_:01:-J5Glj9y-cipFNgrV141__ | |
Included in this script is a helper function for linking door sets. To use this script in quickly planning maps, I | |
maintain a page in my campaign with template sets. This way I am able to quickly copy and paste the templates then | |
link them into a new set. This makes door creation take only a few seconds. In order to link a door group you must | |
start with the three required tokens, but named in a specific way: | |
openDoor: _door_open_ | |
closedDoor: _door_closed_ | |
CommandToken: __toggleDoor_ | |
With those three tokens selected, use the !linkDoors API chat command to update their names and link them into a new | |
door set. You'll have to link the path manually, this is on purpose since the wall layer doesn't understand rotation. | |
By default, !linkDoors will search for the next incremental integer ID from the existing _door_open_X_ objects. | |
You can also pass an ID that you'd like to use. In macro form this can be very useful to prompt for an ID: | |
!linkDoors ?{Door ID} | |
*/ | |
on("ready", function() { | |
on("chat:message", function(msg){ | |
if(msg.type == "api" && (msgMatch = msg.content.match(/^!linkDoors(?:\s(.*))?$/))){ | |
if(linkSuccess = linkDoors(msg.selected, msgMatch[1])) { | |
//sendChat('API', "success!"); | |
} | |
} | |
}); | |
ctRegister("toggleDoor", function(opts){ | |
doorID = opts[0]; | |
pathID = opts[1]; | |
if(doorID==undefined) return; | |
doorObj = { | |
openDoor: findObjs({_type:'graphic', name:'_door_open_'+doorID+'_'})[0], | |
closedDoor: findObjs({_type:'graphic', name:'_door_closed_'+doorID+'_'})[0], | |
pathObj: getObj('path', pathID) | |
} | |
if(doorObj.openDoor == undefined || doorObj.closedDoor == undefined) return; | |
if(isDoorOpen(doorObj)){ | |
openDoorID(doorObj); | |
} else { | |
closeDoorID(doorObj); | |
} | |
return true; | |
}); | |
}); | |
function isDoorOpen(doorObj){ | |
if(parseFloat(doorObj.openDoor.get('width')) < 0.01){ | |
return true; | |
} else { | |
return false; | |
} | |
} | |
function closeDoorID(doorObj) { | |
if(parseFloat(doorObj.openDoor.get('width')) > 0.01){ | |
doorObj.openDoor.set('width', parseFloat(doorObj.openDoor.get('width'))*.00001); | |
doorObj.openDoor.set('height', parseFloat(doorObj.openDoor.get('height'))*.00001); | |
} | |
if(parseFloat(doorObj.closedDoor.get('width')) < 0.01){ | |
doorObj.closedDoor.set('width', parseFloat(doorObj.closedDoor.get('width'))*100000); | |
doorObj.closedDoor.set('height', parseFloat(doorObj.closedDoor.get('height'))*100000); | |
} | |
doorObj.closedDoor.set('rotation', doorObj.openDoor.get('rotation')); | |
doorObj.closedDoor.set('top', doorObj.openDoor.get('top')); | |
doorObj.closedDoor.set('left', doorObj.openDoor.get('left')); | |
if(doorObj.pathObj) doorObj.pathObj.set('layer', 'walls'); | |
} | |
function openDoorID(doorObj) { | |
if(parseFloat(doorObj.closedDoor.get('width')) > 0.01){ | |
doorObj.closedDoor.set('width', parseFloat(doorObj.closedDoor.get('width'))*.00001); | |
doorObj.closedDoor.set('height', parseFloat(doorObj.closedDoor.get('height'))*.00001); | |
} | |
if(parseFloat(doorObj.openDoor.get('width')) < 0.01){ | |
doorObj.openDoor.set('width', parseFloat(doorObj.openDoor.get('width'))*100000); | |
doorObj.openDoor.set('height', parseFloat(doorObj.openDoor.get('height'))*100000); | |
} | |
doorObj.openDoor.set('rotation', doorObj.closedDoor.get('rotation')); | |
doorObj.openDoor.set('top', doorObj.closedDoor.get('top')); | |
doorObj.openDoor.set('left', doorObj.closedDoor.get('left')); | |
if(doorObj.pathObj) doorObj.pathObj.set('layer', 'gmlayer'); | |
} | |
function linkDoors(objs, id) { | |
var doorOpen, doorClosed, doorCommandToken | |
_.each(objs, function(obj){ | |
doorObj = getObj(obj['_type'], obj['_id']) | |
switch(doorObj.get('name')){ | |
case "_door_open_": | |
doorOpen = doorObj; | |
break; | |
case "_door_closed_": | |
doorClosed = doorObj; | |
break; | |
case "__toggleDoor_": | |
doorCommandToken = doorObj; | |
break; | |
}; | |
}); | |
if(!(doorOpen && doorClosed && doorCommandToken)) return false; | |
if(id) | |
nextID = id; | |
else | |
nextID = nextDoorID(); | |
doorOpen.set('name', '_door_open_' + nextID + '_'); | |
doorClosed.set('name', '_door_closed_' + nextID + '_'); | |
doorCommandToken.set('name', '__toggleDoor_:' + nextID + '__'); | |
return true; | |
}; | |
function nextDoorID(){ | |
topID = -1; | |
doors = filterObjs(function(obj){ | |
name = obj.get('name'); | |
if(name && name.match(/^_door_open_\d+_$/)){ | |
return true; | |
} else return false; | |
}); | |
_.each(doors, function(door) { | |
doorID = parseInt(door.get('name').match(/^_door_open_(\d+)_$/)[1]); | |
if(doorID > topID) topID = doorID; | |
}); | |
topID++; | |
return (topID); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment