# Data Model: HP Status Indicators **Feature**: 013-hp-status-indicators **Date**: 2026-03-05 ## Entities ### HpStatus (derived type -- not stored) A discriminated string union representing the health state of a combatant. | Value | Condition | Description | |-------|-----------|-------------| | `"healthy"` | `currentHp >= maxHp / 2` | Combatant is above half HP | | `"bloodied"` | `0 < currentHp < maxHp / 2` | Combatant is below half HP but still conscious | | `"unconscious"` | `currentHp <= 0` | Combatant is at or below zero HP | **Derivation rules**: - Only meaningful when both `currentHp` and `maxHp` are defined - Returns `undefined` when either value is missing (HP tracking not enabled) - Evaluation order: check `unconscious` first (currentHp <= 0), then `bloodied` (currentHp < maxHp / 2), else `healthy` ### Combatant (existing -- unchanged) No modifications to the `Combatant` interface. HP status is computed on demand from existing fields: | Field | Type | Used for status | |-------|------|----------------| | `currentHp` | `number \| undefined` | Compared against thresholds | | `maxHp` | `number \| undefined` | Defines the "half HP" bloodied threshold | ## State Transitions HP status changes are a side effect of existing HP operations (adjustHp, setHp). No new state transitions are introduced. ```text healthy ──[take damage below half]──> bloodied bloodied ──[take damage to 0]──────> unconscious unconscious ──[heal above 0]───────> bloodied or healthy bloodied ──[heal above half]───────> healthy healthy ──[take massive damage]────> unconscious (skip bloodied) ``` ## Storage Impact None. HP status is derived at render time from existing persisted `currentHp` and `maxHp` values. No localStorage schema changes.