Compare commits

..

2 Commits

Author SHA1 Message Date
Manuel Vögele 605f4371e6 1.8.3-alpha1 2021-11-17 12:17:00 +01:00
Manuel Vögele 0ad03ad5f7 Create alpha branch 2021-11-17 12:17:00 +01:00
16 changed files with 51 additions and 183 deletions
-21
View File
@@ -1,24 +1,3 @@
## 1.9.1
### Bugfixes
- Fixed a bug that caused the ruler to misbehave or not show up at all if the speed provider isn't configured (this was a regression introduced in 1.9.0)
### Translation
- Updated the spaish translation (thanks to Viriato139ac#342)
## 1.9.0
### New features
- On Gridless scenes, tokens can now snap to their speed limits, to make full usage of a token's movement speed easier. This feature can be temporarily disabled by pressing Shift during drag and can be disabled completely in the settings.
### Bugfixes
- Non-square tokens (e.g. 2x1) now work correctly on square grids
- When modifying difficult terrain that a token has already moved over, this the movement history of the token won't change anymore (this was a regression introduced in 1.8.0)
- Fixed a bug that prevented pausing/unpausing the game when no scene was active
### API
- Added `dragRuler.getColorForDistanceAndToken` API endpoint that allows other modules to receive the highlight color for a specified distance with a given token.
## 1.8.2 ## 1.8.2
### Compatibility ### Compatibility
- The generic speed provider defaults have been updated for lance 1.0 (thanks to BoltsJ!) - The generic speed provider defaults have been updated for lance 1.0 (thanks to BoltsJ!)
+2 -2
View File
@@ -1,7 +1,7 @@
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/staebchenfisch) [![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/staebchenfisch)
# Drag Ruler # Drag Ruler
This module shows a ruler when you drag a token or measurement template to inform you how far you've dragged it from its start point. Additionally, if you're using a grid, the spaces the token will travel though will be colored depending on your tokens speed. By default, three colors are being used: green for spaces that your token can reach by walking normally are colored green, spaces that can only be reached by dashing will be colored yellow and spaces that cannot be reached with the token's speed will be colored red. If you're using a gridless map the ruler color will change to convey this information. This module shows a ruler when you drag a token or measurement template to infrom you how far you've dragged it from it's start point. Additionally, if you're using a grid, the spaces the token will travel though will be colored depending on your tokens speed. By default three colors are being used: green for spaces that your token can reach by walking normally are colored green, spaces that can only be reached by dashing will be colored red and spaces that cannot be reached with the token's speed will be colored red. If you're using a gridless map the ruler color will change to convey this information.
![Drag Ruler being used on a square grids](https://raw.githubusercontent.com/manuelVo/foundryvtt-drag-ruler/709774b25f7dd818a90591165f74b3e6dbc788cc/media/basic_square.webp) ![Drag Ruler being used on a square grids](https://raw.githubusercontent.com/manuelVo/foundryvtt-drag-ruler/709774b25f7dd818a90591165f74b3e6dbc788cc/media/basic_square.webp)
![Drag Ruler being used on a gridless scene](https://raw.githubusercontent.com/manuelVo/foundryvtt-drag-ruler/709774b25f7dd818a90591165f74b3e6dbc788cc/media/basic_gridless.webp) ![Drag Ruler being used on a gridless scene](https://raw.githubusercontent.com/manuelVo/foundryvtt-drag-ruler/709774b25f7dd818a90591165f74b3e6dbc788cc/media/basic_gridless.webp)
@@ -33,7 +33,7 @@ During combat, Drag Ruler will remember the path a token has taken during it's t
## Game systems with Drag Ruler integration ## Game systems with Drag Ruler integration
Drag Ruler will work with all Foundry VTT game systems. However, some game systems offer a special integration via the [Drag Ruler API](#api), that allows Drag Ruler to take the rules of the game system into account when dispaying speeds (such as weight carried or conditions that apply to the character), offering a smoother experience. While some game systems offer this integration natively, for other game systems there are modules providing the integration. If the integration is provided via a module you need to install and activate both Drag Ruler and the integration module to benefit from the integration. Drag Ruler will work with all Foundry VTT game systems. However some game systems offer a special integration via the [Drag Ruler API](#api), that allows Drag Ruler to take the rules of the game system into account when dispaying speeds (such as weight carried or conditions that apply to the character), offering a smoother experience. While some game systems offer this integration natively, for other game systems there are modules providing the integration. If the integration is provided via a module you need to install and activate both Drag Ruler and the integration module to benefit from the integration.
The game systems that offer Drag Ruler integration are: The game systems that offer Drag Ruler integration are:
- Cypher System (starting with version 1.13.0) - Cypher System (starting with version 1.13.0)
-4
View File
@@ -81,10 +81,6 @@
"swapSpacebarRightClick": { "swapSpacebarRightClick": {
"name": "Leertaste und Rechtsklick tauschen", "name": "Leertaste und Rechtsklick tauschen",
"hint": "Die Funktionen der Leertaste und des Rechtsklicks sind, während eine Spielfigur bewegt wird, vertauscht. Wenn diese Option aktiviert wird können mit Rechtsklick Wegpunkte gesetzt werden und mit der Leertaste werden sie wieder gelöscht." "hint": "Die Funktionen der Leertaste und des Rechtsklicks sind, während eine Spielfigur bewegt wird, vertauscht. Wenn diese Option aktiviert wird können mit Rechtsklick Wegpunkte gesetzt werden und mit der Leertaste werden sie wieder gelöscht."
},
"useGridlessraster": {
"name": "Geschwindigkeitsraster aktivieren",
"hint": "Lässt Spielfiguren auf gitterlosen Szenen an deren Geschwindigkeitsgrenzen einrasten. Dies kann vorübergehend deaktiviert werden, indem während des ziehens die Umschalttaste gedrückt wird."
} }
} }
} }
-4
View File
@@ -81,10 +81,6 @@
"swapSpacebarRightClick": { "swapSpacebarRightClick": {
"name": "Swap spacebar and right click", "name": "Swap spacebar and right click",
"hint": "Swaps the functions of spacebar and right click during dragging. If enabled right click will place waypoints and spacebar will delete them" "hint": "Swaps the functions of spacebar and right click during dragging. If enabled right click will place waypoints and spacebar will delete them"
},
"useGridlessRaster": {
"name": "Use speed based snapping",
"hint": "On Gridless scenes, this makes tokens snap to the token's speed ranges. This can be temporarily disabled by pressing Shift during drag."
} }
} }
} }
-4
View File
@@ -85,10 +85,6 @@
"swapSpacebarRightClick": { "swapSpacebarRightClick": {
"name": "Intercambiar barra espaciadora y clic-derecho", "name": "Intercambiar barra espaciadora y clic-derecho",
"hint": "Cambia el funcionamiento de la barra espaciadora y el clic-derecho del ratón mientras se arrastra un icono. Si está habilitado, clic-derecho establecerá puntos en la ruta y la barra espaciadora los borrará" "hint": "Cambia el funcionamiento de la barra espaciadora y el clic-derecho del ratón mientras se arrastra un icono. Si está habilitado, clic-derecho establecerá puntos en la ruta y la barra espaciadora los borrará"
},
"useGridlessRaster": {
"name": "Usar ajuste a la velocidad",
"hint": "Cuando no se use rejilla en la escena, este ajuste hace que los iconos se ajusten a sus rangos de velocidad. Se puede deshabilitar temporalmente pulsando la tecla Mayús mientras se arrastra"
} }
} }
} }
+8 -8
View File
@@ -1,8 +1,8 @@
{ {
"name": "drag-ruler", "name": "drag-ruler-alpha",
"title": "Drag Ruler", "title": "Drag Ruler (Alpha Branch)",
"description": "When dragging a token displays a ruler showing how far you've moved that token.", "description": "When dragging a token displays a ruler showing how far you've moved that token.",
"version": "1.9.1", "version": "1.8.3-alpha1",
"minimumCoreVersion" : "0.8.5", "minimumCoreVersion" : "0.8.5",
"compatibleCoreVersion" : "0.8.9", "compatibleCoreVersion" : "0.8.9",
"authors": [ "authors": [
@@ -59,10 +59,10 @@
], ],
"socket": true, "socket": true,
"url": "https://github.com/manuelVo/foundryvtt-drag-ruler", "url": "https://github.com/manuelVo/foundryvtt-drag-ruler",
"download": "https://github.com/manuelVo/foundryvtt-drag-ruler/archive/v1.9.1.zip", "download": "https://github.com/manuelVo/foundryvtt-drag-ruler/archive/alpha.zip",
"manifest": "https://raw.githubusercontent.com/manuelVo/foundryvtt-drag-ruler/master/module.json", "manifest": "https://raw.githubusercontent.com/manuelVo/foundryvtt-drag-ruler/alpha/module.json",
"readme": "https://github.com/manuelVo/foundryvtt-drag-ruler/blob/master/README.md", "readme": "https://github.com/manuelVo/foundryvtt-drag-ruler/blob/alpha/README.md",
"changelog": "https://github.com/manuelVo/foundryvtt-drag-ruler/blob/master/CHANGELOG.md", "changelog": "https://github.com/manuelVo/foundryvtt-drag-ruler/blob/alpha/CHANGELOG.md",
"bugs": "https://github.com/manuelVo/foundryvtt-drag-ruler/issues", "bugs": "https://github.com/manuelVo/foundryvtt-drag-ruler/issues",
"allowBugReporter": true "allowBugReporter": false
} }
+2 -3
View File
@@ -121,7 +121,7 @@ export function getColorForDistanceAndToken(distance, token, ranges=null) {
ranges = getRangesFromSpeedProvider(token); ranges = getRangesFromSpeedProvider(token);
} }
if (ranges.length === 0) if (ranges.length === 0)
return null; return this.color;
const currentRange = ranges.reduce((minRange, currentRange) => { const currentRange = ranges.reduce((minRange, currentRange) => {
if (distance <= currentRange.range && currentRange.range < minRange.range) if (distance <= currentRange.range && currentRange.range < minRange.range)
return currentRange; return currentRange;
@@ -131,11 +131,10 @@ export function getColorForDistanceAndToken(distance, token, ranges=null) {
} }
export function getMovedDistanceFromToken(token) { export function getMovedDistanceFromToken(token) {
const terrainRulerAvailable = game.modules.get("terrain-ruler")?.active;
const history = getMovementHistory(token); const history = getMovementHistory(token);
const segments = Ruler.dragRulerGetRaysFromWaypoints(history, {x: token.x, y: token.y}).map(ray => {return {ray}}); const segments = Ruler.dragRulerGetRaysFromWaypoints(history, {x: token.x, y: token.y}).map(ray => {return {ray}});
const shape = getTokenShape(token); const shape = getTokenShape(token);
const distances = measureDistances(segments, token, shape, {enableTerrainRuler: terrainRulerAvailable}); const distances = measureDistances(segments, token, shape);
// Sum up the distances // Sum up the distances
return distances.reduce((acc, val) => acc + val, 0); return distances.reduce((acc, val) => acc + val, 0);
} }
+3
View File
@@ -62,6 +62,9 @@ export function checkDependencies() {
if (game.modules.get("enhanced-terrain-layer")?.active) { if (game.modules.get("enhanced-terrain-layer")?.active) {
enabledTerrainModule = game.modules.get("enhanced-terrain-layer").data.title; enabledTerrainModule = game.modules.get("enhanced-terrain-layer").data.title;
} }
else if (game.modules.get("TerrainLayer")?.active) {
enabledTerrainModule = game.modules.get("TerrainLayer").data.title;
}
if (enabledTerrainModule) { if (enabledTerrainModule) {
new Dialog({ new Dialog({
title: game.i18n.localize("drag-ruler.dependencies.terrain-ruler.title"), title: game.i18n.localize("drag-ruler.dependencies.terrain-ruler.title"),
+1 -1
View File
@@ -168,7 +168,7 @@ export function measure(destination, options={}) {
options.ignoreGrid = false; options.ignoreGrid = false;
} }
options.enableTerrainRuler = isToken && game.modules.get("terrain-ruler")?.active; options.enableTerrainRuler = isToken && game.modules.get("terrain-ruler")?.active && (!game.modules.get("TerrainLayer")?.active || canvas.grid.type !== CONST.GRID_TYPES.GRIDLESS);
const waypoints = this.waypoints.concat([destination]); const waypoints = this.waypoints.concat([destination]);
// Move the waypoints to the center of the grid if a size is used that measures from edge to edge // Move the waypoints to the center of the grid if a size is used that measures from edge to edge
+11 -74
View File
@@ -1,7 +1,7 @@
"use strict" "use strict"
import {currentSpeedProvider, getColorForDistanceAndToken, getMovedDistanceFromToken, getRangesFromSpeedProvider, initApi, registerModule, registerSystem} from "./api.js"; import {currentSpeedProvider, getColorForDistanceAndToken, getMovedDistanceFromToken, initApi, registerModule, registerSystem} from "./api.js";
import {checkDependencies, getHexSizeSupportTokenGridCenter, highlightMeasurementTerrainRuler} from "./compatibility.js"; import {checkDependencies, getHexSizeSupportTokenGridCenter} from "./compatibility.js";
import {moveEntities, onMouseMove} from "./foundry_imports.js" import {moveEntities, onMouseMove} from "./foundry_imports.js"
import {performMigrations} from "./migration.js" import {performMigrations} from "./migration.js"
import {DragRulerRuler} from "./ruler.js"; import {DragRulerRuler} from "./ruler.js";
@@ -32,6 +32,14 @@ Hooks.once("init", () => {
}) })
Hooks.once("ready", () => { Hooks.once("ready", () => {
{
const alphaWarning = "You are using the alpha branch of Drag Ruler. DO NOT USE IT IN PRODUCTION ENVIRONMENTS. This branch is used for pre-release testing. As a result this branch will only be updated sporadically and may be siginificantly newer (or even older) than the main Drag Ruler release branch. In addition this branch is likely to be likely to contain more bugs.";
console.warn(alphaWarning)
ui.notifications.warn(alphaWarning)
if (game.modules.get("drag-ruler")?.active) {
ui.notification.error("You have both the release version and the alpha version of Drag Ruler enabled. Doing so prevents the module from working properly. Please disable either the release or the alpha version of Drag Ruler.", {permanent: true});
}
}
performMigrations() performMigrations()
checkDependencies(); checkDependencies();
Hooks.callAll("dragRuler.ready", SpeedProvider) Hooks.callAll("dragRuler.ready", SpeedProvider)
@@ -66,8 +74,6 @@ function hookDragHandlers(entityType) {
const originalDragLeftMoveHandler = entityType.prototype._onDragLeftMove const originalDragLeftMoveHandler = entityType.prototype._onDragLeftMove
entityType.prototype._onDragLeftMove = function (event) { entityType.prototype._onDragLeftMove = function (event) {
if (entityType === Token)
applyGridlessSnapping.call(this, event);
originalDragLeftMoveHandler.call(this, event) originalDragLeftMoveHandler.call(this, event)
onEntityLeftDragMove.call(this, event) onEntityLeftDragMove.call(this, event)
} }
@@ -151,8 +157,7 @@ function onKeyShift(up) {
function onKeySpace(up) { function onKeySpace(up) {
const ruler = canvas.controls.ruler; const ruler = canvas.controls.ruler;
// Ruler can end up being undefined here if no canvas is active if (!ruler.draggedEntity)
if (!ruler?.draggedEntity)
return false; return false;
if (ruler._state !== Ruler.STATES.INACTIVE) if (ruler._state !== Ruler.STATES.INACTIVE)
@@ -268,71 +273,3 @@ function onEntityDragLeftCancel(event) {
} }
return true return true
} }
function applyGridlessSnapping(event) {
const ruler = canvas.controls.ruler;
if (!game.settings.get(settingsKey, "useGridlessRaster"))
return;
if (!ruler.isDragRuler)
return;
if (game.keyboard.isDown("Shift"))
return;
if (canvas.grid.type !== CONST.GRID_TYPES.GRIDLESS)
return;
const rasterWidth = 35 / canvas.stage.scale.x;
const tokenX = event.data.destination.x;
const tokenY = event.data.destination.y;
const destination = {x: tokenX + ruler.rulerOffset.x, y: tokenY + ruler.rulerOffset.y};
const ranges = getRangesFromSpeedProvider(ruler.draggedEntity);
const terrainRulerAvailable = game.modules.get("terrain-ruler")?.active;
if (terrainRulerAvailable) {
const segments = Ruler.dragRulerGetRaysFromWaypoints(ruler.waypoints, destination).map(ray => {return {ray}});
const pinpointDistances = new Map();
for (const range of ranges) {
pinpointDistances.set(range.range, null);
}
terrainRuler.measureDistances(segments, {pinpointDistances});
const targetDistance = Array.from(pinpointDistances.entries())
.filter(([_key, val]) => val)
.reduce((value, current) => value[0] > current[0] ? value : current, [0, null]);
const rasterLocation = targetDistance[1];
if (rasterLocation) {
const deltaX = destination.x - rasterLocation.x;
const deltaY = destination.y - rasterLocation.y;
const rasterDistance = Math.hypot(deltaX, deltaY);
if (rasterDistance < rasterWidth) {
event.data.destination.x = rasterLocation.x - ruler.rulerOffset.x;
event.data.destination.y = rasterLocation.y - ruler.rulerOffset.y;
}
}
}
else {
let waypointDistance = 0;
let origin = event.data.origin;
if (ruler.waypoints.length > 1) {
const segments = Ruler.dragRulerGetRaysFromWaypoints(ruler.waypoints, destination).map(ray => {return {ray}});
origin = segments.pop().ray.A;
waypointDistance = canvas.grid.measureDistances(segments).reduce((a, b) => a + b);
origin = {x: origin.x - ruler.rulerOffset.x, y: origin.y - ruler.rulerOffset.y};
}
const deltaX = tokenX - origin.x;
const deltaY = tokenY - origin.y;
const distance = Math.hypot(deltaX, deltaY);
// targetRange will be the largest range that's still smaller than distance
let targetDistance = ranges
.map(range => range.range)
.map(range => range - waypointDistance)
.map(range => range * canvas.dimensions.size / canvas.dimensions.distance)
.filter(range => range < distance)
.reduce((a, b) => Math.max(a, b), 0);
if (targetDistance) {
if (distance < targetDistance + rasterWidth) {
event.data.destination.x = origin.x + deltaX * targetDistance / distance;
event.data.destination.y = origin.y + deltaY * targetDistance / distance;
}
}
}
}
+2 -2
View File
@@ -49,14 +49,14 @@ function calculateUpdate(combat, token, rays) {
} }
// Add the passed waypoints to the combatant // Add the passed waypoints to the combatant
const terrainRulerAvailable = game.modules.get("terrain-ruler")?.active; const terrainRulerAvailable = game.modules.get("terrain-ruler")?.active && (!game.modules.get("TerrainLayer")?.active || canvas.grid.type !== CONST.GRID_TYPES.GRIDLESS);
const dragRulerFlags = combatant.data.flags.dragRuler; const dragRulerFlags = combatant.data.flags.dragRuler;
const waypoints = dragRulerFlags.passedWaypoints; const waypoints = dragRulerFlags.passedWaypoints;
for (const ray of rays) { for (const ray of rays) {
// Ignore rays that have the same start and end coordinates // Ignore rays that have the same start and end coordinates
if (ray.A.x !== ray.B.x || ray.A.y !== ray.B.y) { if (ray.A.x !== ray.B.x || ray.A.y !== ray.B.y) {
if (terrainRulerAvailable) { if (terrainRulerAvailable) {
measureDistances([{ray}], token, getTokenShape(token), {terrainRulerInitialState: waypoints[waypoints.length - 1]?.dragRulerFinalState, enableTerrainRuler: terrainRulerAvailable}); measureDistances([{ray}], token, getTokenShape(token), {terrainRulerInitialState: waypoints[waypoints.length - 1]?.dragRulerFinalState});
ray.A.dragRulerVisitedSpaces = ray.terrainRulerVisitedSpaces; ray.A.dragRulerVisitedSpaces = ray.terrainRulerVisitedSpaces;
ray.A.dragRulerFinalState = ray.terrainRulerFinalState; ray.A.dragRulerFinalState = ray.terrainRulerFinalState;
} }
+1 -2
View File
@@ -166,9 +166,8 @@ export class DragRulerRuler extends Ruler {
if (!(this.draggedEntity.actor.data.type === "character" && game.settings.get(settingsKey, "alwaysShowSpeedForPCs"))) if (!(this.draggedEntity.actor.data.type === "character" && game.settings.get(settingsKey, "alwaysShowSpeedForPCs")))
return this.color; return this.color;
} }
distance = Math.round(distance * 100) / 100;
if (!this.dragRulerRanges) if (!this.dragRulerRanges)
this.dragRulerRanges = getRangesFromSpeedProvider(this.draggedEntity); this.dragRulerRanges = getRangesFromSpeedProvider(this.draggedEntity);
return getColorForDistanceAndToken(distance, this.draggedEntity, this.dragRulerRanges) ?? this.color; return getColorForDistanceAndToken(distance, this.draggedEntity, this.dragRulerRanges);
} }
} }
-9
View File
@@ -29,15 +29,6 @@ export function registerSettings() {
default: false, default: false,
}) })
game.settings.register(settingsKey, "useGridlessRaster", {
name: "drag-ruler.settings.useGridlessRaster.name",
hint: "drag-ruler.settings.useGridlessRaster.hint",
scope: "client",
config: true,
type: Boolean,
default: true,
});
game.settings.register(settingsKey, "alwaysShowSpeedForPCs", { game.settings.register(settingsKey, "alwaysShowSpeedForPCs", {
name: "drag-ruler.settings.alwaysShowSpeedForPCs.name", name: "drag-ruler.settings.alwaysShowSpeedForPCs.name",
hint: "drag-ruler.settings.alwaysShowSpeedForPCs.hint", hint: "drag-ruler.settings.alwaysShowSpeedForPCs.hint",
+1 -1
View File
@@ -3,7 +3,7 @@ import {currentSpeedProvider} from "./api.js";
let socket; let socket;
Hooks.once("socketlib.ready", () => { Hooks.once("socketlib.ready", () => {
socket = socketlib.registerModule("drag-ruler"); socket = socketlib.registerModule("drag-ruler-alpha");
socket.register("updateCombatantDragRulerFlags", _socketUpdateCombatantDragRulerFlags); socket.register("updateCombatantDragRulerFlags", _socketUpdateCombatantDragRulerFlags);
socket.register("recalculate", _socketRecalculate); socket.register("recalculate", _socketRecalculate);
}); });
+2 -2
View File
@@ -63,9 +63,9 @@ export class SpeedProvider {
* (1 is regular cost, 2 costs double, 3 costs triple, ...) * (1 is regular cost, 2 costs double, 3 costs triple, ...)
* *
* Parameters: * Parameters:
* - options: An object used to configure Enhanced Terrain Layer's cost calculation. Ex: If options.ignoreGrid is set to true, then Euclidean measurement can be forced on a gridded map. * - options: An object used to configure TerrainLayer's cost calculation. Ex: If options.ignoreGrid is set to true, then Euclidean measurement can be forced on a gridded map.
* *
* This function is only called if the Enhanced Terrain Layer and Terrain Ruler modules are enabled. * This function is only called if the TerrainLayer and TerrainRuler modules are enabled.
* *
* Implementing this method is optional and only needs to be done if you want to provide a custom cost function (for example to allow tokens to ignore difficult terrain) * Implementing this method is optional and only needs to be done if you want to provide a custom cost function (for example to allow tokens to ignore difficult terrain)
*/ */
+16 -44
View File
@@ -10,61 +10,33 @@ export function getSnapPointForToken(x, y, token) {
if (canvas.grid.type === CONST.GRID_TYPES.GRIDLESS) { if (canvas.grid.type === CONST.GRID_TYPES.GRIDLESS) {
return new PIXI.Point(x, y); return new PIXI.Point(x, y);
} }
if (canvas.grid.isHex) { if (canvas.grid.isHex && game.modules.get("hex-size-support")?.active && CONFIG.hexSizeSupport.getAltSnappingFlag(token)) {
if (game.modules.get("hex-size-support")?.active && CONFIG.hexSizeSupport.getAltSnappingFlag(token)) { if (token.document.getFlag("hex-size-support", "borderSize") % 2 === 0) {
if (token.document.getFlag("hex-size-support", "borderSize") % 2 === 0) { const snapPoint = CONFIG.hexSizeSupport.findVertexSnapPoint(x, y, token, canvas.grid.grid)
const snapPoint = CONFIG.hexSizeSupport.findVertexSnapPoint(x, y, token, canvas.grid.grid) return new PIXI.Point(snapPoint.x, snapPoint.y)
return new PIXI.Point(snapPoint.x, snapPoint.y)
}
else {
return new PIXI.Point(...canvas.grid.getCenter(x, y))
}
} }
else { else {
return new PIXI.Point(...canvas.grid.getCenter(x, y)); return new PIXI.Point(...canvas.grid.getCenter(x, y))
} }
} }
const [topLeftX, topLeftY] = canvas.grid.getTopLeft(x, y);
let cellX, cellY;
if (token.data.width % 2 === 0)
cellX = x - canvas.grid.h / 2;
else
cellX = x;
if (token.data.height % 2 === 0)
cellY = y - canvas.grid.h / 2;
else
cellY = y;
const [centerX, centerY] = canvas.grid.getCenter(cellX, cellY);
let snapX, snapY;
// Tiny tokens can snap to the cells corners // Tiny tokens can snap to the cells corners
if (token.data.width <= 0.5) { if (!canvas.grid.isHex && token.data.width <= 0.5) {
const [topLeftX, topLeftY] = canvas.grid.getTopLeft(x, y);
const offsetX = x - topLeftX; const offsetX = x - topLeftX;
const offsetY = y - topLeftY;
const subGridWidth = Math.floor(canvas.grid.w / 2); const subGridWidth = Math.floor(canvas.grid.w / 2);
const subGridHeight = Math.floor(canvas.grid.h / 2);
const subGridPosX = Math.floor(offsetX / subGridWidth); const subGridPosX = Math.floor(offsetX / subGridWidth);
snapX = topLeftX + (subGridPosX + 0.5) * subGridWidth; const subGridPosY = Math.floor(offsetY / subGridHeight);
return new PIXI.Point(topLeftX + (subGridPosX + 0.5) * subGridWidth, topLeftY + (subGridPosY + 0.5) * subGridHeight);
} }
// Tokens with odd multipliers (1x1, 3x3, ...) and tokens smaller than 1x1 but bigger than 0.5x0.5 snap to the center of the grid cell // Hex tokens, tokens with odd multipliers (1x1, 3x3, ...) and tokens smaller than 1x1 but bigger than 0.5x0.5 snap to the center of the grid cell
else if (Math.round(token.data.width) % 2 === 1 || token.data.width < 1) { if (canvas.grid.isHex || Math.round(token.data.width) % 2 === 1 || token.data.width < 1) {
snapX = centerX; return new PIXI.Point(...canvas.grid.getCenter(x, y))
} }
// All remaining tokens (those with even or fractional multipliers on square grids) snap to the intersection points of the grid // All remaining tokens (those with even or fractional multipliers on square grids) snap to the intersection points of the grid
else { const [snappedX, snappedY] = canvas.grid.getCenter(x - canvas.grid.w / 2, y - canvas.grid.h / 2)
snapX = centerX + canvas.grid.w / 2; return new PIXI.Point(snappedX + canvas.grid.w / 2, snappedY + canvas.grid.h / 2)
}
if (token.data.height <= 0.5) {
const offsetY = y - topLeftY;
const subGridHeight = Math.floor(canvas.grid.h / 2);
const subGridPosY = Math.floor(offsetY / subGridHeight);
snapY = topLeftY + (subGridPosY + 0.5) * subGridHeight;
}
else if (Math.round(token.data.height) % 2 === 1 || token.data.height < 1) {
snapY = centerY;
}
else {
snapY = centerY + canvas.grid.h / 2;
}
return new PIXI.Point(snapX, snapY);
} }
export function getSnapPointForMeasuredTemplate(x, y) { export function getSnapPointForMeasuredTemplate(x, y) {