Compare commits
23 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 942bfa04e8 | |||
| b4ac65e478 | |||
| 0de01379e9 | |||
| f6eb5eff9c | |||
| fee0983841 | |||
| 3de044ea45 | |||
| e473fea121 | |||
| 0aee541eb3 | |||
| 40dde08ddd | |||
| 8234aa566d | |||
| 2862643ba8 | |||
| e3abdeab3a | |||
| 2ff4e98fe9 | |||
| e0d0483722 | |||
| 4f1dec3089 | |||
| c4d089e8ff | |||
| f8fe4ee971 | |||
| 378401b5bb | |||
| 0a54a47951 | |||
| 0b71504da3 | |||
| 5a7f5531f2 | |||
| 862477c698 | |||
| 384de1a1b5 |
+44
-1
@@ -1,3 +1,46 @@
|
|||||||
|
## 1.4.4
|
||||||
|
### Bugfixes
|
||||||
|
- Fix snapping for tokens that are smaller than 1x1
|
||||||
|
|
||||||
|
|
||||||
|
## 1.4.3
|
||||||
|
### System compatibility
|
||||||
|
- Drag Ruler's Generic SpeedProvider is now aware of good default values for the Savage Worlds Adventure Edition game system
|
||||||
|
|
||||||
|
### Translation
|
||||||
|
- Added german translation
|
||||||
|
- Updated japanese translation (thanks to touge)
|
||||||
|
|
||||||
|
|
||||||
|
## 1.4.2
|
||||||
|
### Bugfixes
|
||||||
|
- Drag Ruler now works again on gridless maps
|
||||||
|
|
||||||
|
## 1.4.1
|
||||||
|
### Bugfixes
|
||||||
|
- Fixed a bug where Drag Ruler wouldn't work at all on hex grids when the Hex Token Size Support isn't installed
|
||||||
|
|
||||||
|
### Translation
|
||||||
|
- Added chinese translation (thanks to zeteticl)
|
||||||
|
|
||||||
|
|
||||||
|
## 1.4.0
|
||||||
|
### New features
|
||||||
|
- If the [Terrain Ruler module](https://foundryvtt.com/packages/terrain-ruler/) is installed and activated, Drag Ruler will now take difficult terrain that was placed with the [TerrainLayer module](https://foundryvtt.com/packages/TerrainLayer/) into account.
|
||||||
|
- The ruler will now always be drawn from the tokens center (even for tokens larger than 1x1) on all grid types (on Hex Grids this requires the Hex Token Size Support module).
|
||||||
|
- For tokens larger than 1x1 the highlighted path will now reflect the tokens size (on Hex Grids this requires the Hex Token Size Support module)
|
||||||
|
- The GM's Drag Ruler can now be hidden from non GM players via a setting.
|
||||||
|
- When multiple different colors apply to a single grid space because the path crosses itself the color representing ranges further away will take priortiy over colors representing closer ranges.
|
||||||
|
|
||||||
|
### API
|
||||||
|
- Speed providers can now selectively ignore difficult terrain and even implement their own cost functions, if the default Drag Ruler behavior doesn't fit the game system. This can be achieved by overriding the new, optional `SpeedProvider` function `getCostForStep`.
|
||||||
|
|
||||||
|
|
||||||
|
## 1.3.5
|
||||||
|
### Bugfixes
|
||||||
|
- Fixed a regression where spaces could suddenly change their color during measurement
|
||||||
|
|
||||||
|
|
||||||
## 1.3.4
|
## 1.3.4
|
||||||
### Module compatibility
|
### Module compatibility
|
||||||
- Increased compatiblility with other modules (namely Drag Ruler and Terrain Ruler are no longer incompatible)
|
- Increased compatiblility with other modules (namely Drag Ruler and Terrain Ruler are no longer incompatible)
|
||||||
@@ -9,7 +52,7 @@
|
|||||||
|
|
||||||
## 1.3.2
|
## 1.3.2
|
||||||
### Translation
|
### Translation
|
||||||
- Updated japanese translation (thanks to togue)
|
- Updated japanese translation (thanks to touge)
|
||||||
|
|
||||||
|
|
||||||
## 1.3.1
|
## 1.3.1
|
||||||
|
|||||||
@@ -15,6 +15,13 @@ You can add waypoints to the path by pressing spacebar while you drag the token.
|
|||||||
|
|
||||||

|

|
||||||
|
|
||||||
|
## Difficult Terrain
|
||||||
|
**To use support for difficult terrain you must install the [Terrain Ruler module](https://foundryvtt.com/packages/terrain-ruler)**
|
||||||
|
|
||||||
|
With the Terrain Ruler module installed, Drag Ruler is able to take difficult terrain that was placed with the [TerrainLayer module](https://foundryvtt.com/packages/TerrainLayer/) into account when measuring distances.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
|
||||||
## Why would I want to use this instead of ShowDragDistance?
|
## Why would I want to use this instead of ShowDragDistance?
|
||||||
ShowDragDistance isn't maintained anymore. This means that it is at risk to stop working with every foundry update. In fact this process has already begun. As of Foundry Version 0.7.9 ShowDragDistance doesn't work anymore on gridless maps. Drag Ruler on the other hand is fully compatible with the current Foundry release and I'll continue updating it for future foundry releases for the forseeable future.
|
ShowDragDistance isn't maintained anymore. This means that it is at risk to stop working with every foundry update. In fact this process has already begun. As of Foundry Version 0.7.9 ShowDragDistance doesn't work anymore on gridless maps. Drag Ruler on the other hand is fully compatible with the current Foundry release and I'll continue updating it for future foundry releases for the forseeable future.
|
||||||
@@ -34,7 +41,9 @@ The game systems that offer Drag Ruler integration are:
|
|||||||
|
|
||||||
## Translations
|
## Translations
|
||||||
Drag Ruler is available in the follwing languages:
|
Drag Ruler is available in the follwing languages:
|
||||||
|
- Chinese (thanks to zeteticl)
|
||||||
- English
|
- English
|
||||||
|
- German
|
||||||
- Japanese (thanks to touge)
|
- Japanese (thanks to touge)
|
||||||
|
|
||||||
## API
|
## API
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
{
|
||||||
|
"drag-ruler": {
|
||||||
|
"genericSpeedProvider": {
|
||||||
|
"settings": {
|
||||||
|
"dashMultiplier": {
|
||||||
|
"name": "Sprint Multiplikator",
|
||||||
|
"hint": "Diese Einstellung kann genutzt werden, um eine zweite Geschwindigkeitsfarbe im gemessenen Pfad zu erhalten. Die zweite Farbe wird deaktiviert, wenn diese Einstellung auf 0 gesetzt ist."
|
||||||
|
},
|
||||||
|
"speedAttribute": {
|
||||||
|
"name": "Geschwindigkeitsattribut",
|
||||||
|
"hint": "Das Attribut, das die Gehgeschwindigkeit einer Spielfigur definiert. Diese Attribut wird während der Färbung des hervorgehobenen Pfads verwendet."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"speeds": {
|
||||||
|
"walk": "gehen",
|
||||||
|
"dash": "sprinten"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"alwaysShowSpeedForPCs": {
|
||||||
|
"name": "Geschwindigkeit von Spielercharakteren für jeden anzeigen",
|
||||||
|
"hint": "Wenn diese Einstellung aktiviert ist wird die Färbung der hervorgehobenen Felder bei Spielercharakteren allen Spielern angezeigt, selbst wenn diese keinen Zugriff auf den Charakterbogen haben."
|
||||||
|
},
|
||||||
|
"showGMRulerToPlayers": {
|
||||||
|
"name": "Lineal des Sipelleiters bei Spielern anzeigen",
|
||||||
|
"hint": "Wenn diese Option deaktiviert ist wird das Lineal des Spielleiters bei den anderen Spielern nicht angezeigt."
|
||||||
|
},
|
||||||
|
"speedProviderSettings": {
|
||||||
|
"name": "Einstellungen zur Spielsystemintegration",
|
||||||
|
"hint": "In diesem Menü befinden sich alle spielsystemspezifischen Einstellungen.",
|
||||||
|
"button": "Einstellungen zur Spielsystemintegration",
|
||||||
|
"windowTitle": "Einstellungen zur Spielsystemintegration",
|
||||||
|
"headers": {
|
||||||
|
"speedProvider": "Spielsystemintegration",
|
||||||
|
"speedProviderSettings": "Integrationsspezifische Einstellungen"
|
||||||
|
},
|
||||||
|
"activeProvider": {
|
||||||
|
"name": "Verwendete Spielsystemintegration",
|
||||||
|
"hint": "Die unten angezeigten Einstellungen hängen von der verwendeten Spielsystemintegration ab. Wenn der Spielleiter eine andere Spielsystemintegration auswählt können sich die zur Verfügung stehnden Einstellungen ändern."
|
||||||
|
},
|
||||||
|
"noSettings": "Diese Spielsystemintegration hat keine Einstellmöglichkeiten",
|
||||||
|
"color": {
|
||||||
|
"name": "Farbe für {colorName}",
|
||||||
|
"hint": "Die Farbe mit der Felder in {colorName} Reichweite hervorgehoben werden",
|
||||||
|
"unreachable": {
|
||||||
|
"name": "unerreichbar",
|
||||||
|
"hint": "Die Farbe für Felder, die von der bewegten Spielfigur nicht erreicht werden können"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"speedProvider": {
|
||||||
|
"name": "Verwendete Spielsystemintegration",
|
||||||
|
"hint": "Wähle aus, welche Spielsystemintegration für die farbliche Hervorhebung der Felder zuständig sein soll. Drag Ruler stellt eine generische Spielsystemintegration zur Verfügung, die grundlegende Funktionalität bietet und bei korrekter konfiguration mit allen Spielsystemen funktionieren sollte. Weitere Spielsystemintegrationen können durch Module und Spielsysteme angeboten werden. Eine andere Spielsystemintegration als die generische auszuwählen kann eine bessere Inegration in das verwendete Spielsystem bieten. Die Optionen unterhalb sind davon abhäng, welche Spielsystemintegration hier ausgewählt wurde.",
|
||||||
|
"choices": {
|
||||||
|
"module": "Modul {name}",
|
||||||
|
"native": "Generisch",
|
||||||
|
"system": "System {name}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"swapSpacebarRightClick": {
|
||||||
|
"name": "Leertaste und Rechtsklick tauschen",
|
||||||
|
"hint": "Die Funktionen der Leertaste und des Rechtsklicks sind während eine Spielfigur bewegt wird vertauscht. Wenn diese Option aktiviert wrid können mit Rechtsklick Wegpunkte gesetzt werden und mit der Leertaste werden sie wieder gelöscht."
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -21,6 +21,10 @@
|
|||||||
"name": "Show PC speed to everyone",
|
"name": "Show PC speed to everyone",
|
||||||
"hint": "If enabled the coloring based on actor speed for player characters will shown to everyone, even if they don't have observer permission for the character sheet."
|
"hint": "If enabled the coloring based on actor speed for player characters will shown to everyone, even if they don't have observer permission for the character sheet."
|
||||||
},
|
},
|
||||||
|
"showGMRulerToPlayers": {
|
||||||
|
"name": "Show GM ruler to players",
|
||||||
|
"hint": "If disabled the ruler of GMs will not be shown for non-GM players"
|
||||||
|
},
|
||||||
"speedProviderSettings": {
|
"speedProviderSettings": {
|
||||||
"name": "Speed Provider Settings",
|
"name": "Speed Provider Settings",
|
||||||
"hint": "The Speed Provider Settings contain all the game system specific settings.",
|
"hint": "The Speed Provider Settings contain all the game system specific settings.",
|
||||||
|
|||||||
@@ -21,6 +21,10 @@
|
|||||||
"name": "プレイヤーキャラクターの移動速度を全員に公開する",
|
"name": "プレイヤーキャラクターの移動速度を全員に公開する",
|
||||||
"hint": "有効にすると、アクターの観察者(Observer)権限を持たない人にも,移動範囲の色分けが表示されるようになります。"
|
"hint": "有効にすると、アクターの観察者(Observer)権限を持たない人にも,移動範囲の色分けが表示されるようになります。"
|
||||||
},
|
},
|
||||||
|
"showGMRulerToPlayers": {
|
||||||
|
"name": "GMのルーラーをプレイヤーに見せる",
|
||||||
|
"hint": "無効の場合、GMのルーラーはプレイヤーに表示されません。"
|
||||||
|
},
|
||||||
"speedProviderSettings": {
|
"speedProviderSettings": {
|
||||||
"name": "移動速度の提供元",
|
"name": "移動速度の提供元",
|
||||||
"hint": "ゲームシステムに固有のすべての設定をここで行います。",
|
"hint": "ゲームシステムに固有のすべての設定をここで行います。",
|
||||||
|
|||||||
@@ -0,0 +1,66 @@
|
|||||||
|
{
|
||||||
|
"drag-ruler": {
|
||||||
|
"genericSpeedProvider": {
|
||||||
|
"settings": {
|
||||||
|
"dashMultiplier": {
|
||||||
|
"name": "快步 倍數",
|
||||||
|
"hint": "這可用於在對測量路徑進行著色的過程中為棋子賦予第二速度。將其設定為0可禁用第二速度。"
|
||||||
|
},
|
||||||
|
"speedAttribute": {
|
||||||
|
"name": "速度屬性",
|
||||||
|
"hint": "定義棋子的行走速度的屬性。在對測量路徑進行著色時使用。"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"speeds": {
|
||||||
|
"walk": "走路",
|
||||||
|
"dash": "快步"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"settings": {
|
||||||
|
"alwaysShowSpeedForPCs": {
|
||||||
|
"name": "向所有人顯示PC速度",
|
||||||
|
"hint": "如果啟用, 玩家的角色(actor)的速度將顯示給所有人,即使他們沒有角色表的觀察者(Observer)權限也是如此。"
|
||||||
|
},
|
||||||
|
"showGMRulerToPlayers": {
|
||||||
|
"name": "向玩家顯示GM標尺",
|
||||||
|
"hint": "如果禁用,則不為非GM玩家顯示GM的標尺"
|
||||||
|
},
|
||||||
|
"speedProviderSettings": {
|
||||||
|
"name": "速度提供者設定",
|
||||||
|
"hint": "速度提供者設定 包括 所有遊戲系統特定的設定。",
|
||||||
|
"button": "速度提供者設定",
|
||||||
|
"windowTitle": "速度提供者設定",
|
||||||
|
"headers": {
|
||||||
|
"speedProvider": "速度提供者設定",
|
||||||
|
"speedProviderSettings": "特定於速度提供者的設定"
|
||||||
|
},
|
||||||
|
"activeProvider": {
|
||||||
|
"name": "當前活動的速度提供者",
|
||||||
|
"hint": "下面顯示的設定 取決於活動的 速度提供者。如果GM選擇其他速度提供者,則可用的設定可能會更改。"
|
||||||
|
},
|
||||||
|
"noSettings": "該速度提供者不提供任何配置選項。",
|
||||||
|
"color": {
|
||||||
|
"name": "{colorName}的顏色",
|
||||||
|
"hint": "將用於為{colorName}範圍內的正方形上色的顏色",
|
||||||
|
"unreachable": {
|
||||||
|
"name": "無法到達",
|
||||||
|
"hint": "指定拖動棋子無法到達的範圍的顏色"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"speedProvider": {
|
||||||
|
"name": "速度設定的提供者",
|
||||||
|
"hint": "選擇在著色期間為棋子提供速度信息的人。DragRuler提供了一個通用速度提供程序, 該提供程序提供了基本功能, 並且如果配置正確,則可以在所有遊戲系統上使用。可以通過遊戲系統和已安裝的Mod來提供更多速度提供程序。選擇與 標準速度提供者 不同的速度提供者可以更好地集成到您所使用的遊戲系統規則中。以下選項取決於此處選擇的速度提供者。",
|
||||||
|
"choices": {
|
||||||
|
"module": "Mod {name}",
|
||||||
|
"native": "一般",
|
||||||
|
"system": "系統 {name}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"swapSpacebarRightClick": {
|
||||||
|
"name": "交換空格鍵並鼠標右鍵",
|
||||||
|
"hint": "交換空格鍵和右鍵點擊在拖動過程中的功能。如果啟用,右鍵單擊將放置航點,空格鍵將刪除它們。"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+14
-3
@@ -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.3.4",
|
"version": "1.4.4",
|
||||||
"minimumCoreVersion" : "0.7.9",
|
"minimumCoreVersion" : "0.7.9",
|
||||||
"compatibleCoreVersion" : "0.7.9",
|
"compatibleCoreVersion" : "0.7.9",
|
||||||
"authors": [
|
"authors": [
|
||||||
@@ -19,6 +19,11 @@
|
|||||||
"speed_provider_settings.html"
|
"speed_provider_settings.html"
|
||||||
],
|
],
|
||||||
"languages": [
|
"languages": [
|
||||||
|
{
|
||||||
|
"lang": "de",
|
||||||
|
"name": "Deutsch",
|
||||||
|
"path": "lang/de.json"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"lang": "en",
|
"lang": "en",
|
||||||
"name": "English",
|
"name": "English",
|
||||||
@@ -28,12 +33,18 @@
|
|||||||
"lang": "ja",
|
"lang": "ja",
|
||||||
"name": "日本語",
|
"name": "日本語",
|
||||||
"path": "lang/ja.json"
|
"path": "lang/ja.json"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"lang": "zh-tw",
|
||||||
|
"name": "正體中文",
|
||||||
|
"path": "lang/zh-tw.json"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"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.3.4.zip",
|
"download": "https://github.com/manuelVo/foundryvtt-drag-ruler/archive/v1.4.4.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",
|
||||||
"bugs": "https://github.com/manuelVo/foundryvtt-drag-ruler/issues"
|
"bugs": "https://github.com/manuelVo/foundryvtt-drag-ruler/issues",
|
||||||
|
"allowBugReporter": true
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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) {
|
export function registerModule(moduleId, speedProvider) {
|
||||||
// Check if a module with the given id exists and is currently enabled
|
// Check if a module with the given id exists and is currently enabled
|
||||||
const module = game.modules.get(moduleId)
|
const module = game.modules.get(moduleId)
|
||||||
|
|||||||
+11
-16
@@ -1,19 +1,14 @@
|
|||||||
|
import {getColorForDistance} from "./main.js"
|
||||||
|
import {highlightTokenShape} from "./util.js"
|
||||||
|
|
||||||
export function getHexSizeSupportTokenGridCenter(token) {
|
export function getHexSizeSupportTokenGridCenter(token) {
|
||||||
const tokenCenterOffset = CONFIG.hexSizeSupport.getCenterOffset(token)
|
const tokenCenterOffset = CONFIG.hexSizeSupport.getCenterOffset(token)
|
||||||
const tokenCenter = {x: token.x + tokenCenterOffset.x, y: token.y + tokenCenterOffset.y}
|
return {x: token.x + tokenCenterOffset.x, y: token.y + tokenCenterOffset.y}
|
||||||
if (token.getFlag("hex-size-support", "borderSize") % 2 === 1)
|
}
|
||||||
return tokenCenter
|
|
||||||
if (canvas.grid.grid.columns) {
|
export function highlightMeasurementTerrainRuler(ray, startDistance, tokenShape=[{x: 0, y: 0}]) {
|
||||||
let hexOffset = canvas.grid.w / 2
|
for (const space of ray.terrainRulerVisitedSpaces.reverse()) {
|
||||||
if (!CONFIG.hexSizeSupport.getAltOrientationFlag(token))
|
const color = getColorForDistance.call(this, startDistance, space.distance)
|
||||||
hexOffset *= -1
|
highlightTokenShape.call(this, space, tokenShape, color)
|
||||||
tokenCenter.x += hexOffset
|
}
|
||||||
}
|
|
||||||
else {
|
|
||||||
let hexOffset = canvas.grid.h / 2
|
|
||||||
if (CONFIG.hexSizeSupport.getAltOrientationFlag(token))
|
|
||||||
hexOffset *= -1
|
|
||||||
tokenCenter.y += hexOffset
|
|
||||||
}
|
|
||||||
return tokenCenter
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
// Wrapper to fix a FoundryVTT bug that causes the return values of canvas.grid.grid.getPixelsFromGridPosition to be ordered inconsistently
|
||||||
|
|
||||||
|
// https://gitlab.com/foundrynet/foundryvtt/-/issues/4705
|
||||||
|
export function getPixelsFromGridPosition(xGrid, yGrid) {
|
||||||
|
if (canvas.grid.isHex) {
|
||||||
|
return canvas.grid.grid.getPixelsFromGridPosition(yGrid, xGrid)
|
||||||
|
}
|
||||||
|
const [x, y] = canvas.grid.grid.getPixelsFromGridPosition(xGrid, yGrid)
|
||||||
|
if (canvas.grid.type === CONST.GRID_TYPES.SQUARE)
|
||||||
|
return [y, x]
|
||||||
|
return [x, y]
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wrapper to fix a FoundryVTT bug that causes the return values of canvas.grid.grid.getPixelsFromGridPosition to be ordered inconsistently
|
||||||
|
// https://gitlab.com/foundrynet/foundryvtt/-/issues/4705
|
||||||
|
export function getGridPositionFromPixels(xPixel, yPixel) {
|
||||||
|
const [x, y] = canvas.grid.grid.getGridPositionFromPixels(xPixel, yPixel)
|
||||||
|
if (canvas.grid.type !== CONST.GRID_TYPES.GRIDLESS)
|
||||||
|
return [y, x]
|
||||||
|
return [x, y]
|
||||||
|
}
|
||||||
+44
-23
@@ -1,4 +1,8 @@
|
|||||||
|
import { getCostFromSpeedProvider } from "./api.js";
|
||||||
|
import {highlightMeasurementTerrainRuler} from "./compatibility.js";
|
||||||
|
import {getGridPositionFromPixels} from "./foundry_fixes.js";
|
||||||
import {getColorForDistance} from "./main.js"
|
import {getColorForDistance} from "./main.js"
|
||||||
|
import {applyTokenSizeOffset, getAreaFromPositionAndShape, getSnapPointForToken, getTokenShape, highlightTokenShape, zip} from "./util.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(draggedToken, selectedTokens) {
|
export async function moveTokens(draggedToken, selectedTokens) {
|
||||||
@@ -102,9 +106,12 @@ export function measure(destination, {gridSpaces=true, snap=false} = {}) {
|
|||||||
return []
|
return []
|
||||||
|
|
||||||
if (snap)
|
if (snap)
|
||||||
destination = new PIXI.Point(...canvas.grid.getCenter(destination.x, destination.y));
|
destination = getSnapPointForToken(destination.x, destination.y, this.draggedToken)
|
||||||
|
|
||||||
const waypoints = this.waypoints.concat([destination]);
|
const waypoints = this.waypoints.concat([destination]);
|
||||||
const centeredWaypoints = waypoints.map(w => new PIXI.Point(...canvas.grid.getCenter(w.x, w.y)))
|
// Move the waypoints to the center of the grid if a size is used that measures from edge to edge
|
||||||
|
const centeredWaypoints = applyTokenSizeOffset(waypoints, this.draggedToken)
|
||||||
|
|
||||||
const r = this.ruler;
|
const r = this.ruler;
|
||||||
this.destination = destination;
|
this.destination = destination;
|
||||||
|
|
||||||
@@ -126,14 +133,22 @@ export function measure(destination, {gridSpaces=true, snap=false} = {}) {
|
|||||||
centeredSegments.push({ray: centeredRay, label})
|
centeredSegments.push({ray: centeredRay, label})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const shape = getTokenShape(this.draggedToken)
|
||||||
|
|
||||||
// Compute measured distance
|
// Compute measured distance
|
||||||
const distances = canvas.grid.measureDistances(centeredSegments, { gridSpaces });
|
const terrainRulerAvailable = game.modules.get("terrain-ruler")?.active && canvas.grid.type !== CONST.GRID_TYPES.GRIDLESS
|
||||||
|
let distances
|
||||||
|
if (terrainRulerAvailable)
|
||||||
|
distances = game.terrainRuler.measureDistances(centeredSegments, {costFunction: (x, y) => getCostFromSpeedProvider(this.draggedToken, getAreaFromPositionAndShape({x, y}, shape), {x, y})});
|
||||||
|
else
|
||||||
|
distances = canvas.grid.measureDistances(centeredSegments, { gridSpaces });
|
||||||
|
|
||||||
let totalDistance = 0;
|
let totalDistance = 0;
|
||||||
for (let [i, d] of distances.entries()) {
|
for (let [i, d] of distances.entries()) {
|
||||||
let s = segments[i];
|
let s = centeredSegments[i];
|
||||||
s.startDistance = totalDistance
|
s.startDistance = totalDistance
|
||||||
totalDistance += d;
|
totalDistance += d;
|
||||||
s.last = i === (segments.length - 1);
|
s.last = i === (centeredSegments.length - 1);
|
||||||
s.distance = d;
|
s.distance = d;
|
||||||
s.text = this._getSegmentLabel(d, totalDistance, s.last);
|
s.text = this._getSegmentLabel(d, totalDistance, s.last);
|
||||||
}
|
}
|
||||||
@@ -149,24 +164,27 @@ export function measure(destination, {gridSpaces=true, snap=false} = {}) {
|
|||||||
rulerColor = getColorForDistance.call(this, totalDistance)
|
rulerColor = getColorForDistance.call(this, totalDistance)
|
||||||
else
|
else
|
||||||
rulerColor = this.color
|
rulerColor = this.color
|
||||||
for (let s of segments) {
|
for (const [s, cs] of zip(segments.reverse(), centeredSegments.reverse())) {
|
||||||
const { ray, label, text, last } = s;
|
const { label, text, last } = cs;
|
||||||
|
|
||||||
// Draw line segment
|
// Draw line segment
|
||||||
r.lineStyle(6, 0x000000, 0.5).moveTo(ray.A.x, ray.A.y).lineTo(ray.B.x, ray.B.y)
|
r.lineStyle(6, 0x000000, 0.5).moveTo(s.ray.A.x, s.ray.A.y).lineTo(s.ray.B.x, s.ray.B.y)
|
||||||
.lineStyle(4, rulerColor, 0.25).moveTo(ray.A.x, ray.A.y).lineTo(ray.B.x, ray.B.y);
|
.lineStyle(4, rulerColor, 0.25).moveTo(s.ray.A.x, s.ray.A.y).lineTo(s.ray.B.x, s.ray.B.y);
|
||||||
|
|
||||||
// Draw the distance label just after the endpoint of the segment
|
// Draw the distance label just after the endpoint of the segment
|
||||||
if (label) {
|
if (label) {
|
||||||
label.text = text;
|
label.text = text;
|
||||||
label.alpha = last ? 1.0 : 0.5;
|
label.alpha = last ? 1.0 : 0.5;
|
||||||
label.visible = true;
|
label.visible = true;
|
||||||
let labelPosition = ray.project((ray.distance + 50) / ray.distance);
|
let labelPosition = cs.ray.project((cs.ray.distance + 50) / cs.ray.distance);
|
||||||
label.position.set(labelPosition.x, labelPosition.y);
|
label.position.set(labelPosition.x, labelPosition.y);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Highlight grid positions
|
// Highlight grid positions
|
||||||
highlightMeasurementNative.call(this, ray, s.startDistance);
|
if (terrainRulerAvailable)
|
||||||
|
highlightMeasurementTerrainRuler.call(this, cs.ray, cs.startDistance, shape)
|
||||||
|
else
|
||||||
|
highlightMeasurementNative.call(this, cs.ray, cs.startDistance, shape);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Draw endpoints
|
// Draw endpoints
|
||||||
@@ -178,7 +196,7 @@ export function measure(destination, {gridSpaces=true, snap=false} = {}) {
|
|||||||
return segments;
|
return segments;
|
||||||
}
|
}
|
||||||
|
|
||||||
export function highlightMeasurementNative(ray, startDistance) {
|
export function highlightMeasurementNative(ray, startDistance, tokenShape=[{x: 0, y: 0}]) {
|
||||||
const spacer = canvas.scene.data.gridType === CONST.GRID_TYPES.SQUARE ? 1.41 : 1;
|
const spacer = canvas.scene.data.gridType === CONST.GRID_TYPES.SQUARE ? 1.41 : 1;
|
||||||
const nMax = Math.max(Math.floor(ray.distance / (spacer * Math.min(canvas.grid.w, canvas.grid.h))), 1);
|
const nMax = Math.max(Math.floor(ray.distance / (spacer * Math.min(canvas.grid.w, canvas.grid.h))), 1);
|
||||||
const tMax = Array.fromRange(nMax+1).map(t => t / nMax);
|
const tMax = Array.fromRange(nMax+1).map(t => t / nMax);
|
||||||
@@ -187,7 +205,7 @@ export function highlightMeasurementNative(ray, startDistance) {
|
|||||||
let prior = null;
|
let prior = null;
|
||||||
|
|
||||||
// Iterate over ray portions
|
// Iterate over ray portions
|
||||||
for ( let [i, t] of tMax.entries() ) {
|
for ( let [i, t] of tMax.reverse().entries() ) {
|
||||||
let {x, y} = ray.project(t);
|
let {x, y} = ray.project(t);
|
||||||
|
|
||||||
// Get grid position
|
// Get grid position
|
||||||
@@ -197,23 +215,26 @@ export function highlightMeasurementNative(ray, startDistance) {
|
|||||||
|
|
||||||
// Highlight the grid position
|
// Highlight the grid position
|
||||||
let [xg, yg] = canvas.grid.grid.getPixelsFromGridPosition(x1, y1);
|
let [xg, yg] = canvas.grid.grid.getPixelsFromGridPosition(x1, y1);
|
||||||
let subDistance = canvas.grid.measureDistances([{ray: new Ray(ray.A, {x: xg, y: yg})}], {gridSpaces: true})[0]
|
const subDistance = canvas.grid.measureDistances([{ray: new Ray(ray.A, {x: xg, y: yg})}], {gridSpaces: true})[0]
|
||||||
let color = dragRuler.getColorForDistance.call(this, startDistance, subDistance)
|
const color = dragRuler.getColorForDistance.call(this, startDistance, subDistance)
|
||||||
canvas.grid.highlightPosition(this.name, {x: xg, y: yg, color: color});
|
const snapPoint = getSnapPointForToken(...canvas.grid.getTopLeft(x, y), this.draggedToken);
|
||||||
|
const [snapX, snapY] = getGridPositionFromPixels(snapPoint.x + 1, snapPoint.y + 1);
|
||||||
|
|
||||||
// Skip the first one
|
|
||||||
prior = [x1, y1];
|
prior = [x1, y1];
|
||||||
if ( i === 0 ) continue;
|
|
||||||
|
|
||||||
// If the positions are not neighbors, also highlight their halfway point
|
// If the positions are not neighbors, also highlight their halfway point
|
||||||
if ( !canvas.grid.isNeighbor(x0, y0, x1, y1) ) {
|
if (i > 0 && !canvas.grid.isNeighbor(x0, y0, x1, y1)) {
|
||||||
let th = tMax[i - 1] + (0.5 / nMax);
|
let th = tMax[i - 1] - (0.5 / nMax);
|
||||||
let {x, y} = ray.project(th);
|
let {x, y} = ray.project(th);
|
||||||
let [x1h, y1h] = canvas.grid.grid.getGridPositionFromPixels(x, y);
|
let [x1h, y1h] = canvas.grid.grid.getGridPositionFromPixels(x, y);
|
||||||
let [xgh, ygh] = canvas.grid.grid.getPixelsFromGridPosition(x1h, y1h);
|
let [xgh, ygh] = canvas.grid.grid.getPixelsFromGridPosition(x1h, y1h);
|
||||||
subDistance = canvas.grid.measureDistances([{ray: new Ray(ray.A, {x: xg, y: yg})}], {gridSpaces: true})[0]
|
const subDistance = canvas.grid.measureDistances([{ray: new Ray(ray.A, {x: xgh, y: ygh})}], {gridSpaces: true})[0]
|
||||||
color = dragRuler.getColorForDistance.call(this, startDistance, subDistance)
|
const color = dragRuler.getColorForDistance.call(this, startDistance, subDistance)
|
||||||
canvas.grid.highlightPosition(this.name, {x: xgh, y: ygh, color: color});
|
const snapPoint = getSnapPointForToken(...canvas.grid.getTopLeft(x, y), this.draggedToken);
|
||||||
|
const [snapX, snapY] = getGridPositionFromPixels(snapPoint.x + 1, snapPoint.y + 1);
|
||||||
|
highlightTokenShape.call(this, {x: snapX, y: snapY}, tokenShape, color);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
highlightTokenShape.call(this, {x: snapX, y: snapY}, tokenShape, color);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+15
-8
@@ -6,6 +6,7 @@ import {measure, moveTokens, onMouseMove} from "./foundry_imports.js"
|
|||||||
import {performMigrations} from "./migration.js"
|
import {performMigrations} from "./migration.js"
|
||||||
import {registerSettings, settingsKey} from "./settings.js"
|
import {registerSettings, settingsKey} from "./settings.js"
|
||||||
import {SpeedProvider} from "./speed_provider.js"
|
import {SpeedProvider} from "./speed_provider.js"
|
||||||
|
import { getSnapPointForToken } from "./util.js"
|
||||||
|
|
||||||
Hooks.once("init", () => {
|
Hooks.once("init", () => {
|
||||||
registerSettings()
|
registerSettings()
|
||||||
@@ -84,6 +85,9 @@ function hookRulerFunctions() {
|
|||||||
|
|
||||||
const originalUpdate = Ruler.prototype.update
|
const originalUpdate = Ruler.prototype.update
|
||||||
Ruler.prototype.update = function (data) {
|
Ruler.prototype.update = function (data) {
|
||||||
|
// Don't show a GMs drag ruler to non GM players
|
||||||
|
if (data.draggedToken && this.user.isGM && !game.user.isGM && !game.settings.get(settingsKey, "showGMRulerToPlayers"))
|
||||||
|
return
|
||||||
if (data.draggedToken) {
|
if (data.draggedToken) {
|
||||||
this.draggedToken = canvas.tokens.get(data.draggedToken)
|
this.draggedToken = canvas.tokens.get(data.draggedToken)
|
||||||
}
|
}
|
||||||
@@ -99,6 +103,12 @@ function hookRulerFunctions() {
|
|||||||
return originalMeasure.call(this, destination, options)
|
return originalMeasure.call(this, destination, options)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const originalEndMeasurement = Ruler.prototype._endMeasurement
|
||||||
|
Ruler.prototype._endMeasurement = function () {
|
||||||
|
originalEndMeasurement.call(this)
|
||||||
|
this.draggedToken = null
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function hookKeyboardManagerFunctions() {
|
function hookKeyboardManagerFunctions() {
|
||||||
@@ -149,7 +159,7 @@ function onTokenLeftDragStart(event) {
|
|||||||
if (canvas.grid.isHex && game.modules.get("hex-size-support")?.active && CONFIG.hexSizeSupport.getAltSnappingFlag(this))
|
if (canvas.grid.isHex && game.modules.get("hex-size-support")?.active && CONFIG.hexSizeSupport.getAltSnappingFlag(this))
|
||||||
tokenCenter = getHexSizeSupportTokenGridCenter(this)
|
tokenCenter = getHexSizeSupportTokenGridCenter(this)
|
||||||
else
|
else
|
||||||
tokenCenter = {x: this.x + canvas.grid.grid.w / 2, y: this.y + canvas.grid.grid.h / 2}
|
tokenCenter = this.center
|
||||||
ruler.clear();
|
ruler.clear();
|
||||||
ruler._state = Ruler.STATES.STARTING;
|
ruler._state = Ruler.STATES.STARTING;
|
||||||
ruler.rulerOffset = {x: tokenCenter.x - event.data.origin.x, y: tokenCenter.y - event.data.origin.y}
|
ruler.rulerOffset = {x: tokenCenter.x - event.data.origin.x, y: tokenCenter.y - event.data.origin.y}
|
||||||
@@ -167,15 +177,15 @@ function onTokenDragLeftDrop(event) {
|
|||||||
if (!ruler.isDragRuler)
|
if (!ruler.isDragRuler)
|
||||||
return false
|
return false
|
||||||
const selectedTokens = canvas.tokens.controlled
|
const selectedTokens = canvas.tokens.controlled
|
||||||
|
ruler._state = Ruler.STATES.MOVING
|
||||||
moveTokens.call(ruler, ruler.draggedToken, selectedTokens)
|
moveTokens.call(ruler, ruler.draggedToken, selectedTokens)
|
||||||
ruler.draggedToken = null
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
function onTokenDragLeftCancel(event) {
|
function onTokenDragLeftCancel(event) {
|
||||||
// This function is invoked by right clicking
|
// This function is invoked by right clicking
|
||||||
const ruler = canvas.controls.ruler
|
const ruler = canvas.controls.ruler
|
||||||
if (!ruler.isDragRuler)
|
if (!ruler.isDragRuler || ruler._state === Ruler.STATES.MOVING)
|
||||||
return false
|
return false
|
||||||
if (ruler._state === Ruler.STATES.MEASURING) {
|
if (ruler._state === Ruler.STATES.MEASURING) {
|
||||||
if (!game.settings.get(settingsKey, "swapSpacebarRightClick")) {
|
if (!game.settings.get(settingsKey, "swapSpacebarRightClick")) {
|
||||||
@@ -207,10 +217,8 @@ function onRulerMoveToken(event) {
|
|||||||
|
|
||||||
function addWaypoint(point, snap=true) {
|
function addWaypoint(point, snap=true) {
|
||||||
if (snap)
|
if (snap)
|
||||||
point = canvas.grid.getCenter(point.x, point.y);
|
point = getSnapPointForToken(point.x, point.y, this.draggedToken)
|
||||||
else
|
this.waypoints.push(new PIXI.Point(point.x, point.y));
|
||||||
point = [point.x, point.y]
|
|
||||||
this.waypoints.push(new PIXI.Point(point[0], point[1]));
|
|
||||||
this.labels.addChild(new PreciseText("", CONFIG.canvasTextStyle));
|
this.labels.addChild(new PreciseText("", CONFIG.canvasTextStyle));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -225,7 +233,6 @@ function deleteWaypoint() {
|
|||||||
else {
|
else {
|
||||||
const token = ruler.draggedToken
|
const token = ruler.draggedToken
|
||||||
ruler._endMeasurement()
|
ruler._endMeasurement()
|
||||||
ruler.draggedToken = null
|
|
||||||
|
|
||||||
// Deactivate the drag workflow in mouse
|
// Deactivate the drag workflow in mouse
|
||||||
token.mouseInteractionManager._deactivateDragEvents();
|
token.mouseInteractionManager._deactivateDragEvents();
|
||||||
|
|||||||
@@ -29,6 +29,15 @@ export function registerSettings() {
|
|||||||
default: true,
|
default: true,
|
||||||
})
|
})
|
||||||
|
|
||||||
|
game.settings.register(settingsKey, "showGMRulerToPlayers", {
|
||||||
|
name: "drag-ruler.settings.showGMRulerToPlayers.name",
|
||||||
|
hint: "drag-ruler.settings.showGMRulerToPlayers.hint",
|
||||||
|
scope: "world",
|
||||||
|
config: true,
|
||||||
|
type: Boolean,
|
||||||
|
default: true,
|
||||||
|
})
|
||||||
|
|
||||||
// This setting will be modified by the api if modules register to it
|
// This setting will be modified by the api if modules register to it
|
||||||
game.settings.register(settingsKey, "speedProvider", {
|
game.settings.register(settingsKey, "speedProvider", {
|
||||||
scope: "world",
|
scope: "world",
|
||||||
|
|||||||
@@ -56,6 +56,22 @@ export class SpeedProvider {
|
|||||||
return 0xFF0000
|
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.
|
* 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
|
* If this is returns `false` for a token Drag Ruler will be disabled for that token. Dragging a token for which this function
|
||||||
|
|||||||
@@ -7,12 +7,16 @@ export function getDefaultSpeedAttribute() {
|
|||||||
return "actor.data.data.mech.speed"
|
return "actor.data.data.mech.speed"
|
||||||
case "pf1":
|
case "pf1":
|
||||||
return "actor.data.data.attributes.speed.land.total"
|
return "actor.data.data.attributes.speed.land.total"
|
||||||
|
case "swade":
|
||||||
|
return "actor.data.data.stats.speed.value"
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
export function getDefaultDashMultiplier() {
|
export function getDefaultDashMultiplier() {
|
||||||
switch (game.system.id) {
|
switch (game.system.id) {
|
||||||
|
case "swade":
|
||||||
|
return 0
|
||||||
case "dnd5e":
|
case "dnd5e":
|
||||||
case "lancer":
|
case "lancer":
|
||||||
case "pf1":
|
case "pf1":
|
||||||
|
|||||||
+150
@@ -0,0 +1,150 @@
|
|||||||
|
import {getPixelsFromGridPosition} from "./foundry_fixes.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 getSnapPointForToken(x, y, token) {
|
||||||
|
if (canvas.grid.isHex && game.modules.get("hex-size-support")?.active && CONFIG.hexSizeSupport.getAltSnappingFlag(token)) {
|
||||||
|
if (token.getFlag("hex-size-support", "borderSize") % 2 === 0) {
|
||||||
|
const snapPoint = CONFIG.hexSizeSupport.findVertexSnapPoint(x, y, token, canvas.grid.grid)
|
||||||
|
return new PIXI.Point(snapPoint.x, snapPoint.y)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return new PIXI.Point(...canvas.grid.getCenter(x, y))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (canvas.grid.isHex || Math.round(token.data.width) % 2 === 1 || token.data.width < 1) {
|
||||||
|
return new PIXI.Point(...canvas.grid.getCenter(x, y))
|
||||||
|
}
|
||||||
|
const [snappedX, snappedY] = canvas.grid.getCenter(x - canvas.grid.w / 2, y - canvas.grid.h / 2)
|
||||||
|
return new PIXI.Point(snappedX + canvas.grid.w / 2, snappedY + canvas.grid.h / 2)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function highlightTokenShape(position, shape, color) {
|
||||||
|
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)
|
||||||
|
shiftedRow = 1
|
||||||
|
else
|
||||||
|
shiftedRow = 0
|
||||||
|
if (canvas.grid.grid.options.columns) {
|
||||||
|
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}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getTokenShape(token) {
|
||||||
|
if (token.scene.data.gridType === CONST.GRID_TYPES.GRIDLESS) {
|
||||||
|
return [{x: 0, y: 0}]
|
||||||
|
}
|
||||||
|
else if (token.scene.data.gridType === CONST.GRID_TYPES.SQUARE) {
|
||||||
|
const topOffset = -Math.floor(token.data.height / 2)
|
||||||
|
const leftOffset = -Math.floor(token.data.width / 2)
|
||||||
|
const shape = []
|
||||||
|
for (let y = 0;y < token.data.height;y++) {
|
||||||
|
for (let x = 0;x < token.data.width;x++) {
|
||||||
|
shape.push({x: x + leftOffset, y: y + topOffset})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return shape
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// Hex grids
|
||||||
|
if (game.modules.get("hex-size-support")?.active && CONFIG.hexSizeSupport.getAltSnappingFlag(token)) {
|
||||||
|
const borderSize = token.data.flags["hex-size-support"].borderSize;
|
||||||
|
let shape = [{x: 0, y: 0}];
|
||||||
|
if (borderSize >= 2)
|
||||||
|
shape = shape.concat([{x: 0, y: -1}, {x: -1, y: -1}]);
|
||||||
|
if (borderSize >= 3)
|
||||||
|
shape = shape.concat([{x: 0, y: 1}, {x: -1, y: 1}, {x: -1, y: 0}, {x: 1, y: 0}]);
|
||||||
|
if (borderSize >= 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 (Boolean(CONFIG.hexSizeSupport.getAltOrientationFlag(token)) !== canvas.grid.grid.options.columns)
|
||||||
|
shape.forEach(space => space.y *= -1);
|
||||||
|
if (canvas.grid.grid.options.columns)
|
||||||
|
shape = shape.map(space => {return {x: space.y, y: space.x}});
|
||||||
|
return shape;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return [{x: 0, y: 0}];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getTokenSize(token) {
|
||||||
|
let w, h;
|
||||||
|
const hexSizeSupportBorderSize = token.data.flags["hex-size-support"]?.borderSize;
|
||||||
|
if (hexSizeSupportBorderSize > 0) {
|
||||||
|
w = h = hexSizeSupportBorderSize
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
w = token.data.width
|
||||||
|
h = token.data.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) {
|
||||||
|
if (game.modules.get("hex-size-support")?.active) {
|
||||||
|
const isAltOrientation = CONFIG.hexSizeSupport.getAltOrientationFlag(token);
|
||||||
|
if (canvas.grid.grid.options.columns) {
|
||||||
|
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))
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user