diff --git a/lang/en.json b/lang/en.json index b4b1410e..b91d426e 100755 --- a/lang/en.json +++ b/lang/en.json @@ -3161,6 +3161,7 @@ "noSelectionsLeft": "Nothing more to select!", "alreadySelectedClass": "You already have that class!", "classAlreadySelected": "The character already has a class", + "classMissingIdentifier": "The class hasn't set up an identifier", "subclassAlreadySelected": "The character already has a subclass for that class.", "noClassSelected": "Your character has no class selected!", "lacksDomain": "Your character doesn't have the domain of the card!", @@ -3210,7 +3211,6 @@ "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/sheets/items/class.mjs b/module/applications/sheets/items/class.mjs index 05bb0229..9e11d3c7 100644 --- a/module/applications/sheets/items/class.mjs +++ b/module/applications/sheets/items/class.mjs @@ -128,20 +128,21 @@ 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 (itemType === 'subclass') { - if (item.system.linkedClass) { - return ui.notifications.warn( - game.i18n.format('DAGGERHEART.UI.Notifications.subclassAlreadyLinked', { - name: item.name, - class: this.document.name - }) - ); + if (!this.document.system.identifier) { + return ui.notifications.error( + game.i18n.localize('DAGGERHEART.UI.Notifications.classMissingIdentifier') + ); } - 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)) { + + if (item.system.classIdentifiers.includes(this.document.system.identifier)) + return; + + await item.update({ 'system.classIdentifiers': this.document.system.identifier }); + } + + else if (['feature', 'ActiveEffect'].includes(itemType)) { super._onDrop(event); } else if (this.document.parent?.type !== 'character') { if (itemType === 'weapon') { diff --git a/module/data/item/class.mjs b/module/data/item/class.mjs index d3738318..07bc9821 100644 --- a/module/data/item/class.mjs +++ b/module/data/item/class.mjs @@ -30,7 +30,6 @@ 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 }), @@ -51,7 +50,10 @@ export default class DHClass extends BaseDataItem { }), backgroundQuestions: new fields.ArrayField(new fields.StringField(), { initial: ['', '', ''] }), connections: new fields.ArrayField(new fields.StringField(), { initial: ['', '', ''] }), - isMulticlass: new fields.BooleanField({ initial: false }) + isMulticlass: new fields.BooleanField({ initial: false }), + identifier: new fields.StringField(), + /* Subclasses is legacy. If we can safetely migrate it away at some point we could remove it*/ + subclasses: new ForeignDocumentUUIDArrayField({ type: 'Item', required: false }), }; } @@ -70,6 +72,28 @@ export default class DHClass extends BaseDataItem { return this.features.filter(x => x.type === CONFIG.DH.ITEM.featureSubTypes.class).map(x => x.item); } + async getSubclasses() { + const oldLinkedSubclasses = this.subclasses.filter(x => x); + if (!this.identifier) return oldLinkedSubclasses; + + const subclasses = game.items.filter(x => x.type === 'subclass' && x.system.classIdentifiers.includes(this.identifier)); + for(const pack of game.packs) { + const indexes = await pack.getIndex({ fields: ['system.classIdentifiers']}); + for(const index of indexes) { + if ( + index.type === 'subclass' && + (index.system.classIdentifiers??[]).includes(this.identifier && + !subclasses.find(x => x.uuid === index.uuid)) + ) { + 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 d421cc6d..f166d01b 100644 --- a/module/data/item/subclass.mjs +++ b/module/data/item/subclass.mjs @@ -28,6 +28,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 }), + classIdentifiers: new fields.ArrayField(new fields.StringField({ nullable: false })), + /* Linked class is legacy. If we can safetely migrate it away at some point we could remove it */ linkedClass: new ForeignDocumentUUIDField({ type: 'Item', nullable: true, initial: null }) }; } diff --git a/templates/sheets/items/class/header.hbs b/templates/sheets/items/class/header.hbs index 6b60ada6..12c08bc3 100644 --- a/templates/sheets/items/class/header.hbs +++ b/templates/sheets/items/class/header.hbs @@ -3,7 +3,10 @@

-

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

+

+ {{localize 'TYPES.Item.class'}} + {{formInput systemFields.identifier value=source.system.identifier}} +

{{localize "DAGGERHEART.GENERAL.Domain.plural"}}