From f8f63037b0c2e914cdb186deae76baca2df47934 Mon Sep 17 00:00:00 2001 From: ironmonk88 <75920956+ironmonk88@users.noreply.github.com> Date: Sun, 27 Oct 2024 12:25:00 -0700 Subject: [PATCH] 12.03 changes --- CHANGELOG.md | 22 ++++++++++++++++++++++ apps/contestedroll.js | 11 ++++++++--- apps/lootables.js | 6 +++--- apps/resetposition.js | 2 +- apps/savingthrow.js | 28 ++++++++++++++-------------- apps/tokenbar.js | 37 ++++++++++++++++++++++++++++++++----- css/tokenbar.css | 7 +++++++ lang/en.json | 2 ++ module.json | 4 ++-- monks-tokenbar.js | 27 ++++++++++++++++++++++++++- settings.js | 19 ++++++++++--------- systems/base-rolls.js | 2 +- systems/dnd5e-rolls.js | 2 +- templates/tokenbar.html | 2 +- 14 files changed, 130 insertions(+), 41 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a4fa4e..fd2d26b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,25 @@ +## Version 12.03 + +Tried to fix the issue with Dice So Nice not revealing roll. + +Fixed evaluate async warning + +Fixed updating the token bar when an item is equipped that might change the displayed Tokens + +Fixed issue where Tokenbar could be dragged off the screen + +Added token image scaling + +Fixed issue with Dice So Nice hiding tokenbar rolls when the dice are rolling + +Fixed issues with Burning Wheel system and an override to how handlebar grouping is added + +Added the roll request alert sound to use a filepicker button + +Fixed a warning when using the Die class directly + +Fixed an issue that the D&D5e system introduced by changing a setting without providing any backward compatibility. + ## Version 12.02 Fixed issues when using Dice So Nice and figuring out when to reveal the dice diff --git a/apps/contestedroll.js b/apps/contestedroll.js index 8b657c5..78a30c3 100644 --- a/apps/contestedroll.js +++ b/apps/contestedroll.js @@ -275,11 +275,11 @@ export class ContestedRoll { promises.push(game.dice3d.showForRoll(roll, game.user, true, cantSee, canSee.includes(game.user.id), null)); } finishroll = Promise.all(promises).then(() => { - return { id: id, reveal: true, userid: game.userId }; + return { id: id, roll: roll, reveal: true, userid: game.userId }; }); } else { finishroll = new Promise((resolve) => { - resolve({ id: id, reveal: true, userid: game.userId }) + resolve({ id: id, roll: roll, reveal: true, userid: game.userId }) }); } const sound = MonksTokenBar.getDiceSound(); @@ -573,6 +573,11 @@ export class ContestedRoll { for (let update of updates) { let msgtoken = foundry.utils.duplicate(message.getFlag('monks-tokenbar', 'token' + update.id)); msgtoken.reveal = true; + msgtoken.tempreveal = true; + if (!msgtoken.roll && update.roll) { + //if the roll was not set, then set it + msgtoken.roll = Roll.fromData(update.roll); + } flags["token" + update.id] = msgtoken; log("Finish Rolling", msgtoken); } @@ -696,7 +701,7 @@ export class ContestedRoll { const newData = foundry.utils.deepClone(oldRoll.data); const newOptions = { ...oldRoll.options, isReroll: !0 }; const formula = oldRoll.formula.replace("2d20kh", "1d20").replace("2d20kl", "1d20"); - const newRoll = await new Roll(formula, newData, newOptions).evaluate({ async: !0 }); + const newRoll = await new Roll(formula, newData, newOptions).evaluate(); const rollmode = message.getFlag("monks-tokenbar", "rollmode"); if (game.dice3d != undefined && newRoll instanceof Roll && newRoll.ignoreDice !== true && MonksTokenBar.system.showRoll && !game.settings.get("core", "noCanvas") && game.system.id != "dnd5e") { diff --git a/apps/lootables.js b/apps/lootables.js index f238927..b3d09fb 100644 --- a/apps/lootables.js +++ b/apps/lootables.js @@ -581,7 +581,7 @@ export class LootablesApp extends Application { for (let loot of e.items) { if (typeof loot.quantity == "string" && loot.quantity.indexOf("d") != -1) { let r = new Roll(loot.quantity); - await r.evaluate({ async: true }); + await r.evaluate(); loot.quantity = r.total; } else loot.quantity = parseInt(loot.quantity); @@ -889,7 +889,7 @@ export class LootablesApp extends Application { if (currency[curr] != undefined) { if (typeof currency[curr] == "string" && currency[curr].indexOf("d") != -1) { let r = new Roll(currency[curr]); - await r.evaluate({ async: true }); + await r.evaluate(); currency[curr] = r.total; } else { currency[curr] = parseInt(currency[curr]); @@ -939,7 +939,7 @@ export class LootablesApp extends Application { if (currency[curr] != undefined) { if (typeof currency[curr] == "string" && currency[curr].indexOf("d") != -1) { let r = new Roll(currency[curr]); - await r.evaluate({ async: true }); + await r.evaluate(); currency[curr] = r.total; } else { currency[curr] = parseInt(currency[curr]); diff --git a/apps/resetposition.js b/apps/resetposition.js index 8287d23..d8a7e3a 100644 --- a/apps/resetposition.js +++ b/apps/resetposition.js @@ -20,7 +20,7 @@ export class ResetPosition extends FormApplication { static async resetPosition(app) { await game.user.unsetFlag("monks-tokenbar", "position"); if (MonksTokenBar.tokenbar != undefined) - MonksTokenBar.tokenbar.render(true); //MonksTokenBar.tokenbar.setPos(); + MonksTokenBar.tokenbar.render(true); app.close({ force: true }); } } diff --git a/apps/savingthrow.js b/apps/savingthrow.js index 0eea87f..f715307 100644 --- a/apps/savingthrow.js +++ b/apps/savingthrow.js @@ -503,7 +503,7 @@ export class SavingThrow { static async rollDice(dice) { let r = new Roll(dice); - return r.evaluate({ async: true }); + return r.evaluate(); } static async returnRoll (id, roll, actor, rollmode, msgId) { @@ -598,11 +598,11 @@ export class SavingThrow { promises.push(game.dice3d.showForRoll(roll, game.user, true, cantSee, canSee.includes(game.user.id), null)); } finishroll = Promise.all(promises).then(() => { - return { id: id, reveal: true, userid: game.userId }; + return { id: id, roll: roll, reveal: true, userid: game.userId }; }); } else { finishroll = new Promise((resolve) => { - resolve({ id: id, reveal: true, userid: game.userId }) + resolve({ id: id, roll: roll, reveal: true, userid: game.userId }) }); } const sound = MonksTokenBar.getDiceSound(); @@ -759,10 +759,12 @@ export class SavingThrow { let promises = []; + log("Updating message with results", updates, message.toObject(), reveal) + for (let update of updates) { if (update != undefined) { let msgtoken = foundry.utils.duplicate(message.getFlag('monks-tokenbar', 'token' + update.id)); - log('updating actor', msgtoken, update.roll); + log('Updating message token', msgtoken, update.roll); if (update.roll) { let tooltip = ''; @@ -930,11 +932,17 @@ export class SavingThrow { } } else { let flags = {}; + log("Finish Rolling", updates, message.toObject()) for (let update of updates) { let msgtoken = foundry.utils.duplicate(message.getFlag('monks-tokenbar', 'token' + update.id)); msgtoken.reveal = true; + msgtoken.tempreveal = true; + if (!msgtoken.roll && update.roll) { + //if the roll was not set, then set it + msgtoken.roll = Roll.fromData(update.roll); + } flags["token" + update.id] = msgtoken; - log("Finish Rolling", msgtoken); + log("Finish Rolling message token", foundry.utils.duplicate(msgtoken)); } message.update({ flags: { 'monks-tokenbar': flags } }); } @@ -1046,7 +1054,7 @@ export class SavingThrow { const newData = foundry.utils.deepClone(oldRoll.data); const newOptions = { ...oldRoll.options, isReroll: !0 }; const formula = oldRoll.formula.replace("2d20kh", "1d20").replace("2d20kl", "1d20"); - const newRoll = await new Roll(formula, newData, newOptions).evaluate({ async: !0 }); + const newRoll = await new Roll(formula, newData, newOptions).evaluate(); const rollmode = message.getFlag("monks-tokenbar", "rollmode"); if (game.dice3d != undefined && newRoll instanceof Roll && newRoll.ignoreDice !== true && MonksTokenBar.system.showRoll && !game.settings.get("core", "noCanvas") && game.system.id != "dnd5e") { @@ -1130,14 +1138,6 @@ export class SavingThrow { } } -/* -Hooks.on("diceSoNiceRollComplete", (messageid) => { - let message = ui.messages.find(m => m.id == messageid); - if (message != undefined) { - if() - } -})*/ - Hooks.on("renderSavingThrowApp", (app, html) => { if (app.request == undefined) { let request = MonksTokenBar.system.defaultRequest(app) || SavingThrow.lastRequest; diff --git a/apps/tokenbar.js b/apps/tokenbar.js index 199fe39..8e47424 100644 --- a/apps/tokenbar.js +++ b/apps/tokenbar.js @@ -3,8 +3,8 @@ import { SavingThrowApp } from "./savingthrow.js"; import { EditStats } from "./editstats.js"; export class TokenBar extends Application { - constructor(options) { - super(options); + constructor(options) { + super(options); this.entries = []; this.thumbnails = {}; @@ -34,11 +34,21 @@ export class TokenBar extends Application { } }); + Hooks.on('updateItem', (item, data, options) => { + if (((game.user.isGM || setting("allow-player")) && !setting("disable-tokenbar"))) { + let entry = this.entries.find(t => t.actor?.id == item.actor.id); + if (entry != undefined) { + this.updateEntry(entry); + } + } + }); + Hooks.on('updateOwnedItem', (actor, item, data) => { if (((game.user.isGM || setting("allow-player")) && !setting("disable-tokenbar"))) { let entry = this.entries.find(t => t.actor?.id == actor.id); if (entry != undefined) { - setTimeout(function () { this.updateEntry(entry); }, 100); //delay slightly so the PF2E condition can be rendered properly. + let that = this; + setTimeout(function () { that.updateEntry(entry); }, 100); //delay slightly so the PF2E condition can be rendered properly. } } }); @@ -100,7 +110,7 @@ export class TokenBar extends Application { /* -------------------------------------------- */ /** @override */ - static get defaultOptions() { + static get defaultOptions() { return foundry.utils.mergeObject(super.defaultOptions, { id: "tokenbar-window", template: "./modules/monks-tokenbar/templates/tokenbar.html", @@ -109,7 +119,7 @@ export class TokenBar extends Application { }); } - /* -------------------------------------------- */ + /* -------------------------------------------- */ /** @override */ getData(options) { @@ -145,6 +155,16 @@ export class TokenBar extends Application { let hbpos = $('#ui-bottom').offset(); let width = $('#hotbar').width(); this.pos = { left: hbpos.left + width + 36, right: '', top: '', bottom: 10 }; + + game.user.setFlag("monks-tokenbar", "position", this.pos); + } + + let checkLeft = Math.clamp(this.pos.left, 0, window.innerWidth - 200); + let checkTop = Math.clamp(this.pos.top, 0, window.innerHeight - 20); + + if (checkLeft != this.pos.left || checkTop != this.pos.top) { + this.pos.left = checkLeft; + this.pos.top = checkTop; game.user.setFlag("monks-tokenbar", "position", this.pos); } @@ -443,6 +463,9 @@ export class TokenBar extends Application { } diff.thumb = (thumb?.thumb || thumb); + if (setting("use-token-scaling")) { + diff.texture = entry.token?.texture; + } } if (entry.token && entry.movement != foundry.utils.getProperty(entry.token, "flags.monks-tokenbar.movement")) { @@ -550,6 +573,10 @@ export class TokenBar extends Application { //else position.left = xPos;// + 1; + position.left = Math.clamp(position.left, 0, window.innerWidth - 200); + position.top = Math.clamp(position.top, 0, window.innerHeight - 20); + + elmnt.style.bottom = (position.bottom ? position.bottom + "px" : null); elmnt.style.right = (position.right ? position.right + "px" : null); elmnt.style.top = (position.top ? position.top + "px" : null); diff --git a/css/tokenbar.css b/css/tokenbar.css index 9db6937..32c6d3e 100644 --- a/css/tokenbar.css +++ b/css/tokenbar.css @@ -280,6 +280,9 @@ body #tokenbar-window:first-child{ object-position: 50% 50%; border: none; box-shadow: 0 0 5px #444 inset; + transform: scale(var(--scaleX), var(--scaleY)); + -webkit-mask-image: var(--mask); + mask-image: var(--mask); } #tokenbar .token:hover .token-icon { @@ -800,6 +803,10 @@ body #tokenbar-window:first-child{ flex-direction: column; } +.monks-tokenbar.chat-card .token-roll-container .dice-roll.dsn-hide { + display: flex !important; +} + .monks-tokenbar.chat-card .token-properties { text-align: left; width: 100%; diff --git a/lang/en.json b/lang/en.json index 373177e..06642f2 100644 --- a/lang/en.json +++ b/lang/en.json @@ -191,6 +191,8 @@ "MonksTokenBar.show-movement.hint": "Show the movement buttons on the tokenbar", "MonksTokenBar.free-vehicle-combat.name": "Vehicle movement", "MonksTokenBar.free-vehicle-combat.hint": "Allow vehicle movement in combat", + "MonksTokenBar.use-token-scaling.name": "Use Token Scaling", + "MonksTokenBar.use-token-scaling.hint": "Use the token scaling to determine the size of the token", "MonksTokenBar.orientation.vertical": "Vertical", "MonksTokenBar.orientation.horizontal": "Horizontal", diff --git a/module.json b/module.json index 3d027fe..8fb7a0f 100644 --- a/module.json +++ b/module.json @@ -1,7 +1,7 @@ { "title": "Monk's TokenBar", "description": "Add a bar with all the current player tokens. Limit movement, roll saving throws, assign XP.", - "version": "12.02", + "version": "12.03", "authors": [ { "name": "IronMonk", @@ -82,7 +82,7 @@ "css/tokenbar.css" ], "url": "https://github.com/ironmonk88/monks-tokenbar", - "download": "https://github.com/ironmonk88/monks-tokenbar/archive/12.02.zip", + "download": "https://github.com/ironmonk88/monks-tokenbar/archive/12.03.zip", "manifest": "https://github.com/ironmonk88/monks-tokenbar/releases/latest/download/module.json", "bugs": "https://github.com/ironmonk88/monks-tokenbar/issues", "id": "monks-tokenbar", diff --git a/monks-tokenbar.js b/monks-tokenbar.js index 0ff8d7e..3709db6 100644 --- a/monks-tokenbar.js +++ b/monks-tokenbar.js @@ -22,6 +22,7 @@ import { SW5eRolls } from "./systems/sw5e-rolls.js"; import { CoC7Rolls } from "./systems/coc7-rolls.js"; import { T2K4ERolls } from "./systems/t2k4e-rolls.js"; + export let debug = (...args) => { if (MonksTokenBar.debugEnabled > 1) console.log("DEBUG: monks-tokenbar | ", ...args); }; @@ -301,7 +302,12 @@ export class MonksTokenBar { html += ``; } } else { - Object.entries(group.groups).forEach(e => option(...e)); + if (game.system.id == "burningwheel") { + const a = RegExp.escape(Handlebars.escapeExpression(choices)) + , s = new RegExp(` value=["']${a}["']`); + return options.fn(this).replace(s, "$& selected") + } else + Object.entries(choices).forEach(e => option(...e)); } return new Handlebars.SafeString(html); } @@ -1856,3 +1862,22 @@ Hooks.on("updateUser", (user, data, options, userId) => { MonksTokenBar.tokenbar.refresh(); } }); + +Hooks.on("diceSoNiceRollComplete", (messageid) => { + if (game.user.isGM) { + let message = game.messages.find(m => m.id == messageid); + if (message != undefined && message.hasFlag("monks-tokenbar")) { + let flags = {}; + for (let key of Object.keys(foundry.utils.getProperty(message, "flags.monks-tokenbar") || {})) { + if (key.startsWith('token')) { + let token = message.flags['monks-tokenbar'][key]; + if (token.tempreveal && !token.reveal) + flags["token" + token.id] = { reveal: true }; + } + } + + if (Object.keys(flags).length > 0) + message.update({ flags: { 'monks-tokenbar': flags } }); + } + } +}) diff --git a/settings.js b/settings.js index b792d78..7eff2f5 100644 --- a/settings.js +++ b/settings.js @@ -187,6 +187,15 @@ export const registerSettings = function () { requiresReload: true }); + game.settings.register(modulename, "use-token-scaling", { + name: game.i18n.localize("MonksTokenBar.use-token-scaling.name"), + hint: game.i18n.localize("MonksTokenBar.use-token-scaling.hint"), + scope: "client", + config: true, + default: false, + type: Boolean, + }); + //------------------------------------Icon settings-------------------------------------------- game.settings.register(modulename, "token-size", { @@ -464,15 +473,6 @@ export const registerSettings = function () { default: false, type: Boolean, }); - game.settings.register(modulename, "request-roll-sound", { - name: game.i18n.localize("MonksTokenBar.request-roll-sound.name"), - hint: game.i18n.localize("MonksTokenBar.request-roll-sound.hint"), - scope: "world", - config: false, - default: true, - type: Boolean, - filePicker: 'audio', - }); game.settings.register(modulename, "request-roll-sound-file", { name: game.i18n.localize("MonksTokenBar.request-roll-sound.name"), hint: game.i18n.localize("MonksTokenBar.request-roll-sound.hint"), @@ -480,6 +480,7 @@ export const registerSettings = function () { config: true, default: "modules/monks-tokenbar/sounds/RollRequestAlert.ogg", type: String, + filePicker: 'audio', }); game.settings.register(modulename, "gm-sound", { name: game.i18n.localize("MonksTokenBar.gm-sound.name"), diff --git a/systems/base-rolls.js b/systems/base-rolls.js index 773fbc2..52ab159 100644 --- a/systems/base-rolls.js +++ b/systems/base-rolls.js @@ -24,7 +24,7 @@ export class BaseRolls { } isCritical(roll) { - if (!(roll.terms[0] instanceof Die) && (roll.terms[0].faces === 20) || !roll._evaluated) return undefined; + if (!(roll.terms[0] instanceof foundry.dice.terms.Die) && (roll.terms[0].faces === 20) || !roll._evaluated) return undefined; if (Number.isNumeric(roll.options.critical) && roll.dice[0].total >= roll.options.critical) return 'critical'; if (Number.isNumeric(roll.options.fumble) && roll.dice[0].total <= roll.options.fumble) return 'fumble'; return false; diff --git a/systems/dnd5e-rolls.js b/systems/dnd5e-rolls.js index 284794d..12c6176 100644 --- a/systems/dnd5e-rolls.js +++ b/systems/dnd5e-rolls.js @@ -66,7 +66,7 @@ export class DnD5eRolls extends BaseRolls { } get showXP() { - return !game.settings.get('dnd5e', 'disableExperienceTracking'); + return game.settings.get('dnd5e', 'levelingMode') != "noxp"; } getXP(actor) { diff --git a/templates/tokenbar.html b/templates/tokenbar.html index a14872f..5c11501 100644 --- a/templates/tokenbar.html +++ b/templates/tokenbar.html @@ -28,7 +28,7 @@
{{#if this.thumb}} - + {{/if}} {{#if this.resource1.value}}