From 3267685e785cb7cded64fdb63a0059113047c86e Mon Sep 17 00:00:00 2001 From: Michael Enion Date: Tue, 5 Nov 2024 08:22:53 -0800 Subject: [PATCH 1/4] =?UTF-8?q?=F0=9F=8F=B9=20release|Module.json|Update?= =?UTF-8?q?=20verified=20to=2012.331?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- module.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module.json b/module.json index 5489326..cd2f6e4 100644 --- a/module.json +++ b/module.json @@ -6,7 +6,7 @@ "library": false, "compatibility": { "minimum": "12", - "verified": "12.327" + "verified": "12.331" }, "authors": [ { From da97184d903075ace0f7b612af389762ccbc1d15 Mon Sep 17 00:00:00 2001 From: Michael Enion Date: Tue, 5 Nov 2024 13:15:12 -0800 Subject: [PATCH 2/4] =?UTF-8?q?=F0=9F=8E=B8=20feat|Shapes|Add=20rotated=20?= =?UTF-8?q?square=20as=20replacement=20for=20circle?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- languages/en.json | 4 +- scripts/module.js | 2 + scripts/settings.js | 19 ++++- .../template_shapes/WalledTemplateCircle.js | 2 +- .../WalledTemplateRotatedSquare.js | 74 +++++++++++++++++++ .../template_shapes/WalledTemplateSquare.js | 4 +- 6 files changed, 99 insertions(+), 6 deletions(-) create mode 100644 scripts/template_shapes/WalledTemplateRotatedSquare.js diff --git a/languages/en.json b/languages/en.json index ede7362..e5b18df 100644 --- a/languages/en.json +++ b/languages/en.json @@ -126,9 +126,11 @@ "walledtemplates.settings.hideHighlighting.Name": "Hide template highlighting", "walledtemplates.settings.hideHighlighting.Hint": "Unless hovering over the template control icon, do not show the highlighted grid for the template.", - "walledtemplates.settings.showOnHover.Name": "Show on token hover", + "walledtemplates.settings.showOnHover.Name": "Show on token hover", "walledtemplates.settings.showOnHover.Hint": "When hovering over a token, show grid highlighting for all hidden templates that overlap that token's border.", + "walledtemplates.settings.circleSquare.Name": "Replace Circles with Squares", + "walledtemplates.controls.autotarget.Title": "Autotarget tokens with template", "walledtemplates.notifications.attach-last-selected-token": "Please select a token to attach.", diff --git a/scripts/module.js b/scripts/module.js index 3a67964..f148e41 100644 --- a/scripts/module.js +++ b/scripts/module.js @@ -38,6 +38,7 @@ import { WalledTemplateCone } from "./template_shapes/WalledTemplateCone.js"; import { WalledTemplateRay } from "./template_shapes/WalledTemplateRay.js"; import { WalledTemplateRoundedCone } from "./template_shapes/WalledTemplateRoundedCone.js"; import { WalledTemplateSquare } from "./template_shapes/WalledTemplateSquare.js"; +import { WalledTemplateRotatedSquare } from "./template_shapes/WalledTemplateRotatedSquare.js"; // Self-executing scripts for hooks import "./changelog.js"; @@ -102,6 +103,7 @@ Hooks.once("init", function() { WalledTemplateRay, WalledTemplateRoundedCone, WalledTemplateSquare, + WalledTemplateRotatedSquare, PATCHER, diff --git a/scripts/settings.js b/scripts/settings.js index b9901f3..903d417 100644 --- a/scripts/settings.js +++ b/scripts/settings.js @@ -1,6 +1,5 @@ /* globals canvas, -CONFIG, CONST, game, ui @@ -12,6 +11,9 @@ import { MODULE_ID, SHAPE_KEYS } from "./const.js"; import { registerAutotargeting } from "./patching.js"; import { WalledTemplateShapeSettings } from "./WalledTemplateShapeSettings.js"; import { ModuleSettingsAbstract } from "./ModuleSettingsAbstract.js"; +import { WalledTemplateShape } from "./template_shapes/WalledTemplateShape.js"; +import { WalledTemplateCircle } from "./template_shapes/WalledTemplateCircle.js"; +import { WalledTemplateRotatedSquare } from "./template_shapes/WalledTemplateRotatedSquare.js"; const KEYBINDINGS = { AUTOTARGET: "autoTarget", @@ -28,7 +30,8 @@ export const SETTINGS = { HIGHLIGHTING: "hideHighlighting", SHOW_ON_HOVER: "showOnHover" }, - CHANGELOG: "changelog" + CHANGELOG: "changelog", + CIRCLE_SQUARE: "circleSquare" }; SETTINGS.AUTOTARGET = { @@ -201,6 +204,18 @@ export class Settings extends ModuleSettingsAbstract { config: true }); + register(KEYS.CIRCLE_SQUARE, { + name: localize(`${KEYS.CIRCLE_SQUARE}.Name`), + type: Boolean, + default: false, + scope: "world", + config: true, + onChange: value => { + const shapeCl = value ? WalledTemplateRotatedSquare : WalledTemplateCircle; + WalledTemplateShape.shapeCodeRegister.set("circle", shapeCl); + } + }); + // ----- NOTE: Submenu ---- // for ( const shape of SHAPE_KEYS ) { diff --git a/scripts/template_shapes/WalledTemplateCircle.js b/scripts/template_shapes/WalledTemplateCircle.js index 995e012..83c0ad0 100644 --- a/scripts/template_shapes/WalledTemplateCircle.js +++ b/scripts/template_shapes/WalledTemplateCircle.js @@ -32,7 +32,7 @@ export class WalledTemplateCircle extends WalledTemplateShape { calculateOriginalShape({ distance } = {}) { // Convert to degrees and grid units for Foundry method. distance ??= this.distance; - distance = CONFIG.GeometryLib.utils.pixelsToGridUnits(distance); + distance = CONFIG.GeometryLib.utils.pixelsToGridUnits(distance); return CONFIG.MeasuredTemplate.objectClass.getCircleShape(distance); // Pad the circle by one pixel so it better covers expected grid spaces? // (Rounding tends to drop spaces on the edge.) diff --git a/scripts/template_shapes/WalledTemplateRotatedSquare.js b/scripts/template_shapes/WalledTemplateRotatedSquare.js new file mode 100644 index 0000000..bd539cf --- /dev/null +++ b/scripts/template_shapes/WalledTemplateRotatedSquare.js @@ -0,0 +1,74 @@ +/* globals +CONFIG, +PIXI +*/ +/* eslint no-unused-vars: ["error", { "argsIgnorePattern": "^_" }] */ +"use strict"; + +import { WalledTemplateCircle } from "./WalledTemplateCircle.js"; + +export class WalledTemplateRotatedSquare extends WalledTemplateCircle { + + /** + * Square centered on an origin point. + * See dndHelpers for original: + * https://github.com/trioderegion/dnd5e-helpers/blob/342548530088f929d5c243ad2c9381477ba072de/scripts/modules/TemplateScaling.js#L91 + * Conforms with 5-5-5 diagonal rule. + * @param {object} [opts] Optional values to temporarily override the ones in this instance. + * @returns {PIXI.Rectangle} + */ + calculateOriginalShape({ distance, direction } = {}) { + // distance ??= this.distance; + + // Convert to degrees and grid units for Foundry method. + // distance = CONFIG.GeometryLib.utils.pixelsToGridUnits(distance); + + // TODO: Redo for v12's grid settings. + // Based on 5-5-5, the square's width should equate to the circle's diameter. + // (Consider the diameter of the circle in the X-Y directions.) + distance ??= this.distance; + const dist2 = distance * 2; + + direction ??= this.direction; + const rect = new PIXI.Rectangle(-distance, -distance, dist2, dist2); + const poly = rotatePolygon(rect.toPolygon(), direction, new PIXI.Point(0, 0)); + return poly; + } +} + + +/** + * Rotate a polygon a given amount clockwise, in radians. + * @param {PIXI.Polygon} poly The polygon + * @param {number} rotation The amount to rotate clockwise in radians + * @param {number} [centroid] Center of the polygon + */ +function rotatePolygon(poly, rotation = 0, centroid) { + if ( !rotation ) return poly; + centroid ??= poly.center; + + // Translate to 0,0, rotate, translate back based on centroid. + const Matrix = CONFIG.GeometryLib.Matrix; + const rot = Matrix.rotationZ(rotation, false); + const trans = Matrix.translation(-centroid.x, -centroid.y); + const revTrans = Matrix.translation(centroid.x, centroid.y); + const M = trans.multiply3x3(rot).multiply3x3(revTrans); + + // Multiply by the points of the polygon. + const nPoints = poly.points.length * 0.5; + const arr = new Array(nPoints); + for ( let i = 0; i < nPoints; i += 1 ) { + const j = i * 2; + arr[i] = [poly.points[j], poly.points[j+1], 1]; + } + const polyM = new Matrix(arr); + const rotatedM = polyM.multiply(M); + + const rotatedPoints = new Array(poly.points.length); + for ( let i = 0; i < nPoints; i += 1 ) { + const j = i * 2; + rotatedPoints[j] = rotatedM.arr[i][0]; + rotatedPoints[j+1] = rotatedM.arr[i][1]; + } + return new PIXI.Polygon(rotatedPoints); +} diff --git a/scripts/template_shapes/WalledTemplateSquare.js b/scripts/template_shapes/WalledTemplateSquare.js index 6b4bd93..7cb365e 100644 --- a/scripts/template_shapes/WalledTemplateSquare.js +++ b/scripts/template_shapes/WalledTemplateSquare.js @@ -18,10 +18,10 @@ export class WalledTemplateSquare extends WalledTemplateCircle { * @returns {PIXI.Rectangle} */ calculateOriginalShape({ distance } = {}) { - distance ??= this.distance; + // distance ??= this.distance; // Convert to degrees and grid units for Foundry method. - distance = CONFIG.GeometryLib.utils.pixelsToGridUnits(distance); + // distance = CONFIG.GeometryLib.utils.pixelsToGridUnits(distance); // TODO: Redo for v12's grid settings. // Based on 5-5-5, the square's width should equate to the circle's diameter. From b2b3a9b6a93c171d6e72731b54089bced465b96a Mon Sep 17 00:00:00 2001 From: Michael Enion Date: Tue, 5 Nov 2024 13:30:44 -0800 Subject: [PATCH 3/4] =?UTF-8?q?=E2=9C=8F=EF=B8=8F=20docs|Changelog|Add=20v?= =?UTF-8?q?0.8.2=20notes?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Changelog.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Changelog.md b/Changelog.md index f156ba1..2ba5eb5 100644 --- a/Changelog.md +++ b/Changelog.md @@ -1,3 +1,7 @@ +## 0.8.2 +Add module config and template config settings to modify how snap-to-grid works. Also added to dnd5e spell config, but this will not affect template previews in dnd5e until [PR](https://github.com/foundryvtt/dnd5e/pull/4649) is accepted. #116. +Add module config to use a rotating square instead of a circle template. #118. + ## 0.8.1 Dnd5e v4 compatibility. #128. Tidy sheets compatibility. #129. Thanks @morepurplemorebetter! From 2a4854f492cbdaa0c2f566ef621655723b757493 Mon Sep 17 00:00:00 2001 From: Michael Enion Date: Tue, 5 Nov 2024 13:34:15 -0800 Subject: [PATCH 4/4] =?UTF-8?q?=E2=9C=8F=EF=B8=8F=20docs|Change=20Dialog|D?= =?UTF-8?q?escribe=20the=20new=20features?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- scripts/changelog.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/scripts/changelog.js b/scripts/changelog.js index a099163..7fa081d 100644 --- a/scripts/changelog.js +++ b/scripts/changelog.js @@ -196,6 +196,20 @@ Hooks.once("ready", () => { (Sorry, you may need to update the template elevation manually if you had relied on the walled template elevation previously.)` }) + .addEntry({ + version: "0.8.2", + title: "Snap-to-grid and Square Circles", + body: `\ + In the default template settings, you can now set how snap-to-grid works for each template shape. + As with other defaults, you can modify this on a per-template basis in the template configuration. + + If you are using dnd5e, you can also modify the snap settings on a per-spell basis. Unfortunately, + the preview template will not respect this setting until this PR is accepted. + https://github.com/foundryvtt/dnd5e/pull/4649 + + I also added an option, in the module configuration, to use rotating squares instead of circles.` + }) + .build() ?.render(true); });