From f3acacc28928f5d92e2d54e4a54c9526f0d8e16a Mon Sep 17 00:00:00 2001 From: Paul Maskelyne Date: Sat, 16 Nov 2024 17:55:58 +0000 Subject: [PATCH] slight restructure, and add release notes --- RELEASE_NOTES.md | 1 + i18n/en.yaml | 5 +- system/shadowdark.mjs | 9 +- system/src/apps/RequestCheckSD.mjs | 50 ++++++++++- system/src/enrichers.mjs | 44 ++++++++++ .../ActiveEffectsSD.mjs} | 0 system/src/system/ChatSD.mjs | 45 ++++++++++ system/src/utils/ChecksSD.mjs | 85 ------------------- system/src/utils/UtilitySD.mjs | 27 ++++++ system/templates/chat/general.hbs | 6 ++ system/templates/chat/roll-request.hbs | 8 ++ 11 files changed, 186 insertions(+), 94 deletions(-) create mode 100644 system/src/enrichers.mjs rename system/src/{effects.mjs => system/ActiveEffectsSD.mjs} (100%) create mode 100644 system/src/system/ChatSD.mjs delete mode 100644 system/src/utils/ChecksSD.mjs create mode 100644 system/templates/chat/general.hbs create mode 100644 system/templates/chat/roll-request.hbs diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index d24eda88..904cffd8 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -7,6 +7,7 @@ * [#880] Create a new Patron Boon type for Talents * [#901] Added Russian as a partially complete system language. * [#908] Add rollable dice to Cure Wounds spell that includes the necessary calculations *(Many thanks to **nschoenwald** for contributing to this issue)* +* [#910] Implement prompt for DC Checks * [#920] Show tooltips on weapon and armor properties when showing expanded inline view in inventory * [#921] Add way to view/manipulate current Active Effects to the player Effects tab * [#937] Support selecting or rolling Patron in character generator diff --git a/i18n/en.yaml b/i18n/en.yaml index 9fe9036f..3a81b028 100644 --- a/i18n/en.yaml +++ b/i18n/en.yaml @@ -110,8 +110,8 @@ SHADOWDARK.apps.request-check.copied: Copied to Clipboard SHADOWDARK.apps.request-check.copy_to_clipboard: Copy to Clipboard SHADOWDARK.apps.request-check.custom: Custom SHADOWDARK.apps.request-check.easy: Easy -SHADOWDARK.apps.request-check.hard: Hard SHADOWDARK.apps.request-check.extreme: Extreme +SHADOWDARK.apps.request-check.hard: Hard SHADOWDARK.apps.request-check.normal: Normal SHADOWDARK.apps.request-check.title: Request Check SHADOWDARK.apps.shadowdarkling-importer.errors: Items Not Found @@ -351,9 +351,10 @@ SHADOWDARK.error.class_ability.no-uses-remaining: No uses remaining SHADOWDARK.error.general.gm_required: You must have the Game Master role to do that. SHADOWDARK.error.general.no_character_class: No character class has been selected SHADOWDARK.error.general.no_character_selected: No character selected +SHADOWDARK.error.patron.no_supported_class: Unable to add Patron as the currently configured class does not allow it SHADOWDARK.error.source.source_missing: Source missing or unknown... SHADOWDARK.error.spells.no_spellcasting_ability_set: No character spellcasting ability has been configured -SHADOWDARK.error.patron.no_supported_class: Unable to add Patron as the currently configured class does not allow it +SHADOWDARK.error.too_many_tokens_selected: Too many tokens selected SHADOWDARK.form.section_header.equipment.label: Equipment SHADOWDARK.form.section_header.languages.label: Languages SHADOWDARK.form.section_header.names.label: Names diff --git a/system/shadowdark.mjs b/system/shadowdark.mjs index 903fcc7d..3154bb6b 100644 --- a/system/shadowdark.mjs +++ b/system/shadowdark.mjs @@ -1,14 +1,15 @@ +import ActiveEffectsSD from "./src/system/ActiveEffectsSD.mjs"; +import ChatSD from "./src/system/ChatSD.mjs"; import CompendiumsSD from "./src/documents/CompendiumsSD.mjs"; import loadTemplates from "./src/templates.mjs"; import Logger from "./src/utils/Logger.mjs"; import performDataMigration from "./src/migration.mjs"; import registerHandlebarsHelpers from "./src/handlebars.mjs"; import registerSystemSettings from "./src/settings.mjs"; +import registerTextEditorEnrichers from "./src/enrichers.mjs"; import SHADOWDARK from "./src/config.mjs"; import ShadowdarkMacro from "./src/macro.mjs"; import UtilitySD from "./src/utils/UtilitySD.mjs"; -import ChecksSD from "./src/utils/ChecksSD.mjs"; -import ActiveEffectsSD from "./src/effects.mjs"; import * as apps from "./src/apps/_module.mjs"; import * as chat from "./src/chat/_module.mjs"; @@ -30,6 +31,7 @@ import listenOnSocket from "./src/socket.mjs"; globalThis.shadowdark = { apps, + chat: ChatSD, compendiums: CompendiumsSD, config: SHADOWDARK, debug: Logger.debug, @@ -41,7 +43,6 @@ globalThis.shadowdark = { log: Logger.log, macro: ShadowdarkMacro, sheets, - checks: ChecksSD, utils: UtilitySD, warn: Logger.warn, }; @@ -77,9 +78,9 @@ Hooks.once("init", () => { registerHandlebarsHelpers(); registerSystemSettings(); + registerTextEditorEnrichers(); loadTemplates(); - ChecksSD.registerEnrichers(); UtilitySD.loadLegacyArtMappings(); // Register sheet application classes diff --git a/system/src/apps/RequestCheckSD.mjs b/system/src/apps/RequestCheckSD.mjs index b32e93af..b355d519 100644 --- a/system/src/apps/RequestCheckSD.mjs +++ b/system/src/apps/RequestCheckSD.mjs @@ -10,6 +10,49 @@ export default class RequestCheckSD extends FormApplication { }); } + + static async checkHandler(event) { + const data = event.target?.dataset ?? {}; + + if (!data.command) return; + + switch (data.command) { + case "check": + const actor = await shadowdark.utils.getCurrentActor(); + if (!actor) { + return ui.notifications.error( + game.i18n.localize("SHADOWDARK.error.general.no_character_selected") + ); + } + + const options = { + target: data.dc, + stat: data.stat, + }; + + if (event.shiftKey) { + options.fastForward = true; + } + + return actor.rollAbility(data.stat.toLowerCase(), options); + case "request": + return RequestCheckSD.displayRequest(data.dc, data.stat); + } + } + + + static async displayRequest(dc, stat) { + shadowdark.chat.renderRollRequestMessage( + await shadowdark.utils.getCurrentActor(), + { + title: game.i18n.localize("SHADOWDARK.check.requesting"), + body: `[[check ${dc} ${stat}]]`, + }, + CONST.DICE_ROLL_MODES.PUBLIC + ); + } + + activateListeners(html) { super.activateListeners(html); @@ -20,6 +63,7 @@ export default class RequestCheckSD extends FormApplication { ); } + /** @override */ async getData() { return { @@ -33,9 +77,9 @@ export default class RequestCheckSD extends FormApplication { }; } + /** @inheritdoc */ async _updateObject(event, data) { - if (data.custom) { data.difficulty = data.custom; } @@ -48,11 +92,11 @@ export default class RequestCheckSD extends FormApplication { ui.notifications.info(game.i18n.localize("SHADOWDARK.apps.request-check.copied")); break; case "request-check": - shadowdark.checks.displayRequest(data.difficulty, data.stat); + RequestCheckSD.displayRequest(data.difficulty, data.stat); this.close(); break; default: - shadowdark.log("Request Check Error"); + shadowdark.error("Request Check Error"); } } diff --git a/system/src/enrichers.mjs b/system/src/enrichers.mjs new file mode 100644 index 00000000..0e399c05 --- /dev/null +++ b/system/src/enrichers.mjs @@ -0,0 +1,44 @@ +export default function registerTextEditorEnrichers() { + + CONFIG.TextEditor.enrichers.push({ + // [[check DC STAT]] + // [[request DC STAT]] + pattern: /\[\[(?check|request)\s(?\d+)\s(?\w{3})\]\]/g, + enricher: async (match, options) => { + let { command, dc, stat } = match.groups; + + // Check for invalid data + if (!parseInt(dc)) return; + if (CONFIG.SHADOWDARK.ABILITY_KEYS.includes(stat.toLowerCase())) { + stat = stat.toLowerCase(); + } + else { + return; + } + + // create replacement html + const link = document.createElement("a"); + link.className = "content-link"; + link.classList.add("skill-roll-request"); + link.dataset.command = command; + link.dataset.dc = dc; + link.dataset.stat = stat; + const linkText = `${game.i18n.localize("SHADOWDARK.class-ability.dc.label")} ${dc} ${game.i18n.localize(`SHADOWDARK.ability_${stat}`)}`.toUpperCase(); + switch (command) { + case "check": + link.innerHTML = `${linkText}`; + break; + case "request": + link.innerHTML = `${linkText}`; + break; + } + return link; + }, + }); + + $("body").on( + "click", "a.skill-roll-request", + shadowdark.apps.RequestCheckSD.checkHandler + ); + +} diff --git a/system/src/effects.mjs b/system/src/system/ActiveEffectsSD.mjs similarity index 100% rename from system/src/effects.mjs rename to system/src/system/ActiveEffectsSD.mjs diff --git a/system/src/system/ChatSD.mjs b/system/src/system/ChatSD.mjs new file mode 100644 index 00000000..998b044b --- /dev/null +++ b/system/src/system/ChatSD.mjs @@ -0,0 +1,45 @@ +export default class ChatSD { + + static async _renderChatMessage( + actor, + data, + template, + mode + ) { + const html = await renderTemplate(template, data); + + if (!mode) { + mode = game.settings.get("core", "rollMode"); + } + + const messageStyles = shadowdark.utils.getMessageStyles(); + + const chatData = { + user: game.user.id, + speaker: ChatMessage.getSpeaker({ + actor: actor, + }), + rollMode: mode, + content: html, + type: messageStyles.OTHER, + }; + + ChatMessage.applyRollMode(chatData, mode); + + await ChatMessage.create(chatData); + } + + static async renderGeneralMessage(actor, data, mode) { + this._renderChatMessage(actor, data, + "systems/shadowdark/templates/chat/general.hbs", + mode + ); + } + + static async renderRollRequestMessage(actor, data, mode) { + this._renderChatMessage(actor, data, + "systems/shadowdark/templates/chat/roll-request.hbs", + mode + ); + } +} diff --git a/system/src/utils/ChecksSD.mjs b/system/src/utils/ChecksSD.mjs deleted file mode 100644 index ee36dedc..00000000 --- a/system/src/utils/ChecksSD.mjs +++ /dev/null @@ -1,85 +0,0 @@ -export default class ChecksSD { - - static async registerEnrichers() { - // load custom text enrichers - // [[check DC STAT]] - // [[request DC STAT]] - CONFIG.TextEditor.enrichers.push({ - pattern: /\[\[(?check|request)\s(?\d+)\s(?\w{3})\]\]/g, - enricher: async (match, options) => { - let { command, dc, stat } = match.groups; - - // Check for invalid data - if (!parseInt(dc)) return; - if (CONFIG.SHADOWDARK.ABILITY_KEYS.includes(stat.toLowerCase())) { - stat = stat.toLowerCase(); - } - else { - return; - } - - // create replacement html - const link = document.createElement("a"); - link.className = "content-link"; - link.dataset.command = command; - link.dataset.dc = dc; - link.dataset.stat = stat; - const linkText = `${game.i18n.localize("SHADOWDARK.class-ability.dc.label")} ${dc} ${game.i18n.localize(`SHADOWDARK.ability_${stat}`)}`.toUpperCase(); - switch (command) { - case "check": - link.innerHTML = `${linkText}`; - break; - case "request": - link.innerHTML = `${linkText}`; - break; - } - return link; - }, - }); - - document.body.addEventListener("click", this.checkHandler); - } - - static async checkHandler(event) { - let data = event.target?.dataset; - if ( !data.command ) return; - - switch (data.command) { - case "check": - let options = {}; - if (event.shiftKey) { - options.fastForward = true; - } - shadowdark.checks.rollCheck(data.dc, data.stat, options); - break; - case "request": - shadowdark.checks.displayRequest(data.dc, data.stat); - break; - } - } - - static async rollCheck(dc, stat, options={}) { - let actor = game.user.character; - if (!actor) { - ui.notification.error( - game.i18n.localize("SHADOWDARK.error.general.no_character_selected") - ); - } - if (dc) { - options.target = dc; - } - actor.rollAbility(stat.toLowerCase(), options); - } - - - static async displayRequest(dc, stat) { - const HTML = `
[[check ${dc} ${stat}]]
`; - const chatData = { - user: game.user._id, - flavor: game.i18n.localize("SHADOWDARK.check.requesting"), - content: HTML, - }; - ChatMessage.create(chatData, {}); - } - -} diff --git a/system/src/utils/UtilitySD.mjs b/system/src/utils/UtilitySD.mjs index 35269435..3361777a 100644 --- a/system/src/utils/UtilitySD.mjs +++ b/system/src/utils/UtilitySD.mjs @@ -83,6 +83,33 @@ export default class UtilitySD { } + // Work out the current Actor. + // If the user is the GM then use the current token they have selected. + // + static async getCurrentActor() { + let actor = null; + + if (game.user.isGM) { + const controlledTokenCount = canvas.tokens.controlled.length; + if (controlledTokenCount > 0) { + if (controlledTokenCount !== 1) { + return ui.notifications.warn( + game.i18n.localize("SHADOWDARK.error.too_many_tokens_selected") + ); + } + else { + actor = canvas.tokens.controlled[0].actor; + } + } + } + else { + actor = game.user.character; + } + + return actor; + } + + /** * Creates de-duplicated lists of Selected and Unselected Items. * diff --git a/system/templates/chat/general.hbs b/system/templates/chat/general.hbs new file mode 100644 index 00000000..fac8fa8b --- /dev/null +++ b/system/templates/chat/general.hbs @@ -0,0 +1,6 @@ +
+
+

{{title}}

+

{{body}}

+
+
diff --git a/system/templates/chat/roll-request.hbs b/system/templates/chat/roll-request.hbs new file mode 100644 index 00000000..dfe5a99d --- /dev/null +++ b/system/templates/chat/roll-request.hbs @@ -0,0 +1,8 @@ +
+
+

{{title}}

+
+

{{body}}

+
+
+