diff --git a/lang/en.json b/lang/en.json index 20c66a32..aff0d60a 100755 --- a/lang/en.json +++ b/lang/en.json @@ -2442,7 +2442,6 @@ "single": "Miss", "plural": "Miss" }, - "missingX": "Missing {x}", "maxWithThing": "Max {thing}", "missingDragDropThing": "Drop {thing} here", "multiclass": "Multiclass", @@ -2533,9 +2532,6 @@ "recovery": { "label": "Recovery" }, "type": { "label": "Type" }, "value": { "label": "Value" } - }, - "identifier": { - "label": "Identifier" } }, "Ancestry": { @@ -3223,6 +3219,7 @@ "subclassesAlreadyPresent": "You already have a class and multiclass subclass", "noDiceSystem": "Your selected dice {system} does not have a {faces} dice", "gmMenuRefresh": "You refreshed all actions and resources {types}", + "subclassAlreadyLinked": "{name} is already a subclass in the class {class}. Remove it from there if you want it to be a subclass to this class.", "gmRequired": "This action requires an online GM", "gmOnly": "This can only be accessed by the GM", "noActorOwnership": "You do not have permissions for this character", diff --git a/module/applications/characterCreation/characterCreation.mjs b/module/applications/characterCreation/characterCreation.mjs index 82ca9ccb..936bb79d 100644 --- a/module/applications/characterCreation/characterCreation.mjs +++ b/module/applications/characterCreation/characterCreation.mjs @@ -439,13 +439,10 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl 'system.domain': { key: 'system.domain', value: this.setup.class?.system.domains ?? null } }; - if (type === 'subclasses') { - const classItem = this.setup.class; - const uuid = classItem?._stats.compendiumSource ?? classItem?.uuid; + if (type === 'subclasses') presets.filter = { - 'system.linkedClass': { key: 'system.linkedClass', value: uuid } + 'system.linkedClass.uuid': { key: 'system.linkedClass.uuid', value: this.setup.class?.uuid } }; - } if (equipment.includes(type)) presets.filter = { @@ -613,8 +610,7 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl [foundry.utils.randomID()]: {} }; } else if (item.type === 'subclass' && event.target.closest('.subclass-card')) { - const classSubclasses = await this.setup.class.system.fetchSubclasses(); - if (classSubclasses.every(subclass => subclass.uuid !== item.uuid)) { + if (this.setup.class.system.subclasses.every(subclass => subclass.uuid !== item.uuid)) { ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.subclassNotInClass')); return; } diff --git a/module/applications/sheets/items/class.mjs b/module/applications/sheets/items/class.mjs index 25c631fe..05bb0229 100644 --- a/module/applications/sheets/items/class.mjs +++ b/module/applications/sheets/items/class.mjs @@ -104,10 +104,9 @@ export default class ClassSheet extends DHBaseItemSheet { } /**@inheritdoc */ - async _prepareContext(options) { - const context = await super._prepareContext(options); + async _prepareContext(_options) { + const context = await super._prepareContext(_options); context.domains = this.document.system.domains; - context.subclasses = await this.document.system.fetchSubclasses(); return context; } @@ -129,8 +128,20 @@ export default class ClassSheet extends DHBaseItemSheet { const item = await fromUuid(data.uuid); const itemType = data.type === 'ActiveEffect' ? data.type : item.type; const target = event.target.closest('fieldset.drop-section'); - - if (['feature', 'ActiveEffect'].includes(itemType)) { + if (itemType === 'subclass') { + if (item.system.linkedClass) { + return ui.notifications.warn( + game.i18n.format('DAGGERHEART.UI.Notifications.subclassAlreadyLinked', { + name: item.name, + class: this.document.name + }) + ); + } + await item.update({ 'system.linkedClass': this.document.uuid }); + await this.document.update({ + 'system.subclasses': [...this.document.system.subclasses.map(x => x.uuid), item.uuid] + }); + } else if (['feature', 'ActiveEffect'].includes(itemType)) { super._onDrop(event); } else if (this.document.parent?.type !== 'character') { if (itemType === 'weapon') { @@ -189,6 +200,12 @@ export default class ClassSheet extends DHBaseItemSheet { static async #removeItemFromCollection(_event, element) { const { uuid, target } = element.dataset; const prop = foundry.utils.getProperty(this.document.system, target); + + if (target === 'subclasses') { + const subclass = await foundry.utils.fromUuid(uuid); + await subclass?.update({ 'system.linkedClass': null }); + } + await this.document.update({ [`system.${target}`]: prop.filter(i => i && i.uuid !== uuid).map(x => x.uuid) }); } diff --git a/module/applications/sheets/items/subclass.mjs b/module/applications/sheets/items/subclass.mjs index e9d8370e..5c731777 100644 --- a/module/applications/sheets/items/subclass.mjs +++ b/module/applications/sheets/items/subclass.mjs @@ -40,36 +40,4 @@ export default class SubclassSheet extends DHBaseItemSheet { get relatedDocs() { return this.document.system.features.map(x => x.item); } - - async _prepareContext(options) { - const context = await super._prepareContext(options); - if (this.document.system.linkedClass) { - const classData = await fromUuid(this.document.system.linkedClass); - context.class = classData ?? { - name: _loc('DAGGERHEART.GENERAL.missingX', { x: _loc('TYPES.Item.class') }), - missing: true - }; - } - return context; - } - - async _onDrop(event) { - event.stopPropagation(); - const data = TextEditor.getDragEventData(event); - const item = await fromUuid(data.uuid); - const itemType = data.type === 'ActiveEffect' ? data.type : item.type; - if (itemType === 'class') { - const uuid = item._stats.compendiumSource ?? item.uuid; - if (this.document.system.linkedClass !== uuid) { - await this.document.update({ 'system.linkedClass': uuid }); - // Re-render all class sheets for instant feedback - for (const app of foundry.applications.instances.values()) { - if (app.document?.type === 'class') app.render(); - } - } - return; - } - - return super._onDrop(event); - } } diff --git a/module/applications/ui/itemBrowser.mjs b/module/applications/ui/itemBrowser.mjs index 99b9a23d..67a16f6a 100644 --- a/module/applications/ui/itemBrowser.mjs +++ b/module/applications/ui/itemBrowser.mjs @@ -277,7 +277,7 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { (await foundry.applications.ux.TextEditor.implementation.enrichHTML(item.description)); } - this.fieldFilter = await this._createFieldFilter(); + this.fieldFilter = this._createFieldFilter(); if (this.presets?.filter) { Object.entries(this.presets.filter).forEach(([k, v]) => { @@ -355,12 +355,12 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { ); } - async _createFieldFilter() { + _createFieldFilter() { const filters = ItemBrowser.getFolderConfig(this.selectedMenu.data, 'filters'); - for (const f of filters) { + filters.forEach(f => { if (typeof f.field === 'string') f.field = foundry.utils.getProperty(game, f.field); else if (typeof f.choices === 'function') { - f.choices = await f.choices(this.items); + f.choices = f.choices(this.items); } // Clear field label so template uses our custom label parameter @@ -370,8 +370,7 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { f.name ??= f.key; f.value = this.presets?.filter?.[f.name]?.value ?? null; - } - + }); return filters; } diff --git a/module/config/itemBrowserConfig.mjs b/module/config/itemBrowserConfig.mjs index 3e40c97b..04b387cb 100644 --- a/module/config/itemBrowserConfig.mjs +++ b/module/config/itemBrowserConfig.mjs @@ -383,8 +383,7 @@ export const typeConfig = { { key: 'system.linkedClass', label: 'TYPES.Item.class', - format: linkedClass => - foundry.utils.fromUuidSync(linkedClass)?.name ?? 'DAGGERHEART.UI.ItemBrowser.missing' + format: linkedClass => linkedClass?.name ?? 'DAGGERHEART.UI.ItemBrowser.missing' }, { key: 'system.spellcastingTrait', @@ -394,18 +393,15 @@ export const typeConfig = { ], filters: [ { - key: 'system.linkedClass', + key: 'system.linkedClass.uuid', label: 'TYPES.Item.class', - choices: async items => { - const list = []; - for (const item of items.filter(item => item.system.linkedClass)) { - const linkedClass = await foundry.utils.fromUuid(item.system.linkedClass); - list.push({ - value: linkedClass.uuid, - label: linkedClass.name - }); - } - + choices: items => { + const list = items + .filter(item => item.system.linkedClass) + .map(item => ({ + value: item.system.linkedClass.uuid, + label: item.system.linkedClass.name + })); return list.reduce((a, c) => { if (!a.find(i => i.value === c.value)) a.push(c); return a; diff --git a/module/data/item/base.mjs b/module/data/item/base.mjs index ba114fda..aebf33bf 100644 --- a/module/data/item/base.mjs +++ b/module/data/item/base.mjs @@ -200,7 +200,7 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel { const features = []; for (let f of this.features) { const fBase = f.item ?? f; - const feature = fBase.pack ? await foundry.utils.fromUuid(fBase.uuid) : fBase; + const feature = fBase.system ? fBase : await foundry.utils.fromUuid(fBase.uuid); features.push( foundry.utils.mergeObject( feature.toObject(), diff --git a/module/data/item/class.mjs b/module/data/item/class.mjs index 7014e011..d3738318 100644 --- a/module/data/item/class.mjs +++ b/module/data/item/class.mjs @@ -30,6 +30,7 @@ export default class DHClass extends BaseDataItem { }), evasion: new fields.NumberField({ initial: 0, integer: true, label: 'DAGGERHEART.GENERAL.evasion' }), features: new ItemLinkFields(), + subclasses: new ForeignDocumentUUIDArrayField({ type: 'Item', required: false }), inventory: new fields.SchemaField({ take: new ForeignDocumentUUIDArrayField({ type: 'Item', required: false }), choiceA: new ForeignDocumentUUIDArrayField({ type: 'Item', required: false }), @@ -69,24 +70,6 @@ export default class DHClass extends BaseDataItem { return this.features.filter(x => x.type === CONFIG.DH.ITEM.featureSubTypes.class).map(x => x.item); } - async fetchSubclasses() { - const uuids = [this.parent.uuid, this.parent._stats?.compendiumSource].filter(u => !!u); - const subclasses = game.items.filter(x => x.type === 'subclass' && uuids.includes(x.system.linkedClass)); - for (const pack of game.packs) { - const indexes = await pack.getIndex({ fields: ['system.linkedClass'] }); - for (const index of indexes) { - if (index.type !== 'subclass') continue; - if (!uuids.includes(index.system?.linkedClass)) continue; - if (subclasses.find(x => x.uuid === index.uuid)) continue; - - const subclass = await foundry.utils.fromUuid(index.uuid); - subclasses.push(subclass); - } - } - - return subclasses; - } - async _preCreate(data, options, user) { if (this.actor?.type === 'character') { const levelupAuto = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation).levelupAuto; diff --git a/module/data/item/subclass.mjs b/module/data/item/subclass.mjs index 12d85c1e..d421cc6d 100644 --- a/module/data/item/subclass.mjs +++ b/module/data/item/subclass.mjs @@ -28,7 +28,7 @@ export default class DHSubclass extends BaseDataItem { features: new ItemLinkFields(), featureState: new fields.NumberField({ required: true, initial: 1, min: 1 }), isMulticlass: new fields.BooleanField({ initial: false }), - linkedClass: new fields.DocumentUUIDField({ type: 'Item', nullable: true, initial: null }) + linkedClass: new ForeignDocumentUUIDField({ type: 'Item', nullable: true, initial: null }) }; } @@ -83,8 +83,7 @@ export default class DHSubclass extends BaseDataItem { ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.missingClass')); return false; } - - if ((await actorClass.system.fetchSubclasses()).every(x => x.uuid !== dataUuid)) { + if (actorClass.system.subclasses.every(x => x.uuid !== dataUuid)) { ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.subclassNotInClass')); return false; } diff --git a/module/helpers/utils.mjs b/module/helpers/utils.mjs index 90937db4..cec493b4 100644 --- a/module/helpers/utils.mjs +++ b/module/helpers/utils.mjs @@ -861,11 +861,3 @@ export function createShallowProxy(obj) { } }); } - -export function camelize(str) { - return str - .replace(/(?:^\w|[A-Z]|\b\w)/g, (part, index) => { - return index === 0 ? part.toLowerCase() : part.toUpperCase(); - }) - .replace(/\s+/g, ''); -} diff --git a/styles/less/global/feature-section.less b/styles/less/global/feature-section.less index 7d5099e1..13feb92c 100644 --- a/styles/less/global/feature-section.less +++ b/styles/less/global/feature-section.less @@ -19,36 +19,28 @@ &:last-child { margin-bottom: 0px; } - } - .feature-line { - display: grid; - align-items: center; - grid-template-columns: 1fr 4fr 1fr; - h4 { - font-weight: lighter; - color: light-dark(@dark, @beige); - } - .image { - height: 40px; - width: 40px; - object-fit: cover; - border-radius: 6px; - border: none; - } - .image-icon { - font-size: 26px; - width: 40px; - height: 40px; - display: flex; - justify-content: center; + .feature-line { + display: grid; align-items: center; - } - .controls { - display: flex; - justify-content: center; - gap: 10px; - a { - text-shadow: none; + grid-template-columns: 1fr 4fr 1fr; + h4 { + font-weight: lighter; + color: light-dark(@dark, @beige); + } + .image { + height: 40px; + width: 40px; + object-fit: cover; + border-radius: 6px; + border: none; + } + .controls { + display: flex; + justify-content: center; + gap: 10px; + a { + text-shadow: none; + } } } } diff --git a/styles/less/sheets/items/item-sheet-shared.less b/styles/less/sheets/items/item-sheet-shared.less index 5155ad70..d0a8cc48 100644 --- a/styles/less/sheets/items/item-sheet-shared.less +++ b/styles/less/sheets/items/item-sheet-shared.less @@ -10,8 +10,4 @@ font-family: @font-body; color: light-dark(@chat-blue-bg, @beige-50); } - - button.plain.inline-control { - flex: 0 0 auto; - } } diff --git a/templates/sheets/actors/adversary/header.hbs b/templates/sheets/actors/adversary/header.hbs index fba96980..5bdfa421 100644 --- a/templates/sheets/actors/adversary/header.hbs +++ b/templates/sheets/actors/adversary/header.hbs @@ -1,14 +1,7 @@
-

{{source.name}}

+

{{source.name}}

diff --git a/templates/sheets/actors/character/header.hbs b/templates/sheets/actors/character/header.hbs index 8010dfa5..1b1c4965 100644 --- a/templates/sheets/actors/character/header.hbs +++ b/templates/sheets/actors/character/header.hbs @@ -1,14 +1,7 @@
-

{{source.name}}

+

{{source.name}}

{{#if @root.editable}} diff --git a/templates/sheets/actors/companion/header.hbs b/templates/sheets/actors/companion/header.hbs index d10c0640..8b63e396 100644 --- a/templates/sheets/actors/companion/header.hbs +++ b/templates/sheets/actors/companion/header.hbs @@ -6,8 +6,6 @@ name='name' value='{{document.name}}' placeholder='{{localize "DAGGERHEART.GENERAL.actorName"}}' - autocomplete="off" - spellcheck="false" />

{{#if useResourcePips}} diff --git a/templates/sheets/actors/party/header.hbs b/templates/sheets/actors/party/header.hbs index c48902c8..3fdb137d 100644 --- a/templates/sheets/actors/party/header.hbs +++ b/templates/sheets/actors/party/header.hbs @@ -2,9 +2,7 @@
-

- -

+

\ No newline at end of file diff --git a/templates/sheets/items/class/features.hbs b/templates/sheets/items/class/features.hbs index 279ff52c..9d037b65 100644 --- a/templates/sheets/items/class/features.hbs +++ b/templates/sheets/items/class/features.hbs @@ -27,7 +27,10 @@
{{localize "TYPES.Item.subclass"}}
- {{#each subclasses as |subclass index|}} + {{#unless source.system.subclasses}} +
{{localize "DAGGERHEART.GENERAL.missingDragDropThing" thing=(localize "DAGGERHEART.GENERAL.subclasses")}}
+ {{/unless}} + {{#each source.system.subclasses as |subclass index|}}
  • @@ -41,7 +44,16 @@ data-item-uuid={{subclass.uuid}} data-tooltip='{{localize "DAGGERHEART.UI.Tooltip.openItemWorld"}}' > - + + + +
  • diff --git a/templates/sheets/items/class/header.hbs b/templates/sheets/items/class/header.hbs index 019825f8..6b60ada6 100644 --- a/templates/sheets/items/class/header.hbs +++ b/templates/sheets/items/class/header.hbs @@ -3,6 +3,7 @@

    +

    {{localize 'TYPES.Item.class'}}

    {{localize "DAGGERHEART.GENERAL.Domain.plural"}} diff --git a/templates/sheets/items/subclass/description.hbs b/templates/sheets/items/subclass/description.hbs index 0267eb9b..4591bd1a 100644 --- a/templates/sheets/items/subclass/description.hbs +++ b/templates/sheets/items/subclass/description.hbs @@ -1,10 +1,8 @@
    - {{#if spellcastTrait}} -
    -

    {{localize "DAGGERHEART.ITEMS.Subclass.spellcastTrait"}}

    - {{spellcastTrait}} -
    - {{/if}} +
    +

    {{localize "DAGGERHEART.ITEMS.Subclass.spellcastTrait"}}

    + {{spellcastTrait}} +

    {{localize "DAGGERHEART.ITEMS.Subclass.foundationFeatures"}}

    {{#each foundationFeatures as | feature |}} diff --git a/templates/sheets/items/subclass/features.hbs b/templates/sheets/items/subclass/features.hbs index c54e702e..1a75974e 100644 --- a/templates/sheets/items/subclass/features.hbs +++ b/templates/sheets/items/subclass/features.hbs @@ -3,35 +3,6 @@ data-tab='{{tabs.features.id}}' data-group='{{tabs.features.group}}' > -
    - {{localize "TYPES.Item.class"}} - {{#if class}} -
    -
  • - {{#if class.missing}} - - {{class.name}} - {{else}} - - {{class.name}} -
    - - - -
    - {{/if}} -
  • -
    - {{else}} -
    {{localize "DAGGERHEART.GENERAL.missingDragDropThing" thing=(localize "TYPES.Item.class")}}
    - {{/if}} -
    -
    {{localize "DAGGERHEART.GENERAL.Tabs.foundation"}}