'use client'; import { useEffect, useState, lazy, Suspense } from 'react'; import { useShallow } from 'zustand/react/shallow'; import { useGameStore, useUIStore, useManaStore, useCombatStore, usePrestigeStore, useCraftingStore, computeMaxMana, computeRegen, computeClickMana, getMeditationBonus, getIncursionStrength } from '@/lib/game/stores'; import { computeDisciplineEffects } from '@/lib/game/effects/discipline-effects'; import { useGameLoop } from '@/lib/game/stores/gameHooks'; import { getUnifiedEffects } from '@/lib/game/effects'; import { hasSpecial, SPECIAL_EFFECTS } from '@/lib/game/effects'; import { TimeDisplay } from '@/components/game'; import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'; import { TooltipProvider } from '@/components/ui/tooltip'; import { ErrorBoundary } from '@/components/ErrorBoundary'; import { GameOverScreen } from './components/GameOverScreen'; import { LeftPanel } from './components/LeftPanel'; import { GrimoireTab } from './components/GrimoireTab'; // Lazy load tab components const DisciplinesTab = lazy(() => import('@/components/game/tabs').then(m => ({ default: m.DisciplinesTab }))); const SpellsTab = lazy(() => import('@/components/game/tabs').then(m => ({ default: m.SpellsTab }))); const StatsTab = lazy(() => import('@/components/game/tabs').then(m => ({ default: m.StatsTab }))); const DebugTab = lazy(() => import('@/components/game/tabs').then(m => ({ default: m.DebugTab }))); const AchievementsTab = lazy(() => import('@/components/game/tabs').then(m => ({ default: m.AchievementsTab }))); const AttunementsTab = lazy(() => import('@/components/game/tabs').then(m => ({ default: m.AttunementsTab }))); const PrestigeTab = lazy(() => import('@/components/game/tabs').then(m => ({ default: m.PrestigeTab }))); const EquipmentTab = lazy(() => import('@/components/game/tabs').then(m => ({ default: m.EquipmentTab }))); const GolemancyTab = lazy(() => import('@/components/game/tabs').then(m => ({ default: m.GolemancyTab }))); const GuardianPactsTab = lazy(() => import('@/components/game/tabs').then(m => ({ default: m.GuardianPactsTab }))); const SpireSummaryTab = lazy(() => import('@/components/game/tabs').then(m => ({ default: m.SpireSummaryTab }))); const CraftingTab = lazy(() => import('@/components/game/tabs').then(m => ({ default: m.CraftingTab }))); const SpireCombatPage = lazy(() => import('@/components/game/tabs/SpireCombatPage').then(m => ({ default: m.SpireCombatPage }))); const TabFallback = () =>
Loading...
; function TabErrorFallback({ name }: { name: string }) { return
{name} tab failed to load.
; } // ─── Derived Stats Hook ────────────────────────────────────────────────────── function useGameDerivedStats() { const { prestigeUpgrades } = usePrestigeStore(useShallow(s => ({ prestigeUpgrades: s.prestigeUpgrades, }))); const { meditateTicks } = useManaStore(useShallow(s => ({ meditateTicks: s.meditateTicks, }))); const equippedInstances = useCraftingStore((s) => s.equippedInstances); const equipmentInstances = useCraftingStore((s) => s.equipmentInstances); const day = useGameStore((s) => s.day); const hour = useGameStore((s) => s.hour); const upgradeEffects = getUnifiedEffects({ skillUpgrades: {}, skillTiers: {}, equippedInstances, equipmentInstances, }); const disciplineEffects = computeDisciplineEffects(); const maxMana = computeMaxMana({ skills: {}, prestigeUpgrades, skillUpgrades: {}, skillTiers: {}, }, upgradeEffects, disciplineEffects); const baseRegen = computeRegen({ skills: {}, prestigeUpgrades, skillUpgrades: {}, skillTiers: {}, attunements: {}, }, upgradeEffects, disciplineEffects); const clickMana = computeClickMana({}, disciplineEffects); const meditationMultiplier = getMeditationBonus(meditateTicks, {}, upgradeEffects.meditationEfficiency); const incursionStrength = getIncursionStrength(day, hour); const effectiveRegenWithSpecials = baseRegen * (1 - incursionStrength); const manaCascadeBonus = hasSpecial(upgradeEffects, SPECIAL_EFFECTS.MANA_CASCADE) ? Math.floor(maxMana / 100) * 0.1 : 0; const manaWaterfallBonus = hasSpecial(upgradeEffects, SPECIAL_EFFECTS.MANA_WATERFALL) ? Math.floor(maxMana / 100) * 0.25 : 0; const effectiveRegen = (effectiveRegenWithSpecials + manaCascadeBonus + manaWaterfallBonus) * meditationMultiplier; return { maxMana, effectiveRegen, clickMana, meditationMultiplier }; } // ─── Tab Triggers ──────────────────────────────────────────────────────────── function TabTriggers() { return ( 🔮 Spells 📊 Stats 📚 Disciplines 📖 Grimoire 🐛 Debug ⚗️ Attunements 🏆 Achievements ✨ Prestige ⚔️ Equipment 🗿 Golemancy 📜 Pacts 🏔️ Spire ⚒️ Crafting ); } // ─── Lazy Tab Content ──────────────────────────────────────────────────────── function LazyTab({ name, children }: { name: string; children: React.ReactNode }) { return ( }> }> {children} ); } // ─── Main Game Component ───────────────────────────────────────────────────── export default function ManaLoopGame() { const [activeTab, setActiveTab] = useState('spells'); useGameLoop(); const { day, hour, initGame } = useGameStore(useShallow(s => ({ day: s.day, hour: s.hour, initGame: s.initGame, }))); const { insight, loopInsight } = usePrestigeStore(useShallow(s => ({ insight: s.insight, loopInsight: s.loopInsight, }))); const spireMode = useCombatStore((s) => s.spireMode); const gameOver = useUIStore((s) => s.gameOver); useGameDerivedStats(); useEffect(() => { initGame(); }, [initGame]); const [mounted, setMounted] = useState(false); useEffect(() => { setMounted(true); }, []); // eslint-disable-line react-hooks/set-state-in-effect useEffect(() => { if (spireMode) { setActiveTab('spells'); // eslint-disable-line react-hooks/set-state-in-effect } }, [spireMode]); if (gameOver) { return ; } if (!mounted) return
Loading...
; if (spireMode) { return ( { useCombatStore.getState().exitSpireMode(); }} > Loading spire...}> ); } return (

MANA LOOP

); }