'use client'; import { useEffect, useState } from 'react'; import { useGameStore, useGameLoop, fmt, fmtDec, getFloorElement, computeMaxMana, computeRegen, computeClickMana, getMeditationBonus, getIncursionStrength, canAffordSpellCost } from '@/lib/game/store'; import { getActiveEquipmentSpells, getTotalDPS } from '@/lib/game/computed-stats'; import { getDamageBreakdown } from '@/lib/game/computed-stats'; import { ELEMENTS, GUARDIANS, SPELLS_DEF, PRESTIGE_DEF, getStudySpeedMultiplier, getStudyCostMultiplier } from '@/lib/game/constants'; import { SKILL_EVOLUTION_PATHS, getTierMultiplier } from '@/lib/game/skill-evolution'; import { getUnifiedEffects, hasSpecial, SPECIAL_EFFECTS } from '@/lib/game/effects'; import { formatHour } from '@/lib/game/formatting'; 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 { RotateCcw } from 'lucide-react'; import { CraftingTab, SpireTab, SpellsTab, LabTab, SkillsTab, StatsTab, EquipmentTab, AttunementsTab, DebugTab } from '@/components/game/tabs'; import { ActionButtons, CalendarDisplay, ManaDisplay, TimeDisplay } from '@/components/game'; import { LootInventoryDisplay } from '@/components/game/LootInventory'; import { AchievementsDisplay } from '@/components/game/AchievementsDisplay'; export default function ManaLoopGame() { const [activeTab, setActiveTab] = useState('spire'); const [isGathering, setIsGathering] = useState(false); // Game store const store = useGameStore(); const gameLoop = useGameLoop(); // Computed effects from upgrades and equipment const upgradeEffects = getUnifiedEffects(store); // Derived stats const maxMana = computeMaxMana(store, upgradeEffects); const baseRegen = computeRegen(store, upgradeEffects); const clickMana = computeClickMana(store); const floorElem = getFloorElement(store.currentFloor); const floorElemDef = ELEMENTS[floorElem]; const isGuardianFloor = !!GUARDIANS[store.currentFloor]; const currentGuardian = GUARDIANS[store.currentFloor]; const meditationMultiplier = getMeditationBonus(store.meditateTicks, store.skills, upgradeEffects.meditationEfficiency); const incursionStrength = getIncursionStrength(store.day, store.hour); const studySpeedMult = getStudySpeedMultiplier(store.skills); const studyCostMult = getStudyCostMultiplier(store.skills); // 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; // Effective regen const effectiveRegen = (effectiveRegenWithSpecials + manaCascadeBonus) * meditationMultiplier; // Get all active spells from equipment const activeEquipmentSpells = getActiveEquipmentSpells(store.equippedInstances, store.equipmentInstances); // Compute total DPS const totalDPS = getTotalDPS(store, upgradeEffects, floorElem); // Auto-gather while holding useEffect(() => { if (!isGathering) return; let lastGatherTime = 0; const minGatherInterval = 100; let animationFrameId: number; const gatherLoop = (timestamp: number) => { if (timestamp - lastGatherTime >= minGatherInterval) { store.gatherMana(); lastGatherTime = timestamp; } animationFrameId = requestAnimationFrame(gatherLoop); }; animationFrameId = requestAnimationFrame(gatherLoop); return () => cancelAnimationFrame(animationFrameId); }, [isGathering, store]); // Handle gather button events const handleGatherStart = () => { setIsGathering(true); store.gatherMana(); }; const handleGatherEnd = () => { setIsGathering(false); }; // Start game loop useEffect(() => { const cleanup = gameLoop.start(); return cleanup; }, [gameLoop]); // Check if spell can be cast const canCastSpell = (spellId: string): boolean => { const spell = SPELLS_DEF[spellId]; if (!spell) return false; return canAffordSpellCost(spell.cost, store.rawMana, store.elements); }; // Game Over Screen if (store.gameOver) { return (
{store.victory ? 'VICTORY!' : 'LOOP ENDS'}

{store.victory ? 'The Awakened One falls! Your power echoes through eternity.' : 'The time loop resets... but you remember.'}

{fmt(store.loopInsight)}
Insight Gained
{store.maxFloorReached}
Best Floor
{store.signedPacts.length}
Pacts Signed
{store.loopCount + 1}
Total Loops
); } return (
{/* Header */}

MANA LOOP

{/* Main Content */}
{/* Left Panel - Mana & Actions */}
{/* Mana Display */} {/* Action Buttons */} {/* Calendar */} {/* Loot Inventory */} {/* Achievements */}
{/* Right Panel - Tabs */}
⚔️ Spire ✨ Attune 📚 Skills 🔮 Spells 🛡️ Gear 🔧 Craft 🔬 Lab 📊 Stats 🔧 Debug 📖 Grimoire {renderGrimoireTab()}
); // Grimoire Tab (Prestige) function renderGrimoireTab() { return (
{/* Current Status */} Loop Status
{store.loopCount}
Loops Completed
{fmt(store.insight)}
Current Insight
{fmt(store.totalInsight)}
Total Insight
{store.memorySlots}
Memory Slots
{/* Signed Pacts */} Signed Pacts {store.signedPacts.length === 0 ? (
No pacts signed yet. Defeat guardians to earn pacts.
) : (
{store.signedPacts.map((floor) => { const guardian = GUARDIANS[floor]; if (!guardian) return null; return (
{guardian.name}
Floor {floor}
{guardian.pact}x multiplier
); })}
)}
{/* Prestige Upgrades */} Insight Upgrades (Permanent)
{Object.entries(PRESTIGE_DEF).map(([id, def]) => { const level = store.prestigeUpgrades[id] || 0; const maxed = level >= def.max; const canBuy = !maxed && store.insight >= def.cost; return (
{def.name}
{level}/{def.max}
{def.desc}
); })}
{/* Reset Game Button */}
Reset All Progress
Clear all data and start fresh
); } } // Import TooltipProvider import { TooltipProvider } from '@/components/ui/tooltip';