From 8172e8baa74f5eb1c4fa9dacfeb201144224f917 Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Fri, 13 Mar 2026 00:15:52 +0100 Subject: [PATCH] [Feature] DualityDice DiceSoNice Animations (#1722) * . * Fixed translation * Remove fieldset * DiceSoNice Animation Overrides (#1726) * . * . * Fixed hope/fear animation input * Visual tweaks to general tab * Move general tab to top * Fixed localizaiton --------- Co-authored-by: Carlos Fernandez --- lang/en.json | 12 +- .../settings/appearanceSettings.mjs | 53 +++++++- module/config/generalConfig.mjs | 117 +++++++++++++++++- module/config/resourceConfig.mjs | 6 +- module/config/settingsConfig.mjs | 1 + module/data/fields/actorField.mjs | 4 +- module/data/settings/Appearance.mjs | 64 +++++++++- module/data/settings/GlobalOverrides.mjs | 55 ++++++++ module/data/settings/Homebrew.mjs | 2 +- module/data/settings/_module.mjs | 1 + module/dice/dualityRoll.mjs | 6 +- module/helpers/utils.mjs | 8 +- module/systemRegistration/handlebars.mjs | 3 +- module/systemRegistration/settings.mjs | 22 ++-- styles/less/global/elements.less | 59 +-------- styles/less/ui/index.less | 1 + .../appearance-settings/diceSoNice.less | 72 +++++++++++ .../appearance-settings/diceSoNice.hbs | 94 +++++--------- .../appearance-settings/diceSoNiceTab.hbs | 62 ++++++++++ 19 files changed, 492 insertions(+), 150 deletions(-) create mode 100644 module/data/settings/GlobalOverrides.mjs create mode 100644 styles/less/ui/settings/appearance-settings/diceSoNice.less create mode 100644 templates/settings/appearance-settings/diceSoNiceTab.hbs diff --git a/lang/en.json b/lang/en.json index 75896218..98cae76b 100755 --- a/lang/en.json +++ b/lang/en.json @@ -1058,6 +1058,10 @@ "fear": "Fear", "spotlight": "Spotlight" }, + "DaggerheartDiceAnimationEvents": { + "critical": { "name": "Critical" }, + "higher": { "name": "Highest Roll" } + }, "DamageType": { "physical": { "name": "Physical", @@ -2309,6 +2313,7 @@ "plurial": "Players" }, "portrait": "Portrait", + "preview": "Preview", "proficiency": "Proficiency", "quantity": "Quantity", "range": "Range", @@ -2758,7 +2763,12 @@ "colorset": "Theme", "material": "Material", "system": "Dice Preset", - "font": "Font" + "font": "Font", + "critical": "Duality Critical Animation", + "diceAppearance": "Dice Appearance", + "animations": "Animations", + "defaultAnimations": "Set Animations As Player Defaults", + "previewAnimation": "Preview Animation" } }, "variantRules": { diff --git a/module/applications/settings/appearanceSettings.mjs b/module/applications/settings/appearanceSettings.mjs index 9eb0cfbf..151648e1 100644 --- a/module/applications/settings/appearanceSettings.mjs +++ b/module/applications/settings/appearanceSettings.mjs @@ -12,7 +12,7 @@ export default class DHAppearanceSettings extends HandlebarsApplicationMixin(App static DEFAULT_OPTIONS = { tag: 'form', id: 'daggerheart-appearance-settings', - classes: ['daggerheart', 'dialog', 'dh-style', 'setting'], + classes: ['daggerheart', 'dialog', 'dh-style', 'setting', 'appearance-settings'], position: { width: '600', height: 'auto' }, window: { title: 'DAGGERHEART.SETTINGS.Menu.title', @@ -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,15 +91,20 @@ 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; } @@ -120,6 +133,9 @@ export default class DHAppearanceSettings extends HandlebarsApplicationMixin(App * @protected */ async prepareDiceSoNiceContext(context) { + context.animationEvents = CONFIG.DH.GENERAL.daggerheartDiceAnimationEvents; + context.previewAnimation = this.previewAnimation; + context.diceSoNiceTextures = Object.entries(game.dice3d.exports.TEXTURELIST).reduce( (acc, [k, v]) => ({ ...acc, @@ -146,6 +162,13 @@ export default class DHAppearanceSettings extends HandlebarsApplicationMixin(App ); context.diceSoNiceFonts = game.dice3d.exports.Utils.prepareFontList(); + const getAnimationsOptions = key => { + const fields = context.fields.diceSoNice.fields[key].fields.sfx.fields; + return { + higher: fields.higher.fields.class.choices + }; + }; + foundry.utils.mergeObject( context.dsnTabs, ['hope', 'fear', 'advantage', 'disadvantage'].reduce( @@ -153,7 +176,8 @@ export default class DHAppearanceSettings extends HandlebarsApplicationMixin(App ...acc, [key]: { values: this.setting.diceSoNice[key], - fields: this.setting.schema.getField(`diceSoNice.${key}`).fields + fields: this.setting.schema.getField(`diceSoNice.${key}`).fields, + animations: ['hope', 'fear'].includes(key) ? getAnimationsOptions(key) : {} } }), {} @@ -169,13 +193,20 @@ export default class DHAppearanceSettings extends HandlebarsApplicationMixin(App * @param {foundry.applications.ux.FormDataExtended} formData * @returns {Promise} */ - static async #onSubmit(event, form, formData) { + static async #onSubmit(_event, _form, formData) { const data = this.setting.schema.clean(foundry.utils.expandObject(formData.object)); + await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance, data); } /* -------------------------------------------- */ + 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} @@ -183,13 +214,25 @@ export default class DHAppearanceSettings extends HandlebarsApplicationMixin(App */ static async #onPreview(_, target) { const formData = new foundry.applications.ux.FormDataExtended(target.closest('form')); - const { diceSoNice } = foundry.utils.expandObject(formData.object); + const { diceSoNice, ...rest } = foundry.utils.expandObject(formData.object); const { key } = target.dataset; const faces = ['advantage', 'disadvantage'].includes(key) ? 'd6' : 'd12'; const preset = await getDiceSoNicePreset(diceSoNice[key], faces); const diceSoNiceRoll = await new foundry.dice.Roll(`1${faces}`).evaluate(); diceSoNiceRoll.dice[0].options.appearance = preset.appearance; diceSoNiceRoll.dice[0].options.modelFile = preset.modelFile; + + const previewAnimation = rest[`${key}PreviewAnimation`]; + const events = CONFIG.DH.GENERAL.daggerheartDiceAnimationEvents; + if (previewAnimation) { + if (previewAnimation === events.critical.id && diceSoNice.sfx.critical.class) { + diceSoNiceRoll.dice[0].options.sfx = { specialEffect: diceSoNice.sfx.critical.class }; + } + if (previewAnimation === events.higher.id && diceSoNice[key].sfx.higher) { + diceSoNiceRoll.dice[0].options.sfx = { specialEffect: diceSoNice[key].sfx.higher.class }; + } + } + await game.dice3d.showForRoll(diceSoNiceRoll, game.user, false); } diff --git a/module/config/generalConfig.mjs b/module/config/generalConfig.mjs index d46db23a..f1c21d26 100644 --- a/module/config/generalConfig.mjs +++ b/module/config/generalConfig.mjs @@ -630,7 +630,95 @@ export const diceSetNumbers = { flat: 'Flat' }; -export const getDiceSoNicePreset = async (type, faces) => { +export const diceSoNiceSFXClasses = { + PlayAnimationBright: { + id: 'PlayAnimationBright', + label: 'DICESONICE.PlayAnimationBright' + }, + PlayAnimationDark: { + id: 'PlayAnimationDark', + label: 'DICESONICE.PlayAnimationDark' + }, + PlayAnimationOutline: { + id: 'PlayAnimationOutline', + label: 'DICESONICE.PlayAnimationOutline' + }, + PlayAnimationImpact: { + id: 'PlayAnimationImpact', + label: 'DICESONICE.PlayAnimationImpact' + }, + // PlayConfettiStrength1: { + // id: 'PlayConfettiStrength1', + // label: 'DICESONICE.PlayConfettiStrength1' + // }, + // PlayConfettiStrength2: { + // id: 'PlayConfettiStrength2', + // label: 'DICESONICE.PlayConfettiStrength2' + // }, + // PlayConfettiStrength3: { + // id: 'PlayConfettiStrength3', + // label: 'DICESONICE.PlayConfettiStrength3' + // }, + PlayAnimationThormund: { + id: 'PlayAnimationThormund', + label: 'DICESONICE.PlayAnimationThormund' + }, + PlayAnimationParticleSpiral: { + id: 'PlayAnimationParticleSpiral', + label: 'DICESONICE.PlayAnimationParticleSpiral' + }, + PlayAnimationParticleSparkles: { + id: 'PlayAnimationParticleSparkles', + label: 'DICESONICE.PlayAnimationParticleSparkles' + }, + PlayAnimationParticleVortex: { + id: 'PlayAnimationParticleVortex', + label: 'DICESONICE.PlayAnimationParticleVortex' + }, + PlaySoundEpicWin: { + id: 'PlaySoundEpicWin', + label: 'DICESONICE.PlaySoundEpicWin' + }, + PlaySoundEpicFail: { + id: 'PlaySoundEpicFail', + label: 'DICESONICE.PlaySoundEpicFail' + } + // "PlaySoundCustom", + // "PlayMacro" +}; + +export const daggerheartDiceAnimationEvents = { + critical: { + id: 'critical', + label: 'DAGGERHEART.CONFIG.DaggerheartDiceAnimationEvents.critical.name' + }, + higher: { + id: 'higher', + label: 'DAGGERHEART.CONFIG.DaggerheartDiceAnimationEvents.higher.name' + } +}; + +const getDiceSoNiceSFX = sfxOptions => { + 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 { + specialEffect: criticalAnimationData.class, + options: {} + }; + } + + if (sfxOptions.higher && sfxOptions.data.higher) { + return { + specialEffect: sfxOptions.data.higher.class, + options: {} + }; + } + + return {}; +}; + +export const getDiceSoNicePreset = async (type, faces, sfxOptions = {}) => { const system = game.dice3d.DiceFactory.systems.get(type.system).dice.get(faces); if (!system) { ui.notifications.error( @@ -653,16 +741,33 @@ export const getDiceSoNicePreset = async (type, faces) => { appearance: { ...system.appearance, ...type - } + }, + sfx: getDiceSoNiceSFX(sfxOptions) }; }; -export const getDiceSoNicePresets = async (hopeFaces, fearFaces, advantageFaces = 'd6', disadvantageFaces = 'd6') => { - const { diceSoNice } = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance); +export const getDiceSoNicePresets = async ( + result, + hopeFaces, + fearFaces, + advantageFaces = 'd6', + disadvantageFaces = 'd6' +) => { + const diceSoNice = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance).diceSoNiceData; + + const { isCritical, withHope, withFear } = result; return { - hope: await getDiceSoNicePreset(diceSoNice.hope, hopeFaces), - fear: await getDiceSoNicePreset(diceSoNice.fear, fearFaces), + hope: await getDiceSoNicePreset(diceSoNice.hope, hopeFaces, { + critical: isCritical, + higher: withHope, + data: diceSoNice.hope.sfx + }), + fear: await getDiceSoNicePreset(diceSoNice.fear, fearFaces, { + critical: isCritical, + higher: withFear, + data: diceSoNice.fear.sfx + }), advantage: await getDiceSoNicePreset(diceSoNice.advantage, advantageFaces), disadvantage: await getDiceSoNicePreset(diceSoNice.disadvantage, disadvantageFaces) }; diff --git a/module/config/resourceConfig.mjs b/module/config/resourceConfig.mjs index f7d56b44..56ef6cd5 100644 --- a/module/config/resourceConfig.mjs +++ b/module/config/resourceConfig.mjs @@ -72,17 +72,17 @@ const companionBaseResources = Object.freeze({ export const character = { base: characterBaseResources, custom: {}, // module stuff goes here - all: { ...characterBaseResources }, + all: { ...characterBaseResources } }; export const adversary = { base: adversaryBaseResources, custom: {}, // module stuff goes here - all: { ...adversaryBaseResources }, + all: { ...adversaryBaseResources } }; export const companion = { base: companionBaseResources, custom: {}, // module stuff goes here - all: { ...companionBaseResources }, + all: { ...companionBaseResources } }; 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/fields/actorField.mjs b/module/data/fields/actorField.mjs index 65e7abbf..1399fb32 100644 --- a/module/data/fields/actorField.mjs +++ b/module/data/fields/actorField.mjs @@ -21,7 +21,7 @@ const bonusField = label => dice: new fields.ArrayField(new fields.StringField(), { label: `${game.i18n.localize(label)} Dice` }) }); -/** +/** * Field used for actor resources. It is a resource that validates dynamically based on the config. * Because "max" may be defined during runtime, we don't attempt to clamp the maximum value. */ @@ -78,7 +78,7 @@ class ResourcesField extends fields.TypedObjectField { const resource = resources[key]; value.label = resource.label; value.isReversed = resources[key].reverse; - value.max = typeof resource.max === 'number' ? value.max ?? resource.max : null; + value.max = typeof resource.max === 'number' ? (value.max ?? resource.max) : null; } return data; } diff --git a/module/data/settings/Appearance.mjs b/module/data/settings/Appearance.mjs index cd98d6f9..9da3afac 100644 --- a/module/data/settings/Appearance.mjs +++ b/module/data/settings/Appearance.mjs @@ -1,6 +1,16 @@ 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; @@ -15,7 +25,10 @@ export default class DhAppearance extends foundry.abstract.DataModel { colorset: new StringField({ initial: 'inspired', required: true, blank: false }), material: new StringField({ initial: 'metal', required: true, blank: false }), system: new StringField({ initial: 'standard', required: true, blank: false }), - font: new StringField({ initial: 'auto', required: true, blank: false }) + font: new StringField({ initial: 'auto', required: true, blank: false }), + sfx: new SchemaField({ + higher: DhAppearance.sfxSchema() + }) }); return { @@ -30,7 +43,10 @@ export default class DhAppearance extends foundry.abstract.DataModel { hope: diceStyle({ fg: '#ffffff', bg: '#ffe760', outline: '#000000', edge: '#ffffff' }), fear: diceStyle({ fg: '#000000', bg: '#0032b1', outline: '#ffffff', edge: '#000000' }), advantage: diceStyle({ fg: '#ffffff', bg: '#008000', outline: '#000000', edge: '#ffffff' }), - disadvantage: diceStyle({ fg: '#000000', bg: '#b30000', outline: '#ffffff', edge: '#000000' }) + disadvantage: diceStyle({ fg: '#000000', bg: '#b30000', outline: '#ffffff', edge: '#000000' }), + sfx: new SchemaField({ + critical: DhAppearance.sfxSchema() + }) }), extendCharacterDescriptions: new BooleanField(), extendAdversaryDescriptions: new BooleanField(), @@ -65,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/Homebrew.mjs b/module/data/settings/Homebrew.mjs index 9b4ee2cf..d4b7b03f 100644 --- a/module/data/settings/Homebrew.mjs +++ b/module/data/settings/Homebrew.mjs @@ -220,7 +220,7 @@ export default class DhHomebrew extends foundry.abstract.DataModel { return result; }, {}), ...config.custom, - ...config.base, + ...config.base }); } } 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/dice/dualityRoll.mjs b/module/dice/dualityRoll.mjs index 9037250a..75fbdf55 100644 --- a/module/dice/dualityRoll.mjs +++ b/module/dice/dualityRoll.mjs @@ -378,6 +378,8 @@ export default class DualityRoll extends D20Roll { let parsedRoll = game.system.api.dice.DualityRoll.fromData({ ...rollString, evaluated: false }); const term = parsedRoll.terms[target.dataset.dieIndex]; await term.reroll(`/r1=${term.total}`); + const result = await parsedRoll.evaluate(); + if (game.modules.get('dice-so-nice')?.active) { const diceSoNiceRoll = { _evaluated: true, @@ -391,7 +393,7 @@ export default class DualityRoll extends D20Roll { options: { appearance: {} } }; - const diceSoNicePresets = await getDiceSoNicePresets(`d${term._faces}`, `d${term._faces}`); + const diceSoNicePresets = await getDiceSoNicePresets(result, `d${term._faces}`, `d${term._faces}`); const type = target.dataset.type; if (diceSoNicePresets[type]) { diceSoNiceRoll.dice[0].options = diceSoNicePresets[type]; @@ -400,8 +402,6 @@ export default class DualityRoll extends D20Roll { await game.dice3d.showForRoll(diceSoNiceRoll, game.user, true); } - await parsedRoll.evaluate(); - const newRoll = game.system.api.dice.DualityRoll.postEvaluate(parsedRoll, { targets: message.system.targets, roll: { diff --git a/module/helpers/utils.mjs b/module/helpers/utils.mjs index 5704b891..b49a98ca 100644 --- a/module/helpers/utils.mjs +++ b/module/helpers/utils.mjs @@ -60,7 +60,13 @@ export const getCommandTarget = (options = {}) => { export const setDiceSoNiceForDualityRoll = async (rollResult, advantageState, hopeFaces, fearFaces, advantageFaces) => { if (!game.modules.get('dice-so-nice')?.active) return; - const diceSoNicePresets = await getDiceSoNicePresets(hopeFaces, fearFaces, advantageFaces, advantageFaces); + const diceSoNicePresets = await getDiceSoNicePresets( + rollResult, + hopeFaces, + fearFaces, + advantageFaces, + advantageFaces + ); rollResult.dice[0].options = diceSoNicePresets.hope; rollResult.dice[1].options = diceSoNicePresets.fear; if (rollResult.dice[2] && advantageState) { diff --git a/module/systemRegistration/handlebars.mjs b/module/systemRegistration/handlebars.mjs index 9ccb16f4..f51e1035 100644 --- a/module/systemRegistration/handlebars.mjs +++ b/module/systemRegistration/handlebars.mjs @@ -46,6 +46,7 @@ export const preloadHandlebarsTemplates = async function () { 'systems/daggerheart/templates/ui/chat/parts/target-part.hbs', 'systems/daggerheart/templates/ui/chat/parts/button-part.hbs', 'systems/daggerheart/templates/ui/itemBrowser/itemContainer.hbs', - 'systems/daggerheart/templates/scene/dh-config.hbs' + 'systems/daggerheart/templates/scene/dh-config.hbs', + 'systems/daggerheart/templates/settings/appearance-settings/diceSoNiceTab.hbs' ]); }; 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/styles/less/global/elements.less b/styles/less/global/elements.less index f5e92e2c..beffefbb 100755 --- a/styles/less/global/elements.less +++ b/styles/less/global/elements.less @@ -565,60 +565,11 @@ } .application.setting.dh-style { - fieldset { - h2, - h3, - h4 { - margin: 8px 0 4px; - text-align: center; - } - .title-hint { - font-size: var(--font-size-12); - font-variant: small-caps; - text-align: center; - } - - .field-section { - display: flex; - flex-direction: column; - gap: 10px; - - .split-section { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 10px; - } - } - - .label-container { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 10px; - - &.full-width { - grid-template-columns: 1fr 1fr 1fr 1fr; - - select { - grid-column: span 3; - } - } - - label { - align-self: center; - text-align: center; - white-space: nowrap; - } - } - - .button-container { - display: grid; - grid-template-columns: 1fr; - gap: 10px; - text-align: center; - display: flex; - justify-content: center; - width: 100%; - } + h2, + h3, + h4 { + margin: 8px 0 4px; + text-align: center; } footer { diff --git a/styles/less/ui/index.less b/styles/less/ui/index.less index 5a6e5878..31ea8955 100644 --- a/styles/less/ui/index.less +++ b/styles/less/ui/index.less @@ -28,6 +28,7 @@ @import './settings/homebrew-settings/domains.less'; @import './settings/homebrew-settings/types.less'; @import './settings/homebrew-settings/resources.less'; +@import './settings/appearance-settings/diceSoNice.less'; @import './sidebar/tabs.less'; @import './sidebar/daggerheartMenu.less'; diff --git a/styles/less/ui/settings/appearance-settings/diceSoNice.less b/styles/less/ui/settings/appearance-settings/diceSoNice.less new file mode 100644 index 00000000..079bebc5 --- /dev/null +++ b/styles/less/ui/settings/appearance-settings/diceSoNice.less @@ -0,0 +1,72 @@ +.daggerheart.dh-style.setting.appearance-settings { + .tab.active[data-tab='diceSoNice'] { + display: flex; + flex-direction: column; + align-items: center; + gap: 0.5rem; + } + + .diceSoNice-footer { + display: grid; + align-items: center; + grid-template-columns: 1fr 1fr 1fr 1fr; + gap: 8px; + margin-top: 32px; + + label { + text-align: center; + } + + select { + grid-column: span 2; + } + } + + .title-hint { + font-size: var(--font-size-14); + font-variant: small-caps; + text-align: center; + } + + .split-section { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 10px; + + > label { + grid-column: span 2; + text-align: center; + font-size: var(--font-size-18); + font-weight: bold; + } + } + + .field-section { + display: flex; + flex-direction: column; + gap: 10px; + margin-bottom: 4px; + width: 100%; + padding: 0 8px; + } + + .label-container { + display: grid; + grid-template-columns: 1fr 1fr; + gap: 10px; + + &.full-width { + grid-template-columns: 1fr 1fr 1fr 1fr; + + select { + grid-column: span 3; + } + } + + label { + align-self: center; + text-align: center; + white-space: nowrap; + } + } +} diff --git a/templates/settings/appearance-settings/diceSoNice.hbs b/templates/settings/appearance-settings/diceSoNice.hbs index 6c89fd2f..afe7dd5a 100644 --- a/templates/settings/appearance-settings/diceSoNice.hbs +++ b/templates/settings/appearance-settings/diceSoNice.hbs @@ -1,71 +1,37 @@
-
{{localize "DAGGERHEART.SETTINGS.Menu.appearance.diceSoNice.hint"}}
- -
-
{{#each dsnTabs as |dsnTab|}} -
-
-
- - {{formInput fields.system value=values.system localize=true choices=@root.diceSoNiceSystems}} -
-
-
- - {{formInput fields.foreground value=values.foreground localize=true}} -
-
- - {{formInput fields.background value=values.background localize=true}} -
-
- - {{formInput fields.outline value=values.outline localize=true}} -
-
- - {{formInput fields.edge value=values.edge localize=true}} -
-
- - {{formInput fields.colorset value=values.colorset choices=@root.diceSoNiceColorsets localize=true}} -
-
- - {{formInput fields.texture value=values.texture choices=@root.diceSoNiceTextures localize=true}} -
-
- - {{formInput fields.material value=values.material choices=@root.diceSoNiceMaterials localize=true}} -
-
- - {{formInput fields.font value=values.font choices=@root.diceSoNiceFonts localize=true}} -
-
-
- -
-
-
+
+ {{> "systems/daggerheart/templates/settings/appearance-settings/diceSoNiceTab.hbs" dsnTab }} +
{{/each}} -
\ No newline at end of file diff --git a/templates/settings/appearance-settings/diceSoNiceTab.hbs b/templates/settings/appearance-settings/diceSoNiceTab.hbs new file mode 100644 index 00000000..a15b63ec --- /dev/null +++ b/templates/settings/appearance-settings/diceSoNiceTab.hbs @@ -0,0 +1,62 @@ +
+

{{localize "DAGGERHEART.SETTINGS.Menu.appearance.diceSoNice.diceAppearance"}}

+ +
+ + {{formInput fields.system value=values.system localize=true choices=@root.diceSoNiceSystems}} +
+
+
+ + {{formInput fields.foreground value=values.foreground localize=true}} +
+
+ + {{formInput fields.background value=values.background localize=true}} +
+
+ + {{formInput fields.outline value=values.outline localize=true}} +
+
+ + {{formInput fields.edge value=values.edge localize=true}} +
+
+ + {{formInput fields.colorset value=values.colorset choices=@root.diceSoNiceColorsets localize=true}} +
+
+ + {{formInput fields.texture value=values.texture choices=@root.diceSoNiceTextures localize=true}} +
+
+ + {{formInput fields.material value=values.material choices=@root.diceSoNiceMaterials localize=true}} +
+
+ + {{formInput fields.font value=values.font choices=@root.diceSoNiceFonts localize=true}} +
+
+ + {{#if animations}} +

{{localize "DAGGERHEART.SETTINGS.Menu.appearance.diceSoNice.animations"}}

+
+ + {{formInput fields.sfx.fields.higher.fields.class value=values.sfx.higher.class blank="" localize=true}} +
+ {{/if}} + + +
\ No newline at end of file