diff --git a/daggerheart.mjs b/daggerheart.mjs index 1987ec12..05b57ac9 100644 --- a/daggerheart.mjs +++ b/daggerheart.mjs @@ -420,10 +420,7 @@ const updateActorsRangeDependentEffects = async token => { // Get required distance and special case 5 feet to test adjacency const required = rangeMeasurement[range]; const reverse = type === CONFIG.DH.GENERAL.rangeInclusion.outsideRange.id; - const inRange = - required === 5 - ? userTarget.isAdjacentWith(token.object) - : userTarget.distanceTo(token.object) <= required; + const inRange = userTarget.distanceTo(token.object) <= required; if (reverse ? inRange : !inRange) { enabledEffect = false; break; diff --git a/module/canvas/placeables/token.mjs b/module/canvas/placeables/token.mjs index 068f21e1..148466c1 100644 --- a/module/canvas/placeables/token.mjs +++ b/module/canvas/placeables/token.mjs @@ -54,30 +54,58 @@ export default class DhTokenPlaceable extends foundry.canvas.placeables.Token { if (this === target) return 0; const originPoint = this.center; - const destinationPoint = target.center; + const targetPoint = target.center; + const thisBounds = this.bounds; + const targetBounds = target.bounds; + const adjacencyBuffer = canvas.grid.distance * 1.75; // handles diagonals with one square elevation difference + + // Figure out the elevation difference. + // This intends to return "grid distance" for adjacent ones, so we add that number if not overlapping. + const sizePerUnit = canvas.grid.size / canvas.grid.distance; + const thisHeight = Math.max(thisBounds.width, thisBounds.height) / sizePerUnit; + const targetHeight = Math.max(targetBounds.width, targetBounds.height) / sizePerUnit; + const thisElevation = [this.document.elevation, this.document.elevation + thisHeight]; + const targetElevation = [target.document.elevation, target.document.elevation + targetHeight]; + const isSameAltitude = + thisElevation[0] < targetElevation[1] && // bottom of this must be at or below the top of target + thisElevation[1] > targetElevation[0]; // top of this must be at or above the bottom of target + const [lower, higher] = [targetElevation, thisElevation].sort((a, b) => a[1] - b[1]); + const elevation = isSameAltitude ? 0 : higher[0] - lower[1] + canvas.grid.distance; // Compute for gridless. This version returns circular edge to edge + grid distance, // so that tokens that are touching return 5. if (canvas.grid.type === CONST.GRID_TYPES.GRIDLESS) { const boundsCorrection = canvas.grid.distance / canvas.grid.size; - const originRadius = (this.bounds.width * boundsCorrection) / 2; - const targetRadius = (target.bounds.width * boundsCorrection) / 2; - const distance = canvas.grid.measurePath([originPoint, destinationPoint]).distance; - return Math.floor(distance - originRadius - targetRadius + canvas.grid.distance); + const originRadius = (thisBounds.width * boundsCorrection) / 2; + const targetRadius = (targetBounds.width * boundsCorrection) / 2; + const measuredDistance = canvas.grid.measurePath([ + { ...originPoint, elevation: 0 }, + { ...targetPoint, elevation } + ]).distance; + const distance = Math.floor(measuredDistance - originRadius - targetRadius + canvas.grid.distance); + return Math.min(distance, distance > adjacencyBuffer ? Infinity : canvas.grid.distance); } // Compute what the closest grid space of each token is, then compute that distance - const originEdge = this.#getEdgeBoundary(this.bounds, originPoint, destinationPoint); - const targetEdge = this.#getEdgeBoundary(target.bounds, originPoint, destinationPoint); - const adjustedOriginPoint = canvas.grid.getTopLeftPoint({ - x: originEdge.x + Math.sign(originPoint.x - originEdge.x), - y: originEdge.y + Math.sign(originPoint.y - originEdge.y) - }); - const adjustDestinationPoint = canvas.grid.getTopLeftPoint({ - x: targetEdge.x + Math.sign(destinationPoint.x - targetEdge.x), - y: targetEdge.y + Math.sign(destinationPoint.y - targetEdge.y) - }); - return canvas.grid.measurePath([adjustedOriginPoint, adjustDestinationPoint]).distance; + const originEdge = this.#getEdgeBoundary(thisBounds, originPoint, targetPoint); + const targetEdge = this.#getEdgeBoundary(targetBounds, originPoint, targetPoint); + const adjustedOriginPoint = originEdge + ? canvas.grid.getTopLeftPoint({ + x: originEdge.x + Math.sign(originPoint.x - originEdge.x), + y: originEdge.y + Math.sign(originPoint.y - originEdge.y) + }) + : originPoint; + const adjustDestinationPoint = targetEdge + ? canvas.grid.getTopLeftPoint({ + x: targetEdge.x + Math.sign(targetPoint.x - targetEdge.x), + y: targetEdge.y + Math.sign(targetPoint.y - targetEdge.y) + }) + : targetPoint; + const distance = canvas.grid.measurePath([ + { ...adjustedOriginPoint, elevation: 0 }, + { ...adjustDestinationPoint, elevation } + ]).distance; + return Math.min(distance, distance > adjacencyBuffer ? Infinity : canvas.grid.distance); } _onHoverIn(event, options) { @@ -103,8 +131,7 @@ export default class DhTokenPlaceable extends foundry.canvas.placeables.Token { // Determine the actual range const ranges = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.variantRules).rangeMeasurement; - const distanceNum = originToken.distanceTo(this); - const distanceResult = DhMeasuredTemplate.getRangeLabels(distanceNum, ranges); + const distanceResult = DhMeasuredTemplate.getRangeLabels(originToken.distanceTo(this), ranges); const distanceLabel = `${distanceResult.distance} ${distanceResult.units}`.trim(); // Create the element @@ -156,11 +183,6 @@ export default class DhTokenPlaceable extends foundry.canvas.placeables.Token { return null; } - /** Tests if the token is at least adjacent with another, with some leeway for diagonals */ - isAdjacentWith(token) { - return this.distanceTo(token) <= canvas.grid.distance * 1.5; - } - /** @inheritDoc */ _drawBar(number, bar, data) { const val = Number(data.value);