5 Commits

4 changed files with 61 additions and 17 deletions

3
CHANGELOG.md Normal file
View File

@@ -0,0 +1,3 @@
## v1.0.1
- When adding a door to a synchronization group adjust it's state to bring it in sync with the other doors
- Use the players character as speaker for the Locked Door Alert

View File

@@ -1,6 +1,30 @@
# Smart Doors # Smart Doors
Makes doors smarter. Allows doors to synchronize across multiple scenes and sends chat messages when players try to open locked doors (and also tells you which of the doors). Makes doors smarter. Allows doors to synchronize across multiple scenes and sends chat messages when players try to open locked doors (and also tells you which of the doors).
## Feature overview
### Locked door alerts
![Locked door alerts demonstration](https://raw.githubusercontent.com/manuelVo/foundryvtt-smart-doors/360d724240634dbc6cc493a3b62243a8b28b7056/media/locked_door_alert.webp)
Keep everyone informed who tried to open which door. Whenever a player tries to open a door that is locked, a chat message stating that fact will be sent to all players. Additionally the door locked sound will be played for everyone. When the chat message is hovered with the mouse, the door that the player tried to open will be highlighted.
If the GM tries to open a locked door the sound will only played for him and no chat message will be sent.
### Synchronized doors
![Synchronized doors demonstration](https://raw.githubusercontent.com/manuelVo/foundryvtt-smart-doors/360d724240634dbc6cc493a3b62243a8b28b7056/media/synchronized_doors.webp)
Keep multiple doors in sync - even across different scenes. Example use cases:
- A tavern has an outdoor and an indoor scene. If a player opens the entrance door on the outdoor map, the entrance door in the indoor map will be opened as well
- An ancient trap that opens the cell of a monster once the door to the treasury is opened.
#### Usage
To set up door synchronization, assign all doors that should be synchronized to the same Synchronization Group. The Synchronization Group can be any text. Doors that have the same Synchronization Group set will be synchronized. This will work across different scenes. At least two doors must be assigned to the same Synchronization Group. If only a single door is assigned to a synchronization group it will behave as any other normal door.
Once a Synchronization Group is set up for multiple doors, simply open/close/lock/unlock one of the doors to achieve the same effect on other doors as well.
## Planned features ## Planned features
- Attach macros to doors that are being executed when the door is being opened/closed - Attach macros to doors that are being executed when the door is being opened/closed
- Give out keys to players, that allow them to lock/unlock associated doors - Give out keys to players, that allow them to lock/unlock associated doors
- Doors that can only be seen from one side when closed
- Only allow doors to be opened of the character is near
- Doors that can only be opened from one side

46
main.js
View File

@@ -73,22 +73,25 @@ function hookWallConfigUpdate() {
// Store our custom data from the WallConfig dialog // Store our custom data from the WallConfig dialog
async function onWallConfigUpdate(event, formData) { async function onWallConfigUpdate(event, formData) {
// TODO Bring newly merged doors in sync
const updateData = {flags: {smartdoors: {synchronizationGroup: formData.synchronizationGroup}}} const updateData = {flags: {smartdoors: {synchronizationGroup: formData.synchronizationGroup}}}
let ids = this.options.editTargets;
if (ids.length == 0) {
ids = [this.object.data._id];
}
const ids = this.options.editTargets; // If a synchronization group is set, get the state of existing doors and assume their state
if (ids.length > 0) { if (formData.synchronizationGroup) {
// Multiple walls are edited at once. Update all of them const doorInGroup = findInAllWalls(wall => wall.door && wall.flags.smartdoors?.synchronizationGroup == formData.synchronizationGroup && !ids.includes(wall._id));
const updateDataset = ids.reduce((dataset, id) => { if (doorInGroup)
dataset.push({_id: id, ...updateData}) updateData.ds = doorInGroup.ds;
return dataset
}, [])
return canvas.scene.updateEmbeddedEntity("Wall", updateDataset)
}
else {
// Only one wall is being edited
return this.object.update(updateData);
} }
// Update all the edited walls
const updateDataset = ids.reduce((dataset, id) => {
dataset.push({_id: id, ...updateData})
return dataset
}, [])
return canvas.scene.updateEmbeddedEntity("Wall", updateDataset)
} }
// Hook mouse events on DoorControls to perform our logic. // Hook mouse events on DoorControls to perform our logic.
@@ -117,7 +120,18 @@ function hookDoorEvents() {
// Searches through all scenes for walls and returns those that match the given filter criteria. // Searches through all scenes for walls and returns those that match the given filter criteria.
function filterAllWalls(filterFn) { function filterAllWalls(filterFn) {
return game.scenes.map((scene) => {return {scene: scene, walls: scene.data.walls.filter(filterFn)}}); // Find all walls that match the filter criteria
const scenes = game.scenes.map((scene) => {return {scene: scene, walls: scene.data.walls.filter(filterFn)}})
// Drop all scenes that don't contain any results
return scenes.filter(scene => scene.walls.length > 0)
}
// Searches through all scenes for a wall that matches the given filter criteria
function findInAllWalls(filterFn) {
// TODO The performance of this could be increased by stopping the search on the first hit
const scenes = filterAllWalls(filterFn)
// If results were found take the first wall from the first scene.
return scenes[0]?.walls[0]
} }
// Our custom handler for mousedown events on doors // Our custom handler for mousedown events on doors
@@ -165,7 +179,9 @@ function lockedDoorAlertLeftClick() {
// Create and send the chat message // Create and send the chat message
const message = {} const message = {}
message.user = game.user; message.user = game.user
if (game.user.character)
message.speaker = {actor: game.user.character}
message.content = "Just tried to open a locked door" message.content = "Just tried to open a locked door"
message.sound = CONFIG.sounds.lock message.sound = CONFIG.sounds.lock
message.flags = {smartdoors: {sourceId: this.wall.data._id}} message.flags = {smartdoors: {sourceId: this.wall.data._id}}

View File

@@ -2,7 +2,7 @@
"name": "smart-doors", "name": "smart-doors",
"title": "Smart Doors", "title": "Smart Doors",
"description": "Makes doors smarter. Allows doors to synchronize across multiple scenes and sends chat messages when players try to open locked doors.", "description": "Makes doors smarter. Allows doors to synchronize across multiple scenes and sends chat messages when players try to open locked doors.",
"version": "1.0.0", "version": "1.0.1",
"minimumCoreVersion" : "0.7.7", "minimumCoreVersion" : "0.7.7",
"compatibleCoreVersion" : "0.7.8", "compatibleCoreVersion" : "0.7.8",
"author": "Manuel Vögele", "author": "Manuel Vögele",
@@ -18,7 +18,8 @@
], ],
"url": "https://github.com/manuelVo/foundryvtt-smart-doors", "url": "https://github.com/manuelVo/foundryvtt-smart-doors",
"manifest": "https://raw.githubusercontent.com/manuelVo/foundryvtt-smart-doors/master/module.json", "manifest": "https://raw.githubusercontent.com/manuelVo/foundryvtt-smart-doors/master/module.json",
"download": "https://github.com/manuelVo/foundryvtt-smart-doors/archive/v1.0.0.zip", "download": "https://github.com/manuelVo/foundryvtt-smart-doors/archive/v1.0.1.zip",
"readme": "https://github.com/manuelVo/foundryvtt-smart-doors/blob/master/README.md", "readme": "https://github.com/manuelVo/foundryvtt-smart-doors/blob/master/README.md",
"changelog": "https://github.com/manuelVo/foundryvtt-smart-doors/blob/master/CHANGELOG.md",
"bugs": "https://github.com/manuelVo/foundryvtt-smart-doors/issues" "bugs": "https://github.com/manuelVo/foundryvtt-smart-doors/issues"
} }