Add PF2e weak/elite creature adjustments with stat block toggle
Weak/Normal/Elite toggle in PF2e stat block header applies standard adjustments (level, AC, HP, saves, Perception, attacks, damage) to individual combatants. Adjusted stats are highlighted blue (elite) or red (weak). Persisted via creatureAdjustment field on Combatant. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -113,6 +113,11 @@ As a DM running a PF2e encounter, I want to see a creature's carried equipment
|
||||
|
||||
An "Equipment" section appears on the stat block listing each carried item with its name and relevant details (level, traits, activation description). Scrolls additionally show the embedded spell name and rank (e.g., "Scroll of Teleport (Rank 6)"). The section is omitted entirely for creatures that carry no equipment. Equipment data is extracted from the existing cached creature JSON — no additional fetch is required.
|
||||
|
||||
**US-D7 — Toggle Weak/Elite Adjustment on PF2e Stat Block (P2)**
|
||||
As a DM running a PF2e encounter, I want to toggle a weak or elite adjustment on a bestiary-linked combatant's stat block so that the standard PF2e stat modifications are applied to that specific combatant and reflected in both the stat block and the tracker.
|
||||
|
||||
When viewing a PF2e creature's stat block, a Weak/Normal/Elite toggle appears in the header. Selecting "Elite" or "Weak" applies the standard PF2e adjustments: ±2 to AC, saves, Perception, attack rolls, and strike damage; HP adjusted by the standard level bracket table; level shifted. The combatant's stored HP and AC update accordingly (see `specs/003-combatant-state/spec.md`, FR-113–FR-116), and its name gains a prefix (see `specs/001-combatant-management/spec.md`, FR-041–FR-042). The toggle defaults to "Normal" and is not shown for D&D creatures. A visual indicator (the same icon used in the toggle) appears next to the creature name in the header.
|
||||
|
||||
### Requirements
|
||||
|
||||
- **FR-016**: The system MUST display a stat block panel with full creature information when a creature is selected.
|
||||
@@ -138,6 +143,14 @@ An "Equipment" section appears on the stat block listing each carried item with
|
||||
- **FR-081**: Spell descriptions MUST be processed through the existing Foundry tag-stripping utility before display (consistent with FR-068).
|
||||
- **FR-082**: When a spell name has a parenthetical modifier (e.g., "Heal (×3)", "Unfettered Movement (Constant)"), only the spell name portion MUST be the click target; the modifier MUST remain as adjacent plain text.
|
||||
- **FR-083**: The spell description display MUST handle both representations of heightening present in Foundry VTT data: `system.heightening` and `system.overlays`.
|
||||
- **FR-101**: PF2e stat blocks MUST include a Weak/Normal/Elite toggle in the header, defaulting to "Normal".
|
||||
- **FR-102**: The Weak/Normal/Elite toggle MUST NOT be shown for D&D creatures or non-bestiary combatants.
|
||||
- **FR-103**: Selecting "Elite" MUST display the stat block with the standard PF2e elite adjustment applied: +2 to AC, saving throws, Perception, and attack rolls; +2 to strike damage; HP increase by level bracket (per the standard PF2e table); level +1 (or +2 if base level ≤ 0).
|
||||
- **FR-104**: Selecting "Weak" MUST display the stat block with the standard PF2e weak adjustment applied: −2 to AC, saving throws, Perception, and attack rolls; −2 to strike damage; HP decrease by level bracket (per the standard PF2e table); level −1 (or −2 if base level is 1).
|
||||
- **FR-105**: Toggling the adjustment MUST update the combatant's stored maxHp and ac to the adjusted values (see `specs/003-combatant-state/spec.md`, FR-113–FR-116). The combatant's currentHp MUST shift by the same delta as maxHp, clamped to [0, new maxHp].
|
||||
- **FR-106**: Toggling the adjustment MUST update the combatant's name with the appropriate prefix — "Weak" or "Elite" — or remove the prefix when returning to "Normal" (see `specs/001-combatant-management/spec.md`, FR-041–FR-042).
|
||||
- **FR-107**: The stat block header MUST display a visual indicator (the same icon used in the toggle) next to the creature name when the creature has a weak or elite adjustment.
|
||||
- **FR-108**: The adjustment MUST be stored on the combatant as a `creatureAdjustment` field and persist across page reloads.
|
||||
|
||||
### Acceptance Scenarios
|
||||
|
||||
@@ -173,6 +186,14 @@ An "Equipment" section appears on the stat block listing each carried item with
|
||||
30. **Given** a PF2e creature with an ability that has no frequency limit, **When** the DM views the stat block, **Then** the ability name renders without any frequency annotation.
|
||||
31. **Given** a PF2e creature with `perception.details: "smoke vision"`, **When** the DM views the stat block, **Then** the perception line shows "smoke vision" alongside the senses.
|
||||
32. **Given** a PF2e creature with no perception details, **When** the DM views the stat block, **Then** the perception line shows only the modifier and senses as before.
|
||||
33. **Given** a PF2e creature's stat block is open, **When** the DM views the header, **Then** a Weak/Normal/Elite toggle is visible, set to "Normal" by default.
|
||||
34. **Given** a D&D creature's stat block is open, **When** the DM views the header, **Then** no Weak/Normal/Elite toggle is shown.
|
||||
35. **Given** a PF2e creature (level 5, AC 22, HP 75) stat block is open, **When** the DM selects "Elite", **Then** the stat block shows AC 24, HP 95 (75+20 for level 5 bracket), level 6, and all saves/Perception/attacks are adjusted by +2.
|
||||
36. **Given** a PF2e creature (level 5, AC 22, HP 75) stat block is open, **When** the DM selects "Weak", **Then** the stat block shows AC 20, HP 55 (75−20 for level 5 bracket), level 4, and all saves/Perception/attacks are adjusted by −2.
|
||||
37. **Given** a PF2e creature with level 0 stat block is open, **When** the DM selects "Elite", **Then** the level increases by 2 (not 1).
|
||||
38. **Given** a PF2e creature with level 1 stat block is open, **When** the DM selects "Weak", **Then** the level decreases by 2 (to −1, not 0).
|
||||
39. **Given** a PF2e combatant was set to "Elite" and the page is reloaded, **When** the DM opens the stat block, **Then** the toggle shows "Elite" and the stat block displays adjusted stats.
|
||||
40. **Given** a PF2e combatant was set to "Elite", **When** the DM toggles back to "Normal", **Then** the stat block reverts to base stats, the combatant's HP/AC revert, and the name prefix is removed.
|
||||
|
||||
### Edge Cases
|
||||
|
||||
@@ -184,6 +205,13 @@ An "Equipment" section appears on the stat block listing each carried item with
|
||||
- Equipment item with empty description: the item is displayed with its name and metadata (level, traits) but no description text.
|
||||
- Cached source data from before the spell description feature was added: existing cached entries lack the new per-spell data fields. The IndexedDB schema version MUST be bumped to invalidate old caches and trigger re-fetch (re-normalization from raw Foundry data is not possible because the original raw JSON is not retained).
|
||||
- Creature with no recognized type trait (e.g., a creature whose only traits are not in the type-to-skill mapping): the Recall Knowledge line is omitted entirely.
|
||||
- Weak adjustment on a level 1 creature: level becomes −1 (special case, −2 instead of −1).
|
||||
- Elite adjustment on a level ≤ 0 creature: level increases by 2 instead of 1.
|
||||
- HP bracket table: HP adjustments follow the standard PF2e weak/elite HP adjustment table keyed by creature level (1 or lower: ±10, 2–4: ±15, 5–19: ±20, 20+: ±30).
|
||||
- Toggling from Elite to Weak: applies the full swing (reverts elite, then applies weak) in a single operation.
|
||||
- Combatant has taken damage before toggle: currentHp shifts by the maxHp delta, clamped to [0, new maxHp]. E.g., 65/75 HP → Elite → 85/95 HP.
|
||||
- Source data not yet cached when toggling: toggle is disabled until source data is loaded (adjustment requires full creature data to compute).
|
||||
- Recall Knowledge DC updates based on adjusted level.
|
||||
- Creature with a type trait that maps to multiple skills (e.g., Beast → Arcana/Nature): both skills are shown.
|
||||
- Attack with multiple on-hit effects (e.g., `["grab", "knockdown"]`): all effects shown, joined with "and" (e.g., "plus Grab and Knockdown").
|
||||
- Attack effect slug with creature-name prefix (e.g., `"lich-siphon-life"` on a Lich): the creature-name prefix is stripped, rendering as "Siphon Life".
|
||||
@@ -368,7 +396,7 @@ As a DM with a creature pinned, I want to collapse the right (browse) panel inde
|
||||
- **Source** (`BestiarySource`): A D&D or PF2e publication identified by a code (e.g., "XMM") with a display name (e.g., "Monster Manual (2025)"). Caching and fetching operate at the source level.
|
||||
- **Creature (Full)** (`Creature`): A complete creature record with all stat block data (traits, actions, legendary actions, spellcasting, etc.), available only after source data is fetched/uploaded and cached. Identified by a branded `CreatureId`. For PF2e creatures, each spell entry inside `spellcasting` carries full per-spell data (slug, level, traits, range, action cost, target/area, duration, defense, description, heightening) extracted from the embedded `items[type=spell]` data on the source NPC, enabling inline spell description display without additional fetches. PF2e creatures also carry an `equipment` list of carried items (weapons, consumables) extracted from `items[type=weapon]` and `items[type=consumable]` entries, each with name, level, traits, description, and (for scrolls) embedded spell data. PF2e attack entries carry an optional `attackEffects` list of on-hit effect names. PF2e ability entries carry an optional `frequency` with `max` and `per` fields. PF2e creature perception carries an optional `details` string (e.g., "smoke vision").
|
||||
- **Cached Source Data**: The full normalized bestiary data for a single source, stored in IndexedDB. Contains complete creature stat blocks.
|
||||
- **Combatant** (extended): Gains an optional `creatureId` reference to a `Creature`, enabling stat block lookup and stat pre-fill on creation.
|
||||
- **Combatant** (extended): Gains an optional `creatureId` reference to a `Creature`, enabling stat block lookup and stat pre-fill on creation. PF2e bestiary-linked combatants may also carry a `creatureAdjustment` (`"weak" | "elite"`) indicating the active PF2e weak/elite adjustment, persisted across reloads.
|
||||
- **Queued Creature**: Transient UI-only state representing a bestiary creature selected for batch-add, containing the creature reference and a count (1+). Not persisted.
|
||||
- **Bulk Import Operation**: Tracks total sources, completed count, failed count, and current status (idle / loading / complete / partial-failure).
|
||||
- **Toast Notification**: Lightweight custom UI element at bottom-center of screen with text, optional progress bar, and optional dismiss button.
|
||||
|
||||
Reference in New Issue
Block a user