From 154b518383585f07878dd31f15f244edaf252d27 Mon Sep 17 00:00:00 2001 From: WBHarry Date: Thu, 12 Mar 2026 16:50:25 +0100 Subject: [PATCH] . --- lang/en.json | 1 + .../settings/appearanceSettings.mjs | 20 +++++- module/config/generalConfig.mjs | 4 +- module/config/settingsConfig.mjs | 1 + module/data/settings/Appearance.mjs | 68 +++++++++++++++---- module/data/settings/GlobalOverrides.mjs | 55 +++++++++++++++ module/data/settings/_module.mjs | 1 + module/systemRegistration/settings.mjs | 22 ++++-- .../appearance-settings/diceSoNice.hbs | 6 ++ 9 files changed, 156 insertions(+), 22 deletions(-) create mode 100644 module/data/settings/GlobalOverrides.mjs diff --git a/lang/en.json b/lang/en.json index fc9d9bac..4e724675 100755 --- a/lang/en.json +++ b/lang/en.json @@ -2755,6 +2755,7 @@ "globalAnimations": "Global Animations", "diceAppearance": "Dice Appearance", "animations": "Animations", + "defaultAnimations": "Set Animations As Player Defaults", "previewAnimation": "Preview Animation", "diceSoNice": { "title": "Dice So Nice", diff --git a/module/applications/settings/appearanceSettings.mjs b/module/applications/settings/appearanceSettings.mjs index 6266cf39..87135b06 100644 --- a/module/applications/settings/appearanceSettings.mjs +++ b/module/applications/settings/appearanceSettings.mjs @@ -70,6 +70,14 @@ export default class DHAppearanceSettings extends HandlebarsApplicationMixin(App } } + _attachPartListeners(partId, htmlElement, options) { + super._attachPartListeners(partId, htmlElement, options); + + htmlElement + .querySelector('.default-animations-input') + ?.addEventListener('change', this.toggleSFXOverride.bind(this)); + } + /** @inheritdoc */ _configureRenderParts(options) { const parts = super._configureRenderParts(options); @@ -83,14 +91,18 @@ export default class DHAppearanceSettings extends HandlebarsApplicationMixin(App /**@inheritdoc */ async _prepareContext(options) { const context = await super._prepareContext(options); - if (options.isFirstRender) + if (options.isFirstRender) { this.setting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance); + this.globalOverrides = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.GlobalOverrides); + } context.setting = this.setting; + context.globalOverrides = this.globalOverrides; context.fields = this.setting.schema.fields; context.tabs = this._prepareTabs('general'); context.dsnTabs = this._prepareTabs('diceSoNice'); + context.isGM = game.user.isGM; return context; } @@ -188,6 +200,12 @@ export default class DHAppearanceSettings extends HandlebarsApplicationMixin(App /* -------------------------------------------- */ + async toggleSFXOverride(event) { + await this.globalOverrides.diceSoNiceSFXUpdate(this.setting, event.target.checked); + this.globalOverrides = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.GlobalOverrides); + this.render(); + } + /** * Submit the configuration form. * @this {DHAppearanceSettings} diff --git a/module/config/generalConfig.mjs b/module/config/generalConfig.mjs index 804defcb..f1c21d26 100644 --- a/module/config/generalConfig.mjs +++ b/module/config/generalConfig.mjs @@ -699,7 +699,7 @@ export const daggerheartDiceAnimationEvents = { }; const getDiceSoNiceSFX = sfxOptions => { - const { diceSoNice } = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance); + const diceSoNice = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance).diceSoNiceData; const criticalAnimationData = diceSoNice.sfx.critical; if (sfxOptions.critical && criticalAnimationData.class) { return { @@ -753,7 +753,7 @@ export const getDiceSoNicePresets = async ( advantageFaces = 'd6', disadvantageFaces = 'd6' ) => { - const { diceSoNice } = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance); + const diceSoNice = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance).diceSoNiceData; const { isCritical, withHope, withFear } = result; diff --git a/module/config/settingsConfig.mjs b/module/config/settingsConfig.mjs index 38ffcf3b..0b28f0ab 100644 --- a/module/config/settingsConfig.mjs +++ b/module/config/settingsConfig.mjs @@ -26,6 +26,7 @@ export const gameSettings = { Metagaming: 'Metagaming', Homebrew: 'Homebrew', appearance: 'Appearance', + GlobalOverrides: 'GlobalOverrides', variantRules: 'VariantRules', Resources: { Fear: 'ResourcesFear' diff --git a/module/data/settings/Appearance.mjs b/module/data/settings/Appearance.mjs index 30c640b6..9da3afac 100644 --- a/module/data/settings/Appearance.mjs +++ b/module/data/settings/Appearance.mjs @@ -1,19 +1,19 @@ export default class DhAppearance extends foundry.abstract.DataModel { static LOCALIZATION_PREFIXES = ['DAGGERHEART.SETTINGS.Appearance']; + static sfxSchema = () => + new foundry.data.fields.SchemaField({ + class: new foundry.data.fields.StringField({ + nullable: true, + initial: null, + blank: true, + choices: CONFIG.DH.GENERAL.diceSoNiceSFXClasses + }) + }); + static defineSchema() { const { StringField, ColorField, BooleanField, SchemaField } = foundry.data.fields; - const sfxSchema = () => - new SchemaField({ - class: new StringField({ - nullable: true, - initial: null, - blank: true, - choices: CONFIG.DH.GENERAL.diceSoNiceSFXClasses - }) - }); - // helper to create dice style schema const diceStyle = ({ fg, bg, outline, edge }) => new SchemaField({ @@ -27,7 +27,7 @@ export default class DhAppearance extends foundry.abstract.DataModel { system: new StringField({ initial: 'standard', required: true, blank: false }), font: new StringField({ initial: 'auto', required: true, blank: false }), sfx: new SchemaField({ - higher: sfxSchema() + higher: DhAppearance.sfxSchema() }) }); @@ -45,7 +45,7 @@ export default class DhAppearance extends foundry.abstract.DataModel { advantage: diceStyle({ fg: '#ffffff', bg: '#008000', outline: '#000000', edge: '#ffffff' }), disadvantage: diceStyle({ fg: '#000000', bg: '#b30000', outline: '#ffffff', edge: '#000000' }), sfx: new SchemaField({ - critical: sfxSchema() + critical: DhAppearance.sfxSchema() }) }), extendCharacterDescriptions: new BooleanField(), @@ -81,4 +81,48 @@ export default class DhAppearance extends foundry.abstract.DataModel { showGenericStatusEffects: new BooleanField({ initial: true }) }; } + + get diceSoNiceData() { + const globalOverrides = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.GlobalOverrides); + const getSFX = (baseClientData, overrideKey) => { + if (!globalOverrides.diceSoNice.sfx.overrideEnabled) return baseClientData; + const overrideData = globalOverrides.diceSoNice.sfx[overrideKey]; + const clientData = foundry.utils.deepClone(baseClientData); + return Object.keys(clientData).reduce((acc, key) => { + const data = clientData[key]; + acc[key] = Object.keys(data).reduce((acc, dataKey) => { + const value = data[dataKey]; + acc[dataKey] = value ? value : overrideData[key][dataKey]; + return acc; + }, {}); + return acc; + }, {}); + }; + + return { + ...this.diceSoNice, + sfx: getSFX(this.diceSoNice.sfx, 'global'), + hope: { + ...this.diceSoNice.hope, + sfx: getSFX(this.diceSoNice.hope.sfx, 'hope') + }, + fear: { + ...this.diceSoNice.fear, + sfx: getSFX(this.diceSoNice.fear.sfx, 'fear') + } + }; + } + + /** Invoked by the setting when data changes */ + handleChange() { + if (this.displayFear) { + if (ui.resources) { + if (this.displayFear === 'hide') ui.resources.close({ allowed: true }); + else ui.resources.render({ force: true }); + } + } + + const globalOverrides = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.GlobalOverrides); + globalOverrides.diceSoNiceSFXUpdate(this); + } } diff --git a/module/data/settings/GlobalOverrides.mjs b/module/data/settings/GlobalOverrides.mjs new file mode 100644 index 00000000..746a6355 --- /dev/null +++ b/module/data/settings/GlobalOverrides.mjs @@ -0,0 +1,55 @@ +import DhAppearance from './Appearance.mjs'; + +/** + * A setting to handle cases where we want to allow the GM to set a global default for client settings. + */ +export default class DhGlobalOverrides extends foundry.abstract.DataModel { + static defineSchema() { + const fields = foundry.data.fields; + return { + diceSoNice: new fields.SchemaField({ + sfx: new fields.SchemaField({ + overrideEnabled: new fields.BooleanField(), + global: new fields.SchemaField({ + critical: DhAppearance.sfxSchema() + }), + hope: new fields.SchemaField({ + higher: DhAppearance.sfxSchema() + }), + fear: new fields.SchemaField({ + higher: DhAppearance.sfxSchema() + }) + }) + }) + }; + } + + async diceSoNiceSFXUpdate(appearanceSettings, enabled) { + if (!game.user.isGM) return; + + const newEnabled = enabled !== undefined ? enabled : this.diceSoNice.sfx.overrideEnabled; + if (newEnabled) { + const newOverrides = foundry.utils.mergeObject(this.toObject(), { + diceSoNice: { + sfx: { + overrideEnabled: true, + global: appearanceSettings.diceSoNice.sfx, + hope: appearanceSettings.diceSoNice.hope.sfx, + fear: appearanceSettings.diceSoNice.fear.sfx + } + } + }); + await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.GlobalOverrides, newOverrides); + } else { + const newOverrides = { + ...this.toObject(), + diceSoNice: { + sfx: { + overrideEnabled: false + } + } + }; + await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.GlobalOverrides, newOverrides); + } + } +} diff --git a/module/data/settings/_module.mjs b/module/data/settings/_module.mjs index 45405ba5..1343c0c4 100644 --- a/module/data/settings/_module.mjs +++ b/module/data/settings/_module.mjs @@ -3,3 +3,4 @@ export { default as DhAutomation } from './Automation.mjs'; export { default as DhHomebrew } from './Homebrew.mjs'; export { default as DhMetagaming } from './Metagaming.mjs'; export { default as DhVariantRules } from './VariantRules.mjs'; +export { default as DhGlobalOverrides } from './GlobalOverrides.mjs'; diff --git a/module/systemRegistration/settings.mjs b/module/systemRegistration/settings.mjs index 8440e3fe..e7ec37f5 100644 --- a/module/systemRegistration/settings.mjs +++ b/module/systemRegistration/settings.mjs @@ -1,6 +1,13 @@ import { defaultLevelTiers, DhLevelTiers } from '../data/levelTier.mjs'; import DhCountdowns from '../data/countdowns.mjs'; -import { DhAppearance, DhAutomation, DhHomebrew, DhMetagaming, DhVariantRules } from '../data/settings/_module.mjs'; +import { + DhAppearance, + DhAutomation, + DhGlobalOverrides, + DhHomebrew, + DhMetagaming, + DhVariantRules +} from '../data/settings/_module.mjs'; import { DhAppearanceSettings, DhAutomationSettings, @@ -54,17 +61,18 @@ const registerMenuSettings = () => { } }); + game.settings.register(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.GlobalOverrides, { + scope: 'world', + config: false, + type: DhGlobalOverrides + }); + game.settings.register(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance, { scope: 'client', config: false, type: DhAppearance, onChange: value => { - if (value.displayFear) { - if (ui.resources) { - if (value.displayFear === 'hide') ui.resources.close({ allowed: true }); - else ui.resources.render({ force: true }); - } - } + value.handleChange(); } }); }; diff --git a/templates/settings/appearance-settings/diceSoNice.hbs b/templates/settings/appearance-settings/diceSoNice.hbs index b66274ec..3e46b38e 100644 --- a/templates/settings/appearance-settings/diceSoNice.hbs +++ b/templates/settings/appearance-settings/diceSoNice.hbs @@ -8,6 +8,12 @@ {{formInput fields.diceSoNice.fields.sfx.fields.critical.fields.class value=setting.diceSoNice.sfx.critical.class blank="" localize=true}} + {{#if isGM}} +
+ + +
+ {{/if}}