Initial commit

This commit is contained in:
Z User
2026-04-03 17:23:15 +00:00
commit 4f474dbcf3
192 changed files with 47527 additions and 0 deletions
+193
View File
@@ -0,0 +1,193 @@
'use client';
import { useGameStore, fmt, fmtDec, computePactMultiplier } from '@/lib/game/store';
import { ELEMENTS, GUARDIANS, PRESTIGE_DEF } from '@/lib/game/constants';
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
import { Badge } from '@/components/ui/badge';
import { Button } from '@/components/ui/button';
import { RotateCcw } from 'lucide-react';
export function GrimoireTab() {
const store = useGameStore();
return (
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
{/* Current Status */}
<Card className="bg-gray-900/80 border-gray-700">
<CardHeader className="pb-2">
<CardTitle className="text-amber-400 game-panel-title text-xs">Loop Status</CardTitle>
</CardHeader>
<CardContent className="space-y-3">
<div className="grid grid-cols-2 gap-3">
<div className="p-3 bg-gray-800/50 rounded">
<div className="text-2xl font-bold text-amber-400 game-mono">{store.loopCount}</div>
<div className="text-xs text-gray-400">Loops Completed</div>
</div>
<div className="p-3 bg-gray-800/50 rounded">
<div className="text-2xl font-bold text-purple-400 game-mono">{fmt(store.insight)}</div>
<div className="text-xs text-gray-400">Current Insight</div>
</div>
<div className="p-3 bg-gray-800/50 rounded">
<div className="text-2xl font-bold text-blue-400 game-mono">{fmt(store.totalInsight)}</div>
<div className="text-xs text-gray-400">Total Insight</div>
</div>
<div className="p-3 bg-gray-800/50 rounded">
<div className="text-2xl font-bold text-green-400 game-mono">{store.memorySlots}</div>
<div className="text-xs text-gray-400">Memory Slots</div>
</div>
</div>
</CardContent>
</Card>
{/* Signed Pacts */}
<Card className="bg-gray-900/80 border-gray-700 lg:col-span-2">
<CardHeader className="pb-2">
<div className="flex items-center justify-between">
<CardTitle className="text-amber-400 game-panel-title text-xs">Signed Pacts ({store.signedPacts.length}/{1 + (store.prestigeUpgrades.pactCapacity || 0)})</CardTitle>
{store.signedPacts.length > 1 && (
<div className="text-xs text-gray-400">
Combined: ×{fmtDec(computePactMultiplier(store), 2)} damage
</div>
)}
</div>
</CardHeader>
<CardContent>
{store.signedPacts.length === 0 ? (
<div className="text-gray-500 text-sm">No pacts signed yet. Defeat guardians to earn pacts.</div>
) : (
<div className="grid grid-cols-1 md:grid-cols-2 gap-3">
{store.signedPacts.map((floor) => {
const guardian = GUARDIANS[floor];
if (!guardian) return null;
return (
<div
key={floor}
className="p-3 rounded border"
style={{ borderColor: guardian.color, backgroundColor: `${guardian.color}10` }}
>
<div className="flex items-center justify-between mb-2">
<div>
<div className="font-semibold text-sm" style={{ color: guardian.color }}>
{guardian.name}
</div>
<div className="text-xs text-gray-400">{guardian.theme} Floor {floor}</div>
</div>
<Badge style={{ backgroundColor: `${guardian.color}30`, color: guardian.color }}>
{guardian.damageMultiplier}x dmg / {guardian.insightMultiplier}x insight
</Badge>
</div>
{/* Unique Boon */}
{guardian.uniqueBoon && (
<div className="mb-2 p-2 bg-cyan-900/20 rounded border border-cyan-800/30">
<div className="text-xs font-semibold text-cyan-300"> {guardian.uniqueBoon.name}</div>
<div className="text-xs text-cyan-200/70">{guardian.uniqueBoon.desc}</div>
</div>
)}
{/* Perks & Costs */}
<div className="grid grid-cols-2 gap-2 text-xs">
{guardian.perks.length > 0 && (
<div>
<div className="text-green-400 font-semibold mb-1">Perks</div>
{guardian.perks.map(perk => (
<div key={perk.id} className="text-green-300/70"> {perk.desc}</div>
))}
</div>
)}
{guardian.costs.length > 0 && (
<div>
<div className="text-red-400 font-semibold mb-1">Costs</div>
{guardian.costs.map(cost => (
<div key={cost.id} className="text-red-300/70"> {cost.desc}</div>
))}
</div>
)}
</div>
{/* Unlocked Mana */}
{guardian.unlocksMana.length > 0 && (
<div className="mt-2 flex flex-wrap gap-1">
{guardian.unlocksMana.map(elemId => {
const elem = ELEMENTS[elemId];
return (
<Badge key={elemId} variant="outline" className="text-xs" style={{ borderColor: elem?.color, color: elem?.color }}>
{elem?.sym}
</Badge>
);
})}
</div>
)}
</div>
);
})}
</div>
)}
</CardContent>
</Card>
{/* Prestige Upgrades */}
<Card className="bg-gray-900/80 border-gray-700 lg:col-span-2">
<CardHeader className="pb-2">
<CardTitle className="text-amber-400 game-panel-title text-xs">Insight Upgrades (Permanent)</CardTitle>
</CardHeader>
<CardContent>
<div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-3 gap-3">
{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 (
<div
key={id}
className="p-3 rounded border border-gray-700 bg-gray-800/50"
>
<div className="flex items-center justify-between mb-2">
<div className="font-semibold text-amber-400 text-sm">{def.name}</div>
<Badge variant="outline" className="text-xs">
{level}/{def.max}
</Badge>
</div>
<div className="text-xs text-gray-400 italic mb-2">{def.desc}</div>
<Button
size="sm"
variant={canBuy ? 'default' : 'outline'}
className="w-full"
disabled={!canBuy}
onClick={() => store.doPrestige(id)}
>
{maxed ? 'Maxed' : `Upgrade (${fmt(def.cost)} insight)`}
</Button>
</div>
);
})}
</div>
{/* Reset Game Button */}
<div className="mt-4 pt-4 border-t border-gray-700">
<div className="flex items-center justify-between">
<div>
<div className="text-sm text-gray-400">Reset All Progress</div>
<div className="text-xs text-gray-500">Clear all data and start fresh</div>
</div>
<Button
size="sm"
variant="outline"
className="border-red-600/50 text-red-400 hover:bg-red-900/20"
onClick={() => {
if (confirm('Are you sure you want to reset ALL progress? This cannot be undone!')) {
store.resetGame();
}
}}
>
<RotateCcw className="w-4 h-4 mr-1" />
Reset
</Button>
</div>
</div>
</CardContent>
</Card>
</div>
);
}