diff --git a/lang/en.json b/lang/en.json index 4d3927bc..71257664 100755 --- a/lang/en.json +++ b/lang/en.json @@ -1603,13 +1603,7 @@ "attackIsMissing": "Attack is missing", "unownedActionMacro": "Cannot make a Use macro for an Action not on your character", "unownedAttackMacro": "Cannot make a Use macro for an Attack that doesn't belong to one of your characters", - "featureNotHope": "This feature is used as something else than a Hope feature and cannot be used here.", - "featureNotClass": "This feature is used as something else than a Class feature and cannot be used here.", - "featureNotPrimary": "This feature is used as something else than a Primary feature and cannot be used here.", - "featureNotSecondary": "This feature is used as something else than a Secondary feature and cannot be used here.", - "featureNotFoundation": "This feature is used as something else than a Foundation feature and cannot be used here.", - "featureNotSpecialization": "This feature is used as something else than a Specialization feature and cannot be used here.", - "featureNotMastery": "This feature is used as something else than a Mastery feature and cannot be used here." + "featureAlreadyLinked": "{name} is already linked to {origin}. Remove it from there if you want to link it elsewhere." }, "Tooltip": { "disableEffect": "Disable Effect", diff --git a/module/applications/sheets/api/application-mixin.mjs b/module/applications/sheets/api/application-mixin.mjs index c78e5670..467ebcbc 100644 --- a/module/applications/sheets/api/application-mixin.mjs +++ b/module/applications/sheets/api/application-mixin.mjs @@ -506,7 +506,12 @@ export default function DHApplicationMixin(Base) { if (doc) return doc.sheet.render({ force: true }); // TODO: REDO this - const { actionId } = target.closest('[data-action-id]').dataset; + const actionNode = target.closest('[data-action-id]'); + if (!actionNode) { + return ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.featureIsMissing')); + } + + const { actionId } = actionNode.dataset; const { actions, attack } = this.document.system; const action = attack?.id === actionId ? attack : actions?.find(a => a.id === actionId); new DHActionConfig(action).render({ force: true }); diff --git a/module/applications/sheets/api/base-item.mjs b/module/applications/sheets/api/base-item.mjs index 610586cb..cbce24ae 100644 --- a/module/applications/sheets/api/base-item.mjs +++ b/module/applications/sheets/api/base-item.mjs @@ -290,6 +290,16 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) { const item = await fromUuid(data.uuid); if (item?.type === 'feature') { + if (item.system.originId) { + const origin = await foundry.utils.fromUuid(item.system.originId); + return ui.notifications.warn( + game.i18n.format('DAGGERHEART.UI.Notifications.featureAlreadyLinked', { + name: item.name, + origin: origin.name + }) + ); + } + await item.update({ system: { originItemType: CONFIG.DH.ITEM.featureTypes[this.document.type].id, diff --git a/module/applications/sheets/items/ancestry.mjs b/module/applications/sheets/items/ancestry.mjs index e69a7288..92985b78 100644 --- a/module/applications/sheets/items/ancestry.mjs +++ b/module/applications/sheets/items/ancestry.mjs @@ -50,13 +50,17 @@ export default class AncestrySheet extends DHHeritageSheet { const item = await fromUuid(data.uuid); if (item?.type === 'feature') { - const subType = event.target.closest('.primary-feature') ? 'primary' : 'secondary'; - if (item.system.subType && item.system.subType !== CONFIG.DH.ITEM.featureSubTypes[subType]) { - const error = subType === 'primary' ? 'featureNotPrimary' : 'featureNotSecondary'; - ui.notifications.warn(game.i18n.localize(`DAGGERHEART.UI.Notifications.${error}`)); - return; + if (item.system.originId) { + const origin = await foundry.utils.fromUuid(item.system.originId); + return ui.notifications.warn( + game.i18n.format('DAGGERHEART.UI.Notifications.featureAlreadyLinked', { + name: item.name, + origin: origin.name + }) + ); } + const subType = event.target.closest('.primary-feature') ? 'primary' : 'secondary'; await item.update({ system: { subType: subType, diff --git a/module/applications/sheets/items/class.mjs b/module/applications/sheets/items/class.mjs index ec1fff21..c4bba198 100644 --- a/module/applications/sheets/items/class.mjs +++ b/module/applications/sheets/items/class.mjs @@ -83,16 +83,38 @@ export default class ClassSheet extends DHBaseItemSheet { const item = await fromUuid(data.uuid); const target = event.target.closest('fieldset.drop-section'); if (item.type === 'subclass') { + if (item.system.originId) { + const origin = await foundry.utils.fromUuid(item.system.originId); + return ui.notifications.warn( + game.i18n.format('DAGGERHEART.UI.Notifications.featureAlreadyLinked', { + name: item.name, + origin: origin.name + }) + ); + } + + await item.update({ + system: { + originItemType: CONFIG.DH.ITEM.featureTypes[this.document.type].id, + originId: this.document.uuid + } + }); + await this.document.update({ 'system.subclasses': [...this.document.system.subclasses.map(x => x.uuid), item.uuid] }); } else if (item.type === 'feature') { - if (target.classList.contains('hope-feature')) { - if (item.system.subType && item.system.subType !== CONFIG.DH.ITEM.featureSubTypes.hope) { - ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.featureNotHope')); - return; - } + if (item.system.originId) { + const origin = await foundry.utils.fromUuid(item.system.originId); + return ui.notifications.warn( + game.i18n.format('DAGGERHEART.UI.Notifications.featureAlreadyLinked', { + name: item.name, + origin: origin.name + }) + ); + } + if (target.classList.contains('hope-feature')) { await item.update({ system: { subType: CONFIG.DH.ITEM.featureSubTypes.hope, @@ -104,11 +126,6 @@ export default class ClassSheet extends DHBaseItemSheet { 'system.features': [...this.document.system.features.map(x => x.uuid), item.uuid] }); } else if (target.classList.contains('class-feature')) { - if (item.system.subType && item.system.subType !== CONFIG.DH.ITEM.featureSubTypes.class) { - ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.featureNotClass')); - return; - } - await item.update({ system: { subType: CONFIG.DH.ITEM.featureSubTypes.class, @@ -151,18 +168,20 @@ export default class ClassSheet extends DHBaseItemSheet { } } else if (item.type === 'miscellaneous') { if (target.classList.contains('take-section')) { - if (this.document.system.inventory.take.length < 3) + if (this.document.system.inventory.take.length < 3) { await this.document.update({ 'system.inventory.take': [...this.document.system.inventory.take.map(x => x.uuid), item.uuid] }); + } } else if (target.classList.contains('choice-b-section')) { - if (this.document.system.inventory.choiceB.length < 2) + if (this.document.system.inventory.choiceB.length < 2) { await this.document.update({ 'system.inventory.choiceB': [ ...this.document.system.inventory.choiceB.map(x => x.uuid), item.uuid ] }); + } } } } @@ -179,7 +198,19 @@ 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); - await this.document.update({ [`system.${target}`]: prop.filter(i => i.uuid !== uuid) }); + const item = await foundry.utils.fromUuid(uuid); + + if (item) { + await item.update({ + system: { + originItemType: null, + originId: null, + subType: null + } + }); + } + + await this.document.update({ [`system.${target}`]: prop.filter(i => i && i.uuid !== uuid) }); } /** diff --git a/module/applications/sheets/items/subclass.mjs b/module/applications/sheets/items/subclass.mjs index 5593737d..f2a46936 100644 --- a/module/applications/sheets/items/subclass.mjs +++ b/module/applications/sheets/items/subclass.mjs @@ -62,12 +62,17 @@ export default class SubclassSheet extends DHBaseItemSheet { const item = await fromUuid(data.uuid); const target = event.target.closest('fieldset.drop-section'); if (item.type === 'feature') { - if (target.dataset.type === 'foundation') { - if (item.system.subType && item.system.subType !== CONFIG.DH.ITEM.featureSubTypes.foundation) { - ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.featureNotFoundation')); - return; - } + if (item.system.originId) { + const origin = await foundry.utils.fromUuid(item.system.originId); + return ui.notifications.warn( + game.i18n.format('DAGGERHEART.UI.Notifications.featureAlreadyLinked', { + name: item.name, + origin: origin.name + }) + ); + } + if (target.dataset.type === 'foundation') { await item.update({ system: { subType: CONFIG.DH.ITEM.featureSubTypes.foundation, @@ -79,11 +84,6 @@ export default class SubclassSheet extends DHBaseItemSheet { 'system.features': [...this.document.system.features.map(x => x.uuid), item.uuid] }); } else if (target.dataset.type === 'specialization') { - if (item.system.subType && item.system.subType !== CONFIG.DH.ITEM.featureSubTypes.specialization) { - ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.featureNotSpecialization')); - return; - } - await item.update({ system: { subType: CONFIG.DH.ITEM.featureSubTypes.specialization, @@ -95,11 +95,6 @@ export default class SubclassSheet extends DHBaseItemSheet { 'system.features': [...this.document.system.features.map(x => x.uuid), item.uuid] }); } else if (target.dataset.type === 'mastery') { - if (item.system.subType && item.system.subType !== CONFIG.DH.ITEM.featureSubTypes.mastery) { - ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.featureNotMastery')); - return; - } - await item.update({ system: { subType: CONFIG.DH.ITEM.featureSubTypes.mastery, diff --git a/module/data/item/base.mjs b/module/data/item/base.mjs index 92e12040..a9a43e6c 100644 --- a/module/data/item/base.mjs +++ b/module/data/item/base.mjs @@ -21,7 +21,8 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel { hasDescription: false, hasResource: false, isQuantifiable: false, - isInventoryItem: false + isInventoryItem: false, + possibleItemLink: false }; } @@ -69,6 +70,20 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel { if (this.metadata.isQuantifiable) schema.quantity = new fields.NumberField({ integer: true, initial: 1, min: 0, required: true }); + if (this.metadata.possibleItemLink) { + schema.originItemType = new fields.StringField({ + choices: CONFIG.DH.ITEM.featureTypes, + nullable: true, + initial: null + }); + schema.originId = new fields.StringField({ nullable: true, initial: null }); + schema.subType = new fields.StringField({ + choices: CONFIG.DH.ITEM.featureSubTypes, + nullable: true, + initial: null + }); + } + return schema; } @@ -137,22 +152,43 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel { async _preDelete() { if (this.originId) { - if (this.actor && this.actor.type === 'character') { - const items = this.actor.items.filter(item => item.system.originId === this.parent.id); - if (items.length > 0) - await this.actor.deleteEmbeddedDocuments( - 'Item', - items.map(x => x.id) - ); - } else { - const linkedItem = await foundry.utils.fromUuid(this.originId); - if (linkedItem) { - await linkedItem.update({ - 'system.features': linkedItem.system.features - .filter(x => x.uuid !== this.parent.uuid) - .map(x => x.uuid) - }); + if (this.parent.type === 'feature') { + if (this.actor && this.actor.type === 'character') { + const items = this.actor.items.filter(item => item.system.originId === this.parent.id); + if (items.length > 0) + await this.actor.deleteEmbeddedDocuments( + 'Item', + items.map(x => x.id) + ); + } else { + const linkedItem = await foundry.utils.fromUuid(this.originId); + if (linkedItem) { + await linkedItem.update({ + 'system.features': linkedItem.system.features + .filter(x => x.uuid !== this.parent.uuid) + .map(x => x.uuid) + }); + } } + } else if (this.parent.type === 'subclass') { + const linkedItem = await foundry.utils.fromUuid(this.originId); + await linkedItem.update({ + 'system.subclasses': linkedItem.system.subclasses + .filter(x => x.uuid !== this.parent.uuid) + .map(x => x.uuid) + }); + } + } + + if (this.features?.length) { + for (var feature of this.features) { + await feature.update({ + system: { + originItemType: null, + originId: null, + subType: null + } + }); } } } diff --git a/module/data/item/class.mjs b/module/data/item/class.mjs index b8a9ab81..0f873126 100644 --- a/module/data/item/class.mjs +++ b/module/data/item/class.mjs @@ -86,6 +86,18 @@ export default class DHClass extends BaseDataItem { } } + async _preDelete() { + for (var subclass of this.subclasses) { + await subclass.update({ + system: { + originItemType: null, + originId: null, + subType: null + } + }); + } + } + _onDelete(options, userId) { super._onDelete(options, userId); diff --git a/module/data/item/feature.mjs b/module/data/item/feature.mjs index 31c415dc..9f19eddc 100644 --- a/module/data/item/feature.mjs +++ b/module/data/item/feature.mjs @@ -8,7 +8,8 @@ export default class DHFeature extends BaseDataItem { label: 'TYPES.Item.feature', type: 'feature', hasDescription: true, - hasResource: true + hasResource: true, + possibleItemLink: true }); } @@ -17,13 +18,6 @@ export default class DHFeature extends BaseDataItem { const fields = foundry.data.fields; return { ...super.defineSchema(), - originItemType: new fields.StringField({ - choices: CONFIG.DH.ITEM.featureTypes, - nullable: true, - initial: null - }), - originId: new fields.StringField({ nullable: true, initial: null }), - subType: new fields.StringField({ choices: CONFIG.DH.ITEM.featureSubTypes, nullable: true, initial: null }), actions: new fields.ArrayField(new ActionField()) }; } diff --git a/module/data/item/subclass.mjs b/module/data/item/subclass.mjs index e0a76092..56f59179 100644 --- a/module/data/item/subclass.mjs +++ b/module/data/item/subclass.mjs @@ -7,7 +7,8 @@ export default class DHSubclass extends BaseDataItem { return foundry.utils.mergeObject(super.metadata, { label: 'TYPES.Item.subclass', type: 'subclass', - hasDescription: true + hasDescription: true, + possibleItemLink: true }); } diff --git a/templates/sheets/items/class/settings.hbs b/templates/sheets/items/class/settings.hbs index 756687b4..c3362fb2 100644 --- a/templates/sheets/items/class/settings.hbs +++ b/templates/sheets/items/class/settings.hbs @@ -90,7 +90,7 @@ {{this.name}}
- +
{{/each}} @@ -105,7 +105,7 @@ {{this.name}}
- +
{{/each}} @@ -120,7 +120,7 @@ {{this.name}}
- +
{{/each}}