import { useMemo } from "react"; import { classById } from "../app/characterCatalog"; import { abilityAtLevel, 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({ open, onClose }: { open?: boolean; onClose?: () => void } = {}) { const storeOpen = useGameStore((state) => state.overlay === "talents"); const closeOverlay = useGameStore((state) => state.closeOverlay); const close = onClose ?? 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 ?? storeOpen)) 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}` : ""}Skills unlock automatically as you level. There are no talent points or spell ranks to assign.

{GROUPS.filter((group) => abilities.some((ability) => visibleGroup(ability, classId) === group.id)).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 locked = level < catalogAbility.unlockLevel; return {ability.name}{locked ? `Unlocks at level ${ability.unlockLevel}` : ability.secondaryClassId ? `Elite / ${secondary?.name ?? "Secondary class"}` : "Learned"}{ability.passive ? "Passive" : ability.cost.amount ? `${ability.cost.amount} ${ability.cost.resource}` : "No cost"}; })}
; })}
); }