Compare commits
17 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3141deb3a2 | |||
| 2144a536ee | |||
| 2b66b43c55 | |||
| 4bd1473310 | |||
| 24620bd604 | |||
| 82685a1a2f | |||
| c09a85b470 | |||
| 7d01ad6d33 | |||
| b671928ade | |||
| 3d68e324f2 | |||
| c30ff10364 | |||
| 8b69cb2f65 | |||
| 0647fec08f | |||
| ebde56513d | |||
| 74c7d74c5a | |||
| f1542b7789 | |||
| 46edfa8ae6 |
@@ -1,3 +1,22 @@
|
|||||||
|
## 1.2.0
|
||||||
|
### New features
|
||||||
|
- Right click and spacebar can now be swapped, allowing to place waypoints with right click and removing them with spacebar
|
||||||
|
- The module can now be configured use a fixed color instead of the player color for the first speed range
|
||||||
|
- On gridless maps the ruler will now change it's color to indicate the different speed ranges
|
||||||
|
- As an alternative to right click (or spacebar, if you have swapped right and spacebar behavior) waypoints can now also be deleted with the `X` key
|
||||||
|
|
||||||
|
### Bugfixes
|
||||||
|
- Disabling snap to grid with shift now works as expected
|
||||||
|
- Fixed a bug where the ruler would sometimes jump to a different target location when deleting a waypoint
|
||||||
|
|
||||||
|
## v1.1.1
|
||||||
|
### Bugfixes
|
||||||
|
- Fixed a bug where tokens wouldn't be moved to the corect end position on gridless maps
|
||||||
|
- Ruler now appears immediately when the token is being dragged
|
||||||
|
- On gridless maps the ruler will always start measuring at the center of the token
|
||||||
|
- This change has no impact on the distance that is being measured
|
||||||
|
- In addition to the cosmetical aspect this also fixes a bug that allowed players to glitch through walls
|
||||||
|
|
||||||
## v1.1.0
|
## v1.1.0
|
||||||
### New features
|
### New features
|
||||||
- The drag ruler will now be colored for other players than the dragging player as well (only if they have at least observer permissions for that token)
|
- The drag ruler will now be colored for other players than the dragging player as well (only if they have at least observer permissions for that token)
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
[](https://ko-fi.com/staebchenfisch)
|
[](https://ko-fi.com/staebchenfisch)
|
||||||
|
|
||||||
# Drag Ruler
|
# Drag Ruler
|
||||||
This module shows a ruler when you drag a token to infrom you how far you've dragged the token from it's start point. Additionally, if you're using a grid, the spaces the token will travel though will be colored depending on your tokens speed.
|
This module shows a ruler when you drag a token to infrom you how far you've dragged the token from it's start point. Additionally, if you're using a grid, the spaces the token will travel though will be colored depending on your tokens speed. If you're using a gridless map the ruler color will change to convey this information.
|
||||||
|
|
||||||
|
|
||||||
## Path color
|
## Path color
|
||||||
@@ -22,6 +22,14 @@ ShowDragDistance isn't maintained anymore. This means that it is at risk to stop
|
|||||||
In addition Drag Ruler provides more flexibility for game systems and modules via it's api to provide an experience that fits the rules of the game system that you are playing best.
|
In addition Drag Ruler provides more flexibility for game systems and modules via it's api to provide an experience that fits the rules of the game system that you are playing best.
|
||||||
|
|
||||||
|
|
||||||
|
## Game systems with Drag Ruler integration
|
||||||
|
Drag Ruler will work with all Foundry VTT game systems. However some game systems offer a special integration via the [Drag Ruler API](#api), that allows Drag Ruler to take the rules of the game system into account when dispaying speeds (such as weight carried or conditions that apply to the character), offering a smoother experience. While some game systems offer this integration natively, for other game systems there are modules providing the integration. If the integration is provided via a module you need to install and activate both Drag Ruler and the integration module to benefit from the integration.
|
||||||
|
|
||||||
|
The game systems that offer Drag Ruler integration are:
|
||||||
|
- Pathfinder 1 (starting with version 0.77.3)
|
||||||
|
- Pathfinder 2e (via the module [PF2E Drag Ruler Integration](https://foundryvtt.com/packages/pf2e-dragruler/))
|
||||||
|
|
||||||
|
|
||||||
## API
|
## API
|
||||||
*Audience: This paragraph is intended for module and system devleopers that want to add more complex behavior to Drag Ruler. If you just want to use this plugins features skip this paragraph.*
|
*Audience: This paragraph is intended for module and system devleopers that want to add more complex behavior to Drag Ruler. If you just want to use this plugins features skip this paragraph.*
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,14 @@
|
|||||||
"native": "Drag Ruler",
|
"native": "Drag Ruler",
|
||||||
"system": "System"
|
"system": "System"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"staticFirstColor": {
|
||||||
|
"name": "Static First Color",
|
||||||
|
"hint": "Use a static color for the first movement range instead of the player color"
|
||||||
|
},
|
||||||
|
"swapSpacebarRightClick": {
|
||||||
|
"name": "Swap spacebar and right click",
|
||||||
|
"hint": "Swaps the functions of spacebar and right click during dragging. If enabled right click will place waypoints and spacebar will delete them"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-2
@@ -2,7 +2,7 @@
|
|||||||
"name": "drag-ruler",
|
"name": "drag-ruler",
|
||||||
"title": "Drag Ruler",
|
"title": "Drag Ruler",
|
||||||
"description": "When dragging a token displays a ruler showing how far you've moved that token.",
|
"description": "When dragging a token displays a ruler showing how far you've moved that token.",
|
||||||
"version": "1.1.0",
|
"version": "1.2.0",
|
||||||
"minimumCoreVersion" : "0.7.9",
|
"minimumCoreVersion" : "0.7.9",
|
||||||
"compatibleCoreVersion" : "0.7.9",
|
"compatibleCoreVersion" : "0.7.9",
|
||||||
"authors": [
|
"authors": [
|
||||||
@@ -23,7 +23,7 @@
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
"url": "https://github.com/manuelVo/foundryvtt-drag-ruler",
|
"url": "https://github.com/manuelVo/foundryvtt-drag-ruler",
|
||||||
"download": "https://github.com/manuelVo/foundryvtt-drag-ruler/archive/v1.1.0.zip",
|
"download": "https://github.com/manuelVo/foundryvtt-drag-ruler/archive/v1.2.0.zip",
|
||||||
"manifest": "https://raw.githubusercontent.com/manuelVo/foundryvtt-drag-ruler/master/module.json",
|
"manifest": "https://raw.githubusercontent.com/manuelVo/foundryvtt-drag-ruler/master/module.json",
|
||||||
"readme": "https://github.com/manuelVo/foundryvtt-drag-ruler/blob/master/README.md",
|
"readme": "https://github.com/manuelVo/foundryvtt-drag-ruler/blob/master/README.md",
|
||||||
"changelog": "https://github.com/manuelVo/foundryvtt-drag-ruler/blob/master/CHANGELOG.md",
|
"changelog": "https://github.com/manuelVo/foundryvtt-drag-ruler/blob/master/CHANGELOG.md",
|
||||||
|
|||||||
+117
-7
@@ -1,12 +1,13 @@
|
|||||||
|
import {getColorForDistance} from "./main.js"
|
||||||
|
|
||||||
// This is a modified version of Ruler.moveToken from foundry 0.7.9
|
// This is a modified version of Ruler.moveToken from foundry 0.7.9
|
||||||
export async function moveTokens(selectedTokens) {
|
export async function moveTokens(draggedToken, selectedTokens) {
|
||||||
let wasPaused = game.paused;
|
let wasPaused = game.paused;
|
||||||
if (wasPaused && !game.user.isGM) {
|
if (wasPaused && !game.user.isGM) {
|
||||||
ui.notifications.warn(game.i18n.localize("GAME.PausedWarning"));
|
ui.notifications.warn(game.i18n.localize("GAME.PausedWarning"));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!this.visible || !this.destination) return false;
|
if (!this.visible || !this.destination) return false;
|
||||||
const draggedToken = this._getMovementToken();
|
|
||||||
if (!draggedToken) return;
|
if (!draggedToken) return;
|
||||||
|
|
||||||
// Get the movement rays and check collision along each Ray
|
// Get the movement rays and check collision along each Ray
|
||||||
@@ -44,15 +45,21 @@ async function animateToken(token, rays, tokenOffset, wasPaused) {
|
|||||||
|
|
||||||
// Determine offset relative to the Token top-left.
|
// Determine offset relative to the Token top-left.
|
||||||
// This is important so we can position the token relative to the ruler origin for non-1x1 tokens.
|
// This is important so we can position the token relative to the ruler origin for non-1x1 tokens.
|
||||||
const origin = canvas.grid.getTopLeft(this.waypoints[0].x + tokenOffset.x, this.waypoints[0].y + tokenOffset.y);
|
const origin = [this.waypoints[0].x + tokenOffset.x, this.waypoints[0].y + tokenOffset.y]
|
||||||
const s2 = canvas.dimensions.size / 2;
|
let dx, dy
|
||||||
const dx = Math.round((token.data.x - origin[0]) / s2) * s2;
|
if (canvas.grid.type === CONST.GRID_TYPES.GRIDLESS) {
|
||||||
const dy = Math.round((token.data.y - origin[1]) / s2) * s2;
|
dx = token.data.x - origin[0]
|
||||||
|
dy = token.data.y - origin[1]
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dx = token.data.x - origin[0]
|
||||||
|
dy = token.data.y - origin[1]
|
||||||
|
}
|
||||||
|
|
||||||
token._noAnimate = true;
|
token._noAnimate = true;
|
||||||
for (let r of offsetRays) {
|
for (let r of offsetRays) {
|
||||||
if (!wasPaused && game.paused) break;
|
if (!wasPaused && game.paused) break;
|
||||||
const dest = canvas.grid.getTopLeft(r.B.x, r.B.y);
|
const dest = [r.B.x, r.B.y];
|
||||||
const path = new Ray({ x: token.x, y: token.y }, { x: dest[0] + dx, y: dest[1] + dy });
|
const path = new Ray({ x: token.x, y: token.y }, { x: dest[0] + dx, y: dest[1] + dy });
|
||||||
await token.update(path.B);
|
await token.update(path.B);
|
||||||
await token.animateMovement(path);
|
await token.animateMovement(path);
|
||||||
@@ -67,3 +74,106 @@ function calculateTokenOffset(tokenA, tokenB) {
|
|||||||
function applyOffsetToRay(ray, offset) {
|
function applyOffsetToRay(ray, offset) {
|
||||||
return new Ray({x: ray.A.x + offset.x, y: ray.A.y + offset.y}, {x: ray.B.x + offset.x, y: ray.B.y + offset.y})
|
return new Ray({x: ray.A.x + offset.x, y: ray.A.y + offset.y}, {x: ray.B.x + offset.x, y: ray.B.y + offset.y})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This is a modified version of Ruler._onMouseMove from foundry 0.7.9
|
||||||
|
export function onMouseMove(event) {
|
||||||
|
if (this._state === Ruler.STATES.MOVING) return;
|
||||||
|
|
||||||
|
// Extract event data
|
||||||
|
const mt = event._measureTime || 0;
|
||||||
|
const originalEvent = event.data.originalEvent;
|
||||||
|
const destination = {x: event.data.destination.x + this.rulerOffset.x, y: event.data.destination.y + this.rulerOffset.y}
|
||||||
|
|
||||||
|
// Hide any existing Token HUD
|
||||||
|
canvas.hud.token.clear();
|
||||||
|
delete event.data.hudState;
|
||||||
|
|
||||||
|
// Draw measurement updates
|
||||||
|
if (Date.now() - mt > 50) {
|
||||||
|
this.measure(destination, {snap: !originalEvent.shiftKey});
|
||||||
|
event._measureTime = Date.now();
|
||||||
|
this._state = Ruler.STATES.MEASURING;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// This is a modified version of Ruler.measure form foundry 0.7.9
|
||||||
|
export function measure(destination, {gridSpaces=true, snap=false} = {}) {
|
||||||
|
if (this.isDragRuler && !this.draggedToken.isVisible)
|
||||||
|
return []
|
||||||
|
|
||||||
|
if (snap)
|
||||||
|
destination = new PIXI.Point(...canvas.grid.getCenter(destination.x, destination.y));
|
||||||
|
const waypoints = this.waypoints.concat([destination]);
|
||||||
|
const centeredWaypoints = waypoints.map(w => new PIXI.Point(...canvas.grid.getCenter(w.x, w.y)))
|
||||||
|
const r = this.ruler;
|
||||||
|
this.destination = destination;
|
||||||
|
|
||||||
|
// Iterate over waypoints and construct segment rays
|
||||||
|
const segments = [];
|
||||||
|
const centeredSegments = []
|
||||||
|
for (let [i, dest] of waypoints.slice(1).entries()) {
|
||||||
|
const centeredDest = centeredWaypoints[i + 1]
|
||||||
|
const origin = waypoints[i];
|
||||||
|
const centeredOrigin = centeredWaypoints[i]
|
||||||
|
const label = this.labels.children[i];
|
||||||
|
const ray = new Ray(origin, dest);
|
||||||
|
const centeredRay = new Ray(centeredOrigin, centeredDest)
|
||||||
|
if (ray.distance < 10) {
|
||||||
|
if (label) label.visible = false;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
segments.push({ ray, label });
|
||||||
|
centeredSegments.push({ray: centeredRay, label})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compute measured distance
|
||||||
|
const distances = canvas.grid.measureDistances(centeredSegments, { gridSpaces });
|
||||||
|
let totalDistance = 0;
|
||||||
|
for (let [i, d] of distances.entries()) {
|
||||||
|
let s = segments[i];
|
||||||
|
s.startDistance = totalDistance
|
||||||
|
totalDistance += d;
|
||||||
|
s.last = i === (segments.length - 1);
|
||||||
|
s.distance = d;
|
||||||
|
s.text = this._getSegmentLabel(d, totalDistance, s.last);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear the grid highlight layer
|
||||||
|
const hlt = canvas.grid.highlightLayers[this.name] || canvas.grid.addHighlightLayer(this.name);
|
||||||
|
hlt.clear();
|
||||||
|
|
||||||
|
// Draw measured path
|
||||||
|
r.clear();
|
||||||
|
let rulerColor
|
||||||
|
if (canvas.grid.type === CONST.GRID_TYPES.GRIDLESS)
|
||||||
|
rulerColor = getColorForDistance.call(this, totalDistance)
|
||||||
|
else
|
||||||
|
rulerColor = this.color
|
||||||
|
for (let s of segments) {
|
||||||
|
const { ray, label, text, last } = s;
|
||||||
|
|
||||||
|
// Draw line segment
|
||||||
|
r.lineStyle(6, 0x000000, 0.5).moveTo(ray.A.x, ray.A.y).lineTo(ray.B.x, ray.B.y)
|
||||||
|
.lineStyle(4, rulerColor, 0.25).moveTo(ray.A.x, ray.A.y).lineTo(ray.B.x, ray.B.y);
|
||||||
|
|
||||||
|
// Draw the distance label just after the endpoint of the segment
|
||||||
|
if (label) {
|
||||||
|
label.text = text;
|
||||||
|
label.alpha = last ? 1.0 : 0.5;
|
||||||
|
label.visible = true;
|
||||||
|
let labelPosition = ray.project((ray.distance + 50) / ray.distance);
|
||||||
|
label.position.set(labelPosition.x, labelPosition.y);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Highlight grid positions
|
||||||
|
this._highlightMeasurement(ray, s.startDistance);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw endpoints
|
||||||
|
for (let p of waypoints) {
|
||||||
|
r.lineStyle(2, 0x000000, 0.5).beginFill(rulerColor, 0.25).drawCircle(p.x, p.y, 8);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Return the measured segments
|
||||||
|
return segments;
|
||||||
|
}
|
||||||
|
|||||||
+107
-32
@@ -1,14 +1,14 @@
|
|||||||
"use strict"
|
"use strict"
|
||||||
|
|
||||||
import {availableSpeedProviders, currentSpeedProvider, registerModule, registerSystem, setCurrentSpeedProvider} from "./api.js"
|
import {availableSpeedProviders, currentSpeedProvider, registerModule, registerSystem, setCurrentSpeedProvider} from "./api.js"
|
||||||
import {moveTokens} from "./foundry_imports.js"
|
import {measure, moveTokens, onMouseMove} from "./foundry_imports.js"
|
||||||
import {registerSettings, settingsKey} from "./settings.js"
|
import {registerSettings, settingsKey} from "./settings.js"
|
||||||
|
|
||||||
Hooks.once("init", () => {
|
Hooks.once("init", () => {
|
||||||
registerSettings()
|
registerSettings()
|
||||||
hookTokenDragHandlers()
|
hookTokenDragHandlers()
|
||||||
hookRulerFunctions()
|
hookRulerFunctions()
|
||||||
patchRulerMeasure()
|
hookKeyboardManagerFunctions()
|
||||||
patchRulerHighlightMeasurement()
|
patchRulerHighlightMeasurement()
|
||||||
|
|
||||||
availableSpeedProviders["native"] = nativeSpeedProvider
|
availableSpeedProviders["native"] = nativeSpeedProvider
|
||||||
@@ -89,73 +89,147 @@ function hookRulerFunctions() {
|
|||||||
}
|
}
|
||||||
originalUpdate.call(this, data)
|
originalUpdate.call(this, data)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const originalMeasure = Ruler.prototype.measure
|
||||||
|
Ruler.prototype.measure = function (destination, options={}) {
|
||||||
|
if (this.isDragRuler) {
|
||||||
|
return measure.call(this, destination, options)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return originalMeasure.call(this, destination, options)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
if (!canvas.controls.ruler.isDragRuler)
|
||||||
|
return false
|
||||||
|
|
||||||
|
deleteWaypoint()
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
function onKeyShift(up) {
|
||||||
|
if (!canvas.controls.ruler.isDragRuler)
|
||||||
|
return false
|
||||||
|
|
||||||
|
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}
|
||||||
|
canvas.controls.ruler.measure(measurePosition, {snap: up})
|
||||||
}
|
}
|
||||||
|
|
||||||
function onTokenLeftDragStart(event) {
|
function onTokenLeftDragStart(event) {
|
||||||
canvas.controls.ruler._onDragStart(event)
|
|
||||||
canvas.controls.ruler.draggedToken = this
|
canvas.controls.ruler.draggedToken = this
|
||||||
|
const tokenCenter = {x: this.x + canvas.grid.grid.w / 2, y: this.y + canvas.grid.grid.h / 2}
|
||||||
|
canvas.controls.ruler.clear();
|
||||||
|
canvas.controls.ruler._state = Ruler.STATES.STARTING;
|
||||||
|
canvas.controls.ruler.rulerOffset = {x: tokenCenter.x - event.data.origin.x, y: tokenCenter.y - event.data.origin.y}
|
||||||
|
addWaypoint.call(canvas.controls.ruler, tokenCenter, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
function onTokenLeftDragMove(event) {
|
function onTokenLeftDragMove(event) {
|
||||||
if (canvas.controls.ruler.isDragRuler)
|
if (canvas.controls.ruler.isDragRuler)
|
||||||
canvas.controls.ruler._onMouseMove(event)
|
onMouseMove.call(canvas.controls.ruler, event)
|
||||||
}
|
}
|
||||||
|
|
||||||
function onTokenDragLeftDrop(event) {
|
function onTokenDragLeftDrop(event) {
|
||||||
if (!canvas.controls.ruler.isDragRuler)
|
if (!canvas.controls.ruler.isDragRuler)
|
||||||
return false
|
return false
|
||||||
canvas.controls.ruler.draggedToken = null
|
|
||||||
const selectedTokens = canvas.tokens.placeables.filter(token => token._controlled)
|
const selectedTokens = canvas.tokens.placeables.filter(token => token._controlled)
|
||||||
moveTokens.call(canvas.controls.ruler, selectedTokens)
|
moveTokens.call(canvas.controls.ruler, canvas.controls.ruler.draggedToken, selectedTokens)
|
||||||
|
canvas.controls.ruler.draggedToken = null
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
function onTokenDragLeftCancel(event) {
|
function onTokenDragLeftCancel(event) {
|
||||||
|
// This function is invoked by right clicking
|
||||||
if (!canvas.controls.ruler.isDragRuler)
|
if (!canvas.controls.ruler.isDragRuler)
|
||||||
return false
|
return false
|
||||||
if (canvas.controls.ruler._state === Ruler.STATES.MEASURING) {
|
if (canvas.controls.ruler._state === Ruler.STATES.MEASURING) {
|
||||||
if (canvas.controls.ruler.waypoints.length > 1) {
|
if (!game.settings.get(settingsKey, "swapSpacebarRightClick")) {
|
||||||
canvas.controls.ruler._removeWaypoint(canvas.app.renderer.plugins.interaction.mouse.getLocalPosition(canvas.tokens), {snap: !event.shiftKey})
|
if (canvas.controls.ruler.waypoints.length > 1)
|
||||||
game.user.broadcastActivity({ruler: canvas.controls.ruler})
|
event.preventDefault()
|
||||||
event.preventDefault()
|
deleteWaypoint()
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
canvas.controls.ruler._endMeasurement()
|
event.preventDefault()
|
||||||
canvas.controls.ruler.draggedToken = null
|
const snap = !event.shiftKey
|
||||||
return false
|
addWaypoint.call(canvas.controls.ruler, canvas.controls.ruler.destination, snap)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
function onRulerMoveToken(event) {
|
function onRulerMoveToken(event) {
|
||||||
|
// This function is invoked by left clicking
|
||||||
if (!this.isDragRuler)
|
if (!this.isDragRuler)
|
||||||
return false
|
return false
|
||||||
this._addWaypoint(this.destination)
|
if (!game.settings.get(settingsKey, "swapSpacebarRightClick")) {
|
||||||
|
const snap = !event.shiftKey
|
||||||
|
addWaypoint.call(this, this.destination, snap)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
deleteWaypoint()
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function addWaypoint(point, snap=true) {
|
||||||
|
if (snap)
|
||||||
|
point = canvas.grid.getCenter(point.x, point.y);
|
||||||
|
else
|
||||||
|
point = [point.x, point.y]
|
||||||
|
this.waypoints.push(new PIXI.Point(point[0], point[1]));
|
||||||
|
this.labels.addChild(new PreciseText("", CONFIG.canvasTextStyle));
|
||||||
|
}
|
||||||
|
|
||||||
|
function deleteWaypoint() {
|
||||||
|
if (canvas.controls.ruler.waypoints.length > 1) {
|
||||||
|
const mousePosition = canvas.app.renderer.plugins.interaction.mouse.getLocalPosition(canvas.tokens)
|
||||||
|
const rulerOffset = canvas.controls.ruler.rulerOffset
|
||||||
|
canvas.controls.ruler._removeWaypoint({x: mousePosition.x + rulerOffset.x, y: mousePosition.y + rulerOffset.y})
|
||||||
|
game.user.broadcastActivity({ruler: canvas.controls.ruler})
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
const token = canvas.controls.ruler.draggedToken
|
||||||
|
canvas.controls.ruler._endMeasurement()
|
||||||
|
canvas.controls.ruler.draggedToken = null
|
||||||
|
|
||||||
|
// Deactivate the drag workflow in mouse
|
||||||
|
token.mouseInteractionManager._deactivateDragEvents();
|
||||||
|
token.mouseInteractionManager.state = token.mouseInteractionManager.states.HOVER;
|
||||||
|
|
||||||
|
// This will cancel the current drag operation
|
||||||
|
// Pass in a fake event that hopefully is enough to allow other modules to function
|
||||||
|
token._onDragLeftCancel({preventDefault: () => {return}})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
function strInsertAfter(haystack, needle, strToInsert) {
|
function strInsertAfter(haystack, needle, strToInsert) {
|
||||||
const pos = haystack.indexOf(needle) + needle.length
|
const pos = haystack.indexOf(needle) + needle.length
|
||||||
return haystack.slice(0, pos) + strToInsert + haystack.slice(pos)
|
return haystack.slice(0, pos) + strToInsert + haystack.slice(pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
// These patches were written with foundry-0.7.9.js as reference
|
|
||||||
function patchRulerMeasure() {
|
|
||||||
let code = Ruler.prototype.measure.toString()
|
|
||||||
// Replace CRLF with LF in case foundry.js has CRLF for some reason
|
|
||||||
code = code.replace(/\r\n/g, "\n")
|
|
||||||
// Remove function signature and closing curly bracket (those are on the first and last line)
|
|
||||||
code = code.slice(code.indexOf("\n"), code.lastIndexOf("\n"))
|
|
||||||
code = strInsertAfter(code, "for ( let [i, d] of distances.entries() ) {\n", "segments[i].startDistance = totalDistance\n")
|
|
||||||
code = strInsertAfter(code, "this._highlightMeasurement(ray", ", s.startDistance")
|
|
||||||
|
|
||||||
// Don't show ruler if the measured token is invisible
|
|
||||||
code = "if (this.isDragRuler && !this.draggedToken.isVisible) return [];" + code
|
|
||||||
|
|
||||||
Ruler.prototype.measure = new Function("destination", "{gridSpaces=true}={}", code)
|
|
||||||
}
|
|
||||||
|
|
||||||
function nativeSpeedProvider(token, playercolor) {
|
function nativeSpeedProvider(token, playercolor) {
|
||||||
const speedAttribute = game.settings.get(settingsKey, "speedAttribute")
|
const speedAttribute = game.settings.get(settingsKey, "speedAttribute")
|
||||||
if (!speedAttribute)
|
if (!speedAttribute)
|
||||||
@@ -171,7 +245,7 @@ function nativeSpeedProvider(token, playercolor) {
|
|||||||
return [{range: tokenSpeed, color: playercolor}, {range: tokenSpeed * dashMultiplier, color: 0xFFFF00}]
|
return [{range: tokenSpeed, color: playercolor}, {range: tokenSpeed * dashMultiplier, color: 0xFFFF00}]
|
||||||
}
|
}
|
||||||
|
|
||||||
function getColorForDistance(startDistance, subDistance) {
|
export function getColorForDistance(startDistance, subDistance=0) {
|
||||||
if (!this.isDragRuler)
|
if (!this.isDragRuler)
|
||||||
return this.color
|
return this.color
|
||||||
// Don't apply colors if the current user doesn't have at least observer permissions
|
// Don't apply colors if the current user doesn't have at least observer permissions
|
||||||
@@ -181,7 +255,8 @@ function getColorForDistance(startDistance, subDistance) {
|
|||||||
return this.color
|
return this.color
|
||||||
}
|
}
|
||||||
const distance = startDistance + subDistance
|
const distance = startDistance + subDistance
|
||||||
const ranges = currentSpeedProvider(this.draggedToken, this.color)
|
const firstColor = game.settings.get(settingsKey, "staticFirstColor") ? 0x00FF00 : this.color
|
||||||
|
const ranges = currentSpeedProvider(this.draggedToken, firstColor)
|
||||||
if (ranges.length === 0)
|
if (ranges.length === 0)
|
||||||
return this.color
|
return this.color
|
||||||
const currentRange = ranges.reduce((minRange, currentRange) => {
|
const currentRange = ranges.reduce((minRange, currentRange) => {
|
||||||
|
|||||||
@@ -4,6 +4,15 @@ import {getDefaultDashMultiplier, getDefaultSpeedAttribute} from "./systems.js"
|
|||||||
export const settingsKey = "drag-ruler";
|
export const settingsKey = "drag-ruler";
|
||||||
|
|
||||||
export function registerSettings() {
|
export function registerSettings() {
|
||||||
|
game.settings.register(settingsKey, "swapSpacebarRightClick", {
|
||||||
|
name: "drag-ruler.settings.swapSpacebarRightClick.name",
|
||||||
|
hint: "drag-ruler.settings.swapSpacebarRightClick.hint",
|
||||||
|
scope: "client",
|
||||||
|
config: true,
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
})
|
||||||
|
|
||||||
game.settings.register(settingsKey, "alwaysShowSpeedForPCs", {
|
game.settings.register(settingsKey, "alwaysShowSpeedForPCs", {
|
||||||
name: "drag-ruler.settings.alwaysShowSpeedForPCs.name",
|
name: "drag-ruler.settings.alwaysShowSpeedForPCs.name",
|
||||||
hint: "drag-ruler.settings.alwaysShowSpeedForPCs.hint",
|
hint: "drag-ruler.settings.alwaysShowSpeedForPCs.hint",
|
||||||
@@ -44,4 +53,13 @@ export function registerSettings() {
|
|||||||
type: Number,
|
type: Number,
|
||||||
default: getDefaultDashMultiplier(),
|
default: getDefaultDashMultiplier(),
|
||||||
})
|
})
|
||||||
|
|
||||||
|
game.settings.register(settingsKey, "staticFirstColor", {
|
||||||
|
name: "drag-ruler.settings.staticFirstColor.name",
|
||||||
|
hint: "drag-ruler.settings.staticFirstColor.hint",
|
||||||
|
scope: "world",
|
||||||
|
config: true,
|
||||||
|
type: Boolean,
|
||||||
|
default: false,
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user