Improve PF2e stat block action icons, triggers, and tag handling
- Replace unicode action cost chars with custom SVG icons (diamond
with chevron for actions, outlined diamond for free, curved arrow
for reaction) rendered inline via ActivityCost on TraitBlock
- Add activity icons to attacks (all Strikes default to single action)
- Add trigger/effect rendering for reaction abilities (bold labels)
- Fix nested tag stripping ({@b ...{@spell ...}...}) by looping
- Move icon after ability name to match AoN format
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -197,7 +197,8 @@ describe("normalizePf2eBestiary", () => {
|
||||
});
|
||||
const ability = creature.abilitiesBot?.[0];
|
||||
expect(ability).toBeDefined();
|
||||
expect(ability?.name).toBe("\u25C6 Change Shape");
|
||||
expect(ability?.name).toBe("Change Shape");
|
||||
expect(ability?.activity).toEqual({ number: 1, unit: "action" });
|
||||
expect(ability?.segments[0]).toEqual(
|
||||
expect.objectContaining({
|
||||
type: "text",
|
||||
@@ -208,7 +209,7 @@ describe("normalizePf2eBestiary", () => {
|
||||
);
|
||||
});
|
||||
|
||||
it("shows free action icon", () => {
|
||||
it("parses free action activity", () => {
|
||||
const [creature] = normalizePf2eBestiary({
|
||||
creature: [
|
||||
minimalCreature({
|
||||
@@ -224,10 +225,12 @@ describe("normalizePf2eBestiary", () => {
|
||||
}),
|
||||
],
|
||||
});
|
||||
expect(creature.abilitiesBot?.[0]?.name).toBe("\u25C7 Adaptive Strike");
|
||||
const ability = creature.abilitiesBot?.[0];
|
||||
expect(ability?.name).toBe("Adaptive Strike");
|
||||
expect(ability?.activity).toEqual({ number: 1, unit: "free" });
|
||||
});
|
||||
|
||||
it("shows reaction icon", () => {
|
||||
it("parses reaction activity", () => {
|
||||
const [creature] = normalizePf2eBestiary({
|
||||
creature: [
|
||||
minimalCreature({
|
||||
@@ -243,12 +246,12 @@ describe("normalizePf2eBestiary", () => {
|
||||
}),
|
||||
],
|
||||
});
|
||||
expect(creature.abilitiesMid?.[0]?.name).toBe(
|
||||
"\u21BA Attack of Opportunity",
|
||||
);
|
||||
const ability = creature.abilitiesMid?.[0];
|
||||
expect(ability?.name).toBe("Attack of Opportunity");
|
||||
expect(ability?.activity).toEqual({ number: 1, unit: "reaction" });
|
||||
});
|
||||
|
||||
it("shows multi-action icons", () => {
|
||||
it("parses multi-action activity", () => {
|
||||
const [creature] = normalizePf2eBestiary({
|
||||
creature: [
|
||||
minimalCreature({
|
||||
@@ -264,9 +267,9 @@ describe("normalizePf2eBestiary", () => {
|
||||
}),
|
||||
],
|
||||
});
|
||||
expect(creature.abilitiesBot?.[0]?.name).toBe(
|
||||
"\u25C6\u25C6 Breath Weapon",
|
||||
);
|
||||
const ability = creature.abilitiesBot?.[0];
|
||||
expect(ability?.name).toBe("Breath Weapon");
|
||||
expect(ability?.activity).toEqual({ number: 2, unit: "action" });
|
||||
});
|
||||
|
||||
it("renders ability without activity or traits normally", () => {
|
||||
@@ -287,6 +290,7 @@ describe("normalizePf2eBestiary", () => {
|
||||
const ability = creature.abilitiesBot?.[0];
|
||||
expect(ability).toBeDefined();
|
||||
expect(ability?.name).toBe("Constrict");
|
||||
expect(ability?.activity).toBeUndefined();
|
||||
expect(ability?.segments[0]).toEqual(
|
||||
expect.objectContaining({
|
||||
type: "text",
|
||||
@@ -294,6 +298,35 @@ describe("normalizePf2eBestiary", () => {
|
||||
}),
|
||||
);
|
||||
});
|
||||
|
||||
it("includes trigger text before entries", () => {
|
||||
const [creature] = normalizePf2eBestiary({
|
||||
creature: [
|
||||
minimalCreature({
|
||||
abilities: {
|
||||
mid: [
|
||||
{
|
||||
name: "Wing Deflection",
|
||||
activity: { number: 1, unit: "reaction" },
|
||||
trigger: "The dragon is targeted with an attack.",
|
||||
entries: ["The dragon raises its wing."],
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
],
|
||||
});
|
||||
const ability = creature.abilitiesMid?.[0];
|
||||
expect(ability).toBeDefined();
|
||||
expect(ability?.activity).toEqual({ number: 1, unit: "reaction" });
|
||||
expect(ability?.trigger).toBe("The dragon is targeted with an attack.");
|
||||
expect(ability?.segments[0]).toEqual(
|
||||
expect.objectContaining({
|
||||
type: "text",
|
||||
value: "The dragon raises its wing.",
|
||||
}),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("resistances formatting", () => {
|
||||
|
||||
Reference in New Issue
Block a user