fix: 修复武器经验获取并完善义体系统

- 修复战斗胜利后未获得武器技能经验的问题 (initCombat未传递skillExpReward)
- 每级武器技能提供5%武器伤害加成(已实现,无需修改)
- 实现义体安装/卸载功能,支持NPC对话交互
- StatusPanel添加义体装备槽显示
- MapPanel修复NPC对话import问题
- 新增成就系统框架
- 添加项目文档CLAUDE.md

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Claude
2026-02-02 15:52:32 +08:00
parent 27e1c8d440
commit ccfd6a5e75
8 changed files with 672 additions and 35 deletions

View File

@@ -8,9 +8,11 @@ import { EVENT_CONFIG } from '@/config/events.js'
import { LOCATION_CONFIG } from '@/config/locations.js'
import { SKILL_CONFIG } from '@/config/skills.js'
import { ENEMY_CONFIG } from '@/config/enemies.js'
import { ITEM_CONFIG } from '@/config/items.js'
import { unlockSkill } from './skillSystem.js'
import { addItemToInventory } from './itemSystem.js'
import { initCombat, getEnvironmentType } from './combatSystem.js'
import { installProsthetic, removeProsthetic } from './prostheticSystem.js'
/**
* 检查并触发事件
@@ -198,8 +200,9 @@ function renderTemplate(template, context) {
* @param {Object} gameStore - 游戏Store
* @param {String} npcId - NPC ID
* @param {String} dialogueKey - 对话键名
* @param {Object} playerStore - 玩家Store用于动态选项生成
*/
export function startNPCDialogue(gameStore, npcId, dialogueKey = 'first') {
export function startNPCDialogue(gameStore, npcId, dialogueKey = 'first', playerStore = null) {
const npc = NPC_CONFIG[npcId]
if (!npc) {
console.warn(`NPC ${npcId} not found`)
@@ -212,14 +215,27 @@ export function startNPCDialogue(gameStore, npcId, dialogueKey = 'first') {
return
}
// 处理模板变量
let text = dialogue.text
if (playerStore) {
text = renderDialogueTemplate(text, playerStore, dialogue)
}
// 生成选项列表(包括动态选项)
let choices = dialogue.choices || []
if (dialogue.dynamicChoices && playerStore) {
const dynamicChoices = generateDynamicChoices(dialogue.dynamicChoices, playerStore)
choices = [...dynamicChoices, ...choices]
}
// 构建事件数据
const eventData = {
id: `npc_${npcId}_${dialogueKey}`,
type: 'dialogue',
title: npc.name,
text: dialogue.text,
text: text,
npc: npc,
choices: dialogue.choices || [],
choices: choices,
currentDialogue: dialogueKey,
npcId
}
@@ -228,6 +244,61 @@ export function startNPCDialogue(gameStore, npcId, dialogueKey = 'first') {
gameStore.drawerState.event = true
}
/**
* 渲染对话模板(替换变量)
*/
function renderDialogueTemplate(template, playerStore, dialogue) {
let text = template
// 替换义体列表
if (text.includes('{prosthetic_list}')) {
const prostheticList = getProstheticInventoryList(playerStore)
text = text.replace('{prosthetic_list}', prostheticList)
}
// 替换已装备的义体
if (text.includes('{equipped_prosthetic}')) {
const equipped = playerStore.equipment?.prosthetic
const equippedText = equipped ? `${equipped.name} (${equipped.description})` : '无'
text = text.replace('{equipped_prosthetic}', equippedText)
}
return text
}
/**
* 获取玩家背包中的义体列表
*/
function getProstheticInventoryList(playerStore) {
const prosthetics = playerStore.inventory.filter(item => item.type === 'prosthetic')
if (prosthetics.length === 0) {
return '(你没有义体可以安装)'
}
return prosthetics.map(p => `${p.name}: ${p.description}`).join('\n')
}
/**
* 生成动态选项
*/
function generateDynamicChoices(type, playerStore) {
switch (type) {
case 'prosthetic_inventory':
// 生成义体安装选项
const prosthetics = playerStore.inventory.filter(item => item.type === 'prosthetic')
if (prosthetics.length === 0) {
return []
}
return prosthetics.map(p => ({
text: `安装 ${p.name}`,
action: 'install_prosthetic',
actionData: { itemId: p.id }
}))
default:
return []
}
}
/**
* 处理对话选择
* @param {Object} gameStore - 游戏Store
@@ -259,7 +330,7 @@ export function handleDialogueChoice(gameStore, playerStore, choice) {
// 继续对话
const currentEvent = gameStore.currentEvent
if (currentEvent && currentEvent.npc) {
startNPCDialogue(gameStore, currentEvent.npc.id, choice.next)
startNPCDialogue(gameStore, currentEvent.npc.id, choice.next, playerStore)
result.closeEvent = false
}
} else if (!choice.action) {
@@ -418,6 +489,60 @@ export function processDialogueAction(gameStore, playerStore, action, actionData
// 直接关闭
return { success: true, message: '', closeEvent: true }
case 'install_prosthetic':
// 安装义体
if (actionData.itemId) {
const item = playerStore.inventory.find(i => i.id === actionData.itemId)
if (!item) {
return { success: false, message: '找不到该义体', closeEvent: false }
}
const installResult = installProsthetic(playerStore, gameStore, item)
if (installResult.success) {
// 从背包移除义体
const index = playerStore.inventory.findIndex(i => i.id === actionData.itemId)
if (index > -1) {
playerStore.inventory.splice(index, 1)
}
// 解锁义体技能
if (item.grantedSkill) {
unlockSkill(playerStore, item.grantedSkill)
if (gameStore.addLog) {
gameStore.addLog(`解锁了技能: ${SKILL_CONFIG[item.grantedSkill]?.name || item.grantedSkill}`, 'system')
}
}
// 更新成就进度
gameStore.achievementProgress.prostheticEquipped = 1
gameStore.checkAchievements('equip_prosthetic', { prostheticCount: 1 })
// 重新显示对话框
const currentEvent = gameStore.currentEvent
if (currentEvent && currentEvent.npc) {
startNPCDialogue(gameStore, currentEvent.npc.id, 'first', playerStore)
}
}
return { success: installResult.success, message: installResult.message, closeEvent: false }
}
return { success: false, message: '义体参数错误', closeEvent: false }
case 'remove_prosthetic':
// 卸下义体
const removeResult = removeProsthetic(playerStore, gameStore)
if (removeResult.success) {
// 重新显示对话框
const currentEvent = gameStore.currentEvent
if (currentEvent && currentEvent.npc) {
startNPCDialogue(gameStore, currentEvent.npc.id, 'first', playerStore)
}
}
return { success: removeResult.success, message: removeResult.message, closeEvent: false }
case 'refresh_list':
// 刷新列表(重新显示当前对话框)
const evt = gameStore.currentEvent
if (evt && evt.npc && evt.currentDialogue) {
startNPCDialogue(gameStore, evt.npc.id, evt.currentDialogue, playerStore)
}
return { success: true, message: '', closeEvent: false }
default:
console.warn(`Unknown dialogue action: ${action}`)
return { success: false, message: '未知动作', closeEvent: false }