[Feature] Item Description Enrichment (#1666)

* Added enrichment for Ancestries and Communities

* Fixed remainder

* Bit of padding

* Increased left padding
This commit is contained in:
WBHarry 2026-02-22 21:32:35 +01:00 committed by GitHub
parent 267de9a8cf
commit 56cc16b39a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
53 changed files with 350 additions and 54 deletions

View file

@ -1,5 +1,6 @@
import BaseDataItem from './base.mjs';
import ItemLinkFields from '../../data/fields/itemLinkFields.mjs';
import { getFeaturesHTMLData } from '../../helpers/utils.mjs';
export default class DHAncestry extends BaseDataItem {
/** @inheritDoc */
@ -19,7 +20,6 @@ export default class DHAncestry extends BaseDataItem {
};
}
/* -------------------------------------------- */
/**@override */
@ -42,4 +42,18 @@ export default class DHAncestry extends BaseDataItem {
get secondaryFeature() {
return this.features.find(x => x.type === CONFIG.DH.ITEM.featureSubTypes.secondary)?.item;
}
/**@inheritdoc */
async getDescriptionData() {
const baseDescription = this.description;
const features = await getFeaturesHTMLData(this.features);
if (!features.length) return { prefix: null, value: baseDescription, suffix: null };
const suffix = await foundry.applications.handlebars.renderTemplate(
'systems/daggerheart/templates/sheets/items/description.hbs',
{ label: 'DAGGERHEART.ITEMS.Ancestry.featuresLabel', features }
);
return { prefix: null, value: baseDescription, suffix };
}
}

View file

@ -59,11 +59,10 @@ export default class DHArmor extends AttachableItem {
const baseDescription = this.description;
const allFeatures = CONFIG.DH.ITEM.allArmorFeatures();
const features = this.armorFeatures.map(x => allFeatures[x.value]);
if (!features.length) return { prefix: null, value: baseDescription, suffix: null };
const prefix = await foundry.applications.handlebars.renderTemplate(
'systems/daggerheart/templates/sheets/items/armor/description.hbs',
{ features }
{ item: this.parent, features }
);
return { prefix, value: baseDescription, suffix: null };

View file

@ -2,7 +2,7 @@ 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';
import { addLinkedItemsDiff, getFeaturesHTMLData, updateLinkedItemApps } from '../../helpers/utils.mjs';
export default class DHClass extends BaseDataItem {
/** @inheritDoc */
@ -163,4 +163,56 @@ export default class DHClass extends BaseDataItem {
updateLinkedItemApps(options, this.parent.sheet);
}
/**@inheritdoc */
async getDescriptionData() {
const baseDescription = this.description;
const getDomainLabel = domain => {
const data = CONFIG.DH.DOMAIN.allDomains()[domain];
return data ? game.i18n.localize(data.label) : '';
};
let domainsLabel = '';
if (this.domains.length) {
if (this.domains.length === 1) domainsLabel = getDomainLabel(this.domains[0]);
else {
const firstDomains = this.domains
.slice(0, this.domains.length - 1)
.map(getDomainLabel)
.join(', ');
const lastDomain = getDomainLabel(this.domains[this.domains.length - 1]);
domainsLabel = game.i18n.format('DAGGERHEART.GENERAL.thingsAndThing', {
things: firstDomains,
thing: lastDomain
});
}
}
const classItems = [];
for (const itemData of this.inventory.choiceB) {
const linkData = [
undefined,
'UUID', // type
itemData.uuid // target
];
const contentLink = await foundry.applications.ux.TextEditor.implementation._createContentLink(linkData);
classItems.push(contentLink.outerHTML);
}
const hopeFeatures = await getFeaturesHTMLData(this.hopeFeatures);
const classFeatures = await getFeaturesHTMLData(this.classFeatures);
const suffix = await foundry.applications.handlebars.renderTemplate(
'systems/daggerheart/templates/sheets/items/class/description.hbs',
{
class: this.parent,
domains: domainsLabel,
classItems,
hopeFeatures,
classFeatures
}
);
return { prefix: null, value: baseDescription, suffix };
}
}

View file

@ -1,3 +1,4 @@
import { getFeaturesHTMLData } from '../../helpers/utils.mjs';
import ForeignDocumentUUIDArrayField from '../fields/foreignDocumentUUIDArrayField.mjs';
import BaseDataItem from './base.mjs';
@ -24,4 +25,17 @@ export default class DHCommunity extends BaseDataItem {
/**@override */
static DEFAULT_ICON = 'systems/daggerheart/assets/icons/documents/items/village.svg';
/**@inheritdoc */
async getDescriptionData() {
const baseDescription = this.description;
const features = await getFeaturesHTMLData(this.features);
if (!features.length) return { prefix: null, value: baseDescription, suffix: null };
const suffix = await foundry.applications.handlebars.renderTemplate(
'systems/daggerheart/templates/sheets/items/description.hbs',
{ label: 'DAGGERHEART.ITEMS.Community.featuresLabel', features }
);
return { prefix: null, value: baseDescription, suffix };
}
}

View file

@ -1,3 +1,4 @@
import { getFeaturesHTMLData } from '../../helpers/utils.mjs';
import ForeignDocumentUUIDField from '../fields/foreignDocumentUUIDField.mjs';
import ItemLinkFields from '../fields/itemLinkFields.mjs';
import BaseDataItem from './base.mjs';
@ -89,4 +90,28 @@ export default class DHSubclass extends BaseDataItem {
const allowed = await super._preCreate(data, options, user);
if (allowed === false) return;
}
/**@inheritdoc */
async getDescriptionData() {
const baseDescription = this.description;
const spellcastTrait = this.spellcastingTrait
? game.i18n.localize(CONFIG.DH.ACTOR.abilities[this.spellcastingTrait].label)
: null;
const foundationFeatures = await getFeaturesHTMLData(this.foundationFeatures);
const specializationFeatures = await getFeaturesHTMLData(this.specializationFeatures);
const masteryFeatures = await getFeaturesHTMLData(this.masteryFeatures);
const suffix = await foundry.applications.handlebars.renderTemplate(
'systems/daggerheart/templates/sheets/items/subclass/description.hbs',
{
spellcastTrait,
foundationFeatures,
specializationFeatures,
masteryFeatures
}
);
return { prefix: null, value: baseDescription, suffix };
}
}

View file

@ -113,13 +113,26 @@ export default class DHWeapon extends AttachableItem {
/**@inheritdoc */
async getDescriptionData() {
const baseDescription = this.description;
const tier = game.i18n.localize(`DAGGERHEART.GENERAL.Tiers.${this.tier}`);
const trait = game.i18n.localize(CONFIG.DH.ACTOR.abilities[this.attack.roll.trait].label);
const range = game.i18n.localize(`DAGGERHEART.CONFIG.Range.${this.attack.range}.name`);
const damage = Roll.replaceFormulaData(this.attack.damageFormula, this.parent.parent ?? this.parent);
const burden = game.i18n.localize(CONFIG.DH.GENERAL.burden[this.burden].label);
const allFeatures = CONFIG.DH.ITEM.allWeaponFeatures();
const features = this.weaponFeatures.map(x => allFeatures[x.value]);
if (!features.length) return { prefix: null, value: baseDescription, suffix: null };
const prefix = await foundry.applications.handlebars.renderTemplate(
'systems/daggerheart/templates/sheets/items/weapon/description.hbs',
{ features }
{
features,
tier,
trait,
range,
damage,
burden
}
);
return { prefix, value: baseDescription, suffix: null };

View file

@ -496,6 +496,22 @@ export function htmlToText(html) {
return tempDivElement.textContent || tempDivElement.innerText || '';
}
export async function getFeaturesHTMLData(features) {
const result = [];
for (const feature of features) {
if (feature) {
const base = feature.item ?? feature;
const item = base.system ? base : await foundry.utils.fromUuid(base.uuid);
const itemDescription = await foundry.applications.ux.TextEditor.implementation.enrichHTML(
item.system.description
);
result.push({ label: item.name, description: itemDescription });
}
}
return result;
}
/**
* Given a simple flavor-less formula with only +/- operators, returns a list of damage partial terms.
* All subtracted terms become negative terms.