Implement the 013-hp-status-indicators feature that adds visual HP status indicators to combatant rows with a pure domain function deriving bloodied/unconscious states

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Lukas
2026-03-05 23:29:24 +01:00
parent 7d440677be
commit 97d3918cef
12 changed files with 550 additions and 2 deletions

View File

@@ -0,0 +1,98 @@
# Feature Specification: HP Status Indicators
**Feature Branch**: `013-hp-status-indicators`
**Created**: 2026-03-05
**Status**: Draft
**Input**: User description: "When a combatant's health is lower than half, the creature is considered bloodied, which makes the UI show an indicator. If a combatant is at <=0 HP the creature is unconscious/dead, which should also be shown. Visual treatment at implementer's discretion to fit the existing modern UI style."
## User Scenarios & Testing *(mandatory)*
### User Story 1 - Bloodied Indicator (Priority: P1)
As a game master running an encounter, I want to see at a glance which combatants are bloodied (below half their maximum HP) so I can narrate the battle's intensity and make tactical decisions without mental math.
**Why this priority**: The bloodied condition is a core D&D/TTRPG concept that GMs check frequently during combat. Providing a visual indicator eliminates the need to compare current HP vs max HP for every combatant each round.
**Independent Test**: Can be fully tested by setting a combatant's max HP and reducing current HP below half, then verifying the visual indicator appears. Delivers immediate at-a-glance awareness.
**Acceptance Scenarios**:
1. **Given** a combatant with max HP set to 20 and current HP at 10, **When** the combatant row is displayed, **Then** the HP area shows a bloodied visual indicator (e.g., amber/orange color treatment on the HP value)
2. **Given** a combatant with max HP set to 20 and current HP at 9, **When** the combatant row is displayed, **Then** the bloodied indicator is visible
3. **Given** a combatant with max HP set to 20 and current HP at 11, **When** the combatant row is displayed, **Then** no bloodied indicator is shown (normal appearance)
4. **Given** a combatant with max HP set to 21 (odd number) and current HP at 10, **When** the combatant row is displayed, **Then** the bloodied indicator is shown (10 < 21/2 = 10.5)
5. **Given** a combatant with no max HP set, **When** the combatant row is displayed, **Then** no status indicator is shown regardless of current HP value
---
### User Story 2 - Unconscious/Dead Indicator (Priority: P1)
As a game master, I want to see which combatants have reached 0 HP or below so I can immediately identify who is down without scanning HP numbers.
**Why this priority**: Equally critical to bloodied -- knowing who is unconscious or dead is essential for combat flow and takes priority over other status information.
**Independent Test**: Can be fully tested by reducing a combatant's current HP to 0 or below and verifying the visual indicator appears.
**Acceptance Scenarios**:
1. **Given** a combatant with max HP set to 20 and current HP at 0, **When** the combatant row is displayed, **Then** the HP area shows an unconscious/dead visual indicator (e.g., red color treatment and/or a skull/death icon)
2. **Given** a combatant with max HP set to 20 and current HP at -5, **When** the combatant row is displayed, **Then** the unconscious/dead indicator is shown (negative HP still counts as down)
3. **Given** a combatant with max HP set to 20 and current HP at 1, **When** the combatant row is displayed, **Then** the unconscious/dead indicator is NOT shown (1 HP is bloodied, not dead)
4. **Given** a combatant at 0 HP whose HP is then healed above 0, **When** the HP changes, **Then** the unconscious/dead indicator is removed and replaced with the appropriate status (bloodied or healthy)
---
### User Story 3 - Status Transitions (Priority: P2)
As a game master adjusting HP during combat, I want the visual indicators to update in real time as I apply damage or healing so I always have an accurate picture of the battlefield.
**Why this priority**: Indicator transitions are a natural consequence of the first two stories but need explicit attention to ensure smooth, responsive visual feedback.
**Independent Test**: Can be tested by using the quick HP input to deal damage across thresholds and observing indicator changes.
**Acceptance Scenarios**:
1. **Given** a combatant at full HP (20/20), **When** I deal 11 damage (reducing to 9/20), **Then** the indicator transitions from healthy to bloodied
2. **Given** a bloodied combatant (5/20), **When** I deal 5 damage (reducing to 0/20), **Then** the indicator transitions from bloodied to unconscious/dead
3. **Given** an unconscious combatant (0/20), **When** I heal 15 HP (restoring to 15/20), **Then** the indicator transitions from unconscious/dead to healthy (skipping bloodied since 15 > 10)
---
### Edge Cases
- What happens when max HP is 1? At 1/1 HP the combatant is healthy; at 0/1 HP they are unconscious/dead. There is no bloodied state since 0 < 0.5 rounds to unconscious/dead.
- What happens when max HP is 2? At 1/2 HP the combatant is healthy (1 is not less than 2/2 = 1); at 0/2 they are unconscious/dead. Bloodied only applies when currentHp < maxHp / 2 (strict less-than with exact division).
- What happens when current HP exceeds max HP (e.g., temporary HP or manual override)? The combatant shows healthy status -- no special indicator for over-max.
- What happens when max HP is set but current HP has not been modified? Current HP equals max HP by default, so the combatant shows healthy status.
## Requirements *(mandatory)*
### Functional Requirements
- **FR-001**: System MUST derive a combatant's HP status from their current HP and max HP values: "healthy" (currentHp >= maxHp / 2), "bloodied" (0 < currentHp < maxHp / 2), or "unconscious" (currentHp <= 0)
- **FR-002**: System MUST display a visual indicator on the combatant row when a combatant is bloodied -- the HP value text MUST use a warm/amber color to signal danger
- **FR-003**: System MUST display a visual indicator on the combatant row when a combatant is unconscious/dead -- the HP value text MUST use a red/destructive color and the row MUST appear visually muted (reduced opacity or strikethrough name) to signal the combatant is out of action
- **FR-004**: System MUST NOT show any status indicator when max HP is not set for a combatant
- **FR-005**: System MUST update the visual indicator immediately when current HP changes (no delay or animation lag)
- **FR-006**: The HP status derivation MUST be a pure domain-level computation with no UI dependencies
### Key Entities
- **HP Status**: A derived value (not stored) computed from a combatant's currentHp and maxHp. Possible values: "healthy", "bloodied", "unconscious". Only meaningful when maxHp is defined.
## Success Criteria *(mandatory)*
### Measurable Outcomes
- **SC-001**: Users can identify bloodied combatants at a glance without reading HP numbers -- 100% of combatants below half HP display a distinct visual treatment
- **SC-002**: Users can identify unconscious/dead combatants at a glance -- 100% of combatants at 0 HP or below display a distinct visual treatment that differs from the bloodied indicator
- **SC-003**: Visual indicators update within the same interaction frame as HP changes -- no perceptible delay between HP adjustment and indicator update
- **SC-004**: Status indicators are visually consistent with the existing UI design system (colors, spacing, typography match the established style)
## Assumptions
- "Bloodied" uses the D&D 4e/5e convention: strictly below half max HP (not at exactly half)
- The unconscious/dead label is intentionally combined into one state -- the system does not distinguish between unconscious and dead (this is a GM decision, not a system decision)
- No sound effects or animation beyond color/opacity changes for MVP baseline
- MVP baseline does not include a tooltip or label explaining what "bloodied" means
- The status is purely visual/derived -- it does not affect game mechanics or stored data