daggerheart/module/data/item/class.mjs
2025-07-24 22:54:31 +02:00

145 lines
6.4 KiB
JavaScript

import BaseDataItem from './base.mjs';
import ForeignDocumentUUIDField from '../fields/foreignDocumentUUIDField.mjs';
import ForeignDocumentUUIDArrayField from '../fields/foreignDocumentUUIDArrayField.mjs';
import ItemLinkFields from '../fields/itemLinkFields.mjs';
import { addLinkedItemsDiff, updateLinkedItemApps } from '../../helpers/utils.mjs';
export default class DHClass extends BaseDataItem {
/** @inheritDoc */
static get metadata() {
return foundry.utils.mergeObject(super.metadata, {
label: 'TYPES.Item.class',
type: 'class',
hasDescription: true
});
}
/** @inheritDoc */
static defineSchema() {
const fields = foundry.data.fields;
return {
...super.defineSchema(),
domains: new fields.ArrayField(new fields.StringField(), { max: 2 }),
classItems: new ForeignDocumentUUIDArrayField({ type: 'Item', required: false }),
hitPoints: new fields.NumberField({
required: true,
integer: true,
min: 1,
initial: 5,
label: 'DAGGERHEART.GENERAL.HitPoints.plural'
}),
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 }),
choiceB: new ForeignDocumentUUIDArrayField({ type: 'Item', required: false })
}),
characterGuide: new fields.SchemaField({
suggestedTraits: new fields.SchemaField({
agility: new fields.NumberField({ initial: 0, integer: true }),
strength: new fields.NumberField({ initial: 0, integer: true }),
finesse: new fields.NumberField({ initial: 0, integer: true }),
instinct: new fields.NumberField({ initial: 0, integer: true }),
presence: new fields.NumberField({ initial: 0, integer: true }),
knowledge: new fields.NumberField({ initial: 0, integer: true })
}),
suggestedPrimaryWeapon: new ForeignDocumentUUIDField({ type: 'Item' }),
suggestedSecondaryWeapon: new ForeignDocumentUUIDField({ type: 'Item' }),
suggestedArmor: new ForeignDocumentUUIDField({ type: 'Item' })
}),
isMulticlass: new fields.BooleanField({ initial: false })
};
}
get hopeFeatures() {
return this.features.filter(x => x.type === CONFIG.DH.ITEM.featureSubTypes.hope).map(x => x.item);
}
get classFeatures() {
return this.features.filter(x => x.type === CONFIG.DH.ITEM.featureSubTypes.class).map(x => x.item);
}
async _preCreate(data, options, user) {
const allowed = await super._preCreate(data, options, user);
if (allowed === false) return;
if (this.actor?.type === 'character') {
const path = data.system.isMulticlass ? 'system.multiclass.value' : 'system.class.value';
if (foundry.utils.getProperty(this.actor, path)) {
ui.notifications.error(game.i18n.localize('DAGGERHEART.UI.Notifications.classAlreadySelected'));
return false;
}
}
}
_onCreate(data, options, userId) {
super._onCreate(data, options, userId);
if (userId !== game.user.id) return;
if (options.parent?.type === 'character') {
const path = `system.${data.system.isMulticlass ? 'multiclass.value' : 'class.value'}`;
options.parent.update({ [path]: `${options.parent.uuid}.Item.${data._id}` });
}
}
_onDelete(options, userId) {
super._onDelete(options, userId);
if (options.parent?.type === 'character') {
const path = `system.${this.isMulticlass ? 'multiclass' : 'class'}`;
options.parent.update({
[`${path}.value`]: null
});
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;
addLinkedItemsDiff(changed.system?.subclasses, this.subclasses, options, 'changedSubclasses');
const guide = changed.system?.characterGuide;
addLinkedItemsDiff(
guide?.suggestedPrimaryWeapon ? [guide.suggestedPrimaryWeapon] : null,
this.characterGuide.suggestedPrimaryWeapon ? [this.characterGuide.suggestedPrimaryWeapon] : [],
options,
'primaryWeapon'
);
addLinkedItemsDiff(
guide?.suggestedSecondaryWeapon ? [guide.suggestedSecondaryWeapon] : null,
this.characterGuide.suggestedSecondaryWeapon ? [this.characterGuide.suggestedSecondaryWeapon] : [],
options,
'secondaryWeapon'
);
addLinkedItemsDiff(
guide?.suggestedArmor ? [guide.suggestedArmor] : null,
this.characterGuide.suggestedArmor ? [this.characterGuide.suggestedArmor] : [],
options,
'armor'
);
addLinkedItemsDiff(changed.system?.inventory?.take, this.inventory.take, options, 'changedTake');
addLinkedItemsDiff(changed.system?.inventory?.choiceA, this.inventory.choiceA, options, 'changedChoiceA');
addLinkedItemsDiff(changed.system?.inventory?.choiceB, this.inventory.choiceB, options, 'changedChoiceB');
}
_onUpdate(changed, options, userId) {
super._onUpdate(changed, options, userId);
updateLinkedItemApps(options, 'changedSubclasses', this.parent.sheet);
updateLinkedItemApps(options, 'primaryWeapon', this.parent.sheet);
updateLinkedItemApps(options, 'secondaryWeapon', this.parent.sheet);
updateLinkedItemApps(options, 'armor', this.parent.sheet);
updateLinkedItemApps(options, 'changedTake', this.parent.sheet);
updateLinkedItemApps(options, 'changedChoiceA', this.parent.sheet);
updateLinkedItemApps(options, 'changedChoiceB', this.parent.sheet);
}
}