Support for difficult terrain with tokens larger than 1x1
This commit is contained in:
@@ -97,6 +97,13 @@ export function getUnreachableColorFromSpeedProvider() {
|
||||
}
|
||||
}
|
||||
|
||||
export function getCostFromSpeedProvider(token, area) {
|
||||
if (currentSpeedProvider instanceof Function) {
|
||||
return SpeedProvider.prototype.getCostForStep.call(undefined, token, area);
|
||||
}
|
||||
return currentSpeedProvider.getCostForStep(token, area);
|
||||
}
|
||||
|
||||
export function registerModule(moduleId, speedProvider) {
|
||||
// Check if a module with the given id exists and is currently enabled
|
||||
const module = game.modules.get(moduleId)
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
import { getCostFromSpeedProvider } from "./api.js";
|
||||
import {highlightMeasurementTerrainRuler} from "./compatibility.js";
|
||||
import {getGridPositionFromPixels} from "./foundry_fixes.js";
|
||||
import {getColorForDistance} from "./main.js"
|
||||
import {applyTokenSizeOffset, getSnapPointForToken, getTokenShape, getTokenSize, highlightTokenShape, zip} from "./util.js";
|
||||
import {applyTokenSizeOffset, getAreaFromPositionAndShape, getSnapPointForToken, getTokenShape, highlightTokenShape, zip} from "./util.js";
|
||||
|
||||
// This is a modified version of Ruler.moveToken from foundry 0.7.9
|
||||
export async function moveTokens(draggedToken, selectedTokens) {
|
||||
@@ -132,11 +133,13 @@ export function measure(destination, {gridSpaces=true, snap=false} = {}) {
|
||||
centeredSegments.push({ray: centeredRay, label})
|
||||
}
|
||||
|
||||
const shape = getTokenShape(this.draggedToken)
|
||||
|
||||
// Compute measured distance
|
||||
const terrainRulerAvailable = game.modules.get("terrain-ruler")?.active && canvas.grid.type !== CONST.GRID_TYPES.GRIDLESS
|
||||
let distances
|
||||
if (terrainRulerAvailable)
|
||||
distances = game.terrainRuler.measureDistances(centeredSegments)
|
||||
distances = game.terrainRuler.measureDistances(centeredSegments, {costFunction: (x, y) => getCostFromSpeedProvider(this.draggedToken, getAreaFromPositionAndShape({x, y}, shape), {x, y})});
|
||||
else
|
||||
distances = canvas.grid.measureDistances(centeredSegments, { gridSpaces });
|
||||
|
||||
@@ -161,7 +164,6 @@ export function measure(destination, {gridSpaces=true, snap=false} = {}) {
|
||||
rulerColor = getColorForDistance.call(this, totalDistance)
|
||||
else
|
||||
rulerColor = this.color
|
||||
const shape = getTokenShape(this.draggedToken)
|
||||
for (const [s, cs] of zip(segments.reverse(), centeredSegments.reverse())) {
|
||||
const { label, text, last } = cs;
|
||||
|
||||
|
||||
@@ -56,6 +56,22 @@ export class SpeedProvider {
|
||||
return 0xFF0000
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the cost for a token to step into the specificed area.
|
||||
* The area indicates the whole area that the token will occupy (for tokens larger than 1x1) the array will more than one entry.
|
||||
* The return value should be an integer indicating a multiplicator by that the cost of that step should be increased.
|
||||
* (1 is regular cost, 2 costs double, 3 costs triple, ...)
|
||||
* 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)
|
||||
*/
|
||||
getCostForStep(token, area) {
|
||||
// Lookup the cost for each square occupied by the token
|
||||
const costs = area.map(space => canvas.terrain.costGrid[space.y]?.[space.x]?.multiple ?? 1)
|
||||
// Return the maximum of the costs
|
||||
return costs.reduce((max, current) => Math.max(max, current))
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a boolean indicating whether this token will use a Ruler or not.
|
||||
* If this is returns `false` for a token Drag Ruler will be disabled for that token. Dragging a token for which this function
|
||||
|
||||
+15
-8
@@ -24,9 +24,17 @@ export function getSnapPointForToken(x, y, token) {
|
||||
}
|
||||
|
||||
export function highlightTokenShape(position, shape, color) {
|
||||
for (const space of shape) {
|
||||
let gridX = position.x + space.x;
|
||||
let gridY = position.y + space.y;
|
||||
const area = getAreaFromPositionAndShape(position, shape);
|
||||
for (const space of area) {
|
||||
const [x, y] = getPixelsFromGridPosition(space.x, space.y);
|
||||
canvas.grid.highlightPosition(this.name, {x, y, color})
|
||||
}
|
||||
}
|
||||
|
||||
export function getAreaFromPositionAndShape(position, shape) {
|
||||
return shape.map(space => {
|
||||
let x = position.x + space.x;
|
||||
let y = position.y + space.y;
|
||||
if (canvas.grid.isHex) {
|
||||
let shiftedRow;
|
||||
if (canvas.grid.grid.options.even)
|
||||
@@ -35,18 +43,17 @@ export function highlightTokenShape(position, shape, color) {
|
||||
shiftedRow = 0
|
||||
if (canvas.grid.grid.options.columns) {
|
||||
if (space.x % 2 !== 0 && position.x % 2 !== shiftedRow) {
|
||||
gridY += 1;
|
||||
y += 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
if (space.y % 2 !== 0 && position.y % 2 !== shiftedRow) {
|
||||
gridX += 1;
|
||||
x += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
const [x, y] = getPixelsFromGridPosition(gridX, gridY);
|
||||
canvas.grid.highlightPosition(this.name, {x, y, color})
|
||||
}
|
||||
return {x, y}
|
||||
});
|
||||
}
|
||||
|
||||
export function getTokenShape(token) {
|
||||
|
||||
Reference in New Issue
Block a user