import { type CombatantId, type Creature, type CreatureId, calculateInitiative, type DomainError, type DomainEvent, isDomainError, rollInitiative, setInitiative, } from "@initiative/domain"; import type { EncounterStore } from "./ports.js"; export function rollInitiativeUseCase( store: EncounterStore, combatantId: CombatantId, diceRoll: number, getCreature: (id: CreatureId) => Creature | undefined, ): DomainEvent[] | DomainError { const encounter = store.get(); const combatant = encounter.combatants.find((c) => c.id === combatantId); if (!combatant) { return { kind: "domain-error", code: "combatant-not-found", message: `No combatant found with ID "${combatantId}"`, }; } if (!combatant.creatureId) { return { kind: "domain-error", code: "no-creature-link", message: `Combatant "${combatant.name}" has no linked creature`, }; } const creature = getCreature(combatant.creatureId); if (!creature) { return { kind: "domain-error", code: "creature-not-found", message: `Creature not found for ID "${combatant.creatureId}"`, }; } const { modifier } = calculateInitiative({ dexScore: creature.abilities.dex, cr: creature.cr, initiativeProficiency: creature.initiativeProficiency, }); const value = rollInitiative(diceRoll, modifier); if (isDomainError(value)) { return value; } const result = setInitiative(encounter, combatantId, value); if (isDomainError(result)) { return result; } store.save(result.encounter); return result.events; }