// ─── Crafting Design System ───────────────────────────────────────────────── // Design system functions: calculateDesignTime, capacity cost, XP, etc. import type { EnchantmentDesign, DesignEffect, AppliedEnchantment } from './types'; import { calculateEnchantingXP } from './data/attunements'; import { ENCHANTMENT_EFFECTS, calculateEffectCapacityCost } from './data/enchantment-effects'; import { hasSpecial, SPECIAL_EFFECTS } from './effects/special-effects'; import { computeEffects } from './effects/upgrade-effects'; import { EQUIPMENT_TYPES, type EquipmentCategory } from './data/equipment'; // ─── Design Creation & Calculation ────────────────────────────────────────── // Validate effects for a design against equipment category export function validateDesignEffects( effects: DesignEffect[], equipmentTypeId: string, enchantingLevel: number ): { valid: boolean; reason?: string } { if (enchantingLevel < 1) { return { valid: false, reason: 'Requires enchanting skill level 1' }; } const equipType = EQUIPMENT_TYPES[equipmentTypeId]; if (!equipType) { return { valid: false, reason: 'Invalid equipment type' }; } const category = equipType.category; if (!category) { return { valid: false, reason: 'Invalid equipment category' }; } for (const eff of effects) { const effectDef = ENCHANTMENT_EFFECTS[eff.effectId]; if (!effectDef) { return { valid: false, reason: `Unknown effect: ${eff.effectId}` }; } if (!effectDef.allowedEquipmentCategories.includes(category)) { return { valid: false, reason: `Effect ${eff.effectId} not allowed on ${category}` }; } if (eff.stacks > effectDef.maxStacks) { return { valid: false, reason: `Stacks exceed maximum for ${eff.effectId}` }; } } return { valid: true }; } // Create an enchantment design from validated inputs export function createEnchantmentDesign( name: string, equipmentType: string, effects: DesignEffect[], efficiencyBonus: number = 0 ): EnchantmentDesign { const totalCapacityUsed = calculateDesignCapacityCost(effects, efficiencyBonus); const designTime = calculateDesignTime(effects); return { id: `design_${Date.now()}`, name, equipmentType, effects, totalCapacityUsed, designTime, created: Date.now(), }; } // ─── Capacity Cost Calculation ────────────────────────────────────────────── export function calculateDesignCapacityCost(effects: DesignEffect[], efficiencyBonus: number = 0): number { return effects.reduce((total, eff) => total + calculateEffectCapacityCost(eff.effectId, eff.stacks, efficiencyBonus), 0); } export function calculateTotalCapacityCost(design: EnchantmentDesign): number { return design.totalCapacityUsed; } // ─── XP & Progression ─────────────────────────────────────────────────────── export function calculateEnchantingXpFromDesign(design: EnchantmentDesign): number { return calculateEnchantingXP(design.totalCapacityUsed); } export function calculateXpFromInstanceEnchantments( instance: { enchantments: AppliedEnchantment[] } ): number { let totalXp = 0; for (const ench of instance.enchantments) { const effectDef = ENCHANTMENT_EFFECTS[ench.effectId]; const baseCost = effectDef?.baseCapacityCost || 0; totalXp += calculateEnchantingXP(baseCost * ench.stacks); } return totalXp; } // ─── Design Time Calculations ────────────────────────────────────────────── export function calculateDesignTime(effects: DesignEffect[]): number { let time = 1; for (const eff of effects) { const effectDef = ENCHANTMENT_EFFECTS[eff.effectId]; if (effectDef) { time += 0.5 * eff.stacks; } } return time; } export function getDesignTimeWithHaste( effects: DesignEffect[], isRepeatDesign: boolean, computedEffects: any ): number { let time = calculateDesignTime(effects); if (isRepeatDesign && hasSpecial(computedEffects, SPECIAL_EFFECTS.HASTY_ENCHANTER)) { time *= 0.75; } return time; } // ─── Progress Calculations ────────────────────────────────────────────────── export interface DesignProgressUpdate { progress: number; required: number; isComplete: boolean; timeBonus: number; } export function calculateDesignProgress( currentProgress: number, required: number, computedEffects: any, isRepeatDesign: boolean ): DesignProgressUpdate { let progress = currentProgress + 0.04; let timeBonus = 0; if (isRepeatDesign && hasSpecial(computedEffects, SPECIAL_EFFECTS.HASTY_ENCHANTER)) { timeBonus = 0.04 * 0.25; progress += timeBonus; } if (hasSpecial(computedEffects, SPECIAL_EFFECTS.INSTANT_DESIGNS) && Math.random() < 0.10) { progress = required; } return { progress, required, isComplete: progress >= required, timeBonus }; } export function calculateSecondDesignProgress( currentProgress: number, required: number, computedEffects: any, isRepeatDesign: boolean ): DesignProgressUpdate { return calculateDesignProgress(currentProgress, required, computedEffects, isRepeatDesign); } export function isSecondDesignSlotAvailable( designProgress: any, designProgress2: any, hasEnchantMastery: boolean ): boolean { if (!designProgress && !designProgress2) return true; if (!designProgress && designProgress2) return false; if (designProgress && !designProgress2 && hasEnchantMastery) return true; return false; } // ─── Auto-save Completed Design ──────────────────────────────────────────── export function createCompletedDesignFromProgress( progressData: { designId: string; name: string; equipmentType: string; effects: DesignEffect[]; required: number; }, efficiencyBonus: number = 0 ): EnchantmentDesign { const totalCapacityCost = calculateDesignCapacityCost(progressData.effects, efficiencyBonus); return { id: progressData.designId, name: progressData.name, equipmentType: progressData.equipmentType, effects: progressData.effects, totalCapacityUsed: totalCapacityCost, designTime: progressData.required, created: Date.now(), }; } // ─── Design Management ────────────────────────────────────────────────────── export interface DesignWithCapacityInfo { design: EnchantmentDesign; fitsInEquipment: boolean; availableCapacity: number; } export function filterDesignsByEquipment( designs: EnchantmentDesign[], equipment: { instanceId: string; totalCapacity: number; usedCapacity: number } | null ): DesignWithCapacityInfo[] { if (!equipment) return []; return designs.map(design => ({ design, fitsInEquipment: designFitsInEquipment(design, { ...equipment, enchantments: [], rarity: 'common', quality: 100, typeId: '', name: '', } as any), availableCapacity: equipment.totalCapacity - equipment.usedCapacity, })); } function designFitsInEquipment(design: EnchantmentDesign, instance: any): boolean { return (instance.usedCapacity || 0) + design.totalCapacityUsed <= instance.totalCapacity; }