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}}