Support the 2014 DMG encounter difficulty as an alternative to the 5.5e system behind the existing Rules Edition toggle. The 2014 system uses Easy/Medium/Hard/Deadly thresholds, an encounter multiplier based on monster count, and party size adjustment (×0.5–×5 range). - Extract RulesEdition to its own domain module - Refactor DifficultyTier to abstract numeric values (0–3) - Restructure DifficultyResult with thresholds array - Add 2014 XP thresholds table and encounter multiplier logic - Wire edition from context into difficulty hooks - Edition-aware labels in indicator and breakdown panel - Show multiplier, adjusted XP, and party size note for 2014 - Rename settings label from "Conditions" to "Rules Edition" - Update spec 008 with issue #23 requirements Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
70 lines
1.5 KiB
TypeScript
70 lines
1.5 KiB
TypeScript
import type { DifficultyResult, DifficultyTier } from "@initiative/domain";
|
|
import { cn } from "../lib/utils.js";
|
|
|
|
export const TIER_LABELS_5_5E: Record<DifficultyTier, string> = {
|
|
0: "Trivial",
|
|
1: "Low",
|
|
2: "Moderate",
|
|
3: "High",
|
|
};
|
|
|
|
export const TIER_LABELS_2014: Record<DifficultyTier, string> = {
|
|
0: "Easy",
|
|
1: "Medium",
|
|
2: "Hard",
|
|
3: "Deadly",
|
|
};
|
|
|
|
const TIER_COLORS: Record<
|
|
DifficultyTier,
|
|
{ filledBars: number; color: string }
|
|
> = {
|
|
0: { filledBars: 0, color: "" },
|
|
1: { filledBars: 1, color: "bg-green-500" },
|
|
2: { filledBars: 2, color: "bg-yellow-500" },
|
|
3: { filledBars: 3, color: "bg-red-500" },
|
|
};
|
|
|
|
const BAR_HEIGHTS = ["h-2", "h-3", "h-4"] as const;
|
|
|
|
export function DifficultyIndicator({
|
|
result,
|
|
labels,
|
|
onClick,
|
|
}: {
|
|
result: DifficultyResult;
|
|
labels: Record<DifficultyTier, string>;
|
|
onClick?: () => void;
|
|
}) {
|
|
const config = TIER_COLORS[result.tier];
|
|
const label = labels[result.tier];
|
|
const tooltip = `${label} encounter difficulty`;
|
|
|
|
const Element = onClick ? "button" : "div";
|
|
|
|
return (
|
|
<Element
|
|
className={cn(
|
|
"flex items-end gap-0.5",
|
|
onClick && "cursor-pointer rounded p-1 hover:bg-muted/50",
|
|
)}
|
|
title={tooltip}
|
|
role="img"
|
|
aria-label={tooltip}
|
|
onClick={onClick}
|
|
type={onClick ? "button" : undefined}
|
|
>
|
|
{BAR_HEIGHTS.map((height, i) => (
|
|
<div
|
|
key={height}
|
|
className={cn(
|
|
"w-1 rounded-sm",
|
|
height,
|
|
i < config.filledBars ? config.color : "bg-muted",
|
|
)}
|
|
/>
|
|
))}
|
|
</Element>
|
|
);
|
|
}
|