Added use of ItemLinkFields

This commit is contained in:
WBHarry 2025-07-24 04:02:49 +02:00
parent 8cdad5172e
commit 569e567dfd
18 changed files with 232 additions and 288 deletions

View file

@ -340,10 +340,7 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
}) })
}; };
context.traits.nrTotal = Object.keys(context.traits.values).length; context.traits.nrTotal = Object.keys(context.traits.values).length;
context.traits.nrSelected = Object.values(context.traits.values).reduce( context.traits.nrSelected = this.getNrSelectedTrait();
(acc, trait) => acc + (trait.value !== null ? 1 : 0),
0
);
context.experience = { context.experience = {
values: this.setup.experiences, values: this.setup.experiences,
@ -397,6 +394,10 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
choiceA: { suggestions: suggestions.inventory.choiceA, compendium: 'consumables' }, choiceA: { suggestions: suggestions.inventory.choiceA, compendium: 'consumables' },
choiceB: { suggestions: suggestions.inventory.choiceB, compendium: 'general-items' } choiceB: { suggestions: suggestions.inventory.choiceB, compendium: 'general-items' }
}; };
context.noInventoryChoices =
suggestions.inventory.take.length === 0 &&
suggestions.inventory.choiceA?.length === 0 &&
suggestions.inventory.choiceB?.length === 0;
break; break;
} }
@ -427,7 +428,7 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
case 5: case 5:
return Object.values(this.setup.experiences).every(x => x.name) ? 6 : 5; return Object.values(this.setup.experiences).every(x => x.name) ? 6 : 5;
case 4: case 4:
return Object.values(this.setup.traits).every(x => x.value !== null) ? 5 : 4; return this.getNrSelectedTrait() === 6 ? 5 : 4;
case 3: case 3:
return this.setup.class.uuid && this.setup.subclass.uuid ? 4 : 3; return this.setup.class.uuid && this.setup.subclass.uuid ? 4 : 3;
case 2: case 2:
@ -437,6 +438,18 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
} }
} }
getNrSelectedTrait() {
const traitCompareArray = [
...game.settings.get(CONFIG.DH.id, CONFIG.DH.SETTINGS.gameSettings.Homebrew).traitArray
];
return Object.values(this.setup.traits).reduce((acc, x) => {
const index = traitCompareArray.indexOf(x.value);
traitCompareArray.splice(index, 1);
acc += index !== -1;
return acc;
}, 0);
}
async getEquipmentSuggestions(choiceA, choiceB) { async getEquipmentSuggestions(choiceA, choiceB) {
if (!this.setup.class.uuid) return { inventory: { take: [] } }; if (!this.setup.class.uuid) return { inventory: { take: [] } };
@ -448,10 +461,15 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
? { ...characterGuide.suggestedSecondaryWeapon, uuid: characterGuide.suggestedSecondaryWeapon.uuid } ? { ...characterGuide.suggestedSecondaryWeapon, uuid: characterGuide.suggestedSecondaryWeapon.uuid }
: null, : null,
inventory: { inventory: {
take: inventory.take ?? [], take: inventory.take?.filter(x => x) ?? [],
choiceA: choiceA:
inventory.choiceA?.map(x => ({ ...x, uuid: x.uuid, selected: x.uuid === choiceA?.uuid })) ?? [], inventory.choiceA
choiceB: inventory.choiceB?.map(x => ({ ...x, uuid: x.uuid, selected: x.uuid === choiceB?.uuid })) ?? [] ?.filter(x => x)
.map(x => ({ ...x, uuid: x.uuid, selected: x.uuid === choiceA?.uuid })) ?? [],
choiceB:
inventory.choiceB
?.filter(x => x)
.map(x => ({ ...x, uuid: x.uuid, selected: x.uuid === choiceB?.uuid })) ?? []
} }
}; };
} }
@ -525,7 +543,10 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
name: this.setup.ancestryName ?? this.setup.primaryAncestry.name, name: this.setup.ancestryName ?? this.setup.primaryAncestry.name,
system: { system: {
...this.setup.primaryAncestry.system, ...this.setup.primaryAncestry.system,
features: [primaryAncestryFeature.uuid, secondaryAncestryFeature.uuid] features: [
{ type: 'primary', item: primaryAncestryFeature.uuid },
{ type: 'secondary', item: secondaryAncestryFeature.uuid }
]
} }
}; };
@ -554,7 +575,10 @@ export default class DhCharacterCreation extends HandlebarsApplicationMixin(Appl
await this.character.createEmbeddedDocuments('Item', [this.equipment.inventory.choiceA]); await this.character.createEmbeddedDocuments('Item', [this.equipment.inventory.choiceA]);
if (this.equipment.inventory.choiceB.uuid) if (this.equipment.inventory.choiceB.uuid)
await this.character.createEmbeddedDocuments('Item', [this.equipment.inventory.choiceB]); await this.character.createEmbeddedDocuments('Item', [this.equipment.inventory.choiceB]);
await this.character.createEmbeddedDocuments('Item', this.setup.class.system.inventory.take); await this.character.createEmbeddedDocuments(
'Item',
this.setup.class.system.inventory.take.filter(x => x)
);
await this.character.update({ await this.character.update({
system: { system: {

View file

@ -341,7 +341,20 @@ export default function DHApplicationMixin(Base) {
{ {
name: 'CONTROLS.CommonEdit', name: 'CONTROLS.CommonEdit',
icon: 'fa-solid fa-pen-to-square', icon: 'fa-solid fa-pen-to-square',
callback: target => getDocFromElement(target).sheet.render({ force: true }) callback: async target => {
const doc = getDocFromElement(target);
const appId = this.element.id;
doc.apps[appId] = this;
const app = await doc.sheet.render({ force: true });
app.addEventListener(
'close',
() => {
delete doc.apps[appId];
},
{ once: true }
);
return;
}
} }
]; ];
@ -496,9 +509,21 @@ export default function DHApplicationMixin(Base) {
* Renders an embedded document. * Renders an embedded document.
* @type {ApplicationClickAction} * @type {ApplicationClickAction}
*/ */
static #editDoc(_event, target) { static async #editDoc(_event, target) {
const doc = getDocFromElement(target); const doc = getDocFromElement(target);
if (doc) return doc.sheet.render({ force: true }); if (doc) {
const appId = this.element.id;
doc.apps[appId] = this;
const app = await doc.sheet.render({ force: true });
app.addEventListener(
'close',
() => {
delete doc.apps[appId];
},
{ once: true }
);
return;
}
// TODO: REDO this // TODO: REDO this
const { actionId } = target.closest('[data-action-id]').dataset; const { actionId } = target.closest('[data-action-id]').dataset;

View file

@ -178,13 +178,15 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) {
static async #addFeature(_, target) { static async #addFeature(_, target) {
const { type } = target.dataset; const { type } = target.dataset;
const cls = foundry.documents.Item.implementation; const cls = foundry.documents.Item.implementation;
const feature = await cls.create({ const item = await cls.create({
'type': 'feature', type: 'feature',
'name': cls.defaultName({ type: 'feature' }), name: cls.defaultName({ type: 'feature' })
'system.subType': CONFIG.DH.ITEM.featureSubTypes[type]
}); });
await this.document.update({ await this.document.update({
'system.features': [...this.document.system.features, feature].map(f => f.uuid) 'system.features': [...this.document.system.features, { type, item }].map(x => ({
...x,
item: x.item?.uuid
}))
}); });
} }
@ -192,12 +194,14 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) {
* Remove a feature from the item. * Remove a feature from the item.
* @type {ApplicationClickAction} * @type {ApplicationClickAction}
*/ */
static async #deleteFeature(_, target) { static async #deleteFeature(_, element) {
const target = element.closest('[data-item-uuid]');
const feature = getDocFromElement(target); const feature = getDocFromElement(target);
if (!feature) return ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.featureIsMissing')); if (!feature) return ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.featureIsMissing'));
await feature.update({ 'system.subType': null });
await this.document.update({ await this.document.update({
'system.features': this.document.system.features.map(x => x.uuid).filter(uuid => uuid !== feature.uuid) 'system.features': this.document.system.features
.filter(x => target.dataset.type !== x.type || x.item.uuid !== feature.uuid)
.map(x => ({ ...x, item: x.item.uuid }))
}); });
} }
@ -270,10 +274,15 @@ export default class DHBaseItemSheet extends DHApplicationMixin(ItemSheetV2) {
const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event); const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event);
if (data.fromInternal) return; if (data.fromInternal) return;
const target = event.target.closest('fieldset.drop-section');
const item = await fromUuid(data.uuid); const item = await fromUuid(data.uuid);
if (item?.type === 'feature') { if (item?.type === 'feature') {
const current = this.document.system.features.map(x => x.uuid); await this.document.update({
await this.document.update({ 'system.features': [...current, item.uuid] }); 'system.features': [...this.document.system.features, { type: target.dataset.type, item }].map(x => ({
...x,
item: x.item?.uuid
}))
});
} }
} }
} }

View file

@ -3,12 +3,7 @@ import DHHeritageSheet from '../api/heritage-sheet.mjs';
export default class AncestrySheet extends DHHeritageSheet { export default class AncestrySheet extends DHHeritageSheet {
/**@inheritdoc */ /**@inheritdoc */
static DEFAULT_OPTIONS = { static DEFAULT_OPTIONS = {
classes: ['ancestry'], classes: ['ancestry']
actions: {
editFeature: AncestrySheet.#editFeature,
removeFeature: AncestrySheet.#removeFeature
},
dragDrop: [{ dragSelector: null, dropSelector: '.tab.features .drop-section' }]
}; };
/**@inheritdoc */ /**@inheritdoc */
@ -18,40 +13,6 @@ export default class AncestrySheet extends DHHeritageSheet {
features: { template: 'systems/daggerheart/templates/sheets/items/ancestry/features.hbs' } features: { template: 'systems/daggerheart/templates/sheets/items/ancestry/features.hbs' }
}; };
/* -------------------------------------------- */
/* Application Clicks Actions */
/* -------------------------------------------- */
/**
* Edit an existing feature on the item
* @type {ApplicationClickAction}
*/
static async #editFeature(_event, button) {
const target = button.closest('.feature-item');
const feature = this.document.system[`${target.dataset.type}Feature`];
if (!feature || Object.keys(feature).length === 0) {
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.featureIsMissing'));
return;
}
feature.sheet.render(true);
}
/**
* Remove a feature from the item.
* @type {ApplicationClickAction}
*/
static async #removeFeature(event, button) {
event.stopPropagation();
const target = button.closest('.feature-item');
const feature = this.document.system[`${target.dataset.type}Feature`];
if (feature) await feature.update({ 'system.subType': null });
await this.document.update({
'system.features': this.document.system.features.filter(x => x && x.uuid !== feature.uuid).map(x => x.uuid)
});
}
/* -------------------------------------------- */ /* -------------------------------------------- */
/* Application Drag/Drop */ /* Application Drag/Drop */
/* -------------------------------------------- */ /* -------------------------------------------- */
@ -61,22 +22,12 @@ export default class AncestrySheet extends DHHeritageSheet {
* @param {DragEvent} event - The drag event * @param {DragEvent} event - The drag event
*/ */
async _onDrop(event) { async _onDrop(event) {
event.stopPropagation(); const target = event.target.closest('fieldset.drop-section');
const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event); const typeField =
this.document.system[target.dataset.type === 'primary' ? 'primaryFeature' : 'secondaryFeature'];
const item = await fromUuid(data.uuid); if (!typeField) {
if (item?.type === 'feature') { super._onDrop(event);
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;
}
await item.update({ 'system.subType': subType });
await this.document.update({
'system.features': [...this.document.system.features.map(x => x.uuid), item.uuid]
});
} }
} }
} }

View file

@ -87,69 +87,45 @@ export default class ClassSheet extends DHBaseItemSheet {
'system.subclasses': [...this.document.system.subclasses.map(x => x.uuid), item.uuid] 'system.subclasses': [...this.document.system.subclasses.map(x => x.uuid), item.uuid]
}); });
} else if (item.type === 'feature') { } else if (item.type === 'feature') {
if (target.classList.contains('hope-feature')) { super._onDrop(event);
if (item.system.subType && item.system.subType !== CONFIG.DH.ITEM.featureSubTypes.hope) {
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.featureNotHope'));
return;
}
await item.update({ 'system.subType': CONFIG.DH.ITEM.featureSubTypes.hope });
await this.document.update({
'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 });
await this.document.update({
'system.features': [...this.document.system.features.map(x => x.uuid), item.uuid]
});
}
} else if (item.type === 'weapon') { } else if (item.type === 'weapon') {
if (target.classList.contains('primary-weapon-section')) { if (target.classList.contains('primary-weapon-section')) {
if (!this.document.system.characterGuide.suggestedPrimaryWeapon && !item.system.secondary) if (!item.system.secondary)
await this.document.update({ await this.document.update({
'system.characterGuide.suggestedPrimaryWeapon': item.uuid 'system.characterGuide.suggestedPrimaryWeapon': item.uuid
}); });
} else if (target.classList.contains('secondary-weapon-section')) { } else if (target.classList.contains('secondary-weapon-section')) {
if (!this.document.system.characterGuide.suggestedSecondaryWeapon && item.system.secondary) if (item.system.secondary)
await this.document.update({ await this.document.update({
'system.characterGuide.suggestedSecondaryWeapon': item.uuid 'system.characterGuide.suggestedSecondaryWeapon': item.uuid
}); });
} }
} else if (item.type === 'armor') { } else if (item.type === 'armor') {
if (target.classList.contains('armor-section')) { if (target.classList.contains('armor-section')) {
if (!this.document.system.characterGuide.suggestedArmor)
await this.document.update({ await this.document.update({
'system.characterGuide.suggestedArmor': item.uuid 'system.characterGuide.suggestedArmor': item.uuid
}); });
} }
} else if (target.classList.contains('choice-a-section')) { } else if (target.classList.contains('choice-a-section')) {
if (item.type === 'miscellaneous' || item.type === 'consumable') { if (item.type === 'miscellaneous' || item.type === 'consumable') {
if (this.document.system.inventory.choiceA.length < 2) const filteredChoiceA = this.document.system.inventory.choiceA;
if (filteredChoiceA.length < 2)
await this.document.update({ await this.document.update({
'system.inventory.choiceA': [ 'system.inventory.choiceA': [...filteredChoiceA.map(x => x.uuid), item.uuid]
...this.document.system.inventory.choiceA.map(x => x.uuid),
item.uuid
]
}); });
} }
} else if (item.type === 'miscellaneous') { } else if (item.type === 'miscellaneous') {
if (target.classList.contains('take-section')) { if (target.classList.contains('take-section')) {
if (this.document.system.inventory.take.length < 3) const filteredTake = this.document.system.inventory.take.filter(x => x);
if (filteredTake.length < 3)
await this.document.update({ await this.document.update({
'system.inventory.take': [...this.document.system.inventory.take.map(x => x.uuid), item.uuid] 'system.inventory.take': [...filteredTake.map(x => x.uuid), item.uuid]
}); });
} else if (target.classList.contains('choice-b-section')) { } else if (target.classList.contains('choice-b-section')) {
if (this.document.system.inventory.choiceB.length < 2) const filteredChoiceB = this.document.system.inventory.choiceB.filter(x => x);
if (filteredChoiceB.length < 2)
await this.document.update({ await this.document.update({
'system.inventory.choiceB': [ 'system.inventory.choiceB': [...filteredChoiceB.map(x => x.uuid), item.uuid]
...this.document.system.inventory.choiceB.map(x => x.uuid),
item.uuid
]
}); });
} }
} }
@ -167,7 +143,7 @@ export default class ClassSheet extends DHBaseItemSheet {
static async #removeItemFromCollection(_event, element) { static async #removeItemFromCollection(_event, element) {
const { uuid, target } = element.dataset; const { uuid, target } = element.dataset;
const prop = foundry.utils.getProperty(this.document.system, target); const prop = foundry.utils.getProperty(this.document.system, target);
await this.document.update({ [`system.${target}`]: prop.filter(i => i.uuid !== uuid) }); await this.document.update({ [`system.${target}`]: prop.filter(i => i.uuid !== uuid).map(x => x.uuid) });
} }
/** /**

View file

@ -5,8 +5,7 @@ export default class SubclassSheet extends DHBaseItemSheet {
static DEFAULT_OPTIONS = { static DEFAULT_OPTIONS = {
classes: ['subclass'], classes: ['subclass'],
position: { width: 600 }, position: { width: 600 },
window: { resizable: false }, window: { resizable: false }
actions: {}
}; };
/**@override */ /**@override */
@ -36,63 +35,4 @@ export default class SubclassSheet extends DHBaseItemSheet {
labelPrefix: 'DAGGERHEART.GENERAL.Tabs' labelPrefix: 'DAGGERHEART.GENERAL.Tabs'
} }
}; };
async _onDragStart(event) {
const featureItem = event.currentTarget.closest('.drop-section');
if (featureItem) {
const feature = this.document.system[featureItem.dataset.type];
if (!feature) {
ui.notifications.warn(game.i18n.localize('DAGGERHEART.UI.Notifications.featureIsMissing'));
return;
}
const featureData = { type: 'Item', data: { ...feature.toObject(), _id: null }, fromInternal: true };
event.dataTransfer.setData('text/plain', JSON.stringify(featureData));
event.dataTransfer.setDragImage(featureItem.querySelector('img'), 60, 0);
}
}
async _onDrop(event) {
event.stopPropagation();
const data = foundry.applications.ux.TextEditor.implementation.getDragEventData(event);
if (data.fromInternal) return;
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;
}
await item.update({ 'system.subType': CONFIG.DH.ITEM.featureSubTypes.foundation });
await this.document.update({
'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 });
await this.document.update({
'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 });
await this.document.update({
'system.features': [...this.document.system.features.map(x => x.uuid), item.uuid]
});
}
}
}
} }

View file

@ -23,7 +23,10 @@ export default class ForeignDocumentUUIDField extends foundry.data.fields.Docume
/**@override */ /**@override */
initialize(value, _model, _options = {}) { initialize(value, _model, _options = {}) {
if (this.idOnly) return value; if (this.idOnly) return value;
return () => { return () => ForeignDocumentUUIDField.getInitializedField(value);
}
static getInitializedField(value) {
try { try {
const doc = fromUuidSync(value); const doc = fromUuidSync(value);
return doc; return doc;
@ -31,7 +34,6 @@ export default class ForeignDocumentUUIDField extends foundry.data.fields.Docume
console.error(error); console.error(error);
return value ?? null; return value ?? null;
} }
};
} }
/**@override */ /**@override */

View file

@ -0,0 +1,19 @@
import ForeignDocumentUUIDField from './foreignDocumentUUIDField.mjs';
export default class ItemLinkFields extends foundry.data.fields.ArrayField {
constructor(options, context) {
super(new ItemLinkField(), options, context);
}
}
class ItemLinkField extends foundry.data.fields.SchemaField {
constructor(context) {
super(
{
type: new foundry.data.fields.StringField({ choices: CONFIG.DH.ITEM.featureSubTypes, nullable: true }),
item: new ForeignDocumentUUIDField({ type: 'Item' })
},
context
);
}
}

View file

@ -1,5 +1,5 @@
import ForeignDocumentUUIDArrayField from '../fields/foreignDocumentUUIDArrayField.mjs';
import BaseDataItem from './base.mjs'; import BaseDataItem from './base.mjs';
import ItemLinkFields from '../../data/fields/itemLinkFields.mjs';
export default class DHAncestry extends BaseDataItem { export default class DHAncestry extends BaseDataItem {
/** @inheritDoc */ /** @inheritDoc */
@ -15,23 +15,15 @@ export default class DHAncestry extends BaseDataItem {
static defineSchema() { static defineSchema() {
return { return {
...super.defineSchema(), ...super.defineSchema(),
features: new ForeignDocumentUUIDArrayField({ type: 'Item' }) features: new ItemLinkFields()
}; };
} }
get primaryFeature() { get primaryFeature() {
return ( return this.features.find(x => x.type === CONFIG.DH.ITEM.featureSubTypes.primary)?.item;
this.features.find(x => x?.system?.subType === CONFIG.DH.ITEM.featureSubTypes.primary) ??
(this.features.filter(x => !x).length > 0 ? {} : null)
);
} }
get secondaryFeature() { get secondaryFeature() {
return ( return this.features.find(x => x.type === CONFIG.DH.ITEM.featureSubTypes.secondary)?.item;
this.features.find(x => x?.system?.subType === CONFIG.DH.ITEM.featureSubTypes.secondary) ??
(this.features.filter(x => !x || x.system.subType === CONFIG.DH.ITEM.featureSubTypes.primary).length > 1
? {}
: null)
);
} }
} }

View file

@ -124,12 +124,13 @@ export default class BaseDataItem extends foundry.abstract.TypeDataModel {
this.actor.createEmbeddedDocuments( this.actor.createEmbeddedDocuments(
'Item', 'Item',
this.features.map(feature => ({ this.features.map(feature => ({
...feature, ...(feature.item ?? feature),
system: { system: {
...feature.system, ...(feature.item?.system ?? feature.system),
originItemType: this.parent.type, originItemType: this.parent.type,
originId: data._id, originId: data._id,
identifier: feature.identifier identifier: feature.identifier,
subType: feature.item ? feature.type : undefined
} }
})) }))
); );

View file

@ -1,6 +1,7 @@
import BaseDataItem from './base.mjs'; import BaseDataItem from './base.mjs';
import ForeignDocumentUUIDField from '../fields/foreignDocumentUUIDField.mjs'; import ForeignDocumentUUIDField from '../fields/foreignDocumentUUIDField.mjs';
import ForeignDocumentUUIDArrayField from '../fields/foreignDocumentUUIDArrayField.mjs'; import ForeignDocumentUUIDArrayField from '../fields/foreignDocumentUUIDArrayField.mjs';
import ItemLinkFields from '../fields/itemLinkFields.mjs';
export default class DHClass extends BaseDataItem { export default class DHClass extends BaseDataItem {
/** @inheritDoc */ /** @inheritDoc */
@ -27,7 +28,7 @@ export default class DHClass extends BaseDataItem {
label: 'DAGGERHEART.GENERAL.HitPoints.plural' label: 'DAGGERHEART.GENERAL.HitPoints.plural'
}), }),
evasion: new fields.NumberField({ initial: 0, integer: true, label: 'DAGGERHEART.GENERAL.evasion' }), evasion: new fields.NumberField({ initial: 0, integer: true, label: 'DAGGERHEART.GENERAL.evasion' }),
features: new ForeignDocumentUUIDArrayField({ type: 'Item' }), features: new ItemLinkFields(),
subclasses: new ForeignDocumentUUIDArrayField({ type: 'Item', required: false }), subclasses: new ForeignDocumentUUIDArrayField({ type: 'Item', required: false }),
inventory: new fields.SchemaField({ inventory: new fields.SchemaField({
take: new ForeignDocumentUUIDArrayField({ type: 'Item', required: false }), take: new ForeignDocumentUUIDArrayField({ type: 'Item', required: false }),
@ -52,17 +53,11 @@ export default class DHClass extends BaseDataItem {
} }
get hopeFeatures() { get hopeFeatures() {
return ( return this.features.filter(x => x.type === CONFIG.DH.ITEM.featureSubTypes.hope).map(x => x.item);
this.features.filter(x => x?.system?.subType === CONFIG.DH.ITEM.featureSubTypes.hope) ??
(this.features.filter(x => !x).length > 0 ? {} : null)
);
} }
get classFeatures() { get classFeatures() {
return ( return this.features.filter(x => x.type === CONFIG.DH.ITEM.featureSubTypes.class).map(x => x.item);
this.features.filter(x => x?.system?.subType === CONFIG.DH.ITEM.featureSubTypes.class) ??
(this.features.filter(x => !x).length > 0 ? {} : null)
);
} }
async _preCreate(data, options, user) { async _preCreate(data, options, user) {

View file

@ -1,4 +1,4 @@
import ForeignDocumentUUIDArrayField from '../fields/foreignDocumentUUIDArrayField.mjs'; import ItemLinkFields from '../fields/itemLinkFields.mjs';
import BaseDataItem from './base.mjs'; import BaseDataItem from './base.mjs';
export default class DHSubclass extends BaseDataItem { export default class DHSubclass extends BaseDataItem {
@ -22,22 +22,22 @@ export default class DHSubclass extends BaseDataItem {
nullable: true, nullable: true,
initial: null initial: null
}), }),
features: new ForeignDocumentUUIDArrayField({ type: 'Item' }), features: new ItemLinkFields(),
featureState: new fields.NumberField({ required: true, initial: 1, min: 1 }), featureState: new fields.NumberField({ required: true, initial: 1, min: 1 }),
isMulticlass: new fields.BooleanField({ initial: false }) isMulticlass: new fields.BooleanField({ initial: false })
}; };
} }
get foundationFeatures() { get foundationFeatures() {
return this.features.filter(x => x.system.subType === CONFIG.DH.ITEM.featureSubTypes.foundation); return this.features.filter(x => x.type === CONFIG.DH.ITEM.featureSubTypes.foundation).map(x => x.item);
} }
get specializationFeatures() { get specializationFeatures() {
return this.features.filter(x => x.system.subType === CONFIG.DH.ITEM.featureSubTypes.specialization); return this.features.filter(x => x.type === CONFIG.DH.ITEM.featureSubTypes.specialization).map(x => x.item);
} }
get masteryFeatures() { get masteryFeatures() {
return this.features.filter(x => x.system.subType === CONFIG.DH.ITEM.featureSubTypes.mastery); return this.features.filter(x => x.type === CONFIG.DH.ITEM.featureSubTypes.mastery).map(x => x.item);
} }
async _preCreate(data, options, user) { async _preCreate(data, options, user) {

View file

@ -13,7 +13,7 @@
{{localize "DAGGERHEART.APPLICATIONS.CharacterCreation.selectArmor"}} {{localize "DAGGERHEART.APPLICATIONS.CharacterCreation.selectArmor"}}
{{/"systems/daggerheart/templates/components/card-preview.hbs"}} {{/"systems/daggerheart/templates/components/card-preview.hbs"}}
</div> </div>
{{#if armor.suggestion}} {{#if armor.suggestion.name}}
<fieldset class="suggestion-container"> <fieldset class="suggestion-container">
<legend>{{armor.suggestion.name}}</legend> <legend>{{armor.suggestion.name}}</legend>
<div class="suggestion-inner-container {{#if armor.suggestion.taken}}taken{{/if}}" data-action="viewItem" data-uuid="{{armor.suggestion.uuid}}"> <div class="suggestion-inner-container {{#if armor.suggestion.taken}}taken{{/if}}" data-action="viewItem" data-uuid="{{armor.suggestion.uuid}}">
@ -33,7 +33,7 @@
{{localize "DAGGERHEART.APPLICATIONS.CharacterCreation.selectPrimaryWeapon"}} {{localize "DAGGERHEART.APPLICATIONS.CharacterCreation.selectPrimaryWeapon"}}
{{/"systems/daggerheart/templates/components/card-preview.hbs"}} {{/"systems/daggerheart/templates/components/card-preview.hbs"}}
</div> </div>
{{#if primaryWeapon.suggestion}} {{#if primaryWeapon.suggestion.name}}
<fieldset class="suggestion-container"> <fieldset class="suggestion-container">
<legend>{{primaryWeapon.suggestion.name}}</legend> <legend>{{primaryWeapon.suggestion.name}}</legend>
<div class="suggestion-inner-container {{#if primaryWeapon.suggestion.taken}}taken{{/if}}" data-action="viewItem" data-uuid="{{primaryWeapon.suggestion.uuid}}"> <div class="suggestion-inner-container {{#if primaryWeapon.suggestion.taken}}taken{{/if}}" data-action="viewItem" data-uuid="{{primaryWeapon.suggestion.uuid}}">
@ -48,7 +48,7 @@
{{localize "DAGGERHEART.APPLICATIONS.CharacterCreation.selectSecondaryWeapon"}} {{localize "DAGGERHEART.APPLICATIONS.CharacterCreation.selectSecondaryWeapon"}}
{{/"systems/daggerheart/templates/components/card-preview.hbs"}} {{/"systems/daggerheart/templates/components/card-preview.hbs"}}
</div> </div>
{{#if secondaryWeapon.suggestion}} {{#if secondaryWeapon.suggestion.name}}
<fieldset class="suggestion-container"> <fieldset class="suggestion-container">
<legend>{{secondaryWeapon.suggestion.name}}</legend> <legend>{{secondaryWeapon.suggestion.name}}</legend>
<div <div
@ -63,6 +63,7 @@
</div> </div>
</fieldset> </fieldset>
</div> </div>
{{#unless noInventoryChoices}}
<div class="main-equipment-selection triple"> <div class="main-equipment-selection triple">
<fieldset class="equipment-selection"> <fieldset class="equipment-selection">
<legend>{{localize "DAGGERHEART.APPLICATIONS.CharacterCreation.startingItems"}}</legend> <legend>{{localize "DAGGERHEART.APPLICATIONS.CharacterCreation.startingItems"}}</legend>
@ -103,5 +104,6 @@
</div> </div>
</fieldset> </fieldset>
</div> </div>
{{/unless}}
</div> </div>
</section> </section>

View file

@ -1,4 +1,4 @@
<li class='feature-item' data-item-uuid='{{feature.uuid}}'> <li class='feature-item' data-item-uuid='{{feature.uuid}}' data-type="{{type}}">
<div class='feature-line'> <div class='feature-line'>
<img class='image' src='{{feature.img}}' /> <img class='image' src='{{feature.img}}' />
<h4> <h4>

View file

@ -3,7 +3,7 @@
data-tab='{{tabs.features.id}}' data-tab='{{tabs.features.id}}'
data-group='{{tabs.features.group}}' data-group='{{tabs.features.group}}'
> >
<fieldset class="one-column drop-section primary-feature"> <fieldset class="one-column drop-section primary-feature" data-type="primary">
<legend> <legend>
{{localize "DAGGERHEART.ITEMS.Ancestry.primaryFeature"}} {{localize "DAGGERHEART.ITEMS.Ancestry.primaryFeature"}}
{{#unless document.system.primaryFeature}}<a><i data-action="addFeature" data-type="primary" class="fa-solid fa-plus icon-button"></i></a>{{/unless}} {{#unless document.system.primaryFeature}}<a><i data-action="addFeature" data-type="primary" class="fa-solid fa-plus icon-button"></i></a>{{/unless}}
@ -11,20 +11,21 @@
<div class="features-list"> <div class="features-list">
{{#if document.system.primaryFeature}} {{#if document.system.primaryFeature}}
<div class="feature-item" <div class="feature-item"
data-action="editFeature" data-action="editDoc"
data-item-uuid="{{document.system.primaryFeature.uuid}}"
data-type="primary" data-type="primary"
> >
<img class="image" src="{{document.system.primaryFeature.img}}" /> <img class="image" src="{{document.system.primaryFeature.img}}" />
<span>{{document.system.primaryFeature.name}}</span> <span>{{document.system.primaryFeature.name}}</span>
<div class="controls"> <div class="controls">
<a data-action="removeFeature" data-type="primary"><i class="fa-solid fa-trash"></i></a> <a data-action="deleteFeature"><i class="fa-solid fa-trash"></i></a>
</div> </div>
</div> </div>
{{/if}} {{/if}}
</div> </div>
</fieldset> </fieldset>
<fieldset class="one-column drop-section secondary-feature"> <fieldset class="one-column drop-section secondary-feature" data-type="secondary">
<legend> <legend>
{{localize "DAGGERHEART.ITEMS.Ancestry.secondaryFeature"}} {{localize "DAGGERHEART.ITEMS.Ancestry.secondaryFeature"}}
{{#unless document.system.secondaryFeature}}<a><i data-action="addFeature" data-type="secondary" class="fa-solid fa-plus icon-button"></i></a>{{/unless}} {{#unless document.system.secondaryFeature}}<a><i data-action="addFeature" data-type="secondary" class="fa-solid fa-plus icon-button"></i></a>{{/unless}}
@ -32,13 +33,14 @@
<div class="features-list"> <div class="features-list">
{{#if document.system.secondaryFeature}} {{#if document.system.secondaryFeature}}
<div class="feature-item" <div class="feature-item"
data-action="editFeature" data-action="editDoc"
data-item-uuid="{{document.system.secondaryFeature.uuid}}"
data-type="secondary" data-type="secondary"
> >
<img class="image" src="{{document.system.secondaryFeature.img}}" /> <img class="image" src="{{document.system.secondaryFeature.img}}" />
<span>{{document.system.secondaryFeature.name}}</span> <span>{{document.system.secondaryFeature.name}}</span>
<div class="controls"> <div class="controls">
<a data-action="removeFeature" data-type="secondary"><i class="fa-solid fa-trash"></i></a> <a data-action="deleteFeature"><i class="fa-solid fa-trash"></i></a>
</div> </div>
</div> </div>
{{/if}} {{/if}}

View file

@ -4,7 +4,7 @@
data-group='{{tabs.features.group}}' data-group='{{tabs.features.group}}'
> >
<div class="two-columns even"> <div class="two-columns even">
<fieldset class="drop-section hope-feature"> <fieldset class="drop-section hope-feature" data-type='hope'>
<legend>{{localize "DAGGERHEART.ITEMS.Class.hopeFeatures"}} <a><i class="fa-solid fa-plus icon-button" data-type="hope" data-action="addFeature"></i></a></legend> <legend>{{localize "DAGGERHEART.ITEMS.Class.hopeFeatures"}} <a><i class="fa-solid fa-plus icon-button" data-type="hope" data-action="addFeature"></i></a></legend>
<div class="feature-list"> <div class="feature-list">
{{#each source.system.hopeFeatures as |feature|}} {{#each source.system.hopeFeatures as |feature|}}
@ -13,7 +13,7 @@
</div> </div>
</fieldset> </fieldset>
<fieldset class="drop-section class-feature"> <fieldset class="drop-section class-feature" data-type='class'>
<legend>{{localize "DAGGERHEART.ITEMS.Class.classFeatures"}} <a><i class="fa-solid fa-plus icon-button" data-type="class" data-action="addFeature"></i></a></legend> <legend>{{localize "DAGGERHEART.ITEMS.Class.classFeatures"}} <a><i class="fa-solid fa-plus icon-button" data-type="class" data-action="addFeature"></i></a></legend>
<div class="feature-list"> <div class="feature-list">
{{#each source.system.classFeatures as |feature|}} {{#each source.system.classFeatures as |feature|}}
@ -36,8 +36,8 @@
<div class='controls'> <div class='controls'>
<a <a
class='effect-control' class='effect-control'
data-action='viewDoc' data-action='editDoc'
data-uuid={{subclass.uuid}} data-item-uuid={{subclass.uuid}}
data-tooltip='{{localize "DAGGERHEART.UI.Tooltip.openItemWorld"}}' data-tooltip='{{localize "DAGGERHEART.UI.Tooltip.openItemWorld"}}'
> >
<i class="fa-solid fa-globe"></i> <i class="fa-solid fa-globe"></i>

View file

@ -42,7 +42,7 @@
<img class="image" src="{{document.system.characterGuide.suggestedPrimaryWeapon.img}}" /> <img class="image" src="{{document.system.characterGuide.suggestedPrimaryWeapon.img}}" />
<span>{{document.system.characterGuide.suggestedPrimaryWeapon.name}}</span> <span>{{document.system.characterGuide.suggestedPrimaryWeapon.name}}</span>
<div class="controls"> <div class="controls">
<i data-action="removeSuggestedItem" data-target="suggestedPrimaryWeapon" class="fa-solid fa-trash icon-button"></i> <a><i data-action="removeSuggestedItem" data-target="suggestedPrimaryWeapon" class="fa-solid fa-trash icon-button"></i></a>
</div> </div>
</div> </div>
{{/if}} {{/if}}
@ -57,7 +57,7 @@
<img class="image" src="{{document.system.characterGuide.suggestedSecondaryWeapon.img}}" /> <img class="image" src="{{document.system.characterGuide.suggestedSecondaryWeapon.img}}" />
<span>{{document.system.characterGuide.suggestedSecondaryWeapon.name}}</span> <span>{{document.system.characterGuide.suggestedSecondaryWeapon.name}}</span>
<div class="controls"> <div class="controls">
<i data-action="removeSuggestedItem" data-target="suggestedSecondaryWeapon" class="fa-solid fa-trash icon-button"></i> <a><i data-action="removeSuggestedItem" data-target="suggestedSecondaryWeapon" class="fa-solid fa-trash icon-button"></i></a>
</div> </div>
</div> </div>
{{/if}} {{/if}}
@ -72,7 +72,7 @@
<img class="image" src="{{document.system.characterGuide.suggestedArmor.img}}" /> <img class="image" src="{{document.system.characterGuide.suggestedArmor.img}}" />
<span>{{document.system.characterGuide.suggestedArmor.name}}</span> <span>{{document.system.characterGuide.suggestedArmor.name}}</span>
<div class="controls"> <div class="controls">
<i data-action="removeSuggestedItem" data-target="suggestedArmor" class="fa-solid fa-trash icon-button"></i> <a><i data-action="removeSuggestedItem" data-target="suggestedArmor" class="fa-solid fa-trash icon-button"></i></a>
</div> </div>
</div> </div>
{{/if}} {{/if}}
@ -86,13 +86,15 @@
<legend>{{localize "DAGGERHEART.GENERAL.take"}}</legend> <legend>{{localize "DAGGERHEART.GENERAL.take"}}</legend>
<div class="drop-section-body list-items"> <div class="drop-section-body list-items">
{{#each source.system.inventory.take}} {{#each source.system.inventory.take}}
{{#if this}}
<div class="suggested-item item-line" data-action="editDoc" data-item-uuid="{{this.uuid}}"> <div class="suggested-item item-line" data-action="editDoc" data-item-uuid="{{this.uuid}}">
<img class="image" src="{{this.img}}" /> <img class="image" src="{{this.img}}" />
<span>{{this.name}}</span> <span>{{this.name}}</span>
<div class="controls"> <div class="controls">
<i data-action="removeItemFromCollection" data-target="invetory.take" data-uuid="{{this.uuid}}" class="fa-solid fa-trash icon-button"></i> <a><i data-action="removeItemFromCollection" data-target="inventory.take" data-uuid="{{this.uuid}}" class="fa-solid fa-trash icon-button"></i></a>
</div> </div>
</div> </div>
{{/if}}
{{/each}} {{/each}}
</div> </div>
</fieldset> </fieldset>
@ -101,13 +103,15 @@
<legend>{{localize "DAGGERHEART.ITEMS.Class.guide.inventory.thenChoose"}}</legend> <legend>{{localize "DAGGERHEART.ITEMS.Class.guide.inventory.thenChoose"}}</legend>
<div class="drop-section-body list-items"> <div class="drop-section-body list-items">
{{#each source.system.inventory.choiceA}} {{#each source.system.inventory.choiceA}}
{{#if this}}
<div class="suggested-item item-line" data-action="editDoc" data-item-uuid="{{this.uuid}}"> <div class="suggested-item item-line" data-action="editDoc" data-item-uuid="{{this.uuid}}">
<img class="image" src="{{this.img}}" /> <img class="image" src="{{this.img}}" />
<span>{{this.name}}</span> <span>{{this.name}}</span>
<div class="controls"> <div class="controls">
<i data-action="removeItemFromCollection" data-target="invetory.choiceA" data-uuid="{{this.uuid}}" class="fa-solid fa-trash icon-button"></i> <a><i data-action="removeItemFromCollection" data-target="inventory.choiceA" data-uuid="{{this.uuid}}" class="fa-solid fa-trash icon-button"></i></a>
</div> </div>
</div> </div>
{{/if}}
{{/each}} {{/each}}
</div> </div>
</fieldset> </fieldset>
@ -116,13 +120,15 @@
<legend>{{localize "DAGGERHEART.ITEMS.Class.guide.inventory.andEither"}}</legend> <legend>{{localize "DAGGERHEART.ITEMS.Class.guide.inventory.andEither"}}</legend>
<div class="drop-section-body list-items"> <div class="drop-section-body list-items">
{{#each source.system.inventory.choiceB}} {{#each source.system.inventory.choiceB}}
{{#if this}}
<div class="suggested-item item-line" data-action="editDoc" data-item-uuid="{{this.uuid}}"> <div class="suggested-item item-line" data-action="editDoc" data-item-uuid="{{this.uuid}}">
<img class="image" src="{{this.img}}" /> <img class="image" src="{{this.img}}" />
<span>{{this.name}}</span> <span>{{this.name}}</span>
<div class="controls"> <div class="controls">
<i data-action="removeItemFromCollection" data-target="invetory.choiceB" data-uuid="{{this.uuid}}" class="fa-solid fa-trash icon-button"></i> <a><i data-action="removeItemFromCollection" data-target="inventory.choiceB" data-uuid="{{this.uuid}}" class="fa-solid fa-trash icon-button"></i></a>
</div> </div>
</div> </div>
{{/if}}
{{/each}} {{/each}}
</div> </div>
</fieldset> </fieldset>

View file

@ -20,7 +20,7 @@
<fieldset class="two-columns"> <fieldset class="two-columns">
{{#with systemFields.attack.fields.damage.fields.parts.element.fields as | fields | }} {{#with systemFields.attack.fields.damage.fields.parts.element.fields as | fields | }}
{{#with (lookup ../document.system.attack.damage.parts 0) as | source | }} {{#with (lookup ../document.system.attack.damage.parts 0) as | source | }}
<legend>{{localize "DAGGERHEART.GENERAL.title"}}</legend> <legend>{{localize "DAGGERHEART.GENERAL.damage"}}</legend>
<span>{{localize "DAGGERHEART.GENERAL.Dice.single"}}</span> <span>{{localize "DAGGERHEART.GENERAL.Dice.single"}}</span>
{{formInput fields.value.fields.dice value=source.value.dice name="system.attack.damage.parts.0.value.dice"}} {{formInput fields.value.fields.dice value=source.value.dice name="system.attack.damage.parts.0.value.dice"}}
<span>{{localize "DAGGERHEART.GENERAL.bonus"}}</span> <span>{{localize "DAGGERHEART.GENERAL.bonus"}}</span>