import type { Combatant, CombatantDescriptor, CreatureId, DifficultyResult, PlayerCharacter, } from "@initiative/domain"; import { calculateEncounterDifficulty } from "@initiative/domain"; import { useMemo } from "react"; import { useBestiaryContext } from "../contexts/bestiary-context.js"; import { useEncounterContext } from "../contexts/encounter-context.js"; import { usePlayerCharactersContext } from "../contexts/player-characters-context.js"; export function resolveSide(c: Combatant): "party" | "enemy" { if (c.side) return c.side; return c.playerCharacterId ? "party" : "enemy"; } function buildDescriptors( combatants: readonly Combatant[], characters: readonly PlayerCharacter[], getCreature: (id: CreatureId) => { cr: string } | undefined, ): CombatantDescriptor[] { const descriptors: CombatantDescriptor[] = []; for (const c of combatants) { const side = resolveSide(c); const level = c.playerCharacterId ? characters.find((p) => p.id === c.playerCharacterId)?.level : undefined; const cr = c.creatureId ? getCreature(c.creatureId)?.cr : (c.cr ?? undefined); if (level !== undefined || cr !== undefined) { descriptors.push({ level, cr, side }); } } return descriptors; } export function useDifficulty(): DifficultyResult | null { const { encounter } = useEncounterContext(); const { characters } = usePlayerCharactersContext(); const { getCreature } = useBestiaryContext(); return useMemo(() => { const descriptors = buildDescriptors( encounter.combatants, characters, getCreature, ); const hasPartyLevel = descriptors.some( (d) => d.side === "party" && d.level !== undefined, ); const hasCr = descriptors.some((d) => d.cr !== undefined); if (!hasPartyLevel || !hasCr) return null; return calculateEncounterDifficulty(descriptors); }, [encounter.combatants, characters, getCreature]); }