219 lines
9.7 KiB
TypeScript
219 lines
9.7 KiB
TypeScript
'use client';
|
||
|
||
import { Button } from '@/components/ui/button';
|
||
import { Progress } from '@/components/ui/progress';
|
||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card';
|
||
import { ScrollArea } from '@/components/ui/scroll-area';
|
||
import { Separator } from '@/components/ui/separator';
|
||
import { Trash2 } from 'lucide-react';
|
||
import { EQUIPMENT_TYPES } from '@/lib/game/data/equipment';
|
||
import type { EquipmentInstance, AppliedEnchantment, LootInventory, EquipmentCraftingProgress, EquipmentSlot } from '@/lib/game/types';
|
||
import { fmt, type GameStore } from '@/lib/game/store';
|
||
|
||
// Slot display names
|
||
const SLOT_NAMES: Record<EquipmentSlot, string> = {
|
||
mainHand: 'Main Hand',
|
||
offHand: 'Off Hand',
|
||
head: 'Head',
|
||
body: 'Body',
|
||
hands: 'Hands',
|
||
feet: 'Feet',
|
||
accessory1: 'Accessory 1',
|
||
accessory2: 'Accessory 2',
|
||
};
|
||
|
||
export interface EnchantmentPreparerProps {
|
||
store: GameStore;
|
||
selectedEquipmentInstance: string | null;
|
||
setSelectedEquipmentInstance: (id: string | null) => void;
|
||
}
|
||
|
||
export function EnchantmentPreparer({
|
||
store,
|
||
selectedEquipmentInstance,
|
||
setSelectedEquipmentInstance,
|
||
}: EnchantmentPreparerProps) {
|
||
const equippedInstances = store.equippedInstances;
|
||
const equipmentInstances = store.equipmentInstances;
|
||
const preparationProgress = store.preparationProgress;
|
||
const rawMana = store.rawMana;
|
||
const skills = store.skills;
|
||
const startPreparing = store.startPreparing;
|
||
const cancelPreparation = store.cancelPreparation;
|
||
|
||
// Get equipped items as array
|
||
const equippedItems = Object.entries(equippedInstances)
|
||
.filter(([, instanceId]) => instanceId && equipmentInstances[instanceId])
|
||
.map(([slot, instanceId]) => ({
|
||
slot: slot as EquipmentSlot,
|
||
instance: equipmentInstances[instanceId!],
|
||
}));
|
||
|
||
return (
|
||
<div className="grid grid-cols-1 lg:grid-cols-2 gap-4">
|
||
{/* Equipment Selection */}
|
||
<Card className="bg-gray-900/80 border-gray-700">
|
||
<CardHeader className="pb-2">
|
||
<CardTitle className="text-amber-400 text-sm">Select Equipment to Prepare</CardTitle>
|
||
</CardHeader>
|
||
<CardContent>
|
||
{preparationProgress ? (
|
||
<div className="space-y-3">
|
||
<div className="text-sm text-gray-400">
|
||
Preparing: {equipmentInstances[preparationProgress.equipmentInstanceId]?.name}
|
||
</div>
|
||
<Progress value={(preparationProgress.progress / preparationProgress.required) * 100} className="h-3" />
|
||
<div className="flex justify-between text-xs text-gray-400">
|
||
<span>{preparationProgress.progress.toFixed(1)}h / {preparationProgress.required.toFixed(1)}h</span>
|
||
<span>Mana paid: {fmt(preparationProgress.manaCostPaid)}</span>
|
||
</div>
|
||
<Button size="sm" variant="outline" onClick={cancelPreparation}>Cancel</Button>
|
||
</div>
|
||
) : (
|
||
<ScrollArea className="h-64">
|
||
<div className="space-y-2">
|
||
{equippedItems.map(({ slot, instance }) => {
|
||
const hasEnchantments = instance.enchantments.length > 0;
|
||
const isReady = instance.tags?.includes('Ready for Enchantment');
|
||
return (
|
||
<div
|
||
key={instance.instanceId}
|
||
className={`p-3 rounded border cursor-pointer transition-all ${
|
||
selectedEquipmentInstance === instance.instanceId
|
||
? 'border-amber-500 bg-amber-900/20'
|
||
: 'border-gray-700 bg-gray-800/50 hover:border-gray-600'
|
||
} ${hasEnchantments ? 'border-l-4 border-l-red-600' : ''} ${isReady ? 'border-l-4 border-l-green-600' : ''}`}
|
||
onClick={() => setSelectedEquipmentInstance(instance.instanceId)}
|
||
>
|
||
<div className="flex justify-between">
|
||
<div>
|
||
<div className="font-semibold">{instance.name}</div>
|
||
<div className="text-xs text-gray-400">{SLOT_NAMES[slot]}</div>
|
||
{hasEnchantments && (
|
||
<div className="text-xs text-red-400 mt-1">
|
||
⚠️ {instance.enchantments.length} enchantments - Preparation will remove them
|
||
</div>
|
||
)}
|
||
{isReady && (
|
||
<div className="text-xs text-green-400 mt-1">
|
||
✅ Ready for Enchantment
|
||
</div>
|
||
)}
|
||
</div>
|
||
<div className="text-right text-sm">
|
||
<div className="text-green-400">{instance.usedCapacity}/{instance.totalCapacity} cap</div>
|
||
<div className="text-xs text-gray-400">{instance.enchantments.length} enchants</div>
|
||
</div>
|
||
</div>
|
||
</div>
|
||
);
|
||
})}
|
||
{equippedItems.length === 0 && (
|
||
<div className="text-center text-gray-400 py-4">No equipped items</div>
|
||
)}
|
||
</div>
|
||
</ScrollArea>
|
||
)}
|
||
</CardContent>
|
||
</Card>
|
||
|
||
{/* Preparation Details */}
|
||
<Card className="bg-gray-900/80 border-gray-700">
|
||
<CardHeader className="pb-2">
|
||
<CardTitle className="text-amber-400 text-sm">Preparation Details</CardTitle>
|
||
</CardHeader>
|
||
<CardContent>
|
||
{!selectedEquipmentInstance ? (
|
||
<div className="text-center text-gray-400 py-8">
|
||
Select equipment to prepare
|
||
</div>
|
||
) : preparationProgress ? (
|
||
<div className="text-gray-400">Preparation in progress...</div>
|
||
) : (
|
||
(() => {
|
||
const instance = equipmentInstances[selectedEquipmentInstance];
|
||
if (!instance) return null;
|
||
const hasEnchantments = instance.enchantments.length > 0;
|
||
const isReady = instance.tags?.includes('Ready for Enchantment');
|
||
const prepTime = 2 + Math.floor(instance.totalCapacity / 50);
|
||
const manaCost = instance.totalCapacity * 10;
|
||
|
||
// Calculate disenchant recovery
|
||
const recoveryRate = 0.1; // Base recovery rate (disenchanting skill removed)
|
||
const totalRecoverable = instance.enchantments.reduce(
|
||
(sum, e) => sum + Math.floor(e.actualCost * recoveryRate),
|
||
0
|
||
);
|
||
|
||
return (
|
||
<div className="space-y-4">
|
||
<div className="text-lg font-semibold">{instance.name}</div>
|
||
<Separator className="bg-gray-700" />
|
||
|
||
{/* Show warning if item has enchantments */}
|
||
{hasEnchantments && !isReady && (
|
||
<div className="p-3 rounded border border-red-600/50 bg-red-900/20">
|
||
<div className="text-sm font-semibold text-red-400">⚠️ Equipment has enchantments</div>
|
||
<div className="text-xs text-gray-400 mt-1">
|
||
Preparation will remove all existing enchantments and recover some mana.
|
||
</div>
|
||
<div className="flex justify-between text-sm mt-2">
|
||
<span className="text-gray-400">Recoverable Mana:</span>
|
||
<span className="text-green-400">{fmt(totalRecoverable)}</span>
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
{/* Show ready status */}
|
||
{isReady && (
|
||
<div className="p-3 rounded border border-green-600/50 bg-green-900/20">
|
||
<div className="text-sm font-semibold text-green-400">✅ Ready for Enchantment</div>
|
||
<div className="text-xs text-gray-400 mt-1">
|
||
This item has been prepared and is ready for enchantment application.
|
||
</div>
|
||
</div>
|
||
)}
|
||
|
||
<div className="space-y-2 text-sm">
|
||
<div className="flex justify-between">
|
||
<span className="text-gray-400">Capacity:</span>
|
||
<span>{instance.usedCapacity}/{instance.totalCapacity}</span>
|
||
</div>
|
||
<div className="flex justify-between">
|
||
<span className="text-gray-400">Prep Time:</span>
|
||
<span>{prepTime}h</span>
|
||
</div>
|
||
<div className="flex justify-between">
|
||
<span className="text-gray-400">Mana Cost:</span>
|
||
<span className={rawMana < manaCost ? 'text-red-400' : 'text-green-400'}>
|
||
{fmt(manaCost)}
|
||
</span>
|
||
</div>
|
||
</div>
|
||
|
||
<Button
|
||
className="w-full"
|
||
disabled={rawMana < manaCost || isReady}
|
||
onClick={() => startPreparing(selectedEquipmentInstance)}
|
||
>
|
||
{hasEnchantments ? (
|
||
<>
|
||
<Trash2 className="w-4 h-4 mr-2" />
|
||
Start Preparation — this will remove existing enchantments ({prepTime}h, {fmt(manaCost)} mana)
|
||
</>
|
||
) : (
|
||
<>Start Preparation ({prepTime}h, {fmt(manaCost)} mana)</>
|
||
)}
|
||
</Button>
|
||
</div>
|
||
);
|
||
})()
|
||
)}
|
||
</CardContent>
|
||
</Card>
|
||
</div>
|
||
);
|
||
}
|
||
|
||
EnchantmentPreparer.displayName = "EnchantmentPreparer";
|