Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 8e565d24ae | |||
| 81f455c63a | |||
| 42529d3df6 | |||
| 9a40e53d2e | |||
| 01857f6ef4 | |||
| 1215ddf55a |
12
CHANGELOG.md
12
CHANGELOG.md
@@ -1,3 +1,15 @@
|
||||
## 1.2.7
|
||||
### Compatibility
|
||||
- Smart Doors is now compatible with Foundry 0.8.5
|
||||
|
||||
### Feature removals
|
||||
- The door icons now have outlines by defualt in Foundry. As a result the "Door Icon Outline" feature was removed.
|
||||
- Secret doors now have a different icon from regular doors in Foundry, making the "Tint Secret Doors" feature redundant. As a result it was removed.
|
||||
|
||||
## 1.2.6
|
||||
### Compatibility
|
||||
- Smart Doors now uses the libwrapper module and as a result is now compatible with the module "FoundryVTT Arms Reach"
|
||||
|
||||
## 1.2.5
|
||||
### New features
|
||||
- Synchronized doors can now be configured to synchronize their secret door status as well
|
||||
|
||||
@@ -10,11 +10,6 @@ Makes doors smarter. Allows doors to synchronize across multiple scenes and send
|
||||
|
||||
Door Control icons will be rendered the same size in every scene, regardless of the configured grid size. The size of the icons is configurable.
|
||||
|
||||
### Door Control Outline
|
||||

|
||||
|
||||
Door Control icons will be rendered with an outline to improve their visibility on bright backgrounds.
|
||||
|
||||
### Tint Secret Doors
|
||||

|
||||
|
||||
|
||||
@@ -1,18 +1,10 @@
|
||||
{
|
||||
"smart-doors": {
|
||||
"settings": {
|
||||
"doorControlOutline": {
|
||||
"name": "Door Control Outline",
|
||||
"hint": "Draw outlines around Door Control icons to increase their visiblity"
|
||||
},
|
||||
"doorControlSizeFactor": {
|
||||
"name": "Door Control Size Factor",
|
||||
"hint": "Defines by which factor the size of the door control icons should be scaled up"
|
||||
},
|
||||
"highlightSecretDoors": {
|
||||
"name": "Tint Secret Doors",
|
||||
"hint": "Shade secret doors in a different color on the gm screen to differentiate them from normal doors"
|
||||
},
|
||||
"lockedDoorAlert": {
|
||||
"name": "Locked Door Alert",
|
||||
"hint": "Send a message in chat when a player tried to open a locked door"
|
||||
|
||||
61
lib/libwrapper_shim.js
Normal file
61
lib/libwrapper_shim.js
Normal file
@@ -0,0 +1,61 @@
|
||||
// SPDX-License-Identifier: MIT
|
||||
// Copyright © 2021 fvtt-lib-wrapper Rui Pinheiro
|
||||
|
||||
'use strict';
|
||||
|
||||
// A shim for the libWrapper library
|
||||
export let libWrapper = undefined;
|
||||
|
||||
Hooks.once('init', () => {
|
||||
// Check if the real module is already loaded - if so, use it
|
||||
if(globalThis.libWrapper && !(globalThis.libWrapper.is_fallback ?? true)) {
|
||||
libWrapper = globalThis.libWrapper;
|
||||
return;
|
||||
}
|
||||
|
||||
// Fallback implementation
|
||||
libWrapper = class {
|
||||
static get is_fallback() { return true };
|
||||
|
||||
static register(module, target, fn, type="MIXED", {chain=undefined}={}) {
|
||||
const is_setter = target.endsWith('#set');
|
||||
target = !is_setter ? target : target.slice(0, -4);
|
||||
const split = target.split('.');
|
||||
const fn_name = split.pop();
|
||||
const root_nm = split.splice(0,1)[0];
|
||||
const _eval = eval; // The browser doesn't expose all global variables (e.g. 'Game') inside globalThis, but it does to an eval. We copy it to a variable to have it run in global scope.
|
||||
const obj = split.reduce((x,y)=>x[y], globalThis[root_nm] ?? _eval(root_nm));
|
||||
|
||||
let iObj = obj;
|
||||
let descriptor = null;
|
||||
while(iObj) {
|
||||
descriptor = Object.getOwnPropertyDescriptor(iObj, fn_name);
|
||||
if(descriptor) break;
|
||||
iObj = Object.getPrototypeOf(iObj);
|
||||
}
|
||||
if(!descriptor || descriptor?.configurable === false) throw `libWrapper Shim: '${target}' does not exist, could not be found, or has a non-configurable descriptor.`;
|
||||
|
||||
let original = null;
|
||||
const wrapper = (chain ?? type != 'OVERRIDE') ? function() { return fn.call(this, original.bind(this), ...arguments); } : function() { return fn.apply(this, arguments); };
|
||||
|
||||
if(!is_setter) {
|
||||
if(descriptor.value) {
|
||||
original = descriptor.value;
|
||||
descriptor.value = wrapper;
|
||||
}
|
||||
else {
|
||||
original = descriptor.get;
|
||||
descriptor.get = wrapper;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if(!descriptor.set) throw `libWrapper Shim: '${target}' does not have a setter`;
|
||||
original = descriptor.set;
|
||||
descriptor.set = wrapper;
|
||||
}
|
||||
|
||||
descriptor.configurable = true;
|
||||
Object.defineProperty(obj, fn_name, descriptor);
|
||||
}
|
||||
}
|
||||
});
|
||||
@@ -1,152 +0,0 @@
|
||||
/*
|
||||
|
||||
This is a modified version of the PIXI outline filter (https://github.com/pixijs/pixi-filters/tree/master/filters/outline)
|
||||
and is licensed under the MIT license.
|
||||
|
||||
The MIT License
|
||||
|
||||
Copyright (c) 2013-2017 Mathew Groves, Chad Engler
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
*/
|
||||
|
||||
const vertex = `attribute vec2 aVertexPosition;
|
||||
attribute vec2 aTextureCoord;
|
||||
|
||||
uniform mat3 projectionMatrix;
|
||||
|
||||
varying vec2 vTextureCoord;
|
||||
|
||||
void main(void)
|
||||
{
|
||||
gl_Position = vec4((projectionMatrix * vec3(aVertexPosition, 1.0)).xy, 0.0, 1.0);
|
||||
vTextureCoord = aTextureCoord;
|
||||
}`
|
||||
|
||||
const fragment = `varying vec2 vTextureCoord;
|
||||
uniform sampler2D uSampler;
|
||||
|
||||
uniform vec2 thickness;
|
||||
uniform vec4 outlineColor;
|
||||
uniform vec4 filterClamp;
|
||||
|
||||
const float DOUBLE_PI = 3.14159265358979323846264 * 2.;
|
||||
|
||||
void main(void) {
|
||||
vec4 ownColor = texture2D(uSampler, vTextureCoord);
|
||||
vec4 curColor;
|
||||
float maxAlpha = 0.;
|
||||
vec2 displaced;
|
||||
for (float angle = 0.; angle <= DOUBLE_PI; angle += \${angleStep}) {
|
||||
displaced.x = vTextureCoord.x + thickness.x * cos(angle);
|
||||
displaced.y = vTextureCoord.y + thickness.y * sin(angle);
|
||||
curColor = texture2D(uSampler, clamp(displaced, filterClamp.xy, filterClamp.zw));
|
||||
maxAlpha = max(maxAlpha, curColor.a);
|
||||
}
|
||||
float resultAlpha = max(maxAlpha, ownColor.a);
|
||||
// Original line:
|
||||
// gl_FragColor = vec4((ownColor.rgb + outlineColor.rgb * (1. - ownColor.a)) * resultAlpha, resultAlpha);
|
||||
gl_FragColor = vec4(ownColor.rgb + outlineColor.rgb * (resultAlpha - ownColor.a), resultAlpha);
|
||||
}
|
||||
`
|
||||
|
||||
/**
|
||||
* OutlineFilter, originally by mishaa
|
||||
* http://www.html5gamedevs.com/topic/10640-outline-a-sprite-change-certain-colors/?p=69966
|
||||
* http://codepen.io/mishaa/pen/emGNRB<br>
|
||||
* 
|
||||
*
|
||||
* @class
|
||||
* @extends PIXI.Filter
|
||||
* @memberof PIXI.filters
|
||||
* @see {@link https://www.npmjs.com/package/@pixi/filter-outline|@pixi/filter-outline}
|
||||
* @see {@link https://www.npmjs.com/package/pixi-filters|pixi-filters}
|
||||
* @param {number} [thickness=1] The tickness of the outline. Make it 2 times more for resolution 2
|
||||
* @param {number} [color=0x000000] The color of the outline.
|
||||
* @param {number} [quality=0.1] The quality of the outline from `0` to `1`, using a higher quality
|
||||
* setting will result in slower performance and more accuracy.
|
||||
*
|
||||
* @example
|
||||
* someSprite.filters = [new OutlineFilter(2, 0x99ff99)];
|
||||
*/
|
||||
class OutlineFilter extends PIXI.Filter {
|
||||
|
||||
constructor(thickness = 1, color = 0x000000, quality = 0.1) {
|
||||
const samples = Math.max(
|
||||
quality * OutlineFilter.MAX_SAMPLES,
|
||||
OutlineFilter.MIN_SAMPLES
|
||||
);
|
||||
const angleStep = (Math.PI * 2 / samples).toFixed(7);
|
||||
|
||||
super(vertex, fragment.replace(/\$\{angleStep\}/, angleStep));
|
||||
this.uniforms.thickness = new Float32Array([0, 0]);
|
||||
|
||||
/**
|
||||
* The thickness of the outline.
|
||||
* @member {number}
|
||||
* @default 1
|
||||
*/
|
||||
this.thickness = thickness;
|
||||
|
||||
this.uniforms.outlineColor = new Float32Array([0, 0, 0, 1]);
|
||||
this.color = color;
|
||||
|
||||
this.quality = quality;
|
||||
}
|
||||
|
||||
apply(filterManager, input, output, clear) {
|
||||
this.uniforms.thickness[0] = this.thickness / input._frame.width;
|
||||
this.uniforms.thickness[1] = this.thickness / input._frame.height;
|
||||
|
||||
filterManager.applyFilter(this, input, output, clear);
|
||||
}
|
||||
|
||||
/**
|
||||
* The color of the glow.
|
||||
* @member {number}
|
||||
* @default 0x000000
|
||||
*/
|
||||
get color() {
|
||||
return PIXI.utils.rgb2hex(this.uniforms.outlineColor);
|
||||
}
|
||||
set color(value) {
|
||||
PIXI.utils.hex2rgb(value, this.uniforms.outlineColor);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The minimum number of samples for rendering outline.
|
||||
* @static
|
||||
* @member {number} MIN_SAMPLES
|
||||
* @memberof PIXI.filters.OutlineFilter
|
||||
* @default 1
|
||||
*/
|
||||
OutlineFilter.MIN_SAMPLES = 1;
|
||||
|
||||
/**
|
||||
* The maximum number of samples for rendering outline.
|
||||
* @static
|
||||
* @member {number} MAX_SAMPLES
|
||||
* @memberof PIXI.filters.OutlineFilter
|
||||
* @default 100
|
||||
*/
|
||||
OutlineFilter.MAX_SAMPLES = 100;
|
||||
|
||||
export { OutlineFilter };
|
||||
12
module.json
12
module.json
@@ -2,9 +2,9 @@
|
||||
"name": "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.",
|
||||
"version": "1.2.5",
|
||||
"minimumCoreVersion" : "0.7.7",
|
||||
"compatibleCoreVersion" : "0.7.9",
|
||||
"version": "1.2.7",
|
||||
"minimumCoreVersion" : "0.8.5",
|
||||
"compatibleCoreVersion" : "0.8.5",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Manuel Vögele",
|
||||
@@ -13,6 +13,7 @@
|
||||
}
|
||||
],
|
||||
"esmodules": [
|
||||
"lib/libwrapper_shim.js",
|
||||
"src/main.js"
|
||||
],
|
||||
"languages": [
|
||||
@@ -24,8 +25,9 @@
|
||||
],
|
||||
"url": "https://github.com/manuelVo/foundryvtt-smart-doors",
|
||||
"manifest": "https://raw.githubusercontent.com/manuelVo/foundryvtt-smart-doors/master/module.json",
|
||||
"download": "https://github.com/manuelVo/foundryvtt-smart-doors/archive/v1.2.5.zip",
|
||||
"download": "https://github.com/manuelVo/foundryvtt-smart-doors/archive/v1.2.7.zip",
|
||||
"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",
|
||||
"allowBugReporter": true
|
||||
}
|
||||
|
||||
@@ -1,13 +1,14 @@
|
||||
import { libWrapper } from "../../lib/libwrapper_shim.js"
|
||||
import {settingsKey} from "../settings.js"
|
||||
|
||||
// Adjust the repositioning formula for the door controls
|
||||
export function hookDoorControlReposition() {
|
||||
DoorControl.prototype.reposition = function () {
|
||||
libWrapper.register("smart-doors", "DoorControl.prototype.reposition", function () {
|
||||
let gridSize = this.wall.scene.data.grid
|
||||
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
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
import {settingsKey} from "../settings.js"
|
||||
import {OutlineFilter} from "../../lib/outline_filter/outline_filter.js"
|
||||
|
||||
export function onDoorControlPostDraw() {
|
||||
if (!game.settings.get(settingsKey, "doorControlOutline"))
|
||||
return
|
||||
|
||||
const types = CONST.WALL_DOOR_TYPES
|
||||
if (this.wall.data.door === types.NONE)
|
||||
return
|
||||
|
||||
// Remove all OutlineFilters from current filters
|
||||
let pixiFilters = this.icon.filters || []
|
||||
pixiFilters = pixiFilters.filter(pixiFilter => !(pixiFilter instanceof OutlineFilter))
|
||||
|
||||
let outlineFilter;
|
||||
if (this.wall.data.door === types.SECRET && game.settings.get(settingsKey, "highlightSecretDoors"))
|
||||
outlineFilter = new OutlineFilter(1, 0xFFFFFF)
|
||||
else
|
||||
outlineFilter = new OutlineFilter(1, 0x000000)
|
||||
|
||||
pixiFilters.push(outlineFilter)
|
||||
this.icon.filters = pixiFilters
|
||||
}
|
||||
@@ -1,34 +0,0 @@
|
||||
import {settingsKey} from "../settings.js"
|
||||
|
||||
const SECRET_DOOR_TINT = 0x000000
|
||||
|
||||
// Tint all secret doors dark grey
|
||||
export function onCanvasReady(currentCanvas) {
|
||||
if (game.settings.get(settingsKey, "highlightSecretDoors")) {
|
||||
const types = CONST.WALL_DOOR_TYPES
|
||||
const secretDoors = canvas.controls.doors.children.filter(control => control.wall.data.door == types.SECRET)
|
||||
secretDoors.forEach(control => control.icon.tint = SECRET_DOOR_TINT)
|
||||
}
|
||||
}
|
||||
|
||||
// If door type has been changed, tint the door accordingly
|
||||
export function onUpdateWall(scene, wall, update) {
|
||||
if (!game.settings.get(settingsKey, "highlightSecretDoors"))
|
||||
return
|
||||
const types = CONST.WALL_DOOR_TYPES
|
||||
if (wall.door === types.NONE)
|
||||
return
|
||||
// Find the door control corresponding to the changed door
|
||||
const changedDoor = canvas.controls.doors.children.find(control => control.wall.data._id === wall._id);
|
||||
// If the changed door doesn't have a control it's not on this scene - ignore it
|
||||
if (!changedDoor)
|
||||
return
|
||||
// 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
|
||||
if (wall.door === types.DOOR)
|
||||
changedDoor.icon.tint = 0xFFFFFF
|
||||
else if (wall.door === types.SECRET)
|
||||
changedDoor.icon.tint = SECRET_DOOR_TINT
|
||||
else
|
||||
console.warn("Smart Doors | Encountered unknown door type " + wall.door + " while highlighting secret doors.")
|
||||
}
|
||||
@@ -9,7 +9,7 @@ export function onRenderChatMessage(message, html, data) {
|
||||
|
||||
// Tint on mouse enter
|
||||
const mouseEnter = function () {
|
||||
const sourceDoor = canvas.controls.doors.children.find(door => door.wall.data._id === source.wall && door.wall.scene.id === source.scene);
|
||||
const sourceDoor = canvas.controls.doors.children.find(door => door.wall.id === source.wall && door.wall.scene.id === source.scene);
|
||||
if (sourceDoor)
|
||||
sourceDoor.icon.tint = 0xff0000;
|
||||
}
|
||||
@@ -17,7 +17,7 @@ export function onRenderChatMessage(message, html, data) {
|
||||
|
||||
// Remove tint on mouse leave
|
||||
const mouseLeave = function () {
|
||||
const sourceDoor = canvas.controls.doors.children.find(door => door.wall.data._id === source.wall && door.wall.scene.id === source.scene);
|
||||
const sourceDoor = canvas.controls.doors.children.find(door => door.wall.id === source.wall && door.wall.scene.id === source.scene);
|
||||
if (sourceDoor)
|
||||
sourceDoor.icon.tint = 0xffffff;
|
||||
}
|
||||
@@ -34,7 +34,7 @@ export function onDoorLeftClick() {
|
||||
const states = CONST.WALL_DOOR_STATES
|
||||
|
||||
// Only create messages when the door is locked.
|
||||
if (state != states.LOCKED)
|
||||
if (state !== states.LOCKED)
|
||||
return false
|
||||
|
||||
// Generate no message if the gm attempts to open the door
|
||||
@@ -43,7 +43,7 @@ export function onDoorLeftClick() {
|
||||
|
||||
// Create and send the chat message
|
||||
const message = {}
|
||||
message.user = game.user
|
||||
message.user = game.user.id;
|
||||
if (game.user.character)
|
||||
message.speaker = {actor: game.user.character}
|
||||
message.content = "Just tried to open a locked door"
|
||||
|
||||
@@ -35,7 +35,7 @@ export async function onWallConfigUpdate(event, formData) {
|
||||
const updateData = {flags: {smartdoors: {synchronizationGroup: formData.synchronizationGroup}}};
|
||||
let ids = this.options.editTargets;
|
||||
if (ids.length == 0) {
|
||||
ids = [this.object.data._id];
|
||||
ids = [this.object.id];
|
||||
}
|
||||
|
||||
// If a synchronization group is set, get the state of existing doors and assume their state
|
||||
@@ -46,33 +46,30 @@ export async function onWallConfigUpdate(event, formData) {
|
||||
// Search for other doors in the synchronization group that aren't in the list of edited doors
|
||||
const doorInGroup = Util.findInAllWalls(wall => {
|
||||
// We only search for doors
|
||||
if (!wall.door)
|
||||
if (!wall.data.door)
|
||||
return false
|
||||
// We only want doors in the same synchronization group
|
||||
if (wall.flags.smartdoors?.synchronizationGroup !== formData.synchronizationGroup)
|
||||
if (wall.data.flags.smartdoors?.synchronizationGroup !== formData.synchronizationGroup)
|
||||
return false
|
||||
// Doors on this scene that have their id included in `ids` are currently being changed. Ignore them.
|
||||
if (wall.scene === canvas.scene && ids.includes(wall._id))
|
||||
if (wall.parent.id === canvas.scene.id && ids.includes(wall.id))
|
||||
return false
|
||||
return true
|
||||
})
|
||||
if (doorInGroup) {
|
||||
// ds is the door sate in foundry
|
||||
updateData.ds = doorInGroup.ds;
|
||||
updateData.ds = doorInGroup.data.ds;
|
||||
|
||||
if (synchronizeSecretStatus) {
|
||||
// door is the door type in foundry
|
||||
updateData.door = doorInGroup.door
|
||||
updateData.door = doorInGroup.data.door;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update all the edited walls
|
||||
const updateDataset = ids.reduce((dataset, id) => {
|
||||
dataset.push({_id: id, ...updateData})
|
||||
return dataset
|
||||
}, [])
|
||||
const updateResult = await canvas.scene.updateEmbeddedEntity("Wall", updateDataset);
|
||||
const updateDataset = ids.map(id => {return {_id: id, ...updateData}});
|
||||
const updateResult = await canvas.scene.updateEmbeddedDocuments("Wall", updateDataset);
|
||||
|
||||
// If door is synchronized, synchronize secret status among synchronized doors
|
||||
if (formData.synchronizationGroup)
|
||||
@@ -143,13 +140,10 @@ export function onDoorRightClick() {
|
||||
}
|
||||
|
||||
// Updates all doors in the specified synchronization group with the provided data
|
||||
export async function updateSynchronizedDoors(updateData, synchronizationGroup) {
|
||||
export function updateSynchronizedDoors(updateData, synchronizationGroup) {
|
||||
// Search for doors belonging to the synchronization group in all scenes
|
||||
let scenes = Util.filterAllWalls(wall => wall.door && wall.flags.smartdoors?.synchronizationGroup === synchronizationGroup);
|
||||
let scenes = Util.filterAllWalls(wall => wall.data.door && wall.data.flags.smartdoors?.synchronizationGroup === synchronizationGroup);
|
||||
|
||||
// Update all doors in the synchronization group
|
||||
for (const scene of scenes) {
|
||||
// When VFTT 0.8 is out look for a way to do this in a single call.
|
||||
await scene.scene.updateEmbeddedEntity("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}}))));
|
||||
}
|
||||
|
||||
@@ -12,7 +12,7 @@ export function onDoorLeftClick(event) {
|
||||
if (game.settings.get(settingsKey, "synchronizedDoors") && synchronizationGroup && this.wall.data.flags.smartdoors?.synchronizeSecretStatus)
|
||||
updateSynchronizedDoors(updateData, synchronizationGroup)
|
||||
else
|
||||
this.wall.update(updateData)
|
||||
this.wall.document.update(updateData)
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
37
src/main.js
37
src/main.js
@@ -1,8 +1,7 @@
|
||||
"use strict";
|
||||
|
||||
import {libWrapper} from "../lib/libwrapper_shim.js";
|
||||
import * as DoorControlIconScale from "./features/door_control_icon_scale.js"
|
||||
import * as DoorControlOutline from "./features/door_control_outline.js"
|
||||
import * as HighlightSecretDoors from "./features/highlight_secret_doors.js"
|
||||
import * as LockedDoorAlert from "./features/locked_door_alert.js"
|
||||
import * as SynchronizedDoors from "./features/synchronized_doors.js"
|
||||
import * as ToggleSecretDoor from "./features/toggle_secret_door.js"
|
||||
@@ -25,9 +24,6 @@ Hooks.once("ready", () => {
|
||||
Hooks.on("renderChatMessage", LockedDoorAlert.onRenderChatMessage)
|
||||
|
||||
Hooks.on("canvasReady", DoorControlIconScale.onCanvasReady)
|
||||
Hooks.on("canvasReady", HighlightSecretDoors.onCanvasReady)
|
||||
|
||||
Hooks.on("updateWall", HighlightSecretDoors.onUpdateWall)
|
||||
|
||||
// Inject our custom settings into the WallConfig dialog
|
||||
Hooks.on("renderWallConfig", SynchronizedDoors.onRederWallConfig)
|
||||
@@ -35,45 +31,40 @@ Hooks.on("renderWallConfig", SynchronizedDoors.onRederWallConfig)
|
||||
// Hook the update function of the WallConfig dialog so we can store our custom data
|
||||
function hookWallConfigUpdate() {
|
||||
// Replace the original function with our custom one
|
||||
const originalHandler = WallConfig.prototype._updateObject;
|
||||
WallConfig.prototype._updateObject = async function (event, formData) {
|
||||
await originalHandler.call(this, event, formData)
|
||||
libWrapper.register("smart-doors", "WallConfig.prototype._updateObject", async function (wrapped, event, formData) {
|
||||
await wrapped(event, formData);
|
||||
return SynchronizedDoors.onWallConfigUpdate.call(this, event, formData)
|
||||
}
|
||||
}, "WRAPPER");
|
||||
}
|
||||
|
||||
function hookDoorControlDraw() {
|
||||
const originalHandler = DoorControl.prototype.draw
|
||||
DoorControl.prototype.draw = async function () {
|
||||
const result = await originalHandler.call(this)
|
||||
libWrapper.register("smart-doors", "DoorControl.prototype.draw", async function (wrapped) {
|
||||
const result = await wrapped();
|
||||
DoorControlIconScale.onDoorControlPostDraw.call(this)
|
||||
DoorControlOutline.onDoorControlPostDraw.call(this)
|
||||
return result
|
||||
}
|
||||
return result;
|
||||
}, "WRAPPER");
|
||||
}
|
||||
|
||||
// Hook mouse events on DoorControls to perform our logic.
|
||||
// If we successfully handled the event block the original handler. Forward the event otherwise.
|
||||
function hookDoorEvents() {
|
||||
// Replace the original mousedown handler with our custom one
|
||||
const originalMouseDownHandler = DoorControl.prototype._onMouseDown
|
||||
DoorControl.prototype._onMouseDown = function (event) {
|
||||
libWrapper.register("smart-doors", "DoorControl.prototype._onMouseDown", function (wrapped, event) {
|
||||
// Call our handler first. Only allow the original handler to run if our handler returns true
|
||||
const eventHandled = onDoorMouseDown.call(this, event)
|
||||
if (eventHandled)
|
||||
return
|
||||
return originalMouseDownHandler.call(this, event)
|
||||
}
|
||||
return wrapped(event);
|
||||
}, "MIXED");
|
||||
|
||||
// Replace the original rightdown handler with our custom one
|
||||
const originalRightDownHandler = DoorControl.prototype._onRightDown
|
||||
DoorControl.prototype._onRightDown = function (event) {
|
||||
libWrapper.register("smart-doors", "DoorControl.prototype._onRightDown", function (wrapped, event) {
|
||||
// Call our handler first. Only allow the original handler to run if our handler returns true
|
||||
const eventHandled = onDoorRightDown.call(this, event)
|
||||
if (eventHandled)
|
||||
return
|
||||
return originalRightDownHandler.call(this, event)
|
||||
}
|
||||
return wrapped(event);
|
||||
}, "MIXED");
|
||||
}
|
||||
|
||||
// Our custom handler for mousedown events on doors
|
||||
|
||||
@@ -20,9 +20,9 @@ export function performMigrations() {
|
||||
// Make a dictionary that maps all door ids to their scenes
|
||||
const walls = game.scenes.reduce((dict, scene) => {
|
||||
scene.data.walls.forEach(wall => {
|
||||
if (!wall.door)
|
||||
if (!wall.data.door)
|
||||
return
|
||||
dict[wall._id] = scene.id
|
||||
dict[wall.id] = scene.id;
|
||||
})
|
||||
return dict
|
||||
}, {})
|
||||
|
||||
@@ -1,10 +1,5 @@
|
||||
export const settingsKey = "smart-doors";
|
||||
|
||||
function reloadGM() {
|
||||
if (game.user.isGM)
|
||||
location.reload()
|
||||
}
|
||||
|
||||
export function registerSettings() {
|
||||
game.settings.register(settingsKey, "dataVersion", {
|
||||
scope: "world",
|
||||
@@ -21,24 +16,6 @@ export function registerSettings() {
|
||||
default: 1.5,
|
||||
onChange: () => location.reload()
|
||||
})
|
||||
game.settings.register(settingsKey, "doorControlOutline", {
|
||||
name: "smart-doors.settings.doorControlOutline.name",
|
||||
hint: "smart-doors.settings.doorControlOutline.hint",
|
||||
scope: "client",
|
||||
config: true,
|
||||
type: Boolean,
|
||||
default: true,
|
||||
onChange: () => location.reload(),
|
||||
})
|
||||
game.settings.register(settingsKey, "highlightSecretDoors", {
|
||||
name: "smart-doors.settings.highlightSecretDoors.name",
|
||||
hint: "smart-doors.settings.highlightSecretDoors.hint",
|
||||
scope: "world",
|
||||
config: true,
|
||||
type: Boolean,
|
||||
default: true,
|
||||
onChange: reloadGM,
|
||||
})
|
||||
game.settings.register(settingsKey, "toggleSecretDoors", {
|
||||
name: "smart-doors.settings.toggleSecretDoors.name",
|
||||
hint: "smart-doors.settings.toggleSecretDoors.hint",
|
||||
|
||||
Reference in New Issue
Block a user