# Feature Specification: Combatant HP Tracking **Feature Branch**: `009-combatant-hp` **Created**: 2026-03-05 **Status**: Draft **Input**: User description: "Track max HP and current HP per combatant with quick +/- controls (clamp 0..max); keep the design extensible for later richer damage/heal UI." ## User Scenarios & Testing ### User Story 1 - Set Max HP for a Combatant (Priority: P1) As a game master, I want to assign a maximum HP value to a combatant so that I can track their health during the encounter. **Why this priority**: Max HP is the foundation for all HP tracking. Without it, current HP has no upper bound and the feature has no value. **Independent Test**: Can be fully tested by adding a combatant and setting their max HP, then verifying the value is stored and displayed. **Acceptance Scenarios**: 1. **Given** a combatant exists in the encounter, **When** the user sets a max HP value (positive integer), **Then** the combatant's max HP is stored and displayed. 2. **Given** a combatant has no max HP set yet, **When** the combatant is displayed, **Then** both Current HP and Max HP fields are visible (Current HP is disabled until Max HP is set). 3. **Given** a combatant has a max HP of 20, **When** the user changes max HP to 30, **Then** the max HP updates to 30. 4. **Given** a combatant has max HP of 20 and current HP of 20, **When** the user lowers max HP to 15, **Then** current HP is clamped to the new max HP of 15. 5. **Given** a combatant has max HP of 20 and current HP of 20 (full health), **When** the user increases max HP to 30, **Then** current HP increases to 30 (stays at full health). 6. **Given** a combatant has max HP of 20 and current HP of 12 (not full health), **When** the user increases max HP to 30, **Then** current HP remains at 12 (unchanged). --- ### User Story 2 - Quick Adjust Current HP (Priority: P1) As a game master, I want to quickly increase or decrease a combatant's current HP using +/- controls so that I can reflect damage and healing during combat without typing exact values. **Why this priority**: This is the primary interaction loop during combat -- adjusting HP as damage/healing occurs. Equally critical as setting max HP. **Independent Test**: Can be fully tested by setting a combatant's max HP, then using +/- controls and verifying the current HP changes correctly within bounds. **Acceptance Scenarios**: 1. **Given** a combatant has max HP of 20 and current HP of 20, **When** the user presses the "-" control, **Then** current HP decreases by 1 to 19. 2. **Given** a combatant has max HP of 20 and current HP of 15, **When** the user presses the "+" control, **Then** current HP increases by 1 to 16. 3. **Given** a combatant has current HP of 0, **When** the user presses the "-" control, **Then** current HP remains at 0 (clamped to minimum). 4. **Given** a combatant has current HP equal to max HP, **When** the user presses the "+" control, **Then** current HP remains at max HP (clamped to maximum). --- ### User Story 3 - Direct HP Entry (Priority: P2) As a game master, I want to type a specific current HP value directly so that I can apply large amounts of damage or healing in one action. **Why this priority**: Complements the quick +/- controls for cases where the delta is large. Less critical than basic +/- since the same outcome can be achieved with repeated presses. **Independent Test**: Can be fully tested by setting a combatant's max HP, typing a value in the current HP field, and verifying clamping behavior. **Acceptance Scenarios**: 1. **Given** a combatant has max HP of 50, **When** the user types 35 into the current HP field, **Then** current HP is set to 35. 2. **Given** a combatant has max HP of 50, **When** the user types 60 into the current HP field, **Then** current HP is clamped to 50. 3. **Given** a combatant has max HP of 50, **When** the user types -5 into the current HP field, **Then** current HP is clamped to 0. --- ### User Story 4 - HP Persists Across Reloads (Priority: P2) As a game master, I want HP values to survive page reloads so that I don't lose health tracking mid-session. **Why this priority**: Losing HP data on reload would make the feature unreliable during a game session. Important but builds on existing persistence infrastructure. **Independent Test**: Can be tested by setting HP values, reloading the page, and verifying values are restored. **Acceptance Scenarios**: 1. **Given** a combatant has max HP of 30 and current HP of 18, **When** the page is reloaded, **Then** both max HP and current HP are restored. --- ### Edge Cases - What happens when max HP is set to 0? System must reject 0 or negative max HP values; max HP must be a positive integer. - What happens when a combatant is added without HP? The combatant is displayed without HP tracking. HP is optional -- not all combatants need HP (e.g., environmental effects, lair actions). - What happens when the user enters a non-numeric value for HP? The input is rejected and the previous value is preserved. - What happens when max HP is cleared/removed? Current HP is also cleared; the combatant returns to the "no HP" state. Clearing only takes effect on blur/Enter (not while typing), so temporarily emptying the field during editing does not wipe current HP. - What happens when the user selects all text in the max HP field and retypes a new value? The field uses local draft state; the domain only sees the final committed value on blur/Enter. Current HP is preserved. - What happens when HP is adjusted by 0? The system rejects a zero delta -- no change is made and no event is emitted. ## Requirements ### Functional Requirements - **FR-001**: Each combatant MAY have an optional max HP value (positive integer). - **FR-002**: Each combatant with a max HP MUST have a current HP value, defaulting to max HP when first set. - **FR-003**: Current HP MUST be clamped to the range [0, max HP] at all times. - **FR-004**: The system MUST provide "+" and "-" controls to adjust current HP by 1. - **FR-005**: The system MUST allow direct numeric entry of current HP, applying clamping on confirmation. - **FR-006**: The system MUST allow the user to set and edit the max HP value for any combatant. The max HP value is committed on blur or Enter (not per-keystroke) so that intermediate editing states (e.g., clearing the field to retype) do not affect current HP. - **FR-007**: When max HP is reduced below current HP, current HP MUST be clamped to the new max HP. - **FR-011**: When max HP changes and the combatant is at full health (current HP equals previous max HP), current HP MUST stay synced to the new max HP value. - **FR-012**: When max HP changes and the combatant is NOT at full health, current HP MUST remain unchanged (unless clamped by FR-007). - **FR-008**: Max HP MUST be a positive integer (>= 1). The system MUST reject zero, negative, or non-integer values. - **FR-009**: HP values (max and current) MUST persist across page reloads using the existing persistence mechanism. - **FR-010**: HP tracking MUST be optional per combatant. Combatants without max HP set have no HP display beyond the empty input fields. - **FR-013**: Both Current HP and Max HP input fields MUST always be visible in each combatant row. The Current HP field is disabled when Max HP is not set. The +/- buttons only appear when HP tracking is active. ### Key Entities - **Combatant** (extended): Gains optional `maxHp` (positive integer) and `currentHp` (integer, 0..maxHp) attributes. When `maxHp` is undefined, the combatant has no HP tracking. ## Success Criteria ### Measurable Outcomes - **SC-001**: A user can set max HP and adjust current HP for any combatant in under 5 seconds per action. - **SC-002**: Current HP never exceeds max HP or drops below 0, regardless of user input method. - **SC-003**: HP values survive a full page reload without data loss. - **SC-004**: Combatants without HP set display correctly with no HP controls cluttering the interface. ## Assumptions - The increment/decrement step for +/- controls is 1. Larger step sizes (e.g., custom damage amounts) are not in the MVP baseline but the design should not preclude a richer damage/heal UI in the future. - HP is always an integer (no fractional HP). This aligns with standard tabletop RPG conventions. - There is no "temporary HP" concept in the MVP baseline. - There is no death/unconscious state triggered by reaching 0 HP in the MVP baseline. The system simply displays 0. - The +/- controls and direct entry are the only HP modification methods in the MVP baseline. A richer damage/heal dialog (e.g., entering a damage amount to subtract) is not included but the domain design should be extensible to support it.