diff --git a/components/drawers/CraftingDrawer.vue b/components/drawers/CraftingDrawer.vue
new file mode 100644
index 0000000..9720c5d
--- /dev/null
+++ b/components/drawers/CraftingDrawer.vue
@@ -0,0 +1,668 @@
+
+
+
+
+
+
+ 制造技能等级:
+ {{ getCraftingSkillLevel() }}
+
+
+
+
+
+
+
+
+
+ {{ recipe.displayIcon || '📦' }}
+
+ {{ recipe.displayName }}
+ {{ getRecipeDescription(recipe) }}
+
+
+
+ {{ getMaterialIcon(mat.itemId) }} {{ getMaterialName(mat.itemId) }} x{{ mat.count }}
+
+
+
+
+
+ {{ getCraftingTimeDisplay(recipe) }}
+
+ {{ getSuccessRateDisplay(recipe) }}
+
+
+
+
+ 此分类下没有可制作的配方
+
+
+
+
+
+
+
+
+
+ {{ getCraftingItemName() }}
+
+
+
+
+
+
+
+
+
+
diff --git a/config/recipes.js b/config/recipes.js
new file mode 100644
index 0000000..b6e0bce
--- /dev/null
+++ b/config/recipes.js
@@ -0,0 +1,340 @@
+/**
+ * 制造配方配置
+ * 支持武器、防具、消耗品、特殊道具的制造
+ */
+
+import { ITEM_CONFIG } from './items.js'
+import { getItemCount } from '@/utils/itemSystem.js'
+
+/**
+ * 配方类型枚举
+ */
+export const RECIPE_TYPES = {
+ WEAPON: 'weapon', // 武器
+ ARMOR: 'armor', // 防具
+ SHIELD: 'shield', // 盾牌
+ CONSUMABLE: 'consumable', // 消耗品
+ SPECIAL: 'special' // 特殊道具
+}
+
+/**
+ * 配方配置
+ * 每个配方包含:
+ * - id: 配方ID
+ * - type: 配方类型
+ * - resultItem: 产出物品ID
+ * - resultCount: 产出数量
+ * - materials: 材料需求列表
+ * - requiredSkill: 所需技能ID
+ * - requiredSkillLevel: 所需技能等级
+ * - baseTime: 基础制造时间(秒)
+ * - baseSuccessRate: 基础成功率
+ * - unlockCondition: 解锁条件(可选)
+ */
+export const RECIPE_CONFIG = {
+ // ===== 武器配方 =====
+ wooden_club: {
+ id: 'wooden_club',
+ type: RECIPE_TYPES.WEAPON,
+ resultItem: 'wooden_club',
+ resultCount: 1,
+ materials: [
+ { itemId: 'dog_skin', count: 2 }
+ ],
+ requiredSkill: 'club_mastery',
+ requiredSkillLevel: 1,
+ baseTime: 30,
+ baseSuccessRate: 0.95
+ },
+
+ stone_axe: {
+ id: 'stone_axe',
+ type: RECIPE_TYPES.WEAPON,
+ resultItem: 'stone_axe',
+ resultCount: 1,
+ materials: [
+ { itemId: 'iron_ore', count: 3 },
+ { itemId: 'leather', count: 1 }
+ ],
+ requiredSkill: 'axe_mastery',
+ requiredSkillLevel: 1,
+ baseTime: 60,
+ baseSuccessRate: 0.85
+ },
+
+ hunter_bow: {
+ id: 'hunter_bow',
+ type: RECIPE_TYPES.WEAPON,
+ resultItem: 'hunter_bow',
+ resultCount: 1,
+ materials: [
+ { itemId: 'dog_skin', count: 3 },
+ { itemId: 'leather', count: 2 }
+ ],
+ requiredSkill: 'archery',
+ requiredSkillLevel: 3,
+ baseTime: 120,
+ baseSuccessRate: 0.80
+ },
+
+ iron_sword: {
+ id: 'iron_sword',
+ type: RECIPE_TYPES.WEAPON,
+ resultItem: 'iron_sword',
+ resultCount: 1,
+ materials: [
+ { itemId: 'iron_ore', count: 5 },
+ { itemId: 'leather', count: 2 }
+ ],
+ requiredSkill: 'sword_mastery',
+ requiredSkillLevel: 5,
+ baseTime: 180,
+ baseSuccessRate: 0.75,
+ unlockCondition: {
+ type: 'skill',
+ skillId: 'crafting',
+ level: 3
+ }
+ },
+
+ // ===== 防具配方 =====
+ leather_armor: {
+ id: 'leather_armor',
+ type: RECIPE_TYPES.ARMOR,
+ resultItem: 'leather_armor',
+ resultCount: 1,
+ materials: [
+ { itemId: 'leather', count: 5 }
+ ],
+ requiredSkill: 'crafting',
+ requiredSkillLevel: 1,
+ baseTime: 60,
+ baseSuccessRate: 0.90
+ },
+
+ wooden_shield: {
+ id: 'wooden_shield',
+ type: RECIPE_TYPES.SHIELD,
+ resultItem: 'wooden_shield',
+ resultCount: 1,
+ materials: [
+ { itemId: 'leather', count: 2 },
+ { itemId: 'dog_skin', count: 2 }
+ ],
+ requiredSkill: 'crafting',
+ requiredSkillLevel: 2,
+ baseTime: 45,
+ baseSuccessRate: 0.92
+ },
+
+ iron_shield: {
+ id: 'iron_shield',
+ type: RECIPE_TYPES.SHIELD,
+ resultItem: 'iron_shield',
+ resultCount: 1,
+ materials: [
+ { itemId: 'iron_ore', count: 8 },
+ { itemId: 'leather', count: 3 }
+ ],
+ requiredSkill: 'crafting',
+ requiredSkillLevel: 5,
+ baseTime: 120,
+ baseSuccessRate: 0.75
+ },
+
+ // ===== 消耗品配方 =====
+ bandage: {
+ id: 'bandage',
+ type: RECIPE_TYPES.CONSUMABLE,
+ resultItem: 'bandage',
+ resultCount: 3,
+ materials: [
+ { itemId: 'dog_skin', count: 2 }
+ ],
+ requiredSkill: 'crafting',
+ requiredSkillLevel: 1,
+ baseTime: 15,
+ baseSuccessRate: 0.98
+ },
+
+ health_potion_small: {
+ id: 'health_potion_small',
+ type: RECIPE_TYPES.CONSUMABLE,
+ resultItem: 'health_potion_small',
+ resultCount: 1,
+ materials: [
+ { itemId: 'healing_herb', count: 3 }
+ ],
+ requiredSkill: 'herbalism',
+ requiredSkillLevel: 2,
+ baseTime: 30,
+ baseSuccessRate: 0.90
+ },
+
+ health_potion: {
+ id: 'health_potion',
+ type: RECIPE_TYPES.CONSUMABLE,
+ resultItem: 'health_potion',
+ resultCount: 1,
+ materials: [
+ { itemId: 'healing_herb', count: 5 },
+ { itemId: 'bandage', count: 1 }
+ ],
+ requiredSkill: 'herbalism',
+ requiredSkillLevel: 5,
+ baseTime: 60,
+ baseSuccessRate: 0.80
+ },
+
+ // ===== 特殊道具 =====
+ bomb: {
+ id: 'bomb',
+ type: RECIPE_TYPES.SPECIAL,
+ resultItem: 'bomb',
+ resultCount: 1,
+ materials: [
+ { itemId: 'iron_ore', count: 3 },
+ { itemId: 'bat_wing', count: 2 }
+ ],
+ requiredSkill: 'crafting',
+ requiredSkillLevel: 5,
+ baseTime: 90,
+ baseSuccessRate: 0.75
+ },
+
+ // 炸弹堆(一次制造多个)
+ bomb_batch: {
+ id: 'bomb_batch',
+ type: RECIPE_TYPES.SPECIAL,
+ resultItem: 'bomb',
+ resultCount: 3,
+ materials: [
+ { itemId: 'iron_ore', count: 8 },
+ { itemId: 'bat_wing', count: 5 }
+ ],
+ requiredSkill: 'crafting',
+ requiredSkillLevel: 8,
+ baseTime: 200,
+ baseSuccessRate: 0.70
+ },
+
+ // ===== 剧情道具 =====
+ mystic_key: {
+ id: 'mystic_key',
+ type: RECIPE_TYPES.SPECIAL,
+ resultItem: 'mystic_key',
+ resultCount: 1,
+ materials: [
+ { itemId: 'rare_gem', count: 1 },
+ { itemId: 'iron_ore', count: 10 }
+ ],
+ requiredSkill: 'crafting',
+ requiredSkillLevel: 10,
+ baseTime: 300,
+ baseSuccessRate: 0.50,
+ unlockCondition: {
+ type: 'quest',
+ flag: 'found_mystic_recipe'
+ }
+ }
+}
+
+/**
+ * 获取所有配方
+ * @returns {Array} 配方列表
+ */
+export function getAllRecipes() {
+ return Object.values(RECIPE_CONFIG)
+}
+
+/**
+ * 获取指定类型的配方
+ * @param {String} type - 配方类型
+ * @returns {Array} 配方列表
+ */
+export function getRecipesByType(type) {
+ return Object.values(RECIPE_CONFIG).filter(recipe => recipe.type === type)
+}
+
+/**
+ * 获取玩家可制作的配方
+ * @param {Object} playerStore - 玩家Store
+ * @returns {Array} 可制作的配方列表
+ */
+export function getAvailableRecipes(playerStore) {
+ return Object.values(RECIPE_CONFIG)
+ .filter(recipe => {
+ // 检查技能要求
+ if (recipe.requiredSkill) {
+ const skill = playerStore.skills?.[recipe.requiredSkill]
+ if (!skill || !skill.unlocked) return false
+ if (skill.level < recipe.requiredSkillLevel) return false
+ }
+
+ // 检查解锁条件
+ if (recipe.unlockCondition) {
+ if (recipe.unlockCondition.type === 'skill') {
+ const skill = playerStore.skills?.[recipe.unlockCondition.skillId]
+ if (!skill || skill.level < recipe.unlockCondition.level) return false
+ } else if (recipe.unlockCondition.type === 'quest') {
+ if (!playerStore.flags?.[recipe.unlockCondition.flag]) return false
+ }
+ }
+
+ return true
+ })
+ .map(recipe => ({
+ ...recipe,
+ canCraft: true,
+ displayName: ITEM_CONFIG[recipe.resultItem]?.name || recipe.resultItem,
+ displayIcon: ITEM_CONFIG[recipe.resultItem]?.icon || '📦'
+ }))
+}
+
+/**
+ * 获取配方信息
+ * @param {String} recipeId - 配方ID
+ * @returns {Object|null} 配方信息
+ */
+export function getRecipe(recipeId) {
+ return RECIPE_CONFIG[recipeId] || null
+}
+
+/**
+ * 检查是否可以制造(材料是否足够)
+ * @param {Object} playerStore - 玩家Store
+ * @param {Object} recipe - 配方对象
+ * @returns {Object} { canCraft: boolean, missingMaterials: Array }
+ */
+export function checkMaterials(playerStore, recipe) {
+ const missing = []
+
+ for (const material of recipe.materials) {
+ const itemCount = getItemCount(playerStore, material.itemId)
+ if (itemCount < material.count) {
+ const itemConfig = ITEM_CONFIG[material.itemId]
+ missing.push({
+ itemId: material.itemId,
+ itemName: itemConfig?.name || material.itemId,
+ need: material.count,
+ have: itemCount
+ })
+ }
+ }
+
+ return {
+ canCraft: missing.length === 0,
+ missingMaterials: missing
+ }
+}
+
+/**
+ * 配方分类配置
+ */
+export const RECIPE_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: '✨' }
+}
diff --git a/utils/craftingSystem.js b/utils/craftingSystem.js
new file mode 100644
index 0000000..b13f58e
--- /dev/null
+++ b/utils/craftingSystem.js
@@ -0,0 +1,357 @@
+/**
+ * 制造系统 - 配方管理、制造逻辑、品质计算
+ * 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: '✨' }
+ ]
+}
diff --git a/utils/itemSystem.js b/utils/itemSystem.js
index bd6390c..acc427f 100644
--- a/utils/itemSystem.js
+++ b/utils/itemSystem.js
@@ -404,7 +404,7 @@ function removeEquipmentStats(playerStore, slot) {
* @param {Object} playerStore - 玩家Store
* @param {String} itemId - 物品ID
* @param {Number} count - 数量
- * @param {Number} quality - 品质(装备用)
+ * @param {Number} quality - 品质值(装备用,0-250)
* @returns {Object} { success: boolean, item: Object }
*/
export function addItemToInventory(playerStore, itemId, count = 1, quality = null) {
@@ -420,10 +420,10 @@ export function addItemToInventory(playerStore, itemId, count = 1, quality = nul
const itemQuality = quality !== null ? quality
: (needsQuality ? generateRandomQuality(playerStore.baseStats?.intuition || 0) : 100)
- // 计算物品属性
+ // 计算物品属性(包含品质等级)
const itemStats = calculateItemStats(itemId, itemQuality)
- // 堆叠物品 - 只需要匹配ID,不需要匹配品质(素材类物品)
+ // 素材类物品 - 只按ID堆叠
if (config.stackable) {
const existingItem = playerStore.inventory.find(i => i.id === itemId)
if (existingItem) {
@@ -432,10 +432,28 @@ export function addItemToInventory(playerStore, itemId, count = 1, quality = nul
}
}
+ // 装备类物品 - 按物品ID + 品质等级堆叠
+ if (needsQuality) {
+ const qualityLevel = itemStats.qualityLevel
+ const existingItem = playerStore.inventory.find(
+ i => i.id === itemId && i.qualityLevel === qualityLevel
+ )
+ if (existingItem) {
+ existingItem.count += count
+ return { success: true, item: existingItem }
+ }
+ }
+
// 创建新物品
+ // 装备类物品使用 itemId + qualityLevel 作为唯一标识
+ // 素材类物品使用 itemId + 时间戳(虽然可堆叠,但保留唯一ID用于其他用途)
+ const uniqueId = needsQuality
+ ? `${itemId}_q${itemStats.qualityLevel}`
+ : `${itemId}_${Date.now()}_${Math.random().toString(36).substring(2, 11)}`
+
const newItem = {
...itemStats,
- uniqueId: `${itemId}_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`,
+ uniqueId,
count,
equipped: false,
obtainedAt: Date.now()
@@ -504,66 +522,6 @@ export function getItemCount(playerStore, itemId) {
return item ? item.count : 0
}
-/**
- * 检查装备是否解锁技能
- * @param {Object} playerStore - 玩家Store
- * @param {String} itemId - 物品ID
- * @returns {String|null} 解锁的技能ID
- */
-export function checkSkillUnlock(playerStore, itemId) {
- const config = ITEM_CONFIG[itemId]
- if (!config || !config.unlockSkill) {
- return null
- }
-
- const skillId = config.unlockSkill
-
- // 检查技能是否已解锁
- if (playerStore.skills[skillId] && playerStore.skills[skillId].unlocked) {
- return null
- }
-
- return skillId
-}
-
-/**
- * 计算物品出售价格
- * @param {Object} item - 物品对象
- * @param {Number} marketRate - 市场价格倍率 (0.1-2.0)
- * @returns {Number} 出售价格(铜币)
- */
-export function calculateSellPrice(item, marketRate = 0.3) {
- const basePrice = item.finalValue || item.baseValue || 0
- return Math.max(1, Math.floor(basePrice * marketRate))
-}
-
-/**
- * 计算物品购买价格
- * @param {Object} item - 物品对象
- * @param {Number} marketRate - 市场价格倍率 (1.0-3.0)
- * @returns {Number} 购买价格(铜币)
- */
-export function calculateBuyPrice(item, marketRate = 2.0) {
- const basePrice = item.finalValue || item.baseValue || 0
- return Math.max(1, Math.floor(basePrice * marketRate))
-}
-
-/**
- * 获取品质颜色
- * @param {Number} quality - 品质值
- * @returns {String} 颜色代码
- */
-export function getQualityColor(quality) {
- const level = getQualityLevel(quality)
- return level.color
-}
-
-/**
- * 获取品质名称
- * @param {Number} quality - 品质值
- * @returns {String} 品质名称
- */
-export function getQualityName(quality) {
- const level = getQualityLevel(quality)
- return level.name
-}
+// Note: checkSkillUnlock, calculateSellPrice, calculateBuyPrice,
+// getQualityColor, getQualityName are now test-only utilities
+// and are not exported for production use