From 86d451f0d722665a030da4b23734007f0b0a09ba Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Sat, 23 Aug 2025 01:55:18 +0200 Subject: [PATCH 01/10] . (#1060) --- module/documents/activeEffect.mjs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/module/documents/activeEffect.mjs b/module/documents/activeEffect.mjs index f46cc9db..b2896513 100644 --- a/module/documents/activeEffect.mjs +++ b/module/documents/activeEffect.mjs @@ -167,13 +167,11 @@ export default class DhActiveEffect extends foundry.documents.ActiveEffect { if (subclass) { const featureState = subclass.system.featureState; - const featureType = subclass - ? (subclass.system.features.find(x => x.item?.uuid === this.parent.uuid)?.type ?? null) - : null; if ( - (featureType === CONFIG.DH.ITEM.featureSubTypes.specialization && featureState < 2) || - (featureType === CONFIG.DH.ITEM.featureSubTypes.mastery && featureState < 3) + (this.parent.system.identifier === CONFIG.DH.ITEM.featureSubTypes.specialization && + featureState < 2) || + (this.parent.system.identifier === CONFIG.DH.ITEM.featureSubTypes.mastery && featureState < 3) ) { this.transfer = false; } From 7016f71da7b810eb34a7ef32a333ead69e9c7159 Mon Sep 17 00:00:00 2001 From: Dapoulp <74197441+Dapoulp@users.noreply.github.com> Date: Sat, 23 Aug 2025 02:05:16 +0200 Subject: [PATCH 02/10] Fix/spellcast modifier (#1061) * Temp ActionField attack type missing * Move missing attack type to getModel * Fix spellcast modifier bonus --- module/data/action/baseAction.mjs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/module/data/action/baseAction.mjs b/module/data/action/baseAction.mjs index 5d3f7721..2f5935da 100644 --- a/module/data/action/baseAction.mjs +++ b/module/data/action/baseAction.mjs @@ -172,7 +172,7 @@ export default class DHBaseAction extends ActionMixin(foundry.abstract.DataModel dialog: { configure: hasRoll }, - type: this.type, + type: this.roll?.type ?? this.type, hasRoll: hasRoll, hasDamage: this.damage?.parts?.length && this.type !== 'healing', hasHealing: this.damage?.parts?.length && this.type === 'healing', From b83adbf09ba0b427d1c0db739c57e102f800bf30 Mon Sep 17 00:00:00 2001 From: Chris Ryan <73275196+chrisryan10@users.noreply.github.com> Date: Sat, 23 Aug 2025 18:32:17 +1000 Subject: [PATCH 03/10] Fixed the Cult Initiate Group Attack to use Fear instead of marking Stress (#1062) Co-authored-by: Chris Ryan --- .../adversaries/adversary_Cult_Initiate_zx99sOGTXicP4SSD.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/packs/adversaries/adversary_Cult_Initiate_zx99sOGTXicP4SSD.json b/src/packs/adversaries/adversary_Cult_Initiate_zx99sOGTXicP4SSD.json index fe8d090f..b46dc3a0 100644 --- a/src/packs/adversaries/adversary_Cult_Initiate_zx99sOGTXicP4SSD.json +++ b/src/packs/adversaries/adversary_Cult_Initiate_zx99sOGTXicP4SSD.json @@ -265,7 +265,7 @@ "cost": [ { "scalable": false, - "key": "stress", + "key": "fear", "value": 1, "keyIsID": false, "step": null @@ -281,7 +281,7 @@ "type": "self", "amount": null }, - "name": "Mark Stress", + "name": "Spend Fear", "img": "icons/creatures/abilities/tail-strike-bone-orange.webp", "range": "" } From 2d20fb0df447ba50fbe8b545f6f0a6c736489407 Mon Sep 17 00:00:00 2001 From: WBHarry Date: Sat, 23 Aug 2025 13:18:14 +0200 Subject: [PATCH 04/10] Fixed multiclass --- module/data/actor/character.mjs | 5 +++-- module/data/item/base.mjs | 4 ++-- module/data/item/class.mjs | 9 --------- module/data/item/feature.mjs | 1 + module/documents/actor.mjs | 4 ++-- 5 files changed, 8 insertions(+), 15 deletions(-) diff --git a/module/data/actor/character.mjs b/module/data/actor/character.mjs index 7dd7993c..7ddd878c 100644 --- a/module/data/actor/character.mjs +++ b/module/data/actor/character.mjs @@ -317,7 +317,7 @@ export default class DhCharacter extends BaseDataActor { } get multiclass() { - const value = this.parent.items.find(x => x.type === 'Class' && x.system.isMulticlass); + const value = this.parent.items.find(x => x.type === 'class' && x.system.isMulticlass); const subclass = this.parent.items.find(x => x.type === 'subclass' && x.system.isMulticlass); return { @@ -443,7 +443,8 @@ export default class DhCharacter extends BaseDataActor { classFeatures.push(item); } else if (item.system.originItemType === CONFIG.DH.ITEM.featureTypes.subclass.id) { if (this.class.subclass) { - const subclassState = this.class.subclass.system.featureState; + const prop = item.system.multiclassOrigin ? 'multiclass' : 'class'; + const subclassState = this[prop].subclass.system.featureState; if ( item.system.identifier === CONFIG.DH.ITEM.featureSubTypes.foundation || diff --git a/module/data/item/base.mjs b/module/data/item/base.mjs index f333537b..f8eae265 100644 --- a/module/data/item/base.mjs +++ b/module/data/item/base.mjs @@ -148,7 +148,6 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel { for (let f of this.features) { const fBase = f.item ?? f; const feature = fBase.system ? fBase : await foundry.utils.fromUuid(fBase.uuid); - const multiclass = this.isMulticlass ? 'multiclass' : null; features.push( foundry.utils.mergeObject( feature.toObject(), @@ -156,7 +155,8 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel { _stats: { compendiumSource: fBase.uuid }, system: { originItemType: this.parent.type, - identifier: multiclass ?? (f.item ? f.type : null) + identifier: f.item ? f.type : null, + multiclassOrigin: this.isMulticlass } }, { inplace: false } diff --git a/module/data/item/class.mjs b/module/data/item/class.mjs index 5e92d2fc..157f70c5 100644 --- a/module/data/item/class.mjs +++ b/module/data/item/class.mjs @@ -102,15 +102,6 @@ export default class DHClass extends BaseDataItem { if (allowed === false) return; } - _onDelete(options, userId) { - super._onDelete(options, userId); - - if (options.parent?.type === 'character') { - const path = `system.${this.isMulticlass ? 'multiclass' : 'class'}`; - foundry.utils.getProperty(options.parent, `${path}.subclass`)?.delete(); - } - } - async _preUpdate(changed, options, userId) { const allowed = await super._preUpdate(changed, options, userId); if (allowed === false) return false; diff --git a/module/data/item/feature.mjs b/module/data/item/feature.mjs index 6e1aab41..3b8fe064 100644 --- a/module/data/item/feature.mjs +++ b/module/data/item/feature.mjs @@ -29,6 +29,7 @@ export default class DHFeature extends BaseDataItem { nullable: true, initial: null }), + multiclassOrigin: new fields.BooleanField({ initial: false }), identifier: new fields.StringField() }; } diff --git a/module/documents/actor.mjs b/module/documents/actor.mjs index e1dd93af..3325547c 100644 --- a/module/documents/actor.mjs +++ b/module/documents/actor.mjs @@ -164,10 +164,10 @@ export default class DhpActor extends Actor { if (multiclass) { const multiclassItem = this.items.find(x => x.uuid === multiclass.itemUuid); const multiclassFeatures = this.items.filter( - x => x.system.originItemType === 'class' && x.system.identifier === 'multiclass' + x => x.system.originItemType === 'class' && x.system.multiclassOrigin ); const subclassFeatures = this.items.filter( - x => x.system.originItemType === 'subclass' && x.system.identifier === 'multiclass' + x => x.system.originItemType === 'subclass' && x.system.multiclassOrigin ); this.deleteEmbeddedDocuments( From f76515eac1dddc2fca6c5f34ad574ed174089bb4 Mon Sep 17 00:00:00 2001 From: WBHarry Date: Sat, 23 Aug 2025 13:20:02 +0200 Subject: [PATCH 05/10] Revert "Fixed multiclass" This reverts commit 2d20fb0df447ba50fbe8b545f6f0a6c736489407. --- module/data/actor/character.mjs | 5 ++--- module/data/item/base.mjs | 4 ++-- module/data/item/class.mjs | 9 +++++++++ module/data/item/feature.mjs | 1 - module/documents/actor.mjs | 4 ++-- 5 files changed, 15 insertions(+), 8 deletions(-) diff --git a/module/data/actor/character.mjs b/module/data/actor/character.mjs index 7ddd878c..7dd7993c 100644 --- a/module/data/actor/character.mjs +++ b/module/data/actor/character.mjs @@ -317,7 +317,7 @@ export default class DhCharacter extends BaseDataActor { } get multiclass() { - const value = this.parent.items.find(x => x.type === 'class' && x.system.isMulticlass); + const value = this.parent.items.find(x => x.type === 'Class' && x.system.isMulticlass); const subclass = this.parent.items.find(x => x.type === 'subclass' && x.system.isMulticlass); return { @@ -443,8 +443,7 @@ export default class DhCharacter extends BaseDataActor { classFeatures.push(item); } else if (item.system.originItemType === CONFIG.DH.ITEM.featureTypes.subclass.id) { if (this.class.subclass) { - const prop = item.system.multiclassOrigin ? 'multiclass' : 'class'; - const subclassState = this[prop].subclass.system.featureState; + const subclassState = this.class.subclass.system.featureState; if ( item.system.identifier === CONFIG.DH.ITEM.featureSubTypes.foundation || diff --git a/module/data/item/base.mjs b/module/data/item/base.mjs index f8eae265..f333537b 100644 --- a/module/data/item/base.mjs +++ b/module/data/item/base.mjs @@ -148,6 +148,7 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel { for (let f of this.features) { const fBase = f.item ?? f; const feature = fBase.system ? fBase : await foundry.utils.fromUuid(fBase.uuid); + const multiclass = this.isMulticlass ? 'multiclass' : null; features.push( foundry.utils.mergeObject( feature.toObject(), @@ -155,8 +156,7 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel { _stats: { compendiumSource: fBase.uuid }, system: { originItemType: this.parent.type, - identifier: f.item ? f.type : null, - multiclassOrigin: this.isMulticlass + identifier: multiclass ?? (f.item ? f.type : null) } }, { inplace: false } diff --git a/module/data/item/class.mjs b/module/data/item/class.mjs index 157f70c5..5e92d2fc 100644 --- a/module/data/item/class.mjs +++ b/module/data/item/class.mjs @@ -102,6 +102,15 @@ export default class DHClass extends BaseDataItem { if (allowed === false) return; } + _onDelete(options, userId) { + super._onDelete(options, userId); + + if (options.parent?.type === 'character') { + const path = `system.${this.isMulticlass ? 'multiclass' : 'class'}`; + foundry.utils.getProperty(options.parent, `${path}.subclass`)?.delete(); + } + } + async _preUpdate(changed, options, userId) { const allowed = await super._preUpdate(changed, options, userId); if (allowed === false) return false; diff --git a/module/data/item/feature.mjs b/module/data/item/feature.mjs index 3b8fe064..6e1aab41 100644 --- a/module/data/item/feature.mjs +++ b/module/data/item/feature.mjs @@ -29,7 +29,6 @@ export default class DHFeature extends BaseDataItem { nullable: true, initial: null }), - multiclassOrigin: new fields.BooleanField({ initial: false }), identifier: new fields.StringField() }; } diff --git a/module/documents/actor.mjs b/module/documents/actor.mjs index 3325547c..e1dd93af 100644 --- a/module/documents/actor.mjs +++ b/module/documents/actor.mjs @@ -164,10 +164,10 @@ export default class DhpActor extends Actor { if (multiclass) { const multiclassItem = this.items.find(x => x.uuid === multiclass.itemUuid); const multiclassFeatures = this.items.filter( - x => x.system.originItemType === 'class' && x.system.multiclassOrigin + x => x.system.originItemType === 'class' && x.system.identifier === 'multiclass' ); const subclassFeatures = this.items.filter( - x => x.system.originItemType === 'subclass' && x.system.multiclassOrigin + x => x.system.originItemType === 'subclass' && x.system.identifier === 'multiclass' ); this.deleteEmbeddedDocuments( From 936c96a1bed04e9de4254bcd317fc6d8403cbbc3 Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Sat, 23 Aug 2025 13:49:10 +0200 Subject: [PATCH 06/10] Fixed so enriched buttons are inline by default. Can be set to 'inline:true' to make them fit with the text better (#1068) --- module/enrichers/DamageEnricher.mjs | 12 ++++++++---- module/enrichers/DualityRollEnricher.mjs | 2 +- module/enrichers/TemplateEnricher.mjs | 8 ++++++-- styles/less/global/enrichment.less | 14 ++++++++++++++ styles/less/global/index.less | 1 + 5 files changed, 30 insertions(+), 7 deletions(-) create mode 100644 styles/less/global/enrichment.less diff --git a/module/enrichers/DamageEnricher.mjs b/module/enrichers/DamageEnricher.mjs index 918edc39..a859be9f 100644 --- a/module/enrichers/DamageEnricher.mjs +++ b/module/enrichers/DamageEnricher.mjs @@ -2,7 +2,8 @@ export default function DhDamageEnricher(match, _options) { const parts = match[1].split('|').map(x => x.trim()); let value = null, - type = null; + type = null, + inline = false; parts.forEach(part => { const split = part.split(':').map(x => x.toLowerCase().trim()); @@ -14,16 +15,19 @@ export default function DhDamageEnricher(match, _options) { case 'type': type = split[1]; break; + case 'inline': + inline = true; + break; } } }); if (!value || !value) return match[0]; - return getDamageMessage(value, type, match[0]); + return getDamageMessage(value, type, inline, match[0]); } -function getDamageMessage(damage, type, defaultElement) { +function getDamageMessage(damage, type, inline, defaultElement) { const typeIcons = type .replace('[', '') .replace(']', '') @@ -40,7 +44,7 @@ function getDamageMessage(damage, type, defaultElement) { const dualityElement = document.createElement('span'); dualityElement.innerHTML = ` - `; diff --git a/styles/less/global/enrichment.less b/styles/less/global/enrichment.less new file mode 100644 index 00000000..2ad3975a --- /dev/null +++ b/styles/less/global/enrichment.less @@ -0,0 +1,14 @@ +.measured-template-button, +.enriched-damage-button, +.duality-roll-button { + display: inline; + + &.inline { + min-height: unset; + height: 18px; + } + + i { + font-size: 12px; + } +} diff --git a/styles/less/global/index.less b/styles/less/global/index.less index d6c8459e..5f955ce3 100644 --- a/styles/less/global/index.less +++ b/styles/less/global/index.less @@ -2,6 +2,7 @@ @import './dialog.less'; @import './chat.less'; @import './elements.less'; +@import './enrichment.less'; @import './tab-navigation.less'; @import './tab-form-footer.less'; @import './tab-actions.less'; From 0c3ebd6e11ed9ec57c5bbf4a04929609be055ee4 Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Sat, 23 Aug 2025 13:55:31 +0200 Subject: [PATCH 07/10] Fixed description on Dracon and Orderborne (#1067) --- .../feature_Elemental_Breath_sRaE3CgkgjBF1UpV.json | 10 +++++----- .../feature_Dedicated_7aXWdH3gzaYREK0X.json | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/packs/ancestries/feature_Elemental_Breath_sRaE3CgkgjBF1UpV.json b/src/packs/ancestries/feature_Elemental_Breath_sRaE3CgkgjBF1UpV.json index ccd0f87e..9764c5b4 100644 --- a/src/packs/ancestries/feature_Elemental_Breath_sRaE3CgkgjBF1UpV.json +++ b/src/packs/ancestries/feature_Elemental_Breath_sRaE3CgkgjBF1UpV.json @@ -12,7 +12,7 @@ "type": "attack", "_id": "a6WROv0OKx0lbYVa", "systemPath": "actions", - "description": "", + "description": "

Choose an element for your breath (such as electricity, fire, or ice). You can use this breath against a target or group of targets within Very Close range, treating it as an Instinct weapon that deals d8 magic damage using your Proficiency.

", "chatDisplay": true, "actionType": "action", "cost": [], @@ -95,12 +95,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.1.0", "createdTime": 1753994055921, - "modifiedTime": 1753994120065, - "lastModifiedBy": "MQSznptE5yLT7kj8" + "modifiedTime": 1755938895948, + "lastModifiedBy": "tt3PwMBXcTLCtIQU" }, "_key": "!items!sRaE3CgkgjBF1UpV" } diff --git a/src/packs/communities/feature_Dedicated_7aXWdH3gzaYREK0X.json b/src/packs/communities/feature_Dedicated_7aXWdH3gzaYREK0X.json index c93811a9..11ac8208 100644 --- a/src/packs/communities/feature_Dedicated_7aXWdH3gzaYREK0X.json +++ b/src/packs/communities/feature_Dedicated_7aXWdH3gzaYREK0X.json @@ -12,7 +12,7 @@ "type": "effect", "_id": "ZBVqSlsDUKf8uGrI", "systemPath": "actions", - "description": "", + "description": "

Record three sayings or values your upbringing instilled in you. Once per rest, when you describe how you’re embodying one of these principles through your current action, you can roll a d20 as your Hope Die

", "chatDisplay": true, "actionType": "action", "cost": [], @@ -41,12 +41,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.1.0", "createdTime": 1754010247432, - "modifiedTime": 1754010247432, - "lastModifiedBy": "Q9NoTaEarn3VMS6Z" + "modifiedTime": 1755938935013, + "lastModifiedBy": "tt3PwMBXcTLCtIQU" }, "sort": 0, "ownership": { From 0b2694b007711444192f583bc0daf211f1a44e6b Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Sat, 23 Aug 2025 23:50:10 +0200 Subject: [PATCH 08/10] Improved feature request label (#1072) --- .../ISSUE_TEMPLATE/{feature_report.md => feature_request.md} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename .github/ISSUE_TEMPLATE/{feature_report.md => feature_request.md} (76%) diff --git a/.github/ISSUE_TEMPLATE/feature_report.md b/.github/ISSUE_TEMPLATE/feature_request.md similarity index 76% rename from .github/ISSUE_TEMPLATE/feature_report.md rename to .github/ISSUE_TEMPLATE/feature_request.md index df00ba37..35710e2b 100644 --- a/.github/ISSUE_TEMPLATE/feature_report.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -1,6 +1,6 @@ --- -name: Feature report -about: Create a feature report for suggestions on improving the system +name: Feature request +about: Create a feature request for suggestions on improving the system title: "[Feature] " labels: enhancement, discussion, maybe type: feature From 46ea4addd0710708e7d27b82dbb817a49e8db0a6 Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Sun, 24 Aug 2025 02:13:15 +0200 Subject: [PATCH 09/10] [Fix] Subclass Links (#1069) * Attempt at making subclass aware of its class * Update compendium classes/subclasses * Fixed multiclass * Update compenidum browser subclass class filter * Added migration for subclass.linkedClass * Using foundry's isNewer function rather than custom one * Added migration for existing actor features --------- Co-authored-by: Dapoolp --- lang/en.json | 3 +- .../characterCreation/characterCreation.mjs | 7 +- module/applications/sheets/items/class.mjs | 15 + module/applications/ui/itemBrowser.mjs | 9 +- module/config/itemBrowserConfig.mjs | 484 +++++++++--------- module/data/actor/character.mjs | 6 +- module/data/item/base.mjs | 4 +- module/data/item/feature.mjs | 1 + module/data/item/subclass.mjs | 4 +- module/documents/actor.mjs | 8 +- module/helpers/utils.mjs | 11 - module/systemRegistration/migrations.mjs | 44 +- .../classes/class_Bard_vegl3bFOq3pcFTWT.json | 8 +- .../classes/class_Druid_ZNwUTCyGCEcidZFv.json | 8 +- .../class_Guardian_nRAyoC0fOzXPDa4z.json | 8 +- .../class_Ranger_BTyfve69LKqoOi9S.json | 8 +- .../classes/class_Rogue_CvHlkHZfpMiCz5uT.json | 8 +- .../class_Seraph_5ZnlJ5bEoyOTkUJv.json | 8 +- .../class_Sorcerer_DchOzHcWIJE9FKcR.json | 8 +- .../class_Warrior_xCUWwJz4WSthvLfy.json | 8 +- .../class_Wizard_5LwX4m8ziY3F1ZGC.json | 8 +- .../subclass_Beastbound_TIUsIlTS1WkK5vr2.json | 11 +- ...ss_Call_Of_The_Brave_NAFU9roaVG7f3RNJ.json | 11 +- ...s_Call_Of_The_Slayer_bcNe5qP3o6CKadhK.json | 11 +- ...class_Divine_Wielder_M5mpGoAj8LRkylrY.json | 11 +- ...ass_Elemental_Origin_wg1H0hROc2acHwZh.json | 11 +- ...subclass_Nightwalker_h161OSIK24Up4qNd.json | 11 +- ...bclass_Primal_Origin_GLpRVxnY5E82khxH.json | 11 +- ..._School_Of_Knowledge_qqQlgCqhOivUFoQn.json | 11 +- ...bclass_School_Of_War_4y9Ph7RsCIAbkwTk.json | 11 +- .../subclass_Stalwart_rKRxFBlkbh9cDK8K.json | 11 +- .../subclass_Syndicate_95QxNZwgyEm1LqdG.json | 11 +- .../subclass_Troubadour_ld8MIvk0xVJydSBz.json | 11 +- .../subclass_Vengeance_SUo8NPBPO8aN193u.json | 11 +- ...ss_Warden_of_Renewal_xp0XMjYT85Q7E90o.json | 11 +- ...rden_of_the_Elements_W9hs5kxOWeY7eA4Q.json | 11 +- .../subclass_Wayfinder_zsUglcU4NgZ8tNgZ.json | 11 +- ...lass_Winged_Sentinel_y7ERWRIpJsdP9Re4.json | 11 +- .../subclass_Wordsmith_XTSODVM8st75Os8M.json | 11 +- styles/less/ui/item-browser/item-browser.less | 2 + system.json | 2 +- 41 files changed, 479 insertions(+), 391 deletions(-) diff --git a/lang/en.json b/lang/en.json index 6a34037d..f310a01d 100755 --- a/lang/en.json +++ b/lang/en.json @@ -2371,7 +2371,8 @@ "insufficientResources": "You have insufficient resources", "multiclassAlreadyPresent": "You already have a class and multiclass", "subclassesAlreadyPresent": "You already have a class and multiclass subclass", - "noDiceSystem": "Your selected dice {system} does not have a {faces} dice" + "noDiceSystem": "Your selected dice {system} does not have a {faces} dice", + "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." }, "Tooltip": { "disableEffect": "Disable Effect", diff --git a/module/applications/characterCreation/characterCreation.mjs b/module/applications/characterCreation/characterCreation.mjs index f9f832e8..ccb6f7c0 100644 --- a/module/applications/characterCreation/characterCreation.mjs +++ b/module/applications/characterCreation/characterCreation.mjs @@ -432,12 +432,17 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl } }; - if (type == 'domains') + if (type === 'domains') presets.filter = { 'level.max': { key: 'level.max', value: 1 }, 'system.domain': { key: 'system.domain', value: this.setup.class?.system.domains ?? null } }; + if (type === 'subclasses') + presets.filter = { + 'system.linkedClass.uuid': { key: 'system.linkedClass.uuid', value: this.setup.class?.uuid } + }; + if (equipment.includes(type)) presets.filter = { 'system.tier': { key: 'system.tier', value: 1 }, diff --git a/module/applications/sheets/items/class.mjs b/module/applications/sheets/items/class.mjs index 01f4249a..033c63e6 100644 --- a/module/applications/sheets/items/class.mjs +++ b/module/applications/sheets/items/class.mjs @@ -119,6 +119,15 @@ export default class ClassSheet extends DHBaseItemSheet { const itemType = data.data ? data.type : item.type; const target = event.target.closest('fieldset.drop-section'); 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] }); @@ -181,6 +190,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.uuid !== uuid).map(x => x.uuid) }); } diff --git a/module/applications/ui/itemBrowser.mjs b/module/applications/ui/itemBrowser.mjs index f0ad98db..9b9bef91 100644 --- a/module/applications/ui/itemBrowser.mjs +++ b/module/applications/ui/itemBrowser.mjs @@ -235,7 +235,7 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { filters.forEach(f => { if (typeof f.field === 'string') f.field = foundry.utils.getProperty(game, f.field); else if (typeof f.choices === 'function') { - f.choices = f.choices(); + f.choices = f.choices(this.items); } f.name ??= f.key; f.value = this.presets?.filter?.[f.name]?.value ?? null; @@ -248,11 +248,8 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { /* -------------------------------------------- */ /** - * Create and initialize search filter instances for the inventory and loadout sections. + * Create and initialize search filter instance. * - * Sets up two {@link foundry.applications.ux.SearchFilter} instances: - * - One for the inventory, which filters items in the inventory grid. - * - One for the loadout, which filters items in the loadout/card grid. * @private */ _createSearchFilter() { @@ -339,7 +336,7 @@ export class ItemBrowser extends HandlebarsApplicationMixin(ApplicationV2) { item = this.items.find(i => i.uuid === itemUUID); if (!item) continue; - + const matchesMenu = this.fieldFilter.length === 0 || this.fieldFilter.every( diff --git a/module/config/itemBrowserConfig.mjs b/module/config/itemBrowserConfig.mjs index 6e3c0dea..e40c989b 100644 --- a/module/config/itemBrowserConfig.mjs +++ b/module/config/itemBrowserConfig.mjs @@ -2,404 +2,422 @@ export const typeConfig = { adversaries: { columns: [ { - key: "system.tier", - label: "Tier" + key: 'system.tier', + label: 'Tier' }, { - key: "system.type", - label: "Type" + key: 'system.type', + label: 'Type' } ], filters: [ { - key: "system.tier", - label: "Tier", + key: 'system.tier', + label: 'Tier', field: 'system.api.models.actors.DhAdversary.schema.fields.tier' }, { - key: "system.type", - label: "Type", + key: 'system.type', + label: 'Type', field: 'system.api.models.actors.DhAdversary.schema.fields.type' }, { - key: "system.difficulty", - name: "difficulty.min", - label: "Difficulty (Min)", + key: 'system.difficulty', + name: 'difficulty.min', + label: 'Difficulty (Min)', field: 'system.api.models.actors.DhAdversary.schema.fields.difficulty', - operator: "gte" + operator: 'gte' }, { - key: "system.difficulty", - name: "difficulty.max", - label: "Difficulty (Max)", + key: 'system.difficulty', + name: 'difficulty.max', + label: 'Difficulty (Max)', field: 'system.api.models.actors.DhAdversary.schema.fields.difficulty', - operator: "lte" + operator: 'lte' }, { - key: "system.resources.hitPoints.max", - name: "hp.min", - label: "Hit Points (Min)", + key: 'system.resources.hitPoints.max', + name: 'hp.min', + label: 'Hit Points (Min)', field: 'system.api.models.actors.DhAdversary.schema.fields.resources.fields.hitPoints.fields.max', - operator: "gte" + operator: 'gte' }, { - key: "system.resources.hitPoints.max", - name: "hp.max", - label: "Hit Points (Max)", + key: 'system.resources.hitPoints.max', + name: 'hp.max', + label: 'Hit Points (Max)', field: 'system.api.models.actors.DhAdversary.schema.fields.resources.fields.hitPoints.fields.max', - operator: "lte" + operator: 'lte' }, { - key: "system.resources.stress.max", - name: "stress.min", - label: "Stress (Min)", + key: 'system.resources.stress.max', + name: 'stress.min', + label: 'Stress (Min)', field: 'system.api.models.actors.DhAdversary.schema.fields.resources.fields.stress.fields.max', - operator: "gte" + operator: 'gte' }, { - key: "system.resources.stress.max", - name: "stress.max", - label: "Stress (Max)", + key: 'system.resources.stress.max', + name: 'stress.max', + label: 'Stress (Max)', field: 'system.api.models.actors.DhAdversary.schema.fields.resources.fields.stress.fields.max', - operator: "lte" - }, + operator: 'lte' + } ] }, items: { columns: [ { - key: "type", - label: "Type" + key: 'type', + label: 'Type' }, { - key: "system.secondary", - label: "Subtype", - format: (isSecondary) => isSecondary ? "secondary" : (isSecondary === false ? "primary" : '-') + key: 'system.secondary', + label: 'Subtype', + format: isSecondary => (isSecondary ? 'secondary' : isSecondary === false ? 'primary' : '-') }, { - key: "system.tier", - label: "Tier" + key: 'system.tier', + label: 'Tier' } ], filters: [ { - key: "type", - label: "Type", - choices: () => CONFIG.Item.documentClass.TYPES.filter(t => ["armor", "weapon", "consumable", "loot"].includes(t)).map(t => ({ value: t, label: t })) + key: 'type', + label: 'Type', + choices: () => + CONFIG.Item.documentClass.TYPES.filter(t => + ['armor', 'weapon', 'consumable', 'loot'].includes(t) + ).map(t => ({ value: t, label: t })) }, { - key: "system.secondary", - label: "Subtype", + key: 'system.secondary', + label: 'Subtype', choices: [ - { value: false, label: "Primary Weapon"}, - { value: true, label: "Secondary Weapon"} + { value: false, label: 'Primary Weapon' }, + { value: true, label: 'Secondary Weapon' } ] }, { - key: "system.tier", - label: "Tier", - choices: [{ value: "1", label: "1"}, { value: "2", label: "2"}, { value: "3", label: "3"}, { value: "4", label: "4"}] + key: 'system.tier', + label: 'Tier', + choices: [ + { value: '1', label: '1' }, + { value: '2', label: '2' }, + { value: '3', label: '3' }, + { value: '4', label: '4' } + ] }, { - key: "system.burden", - label: "Burden", + key: 'system.burden', + label: 'Burden', field: 'system.api.models.items.DHWeapon.schema.fields.burden' }, { - key: "system.attack.roll.trait", - label: "Trait", + key: 'system.attack.roll.trait', + label: 'Trait', field: 'system.api.models.actions.actionsTypes.attack.schema.fields.roll.fields.trait' }, { - key: "system.attack.range", - label: "Range", + key: 'system.attack.range', + label: 'Range', field: 'system.api.models.actions.actionsTypes.attack.schema.fields.range' }, { - key: "system.baseScore", - name: "armor.min", - label: "Armor Score (Min)", + key: 'system.baseScore', + name: 'armor.min', + label: 'Armor Score (Min)', field: 'system.api.models.items.DHArmor.schema.fields.baseScore', - operator: "gte" + operator: 'gte' }, { - key: "system.baseScore", - name: "armor.max", - label: "Armor Score (Max)", + key: 'system.baseScore', + name: 'armor.max', + label: 'Armor Score (Max)', field: 'system.api.models.items.DHArmor.schema.fields.baseScore', - operator: "lte" + operator: 'lte' }, { - key: "system.itemFeatures", - label: "Features", - choices: () => [...Object.entries(CONFIG.DH.ITEM.weaponFeatures), ...Object.entries(CONFIG.DH.ITEM.armorFeatures)].map(([k,v]) => ({ value: k, label: v.label})), - operator: "contains3" + key: 'system.itemFeatures', + label: 'Features', + choices: () => + [ + ...Object.entries(CONFIG.DH.ITEM.weaponFeatures), + ...Object.entries(CONFIG.DH.ITEM.armorFeatures) + ].map(([k, v]) => ({ value: k, label: v.label })), + operator: 'contains3' } ] }, features: { - columns: [ - - ], - filters: [ - - ] + columns: [], + filters: [] }, cards: { columns: [ { - key: "system.type", - label: "Type" + key: 'system.type', + label: 'Type' }, { - key: "system.domain", - label: "Domain" + key: 'system.domain', + label: 'Domain' }, { - key: "system.level", - label: "Level" + key: 'system.level', + label: 'Level' } ], filters: [ { - key: "system.type", - label: "Type", + key: 'system.type', + label: 'Type', field: 'system.api.models.items.DHDomainCard.schema.fields.type' }, { - key: "system.domain", - label: "Domain", + key: 'system.domain', + label: 'Domain', field: 'system.api.models.items.DHDomainCard.schema.fields.domain', - operator: "contains2" + operator: 'contains2' }, { - key: "system.level", - name: "level.min", - label: "Level (Min)", + key: 'system.level', + name: 'level.min', + label: 'Level (Min)', field: 'system.api.models.items.DHDomainCard.schema.fields.level', - operator: "gte" + operator: 'gte' }, { - key: "system.level", - name: "level.max", - label: "Level (Max)", + key: 'system.level', + name: 'level.max', + label: 'Level (Max)', field: 'system.api.models.items.DHDomainCard.schema.fields.level', - operator: "lte" + operator: 'lte' }, { - key: "system.recallCost", - name: "recall.min", - label: "Recall Cost (Min)", + key: 'system.recallCost', + name: 'recall.min', + label: 'Recall Cost (Min)', field: 'system.api.models.items.DHDomainCard.schema.fields.recallCost', - operator: "gte" + operator: 'gte' }, { - key: "system.recallCost", - name: "recall.max", - label: "Recall Cost (Max)", + key: 'system.recallCost', + name: 'recall.max', + label: 'Recall Cost (Max)', field: 'system.api.models.items.DHDomainCard.schema.fields.recallCost', - operator: "lte" + operator: 'lte' } ] }, classes: { columns: [ { - key: "system.evasion", - label: "Evasion" + key: 'system.evasion', + label: 'Evasion' }, { - key: "system.hitPoints", - label: "Hit Points" + key: 'system.hitPoints', + label: 'Hit Points' }, { - key: "system.domains", - label: "Domains" + key: 'system.domains', + label: 'Domains' } ], filters: [ { - key: "system.evasion", - name: "evasion.min", - label: "Evasion (Min)", + key: 'system.evasion', + name: 'evasion.min', + label: 'Evasion (Min)', field: 'system.api.models.items.DHClass.schema.fields.evasion', - operator: "gte" + operator: 'gte' }, { - key: "system.evasion", - name: "evasion.max", - label: "Evasion (Max)", + key: 'system.evasion', + name: 'evasion.max', + label: 'Evasion (Max)', field: 'system.api.models.items.DHClass.schema.fields.evasion', - operator: "lte" + operator: 'lte' }, { - key: "system.hitPoints", - name: "hp.min", - label: "Hit Points (Min)", + key: 'system.hitPoints', + name: 'hp.min', + label: 'Hit Points (Min)', field: 'system.api.models.items.DHClass.schema.fields.hitPoints', - operator: "gte" + operator: 'gte' }, { - key: "system.hitPoints", - name: "hp.max", - label: "Hit Points (Max)", + key: 'system.hitPoints', + name: 'hp.max', + label: 'Hit Points (Max)', field: 'system.api.models.items.DHClass.schema.fields.hitPoints', - operator: "lte" + operator: 'lte' }, { - key: "system.domains", - label: "Domains", - choices: () => Object.values(CONFIG.DH.DOMAIN.domains).map(d => ({ value: d.id, label: d.label})), - operator: "contains2" + key: 'system.domains', + label: 'Domains', + choices: () => Object.values(CONFIG.DH.DOMAIN.domains).map(d => ({ value: d.id, label: d.label })), + operator: 'contains2' } ] }, subclasses: { columns: [ { - key: "id", - label: "Class", - format: (id) => { - return ""; - } + key: 'system.linkedClass', + label: 'Class', + format: linkedClass => linkedClass.name }, { - key: "system.spellcastingTrait", - label: "Spellcasting Trait" - } - ], - filters: [] - }, - beastforms: { - columns: [ - { - key: "system.tier", - label: "Tier" - }, - { - key: "system.mainTrait", - label: "Main Trait" + key: 'system.spellcastingTrait', + label: 'Spellcasting Trait' } ], filters: [ { - key: "system.tier", - label: "Tier", + key: 'system.linkedClass.uuid', + label: 'Class', + choices: (items) => { + const list = items.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; + }, []); + } + } + ] + }, + beastforms: { + columns: [ + { + key: 'system.tier', + label: 'Tier' + }, + { + key: 'system.mainTrait', + label: 'Main Trait' + } + ], + filters: [ + { + key: 'system.tier', + label: 'Tier', field: 'system.api.models.items.DHBeastform.schema.fields.tier' }, { - key: "system.mainTrait", - label: "Main Trait", + key: 'system.mainTrait', + label: 'Main Trait', field: 'system.api.models.items.DHBeastform.schema.fields.mainTrait' } ] } -} +}; export const compendiumConfig = { - "daggerheart": { - id: "daggerheart", - label: "DAGGERHEART", + daggerheart: { + id: 'daggerheart', + label: 'DAGGERHEART', folders: { - "adversaries": { - id: "adversaries", - keys: ["adversaries"], - label: "Adversaries", - type: ["adversary"], - listType: "adversaries" + adversaries: { + id: 'adversaries', + keys: ['adversaries'], + label: 'Adversaries', + type: ['adversary'], + listType: 'adversaries' }, - "ancestries": { - id: "ancestries", - keys: ["ancestries"], - label: "Ancestries", - type: ["ancestry"], + ancestries: { + id: 'ancestries', + keys: ['ancestries'], + label: 'Ancestries', + type: ['ancestry'], folders: { - "features": { - id: "features", - keys: ["ancestries"], - label: "Features", - type: ["feature"] + features: { + id: 'features', + keys: ['ancestries'], + label: 'Features', + type: ['feature'] } } }, - "equipments": { - id: "equipments", - keys: ["armors", "weapons", "consumables", "loot"], - label: "Equipment", - type: ["armor", "weapon", "consumable", "loot"], - listType: "items" + equipments: { + id: 'equipments', + keys: ['armors', 'weapons', 'consumables', 'loot'], + label: 'Equipment', + type: ['armor', 'weapon', 'consumable', 'loot'], + listType: 'items' }, - "classes": { - id: "classes", - keys: ["classes"], - label: "Classes", - type: ["class"], + classes: { + id: 'classes', + keys: ['classes'], + label: 'Classes', + type: ['class'], folders: { - "features": { - id: "features", - keys: ["classes"], - label: "Features", - type: ["feature"] + features: { + id: 'features', + keys: ['classes'], + label: 'Features', + type: ['feature'] }, - "items": { - id: "items", - keys: ["classes"], - label: "Items", - type: ["armor", "weapon", "consumable", "loot"], - listType: "items" + items: { + id: 'items', + keys: ['classes'], + label: 'Items', + type: ['armor', 'weapon', 'consumable', 'loot'], + listType: 'items' } }, - listType: "classes" + listType: 'classes' }, - "subclasses": { - id: "subclasses", - keys: ["subclasses"], - label: "Subclasses", - type: ["subclass"], - listType: "subclasses" + subclasses: { + id: 'subclasses', + keys: ['subclasses'], + label: 'Subclasses', + type: ['subclass'], + listType: 'subclasses' }, - "domains": { - id: "domains", - keys: ["domains"], - label: "Domain Cards", - type: ["domainCard"], - listType: "cards" + domains: { + id: 'domains', + keys: ['domains'], + label: 'Domain Cards', + type: ['domainCard'], + listType: 'cards' }, - "communities": { - id: "communities", - keys: ["communities"], - label: "Communities", - type: ["community"], + communities: { + id: 'communities', + keys: ['communities'], + label: 'Communities', + type: ['community'], folders: { - "features": { - id: "features", - keys: ["communities"], - label: "Features", - type: ["feature"] + features: { + id: 'features', + keys: ['communities'], + label: 'Features', + type: ['feature'] } } }, - "environments": { - id: "environments", - keys: ["environments"], - label: "Environments", - type: ["environment"] + environments: { + id: 'environments', + keys: ['environments'], + label: 'Environments', + type: ['environment'] }, - "beastforms": { - id: "beastforms", - keys: ["beastforms"], - label: "Beastforms", - type: ["beastform"], - listType: "beastforms", + beastforms: { + id: 'beastforms', + keys: ['beastforms'], + label: 'Beastforms', + type: ['beastform'], + listType: 'beastforms', folders: { - "features": { - id: "features", - keys: ["beastforms"], - label: "Features", - type: ["feature"] + features: { + id: 'features', + keys: ['beastforms'], + label: 'Features', + type: ['feature'] } } } } } -} \ No newline at end of file +}; diff --git a/module/data/actor/character.mjs b/module/data/actor/character.mjs index 7dd7993c..ddcc5bf5 100644 --- a/module/data/actor/character.mjs +++ b/module/data/actor/character.mjs @@ -317,7 +317,7 @@ export default class DhCharacter extends BaseDataActor { } get multiclass() { - const value = this.parent.items.find(x => x.type === 'Class' && x.system.isMulticlass); + const value = this.parent.items.find(x => x.type === 'class' && x.system.isMulticlass); const subclass = this.parent.items.find(x => x.type === 'subclass' && x.system.isMulticlass); return { @@ -443,7 +443,9 @@ export default class DhCharacter extends BaseDataActor { classFeatures.push(item); } else if (item.system.originItemType === CONFIG.DH.ITEM.featureTypes.subclass.id) { if (this.class.subclass) { - const subclassState = this.class.subclass.system.featureState; + const prop = item.system.multiclassOrigin ? 'multiclass' : 'class'; + const subclassState = this[prop].subclass?.system?.featureState; + if (!subclassState) continue; if ( item.system.identifier === CONFIG.DH.ITEM.featureSubTypes.foundation || diff --git a/module/data/item/base.mjs b/module/data/item/base.mjs index f333537b..f8eae265 100644 --- a/module/data/item/base.mjs +++ b/module/data/item/base.mjs @@ -148,7 +148,6 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel { for (let f of this.features) { const fBase = f.item ?? f; const feature = fBase.system ? fBase : await foundry.utils.fromUuid(fBase.uuid); - const multiclass = this.isMulticlass ? 'multiclass' : null; features.push( foundry.utils.mergeObject( feature.toObject(), @@ -156,7 +155,8 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel { _stats: { compendiumSource: fBase.uuid }, system: { originItemType: this.parent.type, - identifier: multiclass ?? (f.item ? f.type : null) + identifier: f.item ? f.type : null, + multiclassOrigin: this.isMulticlass } }, { inplace: false } diff --git a/module/data/item/feature.mjs b/module/data/item/feature.mjs index 6e1aab41..3b8fe064 100644 --- a/module/data/item/feature.mjs +++ b/module/data/item/feature.mjs @@ -29,6 +29,7 @@ export default class DHFeature extends BaseDataItem { nullable: true, initial: null }), + multiclassOrigin: new fields.BooleanField({ initial: false }), identifier: new fields.StringField() }; } diff --git a/module/data/item/subclass.mjs b/module/data/item/subclass.mjs index 46b83753..e16a15f7 100644 --- a/module/data/item/subclass.mjs +++ b/module/data/item/subclass.mjs @@ -1,3 +1,4 @@ +import ForeignDocumentUUIDField from '../fields/foreignDocumentUUIDField.mjs'; import ItemLinkFields from '../fields/itemLinkFields.mjs'; import BaseDataItem from './base.mjs'; @@ -25,7 +26,8 @@ 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 }) + isMulticlass: new fields.BooleanField({ initial: false }), + linkedClass: new ForeignDocumentUUIDField({ type: 'Item', nullable: true, initial: null }) }; } diff --git a/module/documents/actor.mjs b/module/documents/actor.mjs index e1dd93af..9a22eb44 100644 --- a/module/documents/actor.mjs +++ b/module/documents/actor.mjs @@ -1,7 +1,7 @@ import { emitAsGM, GMUpdateEvent } from '../systemRegistration/socket.mjs'; import { LevelOptionType } from '../data/levelTier.mjs'; import DHFeature from '../data/item/feature.mjs'; -import { damageKeyToNumber, versionCompare } from '../helpers/utils.mjs'; +import { damageKeyToNumber } from '../helpers/utils.mjs'; import DhCompanionLevelUp from '../applications/levelup/companionLevelup.mjs'; export default class DhpActor extends Actor { @@ -164,10 +164,10 @@ export default class DhpActor extends Actor { if (multiclass) { const multiclassItem = this.items.find(x => x.uuid === multiclass.itemUuid); const multiclassFeatures = this.items.filter( - x => x.system.originItemType === 'class' && x.system.identifier === 'multiclass' + x => x.system.originItemType === 'class' && x.system.multiclassOrigin ); const subclassFeatures = this.items.filter( - x => x.system.originItemType === 'subclass' && x.system.identifier === 'multiclass' + x => x.system.originItemType === 'subclass' && x.system.multiclassOrigin ); this.deleteEmbeddedDocuments( @@ -759,7 +759,7 @@ export default class DhpActor extends Actor { } const parsedJSON = JSON.parse(json); - if (versionCompare(parsedJSON._stats.systemVersion, '1.1.0')) { + if (foundry.utils.isNewerVersion('1.1.0', parsedJSON._stats.systemVersion)) { const confirmed = await foundry.applications.api.DialogV2.confirm({ window: { title: game.i18n.localize('DAGGERHEART.ACTORS.Character.InvalidOldCharacterImportTitle') diff --git a/module/helpers/utils.mjs b/module/helpers/utils.mjs index c8f4186f..6f4e5a26 100644 --- a/module/helpers/utils.mjs +++ b/module/helpers/utils.mjs @@ -420,14 +420,3 @@ export async function createEmbeddedItemsWithEffects(actor, baseData) { export const slugify = name => { return name.toLowerCase().replaceAll(' ', '-').replaceAll('.', ''); }; - -export const versionCompare = (current, target) => { - const currentSplit = current.split('.').map(x => Number.parseInt(x)); - const targetSplit = target.split('.').map(x => Number.parseInt(x)); - for (var i = 0; i < currentSplit.length; i++) { - if (currentSplit[i] < targetSplit[i]) return true; - if (currentSplit[i] > targetSplit[i]) return false; - } - - return false; -}; diff --git a/module/systemRegistration/migrations.mjs b/module/systemRegistration/migrations.mjs index e84018fa..da0dcb5d 100644 --- a/module/systemRegistration/migrations.mjs +++ b/module/systemRegistration/migrations.mjs @@ -1,10 +1,8 @@ -import { versionCompare } from '../helpers/utils.mjs'; - export async function runMigrations() { let lastMigrationVersion = game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LastMigrationVersion); if (!lastMigrationVersion) lastMigrationVersion = '1.0.6'; - if (versionCompare(lastMigrationVersion, '1.1.0')) { + if (foundry.utils.isNewerVersion('1.1.0', lastMigrationVersion)) { const compendiumActors = []; for (let pack of game.packs) { const documents = await pack.getDocuments(); @@ -37,5 +35,45 @@ export async function runMigrations() { lastMigrationVersion = '1.1.0'; } + if (foundry.utils.isNewerVersion('1.1.1', lastMigrationVersion)) { + const compendiumClasses = []; + const compendiumActors = []; + for (let pack of game.packs) { + const documents = await pack.getDocuments(); + compendiumClasses.push(...documents.filter(x => x.type === 'class')); + compendiumActors.push(...documents.filter(x => x.type === 'character')); + } + + [...compendiumActors, ...game.actors.filter(x => x.type === 'character')].forEach(char => { + const multiclass = char.items.find(x => x.type === 'class' && x.system.isMulticlass); + const multiclassSubclass = multiclass.system.subclasses.length > 0 ? multiclass.system.subclasses[0] : null; + char.items.forEach(item => { + if (item.type === 'feature' && item.system.identifier === 'multiclass') { + const base = item.system.originItemType === 'class' ? multiclass : multiclassSubclass; + if (base) { + const baseFeature = base.system.features.find(x => x.item.name === item.name); + if (baseFeature) { + item.update({ + system: { + multiclassOrigin: true, + identifier: baseFeature.type + } + }); + } + } + } + }); + }); + + const worldClasses = game.items.filter(x => x.type === 'class'); + for (let classVal of [...compendiumClasses, ...worldClasses]) { + for (let subclass of classVal.system.subclasses) { + await subclass.update({ 'system.linkedClass': classVal.uuid }); + } + } + + lastMigrationVersion = '1.1.1'; + } + await game.settings.set(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.LastMigrationVersion, lastMigrationVersion); } diff --git a/src/packs/classes/class_Bard_vegl3bFOq3pcFTWT.json b/src/packs/classes/class_Bard_vegl3bFOq3pcFTWT.json index 836e49b5..5ffd8a11 100644 --- a/src/packs/classes/class_Bard_vegl3bFOq3pcFTWT.json +++ b/src/packs/classes/class_Bard_vegl3bFOq3pcFTWT.json @@ -70,12 +70,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.1.0", "createdTime": 1754174600538, - "modifiedTime": 1754325498779, - "lastModifiedBy": "LgnbNMLaxandgMQq" + "modifiedTime": 1755943467705, + "lastModifiedBy": "tt3PwMBXcTLCtIQU" }, "_id": "vegl3bFOq3pcFTWT", "sort": 300000, diff --git a/src/packs/classes/class_Druid_ZNwUTCyGCEcidZFv.json b/src/packs/classes/class_Druid_ZNwUTCyGCEcidZFv.json index 800598a6..086d363e 100644 --- a/src/packs/classes/class_Druid_ZNwUTCyGCEcidZFv.json +++ b/src/packs/classes/class_Druid_ZNwUTCyGCEcidZFv.json @@ -72,12 +72,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.1.0", "createdTime": 1754222247012, - "modifiedTime": 1754325498779, - "lastModifiedBy": "LgnbNMLaxandgMQq" + "modifiedTime": 1755943479440, + "lastModifiedBy": "tt3PwMBXcTLCtIQU" }, "_key": "!items!ZNwUTCyGCEcidZFv" } diff --git a/src/packs/classes/class_Guardian_nRAyoC0fOzXPDa4z.json b/src/packs/classes/class_Guardian_nRAyoC0fOzXPDa4z.json index 2d76ccfb..b50f86ef 100644 --- a/src/packs/classes/class_Guardian_nRAyoC0fOzXPDa4z.json +++ b/src/packs/classes/class_Guardian_nRAyoC0fOzXPDa4z.json @@ -68,12 +68,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.1.0", "createdTime": 1754246931974, - "modifiedTime": 1754325498779, - "lastModifiedBy": "LgnbNMLaxandgMQq" + "modifiedTime": 1755943488697, + "lastModifiedBy": "tt3PwMBXcTLCtIQU" }, "_key": "!items!nRAyoC0fOzXPDa4z" } diff --git a/src/packs/classes/class_Ranger_BTyfve69LKqoOi9S.json b/src/packs/classes/class_Ranger_BTyfve69LKqoOi9S.json index 17fb6b2d..62e51c7d 100644 --- a/src/packs/classes/class_Ranger_BTyfve69LKqoOi9S.json +++ b/src/packs/classes/class_Ranger_BTyfve69LKqoOi9S.json @@ -68,12 +68,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.1.0", "createdTime": 1754268869310, - "modifiedTime": 1754325517617, - "lastModifiedBy": "LgnbNMLaxandgMQq" + "modifiedTime": 1755943505024, + "lastModifiedBy": "tt3PwMBXcTLCtIQU" }, "_key": "!items!BTyfve69LKqoOi9S" } diff --git a/src/packs/classes/class_Rogue_CvHlkHZfpMiCz5uT.json b/src/packs/classes/class_Rogue_CvHlkHZfpMiCz5uT.json index 617ea0f0..146ad340 100644 --- a/src/packs/classes/class_Rogue_CvHlkHZfpMiCz5uT.json +++ b/src/packs/classes/class_Rogue_CvHlkHZfpMiCz5uT.json @@ -72,12 +72,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.1.0", "createdTime": 1754325275832, - "modifiedTime": 1754500637635, - "lastModifiedBy": "Q9NoTaEarn3VMS6Z" + "modifiedTime": 1755943515533, + "lastModifiedBy": "tt3PwMBXcTLCtIQU" }, "_key": "!items!CvHlkHZfpMiCz5uT" } diff --git a/src/packs/classes/class_Seraph_5ZnlJ5bEoyOTkUJv.json b/src/packs/classes/class_Seraph_5ZnlJ5bEoyOTkUJv.json index b88da6c2..6a2b70a1 100644 --- a/src/packs/classes/class_Seraph_5ZnlJ5bEoyOTkUJv.json +++ b/src/packs/classes/class_Seraph_5ZnlJ5bEoyOTkUJv.json @@ -68,12 +68,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.1.0", "createdTime": 1754351482530, - "modifiedTime": 1754355938087, - "lastModifiedBy": "Q9NoTaEarn3VMS6Z" + "modifiedTime": 1755943523935, + "lastModifiedBy": "tt3PwMBXcTLCtIQU" }, "_key": "!items!5ZnlJ5bEoyOTkUJv" } diff --git a/src/packs/classes/class_Sorcerer_DchOzHcWIJE9FKcR.json b/src/packs/classes/class_Sorcerer_DchOzHcWIJE9FKcR.json index 15e9bcce..0d3d71ac 100644 --- a/src/packs/classes/class_Sorcerer_DchOzHcWIJE9FKcR.json +++ b/src/packs/classes/class_Sorcerer_DchOzHcWIJE9FKcR.json @@ -76,12 +76,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.1.0", "createdTime": 1754349743129, - "modifiedTime": 1754350005553, - "lastModifiedBy": "Q9NoTaEarn3VMS6Z" + "modifiedTime": 1755943536635, + "lastModifiedBy": "tt3PwMBXcTLCtIQU" }, "_key": "!items!DchOzHcWIJE9FKcR" } diff --git a/src/packs/classes/class_Warrior_xCUWwJz4WSthvLfy.json b/src/packs/classes/class_Warrior_xCUWwJz4WSthvLfy.json index 230c3a70..2d120f8e 100644 --- a/src/packs/classes/class_Warrior_xCUWwJz4WSthvLfy.json +++ b/src/packs/classes/class_Warrior_xCUWwJz4WSthvLfy.json @@ -72,12 +72,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.1.0", "createdTime": 1754255776706, - "modifiedTime": 1754325510730, - "lastModifiedBy": "LgnbNMLaxandgMQq" + "modifiedTime": 1755943545980, + "lastModifiedBy": "tt3PwMBXcTLCtIQU" }, "_key": "!items!xCUWwJz4WSthvLfy" } diff --git a/src/packs/classes/class_Wizard_5LwX4m8ziY3F1ZGC.json b/src/packs/classes/class_Wizard_5LwX4m8ziY3F1ZGC.json index 9a5790db..0955e68a 100644 --- a/src/packs/classes/class_Wizard_5LwX4m8ziY3F1ZGC.json +++ b/src/packs/classes/class_Wizard_5LwX4m8ziY3F1ZGC.json @@ -72,12 +72,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.1.0", "createdTime": 1754253505323, - "modifiedTime": 1754325500455, - "lastModifiedBy": "LgnbNMLaxandgMQq" + "modifiedTime": 1755943555087, + "lastModifiedBy": "tt3PwMBXcTLCtIQU" }, "_key": "!items!5LwX4m8ziY3F1ZGC" } diff --git a/src/packs/subclasses/subclass_Beastbound_TIUsIlTS1WkK5vr2.json b/src/packs/subclasses/subclass_Beastbound_TIUsIlTS1WkK5vr2.json index 824572e9..622fb36a 100644 --- a/src/packs/subclasses/subclass_Beastbound_TIUsIlTS1WkK5vr2.json +++ b/src/packs/subclasses/subclass_Beastbound_TIUsIlTS1WkK5vr2.json @@ -30,7 +30,8 @@ } ], "featureState": 1, - "isMulticlass": false + "isMulticlass": false, + "linkedClass": "Compendium.daggerheart.classes.Item.BTyfve69LKqoOi9S" }, "effects": [], "sort": 0, @@ -43,12 +44,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.1.0", "createdTime": 1754268237448, - "modifiedTime": 1754268308097, - "lastModifiedBy": "LgnbNMLaxandgMQq" + "modifiedTime": 1755943503629, + "lastModifiedBy": "tt3PwMBXcTLCtIQU" }, "_key": "!items!TIUsIlTS1WkK5vr2" } diff --git a/src/packs/subclasses/subclass_Call_Of_The_Brave_NAFU9roaVG7f3RNJ.json b/src/packs/subclasses/subclass_Call_Of_The_Brave_NAFU9roaVG7f3RNJ.json index 51718237..46f7f2af 100644 --- a/src/packs/subclasses/subclass_Call_Of_The_Brave_NAFU9roaVG7f3RNJ.json +++ b/src/packs/subclasses/subclass_Call_Of_The_Brave_NAFU9roaVG7f3RNJ.json @@ -26,7 +26,8 @@ } ], "featureState": 1, - "isMulticlass": false + "isMulticlass": false, + "linkedClass": "Compendium.daggerheart.classes.Item.xCUWwJz4WSthvLfy" }, "effects": [], "sort": 0, @@ -39,12 +40,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.1.0", "createdTime": 1754256077777, - "modifiedTime": 1754256954656, - "lastModifiedBy": "MQSznptE5yLT7kj8" + "modifiedTime": 1755943544886, + "lastModifiedBy": "tt3PwMBXcTLCtIQU" }, "_key": "!items!NAFU9roaVG7f3RNJ" } diff --git a/src/packs/subclasses/subclass_Call_Of_The_Slayer_bcNe5qP3o6CKadhK.json b/src/packs/subclasses/subclass_Call_Of_The_Slayer_bcNe5qP3o6CKadhK.json index ab0419d8..bbcf6ca6 100644 --- a/src/packs/subclasses/subclass_Call_Of_The_Slayer_bcNe5qP3o6CKadhK.json +++ b/src/packs/subclasses/subclass_Call_Of_The_Slayer_bcNe5qP3o6CKadhK.json @@ -22,7 +22,8 @@ } ], "featureState": 1, - "isMulticlass": false + "isMulticlass": false, + "linkedClass": "Compendium.daggerheart.classes.Item.xCUWwJz4WSthvLfy" }, "effects": [], "sort": 0, @@ -35,12 +36,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.1.0", "createdTime": 1754256112978, - "modifiedTime": 1754256959532, - "lastModifiedBy": "MQSznptE5yLT7kj8" + "modifiedTime": 1755943545973, + "lastModifiedBy": "tt3PwMBXcTLCtIQU" }, "_key": "!items!bcNe5qP3o6CKadhK" } diff --git a/src/packs/subclasses/subclass_Divine_Wielder_M5mpGoAj8LRkylrY.json b/src/packs/subclasses/subclass_Divine_Wielder_M5mpGoAj8LRkylrY.json index e5f1f4c8..9a7b9c96 100644 --- a/src/packs/subclasses/subclass_Divine_Wielder_M5mpGoAj8LRkylrY.json +++ b/src/packs/subclasses/subclass_Divine_Wielder_M5mpGoAj8LRkylrY.json @@ -26,7 +26,8 @@ } ], "featureState": 1, - "isMulticlass": false + "isMulticlass": false, + "linkedClass": "Compendium.daggerheart.classes.Item.5ZnlJ5bEoyOTkUJv" }, "effects": [], "sort": 0, @@ -39,12 +40,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.1.0", "createdTime": 1754352806098, - "modifiedTime": 1754354057333, - "lastModifiedBy": "Q9NoTaEarn3VMS6Z" + "modifiedTime": 1755943522722, + "lastModifiedBy": "tt3PwMBXcTLCtIQU" }, "_key": "!items!M5mpGoAj8LRkylrY" } diff --git a/src/packs/subclasses/subclass_Elemental_Origin_wg1H0hROc2acHwZh.json b/src/packs/subclasses/subclass_Elemental_Origin_wg1H0hROc2acHwZh.json index b1e5f67e..f1f85e42 100644 --- a/src/packs/subclasses/subclass_Elemental_Origin_wg1H0hROc2acHwZh.json +++ b/src/packs/subclasses/subclass_Elemental_Origin_wg1H0hROc2acHwZh.json @@ -22,7 +22,8 @@ } ], "featureState": 1, - "isMulticlass": false + "isMulticlass": false, + "linkedClass": "Compendium.daggerheart.classes.Item.DchOzHcWIJE9FKcR" }, "effects": [], "sort": 0, @@ -35,12 +36,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.1.0", "createdTime": 1754349604941, - "modifiedTime": 1754349648910, - "lastModifiedBy": "Q9NoTaEarn3VMS6Z" + "modifiedTime": 1755943535524, + "lastModifiedBy": "tt3PwMBXcTLCtIQU" }, "_key": "!items!wg1H0hROc2acHwZh" } diff --git a/src/packs/subclasses/subclass_Nightwalker_h161OSIK24Up4qNd.json b/src/packs/subclasses/subclass_Nightwalker_h161OSIK24Up4qNd.json index 8da59a4c..49f9a520 100644 --- a/src/packs/subclasses/subclass_Nightwalker_h161OSIK24Up4qNd.json +++ b/src/packs/subclasses/subclass_Nightwalker_h161OSIK24Up4qNd.json @@ -30,7 +30,8 @@ } ], "featureState": 1, - "isMulticlass": false + "isMulticlass": false, + "linkedClass": "Compendium.daggerheart.classes.Item.CvHlkHZfpMiCz5uT" }, "effects": [], "sort": 0, @@ -43,12 +44,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.1.0", "createdTime": 1754322815758, - "modifiedTime": 1754323509061, - "lastModifiedBy": "LgnbNMLaxandgMQq" + "modifiedTime": 1755943514465, + "lastModifiedBy": "tt3PwMBXcTLCtIQU" }, "_key": "!items!h161OSIK24Up4qNd" } diff --git a/src/packs/subclasses/subclass_Primal_Origin_GLpRVxnY5E82khxH.json b/src/packs/subclasses/subclass_Primal_Origin_GLpRVxnY5E82khxH.json index e3f38604..37619136 100644 --- a/src/packs/subclasses/subclass_Primal_Origin_GLpRVxnY5E82khxH.json +++ b/src/packs/subclasses/subclass_Primal_Origin_GLpRVxnY5E82khxH.json @@ -22,7 +22,8 @@ } ], "featureState": 1, - "isMulticlass": false + "isMulticlass": false, + "linkedClass": "Compendium.daggerheart.classes.Item.DchOzHcWIJE9FKcR" }, "effects": [], "sort": 0, @@ -35,12 +36,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.1.0", "createdTime": 1754349604941, - "modifiedTime": 1754349673276, - "lastModifiedBy": "Q9NoTaEarn3VMS6Z" + "modifiedTime": 1755943536628, + "lastModifiedBy": "tt3PwMBXcTLCtIQU" }, "_key": "!items!GLpRVxnY5E82khxH" } diff --git a/src/packs/subclasses/subclass_School_Of_Knowledge_qqQlgCqhOivUFoQn.json b/src/packs/subclasses/subclass_School_Of_Knowledge_qqQlgCqhOivUFoQn.json index 7dcbcf35..7ed07d06 100644 --- a/src/packs/subclasses/subclass_School_Of_Knowledge_qqQlgCqhOivUFoQn.json +++ b/src/packs/subclasses/subclass_School_Of_Knowledge_qqQlgCqhOivUFoQn.json @@ -34,7 +34,8 @@ } ], "featureState": 1, - "isMulticlass": false + "isMulticlass": false, + "linkedClass": "Compendium.daggerheart.classes.Item.5LwX4m8ziY3F1ZGC" }, "effects": [], "sort": 0, @@ -47,12 +48,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.1.0", "createdTime": 1754253538384, - "modifiedTime": 1754254543287, - "lastModifiedBy": "MQSznptE5yLT7kj8" + "modifiedTime": 1755943553625, + "lastModifiedBy": "tt3PwMBXcTLCtIQU" }, "_key": "!items!qqQlgCqhOivUFoQn" } diff --git a/src/packs/subclasses/subclass_School_Of_War_4y9Ph7RsCIAbkwTk.json b/src/packs/subclasses/subclass_School_Of_War_4y9Ph7RsCIAbkwTk.json index 03af87fc..856031d8 100644 --- a/src/packs/subclasses/subclass_School_Of_War_4y9Ph7RsCIAbkwTk.json +++ b/src/packs/subclasses/subclass_School_Of_War_4y9Ph7RsCIAbkwTk.json @@ -34,7 +34,8 @@ } ], "featureState": 1, - "isMulticlass": false + "isMulticlass": false, + "linkedClass": "Compendium.daggerheart.classes.Item.5LwX4m8ziY3F1ZGC" }, "effects": [], "sort": 0, @@ -47,12 +48,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.1.0", "createdTime": 1754253587683, - "modifiedTime": 1754254721869, - "lastModifiedBy": "MQSznptE5yLT7kj8" + "modifiedTime": 1755943555081, + "lastModifiedBy": "tt3PwMBXcTLCtIQU" }, "_key": "!items!4y9Ph7RsCIAbkwTk" } diff --git a/src/packs/subclasses/subclass_Stalwart_rKRxFBlkbh9cDK8K.json b/src/packs/subclasses/subclass_Stalwart_rKRxFBlkbh9cDK8K.json index 0e9ea4df..b75f88d0 100644 --- a/src/packs/subclasses/subclass_Stalwart_rKRxFBlkbh9cDK8K.json +++ b/src/packs/subclasses/subclass_Stalwart_rKRxFBlkbh9cDK8K.json @@ -34,7 +34,8 @@ } ], "featureState": 1, - "isMulticlass": false + "isMulticlass": false, + "linkedClass": "Compendium.daggerheart.classes.Item.nRAyoC0fOzXPDa4z" }, "effects": [], "sort": 0, @@ -47,12 +48,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.1.0", "createdTime": 1754245881893, - "modifiedTime": 1754245958817, - "lastModifiedBy": "LgnbNMLaxandgMQq" + "modifiedTime": 1755943487549, + "lastModifiedBy": "tt3PwMBXcTLCtIQU" }, "_key": "!items!rKRxFBlkbh9cDK8K" } diff --git a/src/packs/subclasses/subclass_Syndicate_95QxNZwgyEm1LqdG.json b/src/packs/subclasses/subclass_Syndicate_95QxNZwgyEm1LqdG.json index 8d7285d4..2cef9bbd 100644 --- a/src/packs/subclasses/subclass_Syndicate_95QxNZwgyEm1LqdG.json +++ b/src/packs/subclasses/subclass_Syndicate_95QxNZwgyEm1LqdG.json @@ -22,7 +22,8 @@ } ], "featureState": 1, - "isMulticlass": false + "isMulticlass": false, + "linkedClass": "Compendium.daggerheart.classes.Item.CvHlkHZfpMiCz5uT" }, "effects": [], "sort": 0, @@ -35,12 +36,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.1.0", "createdTime": 1754323643089, - "modifiedTime": 1754323735227, - "lastModifiedBy": "LgnbNMLaxandgMQq" + "modifiedTime": 1755943515526, + "lastModifiedBy": "tt3PwMBXcTLCtIQU" }, "_key": "!items!95QxNZwgyEm1LqdG" } diff --git a/src/packs/subclasses/subclass_Troubadour_ld8MIvk0xVJydSBz.json b/src/packs/subclasses/subclass_Troubadour_ld8MIvk0xVJydSBz.json index e50ecfa8..eb51d60e 100644 --- a/src/packs/subclasses/subclass_Troubadour_ld8MIvk0xVJydSBz.json +++ b/src/packs/subclasses/subclass_Troubadour_ld8MIvk0xVJydSBz.json @@ -21,7 +21,8 @@ } ], "featureState": 1, - "isMulticlass": false + "isMulticlass": false, + "linkedClass": "Compendium.daggerheart.classes.Item.vegl3bFOq3pcFTWT" }, "effects": [], "ownership": { @@ -33,12 +34,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.1.0", "createdTime": 1754174653653, - "modifiedTime": 1754236659263, - "lastModifiedBy": "LgnbNMLaxandgMQq" + "modifiedTime": 1755943465827, + "lastModifiedBy": "tt3PwMBXcTLCtIQU" }, "_id": "ld8MIvk0xVJydSBz", "sort": 100000, diff --git a/src/packs/subclasses/subclass_Vengeance_SUo8NPBPO8aN193u.json b/src/packs/subclasses/subclass_Vengeance_SUo8NPBPO8aN193u.json index 53f7cf96..fedf5f1a 100644 --- a/src/packs/subclasses/subclass_Vengeance_SUo8NPBPO8aN193u.json +++ b/src/packs/subclasses/subclass_Vengeance_SUo8NPBPO8aN193u.json @@ -26,7 +26,8 @@ } ], "featureState": 1, - "isMulticlass": false + "isMulticlass": false, + "linkedClass": "Compendium.daggerheart.classes.Item.nRAyoC0fOzXPDa4z" }, "effects": [], "sort": 0, @@ -39,12 +40,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.1.0", "createdTime": 1754246011733, - "modifiedTime": 1754246076491, - "lastModifiedBy": "LgnbNMLaxandgMQq" + "modifiedTime": 1755943488691, + "lastModifiedBy": "tt3PwMBXcTLCtIQU" }, "_key": "!items!SUo8NPBPO8aN193u" } diff --git a/src/packs/subclasses/subclass_Warden_of_Renewal_xp0XMjYT85Q7E90o.json b/src/packs/subclasses/subclass_Warden_of_Renewal_xp0XMjYT85Q7E90o.json index 08421469..abe97d5e 100644 --- a/src/packs/subclasses/subclass_Warden_of_Renewal_xp0XMjYT85Q7E90o.json +++ b/src/packs/subclasses/subclass_Warden_of_Renewal_xp0XMjYT85Q7E90o.json @@ -29,7 +29,8 @@ } ], "featureState": 1, - "isMulticlass": false + "isMulticlass": false, + "linkedClass": "Compendium.daggerheart.classes.Item.ZNwUTCyGCEcidZFv" }, "effects": [], "folder": "AZWrSJzGXltzQhAJ", @@ -43,12 +44,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.1.0", "createdTime": 1754221346981, - "modifiedTime": 1754236671909, - "lastModifiedBy": "LgnbNMLaxandgMQq" + "modifiedTime": 1755943479431, + "lastModifiedBy": "tt3PwMBXcTLCtIQU" }, "_key": "!items!xp0XMjYT85Q7E90o" } diff --git a/src/packs/subclasses/subclass_Warden_of_the_Elements_W9hs5kxOWeY7eA4Q.json b/src/packs/subclasses/subclass_Warden_of_the_Elements_W9hs5kxOWeY7eA4Q.json index 0e4972f6..43642e89 100644 --- a/src/packs/subclasses/subclass_Warden_of_the_Elements_W9hs5kxOWeY7eA4Q.json +++ b/src/packs/subclasses/subclass_Warden_of_the_Elements_W9hs5kxOWeY7eA4Q.json @@ -21,7 +21,8 @@ } ], "featureState": 1, - "isMulticlass": false + "isMulticlass": false, + "linkedClass": "Compendium.daggerheart.classes.Item.ZNwUTCyGCEcidZFv" }, "effects": [], "folder": "AZWrSJzGXltzQhAJ", @@ -35,12 +36,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.1.0", "createdTime": 1754221102716, - "modifiedTime": 1754236671090, - "lastModifiedBy": "LgnbNMLaxandgMQq" + "modifiedTime": 1755943478132, + "lastModifiedBy": "tt3PwMBXcTLCtIQU" }, "_key": "!items!W9hs5kxOWeY7eA4Q" } diff --git a/src/packs/subclasses/subclass_Wayfinder_zsUglcU4NgZ8tNgZ.json b/src/packs/subclasses/subclass_Wayfinder_zsUglcU4NgZ8tNgZ.json index 4f9a2289..a308d587 100644 --- a/src/packs/subclasses/subclass_Wayfinder_zsUglcU4NgZ8tNgZ.json +++ b/src/packs/subclasses/subclass_Wayfinder_zsUglcU4NgZ8tNgZ.json @@ -26,7 +26,8 @@ } ], "featureState": 1, - "isMulticlass": false + "isMulticlass": false, + "linkedClass": "Compendium.daggerheart.classes.Item.BTyfve69LKqoOi9S" }, "effects": [], "sort": 0, @@ -39,12 +40,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.1.0", "createdTime": 1754268318903, - "modifiedTime": 1754268377047, - "lastModifiedBy": "LgnbNMLaxandgMQq" + "modifiedTime": 1755943505016, + "lastModifiedBy": "tt3PwMBXcTLCtIQU" }, "_key": "!items!zsUglcU4NgZ8tNgZ" } diff --git a/src/packs/subclasses/subclass_Winged_Sentinel_y7ERWRIpJsdP9Re4.json b/src/packs/subclasses/subclass_Winged_Sentinel_y7ERWRIpJsdP9Re4.json index 6da6a117..f71a1fcb 100644 --- a/src/packs/subclasses/subclass_Winged_Sentinel_y7ERWRIpJsdP9Re4.json +++ b/src/packs/subclasses/subclass_Winged_Sentinel_y7ERWRIpJsdP9Re4.json @@ -26,7 +26,8 @@ } ], "featureState": 1, - "isMulticlass": false + "isMulticlass": false, + "linkedClass": "Compendium.daggerheart.classes.Item.5ZnlJ5bEoyOTkUJv" }, "effects": [], "sort": 0, @@ -39,12 +40,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.1.0", "createdTime": 1754354451615, - "modifiedTime": 1754355901649, - "lastModifiedBy": "Q9NoTaEarn3VMS6Z" + "modifiedTime": 1755943523928, + "lastModifiedBy": "tt3PwMBXcTLCtIQU" }, "_key": "!items!y7ERWRIpJsdP9Re4" } diff --git a/src/packs/subclasses/subclass_Wordsmith_XTSODVM8st75Os8M.json b/src/packs/subclasses/subclass_Wordsmith_XTSODVM8st75Os8M.json index f4c35265..6c975ca6 100644 --- a/src/packs/subclasses/subclass_Wordsmith_XTSODVM8st75Os8M.json +++ b/src/packs/subclasses/subclass_Wordsmith_XTSODVM8st75Os8M.json @@ -25,7 +25,8 @@ } ], "featureState": 1, - "isMulticlass": false + "isMulticlass": false, + "linkedClass": "Compendium.daggerheart.classes.Item.vegl3bFOq3pcFTWT" }, "effects": [], "ownership": { @@ -37,12 +38,12 @@ "compendiumSource": null, "duplicateSource": null, "exportSource": null, - "coreVersion": "13.346", + "coreVersion": "13.347", "systemId": "daggerheart", - "systemVersion": "0.0.1", + "systemVersion": "1.1.0", "createdTime": 1754174655078, - "modifiedTime": 1754236660088, - "lastModifiedBy": "LgnbNMLaxandgMQq" + "modifiedTime": 1755943467695, + "lastModifiedBy": "tt3PwMBXcTLCtIQU" }, "_id": "XTSODVM8st75Os8M", "sort": 200000, diff --git a/styles/less/ui/item-browser/item-browser.less b/styles/less/ui/item-browser/item-browser.less index df35d60b..407a3116 100644 --- a/styles/less/ui/item-browser/item-browser.less +++ b/styles/less/ui/item-browser/item-browser.less @@ -356,6 +356,8 @@ display: grid; grid-template-rows: 0fr; transition: all 0.3s ease-in-out; + width: 100%; + .wrapper { overflow: hidden; display: grid; diff --git a/system.json b/system.json index d72c53d5..31130bb8 100644 --- a/system.json +++ b/system.json @@ -2,7 +2,7 @@ "id": "daggerheart", "title": "Daggerheart", "description": "An unofficial implementation of the Daggerheart system", - "version": "1.1.0", + "version": "1.1.1", "compatibility": { "minimum": "13", "verified": "13.347", From fbeff1b90863c1fecdc42b6ea65a7d433db47d86 Mon Sep 17 00:00:00 2001 From: WBHarry <89362246+WBHarry@users.noreply.github.com> Date: Sun, 24 Aug 2025 02:21:00 +0200 Subject: [PATCH 10/10] The basic attack damage shown in the sidebar is modified if horde damage is active (#1071) --- module/data/action/attackAction.mjs | 8 +++++--- module/data/actor/adversary.mjs | 2 +- 2 files changed, 6 insertions(+), 4 deletions(-) diff --git a/module/data/action/attackAction.mjs b/module/data/action/attackAction.mjs index 62463d15..68afc23b 100644 --- a/module/data/action/attackAction.mjs +++ b/module/data/action/attackAction.mjs @@ -51,11 +51,13 @@ export default class DHAttackAction extends DHDamageAction { const labels = []; const { roll, range, damage } = this; - if (roll.trait) labels.push(game.i18n.localize(`DAGGERHEART.CONFIG.Traits.${roll.trait}.short`)) + if (roll.trait) labels.push(game.i18n.localize(`DAGGERHEART.CONFIG.Traits.${roll.trait}.short`)); if (range) labels.push(game.i18n.localize(`DAGGERHEART.CONFIG.Range.${range}.short`)); - for (const { value, type } of damage.parts) { - const str = Roll.replaceFormulaData(value.getFormula(), this.actor?.getRollData() ?? {}); + const useAltDamage = this.actor?.effects?.find(x => x.type === 'horde')?.active; + for (const { value, valueAlt, type } of damage.parts) { + const usedValue = useAltDamage ? valueAlt : value; + const str = Roll.replaceFormulaData(usedValue.getFormula(), this.actor?.getRollData() ?? {}); const icons = Array.from(type) .map(t => CONFIG.DH.GENERAL.damageTypes[t]?.icon) diff --git a/module/data/actor/adversary.mjs b/module/data/actor/adversary.mjs index e64c64f3..a4dfddf5 100644 --- a/module/data/actor/adversary.mjs +++ b/module/data/actor/adversary.mjs @@ -129,7 +129,7 @@ export default class DhpAdversary extends BaseDataActor { CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Automation ).hordeDamage; - if (autoHordeDamage && changes.system?.resources?.hitPoints?.value) { + if (autoHordeDamage && changes.system?.resources?.hitPoints?.value !== undefined) { const hordeActiveEffect = this.parent.effects.find(x => x.type === 'horde'); if (hordeActiveEffect) { const halfHP = Math.ceil(this.resources.hitPoints.max / 2);