---------------------------------------------------
-- 过关斩将/圣树试炼
---------------------------------------------------

--[[
    db.drill = {
		time     =       1,     -- 这次数据的时间
		diff     =       1,     -- 选择的难度
		drillId  =       1，    -- 今日最大 通关关卡
		maxDiff  =       1,     -- 最大通关难度
		lastDiff  =       1,     -- 昨日选择的难度
		lastDrillId  =       1,     -- 昨日最大关卡		
		

		myHelpIndex =    1,     -- 我选择的援助出去英雄
		helpoutList = {},       -- 我选择的援助英雄
		dayGet     =  {},       -- 今日已获得奖励
		boxGet     =  {},       -- 今日宝箱 已领取
	}

]]--

local Config = require("Config")
local DrillExcel = require("excel.drill")
local MailExcel = require("excel.mail")
local MonsterExcel = require("excel.monster")
local Util = require("common.Util")
local Lang = require("common.Lang")
local CommonDB = require("common.CommonDB")
local Msg = require("core.Msg")
local InnerMsg = require("core.InnerMsg")
local ObjHuman = require("core.ObjHuman")
local Timer = require("core.Timer")
local Broadcast = require("broadcast.Broadcast")
local Grid = require("bag.Grid")
local BagLogic = require("bag.BagLogic")
local CombatImpl = require("combat.CombatImpl")
local CombatObj = require("combat.CombatObj")
local CombatLogic = require("combat.CombatLogic")
local CombatDefine = require("combat.CombatDefine")
local CombatPosLogic = require("combat.CombatPosLogic")
local CopyManage = require("copy.CopyManage")
local ChatPaoMaLogic = require("chat.ChatPaoMaLogic")
local DrillDB = require("drill.DrillDB")
local DrillMiddleLogic = require("drill.DrillMiddleLogic")
local DrillLogicAttribute = require("drill.DrillLogicAttribute")
local HeroGrid = require("hero.HeroGrid")
local HeroDefine = require("hero.HeroDefine")
local RoleDefine = require("role.RoleDefine")
local RoleLogic = require("role.RoleLogic")
local RoleDBLogic = require("role.RoleDBLogic")
local RoleSystemDefine = require("roleSystem.RoleSystemDefine")
local RoleSystemLogic = require("roleSystem.RoleSystemLogic")
local MailManager = require("mail.MailManager")
local MiddleConnect = require("middle.MiddleConnect")
local HeroExcel = require("excel.hero")
local FriendDBLogic = require("friend.FriendDBLogic")
local ChengjiuLogic = require("chengjiu.ChengjiuLogic")
local ChengjiuDefine = require("chengjiu.ChengjiuDefine")
local LiLianLogic = require("dailyTask.LiLianLogic")
local BeSkill = require("combat.BeSkill")
local SkinLogic = require("skin.SkinLogic")
local DailyTaskLogic = require("dailyTask.DailyTaskLogic")
local ItemDefine = require("bag.ItemDefine")
local VipLogic = require("vip.VipLogic")
local HeroLogic = require("hero.HeroLogic")
local MailDefine = require("mail.MailIdDefine")
local JibanLogic = require("combat.JibanLogic")
local HeroLogLogic = require("absAct.HeroLogLogic")
local HeroGrowUp = require("absAct.HeroGrowUp")
local MengxinLogic = require("present.MengxinLogic")
local YunYingLogic = require("yunying.YunYingLogic")
local TalismanLogic = require("talisman.TalismanLogic")
local WeekTaskLogic = require("dailyTask.WeekTaskLogic")
local TriggerLogic = require("trigger.TriggerLogic")
local TriggerDefine = require("trigger.TriggerDefine")
local OverflowFundLogic = require("present.OverflowFundLogic")
local Log = require("common.Log")

local queryFields = {["uuid"] = 1}
local queryFieldsList = {}
local queryUuidFields = {["uuid"] = 1}
local queryRawardFields = {["drillId"] = 1, ["rawardStatus"] = 1}
local sortTable = {}

SEASON_KEEP_DAY = 1	  -- 1天一个流程

STATE_NOOPEN = 0 	  -- 未开始
STATE_OPEN = 1 		  -- 开始
STATE_READY = 2 	  -- 准备期间

-- 难度说明
DIFF_NORMAL = 1      -- 普通难度
DIFF_ELITE  = 2      -- 精英难度
DIFF_INCUBI = 3      -- 噩梦难度

DRILL_BOX_STATE_0 = 0 -- 未领取
DRILL_BOX_STATE_1 = 1 -- 可领取
DRILL_BOX_STATE_2 = 2 -- 已领取

DRILL_BOX_GOD_MAX = 3    -- 诸神怜悯 最大获奖次数


local FRIEND_ITEM_CNT = 10 		-- 每次助战获得x点友情点
local MAX_HEROCOMBAT_MUL = 150	-- 助战英雄最大倍数百分比
local INIT_HP_MAX = 100

local SAODANG_COND_LEVEL = 90	--勇者试炼副本扫荡所需等级

local CHALLENGE_DIAMONS = 500  -- 使用钻石通过当前关卡需要的钻石数量

--秘宝加成
local function getTalismanAdd(human)
	local heroExpMul = (TalismanLogic.getTalismanAdd(human, TalismanLogic.OTHER_EFFECT_TBL.DRILL_HERO_EXP) or 0) / 100
	return heroExpMul
end


-- 获取剩余时间
function getState()
--	if MiddleConnect.IS_MIDDLE_CONNECT ~= true then
--		return STATE_NOOPEN, Lang.MIDDLE_SVR_ERR_CONNECT
--	end
	return STATE_OPEN
end

-- 判断
function isOpen(human, sendTip)

--[[
	local isok, tip = CopyManage.isOpen(CopyInfo, human) 
	if not isok then
		if sendTip and tip then
			Broadcast.sendErr(human, tip)
		end
		return 
	end

	local state, _, tip = getState()
	if state ~= STATE_OPEN then
		if sendTip and tip then
			Broadcast.sendErr(human, tip)
		end
		return
	end
]]
	


	return true
end

-- 活动开始倒计时
function getStartLeftTime(human)
	local state, leftSec = getState()
	if state ~= STATE_NOOPEN then
		return leftSec
	end
	return 0
end

function getCopyState(human)
	local state = getState()
	return state
end

-- 最大通关难度
function getMaxDiff(human)
	if not human.db.drill then
		return 0
	end
	return human.db.drill.maxDiff or 0
end

function setMaxDiff(human, diff)
	if not human.db.drill then return end 
	human.db.drill = human.db.drill or {}
	human.db.drill.maxDiff = diff
end

-- 获取关卡奖励配置
function getDrillItems(drillId, diff)
	local config = DrillExcel.drill[drillId]
	if not config then return end

	if diff == DIFF_NORMAL then 
		return config.items
	end	
	return config["items" .. diff]
end

-- 数据重置
-- 重置关卡数据
-- 重置关卡阵容
-- 每天0点检测是否开启了试炼 进行清除
function onHour()
	DrillDB.checkDrillReset()
end

function dayCheck()
	if _G.is_middle then return end	
	DrillDB.reset()
end

-- 查询时间
function querySec(human)	
	if not isOpen(human, true) then return end

	local state, leftSec = getState()
	local msgRet = Msg.gc.GC_DRILL_SEC
	msgRet.leftSec = leftSec
	msgRet.isStart = (state == STATE_OPEN) and 1 or 0
	Msg.send(msgRet, human.fd)
	queryDrillId(human)
end

function inintDrill(human)
	if not human.db.drill then
		human.db.drill = {}
		local drill = human.db.drill 
		drill.time = 0
		drill.diff = 0
		drill.drillId = nil
		drill.maxDiff = 0
		drill.lastDiff = 0
		drill.lastDrillId = 0
		drill.myHelpIndex = 0
		drill.dayGet = nil
		drill.boxGet = nil
		drill.myHelpHero = nil
		drill.helpoutList = nil
	end
end


function updateDaily(human)
--	CombatPosLogic.cleanCombatHeros(human, CombatDefine.COMBAT_TYPE9)
	local drillDB = human.db.drill 
	if not drillDB then return end

	if Util.isSameDay(drillDB.time) then
		return
	end
	local surDay = Util.diffDay(drillDB.time)
	if surDay == 1 then
		drillDB.lastDrillId = drillDB.drillId
		drillDB.lastDiff = drillDB.diff
	else
		drillDB.lastDrillId = 0
		drillDB.lastDiff = 0
	end
	drillDB.time = os.time()
	drillDB.drillId = nil 
	drillDB.diff = 0 
	drillDB.dayGet = nil 
	drillDB.boxGet = nil 
	drillDB.myHelpIndex = 0		
	drillDB.myHelpHero = nil
	drillDB.helpoutList = nil
	drillDB.oneClickSaodangDone = nil  -- 清除扫荡完成标记

end

-- 修正 玩家DB  玩家卡0点 选择难度挑战  DrilDB 后清 导致 玩家DB 和 DrillDB 对不上   后续修改为 以DrillDB 为准
function fixDrillDB(human)
	if human.db.drill then
		human.db.drill.diff = 0
	end
end

-- 难度选择查询
function diffChoseQuery(human)
	if not human.db.drill then
		inintDrill(human)
	end

	local drill = human.db.drill 
    
   
	if not drill.diff or drill.diff == 0 then
		local msgRet = Msg.gc.GC_DRILL_DIFF 
        msgRet.isGuide = drill.isGuide or 1
        drill.isGuide = 0
		for i = DIFF_NORMAL , DIFF_INCUBI do
			local config = DrillExcel.define[i]
			local net = msgRet.list[i]
			net.diff = i
			net.canChose = i == DIFF_NORMAL and 1 or 0
			net.reward[0] = 0
			net.needZhanli = config.needZhanli
			if drill.maxDiff >= i - 1 and  human.db.zhandouli >= config.needZhanli then
				net.canChose = 1
			end
		end
		msgRet.list[0] = DIFF_INCUBI
		Msg.send(msgRet, human.fd) 														
	end
end

function checkSaoDang(human, diff, lastDiff, lastId)
	local diff = diff
	local id = 1
	local drillDB = human.db.drill
	if not drillDB then return diff, id end
	lastId = lastId and lastId or 0
	lastId = lastId <= #DrillExcel.drill and lastId or #DrillExcel.drill
    local double = RoleSystemLogic.isDouble(human, RoleSystemDefine.ROLE_SYS_ID_1204)
    local rewardCnt = double and 2 or 1

	--秘宝加成
	local heroExpMul = getTalismanAdd(human)

	if lastDiff and lastDiff == diff and lastId > 10 then
		id = lastId - 10

		local itemInfo  = {}
		for i = 1 , id do
			local drillItems = getDrillItems( i, lastDiff) 
			-- 关卡奖励		
			for _, item in ipairs(drillItems) do
				local itemID = item[1]
				local itemCnt = item[2] * rewardCnt
				if itemID == ItemDefine.ITEM_GREEN_EXP_ID then
					itemCnt = itemCnt + math.ceil(itemCnt * heroExpMul)
				end

				drillDB.dayGet = drillDB.dayGet or {}
				drillDB.dayGet[itemID] = (drillDB.dayGet[itemID] or 0) + itemCnt
				BagLogic.addItem(human, itemID, itemCnt, "drill")
			end			
		end		
--		BagLogic.sendItemGetList(human, itemList, "drill")  
		local msgRet = Msg.gc.GC_DRILL_SAODANG_ITEM
		msgRet.drillId = id
		local len = 0
		for k , v in pairs(drillDB.dayGet) do
			len = len + 1
			Grid.makeItem(msgRet.itemList[len], k, v)
			-- Grid.makeItem(msgRet.itemList[len], k, v, nil, nil, nil, nil, nil, nil, itemInfo[k])
		end
		msgRet.itemList[0] = len 
		msgRet.double = double and 1 or 0
		Msg.send(msgRet, human.fd)

		id = id + 1
	end 
	return diff, id
end

function saodangQuest(human, drillId)
	if drillId <= 1 then  return end
	local drill = human.db.drill 
	if not drill then return end
	local diff = drill.diff
	local dirllDefConfig = DrillExcel.define[drill.diff] 
	if not dirllDefConfig then  return end
	local drillData = DrillDB.getDrillDataByUuid(human.db._id)
	if not drillData then
		fristQust(human, drillId)
		return
	end

	local zhandouli = CombatPosLogic.getCombatHeroZDL(human, CombatDefine.COMBAT_TYPE1)
	if zhandouli <= 0 then return Broadcast.sendErr(human, Lang.COMBAT_ERR_NO_SET_FIGHT)  end

	if human.maxZDL and human.maxZDL.zhandouli and human.maxZDL.zhandouli > zhandouli then 
		-- 获取玩家真正的最高战力   防止玩家 战役上阵 战力低 去匹配 低战力对手
		zhandouli = human.maxZDL.zhandouli
	end

	local notTab = {}
	for i = 1 , drillId do 
		local drillObj = pipei(human, i, diff, zhandouli, notTab)
	
		drillData.drillObjs[i] = Util.copyTable(drillObj)
	
	end
	DrillDB.updateDrillData(drillData)
end

-- 选择难度
function choseDiff(human, diff)
	if not human.db.drill then
		inintDrill(human) 
	end
	local drill = human.db.drill 

	local now = os.time()
	if not drill.diff or drill.diff == 0  then
		drill.dayGet = {}
		drill.boxGet = {}
		drill.myHelpIndex = 0		
		drill.myHelpHero = nil
		drill.helpoutList = nil
		drill.time  = now
		drill.diff, drill.drillId = checkSaoDang(human, diff, drill.lastDiff, drill.lastDrillId)

		
		local drillData = DrillDB.getDrillDataByUuid(human.db._id)
		-- 临时处理
		if not drillData then
			quest(human, drill.drillId)
		else
			quest(human, drillData.drillId + 1)
		end
	
		saodangQuest(human,  drill.drillId )
		queryDrillId(human)
	end
end

-- 获取宝箱状态
function getBoxState(drill, index)
	local state = DRILL_BOX_STATE_0
	if not drill.drillId or drill.drillId <= 0 then
		return state
	end
	local config = DrillExcel.box[index]

	if drill.drillId > config.needDrill then
		state = DRILL_BOX_STATE_1
	end

	if drill.boxGet and drill.boxGet[index] and drill.boxGet[index].state then
		state = DRILL_BOX_STATE_2	
	end

	return state 
end

-- 查询关卡Id
function queryDrillId(human, drillData, openPanel)
	-- openPanel: 是否打开界面，默认为true（打开界面）
	-- false-不打开界面，只刷新数据；true-打开界面
	if openPanel == nil then
		openPanel = true  -- 默认打开界面
	end
	
	drillData = drillData or DrillDB.getDrillDataByUuid(human.db._id)
	if not drillData then -- 没有记录 请求第一关
		fixDrillDB(human)
		return diffChoseQuery(human)   -- quest(human)
	end

	local drill = human.db.drill
	if not drill then
		-- drill 数据不存在，初始化
		fixDrillDB(human)
		drill = human.db.drill
		if not drill then
			return diffChoseQuery(human)
		end
	end
	
	local diff = drill.diff
	if not drill.diff  or drill.diff == 0 then
		diff = drillData.diff		 
	end

	if diff == 0 then
		return diffChoseQuery(human)
	end

    local msgRet = Msg.gc.GC_DRILL_ID
	-- 按照协议定义的顺序赋值
	-- 1. drillId (byte类型，范围0-255，防止溢出)
	local drillIdValue = drillData.drillId or 1
	if drillIdValue > 255 or drillIdValue < 0 then
		--Log.write(Log.LOGID_DEBUG, "[queryDrillId] WARNING: drillId溢出，原始值="..drillIdValue.."，限制后="..math.min(math.max(drillIdValue, 0), 255))
	end
	msgRet.drillId = math.min(math.max(drillIdValue, 0), 255)
	-- 2. diff (byte类型，范围0-255，防止溢出)
	local diffValue = diff or 1
	if diffValue > 255 or diffValue < 0 then
		--Log.write(Log.LOGID_DEBUG, "[queryDrillId] WARNING: diff溢出，原始值="..diffValue.."，限制后="..math.min(math.max(diffValue, 0), 255))
	end
	msgRet.diff = math.min(math.max(diffValue, 0), 255)
	-- 3. box (数组) - 协议定义最大长度为5
	local boxCount = math.min(#DrillExcel.box, 5)
	msgRet.box[0] = boxCount
	--秘宝加成
	local heroExpMul = getTalismanAdd(human)
	for k = 1, boxCount do
		local config = DrillExcel.box[k]
		local net = msgRet.box[k]	
		-- index 和 needId 都是 byte 类型，防止溢出
		if k > 255 or k < 0 then
			--Log.write(Log.LOGID_DEBUG, "[queryDrillId] WARNING: box index溢出，原始值="..k.."，限制后="..math.min(math.max(k, 0), 255))
		end
		net.index = math.min(math.max(k, 0), 255)
		local needIdValue = config.needDrill or 0
		if needIdValue > 255 or needIdValue < 0 then
			--Log.write(Log.LOGID_DEBUG, "[queryDrillId] WARNING: box needId溢出，原始值="..needIdValue.."，限制后="..math.min(math.max(needIdValue, 0), 255))
		end
		net.needId = math.min(math.max(needIdValue, 0), 255)
		net.state = getBoxState(drill,  k)
		local itemID1  = config["items"..diff][1][1]
		local itemCnt1 = config["items"..diff][1][2]
		if itemID1 == ItemDefine.ITEM_GREEN_EXP_ID and heroExpMul > 0 then
			itemCnt1 = itemCnt1 + math.ceil(itemCnt1 * heroExpMul)
		end

		local itemID2  = config["items"..diff][2][1]
		local itemCnt2 = config["items"..diff][2][2]
		if itemID2 == ItemDefine.ITEM_GREEN_EXP_ID and heroExpMul > 0 then
			itemCnt2 = itemCnt1 + math.ceil(itemCnt2 * heroExpMul)
		end

		Grid.makeItem(net.reward[1], itemID1,  itemCnt1 )
		Grid.makeItem(net.reward[2], itemID2,  itemCnt2 )
		net.reward[0] = 2

		if config["items"..diff][3] then
			local itemID3  = config["items"..diff][3][1]
			local itemCnt3 = config["items"..diff][3][2]
			if itemID3 == ItemDefine.ITEM_GREEN_EXP_ID and heroExpMul > 0 then
				itemCnt3 = itemCnt1 + math.ceil(itemCnt3 * heroExpMul)
			end

			Grid.makeItem(net.reward[3], itemID3,  itemCnt3 )
			net.reward[0] = 3
		end
	end
	-- 4. dayGet (数组)
	msgRet.dayGet[0] = 2
	local dayJinbi = drill.dayGet and drill.dayGet[ItemDefine.ITEM_JINBI_ID] or 0
	local dayCoin = drill.dayGet and drill.dayGet[ItemDefine.ITEM_DRILL_COIN_ID] or 0
	Grid.makeItem(msgRet.dayGet[1], ItemDefine.ITEM_JINBI_ID,  dayJinbi )
	Grid.makeItem(msgRet.dayGet[2], ItemDefine.ITEM_DRILL_COIN_ID,  dayCoin )
	-- 5. maxDiff (byte类型，范围0-255，防止溢出)
	-- 注意：如果 maxDiff 为 0，应该视为未设置，使用默认值 1（因为 0 在 Lua 中是 truthy）
	local maxDiffValue = (drill.maxDiff == nil or drill.maxDiff == 0) and 1 or drill.maxDiff
	if maxDiffValue > 255 or maxDiffValue < 0 then
		--Log.write(Log.LOGID_DEBUG, "[queryDrillId] WARNING: maxDiff溢出，原始值="..maxDiffValue.."，限制后="..math.min(math.max(maxDiffValue, 0), 255))
	end
	msgRet.maxDiff = math.min(math.max(maxDiffValue, 0), 255)
	-- 6. canOneClickSaodang
	-- 计算是否开启一键扫荡
	local canOneClickSaodang = 0
	-- 检查是否购买了基金
	local overflowState = human.db.overflow and human.db.overflow.state and human.db.overflow.state[OverflowFundLogic.OVERFLOW_TYPE_2]
	local hasFund = overflowState ~= nil
	--Log.write(Log.LOGID_DEBUG, "[queryDrillId] 检查基金状态: overflow="..tostring(human.db.overflow ~= nil)..", state="..tostring(human.db.overflow and human.db.overflow.state ~= nil)..", overflowState[2]="..tostring(overflowState)..", hasFund="..tostring(hasFund))
	if hasFund then
		-- 检查试炼是否开启
		local drillOpen = isOpen(human, false)
		if drillOpen then
			-- 检查是否有 drill 数据
			if drill then
				-- 检查是否有 drillData 数据
				if drillData then
					-- 检查 diff 不为 0
					if diff ~= 0 then
						-- 已购买基金且满足其他条件，开启一键扫荡（已去掉等级限制和关卡ID限制）
						-- 注意：即使 drillId=1，也显示按钮，实际扫荡时会检查是否有可扫荡的关卡
						canOneClickSaodang = 1
					else
						--Log.write(Log.LOGID_DEBUG, "[queryDrillId] canOneClickSaodang=0: diff="..diff.." == 0")
					end
				else
					--Log.write(Log.LOGID_DEBUG, "[queryDrillId] canOneClickSaodang=0: drillData为nil")
				end
			else
				--Log.write(Log.LOGID_DEBUG, "[queryDrillId] canOneClickSaodang=0: drill为nil")
			end
		else
			--Log.write(Log.LOGID_DEBUG, "[queryDrillId] canOneClickSaodang=0: 试炼未开启")
		end
	else
		--Log.write(Log.LOGID_DEBUG, "[queryDrillId] canOneClickSaodang=0: 未购买奢华基金（OVERFLOW_TYPE_2）")
	end
	msgRet.canOneClickSaodang = canOneClickSaodang
	-- 7. openPanel
	msgRet.openPanel = (openPanel == true) and 1 or 0

--	Msg.trace(msgRet)
	Msg.send(msgRet, human.fd)
end


-- 是否被击杀
function isObjKill(drillObj)
    if drillObj == nil then return end
	if drillObj.objStatus == nil then
		return 
	end
    for _, hpRate in pairs(drillObj.objStatus) do
		if hpRate > 0 then				
			return 
		end			
    end
	return true
end

-- 查询关卡状态
function query(human, drillId)
	--if not isOpen(human, true) then return end

	local drill = human.db.drill 
	if not drill then return end 

	local drillCfg = DrillExcel.drill[drillId]
	if not drillCfg then  return end

	local drillData = DrillDB.getDrillDataByUuid(human.db._id)
	if not drillData then  return end

	local drillObj = drillData.drillObjs[drillId]
	if not drillObj then  
		if drillId < 15 and drillData.drillId == drillId then
			quest(human, drillId)
		end
		return 
	end

	--秘宝加成
	local heroExpMul = getTalismanAdd(human)

	local double = RoleSystemLogic.isDouble(human, RoleSystemDefine.ROLE_SYS_ID_1204)
	local rewardCnt = double and 2 or 1
	--require("common.Util").printTable(drillObj)
	local nowId = drillData.drillId
	local msgRet = Msg.gc.GC_DRILL_INFO
	msgRet.drillId = drillId
	msgRet.svrName = drillObj.svrName or Config.DB_NAME	
    RoleLogic.makeRoleBase(drillObj, msgRet.roleBase)
	msgRet.reward[0] = 0
	msgRet.double = double and 1 or 0
	local itemConfig = drillCfg.items
	if 	drill.diff == DIFF_ELITE then
		itemConfig = drillCfg.items2
	elseif drill.diff == DIFF_INCUBI then
		itemConfig = drillCfg.items3
	end

	for _, item in pairs(itemConfig) do
		msgRet.reward[0] = msgRet.reward[0] + 1
		local itemCnt = item[2] * rewardCnt
		if item[1] == ItemDefine.ITEM_GREEN_EXP_ID then
			itemCnt = itemCnt + math.ceil(itemCnt * heroExpMul)
		end
		Grid.makeItem(msgRet.reward[msgRet.reward[0]], item[1], itemCnt)
		--Grid.makeItem(msgRet.reward[msgRet.reward[0]], item[1], item[2] * rewardCnt)
	end

	msgRet.defence[0] = 0
	for i = 1, CombatDefine.COMBAT_HERO_CNT do
		local obj = drillObj.heroList[i]	
        if obj and i ~= CombatDefine.BACKUP_POS[1] then
        	local hpRate = DrillLogicAttribute.getObjHpRate(drillObj, obj.bagIndex)
        	local hp = math.ceil(INIT_HP_MAX * hpRate)
        	local hpMax = INIT_HP_MAX
			hp = nowId > drillId and 0 or hp
            local others = HeroGrid.createOthers(obj.lv, hp, hpMax, obj.star)
			msgRet.defence[0] = msgRet.defence[0] + 1
			if drillObj.monsterOutID and drillObj.monsterOutID > 0 then
				HeroGrid.makeHeroSimpleByMonsterID(msgRet.defence[msgRet.defence[0]], obj.id, others)
			else
				HeroGrid.makeHeroSimpleByID(msgRet.defence[msgRet.defence[0]], obj.id, i, others)
			end
        end
	end

    local quick = CombatLogic.getQuick(human, CombatDefine.COMBAT_TYPE9)
    local showNext = 1
    -- if getMaxDiff(human) >= drill.diff and human.db.lv >= SAODANG_COND_LEVEL then
    --    showNext = 1
    -- end

	--取消难度限制
	-- if human.db.lv >= SAODANG_COND_LEVEL then
	-- 	showNext = 1
	--  end


    msgRet.quick = quick or 0
    msgRet.showNext = showNext
	--Msg.trace(msgRet)
	Msg.send(msgRet, human.fd) 
    
    -- 推送英雄的状态信息
	sendHeroList(human, drillData.heroStatus)    
end

local FIX_LIST = {}
function sendHeroList(human, heroStatus)
	local drillData = DrillDB.getDrillDataByUuid(human.db._id)
	if not drillData then return end
	local drill = human.db.drill
	if not drill then return end
	
	heroStatus = heroStatus and heroStatus or drillData.heroStatus	

	local config = DrillExcel.define[drillData.diff] 
	local msgRet = Msg.gc.GC_DRILL_HERO
	msgRet.isFirst = 1
	msgRet.isLast = 0
	msgRet.heroList[0] = 0
	msgRet.helpList[0] = 0
	local limit = human.drill or {}
	-- 雇佣英雄
	if drillData.helpUuids then
		for targetUuid, v in pairs(drillData.helpUuids) do	
			msgRet.helpList[0] = msgRet.helpList[0] + 1
			local net = msgRet.helpList[msgRet.helpList[0]]
			if fontHelpNet(net, targetUuid, true) then
				-- 其它数据
				local hpRate = DrillLogicAttribute.getHelpHpRate(drillData, targetUuid)
				net.heroSimple.hp = math.ceil(INIT_HP_MAX * hpRate) 
				net.heroSimple.hpMax = INIT_HP_MAX	

				if limit.combatHelpUuid and limit.combatHelpUuid == targetUuid then
					net.pos = human.drill.combatHelpPos
				end

				if v.win or net.heroSimple.hp <= 0 then
					net.state = 1
					net.pos = 0
				end
			end 
		end
	end

	local heroMinLevel = config and config.heroMinLevel or 0
	-- 背包的英雄
	for index,heroGrid in pairs(human.db.heroBag) do
		if index ~= 0 and heroGrid.lv >= heroMinLevel then
			if msgRet.heroList[0] >= #msgRet.heroList then
				Msg.send(msgRet, human.fd)
				msgRet.heroList[0] = 0
				msgRet.helpList[0] = 0
				msgRet.isFirst = 0
			end 

			msgRet.heroList[0] = msgRet.heroList[0] + 1
			local heroNet = msgRet.heroList[msgRet.heroList[0]]	
			HeroGrid.makeHeroSimple(heroNet, heroGrid, index)
			-- 其它数据
			local hpRate = DrillLogicAttribute.getHeroHpRate(drillData, heroGrid.uuid)
		    heroNet.hp = math.ceil(INIT_HP_MAX * hpRate) 
		    heroNet.hpMax = INIT_HP_MAX				
		end
	end	
	if msgRet.heroList[0] > 0 or msgRet.isFirst == 1 then
		msgRet.isLast = 1
	--	Msg.trace(msgRet)
		Msg.send(msgRet, human.fd)
	end

end

function drillBoxGet(human, index)
	local drill = human.db.drill 
	if not drill or not drill.diff or drill.diff == 0 then
		return
	end
	local config = DrillExcel.box[index]
	if not config then return end
	local state = getBoxState(drill, index)
	if state ~= 1 then 
		return
	end

	drill.boxGet = drill.boxGet or {}
	drill.boxGet[index] = drill.boxGet[index] or {}
	drill.boxGet[index].cnt = drill.boxGet[index].cnt or 0
	drill.boxGet[index].cnt = drill.boxGet[index].cnt + 1 
	
	local msgRet = Msg.gc.GC_DRILL_BOX_GET
	msgRet.type = 0
	msgRet.index = index
	local random = math.random(1, 100)
	if random <= 10 and drill.boxGet[index].cnt < DRILL_BOX_GOD_MAX then
		-- 诸神的怜悯
		msgRet.type = drill.boxGet[index].cnt >= DRILL_BOX_GOD_MAX - 1 and 2 or 1
	else
		drill.boxGet[index].state = 1		
	end	
	Msg.send(msgRet, human.fd)

	local itemConfig = config.items1
	if 	drill.diff == DIFF_ELITE then
		itemConfig = config.items2
	elseif drill.diff == DIFF_INCUBI then
		itemConfig = config.items3
	end

	--秘宝加成
	local heroExpMul = getTalismanAdd(human)
	local awardVec = {}
	for i, v in ipairs(itemConfig) do
		local itemID = v[1]
		local itemCnt = v[2]
		if itemID == ItemDefine.ITEM_GREEN_EXP_ID and heroExpMul > 0 then
			itemCnt = itemCnt + math.ceil(itemCnt * heroExpMul)
		end
		awardVec[i]= {itemID, itemCnt}
	end

	--BagLogic.addItemList(human, itemConfig, "drill")
	BagLogic.addItemList(human, awardVec, "drill")

	RoleSystemLogic.onDot(human, RoleSystemDefine.ROLE_SYS_ID_1204)
    RoleSystemLogic.onDot(human, RoleSystemDefine.ROLE_SYS_ID_1201)
--	queryDrillId(human)
end

--奖励预览
function rewardPreview(human)
	if not isOpen(human, true) then return end

    local msgRet = Msg.gc.GC_DRILL_REWARD_PREVIEW
    msgRet.list[0] = 0

	--秘宝加成
	local heroExpMul = getTalismanAdd(human)

    for drillId, cf in pairs(DrillExcel.drill) do 
    	msgRet.list[0] = msgRet.list[0] + 1
    	local net = msgRet.list[msgRet.list[0]]
		net.drillId = drillId
		net.items[0] = #cf.items
		for i, item in ipairs(cf.items) do
		    local itemID = item[1]
		    local itemCnt = item[2]
			if itemID == ItemDefine.ITEM_GREEN_EXP_ID and heroExpMul > 0 then
				itemCnt = itemCnt + math.ceil(itemCnt * heroExpMul)
			end
	        Grid.makeItem(net.items[i], itemID, itemCnt)
		end
	end
	Msg.send(msgRet, human.fd)
end

-- 邮件提醒
function sendDrillTip(human)
    if human.db.mailtips[RoleSystemLogic.ROLE_MAILTIPS_ID1] == nil then
		human.db.mailtips[RoleSystemLogic.ROLE_MAILTIPS_ID1] = os.time()
	end
	
	local curTime = os.time()
	local daySec = 3600 * 24;
	if curTime - human.db.mailtips[RoleSystemLogic.ROLE_MAILTIPS_ID1] < daySec then
		return
	end
	human.db.mailtips[RoleSystemLogic.ROLE_MAILTIPS_ID1] = curTime

	if not isOpen(human) then return end
end


--------------------------------------------------------------------------------------
--加入跨服试炼队列
--检测是否有竞技场阵容
--加入数据推送至中心服 [g->m]
function onJjcPos(human)	
	local heroList, helpList, rolebase , formation, elfList = CombatLogic.getHumanObjList(human, CombatDefine.COMBAT_TYPE3)
	if not heroList or not next(heroList) then return end -- 没有上阵
	
	local drillObj = DrillDB.createDrillObj(human)
	if not drillObj then return end

	DrillDB.updateDrillObj(drillObj)
end

--请求关卡记录

------------ 匹配规则 -----------------------
function getDifficulty(quJian, diff,config)
	local str1 = ""
	local str2 = ""

	local stradd = ""
	if quJian == 2 then
		stradd = "1"
	end
	if diff == DIFF_NORMAL then
		str1 = "zdlMin"
		str2 = "zdlMax"
	elseif diff == DIFF_ELITE then
		str1 = "zdlMinElite"
		str2 = "zdlMaxElite"
	elseif diff ==  DIFF_INCUBI then
		str1 = "zdlMinIncubi"
		str2 = "zdlMaxIncubi"
	end

	if stradd == "" then
		return config[str1],  config[str2]
	else
		return config[str1..stradd],  config[str2..stradd]
	end
end

function getZhanLiByNpc(zhandouli)
	local DrillNpcExcel = DrillExcel.npc
    local maxCnt = #DrillNpcExcel
    if DrillNpcExcel[maxCnt].zhandouli[2] < zhandouli then
        return DrillNpcExcel[maxCnt].zhandouli[1], DrillNpcExcel[maxCnt].zhandouli[2]
    end
    
	for k, config in ipairs(DrillExcel.npc) do
		if config.zhandouli[1] <= zhandouli and config.zhandouli[2] >=  zhandouli then
			return config.zhandouli[1], config.zhandouli[2]
		end
	end 
	return  DrillExcel.npc[1].zhandouli[1], DrillExcel.npc[1].zhandouli[2]
end

function findRandomObj(zdlMin, zdlMax, notTab, isRobot)
	local drillObj = DrillDB.randomDrillObj(zdlMin, zdlMax, notTab, isRobot)
	return drillObj
end

-- 请求关卡
function pipei(human, drillId, diff, zhandouli, notTab)	
	local drillCfg = DrillExcel.drill[drillId]
	if not drillCfg then return end
	local minPer, maxPer = getDifficulty(1, diff, drillCfg)
	local zdlMin = math.ceil(minPer / 10000 * zhandouli)
	local zdlMax = math.ceil(maxPer / 10000 * zhandouli)	
	local drillObj 	
	if (diff == DIFF_NORMAL and drillId <= 10) or 
	    (diff == DIFF_ELITE and drillId <= 8) or 
		 (diff == DIFF_INCUBI and drillId <= 6) then
		drillObj = findRandomObj(zdlMin, zdlMax, notTab, true)
		if not drillObj then	
			minPer, maxPer = getDifficulty(2, diff, drillCfg)
			zdlMin = math.ceil(minPer / 10000 * zhandouli)
			zdlMax = math.ceil(maxPer / 10000 * zhandouli)
			if zdlMin <= DrillExcel.npc[1].zhandouli[2] then 
				zdlMin = DrillExcel.npc[1].zhandouli[1]
				zdlMax = DrillExcel.npc[1].zhandouli[2]
			end
			drillObj = findRandomObj(zdlMin, zdlMax, notTab, true)
			if not drillObj then
				zdlMin,zdlMax =  getZhanLiByNpc(zhandouli)
				drillObj = findRandomObj(zdlMin, zdlMax, notTab, true)
			end
		end
	else
		drillObj = findRandomObj(zdlMin, zdlMax, notTab)
		if not drillObj then	
			minPer, maxPer = getDifficulty(2, diff, drillCfg)
			zdlMin = math.ceil(minPer / 10000 * zhandouli)
			zdlMax = math.ceil(maxPer / 10000 * zhandouli)
			drillObj = findRandomObj(zdlMin, zdlMax, notTab)
			if not drillObj then
				minPer = minPer - 500
				maxPer = maxPer + 500
				zdlMin = math.ceil(minPer / 10000 * zhandouli)
	    		zdlMax = math.ceil(maxPer / 10000 * zhandouli)		
				drillObj = findRandomObj(zdlMin, zdlMax, notTab)
				if not drillObj then
					if zdlMin <= DrillExcel.npc[1].zhandouli[2] then 
						zdlMin = DrillExcel.npc[1].zhandouli[1]
						zdlMax = DrillExcel.npc[1].zhandouli[2]
					end
					drillObj = findRandomObj(zdlMin, zdlMax, notTab, true)		
					if not drillObj then
						zdlMin = zhandouli - 50001
						zdlMax = zhandouli + 50001
						zdlMin = zdlMin > DrillExcel.npc[1].zhandouli[1] and zdlMin or DrillExcel.npc[1].zhandouli[1]
						zdlMax = zdlMax > DrillExcel.npc[1].zhandouli[2] and zdlMax or DrillExcel.npc[1].zhandouli[2]
						local maxID = #DrillExcel.npc
						zdlMin = zdlMin < DrillExcel.npc[maxID].zhandouli[1] and zdlMin or DrillExcel.npc[maxID].zhandouli[1]
						zdlMax = zdlMax < DrillExcel.npc[maxID].zhandouli[2] and zdlMax or DrillExcel.npc[maxID].zhandouli[2]
						drillObj = findRandomObj(zdlMin, zdlMax, notTab, true)		
					end
				end
			end
		end
	end

	if not drillObj then
		return Broadcast.sendErr(human, Lang.DRILL_NOT_FING_DRILL)
    end
	return drillObj
end

-----------------------------------------------------------  

--计算战力区间

function fristQust(human, drillId)
	local drill = human.db.drill 
	if not drill then return end
	local diff = drill.diff
	local dirllDefConfig = DrillExcel.define[drill.diff] 
	if not dirllDefConfig then return end
	local drillData = DrillDB.getDrillDataByUuid(human.db._id)
	if drillData then return end
	drillId = drillId and drillId or 1
	if drillId > dirllDefConfig.maxDrillID then return end
	local zhandouli = CombatPosLogic.getCombatHeroZDL(human, CombatDefine.COMBAT_TYPE1)
	if zhandouli <= 0 then
		drill.diff = 0
		return Broadcast.sendErr(human, Lang.COMBAT_ERR_NO_SET_FIGHT)  
	end
	local notTab = {}
	if human.maxZDL and human.maxZDL.zhandouli and human.maxZDL.zhandouli > zhandouli then 
		-- 获取玩家真正的最高战力   防止玩家 战役上阵 战力低 去匹配 低战力对手
		zhandouli = human.maxZDL.zhandouli
	end
	local drillObj = pipei(human, drillId, diff, zhandouli, notTab)
	if not drillObj then return end

	local drillData = DrillDB.createDrillData(human, drillId)	
	drillData.diff = diff
	drillData.drillObjs[drillId] = Util.copyTable(drillObj)
	DrillDB.updateDrillData(drillData)
	queryDrillId(human, drillData)
end

function quest(human, drillId)
	local drill = human.db.drill 
	if not drill then return end
	local diff = drill.diff
	local dirllDefConfig = DrillExcel.define[drill.diff] 
	if not dirllDefConfig then return end
	local drillData = DrillDB.getDrillDataByUuid(human.db._id)
	if not drillData then
		fristQust(human, drillId)
		return
	end
	if drillId > dirllDefConfig.maxDrillID then return end
	local notTab = {}
	notTab[#notTab + 1] = human.db._id
	if drillData then
		for i = 1, dirllDefConfig.maxDrillID do
			local drillObj = drillData.drillObjs[i]
			if drillObj then
				notTab[#notTab + 1] = drillObj._id or drillObj.uuid
			end
		end
	end
	local zhandouli = CombatPosLogic.getCombatHeroZDL(human, CombatDefine.COMBAT_TYPE1)
	if zhandouli <= 0 then return Broadcast.sendErr(human, Lang.COMBAT_ERR_NO_SET_FIGHT)  end
	if human.maxZDL and human.maxZDL.zhandouli and human.maxZDL.zhandouli > zhandouli then 
		-- 获取玩家真正的最高战力   防止玩家 战役上阵 战力低 去匹配 低战力对手
		zhandouli = human.maxZDL.zhandouli
	end
	local drillObj = pipei(human, drillId, diff, zhandouli, notTab)

	drillData.drillObjs[drillId] = Util.copyTable(drillObj)
	DrillDB.updateDrillData(drillData)
--	queryDrillId(human, drillData)
end

--	myHelpIndex =    1,     -- 我选择的援助出去英雄
--  helpoutList = {},       -- 我选择的援助英雄

-- 选择自己的 出战 英雄
function dispatchMyHelpHero(human, index)
	local drill = human.db.drill
	if not drill then return end

	local drillData = DrillDB.getDrillDataByUuid(human.db._id)
	if not drillData then return end
--	if drillData.helpInfo then
--		return Broadcast.sendErr(human, Lang.DRILL_CHOOSE_MY_ERR_HAD)
--	end

	-- 当日已经派遣过
	if drill.myHelpIndex and drill.myHelpIndex > 0 then
		return Broadcast.sendErr(human, Lang.DRILL_CHOOSE_MY_ERR_HAD)
	end
	
	local heroGrid = human.db.heroBag[index]
	if type(heroGrid) ~= "table" then
		return Broadcast.sendErr(human, Lang.DRILL_CHOOSE_MY_ERR_INDEX)
	end	

	local combatObj = CombatLogic.createHumanObj(human, heroGrid.uuid)
	local rolebase = CombatLogic.createRoleBaseByDB(human.db)
	if not combatObj or not rolebase then
		return Broadcast.sendErr(human, Lang.DRILL_CHOOSE_MY_ERR_INDEX)
	end	

	combatObj.bagIndex = nil
	combatObj.friendUuid  = human.db._id
	local helpInfo = {}
	helpInfo.heroGrid = heroGrid
	helpInfo.combatObj = combatObj
	helpInfo.rolebase = rolebase
	drillData.helpInfo = helpInfo
	drill.myHelpIndex = index

	DrillDB.updateDrillData(drillData)

	local heroID = heroGrid.id
	local heroConfig = HeroExcel.hero[heroID]
    if 	heroConfig == nil then return end


	drill.myHelpIndex = index
	drill.myHelpHero = helpInfo
	helpHeroFriendQuery(human)
	RoleSystemLogic.onDot(human, RoleSystemDefine.ROLE_SYS_ID_1204)
    RoleSystemLogic.onDot(human, RoleSystemDefine.ROLE_SYS_ID_1201)
end

-- 获取最大血量
function getCombatObjHpMax(obj)
	if obj.hpMax then return obj.hpMax end
	local hpMax = obj.attrs[RoleDefine.HP]
	hpMax = math.ceil(hpMax * (1 + obj.attrs[RoleDefine.HP_RATE]/10000))
	return hpMax
end

-- 封装助战结构体
function fontHelpNet(net, targetUuid)
	local tDrillData = DrillDB.getDrillDataByUuid(targetUuid)
	if not tDrillData then return end
	local tHelpInfo = tDrillData.helpInfo
	if not tHelpInfo then return end

	net.uuid = targetUuid
	net.name = tHelpInfo.rolebase.name 
	net.state = 0
	net.pos = 0
	HeroGrid.makeHeroSimple(net.heroSimple, tHelpInfo.heroGrid)
	return true
end

local helpHeroFields =  {lv = 1, name = 1, head = 1, technology=1, heroBag = 1, combatHero = 1, drill = 1}
function helpHeroFriendQuery(human)
	local drill = human.db.drill
	if not drill then return end
	local drillData = DrillDB.getDrillDataByUuid(human.db._id)
	if not drillData then return end
	
	local now = os.time()
	local msgRet = Msg.gc.GC_DRILL_FRIEND_HELP_QUERY
	msgRet.myHelpIndex = drill.myHelpIndex and drill.myHelpIndex or 0
	msgRet.ownChose[0] = 0
	msgRet.herolist[0] = 0

	local len = 0
	-- 我已经选择了 部分 援助英雄
	if drill.helpoutList then
		for uuid, v in pairs(drill.helpoutList) do
			local net = msgRet.ownChose[msgRet.ownChose[0] + 1] 
			if fontHelpNet(net, uuid, true) then
				msgRet.ownChose[0] = msgRet.ownChose[0] + 1
			end
		end
	end

	-- 玩家最多选择 三位好友援助英雄
	if len < 3 then
		len = 0
		local cnt, list = FriendDBLogic.getFriendUuids(human.db._id)
		for i = 1, cnt do
			local targetUuid = list[i].uuid
			if not drill.helpoutList or not drill.helpoutList[targetUuid] then
				if msgRet.herolist[0] >= #msgRet.herolist then
					break
				end	
				local net = msgRet.herolist[msgRet.herolist[0] + 1] 
				if fontHelpNet(net, targetUuid) then
					msgRet.herolist[0] = msgRet.herolist[0] + 1
				end			
			end			
		end
	end
	
--	Msg.trace(msgRet)
	Msg.send(msgRet, human.fd)
end

-- 选择支援我的好友助战
local HELP_MAIL_ITEMS = {{}}
function choseHelpFriendHero(human, uuid)
	if not uuid or  uuid == "" then
		return 
	end
	local drill = human.db.drill
	if not drill then return end

	local drillData = DrillDB.getDrillDataByUuid(human.db._id)
	if not drillData then return end

	-- 今天 已经选择该玩家英雄援助了
	if drill.helpoutList and drill.helpoutList[uuid] then
		return
	end
	if not FriendDBLogic.isFriend(human.db._id, uuid) then
		return 
	end

	if drill.helpoutList then
		local len = 0
		for k, _ in pairs(drill.helpoutList) do
			len = len + 1
		end

		if len >= 3 then
			return
		end
	end

	local friendHuman 
	friendHuman = ObjHuman.onlineUuid[uuid]

	if not friendHuman then
		local db = RoleDBLogic.getDb(uuid, helpHeroFields)
		if db then
			friendHuman = {db = db}
		end		
	end

	local drillFriend = friendHuman.db.drill

	if not drillFriend or not drillFriend.myHelpHero then
		return
	end

	-- 检查这个数据是否是当天设置的
	if not Util.isSameDay(drillFriend.time) then
		return
	end

	local tDrillData = DrillDB.getDrillDataByUuid(uuid)
	local helpInfo = tDrillData and tDrillData.helpInfo
	if not helpInfo then
		return Broadcast.sendErr(human, Lang.DRILL_CHOOSE_FRIEND_ERR_INFO)
	end

	local maxZhandouli = HeroLogic.getHeroMaxZDL(human)
	if helpInfo.heroGrid.zhandouli > maxZhandouli * MAX_HEROCOMBAT_MUL / 100 then
		return Broadcast.sendErr(human, Util.format(Lang.LIANYU_MY_SELECT_ERR_ZDL, MAX_HEROCOMBAT_MUL))
	end

	drill.helpoutList = drill.helpoutList or {}
	drill.helpoutList[uuid] = {}
	drill.helpoutList[uuid].time = os.time()

	DrillLogicAttribute.setHelp(drillData ,uuid)
	DrillDB.updateDrillData(drillData)
	-- 给好友发送雇佣奖励
	HELP_MAIL_ITEMS[1][1] = ItemDefine.ITEM_FRIEND_ID
	HELP_MAIL_ITEMS[1][2] = FRIEND_ITEM_CNT

	local mailConfig = MailExcel.mail[MailDefine.MAIL_ID_DRILL_HELP]
	local title = mailConfig.title
	local senderName = mailConfig.senderName
	local content = Util.format(mailConfig.content, human.db.name)
	MailManager.add(MailManager.SYSTEM, uuid, title, content, HELP_MAIL_ITEMS, senderName)	
	helpHeroFriendQuery(human)
	RoleSystemLogic.onDot(human, RoleSystemDefine.ROLE_SYS_ID_1204)
    RoleSystemLogic.onDot(human, RoleSystemDefine.ROLE_SYS_ID_1201)
end

function curFuhuoCnt(human, drillData)
	local maxCnt = VipLogic.getPowerArgs(human, VipLogic.VIP_POWER5) 
	
	local oldCnt = DrillLogicAttribute.getOperCnt(drillData, DrillLogicAttribute.DRILL_OPER_1)
	local curCnt = maxCnt - oldCnt
	curCnt = curCnt > 0 and curCnt or 0
	return maxCnt, curCnt
end

function getResetNeedZuanshi(drillData, maxCnt)

	local oldCnt = DrillLogicAttribute.getOperCnt(drillData, DrillLogicAttribute.DRILL_OPER_1)
	if oldCnt >= maxCnt then
		return 0
	end

	local operConfig = DrillExcel.oper[oldCnt + 1]		
	return operConfig.zuanshi
end

function fuhuoQuery(human)
	local drillData = DrillDB.getDrillDataByUuid(human.db._id)
	if not drillData then return end

	local msgRet = Msg.gc.GC_DRILL_FUHUO_QUERY
	msgRet.maxCnt, msgRet.canCnt  = curFuhuoCnt(human, drillData) 
	msgRet.needZuanshi = getResetNeedZuanshi(drillData, msgRet.maxCnt)
	Msg.send(msgRet, human.fd)
end


function getHelpHeroState(human, args)
	local choseUuid = args[1]
	local drill = human.db.drill
	if not drill then return false end
	
	if drill.helpoutList and drill.helpoutList[choseUuid] then
		local hero = drill.helpoutList[choseUuid]
		-- 挑战胜利过的  不能作为出战英雄
		if hero.winCnt and hero.winCnt > 0 then return false end

		local hp = hero.helpObj.attrs[RoleDefine.HP]
		if hp <= 0 then return false end
		return true, hero.heroObj
	end
	return false
end

-- 助战英雄上阵
function setHelpCombatPos(human, uuid, pos)
	if not isOpen(human, true) then return end
	local drill = human.db.drill
	if not drill then return false end
	local drillData = DrillDB.getDrillDataByUuid(human.db._id)
	if not drillData then return end
	if drill.helpoutList and drill.helpoutList[uuid] then
		human.drill = human.drill or {}
		human.drill.combatHelpUuid = uuid
		human.drill.combatHelpPos = pos
	end	
end
 
-- 防御方数据
function getDefender(drillObj)
	local objList = {}
	for index, obj in pairs(drillObj.heroList) do
		if DrillLogicAttribute.getObjHpRate(drillObj, obj.bagIndex) > 0 and index ~= CombatDefine.BACKUP_POS[1] then -- 剔除死亡的
			objList[index] = obj
		end
	end	
	local roleBase = {}
	RoleLogic.makeRoleBase(drillObj, roleBase)
	return objList, drillObj.helpList,  roleBase, drillObj.formation, drillObj.jiban, drillObj.elfList
end

-- 攻击方数据
function getAttacker(human, drillData, pos2uuidAtk)
	local drill = human.db.drill
	if not drill then return end

	local objList, helpList, rolebase, formation, jiban, elfList = CombatLogic.getHumanObjList(human, CombatDefine.COMBAT_TYPE9)
	for pos, obj in pairs(objList) do
		local heroGrid = human.db.heroBag[obj.bagIndex] 
		if heroGrid then
			pos2uuidAtk[pos] = heroGrid.uuid
		end
	end
	-- 助战英雄
	local combatHelpUuid = human.drill and human.drill.combatHelpUuid
	local combatHelpPos = human.drill and human.drill.combatHelpPos
	if combatHelpUuid and combatHelpPos then
		
		if drill.helpoutList and drill.helpoutList[combatHelpUuid] then
			local tDrillData = DrillDB.getDrillDataByUuid(combatHelpUuid)
			local combatHelp = tDrillData and tDrillData.helpInfo
			if combatHelp and DrillLogicAttribute.getHelpHpRate(drillData, combatHelpUuid) > 0 and 
				CombatPosLogic.checkPos(formation, combatHelpPos) then
				objList[combatHelpPos] = combatHelp.combatObj
				pos2uuidAtk[combatHelpPos] = combatHelpUuid
			end
		end		
	end
	return objList, helpList, rolebase, formation, jiban, elfList
end

-------------------------------------- combat -----------------------------------------
-- 判断是否合适上阵
local function isFixCombatPos(heroGrid, drillData, config)
	if type(heroGrid) ~= "table" then return end
	if not drillData then return end
	if config and config.heroMinLevel and heroGrid.lv < config.heroMinLevel then return end -- 等级不满足
	local hpRate = DrillLogicAttribute.getHeroHpRate(drillData, heroGrid.uuid)
	if hpRate <= 0 then return end -- 死掉了
	return true
end

-- 不合适的下阵
function updateCombatPosCheck(human, drillData)
	local combatHero = CombatPosLogic.getCombatHeros(human, CombatDefine.COMBAT_TYPE9)
	if not combatHero then return end
	
	local drillDB = human.db.drill
	local config = DrillExcel.define[drillData.diff]
	for pos, uuid in pairs(combatHero) do
		local heroGrid = HeroLogic.getHeroGridByUuid(human, uuid)
		if heroGrid and not isFixCombatPos(heroGrid, drillData, config) then
			combatHero[pos] = nil
		end
	end
end

-- 战斗前加属性
function onFightBegin(human, cbParam)
	for index = 1, CombatDefine.COMBAT_HERO_ALL_CNT do
		local obj = CombatImpl.objList[index]
		if obj then
			if index <= CombatDefine.COMBAT_HERO_CNT then
				calcAttrAtk(human, index, obj,cbParam )
			else
				calcAttrDef(human, index, obj, cbParam)
			end
		end		
    end
end

function getHelpGrid(human, uuid)
	local drill = human.db.drill
	if drill.helpoutList and drill.helpoutList[uuid] then
		return  drill.helpoutList[uuid].heroGrid
	end
end

-- 所有属性计算完毕，重新设置血量(攻击)
function calcAttrAtk(human, pos, obj, cbParam)
	local uuid = cbParam.pos2uuidAtk[pos]
	if not uuid then return end

	local hpRate = nil
	if (obj.bagIndex or 0) > 0 then
		hpRate = DrillLogicAttribute.getHeroHpRate(cbParam.drillData, uuid)	
	else
		hpRate = DrillLogicAttribute.getHelpHpRate(cbParam.drillData, uuid)		
	end
	local hpMax = CombatObj.getHpMax(obj)
	obj.hp = math.ceil(hpRate * hpMax)
end  

-- 所有属性计算完毕，重新设置血量(防守)
function calcAttrDef(human, pos, obj, cbParam)
	local hpRate = DrillLogicAttribute.getObjHpRate(cbParam.drillObj, obj.bagIndex)
	local hpMax = CombatObj.getHpMax(obj)
	obj.hp = math.ceil(hpRate * hpMax)
end

-- 战斗
function fight(human, args)
    if not isOpen(human, true) then return end
	if human.db.combatQuick and human.db.combatQuick[CombatDefine.COMBAT_TYPE9] and human.db.combatQuick[CombatDefine.COMBAT_TYPE9] == 1 then 
		local combatHero = CombatPosLogic.getCombatHeros(human, CombatDefine.COMBAT_TYPE9 )
		if CombatLogic.isCombatHeroEmpty(combatHero) then
			queryDrillId(human)
			return Broadcast.sendErr(human, Lang.DRILL_NOT_FIGHT_NOT_HERO) 
		end
	end

	local drill = human.db.drill
	if not drill then return false end

	local drillDB = human.db.drill
	local drillData = DrillDB.getDrillDataByUuid(human.db._id)
	if not drillData then 
		return Broadcast.sendErr(human, Lang.DRILL_IS_FINSH)
	end

	local drillId = tonumber(args[1] or 0)
	if  drillId ~= drillData.drillId then
		return 
	end

    local config = DrillExcel.drill[drillId]
    if not config then return end
	
	local drillObj = drillData.drillObjs[drillId]
	if not drillObj then return end -- 不存在。。	

	updateCombatPosCheck(human, drillData)
	local args = {}
	local pos2uuidAtk = {}
	args.defender, args.defHelp, args.defRBase, args.defFormation, args.defJiban, args.defElfList = getDefender(drillObj)
	args.attacker, args.atkHelp, args.atkRBase, args.atkFormation, args.atkJiban, args.atkElfList = getAttacker(human, drillData, pos2uuidAtk)
    args.drillId = drillData.drillId
 

	local cbParam = {}
	cbParam.pos2uuidAtk = pos2uuidAtk
	cbParam.diff = drillData.diff
	cbParam.drillId = drillData.drillId
	cbParam.drillData = drillData
	cbParam.drillObj = drillObj
	cbParam.combatHelpPos = human.drill and human.drill.combatHelpPos
	cbParam.combatHelpUuid = human.drill and human.drill.combatHelpUuid
	CombatLogic.combatBegin(human, config.mapID, args, CombatDefine.COMBAT_TYPE9, cbParam)
end


-- 获取当前地图ID
function getMapID(human, args)
	local drillDB = human.db.drill
	local drillData = DrillDB.getDrillDataByUuid(human.db._id)
	local drillId = tonumber(args[1] or args.drillId or 0)
	if  drillId ~= drillData.drillId then
	   return 
	end
    local config = DrillExcel.drill[drillId]
    if not config then return end
    return config.mapID
end

-- 刷新drillData记录的血量
function combatOnUpdate(human, cbParam, combatInfo)
	for index = 1, CombatDefine.COMBAT_HERO_CNT do
        -- 更新攻击方血量
        local atkPos = CombatLogic.getPos(CombatDefine.ATTACK_SIDE, index)
		local atkObj = combatInfo.objList[atkPos]
		if atkObj ~= nil then
			local hp = atkObj.hp
			local hpMax = CombatObj.getHpMax(atkObj)
			local hpRate = hp / hpMax
			local uuid = cbParam.pos2uuidAtk[index]
			if (atkObj.bagIndex or 0) > 0 then
				DrillLogicAttribute.setHeroHpRate(cbParam.drillData, uuid, hpRate)	
			else
				DrillLogicAttribute.setHelpHpRate(cbParam.drillData, uuid, hpRate)
			end        	
        end		
        -- 更新防守方血量
        local defPos = CombatLogic.getPos(CombatDefine.DEFEND_SIDE, index)
        local defObj = combatInfo.objList[defPos]
        if defObj ~= nil then
        	local hp = defObj.hp
			local hpMax = CombatObj.getHpMax(defObj)
			local hpRate = hp / hpMax
			DrillLogicAttribute.setObjHpRate(cbParam.drillObj, defObj.bagIndex, hpRate)
        end
	end  
	updateCombatPosCheck(human, cbParam.drillData) 
end

-- 战胜回调
function onFightWinCallback(human, result , diff,drillID)
	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,drillID)

	RoleSystemLogic.onDot(human, RoleSystemDefine.ROLE_SYS_ID_1204)
    RoleSystemLogic.onDot(human, RoleSystemDefine.ROLE_SYS_ID_1201)
end

-- 援助英雄 添加胜利
function addHelpWin(human, drillData)
	if 	human.drill and human.drill.combatHelpUuid then
		DrillLogicAttribute.setHelpWin(drillData, human.drill.combatHelpUuid)
	end
end

-- 通关回调
function tongGuan(human, diff)
	if getMaxDiff(human) < diff then
		setMaxDiff(human, diff)
	end
end

-- 战斗结束
function onFightEnd(human, result, combatType, cbParam, combatInfo)

	local isOtherDay = false 
	if not Util.isSameDay(combatInfo.time) then
		isOtherDay = true
	end
	local drillDB = human.db.drill
	if not drillDB then return end
	combatOnUpdate(human, cbParam, combatInfo)	
	local drillData = cbParam.drillData

	
	local isKill = true

	if not isObjKill(cbParam.drillObj) then -- 未击杀对面
		isKill = false
	end
	
	local diff = cbParam.diff or drillData.diff
	if not isOtherDay then
		if not isKill then
			return DrillDB.updateDrillData(drillData)
		end
			-- 刷新最大通关难度
	
		local dirllDefConfig = DrillExcel.define[diff] 

		if cbParam.drillId >= dirllDefConfig.maxDrillID  then 
			tongGuan(human, diff)  
			ChengjiuLogic.onCallback(human,ChengjiuDefine.CJ_TASK_TYPE_17,1)
			HeroLogLogic.finishTaskCB(human,HeroLogLogic.HERO_LOG_TYPE_5,1)
		end
		drillData.drillId = drillData.drillId + 1
		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 
				drillDB.drillId = drillDB.drillId + 1
				drillData.drillId = drillData.drillId + 1
			end	
			
			addHelpWin(human, drillData)
			DrillDB.updateDrillData(drillData)
			quest(human, cbParam.drillId + 1)
		end]]
	else
		if not isKill then
			updateDaily(human)
			return
		end
	end
	local drillItems = getDrillItems(cbParam.drillId, diff)	
	local double = RoleSystemLogic.isDouble(human, RoleSystemDefine.ROLE_SYS_ID_1204)
	local rewardCnt = double and 2 or 1
	combatInfo.double = double and 2 or 0

	--秘宝加成
	local heroExpMul = getTalismanAdd(human)

	-- 关卡奖励		
	local itemList = {}
	for k, item in ipairs(drillItems) do
		local itemID = item[1]
		local itemCnt = item[2] * rewardCnt
		if itemID == ItemDefine.ITEM_GREEN_EXP_ID and heroExpMul > 0 then
			itemCnt = itemCnt + math.ceil(itemCnt * heroExpMul)
		end

		itemList[k] = {}
		itemList[k][1] =  itemID
		itemList[k][2] = itemCnt
		-- itemList[k][4] = sourceId

		BagLogic.addItem(human, itemID, itemCnt, "drill")
		if not isOtherDay then
			drillDB.dayGet = drillDB.dayGet or {}
			drillDB.dayGet[itemID] = (drillDB.dayGet[itemID] or 0) + itemCnt
		end
	end
	combatInfo.rewardItem = itemList
	human.drill = nil

	if isOtherDay then		
		updateDaily(human)
	end
	-- 回调
	onFightWinCallback(human,result, diff,cbParam.drillId)
    YunYingLogic.onCallBack(human, "onDrill",1)   
	--周任务 -8
	WeekTaskLogic.recordWeekTaskFinishCnt(human, WeekTaskLogic.WEEK_TASK_ID_8, 1)

	TriggerLogic.PublishEvent(TriggerDefine.DRILL_KILL_SHOUWEI, human.db._id, 1)
end

--[[
	-- 增加关卡
function questMid(fd, msg)
	local uuid = msg.uuid
	local drillId = msg.drillId
	local drillObj = msg.drillObj
	if not RoleDBLogic.isUuidExistInDB(uuid) then
		return
	end

	local drillData = DrillDB.getDrillDataByUuid(uuid)
	if not drillData then
	--	if drillId ~= 1 then return end -- 注意哦
		drillData = DrillDB.createDrillData(uuid)	
	else 
		if drillData.drillId ~= drillId then return end	
	end

	print("drillObj",drillObj._id,  drillId)
	drillData.drillObjs[drillId] = Util.copyTable(drillObj)
	DrillDB.updateDrillData(drillData)
	
	local human = ObjHuman.onlineUuid[uuid]
	if human == nil then return end	
	queryDrillId(human, drillData)
end  
]]


function isDot(human)
	local isOpen = RoleSystemLogic.isOpen(human, RoleSystemDefine.ROLE_SYS_ID_1204)
	if not isOpen then return false end

	if not human.db.drill then
		return true
	end

	for k, _  in ipairs(DrillExcel.box) do
		if  getBoxState(human.db.drill,  k) == DRILL_BOX_STATE_1 then
			return true
		end
	end

	if human.db.drill.myHelpIndex and human.db.drill.myHelpIndex > 0 then
		return false
	end

	return  true
end

function getQuick(human)
	if getMaxDiff(human) > 0 then
		return 1
	end
	return 0
end

-- 通关消耗钻石来通关当前关卡
function ChallengeLevelByDiamond(human, levelId)
	local drill = human.db.drill
	if not drill then
		return Broadcast.sendErr(human, Lang.COMMOM_NOT_ENABLED)
	end

	local drillDB = human.db.drill
	local drillData = DrillDB.getDrillDataByUuid(human.db._id)
	if not drillData then
		return Broadcast.sendErr(human, Lang.DRILL_IS_FINSH)
	end

	if levelId ~= drillData.drillId then
		return Broadcast.sendErr(human, Lang.COMMON_ARGUMENT_ERROR)
	end


    local config = DrillExcel.drill[levelId]
    if not config then
		return Broadcast.sendErr(human, Lang.COMMON_COMFIG_ERROR)
	end


	local drillObj = drillData.drillObjs[levelId]
	if not drillObj then
		return	Broadcast.sendErr(human, Lang.COMMON_COMFIG_ERROR)
	end


	if BagLogic.getItemCnt(human, ItemDefine.ITEM_ZUANSHI_ID) < CHALLENGE_DIAMONS then
        return Broadcast.sendErr(human, Lang.COMMON_NO_ZUANSHI)
    end
	BagLogic.delItem(human, ItemDefine.ITEM_ZUANSHI_ID, CHALLENGE_DIAMONS, "drill")


	local oldDrillID = drillData.drillId
	local isOtherDay = false
	local diff = drillData.diff
	local dirllDefConfig = DrillExcel.define[diff]

	if drillData.drillId >= dirllDefConfig.maxDrillID then
		tongGuan(human, diff)
		ChengjiuLogic.onCallback(human,ChengjiuDefine.CJ_TASK_TYPE_17,1)
		HeroLogLogic.finishTaskCB(human,HeroLogLogic.HERO_LOG_TYPE_5,1)
	end

	drillData.drillId = drillData.drillId + 1
	drillDB.drillId = drillData.drillId
	-- addHelpWin(human, drillData)
	DrillDB.updateDrillData(drillData)
	-- 手动通关后清除扫荡完成标记，允许再次扫荡
	if drillDB then
		drillDB.oneClickSaodangDone = nil
	end
	quest(human, oldDrillID + 1)


	local drillItems = getDrillItems(oldDrillID, diff)	
	local double = RoleSystemLogic.isDouble(human, RoleSystemDefine.ROLE_SYS_ID_1204)
	local rewardCnt = double and 2 or 1

	--秘宝加成
	local heroExpMul = getTalismanAdd(human)

	-- 关卡奖励		
	local itemArray = {}
	for k, item in ipairs(drillItems) do
		local itemID = item[1]
		local itemCnt = item[2] * rewardCnt
		if itemID == ItemDefine.ITEM_GREEN_EXP_ID and heroExpMul > 0 then
			itemCnt = itemCnt + math.ceil(itemCnt * heroExpMul)
		end

		itemArray[k] = {itemID, itemCnt}
		-- BagLogic.addItem(human, itemID, itemCnt, "drill")
		if not isOtherDay then
			drillDB.dayGet = drillDB.dayGet or {}
			drillDB.dayGet[itemID] = (drillDB.dayGet[itemID] or 0) + itemCnt
		end
	end

	-- 回调
	onFightWinCallback(human,result, diff, oldDrillID)
    YunYingLogic.onCallBack(human, "onDrill",1)

	--周任务 -8
	WeekTaskLogic.recordWeekTaskFinishCnt(human, WeekTaskLogic.WEEK_TASK_ID_8, 1)

	TriggerLogic.PublishEvent(TriggerDefine.DRILL_KILL_SHOUWEI, human.db._id, 1)

	-- 更新数据
	queryDrillId(human)

	-- 发放奖励
	BagLogic.addItemList(human, itemArray, "drill")
end

-- 一键扫荡
function oneClickSaodang(human)
	-- Log.write(Log.LOGID_DEBUG, "[oneClickSaodang] 收到一键扫荡请求")
	
	-- 检查是否购买了基金（购买项207）
	if not human.db.overflow or not human.db.overflow.state or not human.db.overflow.state[OverflowFundLogic.OVERFLOW_TYPE_2] then
		--Log.write(Log.LOGID_DEBUG, "[oneClickSaodang] 未购买奢华基金（OVERFLOW_TYPE_2）")
		return
	end
	-- Log.write(Log.LOGID_DEBUG, "[oneClickSaodang] 已购买基金，继续执行")
	
	-- 检查是否开启了试炼
	if not isOpen(human, true) then
		-- Log.write(Log.LOGID_DEBUG, "[oneClickSaodang] 试炼未开启")
		return
	end
	-- Log.write(Log.LOGID_DEBUG, "[oneClickSaodang] 试炼已开启，继续执行")
	
	local drill = human.db.drill
	if not drill then
		-- Log.write(Log.LOGID_DEBUG, "[oneClickSaodang] drill为nil")
		return
	end
	
	local drillData = DrillDB.getDrillDataByUuid(human.db._id)
	if not drillData then
		-- Log.write(Log.LOGID_DEBUG, "[oneClickSaodang] drillData为nil")
		return
	end
	
	local diff = drill.diff
	if not drill.diff or drill.diff == 0 then
		diff = drillData.diff
	end
	
	if diff == 0 then
		-- Log.write(Log.LOGID_DEBUG, "[oneClickSaodang] diff="..diff.."，需要!=0")
		return
	end
	
	---- 获取当前关卡ID
	local currentDrillId = drillData.drillId or 1
	-- Log.write(Log.LOGID_DEBUG, "[oneClickSaodang] 当前关卡ID="..currentDrillId..", diff="..diff)
	
	-- 获取总关卡数
	local dirllDefConfig = DrillExcel.define[diff]
	if not dirllDefConfig then
		-- Log.write(Log.LOGID_DEBUG, "[oneClickSaodang] 难度配置不存在，diff="..diff)
		return
	end
	local maxDrillID = dirllDefConfig.maxDrillID
	
	-- 如果已经通关所有关卡（drillId > maxDrillID），不允许再次扫荡
	if currentDrillId > maxDrillID then
		-- Log.write(Log.LOGID_DEBUG, "[oneClickSaodang] 已通关所有关卡，不允许再次扫荡，currentDrillId="..currentDrillId..", maxDrillID="..maxDrillID)
		Broadcast.sendErr(human, "已通关所有关卡，无法再次扫荡")
		return
	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")
		return
	end
	
	-- 计算扫荡后的关卡ID
	-- 一键扫荡后应该全部通关（newDrillId = maxDrillID + 1）
	local newDrillId = maxDrillID + 1  -- 16表示已通关所有关卡
	-- Log.write(Log.LOGID_DEBUG, "[oneClickSaodang] 计算扫荡后关卡ID: 一键扫荡后全部通关, newDrillId="..newDrillId)
	
	-- 检查是否已经扫荡过：
	-- 由于 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)
	
	-- 双倍奖励
	local double = RoleSystemLogic.isDouble(human, RoleSystemDefine.ROLE_SYS_ID_1204)
	local rewardCnt = double and 2 or 1
	
	-- 秘宝加成
	local heroExpMul = getTalismanAdd(human)
	
	-- 初始化今日奖励
	drill.dayGet = drill.dayGet or {}
	
	-- 收集所有奖励到列表中
	local itemList = {}
	
	-- 遍历所有可扫荡的关卡，收集奖励
	for i = currentDrillId, maxSaodangId do
		local drillItems = getDrillItems(i, diff)
		if drillItems then
			for _, item in ipairs(drillItems) do
				local itemID = item[1]
				local itemCnt = item[2] * rewardCnt
				if itemID == ItemDefine.ITEM_GREEN_EXP_ID then
					itemCnt = itemCnt + math.ceil(itemCnt * heroExpMul)
				end
				
				-- 累加奖励到列表
				itemList[itemID] = (itemList[itemID] or 0) + itemCnt
				drill.dayGet[itemID] = (drill.dayGet[itemID] or 0) + itemCnt
			end
		end
	end
	
	-- 使用 addItemList 添加奖励，会自动显示奖励弹窗
	if next(itemList) then
		BagLogic.addItemList(human, itemList, "drill")
	end
	
	-- 发送奖励消息
	local msgRet = Msg.gc.GC_DRILL_ONE_CLICK_SAODANG
	msgRet.drillId = maxSaodangId
	msgRet.double = double and 1 or 0
	
	local len = 0
	local itemInfo = ""
	for k, v in pairs(drill.dayGet) do
		len = len + 1
		Grid.makeItem(msgRet.itemList[len], k, v)
		if len > 1 then itemInfo = itemInfo .. ", " end
		itemInfo = itemInfo .. "itemID="..k..", count="..v
	end
	msgRet.itemList[0] = len
	
	-- Log.write(Log.LOGID_DEBUG, "[oneClickSaodang] 发送协议数据: drillId="..msgRet.drillId..", double="..msgRet.double..", itemCount="..len..", items=["..itemInfo.."]")
	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.." (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
	
	-- 更新数据
	queryDrillId(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