212 lines
6.9 KiB
JavaScript
212 lines
6.9 KiB
JavaScript
"use strict"
|
|
|
|
import {currentSpeedProvider, getMovedDistanceFromToken, getRangesFromSpeedProvider, getUnreachableColorFromSpeedProvider, initApi, registerModule, registerSystem} from "./api.js"
|
|
import {checkDependencies, getHexSizeSupportTokenGridCenter} from "./compatibility.js";
|
|
import {moveEntities, onMouseMove} from "./foundry_imports.js"
|
|
import {performMigrations} from "./migration.js"
|
|
import {DragRulerRuler} from "./ruler.js";
|
|
import {getMovementHistory, resetMovementHistory} from "./movement_tracking.js";
|
|
import {registerSettings, settingsKey} from "./settings.js"
|
|
import {recalculate} from "./socket.js";
|
|
import {SpeedProvider} from "./speed_provider.js"
|
|
|
|
Hooks.once("init", () => {
|
|
registerSettings()
|
|
initApi()
|
|
hookDragHandlers(Token);
|
|
hookDragHandlers(MeasuredTemplate);
|
|
hookKeyboardManagerFunctions()
|
|
|
|
Ruler = DragRulerRuler;
|
|
|
|
window.dragRuler = {
|
|
getColorForDistance,
|
|
getMovedDistanceFromToken,
|
|
registerModule,
|
|
registerSystem,
|
|
recalculate,
|
|
resetMovementHistory,
|
|
}
|
|
})
|
|
|
|
Hooks.once("ready", () => {
|
|
performMigrations()
|
|
checkDependencies();
|
|
Hooks.callAll("dragRuler.ready", SpeedProvider)
|
|
})
|
|
|
|
Hooks.on("canvasReady", () => {
|
|
canvas.controls.rulers.children.forEach(ruler => {
|
|
ruler.draggedEntity = null;
|
|
Object.defineProperty(ruler, "isDragRuler", {
|
|
get: function isDragRuler() {
|
|
return Boolean(this.draggedEntity); // If draggedEntity is set this is a drag ruler
|
|
}
|
|
})
|
|
})
|
|
})
|
|
|
|
Hooks.on("getCombatTrackerEntryContext", function (html, menu) {
|
|
const entry = {
|
|
name: "drag-ruler.resetMovementHistory",
|
|
icon: '<i class="fas fa-undo-alt"></i>',
|
|
callback: li => resetMovementHistory(ui.combat.combat, li.data('combatant-id')),
|
|
};
|
|
menu.splice(1, 0, entry);
|
|
});
|
|
|
|
function hookDragHandlers(entityType) {
|
|
const originalDragLeftStartHandler = entityType.prototype._onDragLeftStart
|
|
entityType.prototype._onDragLeftStart = function(event) {
|
|
originalDragLeftStartHandler.call(this, event)
|
|
onEntityLeftDragStart.call(this, event)
|
|
}
|
|
|
|
const originalDragLeftMoveHandler = entityType.prototype._onDragLeftMove
|
|
entityType.prototype._onDragLeftMove = function (event) {
|
|
originalDragLeftMoveHandler.call(this, event)
|
|
onEntityLeftDragMove.call(this, event)
|
|
}
|
|
|
|
const originalDragLeftDropHandler = entityType.prototype._onDragLeftDrop
|
|
entityType.prototype._onDragLeftDrop = function (event) {
|
|
const eventHandled = onEntityDragLeftDrop.call(this, event)
|
|
if (!eventHandled)
|
|
originalDragLeftDropHandler.call(this, event)
|
|
}
|
|
|
|
const originalDragLeftCancelHandler = entityType.prototype._onDragLeftCancel
|
|
entityType.prototype._onDragLeftCancel = function (event) {
|
|
const eventHandled = onEntityDragLeftCancel.call(this, event)
|
|
if (!eventHandled)
|
|
originalDragLeftCancelHandler.call(this, event)
|
|
}
|
|
}
|
|
|
|
function hookKeyboardManagerFunctions() {
|
|
const originalHandleKeys = KeyboardManager.prototype._handleKeys
|
|
KeyboardManager.prototype._handleKeys = function (event, key, up) {
|
|
const eventHandled = handleKeys.call(this, event, key, up)
|
|
if (!eventHandled)
|
|
originalHandleKeys.call(this, event, key, up)
|
|
}
|
|
}
|
|
|
|
function handleKeys(event, key, up) {
|
|
if (event.repeat || this.hasFocus)
|
|
return false
|
|
|
|
if (key.toLowerCase() === "x") return onKeyX(up)
|
|
if (key.toLowerCase() === "shift") return onKeyShift(up)
|
|
return false
|
|
}
|
|
|
|
function onKeyX(up) {
|
|
if (up)
|
|
return false
|
|
const ruler = canvas.controls.ruler;
|
|
if (!ruler.isDragRuler)
|
|
return false
|
|
|
|
ruler.dragRulerDeleteWaypoint();
|
|
return true
|
|
}
|
|
|
|
function onKeyShift(up) {
|
|
const ruler = canvas.controls.ruler
|
|
if (!ruler.isDragRuler)
|
|
return false
|
|
if (ruler._state !== Ruler.STATES.MEASURING)
|
|
return false;
|
|
|
|
const mousePosition = canvas.app.renderer.plugins.interaction.mouse.getLocalPosition(canvas.tokens)
|
|
const rulerOffset = ruler.rulerOffset
|
|
const measurePosition = {x: mousePosition.x + rulerOffset.x, y: mousePosition.y + rulerOffset.y}
|
|
ruler.measure(measurePosition, {snap: up})
|
|
}
|
|
|
|
function onEntityLeftDragStart(event) {
|
|
const isToken = this instanceof Token;
|
|
if (isToken && !currentSpeedProvider.usesRuler(this))
|
|
return
|
|
const ruler = canvas.controls.ruler
|
|
ruler.draggedEntity = this;
|
|
let entityCenter;
|
|
if (isToken && canvas.grid.isHex && game.modules.get("hex-size-support")?.active && CONFIG.hexSizeSupport.getAltSnappingFlag(this))
|
|
entityCenter = getHexSizeSupportTokenGridCenter(this);
|
|
else
|
|
entityCenter = this.center;
|
|
ruler.clear();
|
|
ruler._state = Ruler.STATES.STARTING;
|
|
ruler.rulerOffset = {x: entityCenter.x - event.data.origin.x, y: entityCenter.y - event.data.origin.y};
|
|
if (isToken && game.settings.get(settingsKey, "enableMovementHistory"))
|
|
ruler.dragRulerAddWaypointHistory(getMovementHistory(this));
|
|
ruler.dragRulerAddWaypoint(entityCenter, false);
|
|
}
|
|
|
|
function onEntityLeftDragMove(event) {
|
|
const ruler = canvas.controls.ruler
|
|
if (ruler.isDragRuler)
|
|
onMouseMove.call(ruler, event)
|
|
}
|
|
|
|
function onEntityDragLeftDrop(event) {
|
|
const ruler = canvas.controls.ruler
|
|
if (!ruler.isDragRuler)
|
|
return false
|
|
onMouseMove.call(ruler, event);
|
|
// When we're dragging a measured template no token will ever be selected,
|
|
// resulting in only the dragged template to be moved as would be expected
|
|
const selectedTokens = canvas.tokens.controlled
|
|
// This can happen if the user presses ESC during drag (maybe there are other ways too)
|
|
if (selectedTokens.length === 0)
|
|
selectedTokens.push(ruler.draggedEntity);
|
|
ruler._state = Ruler.STATES.MOVING
|
|
moveEntities.call(ruler, ruler.draggedEntity, selectedTokens);
|
|
return true
|
|
}
|
|
|
|
function onEntityDragLeftCancel(event) {
|
|
// This function is invoked by right clicking
|
|
const ruler = canvas.controls.ruler
|
|
if (!ruler.isDragRuler || ruler._state === Ruler.STATES.MOVING)
|
|
return false
|
|
if (ruler._state === Ruler.STATES.MEASURING) {
|
|
if (!game.settings.get(settingsKey, "swapSpacebarRightClick")) {
|
|
ruler.dragRulerDeleteWaypoint(event);
|
|
}
|
|
else {
|
|
event.preventDefault()
|
|
const snap = !event.shiftKey
|
|
ruler.dragRulerAddWaypoint(ruler.destination, snap);
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
export function getColorForDistance(startDistance, subDistance=0) {
|
|
if (!this.isDragRuler)
|
|
return this.color
|
|
if (!this.draggedEntity.actor) {
|
|
return this.color;
|
|
}
|
|
// Don't apply colors if the current user doesn't have at least observer permissions
|
|
if (this.draggedEntity.actor.permission < 2) {
|
|
// If this is a pc and alwaysShowSpeedForPCs is enabled we show the color anyway
|
|
if (!(this.draggedEntity.actor.data.type === "character" && game.settings.get(settingsKey, "alwaysShowSpeedForPCs")))
|
|
return this.color
|
|
}
|
|
const distance = startDistance + subDistance
|
|
if (!this.dragRulerRanges)
|
|
this.dragRulerRanges = getRangesFromSpeedProvider(this.draggedEntity);
|
|
const ranges = this.dragRulerRanges;
|
|
if (ranges.length === 0)
|
|
return this.color
|
|
const currentRange = ranges.reduce((minRange, currentRange) => {
|
|
if (distance <= currentRange.range && currentRange.range < minRange.range)
|
|
return currentRange
|
|
return minRange
|
|
}, {range: Infinity, color: getUnreachableColorFromSpeedProvider()})
|
|
return currentRange.color
|
|
}
|