import { useMemo } from "react"; import { classById } from "../app/characterCatalog"; import { abilityAtLevel, abilityRankForLevel, type AbilityDefinition } from "../game/abilityCatalog"; import { useCombatStore } from "../game/combatStore"; import { useGameStore } from "../game/store"; import { useMenuController, type MenuAction } from "../input/useMenuController"; import { ControllerButton } from "./ControllerButton"; const GROUPS = [ { id: "primary", label: "Primary" }, { id: "general", label: "Secondary General" }, { id: "elite", label: "Elite" }, { id: "passive", label: "Passive" }, ] as const; function visibleGroup(ability: AbilityDefinition, primaryClassId: string): (typeof GROUPS)[number]["id"] { if (ability.passive) return "passive"; if (ability.romSkillGroup === "elite") return "elite"; if (ability.classId !== primaryClassId) return "general"; return "primary"; } export function RomSkillsPanel() { const open = useGameStore((state) => state.overlay === "talents"); const close = useGameStore((state) => state.closeOverlay); const classId = useCombatStore((state) => state.classId); const secondaryClassId = useCombatStore((state) => state.secondaryClassId); const level = useCombatStore((state) => state.level); const abilities = useCombatStore((state) => state.abilities); const actions = useMemo(() => [ ...abilities.map((ability) => ({ id: `rom-skill-${ability.id}`, run: () => undefined })), { id: "rom-skills-close", run: close }, ], [abilities, close]); const controller = useMenuController(actions, { initialId: abilities[0] ? `rom-skill-${abilities[0].id}` : "rom-skills-close", onBack: close }); if (!open) return null; const primary = classById(classId); const secondary = secondaryClassId ? classById(secondaryClassId) : null; return (

Runes of Magic / Automatic progression

Skills

Close

{primary.name}{secondary ? ` / ${secondary.name}` : ""}Ranks automatically use the highest source rank available at level {level}. No training-point allocation is required.

{GROUPS.map((group) => { const entries = abilities.filter((ability) => visibleGroup(ability, classId) === group.id); return

{group.label}

{entries.filter((ability) => level >= ability.unlockLevel).length} / {entries.length}
{entries.map((catalogAbility) => { const ability = abilityAtLevel(catalogAbility, level); const rank = abilityRankForLevel(catalogAbility, level); const locked = level < catalogAbility.unlockLevel; return {ability.name}{locked ? `Unlocks at level ${ability.unlockLevel}` : `Rank ${rank?.rank ?? 1}${ability.secondaryClassId ? ` / ${secondary?.name ?? "Elite"}` : ""}`}{ability.passive ? "Passive" : ability.cost.amount ? `${ability.cost.amount} ${ability.cost.resource}` : "No cost"}; })}
; })}
); }