Files
initiative/specs/012-turn-navigation/data-model.md

1.9 KiB

Data Model: Turn Navigation

Existing Entities (unchanged)

Encounter

  • combatants: readonly array of Combatant
  • activeIndex: number (0-based index into combatants)
  • roundNumber: positive integer (>= 1)

Combatant

  • id: CombatantId (branded string)
  • name: string
  • initiative?: number
  • maxHp?: number
  • currentHp?: number

New Domain Events

TurnRetreated

Emitted on every successful RetreatTurn operation.

Field Type Description
type "TurnRetreated" (literal) Discriminant for event union
previousCombatantId CombatantId The combatant whose turn was active before retreat
newCombatantId CombatantId The combatant who is now active after retreat
roundNumber number The round number after the retreat

RoundRetreated

Emitted when RetreatTurn crosses a round boundary (activeIndex wraps from 0 to last combatant).

Field Type Description
type "RoundRetreated" (literal) Discriminant for event union
newRoundNumber number The round number after decrementing

State Transitions

RetreatTurn

Input: Encounter Output: { encounter: Encounter, events: DomainEvent[] } | DomainError

Rules:

  1. If combatants.length === 0 -> DomainError("invalid-encounter")
  2. If roundNumber === 1 && activeIndex === 0 -> DomainError("no-previous-turn")
  3. If activeIndex > 0: newIndex = activeIndex - 1, roundNumber unchanged
  4. If activeIndex === 0: newIndex = combatants.length - 1, roundNumber - 1

Events emitted:

  • Always: TurnRetreated
  • On round boundary crossing (rule 4): TurnRetreated then RoundRetreated (order matters)

Validation Rules

  • RetreatTurn MUST NOT produce roundNumber < 1
  • RetreatTurn MUST NOT produce activeIndex < 0 or >= combatants.length
  • RetreatTurn is a pure function: identical input produces identical output