diff --git a/daggerheart.mjs b/daggerheart.mjs index 153c2f84..4f411b0f 100644 --- a/daggerheart.mjs +++ b/daggerheart.mjs @@ -120,6 +120,7 @@ Hooks.once('init', () => { CONFIG.ChatMessage.documentClass = documents.DhChatMessage; CONFIG.Canvas.rulerClass = placeables.DhRuler; + CONFIG.Canvas.layers.templates.layerClass = placeables.DhTemplateLayer; CONFIG.Combat.documentClass = documents.DhpCombat; CONFIG.ui.combat = applications.ui.DhCombatTracker; CONFIG.ui.chat = applications.ui.DhChatLog; diff --git a/lang/en.json b/lang/en.json index b5ed3b3f..b1441032 100755 --- a/lang/en.json +++ b/lang/en.json @@ -20,6 +20,9 @@ "environment": "Environment" } }, + "CONTROLS": { + "inFront": "In Front" + }, "DAGGERHEART": { "ACTIONS": { "Config": { diff --git a/module/canvas/placeables/_module.mjs b/module/canvas/placeables/_module.mjs index 1da3a1e9..3610559c 100644 --- a/module/canvas/placeables/_module.mjs +++ b/module/canvas/placeables/_module.mjs @@ -1,3 +1,4 @@ export { default as DhMeasuredTemplate } from './measuredTemplate.mjs'; export { default as DhRuler } from './ruler.mjs'; +export { default as DhTemplateLayer } from './templateLayer.mjs'; export { default as DhTokenRuler } from './tokenRuler.mjs'; diff --git a/module/canvas/placeables/templateLayer.mjs b/module/canvas/placeables/templateLayer.mjs new file mode 100644 index 00000000..551a06cc --- /dev/null +++ b/module/canvas/placeables/templateLayer.mjs @@ -0,0 +1,116 @@ +export default class DhTemplateLayer extends foundry.canvas.layers.TemplateLayer { + static prepareSceneControls() { + const sc = foundry.applications.ui.SceneControls; + return { + name: 'templates', + order: 2, + title: 'CONTROLS.GroupMeasure', + icon: 'fa-solid fa-ruler-combined', + visible: game.user.can('TEMPLATE_CREATE'), + onChange: (event, active) => { + if (active) canvas.templates.activate(); + }, + onToolChange: () => canvas.templates.setAllRenderFlags({ refreshState: true }), + tools: { + circle: { + name: 'circle', + order: 1, + title: 'CONTROLS.MeasureCircle', + icon: 'fa-regular fa-circle', + toolclip: { + src: 'toolclips/tools/measure-circle.webm', + heading: 'CONTROLS.MeasureCircle', + items: sc.buildToolclipItems(['create', 'move', 'edit', 'hide', 'delete']) + } + }, + cone: { + name: 'cone', + order: 2, + title: 'CONTROLS.MeasureCone', + icon: 'fa-solid fa-angle-left', + toolclip: { + src: 'toolclips/tools/measure-cone.webm', + heading: 'CONTROLS.MeasureCone', + items: sc.buildToolclipItems(['create', 'move', 'edit', 'hide', 'delete', 'rotate']) + } + }, + inFront: { + name: 'inFront', + order: 3, + title: 'CONTROLS.inFront', + icon: 'fa-solid fa-eye', + toolclip: { + src: 'toolclips/tools/measure-cone.webm', + heading: 'CONTROLS.inFront', + items: sc.buildToolclipItems(['create', 'move', 'edit', 'hide', 'delete', 'rotate']) + } + }, + rect: { + name: 'rect', + order: 4, + title: 'CONTROLS.MeasureRect', + icon: 'fa-regular fa-square', + toolclip: { + src: 'toolclips/tools/measure-rect.webm', + heading: 'CONTROLS.MeasureRect', + items: sc.buildToolclipItems(['create', 'move', 'edit', 'hide', 'delete', 'rotate']) + } + }, + ray: { + name: 'ray', + order: 5, + title: 'CONTROLS.MeasureRay', + icon: 'fa-solid fa-up-down', + toolclip: { + src: 'toolclips/tools/measure-ray.webm', + heading: 'CONTROLS.MeasureRay', + items: sc.buildToolclipItems(['create', 'move', 'edit', 'hide', 'delete', 'rotate']) + } + }, + clear: { + name: 'clear', + order: 6, + title: 'CONTROLS.MeasureClear', + icon: 'fa-solid fa-trash', + visible: game.user.isGM, + onChange: () => canvas.templates.deleteAll(), + button: true + } + }, + activeTool: 'circle' + }; + } + + _onDragLeftStart(event) { + const interaction = event.interactionData; + + // Snap the origin to the grid + if (!event.shiftKey) interaction.origin = this.getSnappedPoint(interaction.origin); + + // Create a pending MeasuredTemplateDocument + const tool = game.activeTool === 'inFront' ? 'cone' : game.activeTool; + const previewData = { + user: game.user.id, + t: tool, + x: interaction.origin.x, + y: interaction.origin.y, + sort: Math.max(this.getMaxSort() + 1, 0), + distance: 1, + direction: 0, + fillColor: game.user.color || '#FF0000', + hidden: event.altKey + }; + const defaults = CONFIG.MeasuredTemplate.defaults; + if (game.activeTool === 'cone') previewData.angle = defaults.angle; + else if (game.activeTool === 'inFront') previewData.angle = 180; + else if (game.activeTool === 'ray') previewData.width = defaults.width * canvas.dimensions.distance; + const cls = foundry.utils.getDocumentClass('MeasuredTemplate'); + const doc = new cls(previewData, { parent: canvas.scene }); + + // Create a preview MeasuredTemplate object + const template = new this.constructor.placeableClass(doc); + doc._object = template; + interaction.preview = this.preview.addChild(template); + template.draw(); + } +} diff --git a/module/data/actor/character.mjs b/module/data/actor/character.mjs index 1dfbd015..daf63a79 100644 --- a/module/data/actor/character.mjs +++ b/module/data/actor/character.mjs @@ -1,5 +1,4 @@ import { burden } from '../../config/generalConfig.mjs'; -import ActionField from '../fields/actionField.mjs'; import ForeignDocumentUUIDField from '../fields/foreignDocumentUUIDField.mjs'; import DhLevelData from '../levelData.mjs'; import BaseDataActor from './base.mjs'; @@ -29,7 +28,7 @@ export default class DhCharacter extends BaseDataActor { return foundry.utils.mergeObject(super.metadata, { label: 'TYPES.Actor.character', type: 'character', - isNPC: false, + isNPC: false }); } diff --git a/module/documents/tooltipManager.mjs b/module/documents/tooltipManager.mjs index b780dfa9..2e660cff 100644 --- a/module/documents/tooltipManager.mjs +++ b/module/documents/tooltipManager.mjs @@ -1,7 +1,7 @@ export default class DhTooltipManager extends foundry.helpers.interaction.TooltipManager { async activate(element, options = {}) { let html = options.html; - if (element.dataset.tooltip.startsWith('#item#')) { + if (element.dataset.tooltip?.startsWith('#item#')) { const item = await foundry.utils.fromUuid(element.dataset.tooltip.slice(6)); if (item) { html = await foundry.applications.handlebars.renderTemplate(