Merge branch 'develop' into pathfinding
This commit is contained in:
@@ -1,3 +1,8 @@
|
||||
## 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
|
||||
### 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.
|
||||
|
||||
+2
-2
@@ -2,7 +2,7 @@
|
||||
"name": "drag-ruler",
|
||||
"title": "Drag Ruler",
|
||||
"description": "When dragging a token displays a ruler showing how far you've moved that token.",
|
||||
"version": "1.11.0",
|
||||
"version": "1.11.1",
|
||||
"minimumCoreVersion" : "9.245",
|
||||
"compatibleCoreVersion" : "9",
|
||||
"authors": [
|
||||
@@ -65,7 +65,7 @@
|
||||
],
|
||||
"socket": true,
|
||||
"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.1.zip",
|
||||
"manifest": "https://raw.githubusercontent.com/manuelVo/foundryvtt-drag-ruler/master/module.json",
|
||||
"readme": "https://github.com/manuelVo/foundryvtt-drag-ruler/blob/master/README.md",
|
||||
"changelog": "https://github.com/manuelVo/foundryvtt-drag-ruler/blob/master/CHANGELOG.md",
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
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 {disableSnap, moveWithoutAnimation} from "./keybindings.js";
|
||||
import {trackRays} from "./movement_tracking.js"
|
||||
import {findPath, isPathfindingEnabled} from "./pathfinding.js";
|
||||
import {settingsKey} from "./settings.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
|
||||
export async function moveEntities(draggedEntity, selectedEntities) {
|
||||
@@ -169,9 +169,11 @@ export function measure(destination, options={}) {
|
||||
this.dragRulerRemovePathfindingWaypoints();
|
||||
|
||||
if (isToken && isPathfindingEnabled()) {
|
||||
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) {
|
||||
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 (path[0].x === this.waypoints[this.waypoints.length - 1].x && path[0].y === this.waypoints[this.waypoints.length - 1].y)
|
||||
|
||||
+21
-15
@@ -1,8 +1,8 @@
|
||||
import {getCenterFromGridPositionObj, getGridPositionFromPixelsObj} from "./foundry_fixes.js";
|
||||
import {getGridPositionFromPixelsObj, getPixelsFromGridPositionObj} from "./foundry_fixes.js";
|
||||
import {togglePathfinding} from "./keybindings.js";
|
||||
import {debugGraphics} from "./main.js";
|
||||
import {settingsKey} from "./settings.js";
|
||||
import {iterPairs} from "./util.js";
|
||||
import {getSnapPointForTokenObj, iterPairs} from "./util.js";
|
||||
|
||||
let cachedNodes = undefined;
|
||||
let use5105 = false;
|
||||
@@ -15,16 +15,16 @@ export function isPathfindingEnabled() {
|
||||
return game.settings.get(settingsKey, "autoPathfinding") != togglePathfinding;
|
||||
}
|
||||
|
||||
export function findPath(from, to, previousWaypoints) {
|
||||
const lastNode = calculatePath(from, to, previousWaypoints);
|
||||
export function findPath(from, to, token, previousWaypoints) {
|
||||
const lastNode = calculatePath(from, to, token, previousWaypoints);
|
||||
if (!lastNode)
|
||||
return null;
|
||||
paintPathfindingDebug(lastNode);
|
||||
paintPathfindingDebug(lastNode, token);
|
||||
const path = [];
|
||||
let currentNode = lastNode;
|
||||
while (currentNode) {
|
||||
// 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
|
||||
path[path.length - 1] = {x: currentNode.node.x, y: currentNode.node.y};
|
||||
else
|
||||
@@ -38,7 +38,7 @@ export function wipePathfindingCache() {
|
||||
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
|
||||
if (!cachedNodes)
|
||||
cachedNodes = new Array(2);
|
||||
@@ -57,12 +57,12 @@ function getNode(pos, initialize=true) {
|
||||
if (neighborPos.x < 0 || neighborPos.y < 0)
|
||||
continue;
|
||||
// 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;
|
||||
let targetLayer = pos.layer;
|
||||
if (use5105 && isDiagonal)
|
||||
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
|
||||
let edgeCost = 1;
|
||||
@@ -77,17 +77,17 @@ function getNode(pos, initialize=true) {
|
||||
return node;
|
||||
}
|
||||
|
||||
function calculatePath(from, to, previousWaypoints) {
|
||||
function calculatePath(from, to, token, previousWaypoints) {
|
||||
if (game.system.id === "pf2e")
|
||||
use5105 = true;
|
||||
if (canvas.grid.diagonalRule === "5105")
|
||||
use5105 = true;
|
||||
let startLayer = 0;
|
||||
if (use5105) {
|
||||
if (use5105 && canvas.grid.type === CONST.GRID_TYPES.SQUARE) {
|
||||
previousWaypoints = previousWaypoints.map(w => getGridPositionFromPixelsObj(w));
|
||||
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();
|
||||
while (nextNodes.length > 0) {
|
||||
// Sort by estimated cost, high to low
|
||||
@@ -99,7 +99,7 @@ function calculatePath(from, to, previousWaypoints) {
|
||||
return currentNode;
|
||||
previousNodes.add(currentNode.node);
|
||||
for (const edge of currentNode.node.edges) {
|
||||
const neighborNode = getNode(edge.target);
|
||||
const neighborNode = getNode(edge.target, token);
|
||||
if (previousNodes.has(neighborNode))
|
||||
continue;
|
||||
const neighbor = {node: neighborNode, cost: currentNode.cost + edge.cost, estimated: currentNode.cost + edge.cost + estimateCost(neighborNode, from), previous: currentNode};
|
||||
@@ -129,7 +129,13 @@ function estimateCost(pos, target) {
|
||||
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)
|
||||
return;
|
||||
|
||||
@@ -137,7 +143,7 @@ function paintPathfindingDebug(lastNode) {
|
||||
let currentNode = lastNode;
|
||||
while (currentNode) {
|
||||
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.x = pixels.x;
|
||||
text.y = pixels.y;
|
||||
|
||||
@@ -86,6 +86,10 @@ export function getSnapPointForToken(x, y, token) {
|
||||
return new PIXI.Point(snapX, snapY);
|
||||
}
|
||||
|
||||
export function getSnapPointForTokenObj(pos, token) {
|
||||
return getSnapPointForToken(pos.x, pos.y, token);
|
||||
}
|
||||
|
||||
export function getSnapPointForMeasuredTemplate(x, y) {
|
||||
if (canvas.grid.type === CONST.GRID_TYPES.GRIDLESS) {
|
||||
return new PIXI.Point(x, y);
|
||||
|
||||
Reference in New Issue
Block a user