'use client'; import { useAttunementStore, usePrestigeStore } from '@/lib/game/stores'; import { ATTUNEMENTS_DEF, ATTUNEMENT_SLOT_NAMES, getAttunementXPForLevel, MAX_ATTUNEMENT_LEVEL } from '@/lib/game/data/attunements'; import type { AttunementDef, AttunementState } from '@/lib/game/types'; import { Card, CardContent } from '@/components/ui/card'; import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; import { DebugName } from '@/components/game/debug/debug-context'; import { fmt } from '@/lib/game/stores'; import { Unlock } from 'lucide-react'; // ─── Helpers ───────────────────────────────────────────────────────────────── function getXpForNextLevel(level: number): number { if (level >= MAX_ATTUNEMENT_LEVEL) return 0; return getAttunementXPForLevel(level + 1); } function getXpProgress(state: AttunementState): number { const nextXp = getXpForNextLevel(state.level); if (nextXp <= 0) return 100; return Math.min(100, Math.round((state.experience / nextXp) * 100)); } function isAttunementUnlocked(id: string, attunements: Record): boolean { return id in attunements; } /** * Check whether an attunement's unlock condition is met. * Evaluates the condition based on current game state. */ function isUnlockConditionMet(id: string, defeatedGuardians: number[]): boolean { switch (id) { case 'invoker': return defeatedGuardians.includes(10); case 'fabricator': return false; // No specific gating condition implemented default: return false; } } // ─── Attunement Card ───────────────────────────────────────────────────────── interface AttunementCardProps { def: AttunementDef; state?: AttunementState; canUnlock?: boolean; onUnlock?: (id: string) => void; } function AttunementCard({ def, state, canUnlock, onUnlock }: AttunementCardProps) { const unlocked = !!state; const isStarting = def.unlocked === true; const xpProgress = state ? getXpProgress(state) : 0; const nextXp = state ? getXpForNextLevel(state.level) : 0; // Style tokens derived from def.color const color = def.color; return ( {/* Starting badge (top-right ribbon) */} {isStarting && unlocked && (
Starting
)} {/* Locked overlay pattern */} {!unlocked && (
)} {/* Header */}
{def.icon}

{def.name}

{ATTUNEMENT_SLOT_NAMES[def.slot] ?? def.slot}

{unlocked ? ( Lv.{state.level} ) : ( 🔒 Locked )}
{/* Description */}

{def.desc}

{/* XP Progress (unlocked only) */} {unlocked && state && (
XP Progress {fmt(state.experience)} / {fmt(nextXp)}
{state.level >= MAX_ATTUNEMENT_LEVEL && (

Maximum level reached

)}
)} {/* Unlock condition (locked only) */} {!unlocked && def.unlockCondition && (
🔒 {def.unlockCondition}
)} {/* Unlock button (locked + condition met) */} {!unlocked && canUnlock && onUnlock && (
)} {/* Details grid */}
Mana Type

{def.primaryManaType ?? 'None (pact-based)'}

Raw Regen

+{def.rawManaRegen}/hr

{def.conversionRate > 0 && (
Conversion

{def.conversionRate}/hr

)}
Status

{state?.active ? '● Active' : unlocked ? '○ Inactive' : 'Locked'}

{/* Invoker special: pact-based note */} {def.primaryManaType === undefined && (
Special

Gains elemental mana from each guardian pact signed

)}
{/* Capabilities */}
Capabilities
{def.capabilities.map((cap) => ( {cap} ))}
{/* Skill Categories */}
Skill Categories
{def.skillCategories.map((cat) => ( {cat} ))}
); } // ─── Main Component ────────────────────────────────────────────────────────── export function AttunementsTab() { const attunements = useAttunementStore((s) => s.attunements); const unlockAttunement = useAttunementStore((s) => s.unlockAttunement); const defeatedGuardians = usePrestigeStore((s) => s.defeatedGuardians); const allDefs = Object.values(ATTUNEMENTS_DEF); const unlockedCount = allDefs.filter((d) => isAttunementUnlocked(d.id, attunements)).length; const handleUnlock = (id: string) => { const prestigeState = usePrestigeStore.getState(); const success = unlockAttunement(id, prestigeState.defeatedGuardians); if (!success) { console.warn(`Failed to unlock attunement: ${id}`); } }; return (
{/* Summary header */}

Attunements

Class-like abilities tied to body locations

{unlockedCount} /{allDefs.length}

Unlocked

{/* Attunement cards */}
{allDefs.map((def) => ( ))}
); } AttunementsTab.displayName = 'AttunementsTab';