local Msg = require("core.Msg")
local Util = require("common.Util")
local CombatObj = require("combat.CombatObj")
local CombatDefine = require("combat.CombatDefine")
local TargetMode = require("combat.TargetMode")
local Skill = require("combat.Skill")
local CombatBuff = require("combat.CombatBuff")
local RoleAttr = require("role.RoleAttr")
local RoleDefine = require("role.RoleDefine")
local BeSkill = require("combat.BeSkill")
local HeroExcel = require("excel.hero").hero
local MonsterExcel = require("excel.monster").monster
local BattleMonsterExcel = require("excel.battlemonster").monster
local BattleMonsterExcel2 = require("excel.battlemonster2").monster
local CombatExcel = require("excel.combat").combat
local SkillExcel = require("excel.skill").skill
-- local BufferExcel = require("excel.buffer").buffer
-- local ProjectLogic = require("platform.ProjectLogic")

objList 		= objList or {}
helpList		= helpList or {}
elfList			= elfList or {}
attackOrder		= attackOrder or {}		-- 出手次序 [index]->pos
round 			= round or 1 			-- 当前回合
attackIndex 	= attackIndex or 1 		-- 当前进攻对象的index
result 			= result or {}			-- 计算结果
sideAttrList 	= sideAttrList or {} 	-- 攻守双方人物属性
skillUseList	= skillUseList or {}	-- 使用过的技能
cmdUseList		= cmdUseList or {}		-- 使用过的额外作用setFightMode
bufferUseList	= bufferUseList or {}	-- 使用过的buffer
frameSkillList	= frameSkillList or {}	-- 当前小回合触发的被动技能
frameBufferList = frameBufferList or {}	-- 当前小回合触发的buffer
mergeFrameBufferList = mergeFrameBufferList or {} --合并后的buffer
frameSayList	= frameSayList or {}	-- 触发buffer的被动技能（需要喊话
frameReviceList = frameReviceList or {} -- 复活列表
frameReviceList2 = frameReviceList2 or {} -- 复活列表2
fanjiList		= fanjiList or {}
beSkillUseList	= beSkillUseList or {}		-- 需要判断使用情况的技能
isFanji			= false
comboType       = 0
isPVP           = 0
comboHurtRate   = 0
--[[
	commonArgs = {
		type -- 战斗类型
		hpLimit -- 血量上限，默认为角色HP，对应特定关卡
	}
]]
commonArgs		= commonArgs or {}
comboList       = comboList or {}
beSkillPosUseList = beSkillPosUseList or {}	--友军技能使用列表
totalAtkCnt		= 0 -- 总共攻击次数 reyes test
maxRound		= CombatDefine.COMBAT_ROUND_MAX
petCD			= CombatDefine.PET_CD
nowAttacker		= nowAttacker or nil
firstAttack		= {}
fightMode       = {0,0,0,0}
initBackup		= {0,0}
comboPosList	= {}
totalHurt		 = 0
useZhuijiObjList = {} --本场战斗使用过追击的英雄列表
heroSpeedList = { -- 对战双方第一回合所有英雄的速度值列表
	--[CombatDefine.ATTACK_SIDE] = {},
	--[CombatDefine.DEFEND_SIDE] = {},
} 


function init(type)
	Util.initTable(objList)
	Util.initTable(helpList)
	Util.initTable(elfList)
	Util.initTable(attackOrder)
	Util.initTable(result)
	Util.initTable(skillUseList)
	Util.initTable(cmdUseList)
	Util.initTable(bufferUseList)
	Util.initTable(frameSkillList)
	Util.initTable(frameBufferList)
	Util.initTable(frameSayList)
	Util.initTable(fanjiList)
	Util.initTable(beSkillUseList)
	Util.initTable(beSkillPosUseList)
	Util.initTable(commonArgs)
	Util.initTable(comboList)
	Util.initTable(initBackup)
    Util.initTable(frameReviceList)
	Util.initTable(frameReviceList2)
	Util.initTable(useZhuijiObjList)
	Util.initTable(heroSpeedList)
	round = 0
	attackIndex = nil
	isFanji = false
    comboType = 0
	totalAtkCnt = 0
	totalHurt		 = 0
	commonArgs.type = type
	maxRound		= CombatDefine.COMBAT_ROUND_MAX
	petCD			= CombatDefine.PET_CD
	nowAttacker		= nil
	local combatConfig = CombatExcel[type]
	if combatConfig and combatConfig.hpLimit == 1 then
		commonArgs.hpLimit = 1
	end
    isPVP = combatConfig.PVP
end

local function mergeFrameBuffer()
	Util.initTable(mergeFrameBufferList)
	mergeFrameBufferList = {[1] = {},[2] = {},[3] = {}}
	for k,v in ipairs(frameBufferList) do
		mergeFrameBufferList[v.op][v.id] = mergeFrameBufferList[v.op][v.id] or {}
		local obj = objList[v.pos]
		mergeFrameBufferList[v.op][v.id][v.pos] = mergeFrameBufferList[v.op][v.id][v.pos] or {id = v.id,cnt = 0,op = v.op,attrs = {},pos = v.pos,hpNow = obj.hp}
		local data = mergeFrameBufferList[v.op][v.id][v.pos]
		data.cnt = data.cnt + v.cnt
		if v.attrs then
			for k,v in pairs(v.attrs) do
				data.attrs[k] = data.attrs[k] or 0
				data.attrs[k] = data.attrs[k] + v
			end
		end

	end

	Util.initTable(frameBufferList)
	local len = 0
	for _,v in ipairs(mergeFrameBufferList) do
		for _,v1 in pairs(v) do
			for _,v2 in pairs(v1) do
				frameBufferList[#frameBufferList+1] = v2
			end
		end
	end
end

function setRoleAttr(side, attr)
	sideAttrList[side] = sideAttrList[side] or {}
	local sideAttr = sideAttrList[side]
	RoleAttr.initCombatAttr(sideAttr)
	if attr then
		for key, value in pairs(attr) do
			sideAttr[key] = value
		end
	end
end

function getValue(obj, key)
	if not obj then return 0 end
	if not obj.attr then return obj.pos end
	return obj.attr[key] or obj.pos
end

function setData(pos, hero)
	local obj = CombatObj.objs[pos]
	CombatObj.init(obj)
	--加入背包索引
	obj.bagIndex = hero.bagIndex or 0
    obj.uuid = hero.uuid
	obj.id = hero.id
	obj.job = hero.job
	obj.body = hero.body
	obj.head = hero.head
	obj.quality = hero.quality
	obj.star = hero.star
	obj.type = hero.type
	obj.lv = hero.lv
    obj.isGedangCnt = 0
    obj.camp = hero.camp
    obj.sex = hero.sex or 0
	obj.relic = hero.relic or {}
	obj.relic.relicID = hero.relic and hero.relic.relicID or 0
	obj.relic.star = hero.relic and hero.relic.star or 0
	obj.skillList = hero.skillList or {}
	obj.formationPos = hero.formationPos
    if CombatDefine.isBackup(obj) == CombatDefine.BACKUP_TYPE0 then
	   obj.beSkillList = hero.beSkillList or {}
    else
       obj.beSkillList = {}
	   obj.backUpSkillList = hero.beSkillList or {}
    end
	obj.normalTarget = nil
	obj.isBoss = hero.isBoss -- 仅显示用
    obj.isGongMing = hero.isGongMing or 0
	CombatObj.setInitAttr(obj, hero.attrs)
	obj.isSysAttrChange = nil

	obj.weaponEffectIdList = hero.weaponEffectIdList

    if hero.type == CombatDefine.COMBAT_OBJ_TYPE1 then
       obj.hurtType = HeroExcel[obj.id].hurtType
    else
       obj.hurtType = MonsterExcel[obj.id] and MonsterExcel[obj.id].hurtType
	   if not obj.hurtType then
			if BattleMonsterExcel[obj.id] or BattleMonsterExcel2[obj.id] then
				-- obj.hurtType = BattleMonsterExcel[obj.id].hurtType or 0
				if BattleMonsterExcel[obj.id] then
					obj.hurtType = BattleMonsterExcel[obj.id].hurtType or 0
				else
					obj.hurtType = BattleMonsterExcel2[obj.id].hurtType or 0
				end
			else
				obj.hurtType = 0
			end
	   end
    end

    if pos == CombatDefine.BACKUP_POS[1] then
    	initBackup[1] = obj.backupPos
    elseif pos == CombatDefine.BACKUP_POS[2] then
    	initBackup[2] = obj.backupPos
    end

	objList[obj.pos] = obj
end

function setHelp(side,helpType,help)
	local pos = CombatDefine.getHelpPos(side,helpType)
	local obj = CombatObj.helps[pos]
	CombatObj.initHelp(obj)
	obj.id = help.id
	obj.lv = help.lv or 0
	obj.quality = help.quality or 0
	obj.head = help.head or 0
	obj.body = help.body or 0
    obj.icon = help.icon or 0
	obj.weight = help.weight or 0
	obj.height = help.height or 0
	obj.skillList = help.skillList or {}
	obj.beSkillList = help.beSkillList or {}
	obj.lvAttrsAdd = help.lvAttrsAdd or {}
	obj.zhuHun = help.zhuHun
	obj.jinglianLV = help.jinglianLV
	obj.skillLV = help.skillLV
	obj.hurt = help.hurt
	obj.args = help.args
	obj.buffers = help.buffers
	helpList[pos] = obj
end

function setElf(pos, elf)
	local elfObj = CombatObj.elfs[pos]
	CombatObj.initElf(elfObj)

	elfObj.id = elf.id
	elfObj.type = elf.type
	elfObj.body = elf.body or 0
	elfObj.head = elf.head or 0
	elfObj.quality = elf.quality or 1
	elfObj.skillList = elf.skillList or {}
	elfObj.beSkillList = elf.beSkillList or {}
	elfList[pos] = elfObj
end


function setMaxRound(value)
	maxRound = value
end

function setFightMode(data)
	for k in pairs(fightMode) do
		fightMode[k] = 0
	end
	if data then
        if data[1] == CombatDefine.FIGHT_MODE1 then
		   fightMode = {data[1], data[2], data[3], 0}
        elseif data[1] == CombatDefine.FIGHT_MODE2 then
           fightMode = {data[1], data[2], data[3], data[4]}
        else
           fightMode = {data[1], data[2], data[3], 0}
        end
	end
end


local function cmp(a,b)
	if a.helpType ~= CombatDefine.HELP_TYPE0 or b.helpType ~= CombatDefine.HELP_TYPE0 then
		-- if a.helpType == CombatDefine.HELP_TYPE0 then
		-- 	return false
		-- elseif b.helpType == CombatDefine.HELP_TYPE0 then
		-- 	return true
		-- else
        --     local aSpeed = a.speed or 0
	    --     local bSpeed = b.speed or 0
	    --     if aSpeed > bSpeed then
	    --     	return true
	    --     elseif aSpeed == bSpeed then
	    --     	return a.pos < b.pos
	    --     else
	    --     	return false
	    --     end 
		-- end

		if a.helpType == CombatDefine.HELP_TYPE0 then
			return false
		elseif b.helpType == CombatDefine.HELP_TYPE0 then
			return true
		elseif a.helpType == CombatDefine.HELP_TYPE1 and b.helpType == CombatDefine.HELP_TYPE2 then
			return true
		elseif a.helpType == CombatDefine.HELP_TYPE2 and b.helpType == CombatDefine.HELP_TYPE1 then
			return false
		else
            local aSpeed = a.speed or 0
			local bSpeed = b.speed or 0
			if aSpeed > bSpeed then
				return true
			elseif aSpeed == bSpeed then
				return a.pos < b.pos
			else
				return false
			end
		end
	end
	local aSpeed = getValue(a, RoleDefine.SPEED)
	local bSpeed = getValue(b, RoleDefine.SPEED)
	if aSpeed > bSpeed then
		return true
	elseif aSpeed == bSpeed then
		return a.pos < b.pos
	else
		return false
	end 
end


local function canAttack(obj)
	if not obj then
		return
	end
	if obj.helpType == CombatDefine.HELP_TYPE0 then
		local pos = obj.pos%CombatDefine.COMBAT_HERO_CNT
		if obj.hp > 0 and (pos > 0 or obj.backupPos) then
            -- 确定释放的技能是否带霸体
            local atkSkillID = getSkillID(obj)
            --local skillConfig = SkillExcel[atkSkillID]
			local skillConfig = Skill.GetSkillConfig(atkSkillID)

            if skillConfig and skillConfig.isBati == 1 then
               return true
            end

			if not CombatBuff.isStop(obj) then
				return true
			elseif CombatBuff.isStop(obj) then
				return false, "isStop"
			end
		end
	elseif obj.helpType == CombatDefine.HELP_TYPE1 then
		return petCD == 0
	elseif obj.helpType == CombatDefine.HELP_TYPE2 then
		for i = 1,#obj.skillList do
			local skill = obj.skillList[i]
			if (skill[3] == 0 or (skill[2] - round) % skill[3] == 0) and Skill.SkillCondCheck(obj, skill[1]) then
				return true
			end
		end
		return false
	elseif obj.helpType == CombatDefine.HELP_TYPE3 then

	elseif obj.helpType == CombatDefine.HELP_TYPE4 then

	end

end


function initAttackOrder()
	Util.initTable(attackOrder)

    -- 确定最高速度
    local atkSpeed = 0
    local atkSide = 0 
	for i = 1, CombatDefine.COMBAT_HERO_ALL_CNT do
		local obj = objList[i]	
		if canAttack(obj) then
			attackOrder[#attackOrder + 1] = obj
            local speed = getValue(obj, RoleDefine.SPEED)
            if speed > atkSpeed then
               atkSpeed = speed
               atkSide = obj.side
            end

			if round == 1 or not next(heroSpeedList) then
				heroSpeedList[obj.side] = heroSpeedList[obj.side] or {speedVal = 0, objCnt = 0, speedAvVal = 0}
				heroSpeedList[obj.side].speedVal = heroSpeedList[obj.side].speedVal + speed
				heroSpeedList[obj.side].objCnt = heroSpeedList[obj.side].objCnt + 1
			end
		end
	end

	for _,pos in ipairs(CombatDefine.SIDE2HELPPOS[0]) do
		local obj = helpList[pos]
		if obj and canAttack(obj) then
			attackOrder[#attackOrder + 1] = obj

            obj.speed = nil
            if obj.side == atkSide then
				obj.speed = atkSpeed
            end
		end
	end

	if round == 1 and heroSpeedList[CombatDefine.ATTACK_SIDE] and heroSpeedList[CombatDefine.DEFEND_SIDE] then
		local atkList = heroSpeedList[CombatDefine.ATTACK_SIDE]
		atkList.speedAvVal = math.floor(atkList.speedVal / atkList.objCnt)

		local defList = heroSpeedList[CombatDefine.DEFEND_SIDE]
		defList.speedAvVal = math.floor(defList.speedVal / defList.objCnt)
	end

	-- 精灵
	for _,pos in ipairs(CombatDefine.SIDE2ELFPOS[0]) do
		local elfObj = elfList[pos]
		if elfObj and canAttack(elfObj) then
			attackOrder[#attackOrder + 1] = elfObj

            -- if elfObj.side == atkSide then
			-- 	elfObj.speed = atkSpeed
            -- end

			elfObj.speed = heroSpeedList[elfObj.side] and heroSpeedList[elfObj.side].speedAvVal or 0
		end
	end


	table.sort(attackOrder,cmp)
	firstAttack = {true,true}
end

--用于战斗对象复活后插入出手列表的函数
function InsertAttackOrder(pos)
	local targetObj = objList[pos]

	if not canAttack(targetObj) then
		return
	end

	local sameSideObjs = {}
	for i=1,#attackOrder do
		local obj = attackOrder[i]
		if obj.pos == pos then
			return
		end

		local res = canAttack(obj)
		if res and obj.side == targetObj.side then
			sameSideObjs[#sameSideObjs + 1] = obj
		end
	end
	sameSideObjs[#sameSideObjs + 1] = targetObj

	if #sameSideObjs > 1 then
		table.sort(sameSideObjs, cmp)

		--没过出手回合才加入
		if sameSideObjs[1].pos ~= pos then
			attackOrder[#attackOrder + 1] = targetObj
		end
	end
end



local tempList = {}
function updateAttackOrder()
	for i = 1,#tempList do
		tempList[i] = nil
	end

	--当前不能出手, 但是下一轮可能可以出手的对象列表
	local maybeObjList = {}

	for i = 2,#attackOrder do
		local obj = attackOrder[i]

		-- if canAttack(obj) then
		-- 	tempList[#tempList + 1] = obj
		-- end

		local res1, tag = canAttack(obj)
		if res1 then
			tempList[#tempList + 1] = obj
		elseif tag == "isStop" then
			--那些被控制的英雄只有没过他的出手时机才加入列表中。可能会有给敌方驱散负面buff的技能, 所以不需要判断 tempList 里面是否有我方可出手英雄
			if #tempList > 0 then
				maybeObjList[#maybeObjList + 1] = obj
			end
		end
	end

	if #tempList > 1 then
		table.sort(tempList,cmp)
	end

	--只有当前轮有能出手的英雄, 才把 maybeObjList 中的对象加入到 tempList 中
	if #tempList >= 1 then
		for _, v in ipairs(maybeObjList) do
			tempList[#tempList + 1] = v
		end
	end


	for i = 1,#attackOrder do
		attackOrder[i] = tempList[i]
	end
end

local function clCombatResult()
	for i= 1,CombatDefine.COMBAT_HERO_ALL_CNT do
		local obj = objList[i]
		if obj then
			obj.combatResult[1] = 0
			obj.combatResult[2] = 0
			for k in pairs(obj.combatResult[3]) do
				obj.combatResult[3][k] = nil
			end
			obj.combatResult[4] = 0

			for k in pairs(obj.combatResult[5]) do
				obj.combatResult[5][k] = nil
			end
		end
	end
end

local function beforeCombat()
	Util.initTable(frameSkillList)
	Util.initTable(frameBufferList)
	Util.initTable(frameSayList)
	Util.initTable(fanjiList)
	Util.initTable(beSkillUseList)
	Util.initTable(beSkillPosUseList)
	Util.initTable(comboList)
	clCombatResult()
	isFanji = false
    comboType = 0
end


-- 战斗回合开始前操作
function onRoundBegin()
	round = round + 1
    -- 超出15回合
	if  round > maxRound then
		return
	end

	petCD = petCD - 1
	if round == 1 or petCD < 0 then
		petCD = CombatDefine.PET_CD - 1
	end
	attackIndex = 1	
	--正常buffer添加只会在小回合结束后添加。此处大回合开始时触发被动技能添加buffer需要特殊处理添加战斗帧操作
	beforeCombat()
	BeSkill.onRoundBegin(round)
	initAttackOrder()
	--每回合开始处理buff
	if #frameBufferList > 0 or #frameSayList > 0 then
		addFrame()
		mergeFrameBuffer()
		for k,v in ipairs(frameBufferList) do
			setBufferList(v)
		end
		for _,v in ipairs(frameSayList) do
			setSaySkill(v[1],v[2],v[3])
		end
	end
    if fightMode[1] == CombatDefine.FIGHT_MODE1 then
	   if round > fightMode[2] then
	   	  fightMode[4] = fightMode[4] + fightMode[3]
	   end
    end
end

function getNormalSkill(obj)
	return obj.skillList[#obj.skillList][1]
end

function getSkillID(obj)
	local skillID
	if obj.helpType == CombatDefine.HELP_TYPE0 then
		for i = 1,#obj.skillList do
			local skill = obj.skillList[i]
			if (skill[3] == 0 or (skill[2] - round) % skill[3] == 0) and Skill.SkillCondCheck(obj, skill[1]) then
				skillID = skill[1]
				skill[2] = round + skill[3]			
				break
			end
			if skill[3] > 0 and skill[2] < round then
				skill[2] = skill[2] + skill[3]
			end
		end

		if CombatBuff.isStatus(obj,{"hunluan"}) or CombatBuff.isChaofen(obj) or CombatBuff.IsCanNoUseSkill(obj) then
			skillID = obj.skillList[#obj.skillList][1]
		end

        if fightMode[1] == CombatDefine.FIGHT_MODE2 then

           -- 如果是援军 必定选择大招
           if obj.backupPos ~= nil then
           	  for i = 1,#obj.skillList do
			      local skill = obj.skillList[i]
                  local skillList = fightMode[2]
                  for k, v in pairs(skillList) do
                     if v == skill[1] then
                   		skillID = skill[1]
                        break
                     end
                  end
              end
           else
              -- 如果是第一回合 且不是防守方 使用大招
              if round == 1 then
                 if obj.side == CombatDefine.ATTACK_SIDE then
                    for i = 1,#obj.skillList do
			           local skill = obj.skillList[i]
                       --local skillConfig = SkillExcel[skill[1]]
					   local skillConfig = Skill.GetSkillConfig(skill[1])
                       if skillConfig.cvSound == 8 then
                          skillID = skill[1]
                          break
                       end
                    end
                 end
              end
           end
        end

	elseif  obj.helpType == CombatDefine.HELP_TYPE1 then
		for i = 1,#obj.skillList do
			local skill = obj.skillList[i]
			if (skill[3] == 0 or (skill[2] - round) % skill[3] == 0) and  Skill.SkillCondCheck(obj, skill[1]) then
				skillID = skill[1]
				skill[2] = round + skill[3]				
				break
			end
		end
	elseif obj.helpType == CombatDefine.HELP_TYPE2 then -- 精灵
		for i = 1,#obj.skillList do
			local skill = obj.skillList[i]
			if (skill[3] == 0 or (skill[2] - round) % skill[3] == 0) and  Skill.SkillCondCheck(obj, skill[1]) then
				skillID = skill[1]
				skill[2] = round + skill[3]
				break
			end
		end
	elseif obj.helpType == CombatDefine.HELP_TYPE3 then

	elseif obj.helpType == CombatDefine.HELP_TYPE4 then

	end
	skillID = BeSkill.onSkillID(obj,skillID)
	return skillID
end

function checkSideResult(pos)
	local cnt = 0
	local obj
	for i= 1,CombatDefine.COMBAT_HERO_CNT do
		if pos > CombatDefine.COMBAT_HERO_CNT then
			obj = objList[i]
		else
			obj = objList[i + CombatDefine.COMBAT_HERO_CNT]
		end
		
		if obj and  obj.hp > 0  then
			cnt = cnt + 1
		end		
	end	

	if cnt == 0 then
		return true
	end
end

local function checkResult()
	local attackCnt = 0
	local defendCnt = 0
	local obj
	for i= 1,CombatDefine.COMBAT_HERO_CNT do
		obj = objList[i]
		if obj and  obj.hp > 0  then
			attackCnt = attackCnt + 1
		end
		obj = objList[i + CombatDefine.COMBAT_HERO_CNT]
		if obj and  obj.hp > 0  then
			defendCnt = defendCnt + 1
		end
	end	

	result.attackCnt = attackCnt
	result.defendCnt = defendCnt

	if attackCnt > 0 and defendCnt == 0 then
		result.isWin = true
	end
	if attackCnt == 0 or defendCnt == 0 then
		return true
	end
end

-- 计算援军上阵附带属性比例
local function calcBackUpSkill(obj, star)
    --local skillConfig = SkillExcel[CombatDefine.BACKUP_BUFF_SKILL[1]]
	local skillConfig = Skill.GetSkillConfig(CombatDefine.BACKUP_BUFF_SKILL[1])
    if not skillConfig then return end
    local buffers = CombatBuff.getSkillBuffers(skillConfig)
    if not buffers then return end
    for i = 1, #buffers do
	    local bufferID = buffers[i][1]
	    --local conf = BufferExcel[bufferID]
		local conf = CombatBuff.GetBuffConfig(bufferID)
        if conf then
           conf.attrRate = CombatDefine.BACKUP_BUFF_REATE[star]
        end
    end
end


local function checkBackup()
	for side = 1, 2 do
		local backupObj = objList[CombatDefine.BACKUP_POS[side]]
		if  backupObj and not backupObj.backupPos then
			for index, pos in ipairs(CombatDefine.SIDE2POS[side]) do
				local obj = objList[pos]
                -- 剧情模式  强行把援军上阵到指定位置
                if fightMode[1] == CombatDefine.FIGHT_MODE2 then
                     if not obj and round == fightMode[3] and index == fightMode[4] then
					    backupObj.backupPos = pos
					    local attrs = {}
					    attrs[RoleDefine.BACKUP_COMBAT] = pos
					    addFrame()
					    setSkillID(backupObj,99999)
					    setExtraHit(backupObj,nil,Skill.getCMD2ID("backup"),attrs)

                        -- 使用上场技能 设定buffer的cmd 确定附加属性星级
                        calcBackUpSkill(backupObj, backupObj.star)
                        BeSkill.onBackupBegin(backupObj)
                        -- 强制速度
                        backupObj.attr[RoleDefine.SPEED] = 9999
					    break
                     end
                else
                	if obj and obj.hp <= 0 and pos ~= CombatDefine.BACKUP_POS[side] then
					    obj.beBackup = 1
					    backupObj.backupPos = pos
					    local attrs = {}
					    attrs[RoleDefine.BACKUP_COMBAT] = pos
					    addFrame()
					    setSkillID(backupObj,99999)
					    setExtraHit(backupObj,nil,Skill.getCMD2ID("backup"),attrs)
                        -- 使用上场技能
                        calcBackUpSkill(backupObj, backupObj.star)
                        BeSkill.onBackupBegin(backupObj)
					    break
				    end
                end
			end
		end
	end
end

local function afterCombat(attacker,isRoundEnd)
	--回合结束处理被动技能时如果是最后一次攻击是反击，不会触发。
	if isRoundEnd then
		isFanji = false
        comboType = 0
		checkBackup()
	end

	--处理回合尾加只生效一轮的buffer，在大回合结束单独加一帧,大回合结束要删buffer。避免客户端出现先删后加的要求导致没有buffer可删。同时显示已经删掉的buffer
	if isRoundEnd and #frameBufferList > 0 then
		addFrame()
		mergeFrameBuffer()
		for k,v in ipairs(frameBufferList) do
			setBufferList(v)
		end
		for _,v in ipairs(frameSayList) do
			setSaySkill(v[1],v[2],v[3])
		end
		Util.initTable(frameBufferList)
		Util.initTable(frameSayList)
	end
	
	BeSkill.onRoundEnd(isRoundEnd, attacker)
	CombatBuff.onRoundEnd(attacker,isRoundEnd)
    
	if #frameBufferList > 0 or #frameSayList > 0 then
		addFrame()
		mergeFrameBuffer()
		for k,v in ipairs(frameBufferList) do
			setBufferList(v)
		end
		for _,v in ipairs(frameSayList) do
			setSaySkill(v[1],v[2],v[3])
		end
		Util.initTable(frameBufferList)
		Util.initTable(frameSayList)
	end

    afterRevice()

	if attacker and attacker.pos <= CombatDefine.COMBAT_HERO_ALL_CNT and firstAttack[attacker.side] then
		firstAttack[attacker.side] = false
	end
end

local function afterFanji()	
	if #frameBufferList > 0 or #frameSayList > 0 then
		addFrame()
		mergeFrameBuffer()
		for k,v in ipairs(frameBufferList) do
			setBufferList(v)
		end
		for pos,v in ipairs(frameSayList) do
			setSaySkill(v[1],v[2],v[3])
		end
		Util.initTable(frameBufferList)
		Util.initTable(frameSayList)
	end
	isFanji = false
end

function afterBuff()
	if #frameBufferList > 0 or #frameSayList > 0 then
		mergeFrameBuffer()
		for k,v in ipairs(frameBufferList) do
			setBufferList(v)
		end
		for _,v in ipairs(frameSayList) do
			setSaySkill(v[1],v[2],v[3])
		end
		Util.initTable(frameBufferList)
		Util.initTable(frameSayList)
	end
end

local function afterCombo()
	if #frameBufferList > 0 or #frameSayList > 0 then
		addFrame()
		mergeFrameBuffer()
		for k,v in ipairs(frameBufferList) do
			setBufferList(v)
		end
		for _,v in ipairs(frameSayList) do
			setSaySkill(v[1],v[2],v[3])
		end
		Util.initTable(frameBufferList)
		Util.initTable(frameSayList)
	end
    comboType = 0
end

function calcFrame()
	-- 没有能出手的人，开始下一个回合
	if not attackOrder[1] then
		onRoundBegin()
	end
	-- 超出15回合
	if  round > maxRound then
		return
	end

	if not attackOrder[1] then
		-- 此回合 双方都没有能出手的英雄
		-- 回合 Buff结算
		afterCombat(nil ,not attackOrder[1])
		if checkResult() then return end
		return true
	end
	beforeCombat()
	local attacker = attackOrder[1]
	if attacker then
		-- 目前mpAtkRate 永远为nil
		local skillID,mpAtkRate = getSkillID(attacker)
    	-- buff作用效果
        --skillID = 10131
		if skillID then
        	Skill.use(attacker,skillID,mpAtkRate)
			CombatBuff.BuffHandleAfterSkill(attacker)
        	addObjResultOut(attacker,round)
		end	
	end
    --技能buff
    afterBuff()
	CombatBuff.beforeFanji()
	--BeSkill.beforeFanji(attacker)
	fanji()
	afterFanji()	
	combo()
	afterCombo()
    afterRevice()
    updateAttackOrder()
	afterCombat(attacker,not attackOrder[1])
	if checkResult() then return end
	return true
end

function addFrame()
	if not result.frames then
		result.frames = {}
	end	
	local frame = {}
	frame.round = round
	frame.petCD = petCD
	frame.skillList = {}
	frame.bufferList = {}
	frame.sayList = {}
	result.frames[#result.frames + 1] = frame
	return frame
end

function setSkillID(obj,skillID)
	onUseSkill(skillID)
	local pos = obj.pos
	local frame = result.frames[#result.frames]
	local skillData = {}
	skillData.attackPos = pos
	skillData.skillID = skillID
	skillData.hitList = {}
	skillData.extraList = {}
	skillData.petList = {}	
	frame.skillList[#frame.skillList+1] = skillData
end

function setSaySkill(pos,skillID,contentType)
	if contentType == 0 then
		return
	end
	--if pos > CombatDefine.COMBAT_HERO_ALL_CNT then
	--	return
	--end
	onUseSkill(skillID)
	local frame = result.frames[#result.frames]
	frame.sayList[pos] = frame.sayList[pos] or {}
	frame.sayList[pos][#frame.sayList[pos]+ 1] = skillID
end

function setSkillHit(target,hpValue,mpValue,flag,attacker,skillID)
	local frame = result.frames[#result.frames]
	local skillFrame = frame.skillList[#frame.skillList]
	if not (not target.isPet and skillFrame.skillID == skillID and skillFrame.attackPos and skillFrame.attackPos == attacker.pos) then
		addFrame()
		setSkillID(attacker,skillID)
		frame = result.frames[#result.frames]
		skillFrame = frame.skillList[#frame.skillList]
	end	

	local pos = target.pos
	if not skillFrame.hitList[pos] then
		skillFrame.hitList[pos] = {}
	end
	
	if not skillFrame.hitList[pos].attrs then
		skillFrame.hitList[pos].attrs = {}
	end
	skillFrame.hitList[pos].flag = flag or 0
	skillFrame.hitList[pos].hpNow = target.hp
	local frameAttrs = skillFrame.hitList[pos].attrs
	if hpValue and hpValue ~= 0 then
		frameAttrs[#frameAttrs + 1] = {RoleDefine.HP_COMBAT,hpValue}
		if target.side == CombatDefine.DEFEND_SIDE and hpValue < 0 then
			frameAttrs[#frameAttrs + 1] = {RoleDefine.HURT_COMBAT_TOTAL,math.floor(totalHurt)}
		end
	end
	
end

function isSkillFrameEmpty()
	local frame = result.frames and result.frames[#result.frames]
	if not frame then
		return true
	end
	local skillFrame = frame.skillList[#frame.skillList]
	if not skillFrame then
		return true
	end
end

function setExtraHit(target,hpValue,cmd,attrs)
	local frame = result.frames[#result.frames]
	local skillFrame = frame.skillList[#frame.skillList]
	--处理下没有使用技能的情况
	if not skillFrame then
		print("======================没有使用技能====================")
		setSkillID({pos = 99}, 66666)
		skillFrame = frame.skillList[#frame.skillList]
	end

	local pos = target.pos

	if not skillFrame.extraList[pos] then
		skillFrame.extraList[pos] = {}
	end
	
	if not skillFrame.extraList[pos].attrs then
		skillFrame.extraList[pos].attrs = {}
	end
	skillFrame.extraList[pos].flag = 0
	if not skillFrame.extraList[pos].cmd then
		skillFrame.extraList[pos].cmd =  cmd or 0
	end
	skillFrame.extraList[pos].hpNow = target.hp
	local frameAttrs = skillFrame.extraList[pos].attrs
	if hpValue and hpValue ~= 0 then
		frameAttrs[#frameAttrs + 1] = {RoleDefine.HP_COMBAT,hpValue}
		if target.side == CombatDefine.DEFEND_SIDE and hpValue < 0 then
			frameAttrs[#frameAttrs + 1] = {RoleDefine.HURT_COMBAT_TOTAL,math.floor(totalHurt)}
		end
	end
	if attrs then
		for k,v in pairs(attrs) do
			frameAttrs[#frameAttrs + 1] = {k,v}
		end
	end
	onUseCmd(cmd)
end

function setBufferList(data)
	if not data then
		return
	end
	local frame = result.frames[#result.frames]
	
	if not frame.bufferList[data.pos] then
		frame.bufferList[data.pos] = {}
	end
	
	local bufferList = frame.bufferList[data.pos]
	local frameBuffer = {}
	frameBuffer.id = data.id
	frameBuffer.cnt = data.cnt
	frameBuffer.round = data.round
	frameBuffer.op = data.op
	frameBuffer.hpNow = data.hpNow
	frameBuffer.attrs = {}
	if data.attrs then
		local hpValue = 0
		for k,v in pairs(data.attrs) do
			frameBuffer.attrs[#frameBuffer.attrs + 1] = {k,v}
			if data.pos > CombatDefine.COMBAT_HERO_CNT and k == RoleDefine.HP_COMBAT and v < 0 then
				hpValue = hpValue + v
			end
		end
		if hpValue < 0 then
			frameBuffer.attrs[#frameBuffer.attrs + 1] = {RoleDefine.HURT_COMBAT_TOTAL,math.floor(totalHurt)}
		end
	end
	bufferList[#bufferList + 1] = frameBuffer
end

function onUseSkill(skillID)
	skillUseList[skillID] = 1
end

function onUseCmd(cmd)
	if not cmd or cmd == 0 then return end
	cmdUseList[cmd] = 1
end

function onAddBuffer(bufferID)
	bufferUseList[bufferID] = 1
end

function addFrameSkill(pos,skillID)
	frameSkillList[#frameSkillList + 1] = {pos,skillID}
end

function addFrameBuffer(obj,buffer,op,bufferCnt)
	local data = {}
	data.id = buffer.id
	data.cnt = bufferCnt or 1
	data.round = buffer.round
	data.op = op
	data.attrs = {}
	if buffer.attrs then
		for k,v in pairs(buffer.attrs) do
			if v ~= 0 then
				data.attrs[k] = data.attrs[k] or 0
				data.attrs[k] = data.attrs[k] + v
			end
		end
	end
	data.pos = obj.pos
	data.hpNow = obj.hp
	frameBufferList[#frameBufferList + 1] = data
end

function addSaySkill(obj,skillConfig)
	if skillConfig.contentType == 0 then
		return
	end

	if obj.pos > CombatDefine.COMBAT_HERO_ALL_CNT then
		return
	end
	frameSayList[#frameSayList + 1] =  {obj.pos,skillConfig.id,skillConfig.contentType}
end

function addRevice(attackPos, obj, bufferID, skillID)
    frameReviceList[#frameReviceList + 1] = {obj.pos, attackPos, bufferID, skillID}
end

function addRevice2(attackPos, obj, bufferID, skillID)
    frameReviceList2[#frameReviceList2 + 1] = {obj.pos, attackPos, bufferID, skillID}
end

function afterRevice()
	if #frameReviceList > 0 then
        for k, v in ipairs(frameReviceList) do
           local obj = objList[v[1]]
		   if obj then
              addFrame()
              CombatBuff.reviceObj(v[2], obj, v[3], v[4])
		   end
        end

        Util.initTable(frameReviceList)
	end

	if #frameReviceList2 > 0 then
		local rmIdxArr = {}
		for k, v in ipairs(frameReviceList2) do
			local obj = objList[v[1]]
			if obj and CombatBuff.isStatus(obj, {"revive1"}) then
				local errCode = CombatBuff.reviceObj(v[2], obj, v[3], v[4])
				if errCode == -1 then -- 死亡状态触发复活失败
					rmIdxArr[#rmIdxArr+1] = k
				end
			else
				rmIdxArr[#rmIdxArr+1] = k
			end
        end

		for _, rmIdx in ipairs(rmIdxArr) do
			table.remove(frameReviceList2, rmIdx)
		end
	end

	if #frameBufferList > 0 or #frameSayList > 0 then
		mergeFrameBuffer()
		for k,v in ipairs(frameBufferList) do
			setBufferList(v)
		end

		for _,v in ipairs(frameSayList) do
			setSaySkill(v[1],v[2],v[3])
		end
			Util.initTable(frameBufferList)
			Util.initTable(frameSayList)
        end
end

function addBeSkillUse(obj,attackerPos,skillID)
	beSkillUseList[obj.pos] = beSkillUseList[obj.pos] or {}
	beSkillUseList[obj.pos][attackerPos] = beSkillUseList[obj.pos][attackerPos] or {}
	beSkillUseList[obj.pos][attackerPos][skillID] = beSkillUseList[obj.pos][attackerPos][skillID] or 0
	beSkillUseList[obj.pos][attackerPos][skillID] = beSkillUseList[obj.pos][attackerPos][skillID] + 1
end

function getBeSkillUse(obj,attackerPos,skillID)
	return beSkillUseList[obj.pos] and beSkillUseList[obj.pos][attackerPos] and beSkillUseList[obj.pos][attackerPos][skillID] or 0
end

function addBeSkillPosUse(pos,skillID)
	beSkillPosUseList[pos] = beSkillPosUseList[pos] or {}
	beSkillPosUseList[pos][skillID] = beSkillPosUseList[pos][skillID] or 0
	beSkillPosUseList[pos][skillID] = beSkillPosUseList[pos][skillID] + 1
end

function getBeSkillPosUse(pos,skillID)
	return beSkillPosUseList[pos] and beSkillPosUseList[pos][skillID]
end

function getBeSkillSideUse(pos,skillID)
	local side
	if pos <= CombatDefine.COMBAT_HERO_CNT then
		side = CombatDefine.ATTACK_SIDE
	elseif pos <= CombatDefine.COMBAT_HERO_ALL_CNT then
		side = CombatDefine.DEFEND_SIDE
	else
		return
	end
	local skillCnt = 0
	for _,v in ipairs(CombatDefine.SIDE2POS[side]) do
		if v ~= pos and beSkillPosUseList[v] and beSkillPosUseList[v][skillID] then
			skillCnt = skillCnt + beSkillPosUseList[v][skillID]
		end
	end
	return skillCnt
end

function setObjResult(pos,value)
	local obj 
	if pos <= CombatDefine.COMBAT_HERO_ALL_CNT then
		obj = objList[pos]
	elseif pos == CombatDefine.PET_ATKPOS then
		obj = helpList[pos]
	elseif pos == CombatDefine.PET_DEFPOS then
		obj = helpList[pos]
	elseif CombatDefine.ELF_MIN_POS <= pos and CombatDefine.ELF_MAX_POS >= pos then
		obj = elfList[pos]
	end
	if not obj then
		return
	end
	if value > 0 then
		obj.result[2] = obj.result[2] + value
	elseif value < 0 then
		obj.result[1] = obj.result[1] - value	

		if obj.side == CombatDefine.ATTACK_SIDE then
			totalHurt = totalHurt - value
		end	
	end
end

function fanji()
	isFanji = true
	for i = 1,#fanjiList do
		local fanjiData = fanjiList[i]
		if fanjiData[1].hp > 0 then
			Skill.use(fanjiData[1],fanjiData[2],fanjiData[3])
		end
	end
end


function comboAgain(obj, type, hurtRate, comboSkillID, skip)
    if not obj or obj.hp <=0 then return end
	local stop = CombatBuff.isStop(obj)

	--新增条件，如果控制buff只有chanrao也能继续执行
	if stop and skip == nil and not CombatBuff.IsJustHaveChanraoBuff(obj)  then return end

    local skillID = comboSkillID or getSkillID(obj)
    if skillID then
       comboType = type
       comboHurtRate = hurtRate
	   if type == 999 then --追击
			local objPos = obj.pos
			local objTag = obj.uuid or obj.id
			useZhuijiObjList[objPos] = {}
			useZhuijiObjList[objPos][objTag] = (useZhuijiObjList[objPos][objTag] or 0) + 1
	   end
       Skill.use(obj, skillID)
       comboType = 0
    end
end

function combo()
	local comboSkillID
	for k,v in pairs(comboPosList) do
		comboPosList[k] = nil
	end

    for k, v in ipairs(comboList) do
	--for i = 1,#comboList do
		local obj = v[1]
        if obj.hp > 0 then
			local type = v[2] or 0
            local hurtRate = v[3] or 10000
			comboSkillID = nil
            local argSkill = v[4] or 0
            if argSkill ~= 0 then
                comboSkillID = argSkill
            else
                if type == 2 then
                   comboSkillID = getNormalSkill(obj)
                end
            end
            local t = v[5] or 1
            local skip = v[6]
            if not (comboPosList[obj.pos] and comboPosList[obj.pos][t] and comboPosList[obj.pos][0] >= 3) then	--避免组合技能触发多次连击，比如10813
				comboAgain(obj, type, hurtRate, comboSkillID, skip)
				comboPosList[obj.pos] = comboPosList[obj.pos] or {}
				comboPosList[obj.pos][0] = comboPosList[obj.pos][0] or 0
				comboPosList[obj.pos][0] = comboPosList[obj.pos][0] + 1
				comboPosList[obj.pos][t] = 1
			end
		end
	end
end

function setObjBearResult(obj, value)
	if not obj then
		return
	end

	if value < 0 then
		obj.result[3] = obj.result[3] - value
	end
end

function addObjResultOut(obj, round)
	if not obj then
		return
	end

	if obj.pos > CombatDefine.COMBAT_HERO_ALL_CNT then
		obj.result[4] = obj.result[4] + 1
	else		
		obj.result[4] = round
	end
end

--即时添加buffer帧
function instantFrameBuffer(obj,skillID)
	if #frameBufferList > 0 or #frameSayList > 0 then
		addFrame()
		if obj and skillID then
			setSkillID(obj, skillID)
		end
		mergeFrameBuffer()
		for k,v in ipairs(frameBufferList) do
			setBufferList(v)
		end
		for _,v in ipairs(frameSayList) do
			setSaySkill(v[1],v[2],v[3])
		end
		Util.initTable(frameBufferList)
		Util.initTable(frameSayList)
	end
end