Initial macro code

This commit is contained in:
2020-12-16 12:29:33 +01:00
parent 8d943230ef
commit cf2d3d8a34
7 changed files with 138 additions and 5 deletions

View File

@@ -1,9 +1,11 @@
## v1.1.0
### New features
- Draw outlines around Door Control icons to increase their visibility
- Execute a macro when someone interacts with a door
### Other
- Secret doors are now tinted black instead of dark grey.
- Setting hints will now be shown below the title of the setting (before it was above)
### New features
- Tint secret doors grey for the GM to differentiate them from regular doors

View File

@@ -17,6 +17,10 @@
"name": "Locked Door Alert",
"hint": "Send a message in chat when a player tried to open a locked door"
},
"macros": {
"name": "Door Interaction Macros",
"hint": "Trigger a macro when a door is being interacted with"
},
"synchronizedDoors": {
"name": "Synchronized Doors",
"hint": "Synchronize the state of configured doors"
@@ -27,7 +31,22 @@
}
},
"ui": {
"form": {
"macroExecuteEverywhere": {
"name": "Execute on all clients",
"hint": "If disabled the macro will be executed on the GMs client"
},
"macroName": {
"name": "Macro Name",
"hint": "The name of the macro that should be executed when this door is interacted with. No macro is executed if left blank."
},
"macroArguments": {
"name": "Marco Parameters",
"hint": "The parameters passed to the macro. Any JSON string is valid."
}
},
"messages": {
"argsInvalidJson": "The macro arguments must be valid JSON. See console for details.",
"migrating": "Migrating Smart Doors to version {version}. Please don't close the application.",
"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."

View File

@@ -0,0 +1,55 @@
import {settingsKey} from "../settings.js"
import {textInput, checkboxInput, injectSettings} from "../form.js"
// Inject settings for synchronized doors
export function onRederWallConfig(wallConfig, html, data) {
if (data.isDoor && game.settings.get(settingsKey, "macros")) {
const settings = [
textInput("macroName", data.object.flags.smartdoors?.macro?.name),
textInput("macroArguments", JSON.stringify(data.object.flags.smartdoors?.macro?.args ?? undefined)),
checkboxInput("macroExecuteEverywhere", data.object.flags.smartdoors?.macro?.executeEverywhere),
]
injectSettings(html, settings)
}
}
// Check data input by the user for validity
export async function onWallConfigPreUpdate(event, formData) {
const args = formData.macroArguments || "null"
try {
// Check if args can be converted to JSON
JSON.parse(args)
}
catch (error) {
ui.notifications.error(game.i18n.localize("smart-doors.ui.messages.argsInvalidJson"))
// Rethrow the error to stop the update and prevent the dialog from closing
throw(error)
}
// The JSON is valid. Assign "null" instead of an empty string if necessary
formData.macroArguments = args
}
// Store our custom data from the WallConfig dialog
export async function onWallConfigUpdate(event, formData) {
let ids = this.options.editTargets;
if (ids.length == 0) {
ids = [this.object.data._id];
}
const updateData = {flags: {smartdoors: {macro: {
name: formData.macroName,
args: JSON.parse(formData.macroArguments),
executeEverywhere: formData.macroExecuteEverywhere
}}}}
// Update all the edited walls
const updateDataset = ids.reduce((dataset, id) => {
dataset.push({_id: id, ...updateData})
return dataset
}, [])
return canvas.scene.updateEmbeddedEntity("Wall", updateDataset)
}

View File

@@ -18,9 +18,6 @@ export function onRederWallConfig(wallConfig, html, data) {
// Fill the injected input fields with values
const input = (name) => html.find(`input[name="${name}"]`)
input("synchronizationGroup").prop("value", smartdoorsData?.synchronizationGroup)
// Recalculate config window height
wallConfig.setPosition({height: "auto"})
}
}

38
src/form.js Normal file
View File

@@ -0,0 +1,38 @@
function formEntry(name, input) {
return `
<div class="form-group">
<label for="${name}">${game.i18n.localize(`smart-doors.ui.form.${name}.name`)}</label>
${input}
</div>
<p class="notes">${game.i18n.localize(`smart-doors.ui.form.${name}.hint`)}</p>
`
}
export function injectSettings(html, settings) {
html.find(".form-group").last().after(settings.join(""))
}
export function textInput(name, value) {
return formEntry(name, `<input type="text" name="${escapeHtml(name)}" value="${escapeHtml(value ?? "")}"/>`)
}
export function selectInput(name, values) {
// TODO Set selected option
let html = `<select name="${name}">`
html += values.reduce((html, value) => html + `<option value="${escapeHtml(value)}">${game.i18n.localize(`smart-doors.ui.form.${name}.options.${value}`)}</option>`, "")
html += "</select>"
return formEntry(name, html)
}
export function checkboxInput(name, checked) {
return formEntry(name, `<input type="checkbox" name="${escapeHtml(name)}" value="true" ${checked ? "checked" : ""}/>`)
}
function escapeHtml(unsafe) {
return unsafe
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
.replace(/"/g, "&quot;")
.replace(/'/g, "&#039;");
}

View File

@@ -2,6 +2,7 @@
import * as DoorControlIconScale from "./features/door_control_icon_scale.js"
import * as DoorControlOutline from "./features/door_control_outline.js"
import * as ExecuteMacro from "./features/execute_macro.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"
@@ -30,15 +31,28 @@ Hooks.on("canvasReady", HighlightSecretDoors.onCanvasReady)
Hooks.on("updateWall", HighlightSecretDoors.onUpdateWall)
// Inject our custom settings into the WallConfig dialog
Hooks.on("renderWallConfig", SynchronizedDoors.onRederWallConfig)
Hooks.on("renderWallConfig", (wallConfig, html, data) => {
SynchronizedDoors.onRederWallConfig(wallConfig, html, data)
ExecuteMacro.onRederWallConfig(wallConfig, html, data)
// Recalculate config window position and height
wallConfig.element[0].style.top = "" // This forces foundry to re-calculate the top position
wallConfig.setPosition({height: "auto"})
})
// 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 ExecuteMacro.onWallConfigPreUpdate.call(this, event, formData)
await originalHandler.call(this, event, formData)
return SynchronizedDoors.onWallConfigUpdate.call(this, event, formData)
return Promise.all([
SynchronizedDoors.onWallConfigUpdate.call(this, event, formData),
ExecuteMacro.onWallConfigUpdate.call(this, event, formData),
])
}
}

View File

@@ -63,4 +63,12 @@ export function registerSettings() {
type: Boolean,
default: true,
})
game.settings.register(settingsKey, "macros", {
name: "smart-doors.settings.macros.name",
hint: "smart-doors.settings.macros.hint",
scope: "world",
config: true,
type: Boolean,
default: true,
})
}