# 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