Implement the 017-combat-conditions feature that adds D&D 5e status conditions to combatants with icon tags, color coding, and a compact toggle picker in the encounter tracker

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Lukas
2026-03-06 11:29:39 +01:00
parent 78c6591973
commit febe892e15
22 changed files with 1301 additions and 62 deletions

View File

@@ -0,0 +1,88 @@
# Data Model: Combat Conditions
## Entities
### ConditionId (new type)
String literal union representing the 15 valid condition identifiers.
```
"blinded" | "charmed" | "deafened" | "exhaustion" | "frightened" |
"grappled" | "incapacitated" | "invisible" | "paralyzed" | "petrified" |
"poisoned" | "prone" | "restrained" | "stunned" | "unconscious"
```
- Order of literals in the union defines the canonical display order (FR-003).
- Extensible: future conditions can be added to the union.
### ConditionDefinition (new type)
Static metadata for each condition.
| Field | Type | Description |
| --------- | ----------- | ------------------------------------------------ |
| id | ConditionId | Unique identifier |
| label | string | Human-readable display name (e.g., "Blinded") |
| iconName | string | Lucide icon component name (e.g., "EyeOff") |
| color | string | Color category (e.g., "neutral", "pink", "amber") |
- Registry: `CONDITION_DEFINITIONS` — a static readonly array of all 15 definitions, ordered by display priority.
- No lifecycle/state transitions — definitions are immutable reference data.
### Combatant (modified)
| Field | Type | Change |
| ---------- | ----------------------------- | -------- |
| id | CombatantId | existing |
| name | string | existing |
| initiative | number \| undefined | existing |
| maxHp | number \| undefined | existing |
| currentHp | number \| undefined | existing |
| ac | number \| undefined | existing |
| conditions | readonly ConditionId[] \| undefined | **new** |
- `conditions` is optional; `undefined` means no conditions active.
- When present, the array contains unique `ConditionId` values sorted in definition order.
- Maximum cardinality: 15 (one of each condition).
## Relationships
```
Encounter 1──* Combatant
Combatant 0──* ConditionId (from CONDITION_DEFINITIONS registry)
```
## Validation Rules
- A condition can appear at most once per combatant.
- Only valid `ConditionId` values are accepted (unknown strings rejected).
- The conditions array is always sorted in definition order after any mutation.
- An empty conditions array is normalized to `undefined`.
## Domain Events
### ConditionAdded
| Field | Type |
| ----------- | ----------- |
| type | "ConditionAdded" |
| combatantId | CombatantId |
| condition | ConditionId |
Emitted when a condition is toggled on or explicitly added.
### ConditionRemoved
| Field | Type |
| ----------- | ----------- |
| type | "ConditionRemoved" |
| combatantId | CombatantId |
| condition | ConditionId |
Emitted when a condition is toggled off (via picker or tag click).
## Persistence
- Serialization: `conditions` array serializes to JSON as `["blinded", "poisoned"]`.
- Deserialization: Filter stored values through the `ConditionId` set; discard unknown strings. If resulting array is empty, set to `undefined`.
- No schema migration required (field is optional with `undefined` default).