Files
Mana-Loop/src/components/game/tabs/SpellsTab.tsx
T
n8n-gitea 25ba565467
Build and Publish Mana Loop Docker Image / build-and-publish (push) Successful in 1m25s
chore: remove unused imports, vars, and params — 84 imports, 7 vars, 16 params across 45+ files
2026-05-25 20:18:39 +02:00

129 lines
5.4 KiB
TypeScript
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
'use client';
import { canAffordSpellCost } from '@/lib/game/stores';
import { useCombatStore, useManaStore } from '@/lib/game/stores';
import { ELEMENTS, SPELLS_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';
// Format spell cost for display
function formatSpellCost(cost: { type: 'raw' | 'element'; element?: string; amount: number }): string {
if (cost.type === 'raw') {
return `${cost.amount} raw`;
}
const elemDef = ELEMENTS[cost.element || ''];
return `${cost.amount} ${elemDef?.sym || '?'}`;
}
// Get cost color
function getSpellCostColor(cost: { type: 'raw' | 'element'; element?: string; amount: number }): string {
if (cost.type === 'raw') {
return '#60A5FA';
}
return ELEMENTS[cost.element || '']?.color || '#9CA3AF';
}
export function SpellsTab() {
const spells = useCombatStore((s) => s.spells);
const activeSpell = useCombatStore((s) => s.activeSpell);
const setSpell = useCombatStore((s) => s.setSpell);
const rawMana = useManaStore((s) => s.rawMana);
const elements = useManaStore((s) => s.elements);
const spellTiers = [0, 1, 2, 3, 4];
return (
<div className="space-y-6">
{spellTiers.map(tier => {
const spellsInTier = Object.entries(SPELLS_DEF).filter(([, def]) => def.tier === tier);
if (spellsInTier.length === 0) return null;
const tierNames = ['Basic Spells (Raw Mana)', 'Tier 1 - Elemental', 'Tier 2 - Advanced', 'Tier 3 - Master', 'Tier 4 - Legendary'];
const tierColors = ['text-gray-400', 'text-green-400', 'text-blue-400', 'text-purple-400', 'text-amber-400'];
return (
<div key={tier}>
<h3 className={`text-lg font-semibold mb-3 ${tierColors[tier]}`}>{tierNames[tier]}</h3>
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-4">
{spellsInTier.map(([id, def]) => {
const state = spells?.[id];
const learned = state?.learned;
const elemDef = def.elem === 'raw' ? null : ELEMENTS[def.elem];
const isActive = activeSpell === id;
const canCast = learned && canAffordSpellCost(def.cost, rawMana, elements);
return (
<Card
key={id}
className={`bg-gray-900/80 border-gray-700 ${learned ? '' : 'opacity-75'} ${canCast ? 'ring-1 ring-green-500/30' : ''}`}
>
<CardHeader className="pb-2">
<div className="flex items-center justify-between">
<CardTitle className="text-sm game-panel-title" style={{ color: def.elem === 'raw' ? '#60A5FA' : elemDef?.color }}>
{def.name}
</CardTitle>
{def.tier > 0 && (
<Badge variant="outline" className="text-xs">
T{def.tier}
</Badge>
)}
</div>
</CardHeader>
<CardContent className="space-y-2">
<div className="text-xs text-gray-400">
{def.elem !== 'raw' && <span className="mr-2">{elemDef?.sym} {elemDef?.name}</span>}
<span className="mr-2"> {def.dmg} dmg</span>
</div>
{/* Cost display */}
<div className="text-xs game-mono" style={{ color: getSpellCostColor(def.cost) }}>
Cost: {formatSpellCost(def.cost)}
</div>
{def.desc && (
<div className="text-xs text-gray-500 italic">{def.desc}</div>
)}
{def.effects && Array.isArray(def.effects) && def.effects.length > 0 && (
<div className="flex gap-1 flex-wrap">
{def.effects.map((eff, i) => (
<Badge key={i} variant="outline" className="text-xs">
{eff.type === 'burn' && `🔥 Burn`}
{eff.type === 'stun' && `⚡ Stun`}
{eff.type === 'pierce' && `🎯 Pierce`}
{eff.type === 'multicast' && `✨ Multicast`}
</Badge>
))}
</div>
)}
{learned ? (
<div className="flex gap-2">
<Badge className="bg-green-900/50 text-green-300">Learned</Badge>
{isActive && <Badge className="bg-amber-900/50 text-amber-300">Active</Badge>}
{!isActive && (
<Button size="sm" variant="outline" onClick={() => setSpell(id)}>
Set Active
</Button>
)}
</div>
) : (
<div className="text-xs text-gray-500">
Not yet learned
</div>
)}
</CardContent>
</Card>
);
})}
</div>
</div>
);
})}
</div>
);
}
SpellsTab.displayName = "SpellsTab";