'use client';
import { useEffect, useState, lazy, Suspense } from 'react';
import type { JSX } from 'react';
// Import from new modular stores
import {
useGameStore,
useUIStore,
useManaStore,
useSkillStore,
useCombatStore,
usePrestigeStore,
useCraftingStore,
fmt,
computeMaxMana,
computeRegen,
computeClickMana,
getMeditationBonus,
getIncursionStrength,
} from '@/lib/game/stores';
import { useGameLoop } from '@/lib/game/stores/gameHooks';
import { getUnifiedEffects } from '@/lib/game/effects';
import {
getStudySpeedMultiplier,
getStudyCostMultiplier,
SPELLS_DEF,
ELEMENTS,
GUARDIANS,
} from '@/lib/game/constants';
import { getActiveEquipmentSpells, getTotalDPS } from '@/lib/game/computed-stats';
import { TimeDisplay } from '@/components/game';
import { hasSpecial, SPECIAL_EFFECTS } from '@/lib/game/effects';
import { Button } from '@/components/ui/button';
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { ScrollArea } from '@/components/ui/scroll-area';
import { RotateCcw, Mountain } from 'lucide-react';
import { TooltipProvider } from '@/components/ui/tooltip';
import { ErrorBoundary } from '@/components/ErrorBoundary';
// Import extracted components
import { GameOverScreen } from './components/GameOverScreen';
import { LeftPanel } from './components/LeftPanel';
// Lazy load tab components
const SpireTab = lazy(() => import('@/components/game/tabs').then(module => ({ default: module.SpireTab })));
const SkillsTab = lazy(() => import('@/components/game/tabs').then(module => ({ default: module.SkillsTab })));
const SpellsTab = lazy(() => import('@/components/game/tabs').then(module => ({ default: module.SpellsTab })));
const LabTab = lazy(() => import('@/components/game/tabs').then(module => ({ default: module.LabTab })));
const StatsTab = lazy(() => import('@/components/game/tabs').then(module => ({ default: module.StatsTab })));
const EquipmentTab = lazy(() => import('@/components/game/tabs').then(module => ({ default: module.EquipmentTab })));
const AttunementsTab = lazy(() => import('@/components/game/tabs').then(module => ({ default: module.AttunementsTab })));
const DebugTab = lazy(() => import('@/components/game/tabs').then(module => ({ default: module.DebugTab })));
const LootTab = lazy(() => import('@/components/game/tabs').then(module => ({ default: module.LootTab })));
const AchievementsTab = lazy(() => import('@/components/game/tabs').then(module => ({ default: module.AchievementsTab })));
const GolemancyTab = lazy(() => import('@/components/game/tabs').then(module => ({ default: module.GolemancyTab })));
const CraftingTab = lazy(() => import('@/components/game/tabs').then(module => ({ default: module.CraftingTab })));
const TabLoadingFallback = () =>
Loading...
;
// ============================================================================
// Grimoire Tab Component
// ============================================================================
function GrimoireTab() {
// Handle SSR - dont access SPELLS_DEF during server-side rendering
// Use state and useEffect to only access on client-side
const [grimoireSpells, setGrimoireSpells] = useState([]);
useEffect(() => {
// Only access SPELLS_DEF on client-side
if (typeof window !== 'undefined' && SPELLS_DEF) {
const filtered = Object.values(SPELLS_DEF || {}).filter((s: any) => s.grimoire);
// eslint-disable-next-line react-hooks/set-state-in-effect
setGrimoireSpells(filtered);
}
}, []);
if (!grimoireSpells.length) {
return Loading grimoire...
;
}
const availablePages = Math.ceil(grimoireSpells.length / 12);
return (
A vast tome of arcane knowledge. Study carefully — each spell costs insight to transcribe into your repertoire.
Available pages: {availablePages}. Spells in grimoire: {grimoireSpells.length}.
{grimoireSpells.map((spell: any) => (
{spell.name}
{spell.element}
{spell.desc}
Cost: {(spell.cost as any[]).map((c: any) => `${c.amount} ${c.type}`).join(', ')}
Power: {spell.power}
{spell.effect &&
Effect: {spell.effect}
}
))}
);
}
// ============================================================================
// Main Game Component
// ============================================================================
export default function ManaLoopGame() {
const [selectedManaType, setSelectedManaType] = useState('');
const [activeTab, setActiveTab] = useState('spire');
// ALL hooks must be called before any conditional returns
const day = useGameStore((s) => s.day);
const hour = useGameStore((s) => s.hour);
const initGame = useGameStore((s) => s.initGame);
useGameLoop();
const skills = useSkillStore((s) => s.skills);
const skillTiers = useSkillStore((s) => s.skillTiers);
const skillUpgrades = useSkillStore((s) => s.skillUpgrades);
const prestigeUpgrades = usePrestigeStore((s) => s.prestigeUpgrades);
const insight = usePrestigeStore((s) => s.insight);
const rawMana = useManaStore((s) => s.rawMana);
const meditateTicks = useManaStore((s) => s.meditateTicks);
const maxFloorReached = useCombatStore((s) => s.maxFloorReached);
const spells = useCombatStore((s) => s.spells);
const gameOver = useUIStore((s) => s.gameOver);
// Get equipment state from crafting store
const equippedInstances = useCraftingStore((s) => s.equippedInstances);
const equipmentInstances = useCraftingStore((s) => s.equipmentInstances);
// Derived state
const upgradeEffects = getUnifiedEffects({
skillUpgrades,
skillTiers,
equippedInstances,
equipmentInstances
});
const maxMana = computeMaxMana({
skills,
prestigeUpgrades,
skillUpgrades,
skillTiers
}, upgradeEffects);
const baseRegen = computeRegen({
skills,
prestigeUpgrades,
skillUpgrades,
skillTiers
}, upgradeEffects);
const clickMana = computeClickMana({
skills,
prestigeUpgrades,
skillUpgrades,
skillTiers
});
const meditationMultiplier = getMeditationBonus(meditateTicks, skills, upgradeEffects.meditationEfficiency);
const incursionStrength = getIncursionStrength(day, hour);
// Effective regen with incursion penalty
const effectiveRegenWithSpecials = baseRegen * (1 - incursionStrength);
// Mana Cascade bonus
const manaCascadeBonus = hasSpecial(upgradeEffects, SPECIAL_EFFECTS.MANA_CASCADE)
? Math.floor(maxMana / 100) * 0.1
: 0;
// Mana Waterfall bonus
const manaWaterfallBonus = hasSpecial(upgradeEffects, SPECIAL_EFFECTS.MANA_WATERFALL)
? Math.floor(maxMana / 100) * 0.25
: 0;
// Effective regen
const effectiveRegen = (effectiveRegenWithSpecials + manaCascadeBonus + manaWaterfallBonus) * meditationMultiplier;
// Initialize game on mount
useEffect(() => {
initGame();
}, [initGame]);
// Conditional returns AFTER all hooks
if (gameOver) {
return ;
}
if (typeof window === 'undefined') {
return Loading...
;
}
return (
{/* Header */}
{/* Main Content */}
⚔️ Spire
✨ Attune
🗿 Golems
📚 Skills
🔮 Spells
🛡️ Gear
🔧 Craft
💎 Loot
🏆 Achieve
🔬 Lab
📊 Stats
🐛 Debug
📖 Grimoire
spire tab failed to load.
}>
}>
attunements tab failed to load. }>
}>
golemancy tab failed to load.}>
}>
skills tab failed to load.}>
}>
spells tab failed to load.}>
}>
equipment tab failed to load.}>
}>
crafting tab failed to load.}>
}>
loot tab failed to load.}>
}>
achievements tab failed to load.}>
}>
lab tab failed to load.}>
}>
stats tab failed to load.}>
}>
debug tab failed to load.}>
}>
);
}