|
|
- import {getPixelsFromGridPosition} from "./foundry_fixes.js";
- import {findVertexSnapPoint} from "./hex_support.js";
- import {disableSnap, moveWithoutAnimation, togglePathfinding} from "./keybindings.js";
- import {settingsKey} from "./settings.js";
-
- export function* zip(it1, it2) {
- for (let i = 0; i < Math.min(it1.length, it2.length); i++) {
- yield [it1[i], it2[i]];
- }
- }
-
- export function* enumeratedZip(it1, it2) {
- let i = 0;
- for (const [v1, v2] of zip(it1, it2)) {
- yield [i, v1, v2];
- i++;
- }
- }
-
- export function* iterPairs(l) {
- for (let i = 1; i < l.length; i++) {
- yield [l[i - 1], l[i]];
- }
- }
-
- export function sum(arr) {
- return arr.reduce((a, b) => a + b, 0);
- }
-
- // A copy of this function lives in the routinglib module
- export function getHexTokenSize(token) {
- const size = token.document.width;
- if (token.document.height !== size) {
- return 1;
- }
- return size;
- }
-
- export function getEntityCenter(token) {
- if (token instanceof Token && canvas.grid.isHex) {
- const center = token.center;
- const size = getHexTokenSize(token);
- if (size % 2 === 0) {
- let offset;
- if (canvas.grid.grid.columnar) {
- offset = canvas.grid.grid.w - canvas.grid.grid.h;
- } else {
- offset = canvas.grid.grid.h - canvas.grid.grid.w;
- }
- if (getAltOrientationFlagForToken(token, size)) {
- offset *= -1;
- }
- if (canvas.grid.grid.columnar) {
- center.x -= offset;
- return center;
- } else {
- center.y -= offset;
- return center;
- }
- }
- }
- return token.center;
- }
-
- // A copy of this function lives in the routinglib module
- export function getAltOrientationFlagForToken(token, size) {
- const hexSizeSupport = game.modules.get("hex-size-support")?.api;
- if (hexSizeSupport) {
- return hexSizeSupport.isAltOrientation(token);
- }
- // In native foundry, tokens of size 2 are oriented like the "alt orientation" from hex-size-support
- // Tokens of size 4 are oriented like alt orientation wasn't set
- return size === 2;
- }
-
- // A copy of this function lives in the librouting module
- export function getSnapPointForToken(x, y, token) {
- if (canvas.grid.type === CONST.GRID_TYPES.GRIDLESS) {
- return {x, y};
- }
-
- if (canvas.grid.isHex) {
- const size = getHexTokenSize(token);
- if (size % 2 === 0) {
- return findVertexSnapPoint(x, y, getAltOrientationFlagForToken(token, size));
- }
- const [snapX, snapY] = canvas.grid.getCenter(x, y);
- return {x: snapX, y: snapY};
- }
-
- const [topLeftX, topLeftY] = canvas.grid.getTopLeft(x, y);
- let cellX, cellY;
- if (token.document.width % 2 === 0) cellX = x - canvas.grid.h / 2;
- else cellX = x;
- if (token.document.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
- if (token.document.width <= 0.5) {
- const offsetX = x - topLeftX;
- const subGridWidth = Math.floor(canvas.grid.w / 2);
- const subGridPosX = Math.floor(offsetX / subGridWidth);
- snapX = topLeftX + (subGridPosX + 0.5) * subGridWidth;
- }
- // 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.document.width) % 2 === 1 || token.document.width < 1) {
- snapX = centerX;
- }
- // All remaining tokens (those with even or fractional multipliers on square grids) snap to the intersection points of the grid
- else {
- snapX = centerX + canvas.grid.w / 2;
- }
- if (token.document.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.document.height) % 2 === 1 || token.document.height < 1) {
- snapY = centerY;
- } else {
- snapY = centerY + canvas.grid.h / 2;
- }
- return {x: snapX, y: 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);
- }
- return canvas.grid.grid.getSnappedPosition(x, y, canvas.templates.gridPrecision);
- }
-
- export function getSnapPointForEntity(x, y, entity) {
- const isToken = entity instanceof Token;
- if (isToken) return getSnapPointForToken(x, y, entity);
- else return getSnapPointForMeasuredTemplate(x, y);
- }
-
- export function highlightTokenShape(position, shape, color, alpha) {
- const layer = canvas.grid.highlightLayers[this.name];
- if (!layer) return false;
- const area = getAreaFromPositionAndShape(position, shape);
- for (const space of area) {
- const [x, y] = getPixelsFromGridPosition(space.x, space.y);
- canvas.grid.grid.highlightGridPosition(layer, {x, y, color, alpha: 0.25 * alpha});
- }
- }
-
- 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) shiftedRow = 1;
- else shiftedRow = 0;
- if (canvas.grid.grid.columnar) {
- if (space.x % 2 !== 0 && position.x % 2 !== shiftedRow) {
- y += 1;
- }
- } else {
- if (space.y % 2 !== 0 && position.y % 2 !== shiftedRow) {
- x += 1;
- }
- }
- }
- return {x, y};
- });
- }
-
- // A copy of this function lives in the routinglib module
- export function getTokenShape(token) {
- let scene = canvas.scene;
- if (scene.grid.type === CONST.GRID_TYPES.GRIDLESS) {
- return [{x: 0, y: 0}];
- } else if (scene.grid.type === CONST.GRID_TYPES.SQUARE) {
- const topOffset = -Math.floor(token.document.height / 2);
- const leftOffset = -Math.floor(token.document.width / 2);
- const shape = [];
- for (let y = 0; y < token.document.height; y++) {
- for (let x = 0; x < token.document.width; x++) {
- shape.push({x: x + leftOffset, y: y + topOffset});
- }
- }
- return shape;
- } else {
- // Hex grids
- const size = getHexTokenSize(token);
- let shape = [{x: 0, y: 0}];
- if (size >= 2)
- shape = shape.concat([
- {x: 0, y: -1},
- {x: -1, y: -1},
- ]);
- if (size >= 3)
- shape = shape.concat([
- {x: 0, y: 1},
- {x: -1, y: 1},
- {x: -1, y: 0},
- {x: 1, y: 0},
- ]);
- if (size >= 4)
- shape = shape.concat([
- {x: -2, y: -1},
- {x: 1, y: -1},
- {x: -1, y: -2},
- {x: 0, y: -2},
- {x: 1, y: -2},
- ]);
-
- if (getAltOrientationFlagForToken(token, size)) {
- shape.forEach(space => (space.y *= -1));
- }
- if (canvas.grid.grid.columnar)
- shape = shape.map(space => {
- return {x: space.y, y: space.x};
- });
- return shape;
- }
- }
-
- export function getTokenSize(token) {
- let w, h;
- if (canvas.grid.isHex) {
- w = h = getHexTokenSize(token);
- } else {
- w = token.document.width;
- h = token.document.height;
- }
- return {w, h};
- }
-
- // Tokens that have a size divisible by two (2x2, 4x4, 2x1) have their ruler at the edge of a cell.
- // This function applies an offset to to the waypoints that will move the ruler from the edge to the center of the cell
- export function applyTokenSizeOffset(waypoints, token) {
- if (canvas.grid.type === CONST.GRID_TYPES.GRIDLESS) {
- return waypoints;
- }
-
- const tokenSize = getTokenSize(token);
- const waypointOffset = {x: 0, y: 0};
- if (canvas.grid.isHex) {
- const isAltOrientation = getAltOrientationFlagForToken(token, getHexTokenSize(token));
- if (canvas.grid.grid.columnar) {
- if (tokenSize.w % 2 === 0) {
- waypointOffset.x = canvas.grid.w / 2;
- if (isAltOrientation) waypointOffset.x *= -1;
- }
- } else {
- if (tokenSize.h % 2 === 0) {
- waypointOffset.y = canvas.grid.h / 2;
- if (isAltOrientation) waypointOffset.y *= -1;
- }
- }
- // If hex size support isn't active leave the waypoints like they are
- } else {
- if (tokenSize.w % 2 === 0) {
- waypointOffset.x = canvas.grid.w / 2;
- }
- if (tokenSize.h % 2 === 0) {
- waypointOffset.y = canvas.grid.h / 2;
- }
- }
-
- return waypoints.map(w => new PIXI.Point(w.x + waypointOffset.x, w.y + waypointOffset.y));
- }
-
- export function setSnapParameterOnOptions(sourceObject, options) {
- // Allow outside modules to override snapping
- if (sourceObject.snapOverride?.active) {
- options.snapOverrideActive = true;
- options.snap = sourceObject.snapOverride.snap;
- sourceObject.snapOverride = undefined; // remove it to prevent any lingering data issues
- } else {
- options.snap = !disableSnap;
- }
- }
-
- export function isClose(a, b, delta) {
- return Math.abs(a - b) <= delta;
- }
-
- export function getMeasurePosition() {
- const mousePosition = canvas.app.renderer.plugins.interaction.mouse.getLocalPosition(
- canvas.tokens,
- );
- const rulerOffset = canvas.controls.ruler.rulerOffset;
- const measurePosition = {x: mousePosition.x + rulerOffset.x, y: mousePosition.y + rulerOffset.y};
- 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;
- }
-
- export function isModuleActive(moduleName) {
- return game.modules.get(moduleName)?.active;
- }
-
- export function isPathfindingEnabled() {
- if (!window.routinglib) return false;
- if (this.user !== game.user) return false;
- if (!game.user.isGM && !game.settings.get(settingsKey, "allowPathfinding")) return false;
- if (moveWithoutAnimation) return false;
- return game.settings.get(settingsKey, "autoPathfinding") != togglePathfinding;
- }
|