Live 3-bar difficulty indicator in the top bar showing encounter difficulty (Trivial/Low/Moderate/High) based on the 2024 5.5e XP budget system. Automatically derived from PC levels and bestiary creature CRs. - Add optional level field (1-20) to PlayerCharacter - Add CR-to-XP and XP Budget per Character lookup tables in domain - Add calculateEncounterDifficulty pure function - Add DifficultyIndicator component with color-coded bars and tooltip - Add useDifficulty hook composing encounter, PC, and bestiary contexts - Indicator hidden when no PCs with levels or no bestiary-linked monsters - Level field in PC create/edit forms, persisted in storage Closes #18 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
34 lines
757 B
TypeScript
34 lines
757 B
TypeScript
import {
|
|
type DomainError,
|
|
type DomainEvent,
|
|
editPlayerCharacter,
|
|
isDomainError,
|
|
type PlayerCharacterId,
|
|
} from "@initiative/domain";
|
|
import type { PlayerCharacterStore } from "./ports.js";
|
|
|
|
interface EditFields {
|
|
readonly name?: string;
|
|
readonly ac?: number;
|
|
readonly maxHp?: number;
|
|
readonly color?: string | null;
|
|
readonly icon?: string | null;
|
|
readonly level?: number | null;
|
|
}
|
|
|
|
export function editPlayerCharacterUseCase(
|
|
store: PlayerCharacterStore,
|
|
id: PlayerCharacterId,
|
|
fields: EditFields,
|
|
): DomainEvent[] | DomainError {
|
|
const characters = store.getAll();
|
|
const result = editPlayerCharacter(characters, id, fields);
|
|
|
|
if (isDomainError(result)) {
|
|
return result;
|
|
}
|
|
|
|
store.save([...result.characters]);
|
|
return result.events;
|
|
}
|