import type { DomainEvent } from "./events.js"; import type { CombatantId, DomainError, Encounter } from "./types.js"; export interface RemoveCombatantSuccess { readonly encounter: Encounter; readonly events: DomainEvent[]; } /** * Pure function that removes a combatant from an encounter by ID. * * Adjusts activeIndex to preserve turn integrity: * - Removed after active → unchanged * - Removed before active → decrement * - Removed is active, mid-list → same index (next slides in) * - Removed is active, at end → wrap to 0 * - Only combatant removed → 0 * * roundNumber is never changed. */ export function removeCombatant( encounter: Encounter, id: CombatantId, ): RemoveCombatantSuccess | DomainError { const removedIdx = encounter.combatants.findIndex((c) => c.id === id); if (removedIdx === -1) { return { kind: "domain-error", code: "combatant-not-found", message: `No combatant found with ID "${id}"`, }; } const removed = encounter.combatants[removedIdx]; const newCombatants = encounter.combatants.filter((_, i) => i !== removedIdx); let newActiveIndex: number; if (newCombatants.length === 0) { newActiveIndex = 0; } else if (removedIdx < encounter.activeIndex) { newActiveIndex = encounter.activeIndex - 1; } else if (removedIdx > encounter.activeIndex) { newActiveIndex = encounter.activeIndex; } else { // removedIdx === activeIndex newActiveIndex = removedIdx >= newCombatants.length ? 0 : encounter.activeIndex; } return { encounter: { combatants: newCombatants, activeIndex: newActiveIndex, roundNumber: encounter.roundNumber, }, events: [ { type: "CombatantRemoved", combatantId: removed.id, name: removed.name, }, ], }; }