'use client'; import { useState } from 'react'; import { Button } from '@/components/ui/button'; import { Progress } from '@/components/ui/progress'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; import { Badge } from '@/components/ui/badge'; import { ScrollArea } from '@/components/ui/scroll-area'; import { Separator } from '@/components/ui/separator'; import { Wand2, Scroll, Trash2, Plus, Minus } from 'lucide-react'; import { EQUIPMENT_TYPES } from '@/lib/game/data/equipment'; import { ENCHANTMENT_EFFECTS, calculateEffectCapacityCost } from '@/lib/game/data/enchantment-effects'; import { LOOT_DROPS, RARITY_COLORS } from '@/lib/game/data/loot-drops'; import { CRAFTING_RECIPES } from '@/lib/game/data/crafting-recipes'; import type { EquipmentInstance, EnchantmentDesign, DesignEffect, LootInventory, EquipmentCraftingProgress } from '@/lib/game/types'; import { fmt, type GameStore } from '@/lib/game/store'; // Slot display names const SLOT_NAMES: Record = { mainHand: 'Main Hand', offHand: 'Off Hand', head: 'Head', body: 'Body', hands: 'Hands', feet: 'Feet', accessory1: 'Accessory 1', accessory2: 'Accessory 2', }; export interface EnchantmentDesignerProps { store: GameStore; selectedEquipmentType: string | null; setSelectedEquipmentType: (type: string | null) => void; selectedEffects: DesignEffect[]; setSelectedEffects: (effects: DesignEffect[]) => void; designName: string; setDesignName: (name: string) => void; selectedDesign: string | null; setSelectedDesign: (id: string | null) => void; } export function EnchantmentDesigner({ store, selectedEquipmentType, setSelectedEquipmentType, selectedEffects, setSelectedEffects, designName, setDesignName, selectedDesign, setSelectedDesign, }: EnchantmentDesignerProps) { const enchantmentDesigns = store.enchantmentDesigns; const designProgress = store.designProgress; const startDesigningEnchantment = store.startDesigningEnchantment; const cancelDesign = store.cancelDesign; const deleteDesign = store.deleteDesign; const unlockedEffects = store.unlockedEffects; const skills = store.skills; const enchantingLevel = skills.enchanting || 0; const efficiencyBonus = (skills.efficientEnchant || 0) * 0.05; // Calculate total capacity cost for current design const designCapacityCost = selectedEffects.reduce( (total, eff) => total + calculateEffectCapacityCost(eff.effectId, eff.stacks, efficiencyBonus), 0 ); // Get capacity limit for selected equipment type const selectedEquipmentCapacity = selectedEquipmentType ? EQUIPMENT_TYPES[selectedEquipmentType]?.baseCapacity || 0 : 0; const isOverCapacity = selectedEquipmentType ? designCapacityCost > selectedEquipmentCapacity : false; // Calculate design time const designTime = selectedEffects.reduce((total, eff) => total + 0.5 * eff.stacks, 1); // Add effect to design const addEffect = (effectId: string) => { const existing = selectedEffects.find(e => e.effectId === effectId); const effectDef = ENCHANTMENT_EFFECTS[effectId]; if (!effectDef) return; if (existing) { if (existing.stacks < effectDef.maxStacks) { setSelectedEffects(selectedEffects.map(e => e.effectId === effectId ? { ...e, stacks: e.stacks + 1 } : e )); } } else { setSelectedEffects([...selectedEffects, { effectId, stacks: 1, capacityCost: calculateEffectCapacityCost(effectId, 1, efficiencyBonus), }]); } }; // Remove effect from design const removeEffect = (effectId: string) => { const existing = selectedEffects.find(e => e.effectId === effectId); if (!existing) return; if (existing.stacks > 1) { setSelectedEffects(selectedEffects.map(e => e.effectId === effectId ? { ...e, stacks: e.stacks - 1 } : e )); } else { setSelectedEffects(selectedEffects.filter(e => e.effectId !== effectId)); } }; // Create design const handleCreateDesign = () => { if (!designName || !selectedEquipmentType || selectedEffects.length === 0) return; const success = startDesigningEnchantment(designName, selectedEquipmentType, selectedEffects); if (success) { // Reset form setDesignName(''); setSelectedEquipmentType(null); setSelectedEffects([]); } }; // Get available effects for selected equipment type (only unlocked ones) const getAvailableEffects = () => { if (!selectedEquipmentType) return []; const type = EQUIPMENT_TYPES[selectedEquipmentType]; if (!type) return []; return Object.values(ENCHANTMENT_EFFECTS).filter( effect => effect.allowedEquipmentCategories.includes(type.category) && unlockedEffects.includes(effect.id) ); }; // Get equipment types that the player has blueprints for const getOwnedEquipmentTypes = () => { const ownedBlueprints = store.lootInventory.blueprints || []; // Map blueprint IDs to equipment type IDs const ownedEquipmentTypeIds = new Set(); for (const blueprintId of ownedBlueprints) { const recipe = CRAFTING_RECIPES[blueprintId]; if (recipe) { ownedEquipmentTypeIds.add(recipe.equipmentTypeId); } } // Also include the starting equipment types (basicStaff, civilianShirt, civilianShoes) // These are the types the player starts with, so they should be able to design for them ownedEquipmentTypeIds.add('basicStaff'); ownedEquipmentTypeIds.add('civilianShirt'); ownedEquipmentTypeIds.add('civilianShoes'); ownedEquipmentTypeIds.add('apprenticeWand'); ownedEquipmentTypeIds.add('clothHood'); ownedEquipmentTypeIds.add('civilianGloves'); ownedEquipmentTypeIds.add('copperRing'); return Object.values(EQUIPMENT_TYPES).filter(type => ownedEquipmentTypeIds.has(type.id)); }; const ownedEquipmentTypes = getOwnedEquipmentTypes(); // Render design stage return (
{/* Equipment Type Selection */} 1. Select Equipment Type {designProgress ? (
Designing for: {EQUIPMENT_TYPES[designProgress.equipmentType]?.name}
{designProgress.name}
{designProgress.progress.toFixed(1)}h / {designProgress.required.toFixed(1)}h
) : (
{ownedEquipmentTypes.map(type => (
setSelectedEquipmentType(type.id)} >
{type.name}
Cap: {type.baseCapacity}
))}
{ownedEquipmentTypes.length === 0 && (
No equipment blueprints owned. Craft or find equipment blueprints first.
)}
)}
{/* Effect Selection */} 2. Select Effects {enchantingLevel < 1 ? (

Learn Enchanting skill to design enchantments

) : designProgress ? (
Design in progress...
{designProgress.effects.map(eff => { const def = ENCHANTMENT_EFFECTS[eff.effectId]; return (
{def?.name} x{eff.stacks} {eff.capacityCost} cap
); })}
) : !selectedEquipmentType ? (
Select an equipment type first
) : ( <>
{getAvailableEffects().map(effect => { const selected = selectedEffects.find(e => e.effectId === effect.id); const cost = calculateEffectCapacityCost(effect.id, (selected?.stacks || 0) + 1, efficiencyBonus); return (
{effect.name}
{effect.description}
Cost: {effect.baseCapacityCost} cap | Max: {effect.maxStacks}
{selected && ( )}
{selected && ( {selected.stacks}/{effect.maxStacks} )}
); })}
{/* Selected effects summary */}
setDesignName(e.target.value)} className="w-full bg-gray-800 border border-gray-700 rounded px-3 py-2 text-sm" />
Total Capacity: {designCapacityCost.toFixed(0)} / {selectedEquipmentCapacity}
Design Time: {designTime.toFixed(1)}h
)}
{/* Saved Designs */} Saved Designs ({enchantmentDesigns.length}) {enchantmentDesigns.length === 0 ? (
No saved designs yet
) : (
{enchantmentDesigns.map(design => (
setSelectedDesign(design.id)} >
{design.name}
{EQUIPMENT_TYPES[design.equipmentType]?.name}
{design.effects.length} effects | {design.totalCapacityUsed} cap
))}
)}
); } EnchantmentDesigner.displayName = "EnchantmentDesigner";