Compare commits
18 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 5cec10941a | |||
|
|
77f1048518 | ||
| 02ea8aeb93 | |||
| 59e2d0884f | |||
|
|
62c76e3d23 | ||
| 0fd9a7b71f | |||
| bc46a05f3c | |||
| e53a1b6a21 | |||
| 2ea4eb04cb | |||
|
|
04d85d818b | ||
| a0cdaff5db | |||
| 30272cfbf4 | |||
| 46581362fb | |||
| 993cc2b658 | |||
| 644f6795a6 | |||
| 31bc7c82e5 | |||
| 7fd6f1f9a9 | |||
|
|
d51c416ac2 |
4
.prettierrc
Normal file
4
.prettierrc
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
printWidth: 100
|
||||||
|
trailingComma: "all"
|
||||||
|
bracketSpacing: false
|
||||||
|
arrowParens: "avoid"
|
||||||
30
CHANGELOG.md
30
CHANGELOG.md
@@ -1,3 +1,33 @@
|
|||||||
|
## 1.4.1
|
||||||
|
### Translation
|
||||||
|
- Added portugese (Brazil) translation (thanks eunaumtenhoid!)
|
||||||
|
|
||||||
|
|
||||||
|
## 1.4.0
|
||||||
|
### Compatibility
|
||||||
|
- Smart Doors is now compatible with Foundry v10
|
||||||
|
|
||||||
|
### Translation
|
||||||
|
- Updated the english text for several UI items
|
||||||
|
- Updated the german translation (thanks Athemis!)
|
||||||
|
- Updated the french translation (thanks rectulo!)
|
||||||
|
|
||||||
|
|
||||||
|
## 1.3.3
|
||||||
|
### Bugfixes
|
||||||
|
- Fixed a bug that could cause some settings to not apply if multiple settings were changed at once
|
||||||
|
- Fixed a bug that caused the french translation to not work
|
||||||
|
|
||||||
|
|
||||||
|
## 1.3.2
|
||||||
|
### Bugfixes
|
||||||
|
- The message sent to chat when triggering a locke door alert can now be translated
|
||||||
|
|
||||||
|
### Translation
|
||||||
|
- Added japanese translation (thanks to touge)
|
||||||
|
- Added german translation
|
||||||
|
|
||||||
|
|
||||||
## 1.3.1
|
## 1.3.1
|
||||||
### Bugfixes
|
### Bugfixes
|
||||||
- The keybinding to toggle secret doors no longer supresses other keybindings that are assigned to the same key
|
- The keybinding to toggle secret doors no longer supresses other keybindings that are assigned to the same key
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ Keep everyone informed who tried to open which door. Whenever a player tries to
|
|||||||
If the GM tries to open a locked door the sound will only played for him and no chat message will be sent.
|
If the GM tries to open a locked door the sound will only played for him and no chat message will be sent.
|
||||||
|
|
||||||
### Tint Secret Doors
|
### Tint Secret Doors
|
||||||
This tints secret doors in a gay shade to make them easier to discern from regular doors when being zoomed further out.
|
This tints secret doors in a gray shade to make them easier to discern from regular doors when being zoomed further out.
|
||||||
|
|
||||||
|
|
||||||
### Synchronized Doors
|
### Synchronized Doors
|
||||||
|
|||||||
41
lang/de.json
Normal file
41
lang/de.json
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"smart-doors": {
|
||||||
|
"keybindings": {
|
||||||
|
"toggleSecretDoor": {
|
||||||
|
"name": "Geheimtüren umschalten",
|
||||||
|
"hint": "Solange diese Taste gedrückt ist, werden Türen beim Klicken zwischen normaler Tür und Geheimtür umgeschaltet."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"doorControlSizeFactor": {
|
||||||
|
"name": "Skalierungsfaktor des Türsymbols",
|
||||||
|
"hint": "Legt fest um welchen Faktor die Größe der Türsymbole hochskaliert werden sollen."
|
||||||
|
},
|
||||||
|
"highlightSecretDoors": {
|
||||||
|
"name": "Geheimtüren einfärben",
|
||||||
|
"hint": "Geheimtüren werden beim Spielleiter in einer anderen Farbe dargestellt, um sie einfacher von anderen Türen unterscheiden zu können."
|
||||||
|
},
|
||||||
|
"lockedDoorAlert": {
|
||||||
|
"name": "Alarm bei verschlossenen Türen",
|
||||||
|
"hint": "Wenn ein Spieler versucht eine verschlossene Tür zu öffnen, wird eine Nachricht im Chat angezeigt."
|
||||||
|
},
|
||||||
|
"synchronizedDoors": {
|
||||||
|
"name": "Synchronisierte Türen",
|
||||||
|
"hint": "Erlaubt es den Zustand mehrerer Türen zu synchronisieren."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ui": {
|
||||||
|
"lockedDoorAlert": "Hat versucht eine verschlossene Tür zu öffnen",
|
||||||
|
"messages": {
|
||||||
|
"migrating": "Aktualisiere Smart Doors zur Version {version}. Bitte schließe die Anwendung nicht.",
|
||||||
|
"migrationDone": "Smart Doors wurde erfolgreich auf die Version {version} aktualisiert.",
|
||||||
|
"unknownVersion": "Die Aktualisierung von Smart Doors ist mit folgendem Fehler fehlgeschlagen: unbekannte Version {version}. Bitte melde diesen Fehler im Bugtracker von Smart Doors. Um Datenverlust zu vermeiden, deaktiviere dieses Modul, bis dieser Fehler behoben ist."
|
||||||
|
},
|
||||||
|
"synchronizedDoors": {
|
||||||
|
"description": "Zustandsänderungen von Türen in der gleichen Synchronisationsgruppe werden szenenübergreifend synchronisiert. Lasse dieses Feld leer, wenn du diese Tür nicht synchronisieren möchtest.",
|
||||||
|
"groupName": "Synchronisationsgruppe",
|
||||||
|
"synchronizeSecretStatus": "Geheimtürstatus synchronisieren"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
15
lang/en.json
15
lang/en.json
@@ -1,34 +1,35 @@
|
|||||||
{
|
{
|
||||||
"smart-doors": {
|
"smart-doors": {
|
||||||
"keybindings": {
|
"keybindings": {
|
||||||
"toggleSecretDoor": {
|
"toggleSecretDoor": {
|
||||||
"name": "Toggle Secret Door",
|
"name": "Toggle Secret Door",
|
||||||
"hint": "While this key is being pressed, clicking on doors will cause the to toggle between normal and secret door"
|
"hint": "While this key is being pressed, clicking on doors will cause the to toggle between normal and secret door."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"doorControlSizeFactor": {
|
"doorControlSizeFactor": {
|
||||||
"name": "Door Control Size Factor",
|
"name": "Door Control Size Factor",
|
||||||
"hint": "Defines by which factor the size of the door control icons should be scaled up"
|
"hint": "Defines by which factor the size of the door control icons should be scaled up."
|
||||||
},
|
},
|
||||||
"highlightSecretDoors": {
|
"highlightSecretDoors": {
|
||||||
"name": "Tint Secret Doors",
|
"name": "Tint Secret Doors",
|
||||||
"hint": "Shade secret doors in a different color on the gm screen to differentiate them from normal doors"
|
"hint": "Shade secret doors in a different color on the GM screen to differentiate them from normal doors."
|
||||||
},
|
},
|
||||||
"lockedDoorAlert": {
|
"lockedDoorAlert": {
|
||||||
"name": "Locked Door Alert",
|
"name": "Locked Door Alert",
|
||||||
"hint": "Send a message in chat when a player tried to open a locked door"
|
"hint": "Send a message in chat when a player tried to open a locked door."
|
||||||
},
|
},
|
||||||
"synchronizedDoors": {
|
"synchronizedDoors": {
|
||||||
"name": "Synchronized Doors",
|
"name": "Synchronized Doors",
|
||||||
"hint": "Synchronize the state of configured doors"
|
"hint": "Synchronize the state of multiple doors."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"ui": {
|
"ui": {
|
||||||
|
"lockedDoorAlert": "Just tried to open a locked door",
|
||||||
"messages": {
|
"messages": {
|
||||||
"migrating": "Migrating Smart Doors to version {version}. Please don't close the application.",
|
"migrating": "Migrating Smart Doors to version {version}. Please don't close the application.",
|
||||||
"migrationDone": "Smart Doors successfully migrated to version {version}.",
|
"migrationDone": "Smart Doors successfully migrated to version {version}.",
|
||||||
"unknownVersion": "Smart Doors migration failed with the error: Unkown Version {version}. Please report this to the Smart Doors issue tracker. To prevent possible data loss don't use this plugin until this error is fixed."
|
"unknownVersion": "Smart Doors migration failed with the error: Unknown Version {version}. Please report this to the Smart Doors issue tracker. To prevent possible data loss don't use this plugin until this error is fixed."
|
||||||
},
|
},
|
||||||
"synchronizedDoors": {
|
"synchronizedDoors": {
|
||||||
"description": "State changes of doors in the same synchronization group will be synchronized across scenes. Leave blank to disable synchronization for this door.",
|
"description": "State changes of doors in the same synchronization group will be synchronized across scenes. Leave blank to disable synchronization for this door.",
|
||||||
|
|||||||
29
lang/fr.json
29
lang/fr.json
@@ -3,19 +3,39 @@
|
|||||||
"settings": {
|
"settings": {
|
||||||
"doorControlSizeFactor": {
|
"doorControlSizeFactor": {
|
||||||
"name": "Facteur de taille de commande de porte",
|
"name": "Facteur de taille de commande de porte",
|
||||||
"hint": "Définit par quel facteur la taille des icônes de contrôle de porte doit être agrandie"
|
"hint": "Définit par quel facteur la taille des icônes de contrôle de porte doit être mise à l'échelle."
|
||||||
},
|
},
|
||||||
"highlightSecretDoors": {
|
"highlightSecretDoors": {
|
||||||
"name": "Teinte des portes secrètes",
|
"name": "Teinte des portes secrètes",
|
||||||
"indice": "Ombragez les portes secrètes d'une couleur différente sur l'écran gm pour les différencier des portes normales"
|
"indice": "Ombragez les portes secrètes d'une couleur différente sur l'écran gm pour les différencier des portes normales",
|
||||||
|
"hint": "Ombre les portes secrètes en une couleur différent sur l'écran du MJ pour les différencier des portes normales."
|
||||||
},
|
},
|
||||||
"lockedDoorAlert": {
|
"lockedDoorAlert": {
|
||||||
"name": "Alerte de porte verrouillée",
|
"name": "Alerte de porte verrouillée",
|
||||||
"hint": "Envoyer un message dans le chat lorsqu'un joueur essaie d'ouvrir une porte verrouillée"
|
"hint": "Envoyer un message dans la conversation lorsqu'un joueur essaie d'ouvrir une porte verrouillée."
|
||||||
},
|
},
|
||||||
"synchronizedDoors": {
|
"synchronizedDoors": {
|
||||||
"name": "Portes synchronisées",
|
"name": "Portes synchronisées",
|
||||||
"hint": "Synchroniser l'état des portes configurées"
|
"hint": "Synchroniser l'état de plusieurs portes."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"keybindings": {
|
||||||
|
"toggleSecretDoor": {
|
||||||
|
"name": "Activer porte secrète",
|
||||||
|
"hint": "Lorsque cette clé est maintenue, cliquer sur les portes permettra de passer d'une porte normale à une porte secrète."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ui": {
|
||||||
|
"synchronizedDoors": {
|
||||||
|
"description": "Les changements d'état des portes dans le même groupe de synchronisation seront synchronisés à travers les scènes. Laisser vierge pour désactiver la synchronisation pour cette porte.",
|
||||||
|
"groupName": "Groupe de synchronisation",
|
||||||
|
"synchronizeSecretStatus": "Synchroniser le statut 'secret'"
|
||||||
|
},
|
||||||
|
"lockedDoorAlert": "vient d'essayer d'ouvrir une porte verrouillée",
|
||||||
|
"messages": {
|
||||||
|
"migrating": "Migre Smart doors à la version {version}. Ne pas fermer l'application.",
|
||||||
|
"migrationDone": "Smart doors a migré avec succès à la version {version}.",
|
||||||
|
"unknownVersion": "La migration de Smart doors est un échec avec l'erreur : version inconnue {version}. SVP, signalez cela dans le traqueur de problème de Smart doors. Pour prévenir de potentielles pertes de donnés, n'utilisez plus le plugin jusqu'à ce que cette erreur soit réparée."
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@@ -32,4 +52,3 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|||||||
40
lang/ja.json
Normal file
40
lang/ja.json
Normal file
@@ -0,0 +1,40 @@
|
|||||||
|
{
|
||||||
|
"smart-doors": {
|
||||||
|
"keybindings": {
|
||||||
|
"toggleSecretDoor": {
|
||||||
|
"name": "シークレット・ドア切替",
|
||||||
|
"hint": "このキーを押しながらドアをクリックすると、シークレット・ドアと通常のドアを切り替えます。"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"doorControlSizeFactor": {
|
||||||
|
"name": "扉アイコンの大きさ",
|
||||||
|
"hint": "扉アイコンをどの程度大きくスケールアップするか設定します。"
|
||||||
|
},
|
||||||
|
"highlightSecretDoors": {
|
||||||
|
"name": "シークレット・ドア色",
|
||||||
|
"hint": "シークレット・ドアに異なる色を重ねることで、GM側から視認しやすくなります。"
|
||||||
|
},
|
||||||
|
"lockedDoorAlert": {
|
||||||
|
"name": "ロック中通知",
|
||||||
|
"hint": "ロックされた扉を誰かが開けようとした時チャットに通知を表示します。"
|
||||||
|
},
|
||||||
|
"synchronizedDoors": {
|
||||||
|
"name": "扉の同期",
|
||||||
|
"hint": "設定した扉の状態を同期させます。"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ui": {
|
||||||
|
"messages": {
|
||||||
|
"migrating": "Smart Doorsをバージョン{version}。にマイグレーションしています。FVTTを終了しないでください。",
|
||||||
|
"migrationDone": "Smart Doorsバージョン{version}のマイグレーションに成功しました。",
|
||||||
|
"unknownVersion": "Smart Doorsのマイグレーションに失敗しました。エラー:不明なバージョン{version}。Smart Doorsのissue trackerに報告していただくか、オンセ工房のDiscordサーバまでご報告ください。データの損失が起こりうる可能性がありますので、このエラーが解消されるまで使用しないでください。"
|
||||||
|
},
|
||||||
|
"synchronizedDoors": {
|
||||||
|
"description": "同じ同期グループにいる扉はシーンをまたいで状態が同期されます。空の場合はこの扉の同期を無効化します。",
|
||||||
|
"groupName": "同期グループ名",
|
||||||
|
"synchronizeSecretStatus": "シークレット状態同期"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
41
lang/pt-BR.json
Normal file
41
lang/pt-BR.json
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"smart-doors": {
|
||||||
|
"keybindings": {
|
||||||
|
"toggleSecretDoor": {
|
||||||
|
"name": "Alternar porta secreta",
|
||||||
|
"hint": "Enquanto esta tecla estiver sendo pressionada, clicar nas portas fará com que ela alterne entre a porta normal e a secreta."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"doorControlSizeFactor": {
|
||||||
|
"name": "Fator de tamanho de controle de porta",
|
||||||
|
"hint": "Define por qual fator o tamanho dos ícones de controle de porta deve ser ampliado."
|
||||||
|
},
|
||||||
|
"highlightSecretDoors": {
|
||||||
|
"name": "Tinta portas secretas",
|
||||||
|
"hint": "Sombreie as portas secretas com uma cor diferente na tela do GM para diferenciá-las das portas normais."
|
||||||
|
},
|
||||||
|
"lockedDoorAlert": {
|
||||||
|
"name": "Alerta de porta trancada",
|
||||||
|
"hint": "Envie uma mensagem no chat quando um jogador tentar abrir uma porta trancada."
|
||||||
|
},
|
||||||
|
"synchronizedDoors": {
|
||||||
|
"name": "Portas sincronizadas",
|
||||||
|
"hint": "Sincronize o estado de várias portas."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"ui": {
|
||||||
|
"lockedDoorAlert": "Apenas tentei abrir uma porta trancada",
|
||||||
|
"messages": {
|
||||||
|
"migrating": "Migrando Smart Doors para a versão {version}. Por favor, não feche o aplicativo.",
|
||||||
|
"migrationDone": "O Smart Doors migrou com sucesso para a versão {version}.",
|
||||||
|
"unknownVersion": "A migração do Smart Doors falhou com o erro: Unknown Version {version}. Informe isso ao rastreador de problemas do Smart Doors. Para evitar uma possível perda de dados, não use este plugin até que este erro seja corrigido."
|
||||||
|
},
|
||||||
|
"synchronizedDoors": {
|
||||||
|
"description": "As mudanças de estado das portas no mesmo grupo de sincronização serão sincronizadas nas cenas. Deixe em branco para desabilitar a sincronização para esta porta.",
|
||||||
|
"groupName": "Grupo de Sincronização",
|
||||||
|
"synchronizeSecretStatus": "Sincronizar status secreto"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
27
module.json
27
module.json
@@ -1,10 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "smart-doors",
|
"id": "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.3.1",
|
"version": "1.4.1",
|
||||||
"minimumCoreVersion" : "9.238",
|
"compatibility": {
|
||||||
"compatibleCoreVersion" : "9",
|
"minimum": 10,
|
||||||
|
"verified": 10
|
||||||
|
},
|
||||||
"authors": [
|
"authors": [
|
||||||
{
|
{
|
||||||
"name": "Manuel Vögele",
|
"name": "Manuel Vögele",
|
||||||
@@ -17,6 +19,11 @@
|
|||||||
"src/main.js"
|
"src/main.js"
|
||||||
],
|
],
|
||||||
"languages": [
|
"languages": [
|
||||||
|
{
|
||||||
|
"lang": "de",
|
||||||
|
"name": "Deutsch",
|
||||||
|
"path": "lang/de.json"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"lang": "en",
|
"lang": "en",
|
||||||
"name": "English",
|
"name": "English",
|
||||||
@@ -26,11 +33,21 @@
|
|||||||
"lang": "fr",
|
"lang": "fr",
|
||||||
"name": "Français",
|
"name": "Français",
|
||||||
"path": "lang/fr.json"
|
"path": "lang/fr.json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lang": "ja",
|
||||||
|
"name": "日本語",
|
||||||
|
"path": "lang/ja.json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lang": "pt-BR",
|
||||||
|
"name": "Português (Brasil)",
|
||||||
|
"path": "lang/pt-BR.json"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"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.3.1.zip",
|
"download": "https://github.com/manuelVo/foundryvtt-smart-doors/archive/v1.4.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",
|
"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",
|
||||||
|
|||||||
@@ -1,37 +1,66 @@
|
|||||||
import { libWrapper } from "../../lib/libwrapper_shim.js"
|
import {libWrapper} from "../../lib/libwrapper_shim.js";
|
||||||
import {settingsKey} from "../settings.js"
|
import {settingsKey} from "../settings.js";
|
||||||
|
|
||||||
// Adjust the repositioning formula for the door controls
|
// Adjust the repositioning formula for the door controls
|
||||||
export function hookDoorControlReposition() {
|
export function hookDoorControlReposition() {
|
||||||
libWrapper.register("smart-doors", "DoorControl.prototype.reposition", function () {
|
libWrapper.register(
|
||||||
let gridSize = this.wall.scene.data.grid
|
"smart-doors",
|
||||||
gridSize *= game.settings.get(settingsKey, "doorControlSizeFactor")
|
"DoorControl.prototype.reposition",
|
||||||
const pos = this.wall.midpoint.map(p => p - gridSize * 0.2)
|
function () {
|
||||||
this.position.set(...pos)
|
let gridSize = this.wall.scene.grid.size;
|
||||||
}, "OVERRIDE");
|
gridSize *= game.settings.get(settingsKey, "doorControlSizeFactor");
|
||||||
|
const pos = this.wall.midpoint.map(p => p - gridSize * 0.2);
|
||||||
|
this.position.set(...pos);
|
||||||
|
},
|
||||||
|
"OVERRIDE",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the size of all door controls in relation to the grid size so it'll have a constant percieved size
|
// Set the size of all door controls in relation to the grid size so it'll have a constant percieved size
|
||||||
export function onCanvasReady(currentCanvas) {
|
export function onCanvasReady(currentCanvas) {
|
||||||
const doors = currentCanvas.controls.doors.children
|
const doors = currentCanvas.controls.doors.children;
|
||||||
doors.forEach(control => fixDoorControlSize(control))
|
doors.forEach(control => fixDoorControlSize(control));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the size of the door control in relation to the grid size so it'll have a constant percieved size
|
// Set the size of the door control in relation to the grid size so it'll have a constant percieved size
|
||||||
export function onDoorControlPostDraw() {
|
export function onDoorControlPostDraw() {
|
||||||
// If the canvas isn't ready we'll do this after the "canvasReady" event is fired instead
|
// If the canvas isn't ready we'll do this after the "canvasReady" event is fired instead
|
||||||
if (!canvas.ready)
|
if (!canvas.ready) return;
|
||||||
return
|
|
||||||
|
|
||||||
fixDoorControlSize(this)
|
fixDoorControlSize(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Resizes the door control according to the grid size
|
// Resizes the door control according to the grid size
|
||||||
function fixDoorControlSize(control) {
|
function fixDoorControlSize(control) {
|
||||||
let gridSize = control.wall.scene.data.grid
|
let gridSize = control.wall.scene.grid.size;
|
||||||
gridSize *= game.settings.get(settingsKey, "doorControlSizeFactor")
|
gridSize *= game.settings.get(settingsKey, "doorControlSizeFactor");
|
||||||
control.icon.width = control.icon.height = gridSize * 0.4
|
control.icon.width = control.icon.height = gridSize * 0.4;
|
||||||
control.hitArea = new PIXI.Rectangle(gridSize * -0.02, gridSize * -0.02, gridSize * 0.44, gridSize * 0.44);
|
control.hitArea = new PIXI.Rectangle(
|
||||||
control.border.clear().lineStyle(1, 0xFF5500, 0.8).drawRoundedRect(gridSize * -0.02, gridSize * -0.02, gridSize * 0.44, gridSize * 0.44, gridSize * 0.05).endFill();
|
gridSize * -0.02,
|
||||||
control.bg.clear().beginFill(0x000000, 1.0).drawRoundedRect(gridSize * -0.02, gridSize * -0.02, gridSize * 0.44, gridSize * 0.44, gridSize * 0.05).endFill();
|
gridSize * -0.02,
|
||||||
|
gridSize * 0.44,
|
||||||
|
gridSize * 0.44,
|
||||||
|
);
|
||||||
|
control.border
|
||||||
|
.clear()
|
||||||
|
.lineStyle(1, 0xff5500, 0.8)
|
||||||
|
.drawRoundedRect(
|
||||||
|
gridSize * -0.02,
|
||||||
|
gridSize * -0.02,
|
||||||
|
gridSize * 0.44,
|
||||||
|
gridSize * 0.44,
|
||||||
|
gridSize * 0.05,
|
||||||
|
)
|
||||||
|
.endFill();
|
||||||
|
control.bg
|
||||||
|
.clear()
|
||||||
|
.beginFill(0x000000, 1.0)
|
||||||
|
.drawRoundedRect(
|
||||||
|
gridSize * -0.02,
|
||||||
|
gridSize * -0.02,
|
||||||
|
gridSize * 0.44,
|
||||||
|
gridSize * 0.44,
|
||||||
|
gridSize * 0.05,
|
||||||
|
)
|
||||||
|
.endFill();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,34 +1,35 @@
|
|||||||
import {settingsKey} from "../settings.js"
|
import {settingsKey} from "../settings.js";
|
||||||
|
|
||||||
const SECRET_DOOR_TINT = 0x888888
|
const SECRET_DOOR_TINT = 0x888888;
|
||||||
|
|
||||||
// Tint all secret doors dark grey
|
// Tint all secret doors dark grey
|
||||||
export function onCanvasReady(currentCanvas) {
|
export function onCanvasReady(currentCanvas) {
|
||||||
if (game.settings.get(settingsKey, "highlightSecretDoors")) {
|
if (game.settings.get(settingsKey, "highlightSecretDoors")) {
|
||||||
const types = CONST.WALL_DOOR_TYPES
|
const types = CONST.WALL_DOOR_TYPES;
|
||||||
const secretDoors = canvas.controls.doors.children.filter(control => control.wall.data.door == types.SECRET)
|
const secretDoors = canvas.controls.doors.children.filter(
|
||||||
secretDoors.forEach(control => control.icon.tint = SECRET_DOOR_TINT)
|
control => control.wall.door == types.SECRET,
|
||||||
|
);
|
||||||
|
secretDoors.forEach(control => (control.icon.tint = SECRET_DOOR_TINT));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If door type has been changed, tint the door accordingly
|
// If door type has been changed, tint the door accordingly
|
||||||
export function onUpdateWall(scene, wall, update) {
|
export function onUpdateWall(wall, update, options) {
|
||||||
if (!game.settings.get(settingsKey, "highlightSecretDoors"))
|
if (!game.settings.get(settingsKey, "highlightSecretDoors")) return;
|
||||||
return
|
const types = CONST.WALL_DOOR_TYPES;
|
||||||
const types = CONST.WALL_DOOR_TYPES
|
if (wall.door === types.NONE) return;
|
||||||
if (wall.door === types.NONE)
|
|
||||||
return
|
|
||||||
// Find the door control corresponding to the changed door
|
// Find the door control corresponding to the changed door
|
||||||
const changedDoor = canvas.controls.doors.children.find(control => control.wall.data._id === wall._id);
|
const changedDoor = canvas.controls.doors.children.find(control => control.wall.id === wall.id);
|
||||||
// If the changed door doesn't have a control it's not on this scene - ignore it
|
// If the changed door doesn't have a control it's not on this scene - ignore it
|
||||||
if (!changedDoor)
|
if (!changedDoor) return;
|
||||||
return
|
|
||||||
// The wall object we got passed might be from another scene so we replace it with the door from the current scene
|
// The wall object we got passed might be from another scene so we replace it with the door from the current scene
|
||||||
wall = changedDoor.wall.data
|
wall = changedDoor.wall;
|
||||||
if (wall.door === types.DOOR)
|
if (wall.document.door === types.DOOR) changedDoor.icon.tint = 0xffffff;
|
||||||
changedDoor.icon.tint = 0xFFFFFF
|
else if (wall.document.door === types.SECRET) changedDoor.icon.tint = SECRET_DOOR_TINT;
|
||||||
else if (wall.door === types.SECRET)
|
|
||||||
changedDoor.icon.tint = SECRET_DOOR_TINT
|
|
||||||
else
|
else
|
||||||
console.warn("Smart Doors | Encountered unknown door type " + wall.door + " while highlighting secret doors.")
|
console.warn(
|
||||||
|
"Smart Doors | Encountered unknown door type " +
|
||||||
|
wall.door +
|
||||||
|
" while highlighting secret doors.",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,54 +1,54 @@
|
|||||||
import {settingsKey} from "../settings.js"
|
import {settingsKey} from "../settings.js";
|
||||||
|
|
||||||
// Tint the source door red when a locked alert is hovered
|
// Tint the source door red when a locked alert is hovered
|
||||||
export function onRenderChatMessage(message, html, data) {
|
export function onRenderChatMessage(message, html, data) {
|
||||||
// Tint the door that generated this message
|
// Tint the door that generated this message
|
||||||
const source = message.data.flags.smartdoors?.source
|
const source = message.flags.smartdoors?.source;
|
||||||
if (!source)
|
if (!source) return;
|
||||||
return
|
|
||||||
|
|
||||||
// Tint on mouse enter
|
// Tint on mouse enter
|
||||||
const mouseEnter = function () {
|
const mouseEnter = function () {
|
||||||
const sourceDoor = canvas.controls.doors.children.find(door => door.wall.id === source.wall && door.wall.scene.id === source.scene);
|
const sourceDoor = canvas.controls.doors.children.find(
|
||||||
if (sourceDoor)
|
door => door.wall.id === source.wall && door.wall.scene.id === source.scene,
|
||||||
sourceDoor.icon.tint = 0xff0000;
|
);
|
||||||
}
|
if (sourceDoor) sourceDoor.icon.tint = 0xff0000;
|
||||||
|
};
|
||||||
html.on("mouseenter", mouseEnter);
|
html.on("mouseenter", mouseEnter);
|
||||||
|
|
||||||
// Remove tint on mouse leave
|
// Remove tint on mouse leave
|
||||||
const mouseLeave = function () {
|
const mouseLeave = function () {
|
||||||
const sourceDoor = canvas.controls.doors.children.find(door => door.wall.id === source.wall && door.wall.scene.id === source.scene);
|
const sourceDoor = canvas.controls.doors.children.find(
|
||||||
if (sourceDoor)
|
door => door.wall.id === source.wall && door.wall.scene.id === source.scene,
|
||||||
sourceDoor.icon.tint = 0xffffff;
|
);
|
||||||
}
|
if (sourceDoor) sourceDoor.icon.tint = 0xffffff;
|
||||||
|
};
|
||||||
html.on("mouseleave", mouseLeave);
|
html.on("mouseleave", mouseLeave);
|
||||||
|
|
||||||
|
// Localize the message
|
||||||
|
html.find(".message-content")[0].innerText = game.i18n.localize("smart-doors.ui.lockedDoorAlert");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Creates a chat message stating that a player tried to open a locked door
|
// Creates a chat message stating that a player tried to open a locked door
|
||||||
export function onDoorLeftClick() {
|
export function onDoorLeftClick() {
|
||||||
// Check if this feature is enabled
|
// Check if this feature is enabled
|
||||||
if (!game.settings.get(settingsKey, "lockedDoorAlert"))
|
if (!game.settings.get(settingsKey, "lockedDoorAlert")) return false;
|
||||||
return false
|
|
||||||
|
|
||||||
const state = this.wall.data.ds
|
const state = this.wall.document.ds;
|
||||||
const states = CONST.WALL_DOOR_STATES
|
const states = CONST.WALL_DOOR_STATES;
|
||||||
|
|
||||||
// Only create messages when the door is locked.
|
// Only create messages when the door is locked.
|
||||||
if (state !== states.LOCKED)
|
if (state !== states.LOCKED) return false;
|
||||||
return false
|
|
||||||
|
|
||||||
// Generate no message if the gm attempts to open the door
|
// Generate no message if the gm attempts to open the door
|
||||||
if (game.user.isGM)
|
if (game.user.isGM) return false;
|
||||||
return false
|
|
||||||
|
|
||||||
// Create and send the chat message
|
// Create and send the chat message
|
||||||
const message = {}
|
const message = {};
|
||||||
message.user = game.user.id;
|
message.user = game.user.id;
|
||||||
if (game.user.character)
|
if (game.user.character) message.speaker = {actor: game.user.character};
|
||||||
message.speaker = {actor: game.user.character}
|
message.content = game.i18n.localize("smart-doors.ui.lockedDoorAlert");
|
||||||
message.content = "Just tried to open a locked door"
|
message.sound = CONFIG.sounds.lock;
|
||||||
message.sound = CONFIG.sounds.lock
|
message.flags = {smartdoors: {source: {wall: this.wall.id, scene: this.wall.scene.id}}};
|
||||||
message.flags = {smartdoors: {source: {wall: this.wall.data._id, scene: this.wall.scene.id}}}
|
ChatMessage.create(message);
|
||||||
ChatMessage.create(message)
|
return true;
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,31 +1,35 @@
|
|||||||
import {settingsKey} from "../settings.js"
|
import {settingsKey} from "../settings.js";
|
||||||
import * as Util from "../util.js"
|
import * as Util from "../util.js";
|
||||||
|
|
||||||
// Inject settings for synchronized doors
|
// Inject settings for synchronized doors
|
||||||
export function onRederWallConfig(wallConfig, html, data) {
|
export function onRederWallConfig(wallConfig, html, data) {
|
||||||
if (game.settings.get(settingsKey, "synchronizedDoors") && data.isDoor) {
|
if (game.settings.get(settingsKey, "synchronizedDoors") && data.data.door) {
|
||||||
// Inject settings
|
// Inject settings
|
||||||
const synchronizedSettings = `
|
const synchronizedSettings = `
|
||||||
<p class="notes">${game.i18n.localize("smart-doors.ui.synchronizedDoors.description")}</p>
|
<p class="notes">${game.i18n.localize("smart-doors.ui.synchronizedDoors.description")}</p>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="synchronizationGroup">${game.i18n.localize("smart-doors.ui.synchronizedDoors.groupName")}</label>
|
<label for="synchronizationGroup">${game.i18n.localize(
|
||||||
|
"smart-doors.ui.synchronizedDoors.groupName",
|
||||||
|
)}</label>
|
||||||
<input type="text" name="synchronizationGroup"/>
|
<input type="text" name="synchronizationGroup"/>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="synchronizeSecretStatus">${game.i18n.localize("smart-doors.ui.synchronizedDoors.synchronizeSecretStatus")}</label>
|
<label for="synchronizeSecretStatus">${game.i18n.localize(
|
||||||
|
"smart-doors.ui.synchronizedDoors.synchronizeSecretStatus",
|
||||||
|
)}</label>
|
||||||
<input type="checkbox" name="synchronizeSecretStatus" value="true"/>
|
<input type="checkbox" name="synchronizeSecretStatus" value="true"/>
|
||||||
</div>
|
</div>
|
||||||
`
|
`;
|
||||||
html.find(".form-group").last().after(synchronizedSettings)
|
html.find(".form-group").last().after(synchronizedSettings);
|
||||||
|
|
||||||
const smartdoorsData = data.object.flags.smartdoors
|
const smartdoorsData = data.object.flags.smartdoors;
|
||||||
// Fill the injected input fields with values
|
// Fill the injected input fields with values
|
||||||
const input = (name) => html.find(`input[name="${name}"]`); // input is a helper function to search for a input field by it's name
|
const input = name => html.find(`input[name="${name}"]`); // input is a helper function to search for a input field by it's name
|
||||||
input("synchronizationGroup").prop("value", smartdoorsData?.synchronizationGroup)
|
input("synchronizationGroup").prop("value", smartdoorsData?.synchronizationGroup);
|
||||||
input("synchronizeSecretStatus").prop("checked", smartdoorsData?.synchronizeSecretStatus);
|
input("synchronizeSecretStatus").prop("checked", smartdoorsData?.synchronizeSecretStatus);
|
||||||
|
|
||||||
// Recalculate config window height
|
// Recalculate config window height
|
||||||
wallConfig.setPosition({height: "auto"})
|
wallConfig.setPosition({height: "auto"});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -46,29 +50,29 @@ export async function onWallConfigUpdate(event, formData) {
|
|||||||
// Search for other doors in the synchronization group that aren't in the list of edited doors
|
// Search for other doors in the synchronization group that aren't in the list of edited doors
|
||||||
const doorInGroup = Util.findInAllWalls(wall => {
|
const doorInGroup = Util.findInAllWalls(wall => {
|
||||||
// We only search for doors
|
// We only search for doors
|
||||||
if (!wall.data.door)
|
if (!wall.door) return false;
|
||||||
return false
|
|
||||||
// We only want doors in the same synchronization group
|
// We only want doors in the same synchronization group
|
||||||
if (wall.data.flags.smartdoors?.synchronizationGroup !== formData.synchronizationGroup)
|
if (wall.flags.smartdoors?.synchronizationGroup !== formData.synchronizationGroup)
|
||||||
return false
|
return false;
|
||||||
// Doors on this scene that have their id included in `ids` are currently being changed. Ignore them.
|
// Doors on this scene that have their id included in `ids` are currently being changed. Ignore them.
|
||||||
if (wall.parent.id === canvas.scene.id && ids.includes(wall.id))
|
if (wall.parent.id === canvas.scene.id && ids.includes(wall.id)) return false;
|
||||||
return false
|
return true;
|
||||||
return true
|
});
|
||||||
})
|
|
||||||
if (doorInGroup) {
|
if (doorInGroup) {
|
||||||
// ds is the door sate in foundry
|
// ds is the door sate in foundry
|
||||||
updateData.ds = doorInGroup.data.ds;
|
updateData.ds = doorInGroup.ds;
|
||||||
|
|
||||||
if (synchronizeSecretStatus) {
|
if (synchronizeSecretStatus) {
|
||||||
// door is the door type in foundry
|
// door is the door type in foundry
|
||||||
updateData.door = doorInGroup.data.door;
|
updateData.door = doorInGroup.door;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update all the edited walls
|
// Update all the edited walls
|
||||||
const updateDataset = ids.map(id => {return {_id: id, ...updateData}});
|
const updateDataset = ids.map(id => {
|
||||||
|
return {_id: id, ...updateData};
|
||||||
|
});
|
||||||
const updateResult = await canvas.scene.updateEmbeddedDocuments("Wall", updateDataset);
|
const updateResult = await canvas.scene.updateEmbeddedDocuments("Wall", updateDataset);
|
||||||
|
|
||||||
// If door is synchronized, synchronize secret status among synchronized doors
|
// If door is synchronized, synchronize secret status among synchronized doors
|
||||||
@@ -80,70 +84,74 @@ export async function onWallConfigUpdate(event, formData) {
|
|||||||
|
|
||||||
// Update the state of all synchronized doors
|
// Update the state of all synchronized doors
|
||||||
export function onDoorLeftClick() {
|
export function onDoorLeftClick() {
|
||||||
const state = this.wall.data.ds
|
const state = this.wall.document.ds;
|
||||||
const states = CONST.WALL_DOOR_STATES
|
const states = CONST.WALL_DOOR_STATES;
|
||||||
|
|
||||||
// Check if this feature is enabled
|
// Check if this feature is enabled
|
||||||
if (!game.settings.get(settingsKey, "synchronizedDoors"))
|
if (!game.settings.get(settingsKey, "synchronizedDoors")) return false;
|
||||||
return false
|
|
||||||
|
|
||||||
const synchronizationGroup = this.wall.data.flags.smartdoors?.synchronizationGroup
|
const synchronizationGroup = this.wall.document.flags.smartdoors?.synchronizationGroup;
|
||||||
|
|
||||||
// Does this door have a synchronization group? If not there is nothing to do
|
// Does this door have a synchronization group? If not there is nothing to do
|
||||||
if (!synchronizationGroup)
|
if (!synchronizationGroup) return false;
|
||||||
return false
|
|
||||||
|
|
||||||
// If the door is locked there is nothing to synchronize
|
// If the door is locked there is nothing to synchronize
|
||||||
if (state === states.LOCKED)
|
if (state === states.LOCKED) return false;
|
||||||
return false
|
|
||||||
|
|
||||||
// Calculate new door state
|
// Calculate new door state
|
||||||
const newstate = state === states.CLOSED ? states.OPEN : states.CLOSED
|
const newstate = state === states.CLOSED ? states.OPEN : states.CLOSED;
|
||||||
|
|
||||||
// Update all doors belonging to the synchronization group
|
// Update all doors belonging to the synchronization group
|
||||||
const updateData = {ds: newstate}
|
const updateData = {ds: newstate};
|
||||||
updateSynchronizedDoors(updateData, synchronizationGroup)
|
updateSynchronizedDoors(updateData, synchronizationGroup);
|
||||||
|
|
||||||
return true
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function onDoorRightClick() {
|
export function onDoorRightClick() {
|
||||||
const state = this.wall.data.ds
|
const state = this.wall.document.ds;
|
||||||
const states = CONST.WALL_DOOR_STATES
|
const states = CONST.WALL_DOOR_STATES;
|
||||||
|
|
||||||
// Check if this feature is enabled
|
// Check if this feature is enabled
|
||||||
if (!game.settings.get(settingsKey, "synchronizedDoors"))
|
if (!game.settings.get(settingsKey, "synchronizedDoors")) return false;
|
||||||
return false
|
|
||||||
|
|
||||||
const synchronizationGroup = this.wall.data.flags.smartdoors?.synchronizationGroup
|
const synchronizationGroup = this.wall.document.flags.smartdoors?.synchronizationGroup;
|
||||||
|
|
||||||
// Does this door have a synchronization group? If not there is nothing to do
|
// Does this door have a synchronization group? If not there is nothing to do
|
||||||
if (!synchronizationGroup)
|
if (!synchronizationGroup) return false;
|
||||||
return false
|
|
||||||
|
|
||||||
// Only the gm is allowed to lock/unlock doors
|
// Only the gm is allowed to lock/unlock doors
|
||||||
if ( !game.user.isGM )
|
if (!game.user.isGM) return false;
|
||||||
return false;
|
|
||||||
|
|
||||||
// If the door is currently opened we cannot lock the door
|
// If the door is currently opened we cannot lock the door
|
||||||
if ( state === states.OPEN )
|
if (state === states.OPEN) return false;
|
||||||
return false;
|
|
||||||
|
|
||||||
// Calculate new door state
|
// Calculate new door state
|
||||||
const newstate = state === states.LOCKED ? states.CLOSED : states.LOCKED;
|
const newstate = state === states.LOCKED ? states.CLOSED : states.LOCKED;
|
||||||
|
|
||||||
// Update all doors belonging to the synchronization group
|
// Update all doors belonging to the synchronization group
|
||||||
const updateData = {ds: newstate}
|
const updateData = {ds: newstate};
|
||||||
updateSynchronizedDoors(updateData, synchronizationGroup)
|
updateSynchronizedDoors(updateData, synchronizationGroup);
|
||||||
|
|
||||||
return true
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Updates all doors in the specified synchronization group with the provided data
|
// Updates all doors in the specified synchronization group with the provided data
|
||||||
export function updateSynchronizedDoors(updateData, synchronizationGroup) {
|
export function updateSynchronizedDoors(updateData, synchronizationGroup) {
|
||||||
// Search for doors belonging to the synchronization group in all scenes
|
// Search for doors belonging to the synchronization group in all scenes
|
||||||
let scenes = Util.filterAllWalls(wall => wall.data.door && wall.data.flags.smartdoors?.synchronizationGroup === synchronizationGroup);
|
let scenes = Util.filterAllWalls(
|
||||||
|
wall => wall.door && wall.flags.smartdoors?.synchronizationGroup === synchronizationGroup,
|
||||||
|
);
|
||||||
|
|
||||||
// Update all doors in the synchronization group
|
// Update all doors in the synchronization group
|
||||||
return Promise.all(scenes.map(scene => scene.scene.updateEmbeddedDocuments("Wall", scene.walls.map((wall) => {return {_id: wall.id, ...updateData}}))));
|
return Promise.all(
|
||||||
|
scenes.map(scene =>
|
||||||
|
scene.scene.updateEmbeddedDocuments(
|
||||||
|
"Wall",
|
||||||
|
scene.walls.map(wall => {
|
||||||
|
return {_id: wall.id, ...updateData};
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,21 +1,24 @@
|
|||||||
import {toggleSecretDoor} from "../keybindings.js";
|
import {toggleSecretDoor} from "../keybindings.js";
|
||||||
import {settingsKey} from "../settings.js"
|
import {settingsKey} from "../settings.js";
|
||||||
import {updateSynchronizedDoors} from "./synchronized_doors.js";
|
import {updateSynchronizedDoors} from "./synchronized_doors.js";
|
||||||
|
|
||||||
// Toggles between normal and secret doors
|
// Toggles between normal and secret doors
|
||||||
export function onDoorLeftClick() {
|
export function onDoorLeftClick() {
|
||||||
// We don't trust the event to be filled with the expected data for compatibilty with arms reach (which passes a broken event)
|
// We don't trust the event to be filled with the expected data for compatibilty with arms reach (which passes a broken event)
|
||||||
if (toggleSecretDoor && game.user.isGM) {
|
if (toggleSecretDoor && game.user.isGM) {
|
||||||
const types = CONST.WALL_DOOR_TYPES
|
const types = CONST.WALL_DOOR_TYPES;
|
||||||
const newtype = this.wall.data.door === types.DOOR ? types.SECRET : types.DOOR
|
const newtype = this.wall.document.door === types.DOOR ? types.SECRET : types.DOOR;
|
||||||
const updateData = {door: newtype}
|
const updateData = {door: newtype};
|
||||||
const synchronizationGroup = this.wall.data.flags.smartdoors?.synchronizationGroup
|
const synchronizationGroup = this.wall.document.flags.smartdoors?.synchronizationGroup;
|
||||||
if (game.settings.get(settingsKey, "synchronizedDoors") && synchronizationGroup && this.wall.data.flags.smartdoors?.synchronizeSecretStatus)
|
if (
|
||||||
updateSynchronizedDoors(updateData, synchronizationGroup)
|
game.settings.get(settingsKey, "synchronizedDoors") &&
|
||||||
else
|
synchronizationGroup &&
|
||||||
this.wall.document.update(updateData)
|
this.wall.document.flags.smartdoors?.synchronizeSecretStatus
|
||||||
|
)
|
||||||
|
updateSynchronizedDoors(updateData, synchronizationGroup);
|
||||||
|
else this.wall.document.update(updateData);
|
||||||
|
|
||||||
return true
|
return true;
|
||||||
}
|
}
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
|
|||||||
131
src/main.js
131
src/main.js
@@ -1,105 +1,116 @@
|
|||||||
"use strict";
|
"use strict";
|
||||||
|
|
||||||
import {libWrapper} from "../lib/libwrapper_shim.js";
|
import {libWrapper} from "../lib/libwrapper_shim.js";
|
||||||
import * as DoorControlIconScale from "./features/door_control_icon_scale.js"
|
import * as DoorControlIconScale from "./features/door_control_icon_scale.js";
|
||||||
import * as HighlightSecretDoors from "./features/highlight_secret_doors.js"
|
import * as HighlightSecretDoors from "./features/highlight_secret_doors.js";
|
||||||
import * as LockedDoorAlert from "./features/locked_door_alert.js"
|
import * as LockedDoorAlert from "./features/locked_door_alert.js";
|
||||||
import * as SynchronizedDoors from "./features/synchronized_doors.js"
|
import * as SynchronizedDoors from "./features/synchronized_doors.js";
|
||||||
import * as ToggleSecretDoor from "./features/toggle_secret_door.js"
|
import * as ToggleSecretDoor from "./features/toggle_secret_door.js";
|
||||||
|
|
||||||
import {performMigrations} from "./migration.js"
|
import {performMigrations} from "./migration.js";
|
||||||
import {registerKeybindings} from "./keybindings.js"
|
import {registerKeybindings} from "./keybindings.js";
|
||||||
import {registerSettings, settingsKey} from "./settings.js"
|
import {registerSettings, settingsKey} from "./settings.js";
|
||||||
|
|
||||||
Hooks.once("init", () => {
|
Hooks.once("init", () => {
|
||||||
registerSettings()
|
registerSettings();
|
||||||
registerKeybindings()
|
registerKeybindings();
|
||||||
|
|
||||||
hookDoorEvents()
|
hookDoorEvents();
|
||||||
hookWallConfigUpdate()
|
hookWallConfigUpdate();
|
||||||
hookDoorControlDraw()
|
hookDoorControlDraw();
|
||||||
DoorControlIconScale.hookDoorControlReposition()
|
DoorControlIconScale.hookDoorControlReposition();
|
||||||
})
|
});
|
||||||
|
|
||||||
Hooks.once("ready", () => {
|
Hooks.once("ready", () => {
|
||||||
performMigrations()
|
performMigrations();
|
||||||
})
|
});
|
||||||
|
|
||||||
Hooks.on("renderChatMessage", LockedDoorAlert.onRenderChatMessage)
|
Hooks.on("renderChatMessage", LockedDoorAlert.onRenderChatMessage);
|
||||||
|
|
||||||
Hooks.on("canvasReady", DoorControlIconScale.onCanvasReady)
|
Hooks.on("canvasReady", DoorControlIconScale.onCanvasReady);
|
||||||
Hooks.on("canvasReady", HighlightSecretDoors.onCanvasReady)
|
Hooks.on("canvasReady", HighlightSecretDoors.onCanvasReady);
|
||||||
|
|
||||||
Hooks.on("updateWall", HighlightSecretDoors.onUpdateWall)
|
Hooks.on("updateWall", HighlightSecretDoors.onUpdateWall);
|
||||||
|
|
||||||
// Inject our custom settings into the WallConfig dialog
|
// Inject our custom settings into the WallConfig dialog
|
||||||
Hooks.on("renderWallConfig", SynchronizedDoors.onRederWallConfig)
|
Hooks.on("renderWallConfig", SynchronizedDoors.onRederWallConfig);
|
||||||
|
|
||||||
// Hook the update function of the WallConfig dialog so we can store our custom data
|
// Hook the update function of the WallConfig dialog so we can store our custom data
|
||||||
function hookWallConfigUpdate() {
|
function hookWallConfigUpdate() {
|
||||||
// Replace the original function with our custom one
|
// Replace the original function with our custom one
|
||||||
libWrapper.register("smart-doors", "WallConfig.prototype._updateObject", async function (wrapped, event, formData) {
|
libWrapper.register(
|
||||||
await wrapped(event, formData);
|
"smart-doors",
|
||||||
return SynchronizedDoors.onWallConfigUpdate.call(this, event, formData)
|
"WallConfig.prototype._updateObject",
|
||||||
}, "WRAPPER");
|
async function (wrapped, event, formData) {
|
||||||
|
await wrapped(event, formData);
|
||||||
|
return SynchronizedDoors.onWallConfigUpdate.call(this, event, formData);
|
||||||
|
},
|
||||||
|
"WRAPPER",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
function hookDoorControlDraw() {
|
function hookDoorControlDraw() {
|
||||||
libWrapper.register("smart-doors", "DoorControl.prototype.draw", async function (wrapped) {
|
libWrapper.register(
|
||||||
const result = await wrapped();
|
"smart-doors",
|
||||||
DoorControlIconScale.onDoorControlPostDraw.call(this)
|
"DoorControl.prototype.draw",
|
||||||
return result;
|
async function (wrapped) {
|
||||||
}, "WRAPPER");
|
const result = await wrapped();
|
||||||
|
DoorControlIconScale.onDoorControlPostDraw.call(this);
|
||||||
|
return result;
|
||||||
|
},
|
||||||
|
"WRAPPER",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Hook mouse events on DoorControls to perform our logic.
|
// Hook mouse events on DoorControls to perform our logic.
|
||||||
// If we successfully handled the event block the original handler. Forward the event otherwise.
|
// If we successfully handled the event block the original handler. Forward the event otherwise.
|
||||||
function hookDoorEvents() {
|
function hookDoorEvents() {
|
||||||
// Replace the original mousedown handler with our custom one
|
// Replace the original mousedown handler with our custom one
|
||||||
libWrapper.register("smart-doors", "DoorControl.prototype._onMouseDown", function (wrapped, event) {
|
libWrapper.register(
|
||||||
// Call our handler first. Only allow the original handler to run if our handler returns true
|
"smart-doors",
|
||||||
const eventHandled = onDoorMouseDown.call(this, event)
|
"DoorControl.prototype._onMouseDown",
|
||||||
if (eventHandled)
|
function (wrapped, event) {
|
||||||
return
|
// Call our handler first. Only allow the original handler to run if our handler returns true
|
||||||
return wrapped(event);
|
const eventHandled = onDoorMouseDown.call(this, event);
|
||||||
}, "MIXED");
|
if (eventHandled) return;
|
||||||
|
return wrapped(event);
|
||||||
|
},
|
||||||
|
"MIXED",
|
||||||
|
);
|
||||||
|
|
||||||
// Replace the original rightdown handler with our custom one
|
// Replace the original rightdown handler with our custom one
|
||||||
libWrapper.register("smart-doors", "DoorControl.prototype._onRightDown", function (wrapped, event) {
|
libWrapper.register(
|
||||||
// Call our handler first. Only allow the original handler to run if our handler returns true
|
"smart-doors",
|
||||||
const eventHandled = onDoorRightDown.call(this, event)
|
"DoorControl.prototype._onRightDown",
|
||||||
if (eventHandled)
|
function (wrapped, event) {
|
||||||
return
|
// Call our handler first. Only allow the original handler to run if our handler returns true
|
||||||
return wrapped(event);
|
const eventHandled = onDoorRightDown.call(this, event);
|
||||||
}, "MIXED");
|
if (eventHandled) return;
|
||||||
|
return wrapped(event);
|
||||||
|
},
|
||||||
|
"MIXED",
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Our custom handler for mousedown events on doors
|
// Our custom handler for mousedown events on doors
|
||||||
function onDoorMouseDown(event) {
|
function onDoorMouseDown(event) {
|
||||||
// If the user doesn't have the "door" permission we don't do anything.
|
// If the user doesn't have the "door" permission we don't do anything.
|
||||||
if (!game.user.can("WALL_DOORS"))
|
if (!game.user.can("WALL_DOORS")) return false;
|
||||||
return false
|
|
||||||
// If the game is paused don't do anything if the current player isn't the gm
|
// If the game is paused don't do anything if the current player isn't the gm
|
||||||
if ( game.paused && !game.user.isGM )
|
if (game.paused && !game.user.isGM) return false;
|
||||||
return false
|
|
||||||
|
|
||||||
if (ToggleSecretDoor.onDoorLeftClick.call(this, event))
|
if (ToggleSecretDoor.onDoorLeftClick.call(this, event)) return true;
|
||||||
return true
|
|
||||||
|
|
||||||
if (LockedDoorAlert.onDoorLeftClick.call(this))
|
if (LockedDoorAlert.onDoorLeftClick.call(this)) return true;
|
||||||
return true
|
|
||||||
|
|
||||||
if (SynchronizedDoors.onDoorLeftClick.call(this))
|
if (SynchronizedDoors.onDoorLeftClick.call(this)) return true;
|
||||||
return true
|
|
||||||
|
|
||||||
return false
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Our custom handler for rightdown events on doors
|
// Our custom handler for rightdown events on doors
|
||||||
function onDoorRightDown(event) {
|
function onDoorRightDown(event) {
|
||||||
|
if (SynchronizedDoors.onDoorRightClick.call(this)) return true;
|
||||||
|
|
||||||
if (SynchronizedDoors.onDoorRightClick.call(this))
|
return false;
|
||||||
return true
|
|
||||||
|
|
||||||
return false
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,57 +1,58 @@
|
|||||||
import {settingsKey} from "./settings.js"
|
import {settingsKey} from "./settings.js";
|
||||||
|
|
||||||
const currentDataVersion = "1.1.0"
|
const currentDataVersion = "1.1.0";
|
||||||
|
|
||||||
export function performMigrations() {
|
export function performMigrations() {
|
||||||
if (!game.user.isGM)
|
if (!game.user.isGM) return;
|
||||||
return
|
|
||||||
|
|
||||||
let dataVersion = game.settings.get(settingsKey, "dataVersion")
|
let dataVersion = game.settings.get(settingsKey, "dataVersion");
|
||||||
if (dataVersion === "fresh install")
|
if (dataVersion === "fresh install") {
|
||||||
{
|
|
||||||
game.settings.set(settingsKey, "dataVersion", currentDataVersion);
|
game.settings.set(settingsKey, "dataVersion", currentDataVersion);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (dataVersion === "1.0.0") {
|
if (dataVersion === "1.0.0") {
|
||||||
dataVersion = "1.1.0"
|
dataVersion = "1.1.0";
|
||||||
ui.notifications.info(game.i18n.format("smart-doors.ui.messages.migrating", {version: dataVersion}))
|
ui.notifications.info(
|
||||||
|
game.i18n.format("smart-doors.ui.messages.migrating", {version: dataVersion}),
|
||||||
|
);
|
||||||
|
|
||||||
// Make a dictionary that maps all door ids to their scenes
|
// Make a dictionary that maps all door ids to their scenes
|
||||||
const walls = game.scenes.reduce((dict, scene) => {
|
const walls = game.scenes.reduce((dict, scene) => {
|
||||||
scene.data.walls.forEach(wall => {
|
scene.walls.forEach(wall => {
|
||||||
if (!wall.data.door)
|
if (!wall.door) return;
|
||||||
return
|
|
||||||
dict[wall.id] = scene.id;
|
dict[wall.id] = scene.id;
|
||||||
})
|
});
|
||||||
return dict
|
return dict;
|
||||||
}, {})
|
}, {});
|
||||||
|
|
||||||
// Migrate all messages that have a (wall) source id
|
// Migrate all messages that have a (wall) source id
|
||||||
game.messages.forEach(async message => {
|
game.messages.forEach(async message => {
|
||||||
const wallId = message.data.flags.smartdoors?.sourceId
|
const wallId = message.flags.smartdoors?.sourceId;
|
||||||
if (!wallId)
|
if (!wallId) return;
|
||||||
return
|
const flags = message.flags;
|
||||||
const flags = message.data.flags
|
delete flags.smartdoors.sourceId;
|
||||||
delete flags.smartdoors.sourceId
|
const scene = walls[wallId];
|
||||||
const scene = walls[wallId]
|
|
||||||
// If there is no wall with this id anymore we can drop the value. It has no purpose anymore
|
// If there is no wall with this id anymore we can drop the value. It has no purpose anymore
|
||||||
if (!scene) {
|
if (!scene) {
|
||||||
if (!message.data.flags.smartdoors)
|
if (!message.flags.smartdoors) delete flags.smartdoors;
|
||||||
delete flags.smartdoors
|
} else {
|
||||||
}
|
|
||||||
else {
|
|
||||||
// Assign the id and the scene id to the new data structure
|
// Assign the id and the scene id to the new data structure
|
||||||
flags.smartdoors.source = {wall: wallId, scene: scene}
|
flags.smartdoors.source = {wall: wallId, scene: scene};
|
||||||
}
|
}
|
||||||
|
|
||||||
// We have to disable recursive here so deleting keys will actually work
|
// We have to disable recursive here so deleting keys will actually work
|
||||||
message.update({flags: flags}, {diff: false, recursive: false})
|
message.update({flags: flags}, {diff: false, recursive: false});
|
||||||
})
|
});
|
||||||
|
|
||||||
game.settings.set(settingsKey, "dataVersion", dataVersion)
|
game.settings.set(settingsKey, "dataVersion", dataVersion);
|
||||||
ui.notifications.info(game.i18n.format("smart-doors.ui.messages.migrationDone", {version: dataVersion}))
|
ui.notifications.info(
|
||||||
|
game.i18n.format("smart-doors.ui.messages.migrationDone", {version: dataVersion}),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
if (dataVersion != currentDataVersion)
|
if (dataVersion != currentDataVersion)
|
||||||
ui.notifications.error(game.i18n.format("smart-doors.ui.messages.unknownVersion", {version: dataVersion}), {permanent: true})
|
ui.notifications.error(
|
||||||
|
game.i18n.format("smart-doors.ui.messages.unknownVersion", {version: dataVersion}),
|
||||||
|
{permanent: true},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,11 @@
|
|||||||
export const settingsKey = "smart-doors";
|
export const settingsKey = "smart-doors";
|
||||||
|
|
||||||
function reloadGM() {
|
function reloadGM() {
|
||||||
if (game.user.isGM)
|
if (game.user.isGM) delayedReload();
|
||||||
location.reload()
|
}
|
||||||
|
|
||||||
|
function delayedReload() {
|
||||||
|
window.setTimeout(() => location.reload(), 500);
|
||||||
}
|
}
|
||||||
|
|
||||||
export function registerSettings() {
|
export function registerSettings() {
|
||||||
@@ -10,8 +13,8 @@ export function registerSettings() {
|
|||||||
scope: "world",
|
scope: "world",
|
||||||
config: false,
|
config: false,
|
||||||
type: String,
|
type: String,
|
||||||
default: "fresh install"
|
default: "fresh install",
|
||||||
})
|
});
|
||||||
game.settings.register(settingsKey, "doorControlSizeFactor", {
|
game.settings.register(settingsKey, "doorControlSizeFactor", {
|
||||||
name: "smart-doors.settings.doorControlSizeFactor.name",
|
name: "smart-doors.settings.doorControlSizeFactor.name",
|
||||||
hint: "smart-doors.settings.doorControlSizeFactor.hint",
|
hint: "smart-doors.settings.doorControlSizeFactor.hint",
|
||||||
@@ -19,8 +22,8 @@ export function registerSettings() {
|
|||||||
config: true,
|
config: true,
|
||||||
type: Number,
|
type: Number,
|
||||||
default: 1.5,
|
default: 1.5,
|
||||||
onChange: () => location.reload()
|
onChange: delayedReload,
|
||||||
})
|
});
|
||||||
game.settings.register(settingsKey, "highlightSecretDoors", {
|
game.settings.register(settingsKey, "highlightSecretDoors", {
|
||||||
name: "smart-doors.settings.highlightSecretDoors.name",
|
name: "smart-doors.settings.highlightSecretDoors.name",
|
||||||
hint: "smart-doors.settings.highlightSecretDoors.hint",
|
hint: "smart-doors.settings.highlightSecretDoors.hint",
|
||||||
@@ -29,7 +32,7 @@ export function registerSettings() {
|
|||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false,
|
default: false,
|
||||||
onChange: reloadGM,
|
onChange: reloadGM,
|
||||||
})
|
});
|
||||||
game.settings.register(settingsKey, "lockedDoorAlert", {
|
game.settings.register(settingsKey, "lockedDoorAlert", {
|
||||||
name: "smart-doors.settings.lockedDoorAlert.name",
|
name: "smart-doors.settings.lockedDoorAlert.name",
|
||||||
hint: "smart-doors.settings.lockedDoorAlert.hint",
|
hint: "smart-doors.settings.lockedDoorAlert.hint",
|
||||||
@@ -37,7 +40,7 @@ export function registerSettings() {
|
|||||||
config: true,
|
config: true,
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
})
|
});
|
||||||
game.settings.register(settingsKey, "synchronizedDoors", {
|
game.settings.register(settingsKey, "synchronizedDoors", {
|
||||||
name: "smart-doors.settings.synchronizedDoors.name",
|
name: "smart-doors.settings.synchronizedDoors.name",
|
||||||
hint: "smart-doors.settings.synchronizedDoors.hint",
|
hint: "smart-doors.settings.synchronizedDoors.hint",
|
||||||
@@ -45,5 +48,5 @@ export function registerSettings() {
|
|||||||
config: true,
|
config: true,
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: true,
|
default: true,
|
||||||
})
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
10
src/util.js
10
src/util.js
@@ -1,15 +1,17 @@
|
|||||||
// 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.
|
||||||
export function filterAllWalls(filterFn) {
|
export function filterAllWalls(filterFn) {
|
||||||
// Find all walls that match the filter criteria
|
// Find all walls that match the filter criteria
|
||||||
const scenes = game.scenes.map((scene) => {return {scene: scene, walls: scene.data.walls.filter(filterFn)}})
|
const scenes = game.scenes.map(scene => {
|
||||||
|
return {scene: scene, walls: scene.walls.filter(filterFn)};
|
||||||
|
});
|
||||||
// Drop all scenes that don't contain any results
|
// Drop all scenes that don't contain any results
|
||||||
return scenes.filter(scene => scene.walls.length > 0)
|
return scenes.filter(scene => scene.walls.length > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Searches through all scenes for a wall that matches the given filter criteria
|
// Searches through all scenes for a wall that matches the given filter criteria
|
||||||
export function findInAllWalls(filterFn) {
|
export function findInAllWalls(filterFn) {
|
||||||
// TODO The performance of this could be increased by stopping the search on the first hit
|
// TODO The performance of this could be increased by stopping the search on the first hit
|
||||||
const scenes = filterAllWalls(filterFn)
|
const scenes = filterAllWalls(filterFn);
|
||||||
// If results were found take the first wall from the first scene.
|
// If results were found take the first wall from the first scene.
|
||||||
return scenes[0]?.walls[0]
|
return scenes[0]?.walls[0];
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user