Compare commits

..

13 Commits

Author SHA1 Message Date
Manuel Vögele fa581ddfc3 Release v1.11.3 2022-02-03 18:23:35 +01:00
Manuel Vögele 56e15be4ca Don't perform pathfinding on other player's rulers 2022-02-03 17:59:35 +01:00
Manuel Vögele 1509307313 Show the setting for automatic pathfinding to players if they are allowed to use pathfinding 2022-02-03 17:59:09 +01:00
Manuel Vögele 68885385ea Formatting fix 2022-02-03 17:42:35 +01:00
Manuel Vögele 6748617f6a Add "DnD5e Drag Ruler Integration" and "Shadow of the Demon Lord" to list of Drag Ruler integraion 2022-02-01 20:57:44 +01:00
Manuel Vögele 9d5dccb504 Release v1.11.2 2022-02-01 11:35:46 +01:00
Manuel Vögele a252da620a Always allow the GM to use pathfinding 2022-02-01 11:33:33 +01:00
Johannes Loher 41c8979925 Add support for Dungeonslayers 4 (#146) 2022-02-01 10:32:54 +01:00
Manuel Vögele 39f9204fa7 Destroy labels that are no longer used 2022-02-01 02:58:55 +01:00
Manuel Vögele 10633e4e2a Add .gitignore 2022-01-30 14:28:02 +01:00
Manuel Vögele f3e1492edd Release v1.11.1 2022-01-30 10:55:10 +01:00
Manuel Vögele 7ac1c828b6 Perform pathfinding on grid-corner to grid-corner basis for tokens with size divisible by two (fixes #144) 2022-01-30 10:51:58 +01:00
Manuel Vögele 1972498b05 Avoid unnecessary diagonal calculation on hex grids 2022-01-30 10:16:19 +01:00
13 changed files with 88 additions and 39 deletions
+1
View File
@@ -0,0 +1 @@
foundry-*.js
+22
View File
@@ -1,3 +1,25 @@
## 1.11.3
### Bugfixes
- The setting to automatically start pathfinding is now visible to players again (this was a regression introduced in 1.11.2)
- Fixed a bug that would show the measurements of other players as if they were using the pathfinder, even if they were not using it.
## 1.11.2
### Bugfixes
- Fixed a memory leak that could cause the rule to slow down after using the pathfinding functionality for a while
### Misc
- GMs are now always allowed to use the pathfinding tool. The setting now only prevents players from using it.
### Compatibility
- Drag Ruler's generic speed provider is now aware of good defaults for Dungeonslayers 4
## 1.11.1
### Bugfixes
- Fixed a bug that would cause the pathfinding algorithm to make tokens of size 2 and 4 to take an unnecessary step
## 1.11.0 ## 1.11.0
### New features ### New features
- Drag Ruler now supports pathfinding. Pressing the assigned button will automatically calculate the shortest route to the point you're dragging your token to and add the necessary waypoints to the ruler. - Drag Ruler now supports pathfinding. Pressing the assigned button will automatically calculate the shortest route to the point you're dragging your token to and add the necessary waypoints to the ruler.
+2
View File
@@ -37,6 +37,7 @@ Drag Ruler will work with all Foundry VTT game systems. However, some game syste
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)
- DnD5e (via the module [DnD5e Drag Ruler Integration](https://foundryvtt.com/packages/elevation-drag-ruler))
- GURPS 4th Edition Game Aid (Unofficial) (starting with version 0.9.1) - GURPS 4th Edition Game Aid (Unofficial) (starting with version 0.9.1)
- Ironclaw Second Edition (starting with version 0.2.2) - Ironclaw Second Edition (starting with version 0.2.2)
- Lancer (via the module [Lancer Speed Provider](https://foundryvtt.com/packages/lancer-speed-provider)) - Lancer (via the module [Lancer Speed Provider](https://foundryvtt.com/packages/lancer-speed-provider))
@@ -44,6 +45,7 @@ The game systems that offer Drag Ruler integration are:
- Pathfinder 1 (starting with version 0.77.3) - Pathfinder 1 (starting with version 0.77.3)
- Pathfinder 2e (via the module [PF2E Drag Ruler Integration](https://foundryvtt.com/packages/pf2e-dragruler/)) - Pathfinder 2e (via the module [PF2E Drag Ruler Integration](https://foundryvtt.com/packages/pf2e-dragruler/))
- Shadowrun 5th Edition (via the module [Drag Ruler Integration for Shadowrun 5E](https://foundryvtt.com/packages/drag-ruler-integration-for-shadowrun-5e)) - Shadowrun 5th Edition (via the module [Drag Ruler Integration for Shadowrun 5E](https://foundryvtt.com/packages/drag-ruler-integration-for-shadowrun-5e))
- Shadow of the Demon Lord (starting with version 1.7.15)
- Starfinder (via the module [Starfinder Drag Ruler Integration](https://foundryvtt.com/packages/starfinder-drag-ruler)) - Starfinder (via the module [Starfinder Drag Ruler Integration](https://foundryvtt.com/packages/starfinder-drag-ruler))
- Stargate RPG (starting with version 1.6.0) - Stargate RPG (starting with version 1.6.0)
- Symbaroum (via the module [Symbaroum drag ruler integration](https://foundryvtt.com/packages/symbaroum-drag-ruler-integration)) - Symbaroum (via the module [Symbaroum drag ruler integration](https://foundryvtt.com/packages/symbaroum-drag-ruler-integration))
+2 -2
View File
@@ -48,8 +48,8 @@
}, },
"settings": { "settings": {
"allowPathfinding": { "allowPathfinding": {
"name": "Wegfindung aktivieren", "name": "Wegfindung für Spieler erlauben",
"hint": "Aktiviert Drag Ruler's Wegfindungsfunktion. Bitte beachte, dass die Wegfindung Wege durch unerkundeten Nebel des Kriegs und Ätherische Wände berechnen kann. Dies kann deinen Spielern Geheimnisse lüften, von denen sie noch nicht erfahren sollten." "hint": "Erlaubt es Spielern die Wegfindungs zu benutzen. Bitte beachte, dass die Wegfindung Wege durch unerkundeten Nebel des Kriegs und Ätherische Wände berechnen kann. Dies kann deinen Spielern Geheimnisse lüften, von denen sie noch nicht erfahren sollten."
}, },
"alwaysShowSpeedForPCs": { "alwaysShowSpeedForPCs": {
"name": "Geschwindigkeit von Spielercharakteren für jeden anzeigen", "name": "Geschwindigkeit von Spielercharakteren für jeden anzeigen",
+2 -2
View File
@@ -48,8 +48,8 @@
}, },
"settings": { "settings": {
"allowPathfinding": { "allowPathfinding": {
"name": "Enable pathfinding feature", "name": "Allow pathfinding for players",
"hint": "Enables Drag Ruler's pathfinding functionality in this world. Be aware that pathfinding can route through unexplored fog of war and Ethereal Walls, which might reveal secrets to your players ahead of time." "hint": "Allows players to use Drag Ruler's pathfinding functionality in this world. Be aware that pathfinding can route through unexplored fog of war and Ethereal Walls, which might reveal secrets to your players ahead of time."
}, },
"alwaysShowSpeedForPCs": { "alwaysShowSpeedForPCs": {
"name": "Show PC speed to everyone", "name": "Show PC speed to everyone",
+2 -2
View File
@@ -2,7 +2,7 @@
"name": "drag-ruler", "name": "drag-ruler",
"title": "Drag Ruler", "title": "Drag Ruler",
"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.11.0", "version": "1.11.3",
"minimumCoreVersion" : "9.245", "minimumCoreVersion" : "9.245",
"compatibleCoreVersion" : "9", "compatibleCoreVersion" : "9",
"authors": [ "authors": [
@@ -65,7 +65,7 @@
], ],
"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.11.0.zip", "download": "https://github.com/manuelVo/foundryvtt-drag-ruler/archive/v1.11.3.zip",
"manifest": "https://raw.githubusercontent.com/manuelVo/foundryvtt-drag-ruler/master/module.json", "manifest": "https://raw.githubusercontent.com/manuelVo/foundryvtt-drag-ruler/master/module.json",
"readme": "https://github.com/manuelVo/foundryvtt-drag-ruler/blob/master/README.md", "readme": "https://github.com/manuelVo/foundryvtt-drag-ruler/blob/master/README.md",
"changelog": "https://github.com/manuelVo/foundryvtt-drag-ruler/blob/master/CHANGELOG.md", "changelog": "https://github.com/manuelVo/foundryvtt-drag-ruler/blob/master/CHANGELOG.md",
+7 -5
View File
@@ -1,12 +1,12 @@
import {highlightMeasurementTerrainRuler, measureDistances} from "./compatibility.js"; import {highlightMeasurementTerrainRuler, measureDistances} from "./compatibility.js";
import {getCenterFromGridPositionObj, getGridPositionFromPixels, getGridPositionFromPixelsObj} from "./foundry_fixes.js"; import {getGridPositionFromPixels, getGridPositionFromPixelsObj, getPixelsFromGridPositionObj} from "./foundry_fixes.js";
import {Line} from "./geometry.js"; import {Line} from "./geometry.js";
import {disableSnap, moveWithoutAnimation} from "./keybindings.js"; import {disableSnap, moveWithoutAnimation} from "./keybindings.js";
import {trackRays} from "./movement_tracking.js" import {trackRays} from "./movement_tracking.js"
import {findPath, isPathfindingEnabled} from "./pathfinding.js"; import {findPath, isPathfindingEnabled} from "./pathfinding.js";
import {settingsKey} from "./settings.js"; import {settingsKey} from "./settings.js";
import {recalculate} from "./socket.js"; import {recalculate} from "./socket.js";
import {applyTokenSizeOffset, enumeratedZip, getSnapPointForEntity, getSnapPointForToken, getTokenShape, highlightTokenShape, sum} from "./util.js"; import {applyTokenSizeOffset, enumeratedZip, getSnapPointForEntity, getSnapPointForToken, getSnapPointForTokenObj, getTokenShape, highlightTokenShape, sum} from "./util.js";
// This is a modified version of Ruler.moveToken from foundry 0.7.9 // This is a modified version of Ruler.moveToken from foundry 0.7.9
export async function moveEntities(draggedEntity, selectedEntities) { export async function moveEntities(draggedEntity, selectedEntities) {
@@ -168,10 +168,12 @@ export function measure(destination, options={}) {
this.dragRulerRemovePathfindingWaypoints(); this.dragRulerRemovePathfindingWaypoints();
if (isToken && isPathfindingEnabled()) { if (isToken && isPathfindingEnabled.call(this)) {
let path = findPath(getGridPositionFromPixelsObj(this.waypoints[this.waypoints.length - 1]), getGridPositionFromPixelsObj(destination), this.waypoints); const from = getGridPositionFromPixelsObj(this.waypoints[this.waypoints.length - 1]);
const to = getGridPositionFromPixelsObj(destination);
let path = findPath(from, to, this.draggedEntity, this.waypoints);
if (path) { if (path) {
path = path.map(point => getCenterFromGridPositionObj(point)) path = path.map(point => getSnapPointForTokenObj(getPixelsFromGridPositionObj(point), this.draggedEntity));
// If the token is snapped to the grid, the first point of the path is already handled by the ruler // If the token is snapped to the grid, the first point of the path is already handled by the ruler
if (path[0].x === this.waypoints[this.waypoints.length - 1].x && path[0].y === this.waypoints[this.waypoints.length - 1].y) if (path[0].x === this.waypoints[this.waypoints.length - 1].x && path[0].y === this.waypoints[this.waypoints.length - 1].y)
+8 -9
View File
@@ -52,15 +52,14 @@ export function registerKeybindings() {
precedence: -1, precedence: -1,
}); });
if (game.settings.get(settingsKey, "allowPathfinding")) { game.keybindings.register(settingsKey, "togglePathfinding", {
game.keybindings.register(settingsKey, "togglePathfinding", { name: "drag-ruler.keybindings.togglePathfinding.name",
name: "drag-ruler.keybindings.togglePathfinding.name", hint: "drag-ruler.keybindings.togglePathfinding.hint",
hint: "drag-ruler.keybindings.togglePathfinding.hint", onDown: handleTogglePathfinding,
onDown: handleTogglePathfinding, onUp: handleTogglePathfinding,
onUp: handleTogglePathfinding, precedence: -1,
precedence: -1, restricted: !game.settings.get(settingsKey, "allowPathfinding"),
}); });
}
} }
function handleDeleteWaypoint() { function handleDeleteWaypoint() {
+25 -17
View File
@@ -1,30 +1,32 @@
import {getCenterFromGridPositionObj, getGridPositionFromPixelsObj} from "./foundry_fixes.js"; import {getGridPositionFromPixelsObj, getPixelsFromGridPositionObj} from "./foundry_fixes.js";
import {togglePathfinding} from "./keybindings.js"; import {togglePathfinding} from "./keybindings.js";
import {debugGraphics} from "./main.js"; import {debugGraphics} from "./main.js";
import {settingsKey} from "./settings.js"; import {settingsKey} from "./settings.js";
import {iterPairs} from "./util.js"; import {getSnapPointForTokenObj, iterPairs} from "./util.js";
let cachedNodes = undefined; let cachedNodes = undefined;
let use5105 = false; let use5105 = false;
export function isPathfindingEnabled() { export function isPathfindingEnabled() {
if (this.user !== game.user)
return false;
if (canvas.grid.type === CONST.GRID_TYPES.GRIDLESS) if (canvas.grid.type === CONST.GRID_TYPES.GRIDLESS)
return false; return false;
if (!game.settings.get(settingsKey, "allowPathfinding")) if (!game.user.isGM && !game.settings.get(settingsKey, "allowPathfinding"))
return false; return false;
return game.settings.get(settingsKey, "autoPathfinding") != togglePathfinding; return game.settings.get(settingsKey, "autoPathfinding") != togglePathfinding;
} }
export function findPath(from, to, previousWaypoints) { export function findPath(from, to, token, previousWaypoints) {
const lastNode = calculatePath(from, to, previousWaypoints); const lastNode = calculatePath(from, to, token, previousWaypoints);
if (!lastNode) if (!lastNode)
return null; return null;
paintPathfindingDebug(lastNode); paintPathfindingDebug(lastNode, token);
const path = []; const path = [];
let currentNode = lastNode; let currentNode = lastNode;
while (currentNode) { while (currentNode) {
// TODO Check if the distance doesn't change // TODO Check if the distance doesn't change
if (path.length >= 2 && !canvas.walls.checkCollision(new Ray(getCenterFromGridPositionObj(currentNode.node), getCenterFromGridPositionObj(path[path.length - 2])))) if (path.length >= 2 && !stepCollidesWithWall(currentNode.node, path[path.length - 2], token))
// Replace last waypoint if the current waypoint leads to a valid path // Replace last waypoint if the current waypoint leads to a valid path
path[path.length - 1] = {x: currentNode.node.x, y: currentNode.node.y}; path[path.length - 1] = {x: currentNode.node.x, y: currentNode.node.y};
else else
@@ -38,14 +40,14 @@ export function wipePathfindingCache() {
cachedNodes = undefined; cachedNodes = undefined;
} }
function getNode(pos, initialize=true) { function getNode(pos, token, initialize=true) {
pos = {layer: 0, ...pos}; // Copy pos and set pos.layer to the default value if it's unset pos = {layer: 0, ...pos}; // Copy pos and set pos.layer to the default value if it's unset
if (!cachedNodes) if (!cachedNodes)
cachedNodes = new Array(2); cachedNodes = new Array(2);
if (!cachedNodes[pos.layer]) if (!cachedNodes[pos.layer])
cachedNodes[pos.layer] = new Array(Math.ceil(canvas.dimensions.height / canvas.grid.h)); cachedNodes[pos.layer] = new Array(Math.ceil(canvas.dimensions.height / canvas.grid.h));
if (!cachedNodes[pos.layer][pos.y]) if (!cachedNodes[pos.layer][pos.y])
cachedNodes[pos.layer][pos.y] = new Array(Math.ceil(canvas.dimensions.width / canvas.grid.w)); cachedNodes[pos.layer][pos.y] = new Array(Math.ceil(canvas.dimensions.width / canvas.grid.w));
if (!cachedNodes[pos.layer][pos.y][pos.x]) { if (!cachedNodes[pos.layer][pos.y][pos.x]) {
cachedNodes[pos.layer][pos.y][pos.x] = pos; cachedNodes[pos.layer][pos.y][pos.x] = pos;
} }
@@ -57,12 +59,12 @@ function getNode(pos, initialize=true) {
if (neighborPos.x < 0 || neighborPos.y < 0) if (neighborPos.x < 0 || neighborPos.y < 0)
continue; continue;
// TODO Work with pixels instead of grid locations // TODO Work with pixels instead of grid locations
if (!canvas.walls.checkCollision(new Ray(getCenterFromGridPositionObj(pos), getCenterFromGridPositionObj(neighborPos)))) { if (!stepCollidesWithWall(pos, neighborPos, token)) {
const isDiagonal = node.x !== neighborPos.x && node.y !== neighborPos.y && canvas.grid.type === CONST.GRID_TYPES.SQUARE; const isDiagonal = node.x !== neighborPos.x && node.y !== neighborPos.y && canvas.grid.type === CONST.GRID_TYPES.SQUARE;
let targetLayer = pos.layer; let targetLayer = pos.layer;
if (use5105 && isDiagonal) if (use5105 && isDiagonal)
targetLayer = 1 - targetLayer; targetLayer = 1 - targetLayer;
const neighbor = getNode({...neighborPos, layer: targetLayer}, false); const neighbor = getNode({...neighborPos, layer: targetLayer}, token, false);
// TODO We currently assume a cost of one or two for all transitions. Change this for difficult terrain support // TODO We currently assume a cost of one or two for all transitions. Change this for difficult terrain support
let edgeCost = 1; let edgeCost = 1;
@@ -77,17 +79,17 @@ function getNode(pos, initialize=true) {
return node; return node;
} }
function calculatePath(from, to, previousWaypoints) { function calculatePath(from, to, token, previousWaypoints) {
if (game.system.id === "pf2e") if (game.system.id === "pf2e")
use5105 = true; use5105 = true;
if (canvas.grid.diagonalRule === "5105") if (canvas.grid.diagonalRule === "5105")
use5105 = true; use5105 = true;
let startLayer = 0; let startLayer = 0;
if (use5105) { if (use5105 && canvas.grid.type === CONST.GRID_TYPES.SQUARE) {
previousWaypoints = previousWaypoints.map(w => getGridPositionFromPixelsObj(w)); previousWaypoints = previousWaypoints.map(w => getGridPositionFromPixelsObj(w));
startLayer = calcNoDiagonals(previousWaypoints) % 2; startLayer = calcNoDiagonals(previousWaypoints) % 2;
} }
const nextNodes = [{node: getNode({...to, layer: startLayer}), cost: 0, estimated: estimateCost(to, from), previous: null}]; const nextNodes = [{node: getNode({...to, layer: startLayer}, token), cost: 0, estimated: estimateCost(to, from), previous: null}];
const previousNodes = new Set(); const previousNodes = new Set();
while (nextNodes.length > 0) { while (nextNodes.length > 0) {
// Sort by estimated cost, high to low // Sort by estimated cost, high to low
@@ -99,7 +101,7 @@ function calculatePath(from, to, previousWaypoints) {
return currentNode; return currentNode;
previousNodes.add(currentNode.node); previousNodes.add(currentNode.node);
for (const edge of currentNode.node.edges) { for (const edge of currentNode.node.edges) {
const neighborNode = getNode(edge.target); const neighborNode = getNode(edge.target, token);
if (previousNodes.has(neighborNode)) if (previousNodes.has(neighborNode))
continue; continue;
const neighbor = {node: neighborNode, cost: currentNode.cost + edge.cost, estimated: currentNode.cost + edge.cost + estimateCost(neighborNode, from), previous: currentNode}; const neighbor = {node: neighborNode, cost: currentNode.cost + edge.cost, estimated: currentNode.cost + edge.cost + estimateCost(neighborNode, from), previous: currentNode};
@@ -129,7 +131,13 @@ function estimateCost(pos, target) {
return Math.max(Math.abs(pos.x - target.x), Math.abs(pos.y - target.y)); return Math.max(Math.abs(pos.x - target.x), Math.abs(pos.y - target.y));
} }
function paintPathfindingDebug(lastNode) { function stepCollidesWithWall(from, to, token) {
const stepStart = getSnapPointForTokenObj(getPixelsFromGridPositionObj(from), token);
const stepEnd = getSnapPointForTokenObj(getPixelsFromGridPositionObj(to), token);
return canvas.walls.checkCollision(new Ray(stepStart, stepEnd));
}
function paintPathfindingDebug(lastNode, token) {
if (!CONFIG.debug.dragRuler) if (!CONFIG.debug.dragRuler)
return; return;
@@ -137,7 +145,7 @@ function paintPathfindingDebug(lastNode) {
let currentNode = lastNode; let currentNode = lastNode;
while (currentNode) { while (currentNode) {
let text = new PIXI.Text(currentNode.cost.toFixed(0)); let text = new PIXI.Text(currentNode.cost.toFixed(0));
let pixels = getCenterFromGridPositionObj(currentNode.node); let pixels = getSnapPointForTokenObj(getPixelsFromGridPositionObj(currentNode.node), token);
text.anchor.set(0.5, 1.0); text.anchor.set(0.5, 1.0);
text.x = pixels.x; text.x = pixels.x;
text.y = pixels.y; text.y = pixels.y;
+1 -1
View File
@@ -116,7 +116,7 @@ export function extendRuler() {
} }
dragRulerRemovePathfindingWaypoints() { dragRulerRemovePathfindingWaypoints() {
this.waypoints.filter(waypoint => waypoint.isPathfinding).forEach(_ => this.labels.removeChild(this.labels.children.pop())); this.waypoints.filter(waypoint => waypoint.isPathfinding).forEach(_ => this.labels.removeChild(this.labels.children[this.labels.children.length - 1]).destroy());
this.waypoints = this.waypoints.filter(waypoint => !waypoint.isPathfinding); this.waypoints = this.waypoints.filter(waypoint => !waypoint.isPathfinding);
} }
+2 -1
View File
@@ -1,5 +1,6 @@
import {availableSpeedProviders, currentSpeedProvider, getDefaultSpeedProvider, updateSpeedProvider} from "./api.js"; import {availableSpeedProviders, currentSpeedProvider, getDefaultSpeedProvider, updateSpeedProvider} from "./api.js";
import {SpeedProvider} from "./speed_provider.js" import {SpeedProvider} from "./speed_provider.js"
import { early_isGM } from "./util.js";
export const settingsKey = "drag-ruler"; export const settingsKey = "drag-ruler";
@@ -96,7 +97,7 @@ export function registerSettings() {
name: "drag-ruler.settings.autoPathfinding.name", name: "drag-ruler.settings.autoPathfinding.name",
hint: "drag-ruler.settings.autoPathfinding.hint", hint: "drag-ruler.settings.autoPathfinding.hint",
scpoe: "client", scpoe: "client",
config: true, config: early_isGM() || game.settings.get(settingsKey, "allowPathfinding"),
type: Boolean, type: Boolean,
defualt: false, defualt: false,
}); });
+3
View File
@@ -17,6 +17,8 @@ export function getDefaultSpeedAttribute() {
return "actor.data.data.movement.walk.value"; return "actor.data.data.movement.walk.value";
case "swade": case "swade":
return "actor.data.data.stats.speed.adjusted"; return "actor.data.data.stats.speed.adjusted";
case "ds4":
return "actor.data.data.combatValues.movement.total";
} }
return "" return ""
} }
@@ -32,6 +34,7 @@ export function getDefaultDashMultiplier() {
case "D35E": case "D35E":
case "sfrpg": case "sfrpg":
case "shadowrun5e": case "shadowrun5e":
case "ds4":
return 2 return 2
case "CoC7": case "CoC7":
return 5; return 5;
+11
View File
@@ -86,6 +86,10 @@ export function getSnapPointForToken(x, y, token) {
return new PIXI.Point(snapX, snapY); return new PIXI.Point(snapX, snapY);
} }
export function getSnapPointForTokenObj(pos, token) {
return getSnapPointForToken(pos.x, pos.y, token);
}
export function getSnapPointForMeasuredTemplate(x, y) { export function getSnapPointForMeasuredTemplate(x, y) {
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);
@@ -268,3 +272,10 @@ export function getMeasurePosition() {
const measurePosition = {x: mousePosition.x + rulerOffset.x, y: mousePosition.y + rulerOffset.y}; const measurePosition = {x: mousePosition.x + rulerOffset.x, y: mousePosition.y + rulerOffset.y};
return measurePosition; return measurePosition;
} }
// isGM function for use during loading when game.user isn't available yet
export function early_isGM() {
const level = game.data.users.find(u => u._id == game.data.userId).role;
const gmLevel = CONST.USER_ROLES.ASSISTANT;
return level >= gmLevel;
}