Compare commits
10 commits
f617b26fe1
...
383f66e297
Author | SHA1 | Date | |
---|---|---|---|
383f66e297 | |||
9bc73100f3 | |||
95bb1c3445 | |||
77ae01a7b3 | |||
73d2a08b88 | |||
7cd85468c7 | |||
22dc500801 | |||
ab02dd139a | |||
fe9b56acaa | |||
3f0f81ee54 |
6 changed files with 249 additions and 115 deletions
36
README.md
36
README.md
|
@ -1,4 +1,4 @@
|
|||
# The Mill's Fabula - v0.2.0
|
||||
# The Mill's Fabula - v0.3.0
|
||||
|
||||
This little [FoundryVTT](https://foundryvtt.com/) module is a collection of compendiums and functionalities
|
||||
to power our Fabula Ultima campaigns.
|
||||
|
@ -31,25 +31,31 @@ highlighting the tokens that have played for this combat turn.
|
|||
The module supports going back and forth in the combat rounds, as well as going back in the turn order.
|
||||
(Though because of limitations of the Fabula Ultima system, does not allow going *forward* in the turn order.)
|
||||
|
||||
## Settings
|
||||
### Settings
|
||||
|
||||
- An image to use for the default/idle border
|
||||
- An image to use for the took turn/played/inactive border
|
||||
|
||||
## Limitations
|
||||
### Limitations
|
||||
|
||||
There are currently two main issues that need to be fixed :
|
||||
1. The tokens will not be updated when the GM is not on the scene.
|
||||
- Indeed, the Fabula Ultima system seems to prevent players from receiving combat events,
|
||||
so the GM is the only one that can receive them and update the tokens. That means they need to be in the active
|
||||
combat scene for the changes to take effect.
|
||||
- However, given that the module only uses the current state, if the GM comes back to the scene and a combat event is
|
||||
triggered, the token borders will become correct.
|
||||
2. The token borders will be incorrect when switching to a new scene
|
||||
- It is unclear why, but apparently switching to another scene is very different from loading a new scene,
|
||||
and the combat encounter of the scene is not available when tokens are created. This means that the combat status,
|
||||
and thus the border type, cannot be properly determined on scene switch.
|
||||
- This can be fixed by receiving a combat update, either from the players or the GM, on the scene.
|
||||
There are currently one minor issue that might be fixed :
|
||||
1. The token borders will be incorrect when switching between different encounters in the same scene
|
||||
- Producing a combat event or switching away and back to the scene will fix it.
|
||||
- It doesn't appear that there is an event on combat switch that could be hooked into, which makes fixing the
|
||||
issue uncertain.
|
||||
|
||||
## Token UI adjustments
|
||||
|
||||
Given that we add a border *on* the tokens, it conflicts with the base attribute bars which are drawn over the token's
|
||||
square.
|
||||
The token UI adjustments move the two attribute bars below the token, outside its space, first HP then mana.
|
||||
As this is where the nameplate of the token should be, move it above the token instead.
|
||||
|
||||
### Limitations
|
||||
|
||||
- The token's detailed UI when right-clicking will overlap the bars in their new positions (it already overlapped the name)
|
||||
- The current implementation relies on monkey patching, which make it vulnerable to compatibility issues with
|
||||
other modules manipulating the same methods.
|
||||
|
||||
# Compendia
|
||||
|
||||
|
|
|
@ -17,6 +17,14 @@
|
|||
"Hint": "The image to use as a border for player tokens that have taken their turn."
|
||||
}
|
||||
}
|
||||
},
|
||||
"TokenUiAdjust": {
|
||||
"Settings": {
|
||||
"Enabled": {
|
||||
"Name": "Token UI adjustments",
|
||||
"Hint": "Moves both attribute bars below the token and the nameplate above."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,6 +17,14 @@
|
|||
"Hint": "L'image à utiliser comme bordure pour les jetons joueurs qui ont joué leur tour."
|
||||
}
|
||||
}
|
||||
},
|
||||
"TokenUiAdjust": {
|
||||
"Settings": {
|
||||
"Enabled": {
|
||||
"Name": "Ajustements d'interface des tokens",
|
||||
"Hint": "Déplace les barres d'attributs sous le token et le nom au dessus."
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
16
module.json
16
module.json
|
@ -2,7 +2,7 @@
|
|||
"id": "the-mills-fabula",
|
||||
"title": "Fabula Moletrina",
|
||||
"description": "A module implementing our idiosyncratic ideas for the Mill's campaigns.",
|
||||
"version": "0.2.0",
|
||||
"version": "0.3.0",
|
||||
"compatibility": {
|
||||
"minimum": "12",
|
||||
"verified": "12",
|
||||
|
@ -50,9 +50,11 @@
|
|||
}
|
||||
],
|
||||
"esmodules": [
|
||||
"scripts/token_combat_border.mjs"
|
||||
"scripts/token_combat_border.mjs",
|
||||
"scripts/token_ui_adjust.mjs"
|
||||
],
|
||||
"socket": true,
|
||||
|
||||
"packs": [
|
||||
{
|
||||
"name": "Macros",
|
||||
|
@ -67,10 +69,18 @@
|
|||
"flags": {}
|
||||
}
|
||||
],
|
||||
"packFolders": [
|
||||
{
|
||||
"name": "Fabula Moletrina",
|
||||
"sorting": "a",
|
||||
"color": "#d3b719",
|
||||
"packs": ["Macros"]
|
||||
}
|
||||
],
|
||||
|
||||
"license": "LICENSE",
|
||||
"readme": "README.md",
|
||||
"url": "https://git.tfk-astrodome.net/trotFunky/TheMillsFabula/src/branch/release",
|
||||
"manifest": "https://git.tfk-astrodome.net/trotFunky/TheMillsFabula/raw/branch/release/module.json",
|
||||
"download": "https://git.tfk-astrodome.net/trotFunky/TheMillsFabula/archive/v0.2.0.zip"
|
||||
"download": "https://git.tfk-astrodome.net/trotFunky/TheMillsFabula/archive/v0.3.0.zip"
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import * as MillsFabula from "./mills_fabula.mjs";
|
||||
import { FUHooks } from "/systems/projectfu/module/hooks.mjs"
|
||||
import { FU } from "/systems/projectfu/module/helpers/config.mjs"
|
||||
import { FUCombat } from '/systems/projectfu/module/ui/combat.mjs';
|
||||
|
||||
// NOTES
|
||||
// Tokens are working PIXI.js objects, can .addChild() a sprite
|
||||
|
@ -14,7 +15,8 @@ import { FU } from "/systems/projectfu/module/helpers/config.mjs"
|
|||
*/
|
||||
let socket;
|
||||
const SocketMessages = Object.freeze({
|
||||
UpdateBorder: "update-border",
|
||||
CombatUpdateBorder: "combat-update-border",
|
||||
SetBorder: "set-border",
|
||||
})
|
||||
|
||||
const BorderSettings = Object.freeze({
|
||||
|
@ -78,16 +80,14 @@ function create_new_border(type, width, height, visible) {
|
|||
}
|
||||
|
||||
/**
|
||||
* Toggle the borders of a token by ID, as we cannot pass the Token object via SocketLib (most objects being recursive).
|
||||
* @param {string} token_id The ID of the token to update
|
||||
* Toggle the borders of a token.
|
||||
* @param {Token} token The token to update
|
||||
* @param {boolean} played Status of the token to update
|
||||
*/
|
||||
function token_set_border_visibility(token_id, played) {
|
||||
let token = canvas.scene?.tokens.get(token_id).object;
|
||||
function token_set_border_visibility(token, played) {
|
||||
// Get the borders we manually added in the `drawToken` hook, if it has any.
|
||||
let borders = token.children.filter((child) => child.borderType);
|
||||
// console.debug("↓↓↓ set_border_visibility ↓↓↓");
|
||||
// console.debug(token)
|
||||
|
||||
for (let border of borders) {
|
||||
if (border.borderType === BorderTypes.Active) {
|
||||
border.visible = !played;
|
||||
|
@ -95,39 +95,105 @@ function token_set_border_visibility(token_id, played) {
|
|||
border.visible = played;
|
||||
}
|
||||
}
|
||||
// console.debug("↑↑↑ set_border_visibility ↑↑↑");
|
||||
}
|
||||
|
||||
/**
|
||||
* A wrapper around `token_set_border_visibility()` to be invoked via SocketLib.
|
||||
* It checks that the client is on the proper scene, otherwise the Token wouldn't be found.
|
||||
*
|
||||
* @param {string} scene_id The ID of the scene of the token to update
|
||||
* @param {string} token_id The ID of the token to update
|
||||
* @param {boolean} played Should the visible borders be the base or the played one ?
|
||||
*/
|
||||
function token_remote_set_border_visibility(scene_id, token_id, played) {
|
||||
/*
|
||||
* Check that we are on the same scene as the token being updated,
|
||||
* otherwise it won't exist for us.
|
||||
*/
|
||||
if (scene_id !== canvas.scene?.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
token_set_border_visibility(canvas.scene?.tokens.get(token_id).object, played)
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a token has played in a specific round, or the current combat round if it exists for the token.
|
||||
* The function does not rely on the token's internal data, as it is not properly set when changing scenes.
|
||||
* @param {Token} token The actual token object to check combat status
|
||||
* @param {number} [round] The round to check the token's status in, will check the token's combat current turn otherwise
|
||||
* @returns {boolean} If the token has played in the current or requested round
|
||||
*/
|
||||
function token_has_played(token, round = -1) {
|
||||
// console.debug("↓↓↓ token_has_played ↓↓↓");
|
||||
// console.debug(token.inCombat)
|
||||
if (!token.inCombat) {
|
||||
return false;
|
||||
/**
|
||||
* When we change scene, the token might not be updated with the combat
|
||||
* data, so we might need to go check ourselves if they are not set.
|
||||
* @type {FUCombat}
|
||||
*/
|
||||
let combat = token.combatant?.combat;
|
||||
/** @type {Combatant} */
|
||||
let combatant = token.combatant;
|
||||
|
||||
// We might be changing scene, so let's check if that's true.
|
||||
if (!combatant) {
|
||||
/*
|
||||
* There should only be one active combat per scene.
|
||||
* If there isn't one, we're sure that the token is not in combat.
|
||||
*/
|
||||
let active_scene_combat = game.combats.contents.filter(
|
||||
(combat) => combat.active && combat.scene.id === token.scene.id)
|
||||
if (active_scene_combat.length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
combat = active_scene_combat[0];
|
||||
|
||||
// Now search among the combatants
|
||||
for (let active_combatant of combat.combatants) {
|
||||
if (active_combatant.tokenId === token.id) {
|
||||
combatant = active_combatant;
|
||||
break;
|
||||
}
|
||||
}
|
||||
// We have not found our token in the active combat, assume it isn't in combat.
|
||||
if (!combatant) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* As we check beforehand, combat should always exist.
|
||||
* @type {Combat}
|
||||
*/
|
||||
let combat = token.combatant.combat;
|
||||
let round_turns_taken = combat?.flags.projectfu.CombatantsTurnTaken[round < 0 ? combat?.round : round]
|
||||
// console.debug(`Testing played for round : ${combat?.round}`)
|
||||
console.debug(round_turns_taken)
|
||||
|
||||
// No token has taken a turn, or all turns were reverted.
|
||||
if (!round_turns_taken || round_turns_taken.length === 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// console.debug("↑↑↑ token_has_played ↑↑↑");
|
||||
// Token might have played, let's search now.
|
||||
return round_turns_taken.includes(token.combatant.id)
|
||||
return round_turns_taken.includes(combatant.id)
|
||||
}
|
||||
|
||||
/**
|
||||
* A wrapper function around `token_set_border_visibility()` that is called via SocketLib for combat updates.
|
||||
* It is executed by every client, which allows us to check if we are on the proper scene, ensuring that
|
||||
* we can find the token on each relevant client, rather than only on the GM's side which doesn't
|
||||
* work if they are not in the combat scene.
|
||||
*
|
||||
* Scene and Token are passed by IDs as the Foundry objects are recursive and cannot be passed via SocketLib.
|
||||
* @param {string} scene_id The ID of the scene of the token to update
|
||||
* @param {string} token_id The ID of the token to update
|
||||
* @param {number} round The combat round relating to the update
|
||||
*/
|
||||
function token_combat_visibility_remote_update(scene_id, token_id, round) {
|
||||
/*
|
||||
* Check that we are on the same scene as the token being updated,
|
||||
* otherwise it won't exist for us.
|
||||
*/
|
||||
if (scene_id !== canvas.scene?.id) {
|
||||
return;
|
||||
}
|
||||
|
||||
let token = canvas.scene?.tokens.get(token_id).object;
|
||||
token_set_border_visibility(token, token_has_played(token, round))
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -137,119 +203,102 @@ function token_has_played(token, round = -1) {
|
|||
*/
|
||||
function combat_hook_update_token_borders(combat, data) {
|
||||
// Turns is the array of *tokens having turns in this encounter*.
|
||||
// console.debug("↓↓↓ combat_hook_update_token_borders ↓↓↓");
|
||||
// console.debug(combat)
|
||||
// console.debug(data)
|
||||
for (let combatant of combat.turns) {
|
||||
// The combat passed by the hook still is on the previous round or turn, which would make the check
|
||||
// use the previous round rather than the new one. Use the round contained in data instead, which is always
|
||||
// the new one.
|
||||
socket.executeForEveryone(SocketMessages.UpdateBorder, combatant.token.id,
|
||||
token_has_played(combatant?.token.object, data.round)).then();
|
||||
// The combat passed by the hook is still on the previous round or turn, which would make the check
|
||||
// use the previous round rather than the new one. Use the round contained in data instead,
|
||||
// which is always the new one.
|
||||
socket.executeForEveryone(SocketMessages.CombatUpdateBorder,
|
||||
combatant.sceneId, combatant.tokenId, data.round).then();
|
||||
}
|
||||
// console.debug("↑↑↑ combat_hook_update_token_borders ↑↑↑");
|
||||
}
|
||||
|
||||
function combat_border_main() {
|
||||
Hooks.once("init", () => {
|
||||
game.settings.register(MillsFabula.id, BorderSettings.BorderEnabled, {
|
||||
name: game.i18n.localize('MF.Border.Settings.BorderEnabled.Name'),
|
||||
hint: game.i18n.localize('MF.Border.Settings.BorderEnabled.Hint'),
|
||||
type: Boolean,
|
||||
config: true,
|
||||
scope: 'world',
|
||||
requiresReload: true,
|
||||
default: true
|
||||
});
|
||||
|
||||
// Only show the settings if the borders are enabled.
|
||||
let borders_enabled = game.settings.get(MillsFabula.id, BorderSettings.BorderEnabled);
|
||||
game.settings.register(MillsFabula.id, BorderSettings.BaseBorderPath, {
|
||||
name: game.i18n.localize('MF.Border.Settings.BaseBorder.Name'),
|
||||
hint: game.i18n.localize('MF.Border.Settings.BaseBorder.Hint'),
|
||||
type: String,
|
||||
config: borders_enabled,
|
||||
scope: 'world',
|
||||
requiresReload: true,
|
||||
filePicker: 'image',
|
||||
default: 'modules/the-mills-fabula/assets/default-borders/base.webp'
|
||||
});
|
||||
|
||||
game.settings.register(MillsFabula.id, BorderSettings.PlayedBorderPath, {
|
||||
name: game.i18n.localize('MF.Border.Settings.PlayedBorder.Name'),
|
||||
hint: game.i18n.localize('MF.Border.Settings.PlayedBorder.Hint'),
|
||||
type: String,
|
||||
config: borders_enabled,
|
||||
scope: 'world',
|
||||
requiresReload: true,
|
||||
filePicker: 'image',
|
||||
default: 'modules/the-mills-fabula/assets/default-borders/played.webp'
|
||||
})
|
||||
|
||||
// Create the border textures based on the image chose in the settings.
|
||||
base_border = PIXI.BaseTexture.from(game.settings.get(MillsFabula.id, BorderSettings.BaseBorderPath));
|
||||
played_border = PIXI.BaseTexture.from(game.settings.get(MillsFabula.id, BorderSettings.PlayedBorderPath));
|
||||
});
|
||||
|
||||
Hooks.once("socketlib.ready", () => {
|
||||
socket = socketlib.registerModule(MillsFabula.id);
|
||||
socket.register(SocketMessages.UpdateBorder, token_set_border_visibility);
|
||||
})
|
||||
socket.register(SocketMessages.CombatUpdateBorder, token_combat_visibility_remote_update);
|
||||
socket.register(SocketMessages.SetBorder, token_remote_set_border_visibility);
|
||||
|
||||
// Create the borders from defined textures and add them to the tokens when they are first created on canvas.
|
||||
// FIXME: Does not work on scene change !
|
||||
Hooks.on("drawToken", (drawn_token) => {
|
||||
// FIXME: Handle deactivation properly
|
||||
if (!game.settings.get(MillsFabula.id, BorderSettings.BorderEnabled)) {
|
||||
return;
|
||||
}
|
||||
// Only apply the borders to player tokens
|
||||
if (drawn_token.actor?.type !== "character")
|
||||
return;
|
||||
|
||||
let has_played_turn = token_has_played(drawn_token);
|
||||
// console.log(drawn_token)
|
||||
// console.log(`Is in combat ? ${drawn_token.inCombat}`)
|
||||
// console.log(`Combatant ? ${drawn_token.combatant}`)
|
||||
// console.log(`Combat ?`)
|
||||
// console.log(drawn_token.combatant.combat);
|
||||
// console.log(game.combats.combats)
|
||||
|
||||
const token_size = drawn_token.getSize();
|
||||
drawn_token.addChild(create_new_border(BorderTypes.Active, token_size.width, token_size.height, !has_played_turn));
|
||||
drawn_token.addChild(create_new_border(BorderTypes.Played, token_size.width, token_size.height, has_played_turn));
|
||||
|
||||
// console.log("============")
|
||||
})
|
||||
|
||||
|
||||
Hooks.on("ready", () => {
|
||||
// FIXME: Handle deactivation properly
|
||||
if (!game.settings.get(MillsFabula.id, BorderSettings.BorderEnabled)) {
|
||||
return;
|
||||
}
|
||||
// Players cannot run the combat hooks used here, which trigger for the GM no matter what.
|
||||
// So register them for the GM only, who will execute the updates for players via SocketLib.
|
||||
if (!game.user?.isGM) {
|
||||
return;
|
||||
}
|
||||
|
||||
// console.debug("↓↓↓ Registering ↓↓↓")
|
||||
Hooks.on("combatTurn", combat_hook_update_token_borders);
|
||||
Hooks.on("combatRound", combat_hook_update_token_borders);
|
||||
// console.debug("↑↑↑ Registering ↑↑↑")
|
||||
|
||||
// No Foundry hook on end of combat, so use Fabula Ultima's.
|
||||
// FIXME: Does not work when the GM is in another scene, as they don't receive the event.
|
||||
Hooks.on(FUHooks.COMBAT_EVENT, (combat_event) => {
|
||||
if (combat_event.type === FU.combatEvent.endOfCombat) {
|
||||
for (let combatant of combat_event.combatants) {
|
||||
// End of combat, clear all tokens.
|
||||
socket.executeForEveryone(SocketMessages.UpdateBorder, combatant.token?.id, false).then();
|
||||
socket.executeForEveryone(SocketMessages.SetBorder,
|
||||
combatant.sceneId, combatant.tokenId, false).then();
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
combat_border_main()
|
||||
// We need to setup socketlib early, doing it in the `init` hook is too late.
|
||||
Hooks.once("socketlib.ready", () => {
|
||||
socket = socketlib.registerModule(MillsFabula.id);
|
||||
})
|
||||
|
||||
Hooks.once("init", () => {
|
||||
game.settings.register(MillsFabula.id, BorderSettings.BorderEnabled, {
|
||||
name: game.i18n.localize('MF.Border.Settings.BorderEnabled.Name'),
|
||||
hint: game.i18n.localize('MF.Border.Settings.BorderEnabled.Hint'),
|
||||
type: Boolean,
|
||||
config: true,
|
||||
scope: 'world',
|
||||
requiresReload: true,
|
||||
default: true
|
||||
});
|
||||
|
||||
// Only show the settings if the borders are enabled.
|
||||
let borders_enabled = game.settings.get(MillsFabula.id, BorderSettings.BorderEnabled);
|
||||
game.settings.register(MillsFabula.id, BorderSettings.BaseBorderPath, {
|
||||
name: game.i18n.localize('MF.Border.Settings.BaseBorder.Name'),
|
||||
hint: game.i18n.localize('MF.Border.Settings.BaseBorder.Hint'),
|
||||
type: String,
|
||||
config: borders_enabled,
|
||||
scope: 'world',
|
||||
requiresReload: true,
|
||||
filePicker: 'image',
|
||||
default: 'modules/the-mills-fabula/assets/default-borders/base.webp'
|
||||
});
|
||||
|
||||
game.settings.register(MillsFabula.id, BorderSettings.PlayedBorderPath, {
|
||||
name: game.i18n.localize('MF.Border.Settings.PlayedBorder.Name'),
|
||||
hint: game.i18n.localize('MF.Border.Settings.PlayedBorder.Hint'),
|
||||
type: String,
|
||||
config: borders_enabled,
|
||||
scope: 'world',
|
||||
requiresReload: true,
|
||||
filePicker: 'image',
|
||||
default: 'modules/the-mills-fabula/assets/default-borders/played.webp'
|
||||
})
|
||||
|
||||
if (!game.settings.get(MillsFabula.id, BorderSettings.BorderEnabled)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the border textures based on the image chose in the settings.
|
||||
base_border = PIXI.BaseTexture.from(game.settings.get(MillsFabula.id, BorderSettings.BaseBorderPath));
|
||||
played_border = PIXI.BaseTexture.from(game.settings.get(MillsFabula.id, BorderSettings.PlayedBorderPath));
|
||||
|
||||
combat_border_main()
|
||||
});
|
||||
|
|
53
scripts/token_ui_adjust.mjs
Normal file
53
scripts/token_ui_adjust.mjs
Normal file
|
@ -0,0 +1,53 @@
|
|||
import * as MillsFabula from "./mills_fabula.mjs";
|
||||
|
||||
const TokenUiSettings = Object.freeze({
|
||||
Enabled: "uiAdjustEnabled",
|
||||
})
|
||||
|
||||
Hooks.once("setup", () => {
|
||||
game.settings.register(MillsFabula.id, TokenUiSettings.Enabled, {
|
||||
name: "MF.TokenUiAdjust.Settings.Enabled.Name",
|
||||
hint: "MF.TokenUiAdjust.Settings.Enabled.Hint",
|
||||
type: Boolean,
|
||||
config: true,
|
||||
scope: "world",
|
||||
requiresReload: true,
|
||||
default: true,
|
||||
})
|
||||
|
||||
if (!game.settings.get(MillsFabula.id, TokenUiSettings.Enabled)) {
|
||||
return;
|
||||
}
|
||||
|
||||
/** Padding above and below the token, percentage of a grid square. */
|
||||
const top_bot_padding = 5;
|
||||
|
||||
Hooks.on("drawToken", (drawn_token) => {
|
||||
/*
|
||||
* Drawing attribute bars and nameplates are handled by private functions called
|
||||
* after the `drawToken` hook. That means that we cannot change their position in this hook.
|
||||
*
|
||||
* We could update them in the `refreshToken` hook, which works, but is called a lot more than
|
||||
* necessary and needs a view update (move the view) from the canvas to show the updates.
|
||||
*
|
||||
* Instead : we can replace the draw functions handling the bars and nameplate.
|
||||
* They are still useful, so make of copy bound to the drawn token so that we can call them
|
||||
* in our replacement function, then make the changes that we need.
|
||||
*/
|
||||
let base_drawBar = drawn_token._drawBar.bind(drawn_token);
|
||||
drawn_token._drawBar = (number, bar, data) => {
|
||||
const token_height = drawn_token.getSize().height
|
||||
const padding = drawn_token.scene.grid.size * top_bot_padding/100;
|
||||
base_drawBar(number, bar, data)
|
||||
bar.position.set(0, token_height + padding + number * bar.height)
|
||||
}
|
||||
|
||||
let base_refreshNameplate = drawn_token._refreshNameplate.bind(drawn_token);
|
||||
drawn_token._refreshNameplate = () => {
|
||||
const token_width = drawn_token.getSize().width;
|
||||
const padding = drawn_token.scene.grid.size * top_bot_padding/100;
|
||||
base_refreshNameplate()
|
||||
drawn_token.nameplate.position.set(token_width/2, -(padding + drawn_token.nameplate.height))
|
||||
}
|
||||
})
|
||||
})
|
Loading…
Add table
Add a link
Reference in a new issue