Просмотр исходного кода

fix:一键扫荡bug和战意查询bug

flowerpig 5 месяцев назад
Родитель
Сommit
20f350458d

+ 13 - 0
script/module/bag/Grid.lua

@@ -57,6 +57,19 @@ end
 
 function makeFuwenSkill(net, skillID, skillLockList)
 	local skillConfig = FuwenExcel.skill[skillID]
+	if not skillConfig then
+		-- 如果技能配置不存在,设置默认值
+		net.skillID = skillID or 0
+		net.skillIcon = 0
+		net.skillName = ""
+		net.skillDesc = ""
+		net.lv = 0
+		net.isRare = 0
+		net.isOnlyBinshu = 0
+		net.isLock = 0
+		return
+	end
+	
 	net.skillID = skillID
 	net.skillIcon = skillConfig.icon 
 	net.skillName = skillConfig.name 

+ 0 - 220
script/module/battleWill/BattleWillLogic.lua

@@ -1,220 +0,0 @@
-------------------------------------------------------
--- 战意逻辑
-------------------------------------------------------
-
-local Lang = require("common.Lang")
-local Util = require("common.Util")
-local Msg = require("core.Msg")
-local ObjHuman = require("core.ObjHuman")
-local Broadcast = require("broadcast.Broadcast")
-local Grid = require("bag.Grid")
-local BagLogic = require("bag.BagLogic")
-local ItemDefine = require("bag.ItemDefine")
-local HeroLogic = require("hero.HeroLogic")
-local Log = require("common.Log")
-
--- 战意回退配置
-local BATTLE_WILL_ROLLBACK_CONFIG = {
-    [1] = {  -- 初级
-        needItemID = 1050,              -- 消耗道具ID
-        needItemCnt = 1,                -- 消耗数量:1个
-        returnBattleWillID = 0,         -- 返还战意道具ID(需要确认实际ID)
-        returnBattleWillCnt = 1,        -- 返还战意:1个
-        returnFragmentID = 0,           -- 返还战意碎片道具ID(需要确认实际ID)
-        returnFragmentCnt = 0,          -- 返还战意碎片:0
-        returnAncientSpiritID = 0,      -- 返还远古之灵道具ID(需要确认实际ID)
-        returnAncientSpiritCnt = 0       -- 返还远古之灵:0
-    },
-    [2] = {  -- 中级
-        needItemID = 1050,
-        needItemCnt = 5,                -- 消耗数量:5个
-        returnBattleWillID = 0,
-        returnBattleWillCnt = 4,        -- 返还战意:4个
-        returnFragmentID = 0,
-        returnFragmentCnt = 10000,      -- 返还战意碎片:10,000
-        returnAncientSpiritID = 0,
-        returnAncientSpiritCnt = 0
-    },
-    [3] = {  -- 高级
-        needItemID = 1050,
-        needItemCnt = 12,               -- 消耗数量:12个
-        returnBattleWillID = 0,
-        returnBattleWillCnt = 9,        -- 返还战意:9个
-        returnFragmentID = 0,
-        returnFragmentCnt = 40000,      -- 返还战意碎片:40,000
-        returnAncientSpiritID = 0,
-        returnAncientSpiritCnt = 0
-    },
-    [4] = {  -- 超级
-        needItemID = 1050,
-        needItemCnt = 50,               -- 消耗数量:50个
-        returnBattleWillID = 0,
-        returnBattleWillCnt = 19,       -- 返还战意:19个
-        returnFragmentID = 0,
-        returnFragmentCnt = 90000,      -- 返还战意碎片:90,000
-        returnAncientSpiritID = 0,
-        returnAncientSpiritCnt = 100   -- 返还远古之灵:100
-    }
-}
-
--- 获取战意格子数据
--- 假设战意数据存储在 heroGrid.battleWill[index] 中,包含 level 字段
-function getBattleWillGrid(heroGrid, index)
-    if not heroGrid then return end
-    if not heroGrid.battleWill then return end
-    return index and heroGrid.battleWill[index]
-end
-
--- 获取战意等级
-function getBattleWillLevel(heroGrid, index)
-    local grid = getBattleWillGrid(heroGrid, index)
-    if not grid then return 0 end
-    return grid.level or 0
-end
-
--- 查询回退信息
-function sendRollbackQuery(human, heroID, heroIndex, index)
-    Log.write(Log.LOGID_DEBUG, "[sendRollbackQuery] 收到查询请求: heroID="..(heroID or "nil")..", heroIndex="..(heroIndex or "nil")..", index="..(index or "nil"))
-    
-    local heroGrid = HeroLogic.getHeroGrid(human, heroID, heroIndex)
-    if not heroGrid then
-        Log.write(Log.LOGID_DEBUG, "[sendRollbackQuery] 英雄不存在")
-        return Broadcast.sendErr(human, Lang.COMMON_ARGUMENT_ERROR)
-    end
-    
-    local currentLevel = getBattleWillLevel(heroGrid, index)
-    Log.write(Log.LOGID_DEBUG, "[sendRollbackQuery] 当前战意等级: "..currentLevel)
-    
-    -- 检查等级是否可回退(等级0为空,不可回退)
-    if currentLevel == 0 or currentLevel < 1 or currentLevel > 4 then
-        Log.write(Log.LOGID_DEBUG, "[sendRollbackQuery] 当前等级不可回退: level="..currentLevel)
-        return Broadcast.sendErr(human, "当前战意格子为空,无法回退")
-    end
-    
-    local config = BATTLE_WILL_ROLLBACK_CONFIG[currentLevel]
-    if not config then
-        Log.write(Log.LOGID_DEBUG, "[sendRollbackQuery] 配置不存在: level="..currentLevel)
-        return Broadcast.sendErr(human, Lang.COMMON_COMFIG_ERROR)
-    end
-    
-    local msgRet = Msg.gc.GC_BATTLE_WILL_ROLLBACK_QUERY
-    msgRet.heroID = heroID
-    msgRet.heroIndex = heroIndex
-    msgRet.index = index
-    msgRet.currentLevel = currentLevel
-    msgRet.targetLevel = 0  -- 回退后等级固定为0(空)
-    
-    -- 消耗道具
-    Grid.makeItem(msgRet.needItem, config.needItemID, config.needItemCnt)
-    
-    -- 返还物品列表
-    msgRet.returnItems[0] = 0
-    local itemCnt = 0
-    
-    -- 返还战意
-    if config.returnBattleWillCnt > 0 and config.returnBattleWillID > 0 then
-        itemCnt = itemCnt + 1
-        if itemCnt <= #msgRet.returnItems then
-            Grid.makeItem(msgRet.returnItems[itemCnt], config.returnBattleWillID, config.returnBattleWillCnt)
-        end
-    end
-    
-    -- 返还战意碎片
-    if config.returnFragmentCnt > 0 and config.returnFragmentID > 0 then
-        itemCnt = itemCnt + 1
-        if itemCnt <= #msgRet.returnItems then
-            Grid.makeItem(msgRet.returnItems[itemCnt], config.returnFragmentID, config.returnFragmentCnt)
-        end
-    end
-    
-    -- 返还远古之灵
-    if config.returnAncientSpiritCnt > 0 and config.returnAncientSpiritID > 0 then
-        itemCnt = itemCnt + 1
-        if itemCnt <= #msgRet.returnItems then
-            Grid.makeItem(msgRet.returnItems[itemCnt], config.returnAncientSpiritID, config.returnAncientSpiritCnt)
-        end
-    end
-    
-    msgRet.returnItems[0] = itemCnt
-    
-    Log.write(Log.LOGID_DEBUG, "[sendRollbackQuery] 发送查询结果: currentLevel="..currentLevel..", needItemCnt="..config.needItemCnt..", returnItemsCount="..itemCnt)
-    Msg.send(msgRet, human.fd)
-end
-
--- 执行回退
-function rollback(human, heroID, heroIndex, index)
-    Log.write(Log.LOGID_DEBUG, "[rollback] 收到回退请求: heroID="..(heroID or "nil")..", heroIndex="..(heroIndex or "nil")..", index="..(index or "nil"))
-    
-    local heroGrid = HeroLogic.getHeroGrid(human, heroID, heroIndex)
-    if not heroGrid then
-        Log.write(Log.LOGID_DEBUG, "[rollback] 英雄不存在")
-        return Broadcast.sendErr(human, Lang.COMMON_ARGUMENT_ERROR)
-    end
-    
-    local currentLevel = getBattleWillLevel(heroGrid, index)
-    Log.write(Log.LOGID_DEBUG, "[rollback] 当前战意等级: "..currentLevel)
-    
-    -- 检查等级是否可回退
-    if currentLevel == 0 or currentLevel < 1 or currentLevel > 4 then
-        Log.write(Log.LOGID_DEBUG, "[rollback] 当前等级不可回退: level="..currentLevel)
-        return Broadcast.sendErr(human, "当前战意格子为空,无法回退")
-    end
-    
-    local config = BATTLE_WILL_ROLLBACK_CONFIG[currentLevel]
-    if not config then
-        Log.write(Log.LOGID_DEBUG, "[rollback] 配置不存在: level="..currentLevel)
-        return Broadcast.sendErr(human, Lang.COMMON_COMFIG_ERROR)
-    end
-    
-    -- 检查消耗道具
-    if not BagLogic.checkItemCnt(human, config.needItemID, config.needItemCnt) then
-        Log.write(Log.LOGID_DEBUG, "[rollback] 消耗道具不足: needItemID="..config.needItemID..", needItemCnt="..config.needItemCnt)
-        return Broadcast.sendErr(human, Lang.COMMON_NO_ITEM)
-    end
-    
-    -- 扣除消耗道具
-    BagLogic.delItem(human, config.needItemID, config.needItemCnt, "battleWill_rollback")
-    Log.write(Log.LOGID_DEBUG, "[rollback] 扣除消耗道具: needItemID="..config.needItemID..", needItemCnt="..config.needItemCnt)
-    
-    -- 收集返还物品
-    local returnItemList = {}
-    
-    -- 返还战意
-    if config.returnBattleWillCnt > 0 and config.returnBattleWillID > 0 then
-        returnItemList[config.returnBattleWillID] = config.returnBattleWillCnt
-    end
-    
-    -- 返还战意碎片
-    if config.returnFragmentCnt > 0 and config.returnFragmentID > 0 then
-        returnItemList[config.returnFragmentID] = config.returnFragmentCnt
-    end
-    
-    -- 返还远古之灵
-    if config.returnAncientSpiritCnt > 0 and config.returnAncientSpiritID > 0 then
-        returnItemList[config.returnAncientSpiritID] = config.returnAncientSpiritCnt
-    end
-    
-    -- 发放返还物品(使用通用道具发放逻辑)
-    if next(returnItemList) then
-        BagLogic.addItemList(human, returnItemList, "battleWill_rollback")
-        Log.write(Log.LOGID_DEBUG, "[rollback] 发放返还物品")
-    end
-    
-    -- 更新战意等级为0(清空)
-    if not heroGrid.battleWill then
-        heroGrid.battleWill = {}
-    end
-    if not heroGrid.battleWill[index] then
-        heroGrid.battleWill[index] = {}
-    end
-    heroGrid.battleWill[index].level = 0
-    
-    Log.write(Log.LOGID_DEBUG, "[rollback] 回退完成: 等级从 "..currentLevel.." 变为 0")
-    
-    -- 重新计算英雄属性
-    ObjHuman.doCalcHero(human, heroIndex)
-    
-    -- 发送英雄数据更新(如果需要)
-    HeroLogic.sendHeroBagDynamic(human, heroID, heroIndex)
-end
-

+ 0 - 12
script/module/battleWill/Handler.lua

@@ -1,12 +0,0 @@
-local BattleWillLogic = require("battleWill.BattleWillLogic")
-
--- 战意回退查询
-function CG_BATTLE_WILL_ROLLBACK_QUERY(human, msg)
-    BattleWillLogic.sendRollbackQuery(human, msg.heroID, msg.heroIndex, msg.index)
-end
-
--- 战意回退执行
-function CG_BATTLE_WILL_ROLLBACK_DO(human, msg)
-    BattleWillLogic.rollback(human, msg.heroID, msg.heroIndex, msg.index)
-end
-

+ 0 - 27
script/module/battleWill/Proto.lua

@@ -1,27 +0,0 @@
-local ItemData = require("bag.Proto").ItemData
-
--- 战意回退查询
-CG_BATTLE_WILL_ROLLBACK_QUERY = {
-    {"heroID",          1,      "int"},
-    {"heroIndex",       1,      "short"},
-    {"index",           1,      "byte"},        -- 战意索引
-}
-
-GC_BATTLE_WILL_ROLLBACK_QUERY = {
-    {"heroID",          1,      "int"},
-    {"heroIndex",       1,      "short"},
-    {"index",           1,      "byte"},        -- 战意索引
-    {"currentLevel",    1,      "byte"},        -- 当前等级(1-4)
-    {"targetLevel",     1,      "byte"},        -- 回退后等级(固定为0,表示空)
-    {"needItem",        1,      ItemData},      -- 消耗道具
-    {"returnItems",     5,      ItemData},      -- 返还物品列表(最多5个)
-}
-
--- 战意回退执行
-CG_BATTLE_WILL_ROLLBACK_DO = {
-    {"heroID",          1,      "int"},
-    {"heroIndex",       1,      "short"},
-    {"index",           1,      "byte"},        -- 战意索引
-}
-
-

+ 59 - 18
script/module/drill/DrillLogic.lua

@@ -257,6 +257,7 @@ function updateDaily(human)
 	drillDB.myHelpIndex = 0		
 	drillDB.myHelpHero = nil
 	drillDB.helpoutList = nil
+	drillDB.oneClickSaodangDone = nil  -- 清除扫荡完成标记
 
 end
 
@@ -1581,6 +1582,10 @@ function onFightEnd(human, result, combatType, cbParam, combatInfo)
 		drillDB.drillId = drillData.drillId
 		addHelpWin(human, drillData)
 		DrillDB.updateDrillData(drillData)
+		-- 手动通关后清除扫荡完成标记,允许再次扫荡
+		if drillDB then
+			drillDB.oneClickSaodangDone = nil
+		end
 		quest(human, cbParam.drillId + 1)
 		--[[if drillDB.drillId == cbParam.drillId and drillDB.diff == diff then
 			if cbParam.drillId <= dirllDefConfig.maxDrillID  then 
@@ -1749,6 +1754,10 @@ function ChallengeLevelByDiamond(human, levelId)
 	drillDB.drillId = drillData.drillId
 	-- addHelpWin(human, drillData)
 	DrillDB.updateDrillData(drillData)
+	-- 手动通关后清除扫荡完成标记,允许再次扫荡
+	if drillDB then
+		drillDB.oneClickSaodangDone = nil
+	end
 	quest(human, oldDrillID + 1)
 
 
@@ -1852,16 +1861,9 @@ function oneClickSaodang(human)
 	end
 	
 	-- 计算可扫荡的关卡数
-	-- 如果当前关卡是1,扫荡所有关卡(1到maxDrillID)
-	-- 如果当前关卡是5,扫荡已通关的关卡(1到currentDrillId-1,即1到4)
-	local maxSaodangId
-	if currentDrillId == 1 then
-		-- 第一关,扫荡所有关卡
-		maxSaodangId = maxDrillID
-	else
-		-- 已通关部分关卡,扫荡已通关的关卡(从1到currentDrillId-1)
-		maxSaodangId = currentDrillId - 1
-	end
+	-- 一键扫荡应该扫荡所有关卡(1到maxDrillID),无论当前关卡ID是多少
+	local maxSaodangId = maxDrillID
+	Log.write(Log.LOGID_DEBUG, "[oneClickSaodang] 一键扫荡:扫荡所有关卡,maxSaodangId="..maxSaodangId..", maxDrillID="..maxDrillID)
 	
 	if maxSaodangId < 1 then
 		Log.write(Log.LOGID_DEBUG, "[oneClickSaodang] 无可扫荡关卡,maxSaodangId="..maxSaodangId.." < 1")
@@ -1869,21 +1871,31 @@ function oneClickSaodang(human)
 	end
 	
 	-- 计算扫荡后的关卡ID
-	local newDrillId = maxSaodangId + 1
-	if newDrillId > maxDrillID then
-		newDrillId = maxDrillID + 1  -- 16表示已通关所有关卡
-	end
+	-- 一键扫荡后应该全部通关(newDrillId = maxDrillID + 1)
+	local newDrillId = maxDrillID + 1  -- 16表示已通关所有关卡
+	Log.write(Log.LOGID_DEBUG, "[oneClickSaodang] 计算扫荡后关卡ID: 一键扫荡后全部通关, newDrillId="..newDrillId)
 	
 	-- 检查是否已经扫荡过:
-	-- 如果 newDrillId < currentDrillId,说明已经扫荡过(扫荡后关卡ID应该 >= 当前关卡ID)
-	-- 如果 newDrillId == currentDrillId,这是正常的(手动通关后扫荡,扫荡后关卡ID等于当前关卡ID)
-	-- 如果 newDrillId > currentDrillId,这也是正常的(扫荡后关卡ID大于当前关卡ID)
+	-- 由于 newDrillId 总是等于 maxDrillID + 1(全部通关),所以:
+	-- - 如果 currentDrillId <= maxDrillID,那么 newDrillId > currentDrillId,这是正常的,允许扫荡
+	-- - 如果 currentDrillId > maxDrillID,说明已经全部通关了,不允许再次扫荡(这个检查已经在前面做了)
+	-- 理论上 newDrillId 不会小于或等于 currentDrillId(除非已经全部通关),但为了安全起见,保留检查
 	if newDrillId < currentDrillId then
 		Log.write(Log.LOGID_DEBUG, "[oneClickSaodang] 已扫荡过,不允许再次扫荡: currentDrillId="..currentDrillId..", newDrillId="..newDrillId..", maxSaodangId="..maxSaodangId)
 		Broadcast.sendErr(human, "已扫荡过,无法再次扫荡")
 		return
 	end
 	
+	-- 如果 newDrillId == currentDrillId,理论上不会出现(因为 newDrillId 总是 maxDrillID + 1)
+	-- 但为了安全起见,保留检查(通过标记判断是否已经扫荡过)
+	if newDrillId == currentDrillId then
+		if drill.oneClickSaodangDone then
+			Log.write(Log.LOGID_DEBUG, "[oneClickSaodang] 已扫荡过(通过标记判断),不允许再次扫荡: currentDrillId="..currentDrillId..", newDrillId="..newDrillId..", maxSaodangId="..maxSaodangId)
+			Broadcast.sendErr(human, "已扫荡过,无法再次扫荡")
+			return
+		end
+	end
+	
 	Log.write(Log.LOGID_DEBUG, "[oneClickSaodang] 可扫荡关卡数: maxSaodangId="..maxSaodangId..", 总关卡数="..maxDrillID)
 	
 	-- 双倍奖励
@@ -1941,16 +1953,32 @@ function oneClickSaodang(human)
 	Msg.send(msgRet, human.fd)
 	
 	-- 更新关卡ID(已经在发放奖励前检查过了,这里直接更新)
+	local oldDrillId = drillData.drillId
 	drillData.drillId = newDrillId
 	drill.drillId = newDrillId
 	DrillDB.updateDrillData(drillData)
-	Log.write(Log.LOGID_DEBUG, "[oneClickSaodang] 更新关卡ID: "..currentDrillId.." -> "..newDrillId)
+	Log.write(Log.LOGID_DEBUG, "[oneClickSaodang] 更新关卡ID: "..currentDrillId.." -> "..newDrillId.." (drillData.drillId: "..(oldDrillId or "nil").." -> "..newDrillId..")")
+	
+	-- 检查是否全部通关
+	if newDrillId > maxDrillID then
+		Log.write(Log.LOGID_DEBUG, "[oneClickSaodang] 扫荡后已全部通关: newDrillId="..newDrillId.." > maxDrillID="..maxDrillID)
+	else
+		Log.write(Log.LOGID_DEBUG, "[oneClickSaodang] 扫荡后未全部通关: newDrillId="..newDrillId.." <= maxDrillID="..maxDrillID..", 可以手动挑战")
+	end
+	
+	-- 设置扫荡完成标记(用于防止重复扫荡)
+	drill.oneClickSaodangDone = true
+	Log.write(Log.LOGID_DEBUG, "[oneClickSaodang] 设置扫荡完成标记: oneClickSaodangDone=true")
 	
 	-- 如果通关所有关卡,触发通关回调
 	if newDrillId > maxDrillID then
+		Log.write(Log.LOGID_DEBUG, "[oneClickSaodang] 触发通关回调: newDrillId="..newDrillId.." > maxDrillID="..maxDrillID)
 		tongGuan(human, diff)
 		ChengjiuLogic.onCallback(human, ChengjiuDefine.CJ_TASK_TYPE_17, 1)
 		HeroLogLogic.finishTaskCB(human, HeroLogLogic.HERO_LOG_TYPE_5, 1)
+		Log.write(Log.LOGID_DEBUG, "[oneClickSaodang] 通关回调执行完成")
+	else
+		Log.write(Log.LOGID_DEBUG, "[oneClickSaodang] 未触发通关回调: newDrillId="..newDrillId.." <= maxDrillID="..maxDrillID)
 	end
 	
 	-- 更新数据
@@ -1959,4 +1987,17 @@ function oneClickSaodang(human)
 	-- 触发相关回调
 	YunYingLogic.onCallBack(human, "onDrill", maxSaodangId)
 	RoleSystemLogic.onDot(human, RoleSystemDefine.ROLE_SYS_ID_1204)
+	
+	-- 更新任务进度(扫荡了maxSaodangId个关卡,每个关卡胜利一次)
+	for i = 1, maxSaodangId do
+		LiLianLogic.onCallback(human, LiLianLogic.LILIAN_OUTID11, 1, diff)
+		DailyTaskLogic.recordDailyTaskFinishCnt(human, DailyTaskLogic.DAILY_TASK_ID_11, 1)
+		HeroGrowUp.onCallback(human, HeroGrowUp.TASKTYPE16, 1)
+		MengxinLogic.onCallBack(human, MengxinLogic.MX_TASK_TYPE_8, i)
+		WeekTaskLogic.recordWeekTaskFinishCnt(human, WeekTaskLogic.WEEK_TASK_ID_8, 1)
+		-- 触发勇者试炼击杀守卫事件(用于主线任务)
+		TriggerLogic.PublishEvent(TriggerDefine.DRILL_KILL_SHOUWEI, human.db._id, 1)
+	end
+	
+	Log.write(Log.LOGID_DEBUG, "[oneClickSaodang] 任务进度已更新: 扫荡关卡数="..maxSaodangId)
 end

+ 473 - 0
script/module/fuwen/BattleWillLogic.lua

@@ -0,0 +1,473 @@
+------------------------------------------------------
+-- 战意逻辑
+------------------------------------------------------
+
+local Lang = require("common.Lang")
+local Util = require("common.Util")
+local Msg = require("core.Msg")
+local ObjHuman = require("core.ObjHuman")
+local Broadcast = require("broadcast.Broadcast")
+local Grid = require("bag.Grid")
+local BagLogic = require("bag.BagLogic")
+local ItemDefine = require("bag.ItemDefine")
+local HeroLogic = require("hero.HeroLogic")
+local Log = require("common.Log")
+local BingshuGrid = require("fuwen.BingshuGrid")
+local FuwenExcel = require("excel.fuwen")
+local BingshuLogic = require("fuwen.BingshuLogic")
+
+-- 战意回退配置
+local BATTLE_WILL_ROLLBACK_CONFIG = {
+    [1] = {  -- 初级
+        needItemID = 1050,              -- 消耗道具ID
+        needItemCnt = 1,                -- 消耗数量:1个
+        returnBattleWillCnt = 1,        -- 返还战意:1个
+        returnFragmentID = 177,         -- 返还战意碎片道具ID
+        returnFragmentCnt = 0,          -- 返还战意碎片:0
+        returnAncientSpiritID = 135,    -- 返还远古之灵道具ID
+        returnAncientSpiritCnt = 0       -- 返还远古之灵:0
+    },
+    [2] = {  -- 中级
+        needItemID = 1050,
+        needItemCnt = 1,                -- 消耗数量:1个(按钮显示)
+        returnBattleWillCnt = 4,        -- 返还战意:4个
+        returnFragmentID = 177,
+        returnFragmentCnt = 10000,      -- 返还战意碎片:10,000
+        returnAncientSpiritID = 135,
+        returnAncientSpiritCnt = 0
+    },
+    [3] = {  -- 高级
+        needItemID = 1050,
+        needItemCnt = 1,                -- 消耗数量:1个(按钮显示)
+        returnBattleWillCnt = 9,        -- 返还战意:9个
+        returnFragmentID = 177,
+        returnFragmentCnt = 40000,      -- 返还战意碎片:40,000
+        returnAncientSpiritID = 135,
+        returnAncientSpiritCnt = 0
+    },
+    [4] = {  -- 超级
+        needItemID = 1050,
+        needItemCnt = 1,                -- 消耗数量:1个(按钮显示)
+        returnBattleWillCnt = 19,       -- 返还战意:19个
+        returnFragmentID = 177,
+        returnFragmentCnt = 90000,      -- 返还战意碎片:90,000
+        returnAncientSpiritID = 135,
+        returnAncientSpiritCnt = 100   -- 返还远古之灵:100
+    }
+}
+
+-- 从配置表中动态获取战意技能组ID
+-- 配置表中 skill 表的所有技能都是战意技能
+local function getBattleWillGroupIDs()
+    local groupIDs = {}
+    local groupIDSet = {}
+    
+    -- 遍历所有兵书技能(isBingshuSkill=1),收集所有 groupID
+    -- 因为整个 skill 表都是战意,所以所有兵书技能的 groupID 都是战意技能组ID
+    for skillID, skillConfig in pairs(FuwenExcel.skill) do
+        if skillConfig and skillConfig.isBingshuSkill == 1 then
+            local groupID = skillConfig.groupID
+            if groupID and not groupIDSet[groupID] then
+                table.insert(groupIDs, groupID)
+                groupIDSet[groupID] = true
+            end
+        end
+    end
+    
+    -- 如果没有找到,使用默认值(兼容性处理)
+    if #groupIDs == 0 then
+        Log.write(Log.LOGID_DEBUG, "[getBattleWillGroupIDs] 未找到战意技能,使用默认值: {1001, 1002}")
+        return {1001, 1002}
+    end
+    
+    -- 排序以确保一致性
+    table.sort(groupIDs)
+    Log.write(Log.LOGID_DEBUG, "[getBattleWillGroupIDs] 找到战意技能组ID: "..table.concat(groupIDs, ","))
+    return groupIDs
+end
+
+-- 缓存战意技能组ID列表(在模块加载时初始化)
+local BATTLE_WILL_GROUP_IDS = getBattleWillGroupIDs()
+
+-- 判断是否是战意技能
+local function isBattleWillSkill(skillConfig)
+    if not skillConfig or not skillConfig.groupID then
+        return false
+    end
+    for _, groupID in ipairs(BATTLE_WILL_GROUP_IDS) do
+        if skillConfig.groupID == groupID then
+            return true
+        end
+    end
+    return false
+end
+
+----------------------------------------- 工具函数 -----------------------------------------
+
+-- 获取战意格子数据(通过索引)
+-- 战意数据存储在 heroGrid.bingshu[index] 中,需要判断 groupID == 1002
+function getBattleWillGrid(heroGrid, index)
+    if not heroGrid then 
+        Log.write(Log.LOGID_DEBUG, "[getBattleWillGrid] heroGrid为nil")
+        return 
+    end
+    if not index then
+        Log.write(Log.LOGID_DEBUG, "[getBattleWillGrid] index为nil")
+        return
+    end
+    -- 从bingshu中获取战意数据
+    if not heroGrid.bingshu then
+        Log.write(Log.LOGID_DEBUG, "[getBattleWillGrid] heroGrid.bingshu为nil")
+        return
+    end
+    local bingshuGrid = heroGrid.bingshu[index]
+    if not bingshuGrid then
+        Log.write(Log.LOGID_DEBUG, "[getBattleWillGrid] heroGrid.bingshu["..index.."]为nil")
+        return
+    end
+    local skillID = bingshuGrid.skillID
+    if not skillID then
+        Log.write(Log.LOGID_DEBUG, "[getBattleWillGrid] skillID为nil, index="..index)
+        return
+    end
+    
+    -- 检查是否是战意技能(groupID=1001"狂暴"或groupID=1002"战意")
+    local skillConfig = FuwenExcel.skill[skillID]
+    if not skillConfig then
+        Log.write(Log.LOGID_DEBUG, "[getBattleWillGrid] skillConfig为nil, skillID="..skillID)
+        return
+    end
+    if not isBattleWillSkill(skillConfig) then
+        Log.write(Log.LOGID_DEBUG, "[getBattleWillGrid] 不是战意技能, groupID="..(skillConfig.groupID or "nil")..", skillID="..skillID..", index="..index)
+        return
+    end
+    
+    Log.write(Log.LOGID_DEBUG, "[getBattleWillGrid] 找到战意技能: index="..index..", skillID="..skillID..", level="..(skillConfig.lv or "nil"))
+    return bingshuGrid, index
+end
+
+-- 查找战意所在的索引(遍历所有bingshu格子)
+function findBattleWillIndex(heroGrid)
+    if not heroGrid or not heroGrid.bingshu then
+        Log.write(Log.LOGID_DEBUG, "[findBattleWillIndex] heroGrid或heroGrid.bingshu为nil")
+        return nil
+    end
+    
+    Log.write(Log.LOGID_DEBUG, "[findBattleWillIndex] 开始遍历所有bingshu格子,查找战意技能(groupID=1001或1002)")
+    Log.write(Log.LOGID_DEBUG, "[findBattleWillIndex] BINGSHU_MAXCNT="..BingshuLogic.BINGSHU_MAXCNT)
+    
+    -- 遍历所有bingshu格子,查找groupID=1001或1002的技能
+    for i = 1, BingshuLogic.BINGSHU_MAXCNT do
+        local bingshuGrid = heroGrid.bingshu[i]
+        if bingshuGrid then
+            local skillID = bingshuGrid.skillID
+            Log.write(Log.LOGID_DEBUG, "[findBattleWillIndex] bingshu["..i.."]存在, skillID="..(skillID or "nil"))
+            if skillID then
+                local skillConfig = FuwenExcel.skill[skillID]
+                if skillConfig then
+                    Log.write(Log.LOGID_DEBUG, "[findBattleWillIndex] bingshu["..i.."] skillConfig存在, skillID="..skillID..", groupID="..(skillConfig.groupID or "nil")..", lv="..(skillConfig.lv or "nil")..", name="..(skillConfig.name or "nil"))
+                    if isBattleWillSkill(skillConfig) then
+                        Log.write(Log.LOGID_DEBUG, "[findBattleWillIndex] ✓ 找到战意: index="..i..", skillID="..skillID..", level="..(skillConfig.lv or "nil")..", name="..(skillConfig.name or "nil")..", groupID="..(skillConfig.groupID or "nil"))
+                        return i
+                    else
+                        Log.write(Log.LOGID_DEBUG, "[findBattleWillIndex] bingshu["..i.."]不是战意, groupID="..(skillConfig.groupID or "nil"))
+                    end
+                else
+                    Log.write(Log.LOGID_DEBUG, "[findBattleWillIndex] bingshu["..i.."] skillConfig为nil, skillID="..skillID)
+                end
+            else
+                Log.write(Log.LOGID_DEBUG, "[findBattleWillIndex] bingshu["..i.."] skillID为nil")
+            end
+        else
+            Log.write(Log.LOGID_DEBUG, "[findBattleWillIndex] bingshu["..i.."]不存在")
+        end
+    end
+    
+    Log.write(Log.LOGID_DEBUG, "[findBattleWillIndex] ✗ 未找到战意技能(groupID=1001或1002),已遍历所有"..BingshuLogic.BINGSHU_MAXCNT.."个格子")
+    return nil
+end
+
+-- 获取战意等级
+-- 根据skillID判断等级:1002=1级, 2002=2级, 3002=3级, 4002=4级
+function getBattleWillLevel(heroGrid, index)
+    local grid, actualIndex = getBattleWillGrid(heroGrid, index)
+    if not grid then 
+        Log.write(Log.LOGID_DEBUG, "[getBattleWillLevel] grid为nil, index="..(index or "nil"))
+        return 0 
+    end
+    local skillID = grid.skillID
+    if not skillID then
+        Log.write(Log.LOGID_DEBUG, "[getBattleWillLevel] skillID为nil")
+        return 0
+    end
+    
+    -- 通过配置表获取等级
+    local skillConfig = FuwenExcel.skill[skillID]
+    if skillConfig and isBattleWillSkill(skillConfig) then
+        local level = skillConfig.lv or 0
+        Log.write(Log.LOGID_DEBUG, "[getBattleWillLevel] 获取到等级: level="..level..", skillID="..skillID..", index="..(index or "nil"))
+        return level
+    end
+    
+    Log.write(Log.LOGID_DEBUG, "[getBattleWillLevel] 不是战意技能, skillID="..skillID)
+    return 0
+end
+
+-- 获取下一级战意技能ID(参考兵书的getNextSkillID)
+function getNextBattleWillSkillID(skillID)
+    local tconfig = FuwenExcel.skill[skillID]
+    if not tconfig then return end
+    if not isBattleWillSkill(tconfig) then return end
+    
+    for id, config in pairs(FuwenExcel.skill) do
+        if (config.isBingshuSkill == 1) and
+           isBattleWillSkill(config) and
+           (config.groupID == tconfig.groupID) and  -- 保持相同的groupID(1001或1002)
+           (config.lv == tconfig.lv + 1) and
+           (#config.bingshuUpNeed > 0) then
+            return id
+        end
+    end
+end
+
+----------------------------------------- 协议处理 -----------------------------------------
+
+-- 查询回退信息
+function sendRollbackQuery(human, heroID, heroIndex, index)
+    Log.write(Log.LOGID_DEBUG, "[sendRollbackQuery] 收到查询请求: heroID="..(heroID or "nil")..", heroIndex="..(heroIndex or "nil")..", index="..(index or "nil"))
+    
+    local heroGrid = HeroLogic.getHeroGrid(human, heroID, heroIndex)
+    if not heroGrid then
+        Log.write(Log.LOGID_DEBUG, "[sendRollbackQuery] 英雄不存在: heroID="..(heroID or "nil")..", heroIndex="..(heroIndex or "nil"))
+        return Broadcast.sendErr(human, Lang.COMMON_ARGUMENT_ERROR)
+    end
+    
+    -- 如果传入的index不是战意,尝试查找战意所在的索引
+    local battleWillIndex = index
+    local grid = getBattleWillGrid(heroGrid, index)
+    if not grid then
+        Log.write(Log.LOGID_DEBUG, "[sendRollbackQuery] index="..index.."不是战意,尝试查找战意所在位置")
+        battleWillIndex = findBattleWillIndex(heroGrid)
+        if not battleWillIndex then
+            Log.write(Log.LOGID_DEBUG, "[sendRollbackQuery] 未找到战意技能")
+            return Broadcast.sendErr(human, "当前战意格子为空,无法回退")
+        end
+        grid = heroGrid.bingshu[battleWillIndex]
+    end
+    
+    local currentLevel = getBattleWillLevel(heroGrid, battleWillIndex)
+    Log.write(Log.LOGID_DEBUG, "[sendRollbackQuery] 当前战意等级: "..currentLevel..", index="..battleWillIndex)
+    
+    -- 检查等级是否可回退(等级0为空,不可回退)
+    if currentLevel == 0 or currentLevel < 1 or currentLevel > 4 then
+        Log.write(Log.LOGID_DEBUG, "[sendRollbackQuery] 当前等级不可回退: level="..currentLevel)
+        return Broadcast.sendErr(human, "当前战意格子为空,无法回退")
+    end
+    
+    local config = BATTLE_WILL_ROLLBACK_CONFIG[currentLevel]
+    if not config then
+        Log.write(Log.LOGID_DEBUG, "[sendRollbackQuery] 配置不存在: level="..currentLevel)
+        return Broadcast.sendErr(human, Lang.COMMON_COMFIG_ERROR)
+    end
+    
+    local msgRet = Msg.gc.GC_BATTLE_WILL_ROLLBACK_QUERY
+    msgRet.heroID = heroID
+    msgRet.heroIndex = heroIndex
+    msgRet.index = battleWillIndex  -- 使用实际找到的索引
+    msgRet.currentLevel = currentLevel
+    msgRet.targetLevel = 0  -- 回退后等级固定为0(空)
+    
+    -- 消耗道具
+    Grid.makeItem(msgRet.needItem, config.needItemID, config.needItemCnt)
+    
+    -- 获取当前技能的groupID,确定返还的战意ID
+    -- groupID=1001(狂暴)对应itemID=301,groupID=1002(战意)对应itemID=302
+    local currentSkillID = grid.skillID
+    local currentSkillConfig = FuwenExcel.skill[currentSkillID]
+    local returnBattleWillID = nil
+    if currentSkillConfig then
+        if currentSkillConfig.groupID == 1001 then
+            returnBattleWillID = 301  -- 狂暴战意
+        elseif currentSkillConfig.groupID == 1002 then
+            returnBattleWillID = 302  -- 战意战意
+        end
+    end
+    
+    -- 返还物品列表
+    msgRet.returnItems[0] = 0
+    local itemCnt = 0
+    
+    -- 返还战意
+    if config.returnBattleWillCnt > 0 and returnBattleWillID then
+        itemCnt = itemCnt + 1
+        if itemCnt <= #msgRet.returnItems then
+            Grid.makeItem(msgRet.returnItems[itemCnt], returnBattleWillID, config.returnBattleWillCnt)
+        end
+    end
+    
+    -- 返还战意碎片
+    if config.returnFragmentCnt > 0 and config.returnFragmentID > 0 then
+        itemCnt = itemCnt + 1
+        if itemCnt <= #msgRet.returnItems then
+            Grid.makeItem(msgRet.returnItems[itemCnt], config.returnFragmentID, config.returnFragmentCnt)
+        end
+    end
+    
+    -- 返还远古之灵
+    if config.returnAncientSpiritCnt > 0 and config.returnAncientSpiritID > 0 then
+        itemCnt = itemCnt + 1
+        if itemCnt <= #msgRet.returnItems then
+            Grid.makeItem(msgRet.returnItems[itemCnt], config.returnAncientSpiritID, config.returnAncientSpiritCnt)
+        end
+    end
+    
+    msgRet.returnItems[0] = itemCnt
+    
+    Log.write(Log.LOGID_DEBUG, "[sendRollbackQuery] 发送查询结果: currentLevel="..currentLevel..", index="..battleWillIndex..", needItemCnt="..config.needItemCnt..", returnItemsCount="..itemCnt)
+    Msg.send(msgRet, human.fd)
+end
+
+-- 执行回退
+function rollback(human, heroID, heroIndex, index)
+    Log.write(Log.LOGID_DEBUG, "[rollback] 收到回退请求: heroID="..(heroID or "nil")..", heroIndex="..(heroIndex or "nil")..", index="..(index or "nil"))
+    
+    local heroGrid = HeroLogic.getHeroGrid(human, heroID, heroIndex)
+    if not heroGrid then
+        Log.write(Log.LOGID_DEBUG, "[rollback] 英雄不存在")
+        return Broadcast.sendErr(human, Lang.COMMON_ARGUMENT_ERROR)
+    end
+    
+    -- 检查index范围(1-BINGSHU_MAXCNT)
+    if index and (index < 1 or index > BingshuLogic.BINGSHU_MAXCNT) then
+        Log.write(Log.LOGID_DEBUG, "[rollback] index超出范围: index="..(index or "nil")..", 有效范围: 1-"..BingshuLogic.BINGSHU_MAXCNT)
+        return Broadcast.sendErr(human, Lang.COMMON_ARGUMENT_ERROR)
+    end
+    
+    -- 如果传入的index不是战意,尝试查找战意所在的索引
+    local battleWillIndex = index
+    local grid = nil
+    if index then
+        grid = getBattleWillGrid(heroGrid, index)
+    end
+    
+    if not grid then
+        if index then
+            Log.write(Log.LOGID_DEBUG, "[rollback] index="..index.."不是战意或为空,尝试查找战意所在位置")
+        else
+            Log.write(Log.LOGID_DEBUG, "[rollback] index为nil,尝试查找战意所在位置")
+        end
+        battleWillIndex = findBattleWillIndex(heroGrid)
+        if not battleWillIndex then
+            Log.write(Log.LOGID_DEBUG, "[rollback] 未找到战意技能")
+            return Broadcast.sendErr(human, "当前战意格子为空,无法回退")
+        end
+        grid = heroGrid.bingshu[battleWillIndex]
+    end
+    
+    -- 获取当前技能配置,确定返还的战意ID和等级
+    local currentSkillID = grid.skillID
+    local currentSkillConfig = FuwenExcel.skill[currentSkillID]
+    if not currentSkillConfig then
+        Log.write(Log.LOGID_DEBUG, "[rollback] 技能配置不存在: skillID="..currentSkillID)
+        return Broadcast.sendErr(human, Lang.COMMON_COMFIG_ERROR)
+    end
+    
+    -- 检查是否是战意技能
+    if not isBattleWillSkill(currentSkillConfig) then
+        Log.write(Log.LOGID_DEBUG, "[rollback] 不是战意技能: skillID="..currentSkillID..", groupID="..(currentSkillConfig.groupID or "nil"))
+        return Broadcast.sendErr(human, "当前格子不是战意技能,无法回退")
+    end
+    
+    -- 从技能配置中获取等级(更可靠)
+    local currentLevel = currentSkillConfig.lv or 0
+    Log.write(Log.LOGID_DEBUG, "[rollback] 当前战意等级: "..currentLevel..", index="..battleWillIndex..", skillID="..currentSkillID)
+    
+    -- 检查等级是否可回退
+    if currentLevel == 0 or currentLevel < 1 or currentLevel > 4 then
+        Log.write(Log.LOGID_DEBUG, "[rollback] 当前等级不可回退: level="..currentLevel)
+        return Broadcast.sendErr(human, "当前战意格子为空,无法回退")
+    end
+    
+    -- 根据groupID确定返还的战意ID
+    -- groupID=1001(狂暴)对应itemID=301,groupID=1002(战意)对应itemID=302
+    local returnBattleWillID = nil
+    if currentSkillConfig.groupID == 1001 then
+        returnBattleWillID = 301  -- 狂暴战意
+    elseif currentSkillConfig.groupID == 1002 then
+        returnBattleWillID = 302  -- 战意战意
+    end
+    
+    if not returnBattleWillID then
+        Log.write(Log.LOGID_DEBUG, "[rollback] 无法确定返还战意ID: groupID="..(currentSkillConfig.groupID or "nil"))
+        return Broadcast.sendErr(human, Lang.COMMON_COMFIG_ERROR)
+    end
+    
+    -- 检查消耗道具(回退消耗)
+    local config = BATTLE_WILL_ROLLBACK_CONFIG[currentLevel]
+    if not config then
+        Log.write(Log.LOGID_DEBUG, "[rollback] 回退配置不存在: level="..currentLevel)
+        return Broadcast.sendErr(human, Lang.COMMON_COMFIG_ERROR)
+    end
+    
+    if not BagLogic.checkItemCnt(human, config.needItemID, config.needItemCnt) then
+        Log.write(Log.LOGID_DEBUG, "[rollback] 消耗道具不足: needItemID="..config.needItemID..", needItemCnt="..config.needItemCnt)
+        return Broadcast.sendErr(human, Lang.COMMON_NO_ITEM)
+    end
+    
+    -- 扣除消耗道具
+    BagLogic.delItem(human, config.needItemID, config.needItemCnt, "battleWill_rollback")
+    Log.write(Log.LOGID_DEBUG, "[rollback] 扣除消耗道具: needItemID="..config.needItemID..", needItemCnt="..config.needItemCnt)
+    
+    -- 收集返还物品(根据配置)
+    local returnItemList = {}
+    
+    -- 返还战意
+    if config.returnBattleWillCnt > 0 and returnBattleWillID then
+        returnItemList[returnBattleWillID] = config.returnBattleWillCnt
+    end
+    
+    -- 返还战意碎片
+    if config.returnFragmentCnt > 0 and config.returnFragmentID > 0 then
+        returnItemList[config.returnFragmentID] = config.returnFragmentCnt
+    end
+    
+    -- 返还远古之灵
+    if config.returnAncientSpiritCnt > 0 and config.returnAncientSpiritID > 0 then
+        returnItemList[config.returnAncientSpiritID] = config.returnAncientSpiritCnt
+    end
+    
+    -- 发放返还物品(使用通用道具发放逻辑)
+    if next(returnItemList) then
+        BagLogic.addItemList(human, returnItemList, "battleWill_rollback")
+        Log.write(Log.LOGID_DEBUG, "[rollback] 发放返还物品")
+        for itemID, cnt in pairs(returnItemList) do
+            Log.write(Log.LOGID_DEBUG, "[rollback]   返还道具: itemID="..itemID..", cnt="..cnt)
+        end
+    end
+    
+    -- 更新战意等级为0(清空)- 删除bingshu中的战意技能
+    if not heroGrid.bingshu then
+        heroGrid.bingshu = {}
+    end
+    local bingshuGrid = heroGrid.bingshu[battleWillIndex]
+    if bingshuGrid then
+        local skillConfig = FuwenExcel.skill[bingshuGrid.skillID]
+        if skillConfig and isBattleWillSkill(skillConfig) then
+            -- 这是战意技能,删除它
+            heroGrid.bingshu[battleWillIndex] = nil
+            Log.write(Log.LOGID_DEBUG, "[rollback] 删除战意技能: index="..battleWillIndex..", skillID="..bingshuGrid.skillID..", groupID="..(skillConfig.groupID or "nil"))
+        else
+            Log.write(Log.LOGID_DEBUG, "[rollback] WARNING: bingshu["..battleWillIndex.."]不是战意技能, skillID="..(bingshuGrid.skillID or "nil"))
+        end
+    else
+        Log.write(Log.LOGID_DEBUG, "[rollback] bingshu["..battleWillIndex.."]不存在")
+    end
+    
+    Log.write(Log.LOGID_DEBUG, "[rollback] 回退完成: 等级从 "..currentLevel.." 变为 0")
+    
+    -- 重新计算英雄属性
+    ObjHuman.doCalcHero(human, heroIndex)
+    
+    -- 发送英雄数据更新(如果需要)
+    HeroLogic.sendHeroBagDynamic(human, heroID, heroIndex)
+end

+ 67 - 3
script/module/fuwen/BingshuLogic.lua

@@ -14,6 +14,7 @@ local BagLogic = require("bag.BagLogic")
 local BingshuGrid = require("fuwen.BingshuGrid")
 local HeroLogic = require("hero.HeroLogic")
 local LiLianLogic = require("dailyTask.LiLianLogic")
+local Log = require("common.Log")
 
 BINGSHU_MAXCNT = 3 			-- 最多x个兵书
 BINGSHU_OPEN_LIST = {6, 11, 13}
@@ -189,10 +190,19 @@ end
 
 -- 升级查询
 function sendLevelUpQuery(human, heroID, heroIndex, index)
+	Log.write(Log.LOGID_DEBUG, "[sendLevelUpQuery] 收到查询请求: heroID="..(heroID or "nil")..", heroIndex="..(heroIndex or "nil")..", index="..(index or "nil"))
+	
 	local heroGrid = HeroLogic.getHeroGrid(human, heroID, heroIndex)
-	if not heroGrid then return end
+	if not heroGrid then 
+		Log.write(Log.LOGID_DEBUG, "[sendLevelUpQuery] 英雄不存在: heroID="..(heroID or "nil")..", heroIndex="..(heroIndex or "nil"))
+		return Broadcast.sendErr(human, Lang.COMMON_ARGUMENT_ERROR)
+	end
+	
 	local grid = getBingshuGrid(heroGrid, index)
-	if not grid then return end
+	if not grid then 
+		Log.write(Log.LOGID_DEBUG, "[sendLevelUpQuery] 兵书格子不存在: heroID="..(heroID or "nil")..", heroIndex="..(heroIndex or "nil")..", index="..(index or "nil"))
+		return Broadcast.sendErr(human, "兵书格子不存在")
+	end
 
 	local config = FuwenExcel.skill[grid.skillID]
 	local nextSkillID = getNextSkillID(grid.skillID)
@@ -200,6 +210,19 @@ function sendLevelUpQuery(human, heroID, heroIndex, index)
 	local msgRet = Msg.gc.GC_BINGSHU_LEVELUP_QUERY
 	msgRet.heroID = heroID
 	msgRet.heroIndex = heroIndex
+	
+	-- 检查grid和skillID
+	if not grid or not grid.skillID then
+		Log.write(Log.LOGID_DEBUG, "[sendLevelUpQuery] ERROR: grid或grid.skillID不存在, grid="..tostring(grid)..", skillID="..(grid and grid.skillID or "nil"))
+		return Broadcast.sendErr(human, "兵书数据错误")
+	end
+	
+	-- 检查技能配置
+	if not config then
+		Log.write(Log.LOGID_DEBUG, "[sendLevelUpQuery] ERROR: 技能配置不存在, skillID="..grid.skillID)
+		return Broadcast.sendErr(human, "技能配置不存在")
+	end
+	
 	BingshuGrid.makeBingshuNet(msgRet.bingshu, grid, index)
 	msgRet.upData[0] = 0
 	if nextConfig then
@@ -213,8 +236,49 @@ function sendLevelUpQuery(human, heroID, heroIndex, index)
 		local itemCnt = config.bingshuForgetReturn[i][2]
 		Grid.makeItem(msgRet.returnItems[i], itemID, itemCnt)
 	end
---	Msg.trace(msgRet)
+	
+	-- 检查消息格式
+	local protoID = msgRet[1]
+	Log.write(Log.LOGID_DEBUG, "[sendLevelUpQuery] 准备发送消息: protoID="..(protoID or "nil")..", heroID="..heroID..", heroIndex="..heroIndex..", index="..index..", skillID="..(grid.skillID or "nil")..", forgetCost="..msgRet.forgetCost)
+	Log.write(Log.LOGID_DEBUG, "[sendLevelUpQuery] human.fd="..(human.fd or "nil")..", upData[0]="..(msgRet.upData[0] or "nil")..", returnItems[0]="..(msgRet.returnItems[0] or "nil"))
+	
+	-- 检查bingshu数据
+	if msgRet.bingshu then
+		Log.write(Log.LOGID_DEBUG, "[sendLevelUpQuery] msgRet.bingshu存在, index="..(msgRet.bingshu.index or "nil")..", skillID="..(msgRet.bingshu.skill and msgRet.bingshu.skill.skillID or "nil"))
+		if msgRet.bingshu.skill then
+			Log.write(Log.LOGID_DEBUG, "[sendLevelUpQuery] msgRet.bingshu.skill.skillID="..(msgRet.bingshu.skill.skillID or "nil")..", skillName="..(msgRet.bingshu.skill.skillName or "nil"))
+		else
+			Log.write(Log.LOGID_DEBUG, "[sendLevelUpQuery] WARNING: msgRet.bingshu.skill为nil")
+		end
+	else
+		Log.write(Log.LOGID_DEBUG, "[sendLevelUpQuery] WARNING: msgRet.bingshu为nil")
+	end
+	
+	-- 检查upData数据
+	if msgRet.upData[0] > 0 and msgRet.upData[1] then
+		Log.write(Log.LOGID_DEBUG, "[sendLevelUpQuery] msgRet.upData[1]存在, skillID="..(msgRet.upData[1].skill and msgRet.upData[1].skill.skillID or "nil"))
+	end
+	
+	-- 检查returnItems数据
+	if msgRet.returnItems[0] > 0 then
+		Log.write(Log.LOGID_DEBUG, "[sendLevelUpQuery] msgRet.returnItems[0]="..msgRet.returnItems[0])
+		for i = 1, msgRet.returnItems[0] do
+			if msgRet.returnItems[i] then
+				Log.write(Log.LOGID_DEBUG, "[sendLevelUpQuery] msgRet.returnItems["..i.."]: id="..(msgRet.returnItems[i].id or "nil")..", cnt="..(msgRet.returnItems[i].cnt or "nil"))
+			end
+		end
+	end
+	
+	if not human.fd then
+		Log.write(Log.LOGID_DEBUG, "[sendLevelUpQuery] ERROR: human.fd为nil,无法发送消息")
+		return Broadcast.sendErr(human, "连接已断开")
+	end
+	
+	-- 使用Msg.trace检查消息格式(如果可用)
+	-- Msg.trace(msgRet)
+	
 	Msg.send(msgRet, human.fd)
+	Log.write(Log.LOGID_DEBUG, "[sendLevelUpQuery] 消息已发送: protoID="..(protoID or "nil")..", heroID="..heroID..", heroIndex="..heroIndex..", index="..index)
 end
 
 -- 升级

+ 11 - 0
script/module/fuwen/Handler.lua

@@ -1,5 +1,6 @@
 local FuwenLogic = require("fuwen.FuwenLogic")
 local BingshuLogic = require("fuwen.BingshuLogic")
+local BattleWillLogic = require("fuwen.BattleWillLogic")
 
 function CG_FUWEN_PUTON(human,msg)
     FuwenLogic.putOn(human, msg.heroID, msg.heroIndex, msg.fuwenIndex,msg.pos,nil)
@@ -107,4 +108,14 @@ end
 
 function CG_FUWEN_RESET_LOCK(human, msg)
     FuwenLogic.ResetLock(human, msg.fuwenID, msg.fuwenIndex, msg.heroID, msg.heroIndex, msg.pos, msg.opTarget, msg.opIdx, msg.opType)
+end
+
+-- 战意回退查询
+function CG_BATTLE_WILL_ROLLBACK_QUERY(human, msg)
+    BattleWillLogic.sendRollbackQuery(human, msg.heroID, msg.heroIndex, msg.index)
+end
+
+-- 战意回退执行
+function CG_BATTLE_WILL_ROLLBACK_DO(human, msg)
+    BattleWillLogic.rollback(human, msg.heroID, msg.heroIndex, msg.index)
 end

+ 24 - 0
script/module/fuwen/Proto.lua

@@ -365,4 +365,28 @@ GC_FUWEN_GET_WAY_QUERY = {
     {"newFuwen",        1,      ItemData},            -- 合成符文
     {"desc1",           1,      "string"},               -- 新符文属性描述
     {"desc2",           1,      "string"},               -- 新符文技能描述
+}
+
+-- 战意回退查询
+CG_BATTLE_WILL_ROLLBACK_QUERY = {
+    {"heroID",          1,      "int"},
+    {"heroIndex",       1,      "short"},
+    {"index",           1,      "byte"},        -- 战意索引
+}
+
+GC_BATTLE_WILL_ROLLBACK_QUERY = {
+    {"heroID",          1,      "int"},
+    {"heroIndex",       1,      "short"},
+    {"index",           1,      "byte"},        -- 战意索引
+    {"currentLevel",    1,      "byte"},        -- 当前等级(1-4)
+    {"targetLevel",     1,      "byte"},        -- 回退后等级(固定为0,表示空)
+    {"needItem",        1,      ItemData},      -- 消耗道具
+    {"returnItems",     5,      ItemData},      -- 返还物品列表(最多5个)
+}
+
+-- 战意回退执行
+CG_BATTLE_WILL_ROLLBACK_DO = {
+    {"heroID",          1,      "int"},
+    {"heroIndex",       1,      "short"},
+    {"index",           1,      "byte"},        -- 战意索引
 }