Add 2014 DMG encounter difficulty calculation
All checks were successful
CI / check (push) Successful in 2m18s
CI / build-image (push) Successful in 17s

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>
This commit is contained in:
Lukas
2026-04-04 14:52:23 +02:00
parent 94e1806112
commit 817cfddabc
17 changed files with 892 additions and 257 deletions

View File

@@ -1,27 +1,44 @@
import type { DifficultyResult, DifficultyTier } from "@initiative/domain";
import { cn } from "../lib/utils.js";
const TIER_CONFIG: Record<
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; label: string }
{ filledBars: number; color: string }
> = {
trivial: { filledBars: 0, color: "", label: "Trivial" },
low: { filledBars: 1, color: "bg-green-500", label: "Low" },
moderate: { filledBars: 2, color: "bg-yellow-500", label: "Moderate" },
high: { filledBars: 3, color: "bg-red-500", label: "High" },
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_CONFIG[result.tier];
const tooltip = `${config.label} encounter difficulty`;
const config = TIER_COLORS[result.tier];
const label = labels[result.tier];
const tooltip = `${label} encounter difficulty`;
const Element = onClick ? "button" : "div";