Compare commits

...

46 Commits

Author SHA1 Message Date
Manuel Vögele 8d67ca01c3 Release v1.14.2 2024-07-28 23:26:33 +02:00
Manuel Vögele 80ff8832fd Add a word of warning about bugs to the readme 2024-07-28 23:24:40 +02:00
Manuel Vögele c787b18fcb Add 1 to hex positions before snapping to avoid rounding issues (fixes #334) 2024-07-28 23:13:23 +02:00
Manuel Vögele c03dbc09ff Always use the token's center as origin for gridless snapping (fixes #336) 2024-07-28 23:03:37 +02:00
Manuel Vögele 27a2b46a8a Revert "Restore rulerOffset for all uses except hex grids (fixes #332)"
This reverts commit ab1f5b4c9b.
2024-07-28 22:47:26 +02:00
Manuel Vögele 94a8e6f147 Release v1.14.1 2024-07-28 09:29:39 +02:00
Manuel Vögele ab1f5b4c9b Restore rulerOffset for all uses except hex grids (fixes #332)
This restores the functinality of gridless, but it is not a proper fix. Most likely all the functionality in foundry_imports.js has to be re-imported at this point
2024-07-28 09:28:13 +02:00
Manuel Vögele 1974e6e4a3 Revert to pre-v12 maeasureDistances to restore gridless functionality 2024-07-28 09:04:41 +02:00
Manuel Vögele cb40c8de50 Release v1.14.0 2024-07-27 23:18:55 +02:00
Manuel Vögele 6da3e65301 Fix some deprecation warnings 2024-07-27 23:14:40 +02:00
Manuel Vögele a7d06eaed3 Make use of new foundry functions for highlightMeasurementNative 2024-07-27 23:14:40 +02:00
Manuel Vögele 18cf63895c Remove v11 compatibility code 2024-07-27 22:03:48 +02:00
n0q 0e2ab35db7 fix hex calculations in v12 2024-07-27 21:55:29 +02:00
Nils 0808f17ee3 Update foundry for v12 2024-07-27 21:55:29 +02:00
Manuel Vögele b649dacdb5 Add World of Darkness 20th ed to supported Game System list 2024-03-25 16:38:38 +01:00
KitCat c490550ed9 Add Support for 5x5 Hex Tokens (#315) 2024-03-06 23:28:16 +01:00
Manuel Vögele f12dbf0e61 Update wall colission error string to it's new location (it's a foundry native string that was moved to a new key) 2024-03-06 22:31:57 +01:00
Manuel Vögele f1fcc52867 Remove v10 support code 2023-06-13 19:53:30 +02:00
Manuel Vögele af03341638 Use token.center instead of calculating the center manually 2023-06-13 18:25:42 +02:00
Manuel Vögele 79db620fc1 Release v1.13.8 2023-06-13 18:08:40 +02:00
Manuel Vögele 8bf075c2ce Use the token center as token position in getMovedDistanceFromToken on gridless scenes (fixes #200) 2023-06-13 18:04:14 +02:00
Manuel Vögele f0c6ce1bcc Release v1.13.7 2023-06-13 17:01:02 +02:00
Manuel Vögele 7b392e5c9d Update module.json to reflect the new discord name 2023-06-13 17:00:48 +02:00
YenBenGrey efe6eac5aa Add default values for the Crucible system (#283) 2023-06-13 09:53:18 +02:00
Manuel Vögele 52b64c3016 Release v1.13.6 2023-06-12 22:22:54 +02:00
Manuel Vögele 48d0d17628 Use canvas.scene.grid.type instead of cnavas.scene.gridType (which is undefined since v10) (fixes #272) 2023-06-12 22:21:19 +02:00
Manuel Vögele 8101381cc4 Remove redundant & broken code path in _computeDistance (fixes #280) 2023-06-12 21:40:04 +02:00
Manuel Vögele 844df150a6 Release v1.13.5 2023-06-12 19:52:33 +02:00
Manuel Vögele 47715e95f6 Replace newly private functions with public alternatives 2023-06-12 19:50:55 +02:00
Manuel Vögele 1dccbcb081 Reformat with prettier 2023-06-12 19:36:20 +02:00
Manuel Vögele 4c3d7ab42a Add .prettierignore 2023-06-12 19:26:44 +02:00
Manuel Vögele 61fc795f7b Correct a typo in a variable name (fixes #255) 2023-06-11 13:46:09 +02:00
Foundry Hub f10fa049b9 Translated using Weblate (Portuguese (Brazil)) (#268)
Currently translated at 100.0% (59 of 59 strings)

Translation: Drag Ruler/main
Translate-URL: https://weblate.foundryvtt-hub.com/projects/drag-ruler/main/pt_BR/

Co-authored-by: eunaumtenhoid <eunaumtenhoid@outlook.com>
2023-06-11 13:20:55 +02:00
Manuel Vögele c844318836 Update module.json to reflect v11 compatiblility 2023-06-11 13:20:11 +02:00
pkonshik 9af692566c Apply changes for v11 compatibility (#277) 2023-06-11 13:17:36 +02:00
Txus d08416777b Wfrp4e default values (#276) 2023-06-10 10:27:42 +02:00
Manuel Vögele 56f506bad2 Release v1.13.4 2023-03-14 16:27:36 +01:00
Manuel Vögele e1d54ed55d Use "cn" as language code for Simplified Chinese, as is done by foundry 2023-03-14 16:24:16 +01:00
eunaumtenhoid 504c242e86 Translated using Weblate (Portuguese (Brazil))
Currently translated at 100.0% (59 of 59 strings)

Translation: Drag Ruler/main
Translate-URL: https://weblate.foundryvtt-hub.com/projects/drag-ruler/main/pt_BR/
2023-03-14 16:22:01 +01:00
eunaumtenhoid a48c199863 Added translation using Weblate (Portuguese (Brazil)) 2023-03-14 16:22:01 +01:00
Manuel Vögele b7ace776d5 Release v1.13.3 2023-02-21 10:02:05 +01:00
bnp800 cf98287afd Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (59 of 59 strings)

Translation: Drag Ruler/main
Translate-URL: https://weblate.foundryvtt-hub.com/projects/drag-ruler/main/zh_Hans/
2023-02-21 09:58:43 +01:00
bnp800 7a3b547741 Added translation using Weblate (Chinese (Simplified)) 2023-02-21 09:58:43 +01:00
Raul Castaño 5329a4056c Translated using Weblate (Spanish)
Currently translated at 100.0% (59 of 59 strings)

Translation: Drag Ruler/main
Translate-URL: https://weblate.foundryvtt-hub.com/projects/drag-ruler/main/es/
2022-11-18 14:17:56 +01:00
Manuel Vögele a65ff4ddb4 Release v1.13.2 2022-10-15 18:40:48 +02:00
Manuel Vögele c2aa47985b Take into account that the hex size support module may not be installed (fixes #241) 2022-10-15 18:39:44 +02:00
18 changed files with 503 additions and 191 deletions
+4
View File
@@ -0,0 +1,4 @@
*.md
*.html
*.json
foundry.js
+59
View File
@@ -1,3 +1,62 @@
## 1.14.2
### Bug fixes
- Fixed a bug where tokens would snap to inconsistent distances on gridless scenes
- Fixed a bug that caused the highlighted path on hex grids to be incorrect
## 1.14.1
### Bug fixes
- The functionality Drag Ruler on gridless has been restored
## 1.14.0
### New features
- Drag Ruler now supports hex tokens of size 5 (thanks KitCat!)
### Compatibility
- Drag Ruler has been updated to work with Foundry v12 (thanks TPNils and N0q!)
## 1.13.8
### Bugfixes
- `getMovedDistanceFromToken` no longer returns incorrect values on gridless maps
## 1.13.7
### Compatibility
- Drag Ruler's generic speed provider is now aware of good defaults for the Crucible game system
## 1.13.6
### Bugfixes
- Fixed a bug that caused no measurements to be shown next to the ruler
- Fixed a bug where diagonal paths would sometimes highlight squares that don't blong to the path on square maps
## 1.13.5
### Compatibility
- Drag Ruler is now compatible with Foundry VTT v11 (thanks to pkonshik for doing much of the porting work!)
- Drag Ruler's generic speed provider is now aware of good defaults for Warhammer Fantasy Roleplay 4th Edition
### Translations
- Updated Portugese (Brazil) translation (thanks eunaumtenhoid!)
## 1.13.4
### Translations
- New translation: Portuguese (Brazil) (thanks eunaumtenhoid!)
- Foundry should now be able to detect the Simplified Chenese translation properly
## 1.13.3
### Translations
- New translation: Chinese (Simplified) (thanks bnp800!)
## 1.13.2
### Bugfixes
- Fixed a bug that prevented pathfinding on hex to work when the hex size support module is not installed
## 1.13.1
### Bugfixes
- Fixed a bug that caused large hex tokens to not snap correctly
+6 -1
View File
@@ -1,13 +1,17 @@
[![ko-fi](https://ko-fi.com/img/githubbutton_sm.svg)](https://ko-fi.com/staebchenfisch)
## Beware of bugs in v12 and onward
Foundry v12 has introduced significant changes to how the grid and the ruler are implemented. While Drag Ruler has now been updated to generally work with v12, quite a lot of bugs remain. This is espeically true for Hex grids, but some bugs affect all the grid types. Some of the issues require a large code rewrite to address them properly. Unfortunately this means that Drag Ruler will not provide the same quality experience (snappyness, bugfreeness) you're used to in v12 (and possibly onward). If you're planning to update to v12 and depend on Drag Ruler, proceed with caution.
# Drag Ruler
This module shows a ruler when you drag a token or measurement template to inform you how far you've dragged it from its start point. Additionally, if you're using a grid, the spaces the token will travel though will be colored depending on your tokens speed. By default, three colors are being used: green for spaces that your token can reach by walking normally are colored green, spaces that can only be reached by dashing will be colored yellow and spaces that cannot be reached with the token's speed will be colored red. If you're using a gridless map the ruler color will change to convey this information.
![Drag Ruler being used on a square grids](https://raw.githubusercontent.com/manuelVo/foundryvtt-drag-ruler/709774b25f7dd818a90591165f74b3e6dbc788cc/media/basic_square.webp)
![Drag Ruler being used on a gridless scene](https://raw.githubusercontent.com/manuelVo/foundryvtt-drag-ruler/709774b25f7dd818a90591165f74b3e6dbc788cc/media/basic_gridless.webp)
![Drag Ruler while dragging a measurement template](https://raw.githubusercontent.com/manuelVo/foundryvtt-drag-ruler/709774b25f7dd818a90591165f74b3e6dbc788cc/media/measurement_template.webp)
## Supports Tokens of all sizes
Terrain ruler has excellent support for tokens of all sizes. The Ruler will always originate from the token's center and will always highlight all the squares that tokens move over.
@@ -66,6 +70,7 @@ The game systems that offer Drag Ruler integration are:
- The Dark Eye 5 / Das Schwarze Auge 5 (via the module [TDE5/DSA5 Drag Ruler Integration](https://foundryvtt.com/packages/dsa5-drag-ruler))
- Shadow of the Demon Lord (starting with version 1.7.15)
- Wasteland Ventures (starting with version 0.1.0)
- World of Darkness 20th ed (starting with version 3.3.0)
- WWII:OWB (starting with version 1.0.4)
+23 -23
View File
@@ -8,24 +8,24 @@
"ok": "OK",
"terrain-ruler": {
"title": "Cómo medir a través de terreno difícil con Drag Ruler",
"text": "You have the {moduleName} module enabled. Drag Ruler is able to measure difficult terrain that was placed down using that module. To make this possible Drag Ruler utilizes the Terrain Ruler module. If Terrain Ruler is installed and activated Drag Ruler will automatically start to respect difficult terrain in it's measurements.",
"text": "Tienes habilitado el módulo {moduleName}. Drag Ruler puede medir terrenos difíciles que se colocaron usando ese módulo. Para hacer esto posible, Drag Ruler utiliza el módulo Terrain Ruler. Si Terrain Ruler está instalado y activado, Drag Ruler automáticamente comenzará a respetar terrenos difíciles en sus medidas.",
"neverShowAgain": "No volver a mostrar"
},
"socketlib": {
"title": "El módulo Socketlib no está instalado",
"text": "Drag Ruler necesita para su funcionamiento correcto que instale socketlib. Por favor, active socketlib en este mundo"
"text": "Drag Ruler necesita para su funcionamiento correcto que instale socketlib. Por favor, active socketlib en este mundo."
}
},
"resetMovementHistory": "Reiniciar historial de movimiento",
"resetMovementHistory": "Reiniciar el historial de movimiento",
"genericSpeedProvider": {
"settings": {
"dashMultiplier": {
"name": "Multiplicador por correr",
"hint": "Se puede usar para aplicar a los iconos una velocidad secundaria que use un color distinto en la medición de la ruta a seguir. Establece el valor a 0 para deshabilitar esta velocidad secundaria"
"hint": "Se puede usar para aplicar a los iconos una velocidad secundaria que use un color distinto en la medición de la ruta a seguir. Establece el valor a 0 para deshabilitar esta velocidad secundaria."
},
"speedAttribute": {
"name": "Attributo de velocidad",
"hint": "El atributo que define la velocidad de movimiento andando del icono. Se usa para los códigos de colores al medir la ruta a seguir"
"hint": "El atributo que define la velocidad de movimiento andando del icono. Se usa para los códigos de colores al medir la ruta a seguir."
}
},
"speeds": {
@@ -39,41 +39,41 @@
"deleteWaypoint": "Borrar punto de ruta",
"disableSnap": {
"name": "Deshabilitar ajuste",
"hint": "El ajuste a la rejilla se deshabilitará temporalmente mientras se presione esta tecla"
"hint": "El ajuste a la rejilla se deshabilitará temporalmente mientras se presione esta tecla."
},
"moveWithoutAnimation": {
"name": "Deshabilitar animación de icono",
"hint": "Si al soltar un icono se presiona esta tecla, se deshabilitará la animación del icono al moverse al destino"
"hint": "Si al soltar un icono se presiona esta tecla, se deshabilitará la animación del icono al moverse al destino."
},
"togglePathfinding": {
"name": "Conmutar búsqueda de camino",
"hint": "Cuando se presione al arrastrar un icono, la funcionalidad de búsqueda de camino será temporalmente habilitada/deshabilitada"
"hint": "Cuando se presione al arrastrar un icono, la funcionalidad de búsqueda de camino será temporalmente habilitada/deshabilitada."
}
},
"settings": {
"allowPathfinding": {
"name": "Permitir búsqueda de camino a los jugadores",
"hint": "Permite a los jugadores usar en este mundo la funcionalidad de búsqueda de camino. Tenga cuidado porque la ruta puede transcurrir por lugares con niebla de guerra o muros invisibles, lo que podrá revelar algunos secretos a los jugadores antes de tiempo"
"hint": "Permite a los jugadores usar en este mundo la funcionalidad de búsqueda de camino. Tenga cuidado porque la ruta puede transcurrir por lugares con niebla de guerra o muros invisibles, lo que podrá revelar algunos secretos a los jugadores antes de tiempo."
},
"alwaysShowSpeedForPCs": {
"name": "Mostrar velocidad de los PJs a todo el mundo",
"hint": "Si se habilita, se mostrará a todo el mundo los códigos de colores de las rutas de los PJs, incluso si no tienen permisos de observador para ese personaje"
"hint": "Si se habilita, se mostrará a todo el mundo los códigos de colores de las rutas de los PJs, incluso si no tienen permisos de observador para ese personaje."
},
"autoStartMeasurement": {
"name": "Comenzar a medir automáticamente",
"hint": "Si se habilita, Drag Ruler comenzará a medir en cuanto se comience a arrastrar un icono. Si se deshabilita, Drag Ruler permanecerá inactivo y comenzará a medir únicamente cuando se presione el botón configurado para añadir un nuevo punto de ruta"
"hint": "Si se habilita, Drag Ruler comenzará a medir en cuanto se comience a arrastrar un icono. Si se deshabilita, Drag Ruler permanecerá inactivo y comenzará a medir únicamente cuando se presione el botón configurado para añadir un nuevo punto de ruta."
},
"autoPathfinding": {
"name": "Búsqueda de camino por defecto",
"hint": "Si se habilita, al arrastrar un icono se usará automáticamente la regla de búsqueda de camino"
"hint": "Si se habilita, al arrastrar un icono se usará automáticamente la regla de búsqueda de camino."
},
"enableMovementHistory": {
"name": "Habilitar historial de movimiento durante el combate",
"hint": "Si se habilita, Drag Ruler recordará la ruta que ha seguido un icono en su turno y la mostrará al seleccionarlo de nuevo"
"hint": "Si se habilita, Drag Ruler recordará la ruta que ha seguido un icono en su turno de combate y la mostrará al seleccionarlo de nuevo."
},
"rightClickAction": {
"name": "Acción del botón derecho",
"hint": "Qué acción se llevará a cabo cuando se haga clic derecho mientras se arrastra un icono",
"hint": "¿Qué acción se realizará al hacer clic derecho mientras se arrastra un icono?",
"choices": {
"create": "Crear punto de ruta",
"delete": "Borrar punto de ruta",
@@ -82,11 +82,11 @@
},
"showGMRulerToPlayers": {
"name": "Mostrar regla del GM a los jugadores",
"hint": "Si se deshabilita, no se mostrará la regla de medición de los GMs al resto de usuarios"
"hint": "Si se deshabilita, no se mostrará la regla de medición de los GMs al resto de usuarios no-GMs."
},
"speedProviderSettings": {
"name": "Proveedor de configuración de velocidad",
"hint": "El proveedor de ajustes de velocidad contiene todos los ajustes específicos de cada sistema",
"hint": "El Proveedor de Ajustes de Velocidad contiene todos los ajustes específicos de cada sistema de juego.",
"button": "Proveedor de configuración de velocidad",
"windowTitle": "Proveedor de configuración de velocidad",
"headers": {
@@ -94,21 +94,21 @@
"speedProviderSettings": "Configuraciones específicas del proveedor de velocidad"
},
"activeProvider": {
"name": "Proveedor de velocidad actualmente activo",
"hint": "La configuración que se muestra más abajo depende del proveedor de velocidad activo. Si el GM selecciona un proveedor distinto, los ajustes disponibles puede que cambien"
"name": "Proveedor de Velocidad Activo",
"hint": "La configuración que se muestra más abajo depende del proveedor de velocidad activo. Si el GM selecciona un proveedor distinto, los ajustes disponibles puede que cambien."
},
"noSettings": "Este proveedor de velocidad no dispone de ninguna opción de configuración",
"noSettings": "Este proveedor de velocidad no dispone de ninguna opción de configuración.",
"color": {
"name": "Color para {colorName}",
"hint": "Color que se usará para establecer el tono de las cuadrículas que se encuentran dentro del rango {colorName}",
"hint": "Color que se usará para establecer el tono de las cuadrículas que se encuentran dentro del rango {colorName}.",
"unreachable": {
"name": "inalcanzable",
"hint": "Color que se usará para las cuadrículas más allá de la distancia máxima de movimiento del icono"
"hint": "Color que se usará para las cuadrículas más allá de la distancia máxima de movimiento del icono."
}
},
"speedProvider": {
"name": "Proveedor de configuración de velocidad",
"hint": "Seleccione quien suministra la información de la velocidad de los iconos a la hora de colorear la ruta a seguir. Drag Ruler incluye un proveedor genérico que ofrece una funcionalidad básica y que probablemente funcione para casi todos los sistemas si se usa de forma correcta. Se pueden añadir otros proveedores de velocidad al instalar sistemas o módulos. Seleccionar un proveedor distinto al genérico asegurará una mejor integración con las reglas del sistema que está usando. Las opciones siguientes dependerán del proveedor que seleccione",
"hint": "Seleccione quien suministra la información de la velocidad de los iconos a la hora de colorear la ruta a seguir. Drag Ruler incluye un proveedor genérico que ofrece una funcionalidad básica y que probablemente funcione para casi todos los sistemas si se usa de forma correcta. Se pueden añadir otros proveedores de velocidad al instalar sistemas o módulos. Seleccionar un proveedor distinto al genérico asegurará una mejor integración con las reglas del sistema que está usando. Las opciones siguientes dependerán del proveedor que seleccione.",
"choices": {
"module": "Módulo {name}",
"native": "Genérico",
@@ -118,7 +118,7 @@
},
"useGridlessRaster": {
"name": "Usar ajuste a la velocidad",
"hint": "Cuando no se use rejilla en la escena, este ajuste hace que los iconos se ajusten a sus rangos de velocidad. Se puede deshabilitar temporalmente pulsando la tecla Mayús mientras se arrastra"
"hint": "Cuando no se use rejilla en la escena, este ajuste hace que los iconos se ajusten a sus rangos de velocidad."
}
}
}
+121
View File
@@ -0,0 +1,121 @@
{
"drag-ruler": {
"dependencies": {
"ok": "Ok",
"terrain-ruler": {
"neverShowAgain": "Nunca mostre isso de novo",
"title": "Como medir terrenos difíceis com o Drag Ruler",
"text": "Você tem o módulo {moduleName} habilitado. Drag Ruler é capaz de medir terreno difícil que foi colocado para baixo usando esse módulo. Para tornar isto possível, Drag Ruler utiliza o módulo Terrain Ruler. Se o Terrain Ruler for instalado e ativado, o Drag Ruler começará automaticamente a respeitar o terreno difícil em suas medições."
},
"socketlib": {
"title": "Módulo Socketlib ausente",
"text": "Drag Ruler requer que o módulo socketlib funcione corretamente. Por favor, ative o módulo socketlib neste mundo."
}
},
"resetMovementHistory": "Redefinir histórico de movimento",
"genericSpeedProvider": {
"settings": {
"dashMultiplier": {
"name": "Traço Multiplicador",
"hint": "Isso pode ser usado para dar aos tokens uma velocidade secundária durante a coloração do caminho medido. Defina-o como 0 para desativar a velocidade secundária."
},
"speedAttribute": {
"name": "Atributo de velocidade",
"hint": "O atributo que define a velocidade de caminhada de um token. Isso é usado durante a coloração do caminho medido."
}
},
"speeds": {
"walk": "andar",
"dash": "traço"
}
},
"keybindings": {
"cancelDrag": "Cancelar o arrasto",
"disableSnap": {
"name": "Desativar encaixe",
"hint": "O encaixe será desativado temporariamente enquanto esta tecla estiver pressionada."
},
"createWaypoint": "Criar parada",
"deleteWaypoint": "Apagar parada",
"togglePathfinding": {
"name": "Alternar localização de caminhos",
"hint": "Ao ser segurado enquanto arrasta um token, a funcionalidade de localização de caminhos será temporariamente habilitada/desabilitada."
},
"moveWithoutAnimation": {
"name": "Desativar animação de token",
"hint": "Ao ser segurado ao soltar um token, o token se moverá para o local de destino sem animação."
}
},
"settings": {
"allowPathfinding": {
"name": "Permitir localização de caminhos para jogadores",
"hint": "Permite que os jogadores usem a funcionalidade de localização de caminhos do Drag Ruler neste mundo. Esteja ciente de que a localização de caminhos pode passar por uma névoa de guerra inexplorada e paredes etéreas, que podem revelar segredos para seus jogadores antes do tempo."
},
"alwaysShowSpeedForPCs": {
"name": "Mostre a velocidade do PJ para todos",
"hint": "Se ativado, a coloração baseada na velocidade do ator para os personagens dos jogadores será mostrada a todos, mesmo que eles não tenham permissão de observador para a ficha de personagem."
},
"autoStartMeasurement": {
"name": "Iniciar a medição automaticamente",
"hint": "Se ativado, Drag Ruler começará a medir assim que o token estiver sendo arrastado. Se desativado, o Drag Ruler permanecerá inativo e só começará a medir quando o botão para adicionar uma parada for pressionado."
},
"autoPathfinding": {
"hint": "Se ativado, arrastar um token usará automaticamente uma régua de localização de caminho.",
"name": "localização de caminho por padrão"
},
"enableMovementHistory": {
"name": "Habilitar histórico de movimento durante o combate",
"hint": "Se ativado, o Drag Ruler lembrará o caminho que um token percorreu durante seu turno em combate e o exibirá quando você pegar o token de volta."
},
"rightClickAction": {
"name": "Ação do botão direito",
"hint": "Que ação deve ser executada ao clicar com o botão direito do mouse enquanto arrasta um token?",
"choices": {
"create": "Criar parada",
"delete": "Apagar parada",
"cancel": "Cancelar arrasto"
}
},
"showGMRulerToPlayers": {
"name": "Mostrar régua do GM aos jogadores",
"hint": "Se desativado, a régua dos GMs não será exibido para jogadores não-GM."
},
"speedProviderSettings": {
"name": "Configurações do provedor de velocidade",
"button": "Configurações do provedor de velocidade",
"windowTitle": "Configurações do provedor de velocidade",
"headers": {
"speedProvider": "Provedor de velocidade",
"speedProviderSettings": "Configurações específicas do provedor de velocidade"
},
"activeProvider": {
"name": "Provedor de velocidade ativo",
"hint": "As configurações mostradas abaixo dependem do provedor de velocidade ativo. Se o GM selecionar um provedor de velocidade diferente, as configurações disponíveis podem mudar."
},
"noSettings": "Este provedor de velocidade não oferece nenhuma opção de configuração.",
"color": {
"name": "Cor para {colorName}",
"hint": "A cor que será usada para colorir os quadrados que estão dentro do intervalo {colorName}.",
"unreachable": {
"name": "inacessível",
"hint": "A cor dos espaços que não podem ser acessados pelo token arrastado."
}
},
"speedProvider": {
"name": "Provedor de configurações de velocidade",
"hint": "Selecione quem fornece informações de velocidade para tokens durante a coloração. Drag Ruler oferece um provedor de velocidade genérico que fornece funcionalidade básica e deve funcionar para todos os sistemas de jogo se configurado corretamente. Mais provedores de velocidade podem ser disponibilizados por meio de sistemas de jogos e módulos instalados. Selecionar um provedor de velocidade diferente do provedor de velocidade genérico pode oferecer uma melhor integração com as regras do sistema de jogo que você está usando. As opções abaixo dependem do provedor de velocidade selecionado aqui.",
"choices": {
"module": "Módulo {name}",
"native": "Genérico",
"system": "Sistema {name}"
}
},
"hint": "As configurações do provedor de velocidade contêm todas as configurações específicas do sistema de jogo."
},
"useGridlessRaster": {
"name": "Use o ajuste baseado em velocidade",
"hint": "Em cenas sem grid, isso faz com que os tokens se encaixem nas faixas de velocidade do token."
}
}
}
}
+121
View File
@@ -0,0 +1,121 @@
{
"drag-ruler": {
"dependencies": {
"ok": "OK",
"terrain-ruler": {
"title": "Drag Ruler 如何测量困难地形",
"text": "你已启用 {moduleName}。Drag Ruler 可以使用此模组测量放置的困难地形。为此,Drag Ruler 将使用 Terrain Ruler 模组。如果已经安装并启用了 Terrain RulerDrag Ruler 将自动开始在测量中反映困难地形的结果。",
"neverShowAgain": "不再显示此条"
},
"socketlib": {
"title": "Socketlib 模组未安装/启用",
"text": "Drag Ruler 依赖于 socketlib 模组以正常运行。请在该世界中激活 socketlib 模组。"
}
},
"resetMovementHistory": "重置移动历史",
"settings": {
"alwaysShowSpeedForPCs": {
"name": "向所有人展示 PC 的速度",
"hint": "启用后,基于 PC 速度的着色将会展示给所有人,即使并未对该角色有观察权限。"
},
"speedProviderSettings": {
"speedProvider": {
"choices": {
"native": "通用",
"system": "系统 {name}",
"module": "模组 {name}"
},
"name": "速度设置提供方",
"hint": "选择指示物移动着色时,速度信息的提供方。Drag Ruler 自带通用的速度提供方,提供基础功能并且在配置正确时,应对所有游戏系统都有效。游戏系统和安装的模组可能会提供可用的新速度提供方。选择其他速度提供方替换通用速度提供方可能会与正在使用的游戏系统的规则整合得更好。下列的选项依赖于此处选择的速度提供方。"
},
"name": "速度提供方设置",
"hint": "速度提供方设置内包含了所有游戏系统相关的设置。",
"button": "速度提供方设置",
"windowTitle": "速度提供方设置",
"headers": {
"speedProvider": "速度提供",
"speedProviderSettings": "速度提供方特定设置"
},
"activeProvider": {
"name": "激活的速度提供方",
"hint": "下方显示的此设置依赖于一个激活的速度提供方。如果 GM 选择了其他的速度提供方,可用的设置项可能会改变。"
},
"noSettings": "此速度提供方并不提供任何配置项。",
"color": {
"name": "颜色 {colorName}",
"hint": "将在 {colorName} 范围内的色彩格子内使用的颜色。",
"unreachable": {
"name": "不可抵达",
"hint": "拖拽指示物时显示的不可抵达的格子的颜色。"
}
}
},
"useGridlessRaster": {
"name": "使用基于速度的吸附",
"hint": "在无网格场景中,这使得指示物吸附至其速度范围。"
},
"allowPathfinding": {
"name": "允许玩家寻路",
"hint": "允许玩家在此世界中使用Drag Ruler的寻路功能。注意寻路可能经过未探索的战争迷雾和虚体墙,这可能提前向玩家暴露秘密。"
},
"autoStartMeasurement": {
"name": "自动测量",
"hint": "如果启用此选项,在你拖动棋子时标尺会自动显示,如果禁用,拖动棋子时将不会启用标尺,仅在按下显示路径按钮时显示。"
},
"autoPathfinding": {
"name": "默认寻路",
"hint": "若启用,拖动指示物会自动使用寻路标尺。"
},
"enableMovementHistory": {
"name": "在战斗时启用移动历史",
"hint": "启用后,Drag Ruler 将会记住指示物在战斗中其回合内行经的路径,并且会在拉起指示物时显示。"
},
"rightClickAction": {
"name": "右键点击动作",
"hint": "拖动指示物时点击右键应该执行什么动作?",
"choices": {
"create": "创建路径点",
"delete": "删除路径点",
"cancel": "取消拖动"
}
},
"showGMRulerToPlayers": {
"name": "向玩家展示 GM 尺子",
"hint": "禁用后,GM 的测量尺将不会向非 GM 玩家展示。"
}
},
"genericSpeedProvider": {
"settings": {
"dashMultiplier": {
"name": "疾跑倍数",
"hint": "此项可以赋予测量路径着色的指示物第二速度显示。将此项设置为 0 以禁用第二速度。"
},
"speedAttribute": {
"name": "速度字段",
"hint": "该字段定义了指示物的步行速度,用于测量路径的着色。"
}
},
"speeds": {
"walk": "步行",
"dash": "疾跑"
}
},
"keybindings": {
"cancelDrag": "取消拖动",
"createWaypoint": "创建路径点",
"deleteWaypoint": "删除路径点",
"disableSnap": {
"name": "禁用吸附",
"hint": "按下此键时吸附会被暂时禁用。"
},
"moveWithoutAnimation": {
"name": "禁用指示物动画",
"hint": "放置指示物时按住,则指示物将直接移动至目标地点。"
},
"togglePathfinding": {
"name": "寻路开关",
"hint": "拖动指示物时按住,寻路功能便会暂时启用/禁用。"
}
}
}
}
+16 -5
View File
@@ -2,16 +2,17 @@
"id": "drag-ruler",
"title": "Drag Ruler",
"description": "When dragging a token displays a ruler showing how far you've moved that token.",
"version": "1.13.1",
"version": "1.14.2",
"compatibility": {
"minimum": "10",
"verified": "10"
"minimum": "12",
"verified": "12",
"maximum": "12"
},
"authors": [
{
"name": "Manuel Vögele",
"email": "develop@manuel-voegele.de",
"discord": "Stäbchenfisch#5107"
"discord": "stabchenfisch"
}
],
"esmodules": [
@@ -57,6 +58,16 @@
"lang": "zh-tw",
"name": "正體中文",
"path": "lang/zh-tw.json"
},
{
"lang": "cn",
"name": "中文(简体)",
"path": "lang/zh_Hans.json"
},
{
"lang": "pt-BR",
"name": "Português (Brasil)",
"path": "lang/pt_BR.json"
}
],
"relationships": {
@@ -70,7 +81,7 @@
},
"socket": true,
"url": "https://github.com/manuelVo/foundryvtt-drag-ruler",
"download": "https://github.com/manuelVo/foundryvtt-drag-ruler/archive/v1.13.1.zip",
"download": "https://github.com/manuelVo/foundryvtt-drag-ruler/archive/v1.14.2.zip",
"manifest": "https://raw.githubusercontent.com/manuelVo/foundryvtt-drag-ruler/master/module.json",
"readme": "https://github.com/manuelVo/foundryvtt-drag-ruler/blob/master/README.md",
"changelog": "https://github.com/manuelVo/foundryvtt-drag-ruler/blob/master/CHANGELOG.md",
+5 -1
View File
@@ -133,8 +133,12 @@ export function getColorForDistanceAndToken(distance, token, ranges = null) {
export function getMovedDistanceFromToken(token) {
const terrainRulerAvailable = game.modules.get("terrain-ruler")?.active;
const history = getMovementHistory(token);
let tokenPos = {x: token.x, y: token.y};
if (canvas.grid.type === CONST.GRID_TYPES.GRIDLESS) {
tokenPos = token.center;
}
const segments = CONFIG.Canvas.rulerClass
.dragRulerGetRaysFromWaypoints(history, {x: token.x, y: token.y})
.dragRulerGetRaysFromWaypoints(history, tokenPos)
.map(ray => {
return {ray};
});
+3 -3
View File
@@ -15,10 +15,10 @@ export function highlightMeasurementTerrainRuler(
}
export function measureDistances(segments, entity, shape, options = {}) {
const opts = duplicate(options);
const opts = foundry.utils.duplicate(options);
if (canvas.grid.diagonalRule === "EUCL") {
opts.ignoreGrid = true;
opts.gridSpaes = false;
opts.gridSpaces = false;
}
if (opts.enableTerrainRuler) {
opts.gridSpaces = true;
@@ -31,7 +31,7 @@ export function measureDistances(segments, entity, shape, options = {}) {
);
previousSegments.forEach(
segment =>
(segment.ray.terrainRulerVisitedSpaces = duplicate(segment.ray.dragRulerVisitedSpaces)),
(segment.ray.terrainRulerVisitedSpaces = foundry.utils.duplicate(segment.ray.dragRulerVisitedSpaces)),
);
opts.costFunction = buildCostFunction(entity, shape);
if (previousSegments.length > 0)
+11 -16
View File
@@ -1,31 +1,26 @@
// 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
// This code could be phased out. The bug that caused the creation of these functions is now fixed, so this is only a wrapper function now
export function getPixelsFromGridPosition(xGrid, yGrid) {
if (canvas.grid.type !== CONST.GRID_TYPES.GRIDLESS) {
return canvas.grid.grid.getPixelsFromGridPosition(yGrid, xGrid);
}
return canvas.grid.grid.getPixelsFromGridPosition(xGrid, yGrid);
let coord = getPixelsFromGridPositionObj({x: xGrid, y: yGrid});
return [coord.x, coord.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
// This code could be phased out. The bug that caused the creation of these functions is now fixed, so this is only a wrapper function now
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];
let coord = getGridPositionFromPixelsObj({x: xPixel, y: yPixel});
return [coord.x, coord.y];
}
// This code could be phased out. The bug that caused the creation of these functions is now fixed, so this is only a wrapper function now
export function getGridPositionFromPixelsObj(o) {
const r = {};
[r.x, r.y] = getGridPositionFromPixels(o.x, o.y);
return r;
const coord = canvas.grid.getOffset(o);
return {x: coord.j, y: coord.i};
}
// This code could be phased out. The bug that caused the creation of these functions is now fixed, so this is only a wrapper function now
export function getPixelsFromGridPositionObj(o) {
const r = {};
[r.x, r.y] = getPixelsFromGridPosition(o.x, o.y);
return r;
return canvas.grid.getTopLeftPoint({j: o.x, i: o.y});
}
export function getCenterFromGridPositionObj(o) {
+14 -47
View File
@@ -35,7 +35,8 @@ export async function moveEntities(draggedEntity, selectedEntities) {
);
});
if (hasCollision) {
ui.notifications.error(game.i18n.localize("ERROR.TokenCollide"));
ui.notifications.error(game.i18n.localize("RULER.MovementCollision"));
this._state = Ruler.STATES.MEASURING;
this._endMeasurement();
return true;
}
@@ -47,7 +48,10 @@ export async function moveEntities(draggedEntity, selectedEntities) {
await animateEntities.call(this, selectedEntities, draggedEntity, rays, wasPaused);
// Once all animations are complete we can clear the ruler
if (this.draggedEntity?.id === draggedEntity.id) this._endMeasurement();
if (this.draggedEntity?.id === draggedEntity.id) {
this._state = Ruler.STATES.MEASURING;
this._endMeasurement();
}
}
// This is a modified version code extracted from Ruler.moveToken from foundry 0.7.9
@@ -133,8 +137,8 @@ export function onMouseMove(event) {
// Extract event data
const destination = {
x: event.data.destination.x + this.rulerOffset.x,
y: event.data.destination.y + this.rulerOffset.y,
x: event.interactionData.destination.x,
y: event.interactionData.destination.y,
};
// Hide any existing Token HUD
@@ -148,7 +152,7 @@ export function onMouseMove(event) {
function scheduleMeasurement(destination, event) {
const measurementInterval = 50;
const mt = event._measureTime || 0;
const originalEvent = event.data.originalEvent;
const originalEvent = event.interactionData.originalEvent;
if (Date.now() - mt > measurementInterval) {
this.measure(destination, {snap: !disableSnap});
event._measureTime = Date.now();
@@ -185,51 +189,14 @@ export function highlightMeasurementNative(
tokenShape = [{x: 0, y: 0}],
alpha = 1,
) {
const spacer = canvas.scene.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 tMax = Array.fromRange(nMax + 1).map(t => t / nMax);
// Track prior position
let prior = null;
// Iterate over ray portions
for (let [i, t] of tMax.reverse().entries()) {
let {x, y} = ray.project(t);
// Get grid position
let [x0, y0] = i === 0 ? [null, null] : prior;
let [x1, y1] = canvas.grid.grid.getGridPositionFromPixels(x, y);
if (x0 === x1 && y0 === y1) continue;
// Highlight the grid position
let [xgtl, ygtl] = canvas.grid.grid.getPixelsFromGridPosition(x1, y1);
let [xg, yg] = canvas.grid.grid.getCenter(xgtl, ygtl);
const pathUntilSpace = previousSegments.concat([{ray: new Ray(ray.A, {x: xg, y: yg})}]);
for (const offset of canvas.grid.getDirectPath([ray.A, ray.B]).reverse()) {
const point = canvas.grid.getTopLeftPoint(offset);
const center = canvas.grid.getCenterPoint(offset);
const pathUntilSpace = previousSegments.concat([{ray: new Ray(ray.A, center)}]);
const distance = sum(canvas.grid.measureDistances(pathUntilSpace, {gridSpaces: true}));
const color = this.dragRulerGetColorForDistance(distance);
const snapPoint = getSnapPointForToken(...canvas.grid.getTopLeft(x, y), this.draggedEntity);
const snapPoint = getSnapPointForToken(point.x + 1, point.y + 1, this.draggedEntity);
const [snapX, snapY] = getGridPositionFromPixels(snapPoint.x + 1, snapPoint.y + 1);
prior = [x1, y1];
// If the positions are not neighbors, also highlight their halfway point
if (i > 0 && !canvas.grid.isNeighbor(x0, y0, x1, y1)) {
let th = tMax[i - 1] - 0.5 / nMax;
let {x, y} = ray.project(th);
let [x1h, y1h] = canvas.grid.grid.getGridPositionFromPixels(x, y);
let [xghtl, yghtl] = canvas.grid.grid.getPixelsFromGridPosition(x1h, y1h);
let [xgh, ygh] = canvas.grid.grid.getCenter(xghtl, yghtl);
const pathUntilSpace = previousSegments.concat([{ray: new Ray(ray.A, {x: xgh, y: ygh})}]);
const distance = sum(canvas.grid.measureDistances(pathUntilSpace, {gridSpaces: true}));
const color = this.dragRulerGetColorForDistance(distance);
const snapPoint = getSnapPointForToken(...canvas.grid.getTopLeft(x, y), this.draggedEntity);
const [snapX, snapY] = getGridPositionFromPixels(snapPoint.x + 1, snapPoint.y + 1);
highlightTokenShape.call(this, {x: snapX, y: snapY}, tokenShape, color, alpha);
}
highlightTokenShape.call(this, {x: snapX, y: snapY}, tokenShape, color, alpha);
}
}
+3 -3
View File
@@ -9,11 +9,11 @@
* - Instead of taking a grid parameter, get the grid value from the globas canvas
*/
export function findVertexSnapPoint(x, y, altOrientationFlag) {
const grid = canvas.grid.grid;
const grid = canvas.grid;
if (grid.columnar) {
return findSnapPointCols(x, y, grid.h, grid.w, altOrientationFlag);
return findSnapPointCols(x, y, grid.sizeY, grid.sizeX, altOrientationFlag);
} else {
return findSnapPointRows(x, y, grid.h, grid.w, altOrientationFlag);
return findSnapPointRows(x, y, grid.sizeY, grid.sizeX, altOrientationFlag);
}
}
+10 -14
View File
@@ -137,10 +137,6 @@ function onEntityLeftDragStart(wrapped, event) {
const ruler = canvas.controls.ruler;
ruler.draggedEntity = this;
const entityCenter = getEntityCenter(this);
ruler.rulerOffset = {
x: entityCenter.x - event.data.origin.x,
y: entityCenter.y - event.data.origin.y,
};
if (game.settings.get(settingsKey, "autoStartMeasurement")) {
let options = {};
setSnapParameterOnOptions(ruler, options);
@@ -149,7 +145,7 @@ function onEntityLeftDragStart(wrapped, event) {
}
function onEntityLeftDragMoveSnap(wrapped, event) {
applyGridlessSnapping.call(this, event);
applyGridlessSnapping.call(canvas.controls.ruler, event);
onEntityLeftDragMove.call(this, wrapped, event);
}
@@ -215,9 +211,9 @@ function applyGridlessSnapping(event) {
if (canvas.grid.type !== CONST.GRID_TYPES.GRIDLESS) return;
const rasterWidth = 35 / canvas.stage.scale.x;
const tokenX = event.data.destination.x;
const tokenY = event.data.destination.y;
const destination = {x: tokenX + ruler.rulerOffset.x, y: tokenY + ruler.rulerOffset.y};
const tokenX = event.interactionData.destination.x;
const tokenY = event.interactionData.destination.y;
const destination = {x: tokenX, y: tokenY};
const ranges = getRangesFromSpeedProvider(ruler.draggedEntity);
const terrainRulerAvailable = game.modules.get("terrain-ruler")?.active;
@@ -241,13 +237,13 @@ function applyGridlessSnapping(event) {
const deltaY = destination.y - rasterLocation.y;
const rasterDistance = Math.hypot(deltaX, deltaY);
if (rasterDistance < rasterWidth) {
event.data.destination.x = rasterLocation.x - ruler.rulerOffset.x;
event.data.destination.y = rasterLocation.y - ruler.rulerOffset.y;
event.interactionData.destination.x = rasterLocation.x;
event.interactionData.destination.y = rasterLocation.y;
}
}
} else {
let waypointDistance = 0;
let origin = event.data.origin;
let origin = this.draggedEntity.getCenterPoint();
if (ruler.waypoints.length > 1) {
const segments = ruler.constructor
.dragRulerGetRaysFromWaypoints(ruler.waypoints, destination)
@@ -256,7 +252,7 @@ function applyGridlessSnapping(event) {
});
origin = segments.pop().ray.A;
waypointDistance = canvas.grid.measureDistances(segments).reduce((a, b) => a + b);
origin = {x: origin.x - ruler.rulerOffset.x, y: origin.y - ruler.rulerOffset.y};
origin = {x: origin.x, y: origin.y};
}
const deltaX = tokenX - origin.x;
@@ -271,8 +267,8 @@ function applyGridlessSnapping(event) {
.reduce((a, b) => Math.max(a, b), 0);
if (targetDistance) {
if (distance < targetDistance + rasterWidth) {
event.data.destination.x = origin.x + (deltaX * targetDistance) / distance;
event.data.destination.y = origin.y + (deltaY * targetDistance) / distance;
event.interactionData.destination.x = origin.x + (deltaX * targetDistance) / distance;
event.interactionData.destination.y = origin.y + (deltaY * targetDistance) / distance;
}
}
}
+50 -44
View File
@@ -17,6 +17,7 @@ import {
getTokenShape,
isPathfindingEnabled,
} from "./util.js";
import {getPointer} from "./util.js";
export function extendRuler() {
class DragRulerRuler extends CONFIG.Canvas.rulerClass {
@@ -40,14 +41,17 @@ export function extendRuler() {
if (!this.isDragRuler) return await super.moveToken(event);
}
toJSON() {
const json = super.toJSON();
_getMeasurementData() {
const json =
typeof super._getMeasurementData === "function"
? super._getMeasurementData()
: super.toJSON();
if (this.draggedEntity) {
const isToken = this.draggedEntity instanceof Token;
json.draggedEntityIsToken = isToken;
json.draggedEntity = this.draggedEntity.id;
json.waypoints = json.waypoints.map(old => {
let w = duplicate(old);
let w = foundry.utils.duplicate(old);
w.isPathfinding = undefined;
return w;
});
@@ -55,7 +59,13 @@ export function extendRuler() {
return json;
}
/** @deprecated since V12 */
toJSON() {
return this._getMeasurementData();
}
update(data) {
if (!data || data.state === Ruler.STATES.INACTIVE) return this.clear();
// Don't show a GMs drag ruler to non GM players
if (
data.draggedEntity &&
@@ -104,7 +114,10 @@ export function extendRuler() {
// Compute the measurement destination, segments, and distance
const d = this._getMeasurementDestination(destination);
if (d.x === this.destination.x && d.y === this.destination.y) return;
if (this.destination && d.x === this.destination.x && d.y === this.destination.y) {
this.performPostPathfindingActions(options);
return;
}
this.destination = d;
// TODO Check if we can reuse the old path
@@ -205,6 +218,7 @@ export function extendRuler() {
}
}
}
this.dragRulerSendState();
return this.segments;
}
@@ -226,7 +240,7 @@ export function extendRuler() {
const waypoints =
this.draggedEntity instanceof Token
? applyTokenSizeOffset(unsnappedWaypoints, this.draggedEntity)
: duplicate(unsnappedWaypoints);
: foundry.utils.duplicate(unsnappedWaypoints);
const unsnappedSegments = [];
const segments = [];
for (const [i, p1] of waypoints.entries()) {
@@ -251,6 +265,9 @@ export function extendRuler() {
unsnappedSegments.push({ray: unsnappedRay, label});
}
this.dragRulerUnsnappedSegments = unsnappedSegments;
if (this.labels.children.length > segments.length) {
this.labels.removeChildren(segments.length).forEach(c => c.destroy());
}
return segments;
} else {
return super._getMeasurementSegments();
@@ -261,29 +278,23 @@ export function extendRuler() {
if (!this.isDragRuler) {
return super._computeDistance(gridSpaces);
}
if (!this.dragRulerEnableTerrainRuler) {
if (!this.dragRulerIgnoreGrid) {
gridSpaces = true;
}
super._computeDistance(gridSpaces);
} else {
const shape = this.draggedEntity ? getTokenShape(this.draggedEntity) : null;
const options = {
ignoreGrid: this.dragRulerIgnoreGrid,
gridSpaces,
enableTerrainRuler: this.dragRulerEnableTerrainRuler,
};
const distances = measureDistances(this.segments, this.draggedEntity, shape, options);
let totalDistance = 0;
for (const [i, d] of distances.entries()) {
let s = this.segments[i];
s.startDistance = totalDistance;
totalDistance += d;
s.last = i === this.segments.length - 1;
s.distance = d;
s.text = this._getSegmentLabel(s, totalDistance);
}
const shape = this.draggedEntity ? getTokenShape(this.draggedEntity) : null;
const options = {
ignoreGrid: this.dragRulerIgnoreGrid,
gridSpaces,
enableTerrainRuler: this.dragRulerEnableTerrainRuler,
};
const distances = measureDistances(this.segments, this.draggedEntity, shape, options);
this.totalDistance = 0;
for (const [i, d] of distances.entries()) {
let s = this.segments[i];
s.startDistance = this.totalDistance;
this.totalDistance += d;
s.last = i === this.segments.length - 1;
s.distance = d;
s.text = this._getSegmentLabel(s);
}
for (const [i, segment] of this.segments.entries()) {
const unsnappedSegment = this.dragRulerUnsnappedSegments[i];
unsnappedSegment.startDistance = segment.startDistance;
@@ -379,18 +390,12 @@ export function extendRuler() {
options.snap = options.snap ?? true;
if (this.waypoints.filter(w => !w.isPrevious).length > 1) {
event.preventDefault();
const mousePosition = canvas.app.renderer.plugins.interaction.mouse.getLocalPosition(
canvas.tokens,
);
const rulerOffset = this.rulerOffset;
const mousePosition = getPointer().getLocalPosition(canvas.tokens);
// Options are not passed to _removeWaypoint in vanilla Foundry.
// Send them in case other modules have overriden that behavior and accept an options parameter (Toggle Snap to Grid)
this._removeWaypoint(
{x: mousePosition.x + rulerOffset.x, y: mousePosition.y + rulerOffset.y},
options,
);
game.user.broadcastActivity({ruler: this});
this._removeWaypoint({x: mousePosition.x, y: mousePosition.y}, options);
this.performPostPathfindingActions(options);
} else {
this.dragRulerAbortDrag(event);
}
@@ -416,7 +421,7 @@ export function extendRuler() {
this._endMeasurement();
// Deactivate the drag workflow in mouse
token.mouseInteractionManager._deactivateDragEvents();
token.mouseInteractionManager.cancel(event);
token.mouseInteractionManager.state = token.mouseInteractionManager.states.HOVER;
// This will cancel the current drag operation
@@ -435,7 +440,7 @@ export function extendRuler() {
this.dragRulerAddWaypoint(waypoint, {snap: false});
}
this.measure(this.destination);
game.user.broadcastActivity({ruler: this});
this.dragRulerSendState();
}
static dragRulerGetRaysFromWaypoints(waypoints, destination) {
@@ -483,19 +488,20 @@ export function extendRuler() {
if (isToken && game.settings.get(settingsKey, "enableMovementHistory"))
ruler.dragRulerAddWaypointHistory(getMovementHistory(entity));
ruler.dragRulerAddWaypoint(entityCenter, {snap: false});
const mousePosition = canvas.app.renderer.plugins.interaction.mouse.getLocalPosition(
canvas.tokens,
);
const mousePosition = getPointer().getLocalPosition(canvas.tokens);
const destination = {
x: mousePosition.x + ruler.rulerOffset.x,
y: mousePosition.y + ruler.rulerOffset.y,
x: mousePosition.x,
y: mousePosition.y,
};
if (measureImmediately) ruler.measure(destination, options);
}
dragRulerSendState() {
if (this.user !== game.user) {
return;
}
game.user.broadcastActivity({
ruler: this.toJSON(),
ruler: this._getMeasurementData(),
});
}
}
+1 -1
View File
@@ -298,7 +298,7 @@ function enumerateProviderSettings(provider) {
for (const setting of provider.settings) {
try {
if (setting.scope === "world" && !game.user.isGM) continue;
const s = duplicate(setting);
const s = foundry.utils.duplicate(setting);
s.id = `${provider.id}.setting.${s.id}`;
s.name = game.i18n.localize(s.name);
s.hint = game.i18n.localize(s.hint);
+1 -1
View File
@@ -115,7 +115,7 @@ export class GenericSpeedProvider extends SpeedProvider {
getRanges(token) {
const speedAttribute = this.getSetting("speedAttribute");
if (!speedAttribute) return [];
const tokenSpeed = parseFloat(getProperty(token, speedAttribute));
const tokenSpeed = parseFloat(foundry.utils.getProperty(token, speedAttribute));
if (tokenSpeed === undefined) {
console.warn(
`Drag Ruler (Generic Speed Provider) | The configured token speed attribute "${speedAttribute}" didn't return a speed value. To use colors based on drag distance set the setting to the correct value (or clear the box to disable this feature).`,
+8
View File
@@ -23,6 +23,10 @@ export function getDefaultSpeedAttribute() {
return "actor.system.combatValues.movement.total";
case "splittermond":
return "actor.derivedValues.speed.value";
case "wfrp4e":
return "actor.system.details.move.walk";
case "crucible":
return "actor.system.movement.stride";
}
return "";
}
@@ -45,6 +49,10 @@ export function getDefaultDashMultiplier() {
return 5;
case "splittermond":
return 3;
case "wfrp4e":
return 2;
case "crucible":
return 0;
}
return 0;
}
+47 -32
View File
@@ -37,20 +37,20 @@ export function getHexTokenSize(token) {
}
export function getEntityCenter(token) {
if (token instanceof Token && canvas.grid.isHex) {
if (token instanceof Token && isCanvasHex()) {
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;
if (canvas.grid.columnar) {
offset = canvas.grid.sizeX - canvas.grid.sizeY;
} else {
offset = canvas.grid.grid.h - canvas.grid.grid.w;
offset = canvas.grid.sizeY - canvas.grid.sizeX;
}
if (getAltOrientationFlagForToken(token, size)) {
offset *= -1;
}
if (canvas.grid.grid.columnar) {
if (canvas.grid.columnar) {
center.x -= offset;
return center;
} else {
@@ -64,7 +64,7 @@ export function getEntityCenter(token) {
// A copy of this function lives in the routinglib module
export function getAltOrientationFlagForToken(token, size) {
const hexSizeSupport = game.modules.get("hex-size-support").api;
const hexSizeSupport = game.modules.get("hex-size-support")?.api;
if (hexSizeSupport) {
return hexSizeSupport.isAltOrientation(token);
}
@@ -79,7 +79,7 @@ export function getSnapPointForToken(x, y, token) {
return {x, y};
}
if (canvas.grid.isHex) {
if (isCanvasHex()) {
const size = getHexTokenSize(token);
if (size % 2 === 0) {
return findVertexSnapPoint(x, y, getAltOrientationFlagForToken(token, size));
@@ -89,27 +89,27 @@ export function getSnapPointForToken(x, y, token) {
}
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 cell = {};
if (token.document.width % 2 === 0) cell.x = x - canvas.grid.sizeY / 2;
else cell.x = x;
if (token.document.height % 2 === 0) cell.y = y - canvas.grid.sizeY / 2;
else cell.y = y;
const center = canvas.grid.getCenterPoint(cell);
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 subGridWidth = Math.floor(canvas.grid.sizeX / 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;
snapX = center.x;
}
// 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;
snapX = center.x + canvas.grid.sizeX / 2;
}
if (token.document.height <= 0.5) {
const offsetY = y - topLeftY;
@@ -117,9 +117,9 @@ export function getSnapPointForToken(x, y, token) {
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;
snapY = center.y;
} else {
snapY = centerY + canvas.grid.h / 2;
snapY = center.y + canvas.grid.sizeY / 2;
}
return {x: snapX, y: snapY};
}
@@ -147,7 +147,7 @@ export function highlightTokenShape(position, shape, color, alpha) {
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});
canvas.grid.highlightGridPosition(layer, {x, y, color, alpha: 0.25 * alpha});
}
}
@@ -155,9 +155,9 @@ 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) {
if (isCanvasHex()) {
let shiftedRow;
if (canvas.grid.grid.options.even) shiftedRow = 1;
if (canvas.grid?.even) shiftedRow = 1;
else shiftedRow = 0;
if (canvas.grid.grid.columnar) {
if (space.x % 2 !== 0 && position.x % 2 !== shiftedRow) {
@@ -212,6 +212,16 @@ export function getTokenShape(token) {
{x: 0, y: -2},
{x: 1, y: -2},
]);
if (size >= 5)
shape = shape.concat([
{x: -2, y: 0},
{x: 1, y: 1},
{x: -1, y: 2},
{x: 0, y: 2},
{x: 1, y: 2},
{x: -2, y: 1},
{x: 2, y: 0},
]);
if (getAltOrientationFlagForToken(token, size)) {
shape.forEach(space => (space.y *= -1));
@@ -226,7 +236,7 @@ export function getTokenShape(token) {
export function getTokenSize(token) {
let w, h;
if (canvas.grid.isHex) {
if (isCanvasHex()) {
w = h = getHexTokenSize(token);
} else {
w = token.document.width;
@@ -244,26 +254,26 @@ export function applyTokenSizeOffset(waypoints, token) {
const tokenSize = getTokenSize(token);
const waypointOffset = {x: 0, y: 0};
if (canvas.grid.isHex) {
if (isCanvasHex()) {
const isAltOrientation = getAltOrientationFlagForToken(token, getHexTokenSize(token));
if (canvas.grid.grid.columnar) {
if (tokenSize.w % 2 === 0) {
waypointOffset.x = canvas.grid.w / 2;
waypointOffset.x = canvas.grid.sizeX / 2;
if (isAltOrientation) waypointOffset.x *= -1;
}
} else {
if (tokenSize.h % 2 === 0) {
waypointOffset.y = canvas.grid.h / 2;
waypointOffset.y = canvas.grid.sizeY / 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;
waypointOffset.x = canvas.grid.sizeX / 2;
}
if (tokenSize.h % 2 === 0) {
waypointOffset.y = canvas.grid.h / 2;
waypointOffset.y = canvas.grid.sizeY / 2;
}
}
@@ -285,12 +295,13 @@ export function isClose(a, b, delta) {
return Math.abs(a - b) <= delta;
}
export function getPointer() {
return canvas.app.renderer.events.pointer;
}
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};
const mousePosition = getPointer().getLocalPosition(canvas.tokens);
const measurePosition = {x: mousePosition.x, y: mousePosition.y};
return measurePosition;
}
@@ -312,3 +323,7 @@ export function isPathfindingEnabled() {
if (moveWithoutAnimation) return false;
return game.settings.get(settingsKey, "autoPathfinding") != togglePathfinding;
}
function isCanvasHex() {
return canvas.grid.isHexagonal;
}