/** * 制造系统 - 配方管理、制造逻辑、品质计算 * Phase 6 核心系统实现 */ import { ITEM_CONFIG } from '@/config/items.js' import { RECIPE_CONFIG, getAvailableRecipes, checkMaterials } from '@/config/recipes.js' import { SKILL_CONFIG } from '@/config/skills.js' import { startTask } from './taskSystem.js' import { TASK_TYPES } from './taskSystem.js' import { addItemToInventory } from './itemSystem.js' import { addSkillExp, unlockSkill } from './skillSystem.js' /** * 获取玩家可制作的配方 * @param {Object} playerStore - 玩家Store * @returns {Array} 可制作的配方列表(含材料检查) */ export function getCraftableRecipes(playerStore) { const availableRecipes = getAvailableRecipes(playerStore) return availableRecipes.map(recipe => { const materialCheck = checkMaterials(playerStore, recipe) return { ...recipe, canCraftNow: materialCheck.canCraft, missingMaterials: materialCheck.missingMaterials } }) } /** * 按分类获取可制作的配方 * @param {Object} playerStore - 玩家Store * @param {String} category - 分类 'weapon' | 'armor' | 'shield' | 'consumable' | 'special' * @returns {Array} 配方列表 */ export function getRecipesByCategory(playerStore, category) { const recipes = getCraftableRecipes(playerStore) return recipes.filter(recipe => recipe.type === category) } /** * 计算制造时间 * @param {Object} playerStore - 玩家Store * @param {Object} recipe - 配方对象 * @returns {Number} 制造时间(秒) */ export function calculateCraftingTime(playerStore, recipe) { let baseTime = recipe.baseTime // 技能加成 const skill = playerStore.skills[recipe.requiredSkill] if (skill && skill.level > 0) { // 检查制造技能的时间加成里程碑 let speedBonus = 0 if (playerStore.skills.crafting?.unlocked) { const craftingSkill = playerStore.skills.crafting // 检查里程碑 const milestones = SKILL_CONFIG.crafting?.milestones || {} for (const [level, milestone] of Object.entries(milestones)) { if (craftingSkill.level >= parseInt(level) && milestone.effect?.craftingSpeed) { speedBonus += milestone.effect.craftingSpeed } } } // 技能等级直接加成(每级5%) speedBonus += Math.min(skill.level, 20) * 0.05 baseTime = baseTime * (1 - speedBonus) } return Math.max(5, Math.floor(baseTime)) // 最少5秒 } /** * 计算制造成功率 * @param {Object} playerStore - 玩家Store * @param {Object} recipe - 配方对象 * @returns {Number} 成功率 (0-100) */ export function calculateSuccessRate(playerStore, recipe) { let successRate = recipe.baseSuccessRate * 100 // 技能等级加成(每级+2%) const skill = playerStore.skills[recipe.requiredSkill] if (skill && skill.level > 0) { successRate += Math.min(skill.level, 20) * 2 } // 运气加成 const luck = playerStore.baseStats?.luck || 10 successRate += luck * 0.1 // 检查制造技能的成功率加成里程碑 if (playerStore.skills.crafting?.unlocked) { const craftingSkill = playerStore.skills.crafting const milestones = SKILL_CONFIG.crafting?.milestones || {} for (const [level, milestone] of Object.entries(milestones)) { if (craftingSkill.level >= parseInt(level) && milestone.effect?.craftingSuccessRate) { successRate += milestone.effect.craftingSuccessRate } } } return Math.min(98, Math.max(5, Math.floor(successRate))) } /** * 计算物品品质 * @param {Object} playerStore - 玩家Store * @param {Object} recipe - 配方对象 * @returns {Number} 品质值 (0-250) */ export function calculateQuality(playerStore, recipe) { // 基础品质(普通范围 50-99) let qualityValue = 50 + Math.floor(Math.random() * 50) // 默认普通 // 随机因素 (0-100) const randomRoll = Math.random() * 100 // 技能加成(每级增加高品质概率) const skill = playerStore.skills[recipe.requiredSkill] let skillBonus = 0 if (skill) { skillBonus = skill.level * 2 } // 运气加成 const luck = playerStore.baseStats?.luck || 10 const luckBonus = luck * 0.5 // 制造技能品质加成 let craftingQualityBonus = 0 if (playerStore.skills.crafting?.unlocked) { const craftingSkill = playerStore.skills.crafting const milestones = SKILL_CONFIG.crafting?.milestones || {} for (const [level, milestone] of Object.entries(milestones)) { if (craftingSkill.level >= parseInt(level) && milestone.effect?.craftingQuality) { craftingQualityBonus += milestone.effect.craftingQuality } } } const totalBonus = skillBonus + luckBonus + craftingQualityBonus const finalRoll = randomRoll + totalBonus // 品质判定 - 与全局品质等级保持一致 if (finalRoll >= 95) qualityValue = 200 + Math.floor(Math.random() * 50) // 传说 [200, 250] else if (finalRoll >= 85) qualityValue = 160 + Math.floor(Math.random() * 39) // 史诗 [160, 199] else if (finalRoll >= 70) qualityValue = 130 + Math.floor(Math.random() * 29) // 稀有 [130, 159] else if (finalRoll >= 50) qualityValue = 100 + Math.floor(Math.random() * 29) // 优秀 [100, 129] else if (finalRoll >= 20) qualityValue = 50 + Math.floor(Math.random() * 49) // 普通 [50, 99] else qualityValue = Math.floor(Math.random() * 50) // 垃圾 [0, 49] // 特殊道具(如剧情道具)固定为传说品质 if (recipe.type === 'special' && recipe.keyItem) { qualityValue = 225 // 传说中值 } return Math.min(250, Math.max(0, qualityValue)) } /** * 消耗材料(通过 itemSystem 接口) * @param {Object} playerStore - 玩家Store * @param {Object} recipe - 配方对象 * @returns {Boolean} 是否成功消耗 */ export function consumeMaterials(playerStore, recipe) { // 先检查材料是否足够 const check = checkMaterials(playerStore, recipe) if (!check.canCraft) { return false } // 消耗材料 - 使用 itemSystem 接口 for (const material of recipe.materials) { // 查找背包中该物品的实例 const itemIndex = playerStore.inventory.findIndex(i => i.id === material.itemId) if (itemIndex !== -1) { const item = playerStore.inventory[itemIndex] const countToRemove = Math.min(item.count, material.count) item.count -= countToRemove if (item.count <= 0) { playerStore.inventory.splice(itemIndex, 1) } } } return true } /** * 开始制造 * @param {Object} gameStore - 游戏Store * @param {Object} playerStore - 玩家Store * @param {String} recipeId - 配方ID * @returns {Object} { success: boolean, message: string, taskId: string|null } */ export function startCrafting(gameStore, playerStore, recipeId) { const recipe = RECIPE_CONFIG[recipeId] if (!recipe) { return { success: false, message: '配方不存在' } } // 检查材料 const materialCheck = checkMaterials(playerStore, recipe) if (!materialCheck.canCraft) { const missingList = materialCheck.missingMaterials.map(m => `${m.itemName} x${m.need - m.have}`).join(', ') return { success: false, message: `材料不足:${missingList}` } } // 检查技能 if (recipe.requiredSkill) { const skill = playerStore.skills[recipe.requiredSkill] if (!skill || !skill.unlocked) { return { success: false, message: '需要解锁对应技能' } } if (skill.level < recipe.requiredSkillLevel) { return { success: false, message: `技能等级不足(需要${recipe.requiredSkillLevel}级)` } } } // 计算制造时间 const craftingTime = calculateCraftingTime(playerStore, recipe) // 消耗材料(在开始制造时消耗) if (!consumeMaterials(playerStore, recipe)) { return { success: false, message: '材料消耗失败' } } // 开始制造任务 const result = startTask(gameStore, playerStore, TASK_TYPES.CRAFTING, { recipeId, duration: craftingTime }) if (result.success) { // 预先计算品质(制造开始时确定) const task = gameStore.activeTasks.find(t => t.id === result.taskId) if (task) { task.preCalculatedQuality = calculateQuality(playerStore, recipe) } const itemConfig = ITEM_CONFIG[recipe.resultItem] return { success: true, message: `开始制造:${itemConfig?.name || recipe.resultItem}`, taskId: result.taskId, estimatedTime: craftingTime, successRate: calculateSuccessRate(playerStore, recipe) } } return result } /** * 完成制造(任务完成回调) * @param {Object} _gameStore - 游戏Store(未使用,保留以兼容接口) * @param {Object} playerStore - 玩家Store * @param {Object} task - 制造任务 * @param {Object} result - 任务结果 * @returns {Object} { success: boolean, item: Object|null } */ export function completeCrafting(_gameStore, playerStore, task, result) { const recipeId = task.data.recipeId const recipe = RECIPE_CONFIG[recipeId] if (!recipe) { return { success: false, message: '配方不存在' } } // 如果制造失败 if (!result.success) { // 失败可能部分返还材料(基于成功率) const successRate = calculateSuccessRate(playerStore, recipe) if (successRate > 70) { // 高成功率:返还部分材料 // 材料已在开始时消耗,这里可以考虑返还逻辑 return { success: false, message: '制造失败,但部分材料已保留', failed: true } } return { success: false, message: '制造失败,材料已消耗', failed: true } } // 制造成功,计算品质(已经是品质值 0-250) const qualityValue = task.preCalculatedQuality || calculateQuality(playerStore, recipe) // 添加到背包 - 使用 itemSystem 接口 const addResult = addItemToInventory(playerStore, recipe.resultItem, recipe.resultCount, qualityValue) if (!addResult.success) { return { success: false, message: '添加物品失败' } } // 获取物品显示信息 const item = addResult.item // 给予制造技能经验 if (result.rewards && result.rewards[recipe.requiredSkill]) { const skillId = recipe.requiredSkill const exp = result.rewards[skillId] if (!playerStore.skills[skillId]) { unlockSkill(playerStore, skillId) } addSkillExp(playerStore, skillId, exp) } return { success: true, item, message: `制造成功:${item.qualityName} ${item.name}`, addResult } } /** * 获取分类显示信息 * @param {String} type - 配方类型 * @returns {Object} 分类信息 */ export function getCategoryInfo(type) { const categories = { weapon: { id: 'weapon', name: '武器', icon: '⚔️' }, armor: { id: 'armor', name: '防具', icon: '🛡️' }, shield: { id: 'shield', name: '盾牌', icon: '🛡️' }, consumable: { id: 'consumable', name: '消耗品', icon: '🧪' }, special: { id: 'special', name: '特殊', icon: '✨' } } return categories[type] || { id: type, name: type, icon: '📦' } } /** * 获取所有分类 * @returns {Array} 分类列表 */ export function getAllCategories() { return [ { id: 'weapon', name: '武器', icon: '⚔️' }, { id: 'armor', name: '防具', icon: '🛡️' }, { id: 'shield', name: '盾牌', icon: '🛡️' }, { id: 'consumable', name: '消耗品', icon: '🧪' }, { id: 'special', name: '特殊', icon: '✨' } ] }