69 lines
2.3 KiB
Markdown
69 lines
2.3 KiB
Markdown
# Data Model: Roll Initiative
|
||
|
||
## Existing Entities (no changes)
|
||
|
||
### Combatant
|
||
|
||
| Field | Type | Notes |
|
||
|-------|------|-------|
|
||
| id | CombatantId | Branded string identifier |
|
||
| name | string | Display name |
|
||
| initiative | number \| undefined | The initiative value (set by manual input OR roll) |
|
||
| creatureId | CreatureId \| undefined | Link to bestiary creature — presence determines roll eligibility |
|
||
| maxHp | number \| undefined | From bestiary or manual |
|
||
| currentHp | number \| undefined | Current hit points |
|
||
| ac | number \| undefined | Armor class |
|
||
| conditions | ConditionId[] | Active conditions |
|
||
| isConcentrating | boolean | Concentration flag |
|
||
|
||
### Creature (from bestiary)
|
||
|
||
| Field | Type | Notes |
|
||
|-------|------|-------|
|
||
| id | CreatureId | Branded string identifier |
|
||
| dexScore | number | Dexterity ability score (used for initiative modifier) |
|
||
| cr | string | Challenge rating (determines proficiency bonus) |
|
||
| initiativeProficiency | number | 0 = none, 1 = proficiency, 2 = expertise |
|
||
|
||
### Initiative Modifier (derived, not stored)
|
||
|
||
Calculated on demand via `calculateInitiative(creature)`:
|
||
- `modifier = Math.floor((dexScore - 10) / 2) + (initiativeProficiency × proficiencyBonus(cr))`
|
||
- `passive = 10 + modifier`
|
||
|
||
## New Concepts (no new stored entities)
|
||
|
||
### Roll Result (transient)
|
||
|
||
Not persisted — computed at the adapter boundary and immediately applied:
|
||
- `diceRoll`: integer 1–20 (generated via Math.random at adapter layer)
|
||
- `initiativeValue = diceRoll + modifier` (computed by domain function, stored as combatant's `initiative`)
|
||
|
||
## State Transitions
|
||
|
||
### Single Roll
|
||
|
||
```
|
||
Combatant(initiative: any | undefined)
|
||
→ rollInitiative(diceRoll, modifier)
|
||
→ Combatant(initiative: diceRoll + modifier)
|
||
→ encounter re-sorted by initiative descending
|
||
```
|
||
|
||
### Batch Roll
|
||
|
||
```
|
||
Encounter(combatants: [...])
|
||
→ for each combatant with creatureId:
|
||
→ rollInitiative(diceRoll_i, modifier_i)
|
||
→ setInitiative(encounter, id, value)
|
||
→ single save with final sorted state
|
||
```
|
||
|
||
## Validation Rules
|
||
|
||
- `diceRoll` must be an integer in range [1, 20]
|
||
- `modifier` is any integer (can be negative)
|
||
- Final `initiative` value is any integer (can be negative, e.g., 1 + (−3) = −2)
|
||
- Only combatants with a non-undefined `creatureId` are eligible for rolling
|