From ee5c3a93223aa5bd285a1c083e61aaebb35a92b9 Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Sat, 2 Aug 2025 22:36:21 +0200 Subject: [PATCH] [Feature] Loadout&Domains Homebrew (#529) * Removed ChatTheme from settings * 0 or blank loadoutSize now means unlimited * Added Homebrew maxDomains --- daggerheart.mjs | 11 ++------- lang/en.json | 15 ++++++------ .../settings/appearanceSettings.mjs | 7 +----- .../applications/sheets/actors/character.mjs | 9 ++++--- module/applications/sheets/items/class.mjs | 5 +++- module/config/settingsConfig.mjs | 11 --------- module/data/actor/character.mjs | 7 +++--- module/data/item/class.mjs | 10 +++++++- module/data/settings/Appearance.mjs | 17 ------------- module/data/settings/Homebrew.mjs | 7 ++++++ module/documents/actor.mjs | 24 +++++++++++++++---- module/helpers/utils.mjs | 2 +- styles/less/ui/settings/settings.less | 12 ++++++++++ templates/settings/homebrew-settings.hbs | 2 ++ 14 files changed, 74 insertions(+), 65 deletions(-) diff --git a/daggerheart.mjs b/daggerheart.mjs index 025dde3a..d0b003bc 100644 --- a/daggerheart.mjs +++ b/daggerheart.mjs @@ -8,7 +8,6 @@ import RegisterHandlebarsHelpers from './module/helpers/handlebarsHelper.mjs'; import { enricherConfig, enricherRenderSetup } from './module/enrichers/_module.mjs'; import { getCommandTarget, rollCommandToJSON } from './module/helpers/utils.mjs'; import { NarrativeCountdowns } from './module/applications/ui/countdowns.mjs'; -import { DualityRollColor } from './module/data/settings/Appearance.mjs'; import { DHRoll, DualityRoll, D20Roll, DamageRoll, DualityDie } from './module/dice/_module.mjs'; import { enrichedDualityRoll } from './module/enrichers/DualityRollEnricher.mjs'; import { registerCountdownHooks } from './module/data/countdowns.mjs'; @@ -56,8 +55,8 @@ Hooks.once('init', () => { }; CONFIG.Dice.rolls = [...CONFIG.Dice.rolls, DHRoll, DualityRoll, D20Roll, DamageRoll]; - Roll.CHAT_TEMPLATE = "systems/daggerheart/templates/ui/chat/foundryRoll.hbs"; - Roll.TOOLTIP_TEMPLATE = "systems/daggerheart/templates/ui/chat/foundryRollTooltip.hbs"; + Roll.CHAT_TEMPLATE = 'systems/daggerheart/templates/ui/chat/foundryRoll.hbs'; + Roll.TOOLTIP_TEMPLATE = 'systems/daggerheart/templates/ui/chat/foundryRollTooltip.hbs'; CONFIG.MeasuredTemplate.objectClass = placeables.DhMeasuredTemplate; const { DocumentSheetConfig } = foundry.applications.apps; @@ -162,12 +161,6 @@ Hooks.on('ready', () => { if (game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.appearance).displayFear !== 'hide') ui.resources.render({ force: true }); - document.body.classList.toggle( - 'theme-colorful', - game.settings.get(SYSTEM.id, SYSTEM.SETTINGS.gameSettings.appearance).dualityColorScheme === - DualityRollColor.colorful.value - ); - registerCountdownHooks(); socketRegistration.registerSocketHooks(); registerRollDiceHooks(); diff --git a/lang/en.json b/lang/en.json index e15c9af5..be797216 100755 --- a/lang/en.json +++ b/lang/en.json @@ -2077,12 +2077,6 @@ } } }, - "DualityRollColor": { - "options": { - "colorful": "Colorful", - "normal": "Normal" - } - }, "Homebrew": { "newDowntimeMove": "Downtime Move", "downtimeMoves": "Downtime Moves", @@ -2092,7 +2086,11 @@ "FIELDS": { "maxFear": { "label": "Max Fear" }, "traitArray": { "label": "Initial Trait Modifiers" }, - "maxLoadout": { "label": "Max Cards in Loadout" } + "maxLoadout": { + "label": "Max Cards in Loadout", + "hint": "Set to blank or 0 for unlimited maximum" + }, + "maxDomains": { "label": "Max Class Domains", "hint": "Max domains you can set on a class" } }, "currency": { "enabled": "Enable Overrides", @@ -2282,7 +2280,8 @@ "beastformToManyAdvantages": "You cannot select any more advantages.", "beastformToManyFeatures": "You cannot select any more features.", "beastformEquipWeapon": "You cannot use weapons while in a Beastform.", - "loadoutMaxReached": "You already have {max} cards in your loadout. Move atleast one to your vault before adding a new one.", + "loadoutMaxReached": "You've reached maximum loadout. Move atleast one domain card to the vault, or increase the limit in homebrew settings if desired.", + "domainMaxReached": "You've reached the maximum domains for the class. Increase the limit in homebrew settings if desired.", "insufficientResources": "You have insufficient resources", "multiclassAlreadyPresent": "You already have a class and multiclass", "subclassesAlreadyPresent": "You already have a class and multiclass subclass" diff --git a/module/applications/settings/appearanceSettings.mjs b/module/applications/settings/appearanceSettings.mjs index 533dacff..491c9799 100644 --- a/module/applications/settings/appearanceSettings.mjs +++ b/module/applications/settings/appearanceSettings.mjs @@ -1,4 +1,4 @@ -import DhAppearance, { DualityRollColor } from '../../data/settings/Appearance.mjs'; +import DhAppearance from '../../data/settings/Appearance.mjs'; const { HandlebarsApplicationMixin, ApplicationV2 } = foundry.applications.api; @@ -96,11 +96,6 @@ export default class DHAppearanceSettings extends HandlebarsApplicationMixin(App static async save() { await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance, this.settings.toObject()); - document.body.classList.toggle( - 'theme-colorful', - game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.appearance).dualityColorScheme === - DualityRollColor.colorful.value - ); this.close(); } diff --git a/module/applications/sheets/actors/character.mjs b/module/applications/sheets/actors/character.mjs index 6e38e25d..76ca7562 100644 --- a/module/applications/sheets/actors/character.mjs +++ b/module/applications/sheets/actors/character.mjs @@ -266,9 +266,7 @@ export default class CharacterSheet extends DHBaseActorSheet { const doc = await getDocFromElement(target); const actorLoadout = doc.actor.system.loadoutSlot; if (actorLoadout.available) return doc.update({ 'system.inVault': false }); - ui.notifications.warn( - game.i18n.format('DAGGERHEART.UI.Notifications.loadoutMaxReached', { max: actorLoadout.max }) - ); + ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.loadoutMaxReached')); } }, { @@ -686,6 +684,11 @@ export default class CharacterSheet extends DHBaseActorSheet { */ static async #toggleVault(_event, button) { const doc = await getDocFromElement(button); + const { available } = this.document.system.loadoutSlot; + if (doc.system.inVault && !available) { + return ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.loadoutMaxReached')); + } + await doc?.update({ 'system.inVault': !doc.system.inVault }); } diff --git a/module/applications/sheets/items/class.mjs b/module/applications/sheets/items/class.mjs index 3dce0a11..192555a8 100644 --- a/module/applications/sheets/items/class.mjs +++ b/module/applications/sheets/items/class.mjs @@ -15,7 +15,10 @@ export default class ClassSheet extends DHBaseItemSheet { { selector: '.domain-input', options: () => CONFIG.DH.DOMAIN.domains, - callback: ClassSheet.#onDomainSelect + callback: ClassSheet.#onDomainSelect, + tagifyOptions: { + maxTags: () => game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).maxDomains + } } ], dragDrop: [ diff --git a/module/config/settingsConfig.mjs b/module/config/settingsConfig.mjs index 51197e8a..df3cb619 100644 --- a/module/config/settingsConfig.mjs +++ b/module/config/settingsConfig.mjs @@ -29,14 +29,3 @@ export const gameSettings = { LevelTiers: 'LevelTiers', Countdowns: 'Countdowns' }; - -export const DualityRollColor = { - colorful: { - value: 0, - label: 'DAGGERHEART.SETTINGS.DualityRollColor.options.colorful' - }, - normal: { - value: 1, - label: 'DAGGERHEART.SETTINGS.DualityRollColor.options.normal' - } -}; diff --git a/module/data/actor/character.mjs b/module/data/actor/character.mjs index f9f6e161..0e78e96a 100644 --- a/module/data/actor/character.mjs +++ b/module/data/actor/character.mjs @@ -362,13 +362,12 @@ export default class DhCharacter extends BaseDataActor { get loadoutSlot() { const loadoutCount = this.domainCards.loadout?.length ?? 0, - max = - game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).maxLoadout + - this.bonuses.maxLoadout; + worldSetting = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).maxLoadout, + max = !worldSetting ? null : worldSetting + this.bonuses.maxLoadout; return { current: loadoutCount, - available: Math.max(max - loadoutCount, 0), + available: !max ? true : Math.max(max - loadoutCount, 0), max }; } diff --git a/module/data/item/class.mjs b/module/data/item/class.mjs index bca6434c..72f58b8b 100644 --- a/module/data/item/class.mjs +++ b/module/data/item/class.mjs @@ -19,7 +19,7 @@ export default class DHClass extends BaseDataItem { const fields = foundry.data.fields; return { ...super.defineSchema(), - domains: new fields.ArrayField(new fields.StringField(), { max: 2 }), + domains: new fields.ArrayField(new fields.StringField()), classItems: new ForeignDocumentUUIDArrayField({ type: 'Item', required: false }), hitPoints: new fields.NumberField({ required: true, @@ -123,6 +123,14 @@ export default class DHClass extends BaseDataItem { const allowed = await super._preUpdate(changed, options, userId); if (allowed === false) return false; + if (changed.system?.domains) { + const maxDomains = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).maxDomains; + if (changed.system.domains.length > maxDomains) { + ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.domainMaxReached')); + return false; + } + } + const paths = [ 'subclasses', 'characterGuide.suggestedPrimaryWeapon', diff --git a/module/data/settings/Appearance.mjs b/module/data/settings/Appearance.mjs index c59cd436..e215f956 100644 --- a/module/data/settings/Appearance.mjs +++ b/module/data/settings/Appearance.mjs @@ -10,12 +10,6 @@ export default class DhAppearance extends foundry.abstract.DataModel { initial: fearDisplay.token.value, label: 'DAGGERHEART.SETTINGS.Appearance.FIELDS.displayFear.label' }), - dualityColorScheme: new fields.StringField({ - required: true, - choices: DualityRollColor, - initial: DualityRollColor.normal.value, - label: 'DAGGERHEART.SETTINGS.Appearance.FIELDS.dualityColorScheme.label' - }), diceSoNice: new fields.SchemaField({ hope: new fields.SchemaField({ foreground: new fields.ColorField({ required: true, initial: '#ffffff' }), @@ -65,14 +59,3 @@ export default class DhAppearance extends foundry.abstract.DataModel { }; } } - -export const DualityRollColor = { - colorful: { - value: 'colorful', - label: 'DAGGERHEART.SETTINGS.DualityRollColor.options.colorful' - }, - normal: { - value: 'normal', - label: 'DAGGERHEART.SETTINGS.DualityRollColor.options.normal' - } -}; diff --git a/module/data/settings/Homebrew.mjs b/module/data/settings/Homebrew.mjs index 29da1aa0..0251dd54 100644 --- a/module/data/settings/Homebrew.mjs +++ b/module/data/settings/Homebrew.mjs @@ -21,6 +21,13 @@ export default class DhHomebrew extends foundry.abstract.DataModel { initial: 5, label: 'DAGGERHEART.SETTINGS.Homebrew.FIELDS.maxLoadout.label' }), + maxDomains: new fields.NumberField({ + required: true, + integer: true, + min: 1, + initial: 2, + label: 'DAGGERHEART.SETTINGS.Homebrew.FIELDS.maxDomains.label' + }), traitArray: new fields.ArrayField(new fields.NumberField({ required: true, integer: true }), { initial: () => [2, 1, 1, 0, 0, -1] }), diff --git a/module/documents/actor.mjs b/module/documents/actor.mjs index ef968b47..4dad59c7 100644 --- a/module/documents/actor.mjs +++ b/module/documents/actor.mjs @@ -318,8 +318,16 @@ export default class DhpActor extends Actor { for (var domainCard of domainCards) { if (levelupAuto) { - const item = await foundry.utils.fromUuid(domainCard.data[0]); - const embeddedItem = await this.createEmbeddedDocuments('Item', [item.toObject()]); + const itemData = (await foundry.utils.fromUuid(domainCard.data[0])).toObject(); + const embeddedItem = await this.createEmbeddedDocuments('Item', [ + { + ...itemData, + system: { + ...itemData.system, + inVault: true + } + } + ]); selections.push({ ...domainCard, itemUuid: embeddedItem[0].uuid }); } else { selections.push({ ...domainCard }); @@ -329,8 +337,16 @@ export default class DhpActor extends Actor { const achievementDomainCards = []; if (levelupAuto) { for (var card of Object.values(level.achievements.domainCards)) { - const item = await foundry.utils.fromUuid(card.uuid); - const embeddedItem = await this.createEmbeddedDocuments('Item', [item.toObject()]); + const itemData = (await foundry.utils.fromUuid(card.uuid)).toObject(); + const embeddedItem = await this.createEmbeddedDocuments('Item', [ + { + ...itemData, + system: { + ...itemData.system, + inVault: true + } + } + ]); card.itemUuid = embeddedItem[0].uuid; achievementDomainCards.push(card); } diff --git a/module/helpers/utils.mjs b/module/helpers/utils.mjs index 34de5a5c..4de67e86 100644 --- a/module/helpers/utils.mjs +++ b/module/helpers/utils.mjs @@ -97,7 +97,7 @@ export const tagifyElement = (element, options, onChange, tagifyOptions = {}) => description: option.description }; }), - maxTags: maxTags, + maxTags: typeof maxTags === 'function' ? maxTags() : maxTags, dropdown: { mapValueTo: 'name', searchKeys: ['name'], diff --git a/styles/less/ui/settings/settings.less b/styles/less/ui/settings/settings.less index 0ba6f094..3033b4e7 100644 --- a/styles/less/ui/settings/settings.less +++ b/styles/less/ui/settings/settings.less @@ -126,4 +126,16 @@ } } } + + .settings-hint { + width: 100%; + display: flex; + justify-content: end; + + label { + width: 240px; + font-style: italic; + text-align: center; + } + } } diff --git a/templates/settings/homebrew-settings.hbs b/templates/settings/homebrew-settings.hbs index 6bfcbb9c..b70d63ad 100644 --- a/templates/settings/homebrew-settings.hbs +++ b/templates/settings/homebrew-settings.hbs @@ -3,7 +3,9 @@