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,46 @@
# 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.