diff --git a/src/module/actor/character/feats/collection.ts b/src/module/actor/character/feats/collection.ts index 65f434801f7..b5e0ac1f3ff 100644 --- a/src/module/actor/character/feats/collection.ts +++ b/src/module/actor/character/feats/collection.ts @@ -247,6 +247,9 @@ class CharacterFeats extends Collection extends CreatureSheetPF2e /** Non-persisted tweaks to formula data */ #formulaQuantities: Record = {}; + /** Nested feat rows for sheet UI from `flags.pf2e.itemGrants` (same rules as `FeatGroup.#getChildSlots`). */ + #getNestedSlots(granter: ItemPF2e): FeatSlot>[] { + const itemGrants = (granter.flags?.[SYSTEM_ID]?.itemGrants ?? {}) as Record< + string, + { id?: string; nested?: boolean } + >; + + return Object.values(itemGrants) + .filter((g) => (g?.nested ?? null) !== false) + .map((g) => (typeof g?.id === "string" && g.id.length > 0 ? (this.actor.items.get(g.id) ?? null) : null)) + .filter((i): i is FeatPF2e => !!i && i.isOfType("feat")) + .map( + (grant): FeatSlot> => ({ + id: grant.id, + label: null, + level: null, + feat: grant, + children: this.#getNestedSlots(grant), + }), + ); + } + static override get defaultOptions(): ActorSheetOptions { const options = super.defaultOptions; options.classes = [...options.classes, "character"]; @@ -288,7 +310,23 @@ class CharacterSheetPF2e extends CreatureSheetPF2e // Is the stamina variant rule enabled? sheetData.hasStamina = game.pf2e.settings.variants.stamina; sheetData.actions = this.#prepareAbilities(); - sheetData.feats = [...actor.feats, actor.feats.bonus]; + + const featGroups: FeatGroup[] = [...actor.feats, actor.feats.bonus]; + const ancestryFeatures = featGroups.find((g) => g.id === "ancestryfeature"); + // Add the heritage to the ancestry features if it is not already present + if (actor.heritage && ancestryFeatures) { + const alreadyPresent = ancestryFeatures.feats.some((f) => f.feat?.id === actor.heritage?.id); + if (!alreadyPresent) { + ancestryFeatures.feats.unshift({ + id: "heritage", + label: null, + level: null, + feat: actor.heritage, + children: this.#getNestedSlots(actor.heritage), + } as never); + } + } + sheetData.feats = featGroups; sheetData.crafting = await this.#prepareCrafting();