-- 异界之战

--db
--[=[

    human.db.anotherWorlBattle = {
        startTime = nil,
        formation = {
            [cityId1] = {
                [pointIdx1] = {list = {},helpList = {},formation = 1,jiban = {}, elfList = {}}
                [pointIdx2] = {list = {},helpList = {},formation = 1,jiban = {}, elfList = {}}
            },

            [cityId2] = {
                [pointIdx1] = {list = {},helpList = {},formation = 1,jiban = {}, elfList = {}}
                [pointIdx2] = {list = {},helpList = {},formation = 1,jiban = {}, elfList = {}}
            },
        }
    }

]=]--

local Config = require("Config")
local Msg = require("core.Msg")
local Lang = require("common.Lang")
local ObjHuman = require("core.ObjHuman")
local Broadcast = require("broadcast.Broadcast")
local RoleSystemLogic = require("roleSystem.RoleSystemLogic")
local RoleSystemDefine = require("roleSystem.RoleSystemDefine")
local CombatDefine = require("combat.CombatDefine")
local RoleDBLogic = require("role.RoleDBLogic")
local CombatPosLogic = require("combat.CombatPosLogic")
local CombatLogic = require("combat.CombatLogic")
local MailExcel = require("excel.mail")
local Util = require("common.Util")
local InnerMsg = require("core.InnerMsg")
local RoleHeadLogic = require("role.RoleHeadLogic")
local MailManager = require("mail.MailManager")
local Log = require("common.Log")
local Timer = require("core.Timer")
local Grid = require("bag.Grid")
local UnionLogic = require("union.UnionLogic")
local BillboardLogic = require("billboard.BillboardLogic")
local BillboardDefine = require("billboard.BillboardDefine")
local AnotherWorldBattleDefine = require("anotherWorldBattle.AnotherWorldBattleDefine")
local AnotherWorldBattleConfig = require("excel.anotherWorldBattle")
local MonsterGrid = require("monster.MonsterGrid")
local RoleConfig = require("excel.role")
local MonsterExcel = require("excel.monster")
local HeroExcel = require("excel.hero")
local MiddleCommonLogic = require("middle.MiddleCommonLogic")
local CombatImpl = require("combat.CombatImpl")
local RoleAttr = require("role.RoleAttr")
local CommonDB = require("common.CommonDB")
local BagLogic = require("bag.BagLogic")


local HeroLogic
local JibanLogic

local LOGTAG = "AnotherWorldBattleNS"


local function writeLog(logStr)
    Log.write(Log.LOGID_OSS_ANOTHERWORLDBATTLE, logStr)
end

local function sendMail(mailId, receiverUuid, itemArray, extraInfo, rank)
    if not mailId or not receiverUuid then
        return
    end

    local mailCfg = MailExcel.mail[mailId]
    local content = mailCfg.content

    if mailId == AnotherWorldBattleDefine.AB_AWARD_MAIL_ID then
        local v1,v2,v3,v4,v5
        v1,v2,v3 = extraInfo and extraInfo[1] or 0, extraInfo and extraInfo[2] or 0, extraInfo and extraInfo[3] or 0
        v4,v5 = extraInfo and extraInfo[4] or 0, extraInfo and extraInfo[5] or 0
        content = Util.format(content, v1,v2,v3,v4,v5)

    elseif mailId == AnotherWorldBattleDefine.AB_UNIONRANK_AWARD_MAIL_ID then
        content = Util.format(content, rank)
    else
        if rank > AnotherWorldBattleDefine.AB_RANK_MAX_NUM then
            rank = "50+"
        end
        content = Util.format(content, rank)
    end

    MailManager.add(MailManager.SYSTEM, receiverUuid, mailCfg.title, content, itemArray, mailCfg.senderName or "GM")
end

local function createRewardQueue()
    local issueRewardQueue = {
        playerArray = {},
        insertMaxNum = 100, -- 一次最多插入数据库的邮件数量
        repeatMaxTimes = 3, -- 重试次数
        repeatTb = {},
        extraInfo = {},
    }

    function issueRewardQueue:add(playerInfo)
        table.insert(self.playerArray, playerInfo)
    end

    function issueRewardQueue:insertDB()
        local maxNum = math.min(self.insertMaxNum, #self.playerArray)

        for i=1, maxNum do
            local resTag = AnotherWorldBattleDefine.AB_MAIL_SUCC_TAG
            local playerInfo = table.remove(self.playerArray)
            local playerUuid = playerInfo[1]
            local mailId = playerInfo[3]
            local rank = playerInfo[4]

            local ok, err = pcall(sendMail, mailId, playerUuid, playerInfo[2], issueRewardQueue.extraInfo, rank)

            if not ok then
                if not self.repeatTb[playerUuid] or self.repeatTb[playerUuid] < self.repeatMaxTimes then
                    issueRewardQueue:add(playerInfo)
                    self.repeatTb[playerUuid] = (self.repeatTb[playerUuid] or 0) + 1
                end

                resTag = AnotherWorldBattleDefine.AB_MAIL_FAIL_TAG
            end

            -- 写入日志
            local str = string.format("Result: %s, playerUuid: %s, mailId: %d, insertErrTimes: %d, errInfo: %s",
                    resTag, playerUuid, mailId, self.repeatTb[playerUuid] or 0, err)

            writeLog(str)
        end

        if #self.playerArray > 0 then
            Timer.addLater(2, self.insertDB, self)
        end
    end

    return issueRewardQueue
end


-- 获取当天是星期几
local function getWDay()
    return Util.getWeekDay()
end

-- 开服天数和玩家等级检查
local function baseCondCheck(human)
    return RoleSystemLogic.isOpen(human, RoleSystemDefine.ROLE_SYS_ID_1216)
end

-- 根据最近一轮活动开启时间, 判断当前是否处于活动开启时间范围
local function actStartTimeCheck()
    local wDay = getWDay()
    if wDay > AnotherWorldBattleDefine.AB_OPEN_WDAY_AREA[2] and wDay < AnotherWorldBattleDefine.AB_OPEN_WDAY_AREA[1] then
        return false
    end

    local startTime = CommonDB.getValueByKey(CommonDB.KEY_ANOTHERWORLDBATTLE_START_TI)
    if not startTime then
        return false
    end

    if not IsRuning(startTime) then
        return false
    end

    return true
end

-- 计算怪物战力
local function calcMonsterPower(monsterOutID)
    local power = 0
    local objList = MonsterGrid.createMonsterObjListByMonsterOutID(monsterOutID)
    if not objList then
        return power
    end

    for _, monster in ipairs(objList) do
        power = power + (monster.power or 0)
    end

    return power
end

-- 根据据点所属城池,计算多个据点每分钟产出道具数量之和
local function calcPointAward(cityIdArr)
    local myUnionAwardNum = 0
    if cityIdArr then
        for _, cityId in ipairs(cityIdArr) do
            local targetCityCfg = AnotherWorldBattleConfig.city[cityId]
            if targetCityCfg.isBaseCity == 1 then
                myUnionAwardNum = myUnionAwardNum + targetCityCfg.cityAward[2] * AnotherWorldBattleDefine.AB_POINT_MAX_NUM
            else
                myUnionAwardNum = myUnionAwardNum + targetCityCfg.cityAward[2]
            end

        end
    end

    return math.min(myUnionAwardNum, AnotherWorldBattleDefine.AB_MIN_ITEM_MAX_NUM)
end

-- 获取展示部位的固定Id
local function getDefaultShowId(showType, idx)
    local targetCfg
    if showType == 1 then
        targetCfg = RoleConfig.head
    else
        targetCfg = RoleConfig.headFrame
    end

    local t = {}
    for k in pairs(targetCfg) do
        t[#t+1] = k
    end

    table.sort(t)

    return t[idx] or t[1]
end

-- 单个英雄数据
local function getHeroInfo(human, targetHeroUuid)
    HeroLogic = HeroLogic or require("hero.HeroLogic")
    local heroGrid = HeroLogic.getHeroGridByUuid(human, targetHeroUuid)
    if heroGrid then
        local heroCfg = HeroExcel.hero[heroGrid.id]
        RoleAttr.calcHeroGrid(heroGrid, nil, human)
        local heroInfo = {
            heroUuid  = targetHeroUuid,
            heroStar  = heroGrid.star,
            heroLevel = heroGrid.lv,
            heroCamp  =  heroGrid.camp or heroCfg.camp,
            heroBody  = heroCfg.body,
            heroIcon  = heroGrid.head or heroCfg.head,
            heroPower = heroGrid.zhandouli,
            heroId = heroGrid.id,
            heroQuality = heroCfg.grade,
        }

        return heroInfo
    end
end

-- 获取上阵英雄数据
local function getHeroListInfo(human, targetHeroUuid)
    local len = 0
    local heroArr = {}

    local heroList = CombatPosLogic.getCombatHeros(human, CombatDefine.COMBAT_TYPE35)
    if not next(heroList) then
        return heroArr
    end

    for _, heroUuid in pairs(heroList) do
        if (heroUuid ~= "" and heroUuid ~= "0") and (not targetHeroUuid or targetHeroUuid == heroUuid) then
            len = len + 1
            heroArr[len] = getHeroInfo(human, heroUuid)
        end
    end

    if len == 0 then
        return
    end
    return heroArr
end

-- 生成展示数据
local function generateShowInfo(human)
    local showInfo = {
        name = human.db.name,
        lv = human.db.lv,
        power = human.db.zhandouli,
    }

    showInfo.head = RoleHeadLogic.getRoleAppearance(human, RoleHeadLogic.HEAD_TYPE_1)
    showInfo.headFrame = RoleHeadLogic.getRoleAppearance(human, RoleHeadLogic.HEAD_TYPE_2)
    -- showInfo.body = RoleHeadLogic.getRoleAppearance(human, RoleHeadLogic.HEAD_TYPE_3)
    showInfo.heroArr = getHeroListInfo(human)

    return showInfo
end

-- 阵容数据检查，如果不在 "活动开启且战斗阶段" 则清空
local function formationDataCheeck(human)
    if not human.db.anotherWorlBattle then
        return
    end

    -- 不在战斗阶段时间范围
    local wDay = getWDay()
    if not (AnotherWorldBattleDefine.AB_BATTLE_WDAY_AREA[1] <= wDay and AnotherWorldBattleDefine.AB_BATTLE_WDAY_AREA[2] >= wDay) then
        human.db.anotherWorlBattle = nil
        return
    end

    -- 处于战斗阶段最后一天, 但是活动已经结束
    local now = os.time()
    local toDayStartTime = Util.getDayStartTime(now)
    if AnotherWorldBattleDefine.AB_BATTLE_WDAY_AREA[2] == wDay and now > (toDayStartTime + AnotherWorldBattleDefine.AB_BATTLE_END_SEC) then
        human.db.anotherWorlBattle = nil
        return
    end

    -- 处于战斗阶段时间范围内, 但是活动未开(因为两轮活动时间间隔至少9天)
    local startTime = human.db.anotherWorlBattle.startTime
    local diffDays = Util.diffDay(startTime)
    if diffDays > AnotherWorldBattleDefine.AB_BATTLE_DAYS then
        human.db.anotherWorlBattle = nil
    end
end

-- 把玩家最新的异界之战所有防守英雄uuid推给客户端
local function sendDefHeroArr(human)
    local msgRet = Msg.gc.GC_AB_DEF_HERO_QUERY
    msgRet.heroUuidArr[0] = 0

    if not human.db.anotherWorlBattle then
        return Msg.send(msgRet, human.fd)
    end

    local len = 0
    local heroUuidArrMsg = msgRet.heroUuidArr

    for _, pointList in pairs(human.db.anotherWorlBattle.formation) do
        for _, combatData in pairs(pointList) do
            local heroList = combatData.list

            for _, heroUuid in pairs(heroList) do
                if heroUuid ~= "" and heroUuid ~= "0" then
                    len = len + 1
                    heroUuidArrMsg[len] = heroUuid
                end
            end
        end
    end

    heroUuidArrMsg[0] = len

    Msg.send(msgRet, human.fd)
end

-- 如果活动开启时间范围内, 则通知客户端弹出提示框
local function notifyTips(human)
    if not baseCondCheck(human) then
        return
    end

    local wDay = getWDay()
    if wDay > AnotherWorldBattleDefine.AB_OPEN_WDAY_AREA[2] and wDay < AnotherWorldBattleDefine.AB_OPEN_WDAY_AREA[1] then
        return
    end

    AB_GetState(human, true)
end


-- 是否是防守阵容中的英雄
local function isDefHero(human, checkHeroUuid, excludeCityId, excludePointIdx)
    if not human.db.anotherWorlBattle then
        return
    end

    for cityId, pointList in pairs(human.db.anotherWorlBattle.formation) do
        for pointIdx, combatData in pairs(pointList) do
            if (excludeCityId and excludeCityId == cityId) and (excludePointIdx and excludePointIdx == pointIdx) then
                break
            end

            local heroList = combatData.list
            for _, heroUuid in pairs(heroList) do
                if heroUuid == checkHeroUuid then
                    return cityId, pointIdx
                end
            end
        end
    end

    return
end

-- 是否是公会战力榜前N名（可参加异界之战）
local function isTopJoinRankUnion(human)
    local unionRanList = BillboardLogic.GetRankList(BillboardDefine.TYPE_UNION)
    if not unionRanList then
        return false
    end

    local unionId = human.db.unionUuid
    local rankMax = AnotherWorldBattleDefine.AB_UNION_JOIN_RANK_MAX
    for i = 1, rankMax do
        if unionRanList[i] and unionRanList[i].uuid == unionId then
            return true
        end
    end

    return false
end

-- 是否处于战斗阶段
local function isBattleStage()
    local wDay = getWDay()
    if wDay >= AnotherWorldBattleDefine.AB_BATTLE_WDAY_AREA[1] and wDay <= AnotherWorldBattleDefine.AB_BATTLE_WDAY_AREA[2] then
        return true
    end

    return false
end

-- 重置在线玩家的防守数据
local function resetDefData(playerInfoArr)
    for _, playerInfo in ipairs(playerInfoArr or {}) do
        local playerUuid = playerInfo[1]
        local human = ObjHuman.onlineUuid[playerUuid]
        if human then
            onLogin(human)
        end
    end
end

-- 获取公会/个人排行榜通用的奖励Id
local function getRankGenericAwadId(rankRewardList, rankType)
    for _, v in ipairs(rankRewardList) do
        if v.nRankType == rankType then
            return v.Prize
        end
    end
end

-- 获取排名奖励
local function getRankAward(rankRewardList, rankType, targetRank)
    for _, v in ipairs(rankRewardList) do
        if v.nRankType == rankType and (targetRank >= v.nOrder[1] and targetRank <= v.nOrder[2]) then
            return v.Prize
        end
    end
end

-- 计算整个战斗阶段占据据点的最大产出数量
local function calcRewardMax()
    local totalSec = AnotherWorldBattleDefine.AB_BATTLE_DAYS * 86400
    totalSec = totalSec - AnotherWorldBattleDefine.AB_START_SEC -- 第一天0:10分才开始
    totalSec = totalSec - (86400 - AnotherWorldBattleDefine.AB_BATTLE_END_SEC) -- 最后一天只到23点

    local itemCntMax = math.floor(totalSec / 60) * AnotherWorldBattleDefine.AB_MIN_ITEM_MAX_NUM
    return itemCntMax
end

-- 计算当前占领的据点最大产出数量
local function calcRewardNow()
    local now = os.time()
    local toDayStartTime = Util.getDayStartTime(now)

    local wDay = getWDay()
    local subDay = wDay - AnotherWorldBattleDefine.AB_BATTLE_WDAY_AREA[1]

    local battleStageStartTime = toDayStartTime - (subDay * 86400)
    battleStageStartTime = battleStageStartTime + AnotherWorldBattleDefine.AB_START_SEC

    local subSec = now - battleStageStartTime
    local itemCntMax = math.floor(subSec / 60) * AnotherWorldBattleDefine.AB_MIN_ITEM_MAX_NUM
    return itemCntMax
end

-- 生成奖励发放对象列表
local function genAwardObjArr(unionOccupyInfo)
    local function calcMinute(timeArr)
        local minuteVal = 0
        for _, timeTb in ipairs(timeArr or {}) do
            local sec = (timeTb[2] or 0) - (timeTb[1] or 0)
            if sec > 0 then
                minuteVal = minuteVal + sec
            end
        end

        return math.floor(minuteVal / 60)
    end

    -- 没有玩家参与
    if not unionOccupyInfo.playerInfoArr or #unionOccupyInfo.playerInfoArr <= 0 then
        return
    end

    local itemList = {}
    local occupyCityInfo = {0,0,0,0,0}
    local item_185_Id = 185
    local item_185_Num = 0

    occupyCityInfo[1] = unionOccupyInfo.occuoyPointNum

    -- 额外奖励
    item_185_Num = item_185_Num + (unionOccupyInfo.occuoyPointNum or 0)

    for _, cityId in ipairs(unionOccupyInfo.occupyCityArr) do
        local cityCfg = AnotherWorldBattleConfig.city[cityId]
        if cityCfg then
            if cityCfg.isBaseCity == 1 then
                item_185_Num = item_185_Num + 20
            else
                if cityCfg.cityLv == 2 then
                    item_185_Num = item_185_Num + 2
                    occupyCityInfo[2] = occupyCityInfo[2] + 1
                elseif cityCfg.cityLv == 3 then
                    item_185_Num = item_185_Num + 3
                    occupyCityInfo[3] = occupyCityInfo[3] + 1
                elseif cityCfg.cityLv == 4 then
                    item_185_Num = item_185_Num + 5
                    occupyCityInfo[4] = occupyCityInfo[4] + 1
                elseif cityCfg.cityLv == 5 then
                    item_185_Num = item_185_Num + 20
                    occupyCityInfo[5] = occupyCityInfo[5] + 1
                end
            end
        end
    end

    -- 占领据点每分钟的奖励
    local minuteAwardId, minuteAwardNum = 0, 0

    for _, pointInfo in ipairs(unionOccupyInfo.point2CityIdArr) do
        local cityId = pointInfo[1]
        local occupyTimeArr = pointInfo[2]

        local cityCfg = AnotherWorldBattleConfig.city[cityId]
        local totalMinVal = calcMinute(occupyTimeArr)
        if totalMinVal > 0 then
            local itemId, itemNum = cityCfg.cityAward[1], cityCfg.cityAward[2]
            minuteAwardId = itemId
            minuteAwardNum = minuteAwardNum + totalMinVal * itemNum
            -- itemList[itemId] = (itemList[itemId] or 0) + totalMinVal * itemNum
        end
    end

    local maxNum = calcRewardMax()
    if maxNum > 0 then
        minuteAwardNum = math.min(minuteAwardNum, maxNum)
    end
    itemList[minuteAwardId] = (itemList[minuteAwardId] or 0) + minuteAwardNum


    if item_185_Num > 0 then
        itemList[item_185_Id] = item_185_Num
    end

    local itemArr = {}
    for itemId, itemNum in pairs(itemList) do
        itemArr[#itemArr+1] = { itemId, itemNum }
    end

    local rankReward = AnotherWorldBattleConfig.rankReward

    local awardObjArr = {}
    for _, playerInfo in ipairs(unionOccupyInfo.playerInfoArr) do
        local playerUuid = playerInfo[1]
        local playerRank = playerInfo[2]

        -- 据点每分钟奖励 + 额外奖励
        awardObjArr[#awardObjArr+1] = {playerUuid, itemArr, AnotherWorldBattleDefine.AB_AWARD_MAIL_ID}

        -- 公会排名奖励
        -- local itemId, itemNum = getRankAward(rankReward, 1, unionOccupyInfo.unionRank)
        -- if itemId and itemNum then
        --     awardObjArr[#awardObjArr+1] = {playerUuid, {{itemId, itemNum}}, AnotherWorldBattleDefine.AB_UNIONRANK_AWARD_MAIL_ID, unionOccupyInfo.unionRank}
        -- end
        local itemTb = getRankAward(rankReward, 1, unionOccupyInfo.unionRank)
        if itemTb then
            local items
            for _, itemInfo in ipairs(itemTb) do
                items = items or {}
                items[#items+1] = {itemInfo[1], itemInfo[2]}
            end
            if items then
                awardObjArr[#awardObjArr+1] = {playerUuid, items, AnotherWorldBattleDefine.AB_UNIONRANK_AWARD_MAIL_ID, unionOccupyInfo.unionRank}
            end
        end


        -- 玩家排名奖励
        -- local itemId2, itemNum2 = getRankAward(rankReward, 2, playerRank)
        -- if itemId2 and itemNum2 then
        --     awardObjArr[#awardObjArr+1] = {playerUuid, {{itemId2, itemNum2}}, AnotherWorldBattleDefine.AB_PLAYERRANK_AWARD_MAIL_ID, playerRank}
        -- end

        itemTb = getRankAward(rankReward, 2, playerRank)
        if itemTb then
            local items
            for _, itemInfo in ipairs(itemTb) do
                items = items or {}
                items[#items+1] = {itemInfo[1], itemInfo[2]}
            end

            if items then
                awardObjArr[#awardObjArr+1] = {playerUuid, items, AnotherWorldBattleDefine.AB_PLAYERRANK_AWARD_MAIL_ID, playerRank}
            end
        end
    end

    return awardObjArr, occupyCityInfo
end



-- 活动是否处于开启中
function IsRuning(joinTime)
    if not joinTime then
        return true
    end

    local wDay = getWDay()
    if wDay > AnotherWorldBattleDefine.AB_OPEN_WDAY_AREA[2] and wDay < AnotherWorldBattleDefine.AB_OPEN_WDAY_AREA[1] then
        return false
    end

    local now = os.time()
    local toDayStartTime = Util.getDayStartTime(now)
    if AnotherWorldBattleDefine.AB_BATTLE_WDAY_AREA[2] == wDay and now > (toDayStartTime + AnotherWorldBattleDefine.AB_BATTLE_END_SEC) then
        return false
    end


    local diffDays = Util.diffDay(joinTime)
    -- local joinWday = Util.getWeekDay(joinTime)

    -- 如果是周六加入则相差6天, 如果是周日加入则相差5天。 当前时间与加入时间相差6或5天, 则都表示当前可能是活动最后一天, 如果当前时间 > 结束时间则活动结束
    -- if (diffDays == AnotherWorldBattleDefine.AB_OPEN_DAYS and joinWday == 7) or (diffDays == (AnotherWorldBattleDefine.AB_OPEN_DAYS-1) and joinWday == 1) then
    --     if now > (toDayStartTime + AnotherWorldBattleDefine.AB_BATTLE_END_SEC) then
    --         return false
    --     end
    -- end

    -- < 6天说明处于本轮活动开启时间范围, > 6天说明活动已经结束
    if diffDays > AnotherWorldBattleDefine.AB_OPEN_DAYS then
        return false
    end

    return true
end

--检测上阵英雄
function checkUpdatePos(human, msg)
    local heroList = Util.split(msg.heroList, ",")
    for i = 1, CombatDefine.COMBAT_HERO_CNT do
        local uuid = heroList[i] or ""
        if uuid ~= "0" and uuid ~= "" then
            if isDefHero(human, uuid) then
                return false
            end
        end

    end
    return true
end

-- 公会战力更新
function UnionPowerChange(unionId, newPower)
    if not actStartTimeCheck() then
        return false
    end

    local msgData = InnerMsg.lw.LW_ANOTHERWORLDBATTLE_UPDATE_UNION
    msgData.myUnionId = unionId
    msgData.updateData = {}
    msgData.updateData.power = newPower
    InnerMsg.sendMsg(0, msgData)
end

-- 玩家战力更新
function PlayerPowerChange(human)
    if not human.db.anotherWorlBattle then
        return
    end

    if not baseCondCheck(human) then
        return false
    end

    if not actStartTimeCheck() then
        return false
    end

    local msgData = InnerMsg.lw.LW_ANOTHERWORLDBATTLE_UPDATE_PLAYER
    msgData.playerUuid = human.db._id
    msgData.myUnionId = human.db.unionUuid
    msgData.updateData = {}
    msgData.updateData.power = human.db.zhandouli
    InnerMsg.sendMsg(0, msgData)
end

-- 英雄更新
function HeroDataUpdate(human, heroUuid)
    if not baseCondCheck(human) then
        return false
    end

    if not actStartTimeCheck() then
        return false
    end

    local cityId, pointIdx = isDefHero(human, heroUuid)
    if not cityId then
        return
    end

    HeroLogic = HeroLogic or require("hero.HeroLogic")
    local heroGrid = HeroLogic.getHeroGridByUuid(human, heroUuid)
    if heroGrid then
        RoleAttr.calcHeroGrid(heroGrid, nil, human)
        local heroInfo = {
            heroUuid  = heroUuid,
            heroStar  = heroGrid.star,
            heroLevel = heroGrid.lv,
            heroPower = heroGrid.zhandouli,
        }

        local msgData = InnerMsg.lw.LW_ANOTHERWORLDBATTLE_UPDATE_HERO
        msgData.playerUuid = human.db._id
        msgData.targetCityId = cityId
        msgData.targetPointIdx = pointIdx
        msgData.heroData = heroInfo
        InnerMsg.sendMsg(0, msgData)
    end
end

-- 玩家改名
function PlayerChangeName(human)
    if not human.db.anotherWorlBattle then
        return
    end

    if not baseCondCheck(human) then
        return false
    end

    if not actStartTimeCheck() then
        return false
    end

    local msgData = InnerMsg.lw.LW_ANOTHERWORLDBATTLE_UPDATE_PLAYER
    msgData.playerUuid = human.db._id
    msgData.myUnionId = human.db.unionUuid
    msgData.updateData = {}
    msgData.updateData.name = human.db.name
    InnerMsg.sendMsg(0, msgData)
end

-- 公会改名
function UnionChangeName(unionId, newName)
    if not actStartTimeCheck() then
        return false
    end

    local msgData = InnerMsg.lw.LW_ANOTHERWORLDBATTLE_UPDATE_UNION
    msgData.myUnionId = unionId
    msgData.updateData = {}
    msgData.updateData.name = newName
    InnerMsg.sendMsg(0, msgData)
end

function isDot(human)
    if not baseCondCheck(human) then
        return false
    end

    if not actStartTimeCheck() then
        return false
    end

    return true
end

function onLogin(human)
    formationDataCheeck(human)
    sendDefHeroArr(human)
    notifyTips(human)
end




-- 请求状态
function AB_GetState(human, isTips)
    local msgData = InnerMsg.lw.LW_ANOTHERWORLDBATTLE_GET_STATE
    msgData.sourceServerId = Config.SVR_INDEX
    msgData.playerUuid = human.db._id
    msgData.myUnionId = human.db.unionUuid or ""
    msgData.isTips = isTips and 1 or 0

    InnerMsg.sendMsg(0, msgData)
end

-- 报名
function AB_Join(human)
    local unionId = human.db.unionUuid
    local msgRet = Msg.gc.GC_AB_JOIN
    if not unionId then
        msgRet.Joinstate = 3
        return Msg.send(msgRet, human.fd)
    end

    local wDay = getWDay()
    -- if wDay ~= AnotherWorldBattleDefine.AB_JOIN_WDAY then
    --     msgRet.Joinstate = 5
    --     return Msg.send(msgRet, human.fd)
    -- end

    if not table.find(AnotherWorldBattleDefine.AB_JOIN_WDAY_AREA, wDay) then
        msgRet.Joinstate = 5
        return Msg.send(msgRet, human.fd)
    end

    -- 公会战力榜前五才能参加
    if not isTopJoinRankUnion(human) then
        msgRet.Joinstate = 2
        return Msg.send(msgRet, human.fd)
    end

    -- 会长/副会长才能报名
    if not UnionLogic.IsTopTwoManager(human, unionId) then
        return Broadcast.sendErr(human, Lang.AB_NOT_TOPTWO_MANGER)
    end

    local queryFiles = {name = 1, zhandouli = 1}
    local unionInfo = UnionLogic.GetUnionData(unionId, queryFiles)
    if not unionInfo then
        return Broadcast.sendErr(human, Lang.DATA_ERR)
    end

    local msgData = InnerMsg.lw.LW_ANOTHERWORLDBATTLE_JOIN
    msgData.sourceServerId = Config.SVR_INDEX
    msgData.playerUuid = human.db._id
    msgData.unionInfo = {
        name = unionInfo.name,
        power = unionInfo.zhandouli,
        unionId = unionId
    }
    InnerMsg.sendMsg(0, msgData)
end

-- 查询所有城池信息
function AB_AllCity_Query(human)
    if not human.db.unionUuid then
        return
    end
    local msgData = InnerMsg.lw.LW_ANOTHERWORLDBATTLE_ALLCITY_QUERY
    msgData.sourceServerId = Config.SVR_INDEX
    msgData.playerUuid = human.db._id
    msgData.myUnionId = human.db.unionUuid
    InnerMsg.sendMsg(0, msgData)

    -- 报名状态查询
    -- local msgData2 = InnerMsg.lw.LW_ANOTHERWORLDBATTLE_GET_JOIN_STATE
    -- msgData2.sourceServerId = Config.SVR_INDEX
    -- msgData2.playerUuid = human.db._id
    -- msgData2.myUnionId = human.db.unionUuid
    -- InnerMsg.sendMsg(0, msgData2)
end

-- 查询单个城池的详细信息
function AB_CityDetailed_Query(human, targetCityId)
    if not AnotherWorldBattleConfig.city[targetCityId] then
        return Broadcast.sendErr(human, Lang.COMMON_ARGUMENT_ERROR)
    end


    local msgData = InnerMsg.lw.LW_ANOTHERWORLDBATTLE_CITYDETAILED_QUERY
    msgData.sourceServerId = Config.SVR_INDEX
    msgData.playerUuid = human.db._id
    msgData.myUnionId = human.db.unionUuid
    msgData.targetCityId = targetCityId

    InnerMsg.sendMsg(0, msgData)
end

-- 查询某个城池的某个据点的详细信息
function AB_PointDetailed_Query(human, targetCityId, targetPointIdx)
    if not AnotherWorldBattleConfig.city[targetCityId] then
        return Broadcast.sendErr(human, Lang.COMMON_ARGUMENT_ERROR)
    end

    if 0 >= targetPointIdx or AnotherWorldBattleDefine.AB_POINT_MAX_NUM < targetPointIdx then
        return Broadcast.sendErr(human, Lang.COMMON_ARGUMENT_ERROR)
    end


    local msgData = InnerMsg.lw.LW_ANOTHERWORLDBATTLE_POINTtDETAILED_QUERY
    msgData.sourceServerId = Config.SVR_INDEX
    msgData.playerUuid = human.db._id
    msgData.myUnionId = human.db.unionUuid
    msgData.targetCityId = targetCityId
    msgData.targetPointIdx = targetPointIdx

    InnerMsg.sendMsg(0, msgData)
end

-- 查询本公会出生点信息
function AB_BaseCity_Query(human)
    local msgData = InnerMsg.lw.LW_ANOTHERWORLDBATTLE_BASECITY_QUERY
    msgData.sourceServerId = Config.SVR_INDEX
    msgData.playerUuid = human.db._id
    msgData.myUnionId = human.db.unionUuid

    InnerMsg.sendMsg(0, msgData)
end

-- 查询玩家占领的所有据点信息
function AB_PlayerOccupyPOint_Query(human)
    local msgData = InnerMsg.lw.LW_ANOTHERWORLDBATTLE_PLAYEROCCUPYPOINT_QUERY
    msgData.sourceServerId = Config.SVR_INDEX
    msgData.playerUuid = human.db._id
    msgData.myUnionId = human.db.unionUuid

    InnerMsg.sendMsg(0, msgData)
end

-- 查询公会排行榜
function AB_UnionRank_Query(human)
    local msgData = InnerMsg.lw.LW_ANOTHERWORLDBATTLE_UNIONRANK_QUERY
    msgData.sourceServerId = Config.SVR_INDEX
    msgData.playerUuid = human.db._id
    msgData.myUnionId = human.db.unionUuid

    InnerMsg.sendMsg(0, msgData)
end

-- 查询玩家排行榜
function AB_PlayerRank_Query(human)
    local msgData = InnerMsg.lw.LW_ANOTHERWORLDBATTLE_PLAYERRANK_QUERY
    msgData.sourceServerId = Config.SVR_INDEX
    msgData.playerUuid = human.db._id
    msgData.myUnionId = human.db.unionUuid

    InnerMsg.sendMsg(0, msgData)
end

-- 发起集结
function AB_Gather(human, targetCityId, opType)
    if not AnotherWorldBattleConfig.city[targetCityId] then
        return Broadcast.sendErr(human, Lang.COMMON_ARGUMENT_ERROR)
    end

    if opType ~= 1 and opType ~= 2 then
        return Broadcast.sendErr(human, Lang.COMMON_ARGUMENT_ERROR)
    end

    local unionId = human.db.unionUuid
    if not unionId then
        return Broadcast.sendErr(human, Lang.AB_NO_UNION)
    end

    -- 会长/副会长才能集结
    if not UnionLogic.IsTopTwoManager(human, unionId) then
        return Broadcast.sendErr(human, Lang.AB_NOT_TOPTWO_MANAGER)
    end

    local msgData = InnerMsg.lw.LW_ANOTHERWORLDBATTLE_GATHER
    msgData.sourceServerId = Config.SVR_INDEX
    msgData.playerUuid = human.db._id
    msgData.myUnionId = human.db.unionUuid
    msgData.targetCityId = targetCityId
    msgData.opType = opType

    InnerMsg.sendMsg(0, msgData)
end

-- 请求挑战某个据点
function AB_TryChallengePoint(human, targetCityId, targetPointIdx)
    local combatHero = CombatPosLogic.getCombatHeros(human, CombatDefine.COMBAT_TYPE35)
    if not combatHero or not next(combatHero) then
        return Broadcast.sendErr(human, Lang.COMBAT_NEED_FIGHT_HERO)
    end

    local msgData = InnerMsg.lw.LW_ANOTHERWORLDBATTLE_POINT_ISCAN_CHALLENGE
    msgData.sourceServerId = Config.SVR_INDEX
    msgData.playerUuid = human.db._id
    msgData.myUnionId = human.db.unionUuid
    msgData.targetCityId = targetCityId
    msgData.targetPointIdx = targetPointIdx

    InnerMsg.sendMsg(0, msgData)
end

-- 战斗结束
local function challenge_End(human, args)
    local cityId = args.cityId
    local pointIdx = args.pointIdx

    local msgData = InnerMsg.lw.LW_ANOTHERWORLDBATTLE_POINT_CHALLENGE_END
    msgData.sourceServerId = Config.SVR_INDEX
    msgData.playerUuid = human.db._id
    msgData.myUnionId = human.db.unionUuid
    msgData.targetCityId = cityId
    msgData.targetPointIdx = pointIdx
    msgData.challengeRes = args.challengeRes

    -- 挑战没有胜利
    if args.challengeRes ~= CombatDefine.RESULT_WIN then
        -- 说明之前已经在跨服上保存玩家的基础数据了
        -- if human.db.anotherWorlBattle then
        --     return
        -- end

        msgData.playerShowInfo = {
            name = human.db.name,
            lv = human.db.lv,
            power = human.db.zhandouli,
        }
        return InnerMsg.sendMsg(0, msgData)
    end


    if not human.db.anotherWorlBattle then
        human.db.anotherWorlBattle = {
            startTime = os.time(),
            formation = {}
        }
    end

    -- 把当前战斗阵容数据保存到当前模块，作为防守阵容
    local combatData = CombatPosLogic.getCombatHeroDB(human, CombatDefine.COMBAT_TYPE35)
    local formationData = human.db.anotherWorlBattle.formation or {}
    formationData[cityId] = formationData[cityId] or {}
    formationData[cityId][pointIdx] = Util.copyTable(combatData)

    -- 把最新的防守英雄uuid列表推送给客户端
    sendDefHeroArr(human)

    --同步到跨服
    msgData.playerShowInfo = generateShowInfo(human)
    InnerMsg.sendMsg(0, msgData)

    -- 清空战斗阵容
    CombatPosLogic.cleanCombatHeros(human, CombatDefine.COMBAT_TYPE35)
end

-- 更换据点的防守阵容
function AB_UpdateLineup(human, msg)
    if not isBattleStage() then
        return Broadcast.sendErr(human, Lang.AB_NOT_BATTLE_TIME)
    end

    local anotherWorlBattle = human.db.anotherWorlBattle
    if not anotherWorlBattle or not anotherWorlBattle.formation then
        return Broadcast.sendErr(human, Lang.AB_NOT_OCCUPY_POINT)
    end

    local cityId = msg.cityId
    local pointIdx = msg.pointIdx
    local formationData = anotherWorlBattle.formation
    if not formationData[cityId] or not formationData[cityId][pointIdx] then
        return Broadcast.sendErr(human, Lang.AB_NOT_OCCUPY_TARGET_POINT)
    end

    local res, heroList, helpList = CombatPosLogic.CheckUpdatePos(human, msg)
    if not res then
        return Broadcast.sendErr(human, Lang.COMBAT_POS__ERR)
    end

    local len = 0
    local heroArr = {}
    for i = 1, CombatDefine.COMBAT_HERO_CNT do
        local uuid = heroList[i] or ""
        if uuid ~= "0" and uuid ~= "" then
            if isDefHero(human, uuid, cityId, pointIdx) then
                return Broadcast.sendErr(human, Lang.AB_HERO_IN_OTHER_POINT)
            end

            len = len + 1
            heroArr[len] = getHeroInfo(human, uuid)
        end
    end

    if len == 0 then
        return
    end

    local msgData = InnerMsg.lw.LW_ANOTHERWORLDBATTLE_UPDATE_POINT_LINEIP
    msgData.sourceServerId = Config.SVR_INDEX
    msgData.playerUuid = human.db._id
    msgData.heroArr = heroArr
    msgData.targetCityId = cityId
    msgData.targetPointIdx = pointIdx
    msgData.formation = msg.formation
    msgData.heroList = heroList
    msgData.helpList = helpList

    InnerMsg.sendMsg(0, msgData)
end

-- 放弃据点
function AB_LeavePoint(human, msg)
    local targetCityId = msg.cityId
    if not AnotherWorldBattleConfig.city[targetCityId] then
        return Broadcast.sendErr(human, Lang.COMMON_ARGUMENT_ERROR)
    end

    local targetPointIdx = msg.pointIdx
    if targetPointIdx <= 0 or targetPointIdx > AnotherWorldBattleDefine.AB_POINT_MAX_NUM then
        return Broadcast.sendErr(human, Lang.COMMON_ARGUMENT_ERROR)
    end

    local msgData = InnerMsg.lw.LW_ANOTHERWORLDBATTLE_LEAVE_POINT
    msgData.sourceServerId = Config.SVR_INDEX
    msgData.playerUuid = human.db._id
    msgData.myUnionId = human.db.unionUuid
    msgData.targetCityId = targetCityId
    msgData.targetPointIdx = targetPointIdx

    InnerMsg.sendMsg(0, msgData)
end

--获取据点的防守阵容数据
function AB_GetPointLineup(human, msg)
    local targetCityId = msg.cityId
    local targetPointIdx = msg.pointIdx

    local anotherWorlBattle = human.db.anotherWorlBattle
    local formationData = anotherWorlBattle.formation
    if not formationData[targetCityId] or not formationData[targetCityId][targetPointIdx] then
        return Broadcast.sendErr(human, Lang.AB_NOT_OCCUPY_TARGET_POINT)
    end

    local extraArgs = {
        cityId = targetCityId,
        pointIdx = targetPointIdx
    }
    CombatPosLogic.posQuery(human, msg.type, msg.groupID, msg.param, 1, extraArgs)
end

-- 请求公会士气信息
function AB_GetMyUnionMoraleInfo(human)
    local msgData = InnerMsg.lw.LW_ANOTHERWORLDBATTLE_GET_MYUIONMORALE
    msgData.sourceServerId = Config.SVR_INDEX
    msgData.playerUuid = human.db._id
    msgData.myUnionId = human.db.unionUuid

    InnerMsg.sendMsg(0, msgData)
end

-- 给本公会加士气
function AB_Morale_Do(human)
    local unionId = human.db.unionUuid
    if not UnionLogic.IsTopTwoManager(human, unionId) then
        return Broadcast.sendErr(human, Lang.AB_NOT_TOPTWO_MANGER)
    end

    -- 先扣除道具
    local moraleCostCfg = AnotherWorldBattleConfig.var[1].moraleCost
    if not moraleCostCfg then
        return  Broadcast.sendErr(human, Lang.COMMON_COMFIG_ERROR)
    end
    local itemId, itemNum = moraleCostCfg[1], moraleCostCfg[2]
    if BagLogic.getItemCnt(human, itemId) < itemNum then
        return Broadcast.sendErr(human, COMMON_ITEM_NOT_ENOUGH)
    end
    BagLogic.delItem(human, itemId, itemNum, LOGTAG)

    local msgData = InnerMsg.lw.LW_ANOTHERWORLDBATTLE_UIONMORALE_DO
    msgData.sourceServerId = Config.SVR_INDEX
    msgData.playerUuid = human.db._id
    msgData.myUnionId = human.db.unionUuid

    InnerMsg.sendMsg(0, msgData)
end

-- 查询据点羁绊数据
function AB_PointLine_JiBan_Query(human, msg)
    if not isBattleStage() then
        return
    end

    JibanLogic = JibanLogic or require("combat.JibanLogic")

    local extraArgs = {
        cityId = msg.cityId,
        pointIdx = msg.pointIdx,
    }
    JibanLogic.query(human, msg.combatType, msg.heroID, extraArgs)
end

-- 更新据点羁绊
function AB_PointLine_JiBan_Update(human, msg)
    if not isBattleStage() then
        return
    end

    JibanLogic = JibanLogic or require("combat.JibanLogic")

    local extraArgs = {
        cityId = msg.cityId,
        pointIdx = msg.pointIdx,
    }
    JibanLogic.update(human, msg.combatType, msg.jibanList, msg.heroIdArr, extraArgs)
end

-- 查询据点精灵数据
function AB_PointLine_Elf_Query(human, msg)
    if not isBattleStage() then
        return
    end
    local extraArgs = {
        cityId = msg.cityId,
        pointIdx = msg.pointIdx,
    }
    CombatPosLogic.Elf_Pos_Query(human, msg.combatType, extraArgs)
end

-- 更新据点精灵
function AB_PointLine_Elf_Update(human, msg)
    if not isBattleStage() then
        return
    end

    local extraArgs = {
        cityId = msg.cityId,
        pointIdx = msg.pointIdx,
    }
    CombatPosLogic.Elf_Pos_Update(human, msg.combatType, msg.elfPosArr, extraArgs)
end

------------------------------------C2N---------------------------------------------------

-- 跨服通知活动开启
function C2N_Act_Start(msg)
    local startTime = msg.startTime

    if not startTime or startTime == 0 then
        return
    end

    CommonDB.updateValue(CommonDB.KEY_ANOTHERWORLDBATTLE_START_TI, startTime)
end

-- 错误提示
function C2N_ErrTips(msg)
    local human = ObjHuman.onlineUuid[msg.playerUuid]
    if not human then
        return
    end

    local tips = Lang.DATA_ERR
    local errCode = msg.errCode
    if errCode == AnotherWorldBattleDefine.ERR_CODE_1 then
        tips = Lang.AB_NOT_OPEN_TIME
    elseif errCode == AnotherWorldBattleDefine.ERR_CODE_2 then
        tips = Lang.AB_NOT_UNION_NUM_EXCEED
    elseif errCode == AnotherWorldBattleDefine.ERR_CODE_3 then
        tips = Lang.AB_UNION_NO_JOIN
    elseif errCode == AnotherWorldBattleDefine.ERR_CODE_4 then
        tips = Lang.DATA_ERR
    elseif errCode == AnotherWorldBattleDefine.ERR_CODE_5 then
        tips = Lang.AB_NOT_OCCUPY_POINT
    elseif errCode == AnotherWorldBattleDefine.ERR_CODE_6 then
        tips = Lang.AB_GATHER_CD
    elseif errCode == AnotherWorldBattleDefine.ERR_CODE_7 then
        tips = Lang.AB_CITY_NOT_ADDJION
    elseif errCode == AnotherWorldBattleDefine.ERR_CODE_8 then
        tips = Lang.AB_JOINED
    elseif errCode == AnotherWorldBattleDefine.ERR_CODE_9 then
        tips = Lang.AB_CITY_NO_GATHER
    elseif errCode == AnotherWorldBattleDefine.ERR_CODE_10 then
        tips = Lang.AB_OCCUPY_POINT_MAX
    elseif errCode == AnotherWorldBattleDefine.ERR_CODE_11 then
        tips = Lang.AB_POINT_CHALLENGING
    elseif errCode == AnotherWorldBattleDefine.ERR_CODE_12 then
        tips = Lang.AB_CHALLENGING_TIMES_NOT_ENOUGH
    end

    Broadcast.sendErr(human, tips)
end

-- 跨服返回状态
function C2N_State_Response(msg)
    local human = ObjHuman.onlineUuid[msg.playerUuid]
    if not human then
        return
    end

    -- 只用于弹出提示框
    if msg.isTips and msg.isTips == 1 then
        if (msg.systemState > 0 and msg.systemState <= 2) and msg.joinState <= 1 then
            local msgRet = Msg.gc.GC_AB_TIPS
            Msg.send(msgRet, human.fd)
        end

        return
    end

    local msgRet = Msg.gc.GC_AB_GetState
    msgRet.joinState = msg.joinState
    msgRet.systemState = msg.systemState

    if msgRet.joinState == 0 then
        local unionId = human.db.unionUuid
        if not unionId then
            msgRet.Joinstate = 2
            return Msg.send(msgRet, human.fd)
        end

        -- 公会战力榜前五才行
        if not isTopJoinRankUnion(human) then
            msgRet.Joinstate = 2
            return Msg.send(msgRet, human.fd)
        end
    end

    Msg.send(msgRet, human.fd)
end

-- 报名成功
function C2N_Join_Response(msg)
    local now = os.time()
    local unionId = msg.myUnionId
    UnionLogic.UpdateJoinAbTime(unionId, now)


    local human = ObjHuman.onlineUuid[msg.playerUuid]
    if not human then
        return
    end

    local msgRet = Msg.gc.GC_AB_JOIN
    msgRet.Joinstate = 1
    Msg.send(msgRet, human.fd)
end

-- 跨服返回的所有城池数据
function C2N_AllCity_Response(msg)
    local human = ObjHuman.onlineUuid[msg.playerUuid]
    if not human then
        return
    end

    local msgRet = Msg.gc.GC_AB_ALLCITY_QUERY
    msgRet.myBaseCityId = msg.myUnionBaseCityId
    msgRet.hasPointNum = msg.hasPointNum
    msgRet.challengeTimes = msg.challengeTimes
    local now = os.time()
    msgRet.leftTime = msg.lastTime
    if msgRet.leftTime ~= 0 then
        msgRet.leftTime = (msg.lastTime + AnotherWorldBattleDefine.AB_PLAYER_CHALLENGETIMES_SEC) - now
    end

    msgRet.cityArr[0] = 0
    local cityArrMsg = msgRet.cityArr

    for cityId, cityInfo in ipairs(msg.cityArr) do
        cityArrMsg[0] = cityId
        local cityCfg = AnotherWorldBattleConfig.city[cityId]
        cityArrMsg[cityId].cityId = cityId
        cityArrMsg[cityId].cityName = cityCfg.cityName
        cityArrMsg[cityId].cityLv = cityCfg.cityLv
        cityArrMsg[cityId].occupyPointNum = cityInfo.occupyPointNum or 0
        cityArrMsg[cityId].occupyUnionName = cityInfo.occupyUnionName or ""
        cityArrMsg[cityId].cityState = cityInfo.cityState

        cityArrMsg[cityId].adJoinCityArr[0] = #cityCfg.adJoinCityArr
        for i, cId in ipairs(cityCfg.adJoinCityArr) do
            cityArrMsg[cityId].adJoinCityArr[i] = cId
        end
    end

    msgRet.myOccupyCityArr[0] = #msg.myOccupyCityArr
    for i, cityId in ipairs(msg.myOccupyCityArr) do
        msgRet.myOccupyCityArr[i] = cityId
    end


    -- 占领据点奖励
    local itemId, itemNum = 0, 0
    local cityCfg = AnotherWorldBattleConfig.city[1]
    itemId = cityCfg.cityAward[1]

    for _, pointInfo in ipairs(msg.occupyPointData) do
        local cityId = pointInfo[1]
        local occupyTimeArr = pointInfo[2]
        local cityCfg = AnotherWorldBattleConfig.city[cityId]

        local minuteVal = 0
        for _, timeTb in ipairs(occupyTimeArr) do
            local sec = (timeTb[2] or now) - (timeTb[1] or now)
            if sec > 0 then
                minuteVal = minuteVal + sec
            end

            minuteVal = math.floor(minuteVal / 60)
        end

        itemNum = itemNum + minuteVal * cityCfg.cityAward[2]
    end

    local itemNumMax = calcRewardMax()
    local isRun = actStartTimeCheck()
    local isBattle = isBattleStage()
    if isRun and isBattle then
        itemNumMax = calcRewardNow()
    end
    if itemNumMax > 0 then
        itemNum = math.min(itemNum, itemNumMax)
    end

    Grid.makeItem(msgRet.myUnionAward, itemId, itemNum)

    Msg.send(msgRet, human.fd)
end

-- 跨服返回某个城池详细数据
function C2N_CityDetailed_Response(msg)
    local human = ObjHuman.onlineUuid[msg.playerUuid]
    if not human then
        return
    end

    local cityCfg = AnotherWorldBattleConfig.city[msg.targetCityId]
    local msgRet = Msg.gc.GC_AB_CITY_DETAILED_QUERY

    msgRet.cityId = msg.targetCityId
    msgRet.cityLv = cityCfg.cityLv
    msgRet.cityIconId = cityCfg.cityIconId
    Grid.makeItem(msgRet.cityAward, cityCfg.cityAward[1], cityCfg.cityAward[2] * AnotherWorldBattleDefine.AB_POINT_MAX_NUM )

    local myUnionAwardNum = calcPointAward(msg.myUnionOccupyArr)
    Grid.makeItem(msgRet.myUnionAward, cityCfg.cityAward[1], myUnionAwardNum)

    -- 活动没有进入战斗阶段时, 使用默认数据
    if #msg.pointArr == 0 then
        for i=1, AnotherWorldBattleDefine.AB_POINT_MAX_NUM do
            msg.pointArr[i] = {}
        end
    end

    msgRet.pointArr[0] = AnotherWorldBattleDefine.AB_POINT_MAX_NUM
    for pointIdx, pointInfo in ipairs(msg.pointArr) do
        if pointInfo.occupyUnionName then
            msgRet.pointArr[pointIdx].occupyUnionName = pointInfo.occupyUnionName
            msgRet.pointArr[pointIdx].occupyPlayerName = pointInfo.occupyPlayerName
            msgRet.pointArr[pointIdx].power = pointInfo.power
            msgRet.pointArr[pointIdx].state = pointInfo.state
        else
            msgRet.pointArr[pointIdx].occupyUnionName = ""
            msgRet.pointArr[pointIdx].occupyPlayerName = AnotherWorldBattleDefine.AB_DEF_NAME_STR.. pointIdx
            msgRet.pointArr[pointIdx].power = calcMonsterPower(cityCfg.pointMonsterId)
            msgRet.pointArr[pointIdx].state = pointInfo.state
        end

    end

    msgRet.gatherState = msg.gatherState
    if msg.gatherState == 1 then
        -- 公会会长/副会长才能集结
        if not UnionLogic.IsTopTwoManager(human, human.db.unionUuid) then
            msgRet.gatherState = 0
        end
    end

    msgRet.gatherLeftTime = msg.gatherTime
    if msg.gatherTime ~= -1 then
        local now = os.time()
        local subSec = msg.gatherTime + AnotherWorldBattleDefine.AB_GATHER_CD_SEC - now
        msgRet.gatherLeftTime = subSec > 0 and subSec or 0
    end

    Msg.send(msgRet, human.fd)
end

-- 跨服返回某个据点数据
function C2N_PointDetailed_Response(msg)
    local human = ObjHuman.onlineUuid[msg.playerUuid]
    if not human then
        return
    end

    local pointInfo = msg.pointInfo
    local msgRet = Msg.gc.GC_AB_POINT_DETAILEDINFO_QUERY
    msgRet.state = pointInfo.state

    if pointInfo.name then
        msgRet.name = pointInfo.name
        msgRet.power = pointInfo.power
        msgRet.head = pointInfo.head
        msgRet.headFrame = pointInfo.headFrame
        msgRet.defLv = pointInfo.defLv

        msgRet.heroArr[0] = #pointInfo.heroArr
        for i, heroInfo in ipairs(pointInfo.heroArr) do
            msgRet.heroArr[i].heroBody = heroInfo.heroBody
            msgRet.heroArr[i].heroStar = heroInfo.heroStar
            msgRet.heroArr[i].heroLv = heroInfo.heroLv
            msgRet.heroArr[i].heroCamp = heroInfo.heroCamp
            msgRet.heroArr[i].heroIcon = heroInfo.heroIcon
            msgRet.heroArr[i].heroId = heroInfo.heroId
            msgRet.heroArr[i].heroQuality = heroInfo.heroQuality
        end
    else
        msgRet.name = AnotherWorldBattleDefine.AB_DEF_NAME_STR .. msg.targetPointIdx
        msgRet.head = getDefaultShowId(1, msg.targetPointIdx)
        msgRet.headFrame = getDefaultShowId(2, msg.targetPointIdx)
        msgRet.defLv = 200
        local cityCfg = AnotherWorldBattleConfig.city[msg.targetCityId]
        msgRet.power = calcMonsterPower(cityCfg.pointMonsterId)

        msgRet.heroArr[0] = 0
        local monsterOutConfig = MonsterExcel.monsterOut[cityCfg.pointMonsterId]
        for idx, monsterInfo in ipairs(monsterOutConfig.member) do
            if idx > 6 then
                break
            end

            msgRet.heroArr[0] = idx
            local monsterID = monsterInfo[1]
            local mcf = MonsterExcel.monster[monsterID]
            msgRet.heroArr[idx].heroBody = mcf.body
            msgRet.heroArr[idx].heroStar = mcf.star
            msgRet.heroArr[idx].heroLv = monsterInfo[2]
            msgRet.heroArr[idx].heroCamp = mcf.camp
            msgRet.heroArr[idx].heroIcon = mcf.head
            msgRet.heroArr[idx].heroId = monsterID
            msgRet.heroArr[idx].heroQuality = mcf.heroQuality or 1
        end
    end

    Msg.send(msgRet, human.fd)
end

-- 跨服返回公会出生点数据
function C2N_BaseCity_Response(msg)
    local human = ObjHuman.onlineUuid[msg.playerUuid]
    if not human then
        return
    end

    local baseCityInfo = msg.baseCityInfo
    local msgRet = Msg.gc.GC_AB_BASECITY_QUERY

    local cityCfg = AnotherWorldBattleConfig.city[baseCityInfo.cityId]
    msgRet.cityIconId = cityCfg.cityIconId
    Grid.makeItem(msgRet.cityAward, cityCfg.cityAward[1], cityCfg.cityAward[2] * AnotherWorldBattleDefine.AB_POINT_MAX_NUM)

    local myUnionAwardNum = calcPointAward(baseCityInfo.myUnionOccupyArr)
    Grid.makeItem(msgRet.myUnionAward, cityCfg.cityAward[1], myUnionAwardNum)

    -- msgRet.cityIconId = baseCityInfo.occupyPointNum
    msgRet.occupyPointNum = baseCityInfo.occupyPointNum
    msgRet.occupyCityLv2Num = baseCityInfo.occupyCityLv2Num
    msgRet.occupyCityLv3Num = baseCityInfo.occupyCityLv3Num
    msgRet.occupyCityLv4Num = baseCityInfo.occupyCityLv4Num
    msgRet.occupyCityLv5Num = baseCityInfo.occupyCityLv5Num
    Msg.send(msgRet, human.fd)
end

-- 跨服返回玩家占领的据点数据
function C2N_PlayerOccupyPoint_Response(msg)
    local human = ObjHuman.onlineUuid[msg.playerUuid]
    if not human then
        return
    end

    local msgRet = Msg.gc.GC_AB_MY_OCCUPY_POINT_QUERY
    local myPointArr = msgRet.myPointArr
    myPointArr[0] = 0

    for idx, pointInfo in ipairs(msg.occupyPointArr) do
        myPointArr[0] = idx
        local cityCfg = AnotherWorldBattleConfig.city[pointInfo.cityId]
        myPointArr[idx].cityIconId = cityCfg.cityIconId
        myPointArr[idx].cityName = cityCfg.cityName
        myPointArr[idx].cityLv = cityCfg.cityLv
        myPointArr[idx].pointIdx = pointInfo.pointIdx
        myPointArr[idx].power = pointInfo.power
        myPointArr[idx].cityId = pointInfo.cityId

        myPointArr[idx].heroArr[0] = #pointInfo.heroArr
        for heroIdx, heroInfo in ipairs(pointInfo.heroArr) do
            local hero = myPointArr[idx].heroArr[heroIdx]
            hero.heroBody = heroInfo.heroBody
            hero.heroStar = heroInfo.heroStar
            hero.heroLv = heroInfo.heroLv
            hero.heroCamp = heroInfo.heroCamp
            hero.heroIcon = heroInfo.heroIcon
            hero.heroId = heroInfo.heroId
            hero.heroQuality = heroInfo.heroQuality
        end
    end

    Msg.send(msgRet, human.fd)
end

-- 跨服返回集结/取消集结成功
function C2N_Gather_Response(msg)
    local human = ObjHuman.onlineUuid[msg.playerUuid]
    if not human then
        return
    end

    local targetCityId = msg.targetCityId
    local cityCfg = AnotherWorldBattleConfig.city[targetCityId]
    local msgRet = Msg.gc.GC_AB_GARHER
    msgRet.cityId = targetCityId
    msgRet.cityName = cityCfg.cityName
    msgRet.opType = msg.opType

    Msg.send(msgRet, human.fd)
end

--跨服返回公会排行榜数据
function C2N_UnionRank_Response(msg)
    local human = ObjHuman.onlineUuid[msg.playerUuid]
    if not human then
        return
    end

    -- local itemId, itemNum = 184, 0
    local rankReward = AnotherWorldBattleConfig.rankReward
    local itemArr = getRankGenericAwadId(rankReward, 1)

    local msgRet = Msg.gc.GC_AB_UNION_RANK_QUERY
    msgRet.unionRankArr[0] = 0
    msgRet.myUnionRank = msg.myUnionRank
    msgRet.myData.name = ""
    msgRet.myData.power = 0
    msgRet.myData.cityNum = 0
    msgRet.myData.pointNum = 0

    msgRet.myData.rankAward[0] = 0
    for i, itemInfo in ipairs(itemArr or {}) do
        msgRet.myData.rankAward[0] = i
        Grid.makeItem(msgRet.myData.rankAward[i], itemInfo[1], itemInfo[2])
    end

    for rank, rankdData in ipairs(msg.unionRankArr) do
        msgRet.unionRankArr[0] = rank
        msgRet.unionRankArr[rank].name = rankdData.name
        msgRet.unionRankArr[rank].power = rankdData.power
        msgRet.unionRankArr[rank].cityNum = rankdData.cityNum
        msgRet.unionRankArr[rank].pointNum = rankdData.pointNum

        -- Grid.makeItem(msgRet.unionRankArr[rank].rankAward, itemId, itemNum)
        msgRet.unionRankArr[rank].rankAward[0] = 0
        itemArr = getRankAward(rankReward, 1, rank)
        for i, itemInfo in ipairs(itemArr or {}) do
            msgRet.unionRankArr[rank].rankAward[0] = i
            Grid.makeItem(msgRet.unionRankArr[rank].rankAward[i], itemInfo[1], itemInfo[2])
        end

        if rank == msg.myUnionRank then
            msgRet.myData.name = rankdData.name
            msgRet.myData.power = rankdData.power
            msgRet.myData.cityNum = rankdData.cityNum
            msgRet.myData.pointNum = rankdData.pointNum
            -- Grid.makeItem(msgRet.myData.rankAward, itemId, itemNum)
            msgRet.myData.rankAward[0] = 0
            for i, itemInfo in ipairs(itemArr or {}) do
                msgRet.myData.rankAward[0] = i
                Grid.makeItem(msgRet.myData.rankAward[i], itemInfo[1], itemInfo[2])
            end
        end
    end

    if msgRet.myData.power == 0 then
        local unionId = human.db.unionUuid
        local queryFiles = {name = 1, zhandouli = 1}
        local unionInfo = UnionLogic.GetUnionData(unionId, queryFiles)
        msgRet.myData.name = unionInfo and unionInfo.name or ""
        msgRet.myData.power = unionInfo and unionInfo.zhandouli or 0
    end

    Msg.send(msgRet, human.fd)
end

--跨服返回玩家排行榜数据
function C2N_PlayerRank_Response(msg)
    local human = ObjHuman.onlineUuid[msg.playerUuid]
    if not human then
        return
    end

    -- local itemId, itemNum = 184, 0
    local rankReward = AnotherWorldBattleConfig.rankReward
    local itemArr = getRankGenericAwadId(rankReward, 2)

    local msgRet = Msg.gc.GC_AB_PLAYER_RANK_QUERY
    msgRet.playerRankArr[0] = 0
    msgRet.myRank = msg.myRank
    msgRet.myData.name = human.db.name
    msgRet.myData.power = human.db.zhandouli
    msgRet.myData.pointNum = 0
    msgRet.myData.pointWeight = 0
    msgRet.myData.rankAward[0] = 0
    for i, itemInfo in ipairs(itemArr or {}) do
        msgRet.myData.rankAward[0] = i
        Grid.makeItem(msgRet.myData.rankAward[i], itemInfo[1], itemInfo[2])
    end

    for rank, rankdData in ipairs(msg.playerRankArr) do
        msgRet.playerRankArr[0] = rank
        msgRet.playerRankArr[rank].name = rankdData.name
        msgRet.playerRankArr[rank].power = rankdData.power
        msgRet.playerRankArr[rank].pointNum = rankdData.pointNum
        msgRet.playerRankArr[rank].pointWeight = rankdData.pointWeight

        -- itemId, itemNum = getRankAward(rankReward, 2, rank)
        -- Grid.makeItem(msgRet.playerRankArr[rank].rankAward, itemId, itemNum)
        itemArr = getRankAward(rankReward, 2, rank)
        msgRet.playerRankArr[rank].rankAward[0] = 0
        for i, itemInfo in ipairs(itemArr or {}) do
            msgRet.playerRankArr[rank].rankAward[0] = i
            Grid.makeItem(msgRet.playerRankArr[rank].rankAward[i], itemInfo[1], itemInfo[2])
        end

        if rank == msg.myRank then
            msgRet.myData.pointNum = rankdData.pointNum
            msgRet.myData.pointWeight = rankdData.pointWeight
            -- Grid.makeItem(msgRet.myData.rankAward, itemId, itemNum)
            msgRet.myData.rankAward[0] = 0
            for i, itemInfo in ipairs(itemArr or {}) do
                msgRet.myData.rankAward[0] = i
                Grid.makeItem(msgRet.myData.rankAward[i], itemInfo[1], itemInfo[2])
            end
        end
    end

    Msg.send(msgRet, human.fd)
end

-- 跨服返回要挑战的据点的数据(据点可以被挑战)
function C2N_TryChallengePoint_Response(msg)
    local human = ObjHuman.onlineUuid[msg.playerUuid]
    if not human then
        return
    end

    local pointInfo = msg.pointInfo
    human.AB_Battle_Cache = {
        isGather = pointInfo.isGather,
        cityId = pointInfo.targetCityId,
        pointIdx = pointInfo.targetPointIdx,
        defMoraleAttrIdx = pointInfo.defMoraleAttrIdx,
        atkMoraleAttrIdx = pointInfo.atkMoraleAttrIdx,
    }

    if pointInfo.occupySrvId then -- 玩家占领
        local args = {
            combatType = CombatDefine.COMBAT_TYPE35,
            nServerIndex = pointInfo.occupySrvId,
            param = pointInfo.occupyPlayerUuid,
            extraArgs = {
                cityId = pointInfo.targetCityId,
                pointIdx = pointInfo.targetPointIdx,
                useDef = true,
            }
        }
        MiddleCommonLogic.MiddleCommonLogic_CombatBegin_LW(human, args)
    else
        -- 机器人
        CombatLogic.combatBegin(human, nil, {human.db._id, pointInfo.targetCityId }, CombatDefine.COMBAT_TYPE35)
    end
end

-- 跨服通知据点被别的玩家占领了
function C2N_PointLose_Response(msg)
    local human = ObjHuman.onlineUuid[msg.playerUuid]

    if not human then
        local db = RoleDBLogic.getDb(msg.playerUuid) --后续可优化只取 anotherWorlBattle 数据
        if not db then
            return
        end
        human = {}
        human.db = db
    end

    -- 更新防守阵容数据
    local loseCityId = msg.loseCityId
    local losePointIdx = msg.losePointIdx
    local formationData = human.db.anotherWorlBattle.formation
    formationData[loseCityId][losePointIdx] = nil
    -- 玩家不在线, 手动保存数据
    if not human.fd then
        ObjHuman.save(human) --后续可优化只更新 anotherWorlBattle 数据
    end


    local cityCfg = AnotherWorldBattleConfig.city[loseCityId]

    -- 发邮件
    local mailCfg = MailExcel.mail[AnotherWorldBattleDefine.AB_LOSE_POINT_MAIL_ID]
    local content = Util.format(mailCfg.content, cityCfg and cityCfg.cityName or "", loseCityId)
    MailManager.add(MailManager.SYSTEM, msg.playerUuid, mailCfg.title, content, nil, mailCfg.senderName or "GM")

    -- 把最新的防守阵容数据推给客户端
    if human.fd then
        sendDefHeroArr(human)
    end
end

-- 跨服通知可以更换据点的防守阵容数据
function C2N_UpdatePointLineup_Response(msg)
    local human = ObjHuman.onlineUuid[msg.playerUuid]
    if not human then
        local db = RoleDBLogic.getDb(msg.playerUuid)
        if not db then
            return
        end
        human = {}
        human.db = db
    end

    local anotherWorlBattle = human.db.anotherWorlBattle
    if not anotherWorlBattle or not anotherWorlBattle.formation then
        return Broadcast.sendErr(human, Lang.AB_NOT_OCCUPY_POINT)
    end

    local cityId = msg.targetCityId
    local pointIdx = msg.targetPointIdx
    if not anotherWorlBattle.formation[cityId] or not anotherWorlBattle.formation[cityId][pointIdx] then
        return
    end

    local pointLinupData = anotherWorlBattle.formation[cityId][pointIdx]
    pointLinupData.list = msg.heroList
    pointLinupData.helpList = msg.helpList
    pointLinupData.formation = msg.formation

    if not human.fd then
        ObjHuman.save(human)
    end

    sendDefHeroArr(human)
    Broadcast.sendCenter(human, Lang.AB_UPDATE_LINEUP_SUCC)
end

-- 跨服通知放弃据点成功
function C2N_LeavePoint_Response(msg)
    local human = ObjHuman.onlineUuid[msg.playerUuid]
    if not human then
        local db = RoleDBLogic.getDb(msg.playerUuid)
        if not db then
            return
        end
        human = {}
        human.db = db
    end

    local anotherWorlBattle = human.db.anotherWorlBattle
    if not anotherWorlBattle or not anotherWorlBattle.formation then
        return
    end

    local cityId = msg.targetCityId
    local pointIdx = msg.targetPointIdx
    anotherWorlBattle.formation[cityId][pointIdx] = nil
    if not next(anotherWorlBattle.formation[cityId]) then
        anotherWorlBattle.formation[cityId] = nil
    end

    -- 玩家不在线, 手动保存数据
    if not human.fd then
        ObjHuman.save(human) --后续可优化只更新 anotherWorlBattle 数据
    else
        -- 把最新的防守阵容数据推给客户端
        sendDefHeroArr(human)
    end
end

-- 跨服返回本公会士气信息
function C2N_MyUnionMoraleInfo_Response(msg)
    local human = ObjHuman.onlineUuid[msg.playerUuid]
    if not human then
        return
    end

    local varCfg = AnotherWorldBattleConfig.var[1]
    local msgRet = Msg.gc.GC_AB_GET_MORALE_INFO
    msgRet.moraleState = msg.moraleState
    msgRet.leftTime = 0

    local now = os.time()
    local leftTime = msg.moraleStartTime + AnotherWorldBattleDefine.AB_MORALE_DURATION - now
    if leftTime > 0 then
        msgRet.leftTime = leftTime
    end

    local itemCfg = varCfg.moraleCost
    local itemId = itemCfg and itemCfg[1] or 101
    local itemNum = itemCfg and itemCfg[2] or 0
    Grid.makeItem(msgRet.moraleCost, itemId, itemNum)

    msgRet.moraleAttrs[0] = 0
    local moraleAttrCfg = varCfg.moraleAtrrs
    if moraleAttrCfg then
        local attrArr = moraleAttrCfg[msg.moraleAttrIdx] or moraleAttrCfg[1]
        for i, attrTb in ipairs(attrArr) do
            msgRet.moraleAttrs[0] = i
            msgRet.moraleAttrs[i].key = attrTb[1]
            msgRet.moraleAttrs[i].value = attrTb[2]
        end
    end

    Msg.send(msgRet, human.fd)
end

-- 跨服返回加士气结果
function C2N_UnionMorale_Response(msg)
    if msg.opRes == 0 then
        return
    end

    local human = ObjHuman.onlineUuid[msg.playerUuid]
    if not human then
        local db = RoleDBLogic.getDb(msg.playerUuid)
        if not db then
            return
        end
        human = {}
        human.db = db
    end

    local moraleCostCfg = AnotherWorldBattleConfig.var[1].moraleCost
    local itemId, itemNum = moraleCostCfg[1], moraleCostCfg[2]
    BagLogic.addItem(human, itemId, itemNum, LOGTAG)

    if not human.fd then
        ObjHuman.save(human)
    else
        local tips = Lang.AB_CANNOT_DO
        if msg.opRes == -2 then
            tips = Lang.AB_MORALE_IS_DURING
        end
        Broadcast.sendErr(human, tips)
    end
end

-- 跨服通知给玩家发奖
function C2N_IssueReward(msg)
    -- 删除公会参加异界之战活动时间
    UnionLogic.UpdateJoinAbTime(msg.unionOccupyInfo.unionId, nil)

    resetDefData(msg.unionOccupyInfo.playerInfoArr)

    -- 发奖
    local awardObjArr, occupyCityInfo = genAwardObjArr(msg.unionOccupyInfo)
    if awardObjArr then
        local issueRewardQueue = createRewardQueue()
        issueRewardQueue.extraInfo = occupyCityInfo

        for _, obj in ipairs(awardObjArr) do
            issueRewardQueue:add(obj)
        end
        issueRewardQueue:insertDB()
    end
end


-------------------------------------------战斗---------------------------------

function getCombatMonsterOutID(human, side, args)
    if side ~= CombatDefine.DEFEND_SIDE then return end

    local cityId = args[2]
    local cityCfg = AnotherWorldBattleConfig.city[cityId]
    return cityCfg and cityCfg.pointMonsterId
end

function getCombatObjList(human, side, args, combatType, extraArgs)
    if side == CombatDefine.ATTACK_SIDE and not human then return end

    if side == CombatDefine.DEFEND_SIDE and human then
        return
    end

    if not human then
        local uuid = args[1]
        local db = RoleDBLogic.getDb(uuid)
        if not db then
            return
        end
        human = {}
        human.db = db
    end

    return CombatLogic.getHumanObjList(human, combatType, extraArgs)
end

function getCombatHeros(human, combatType, args)
    if not human.db.anotherWorlBattle then
        return
    end

    if not args then
        return
    end

    local formation = human.db.anotherWorlBattle.formation
    if not formation then
        return
    end

    local cityId, pointIdx = args.cityId, args.pointIdx
    if formation[cityId] and formation[cityId][pointIdx] then
        local combatHeroDB = formation[cityId][pointIdx]
        return combatHeroDB.list, combatHeroDB.helpList, combatHeroDB.formation or 1, combatHeroDB
    end
end

function onFightBegin(human, cbParam, combatType, param)
    if not human.AB_Battle_Cache or (not human.AB_Battle_Cache.isGather and not human.AB_Battle_Cache.defMoraleAttrIdx and not human.AB_Battle_Cache.atkMoraleAttrIdx) then
        return
    end

    local function addAttr(obj, attrs)
        for _, atrrTb in ipairs(attrs or {}) do
            local attrId, attrVal = atrrTb[1], atrrTb[2]
            obj.sysAttr[attrId] = (obj.sysAttr[attrId] or 0) + attrVal
        end
    end

    local atkGatherAttrs, atkMoraleAttrs, defMoraleAttrs
    local varCfg = AnotherWorldBattleConfig.var[1]

    if human.AB_Battle_Cache.isGather then
        atkGatherAttrs = varCfg.gatherAttrs
    end

    if human.AB_Battle_Cache.atkMoraleAttrIdx then
        local idx = human.AB_Battle_Cache.atkMoraleAttrIdx
        atkMoraleAttrs = varCfg.moraleAtrrs and varCfg.moraleAtrrs[idx]
    end

    if human.AB_Battle_Cache.defMoraleAttrIdx then
        local idx = human.AB_Battle_Cache.defMoraleAttrIdx
        defMoraleAttrs = varCfg.moraleAtrrs and varCfg.moraleAtrrs[idx]
    end

    for index = 1, CombatDefine.COMBAT_HERO_ALL_CNT do
        local side = index > CombatDefine.COMBAT_HERO_CNT and CombatDefine.DEFEND_SIDE or CombatDefine.ATTACK_SIDE
        local realPos = CombatLogic.getPos(side, index)
        local obj = CombatImpl.objList[realPos]

        if obj then
            if side == CombatDefine.ATTACK_SIDE then
                if atkGatherAttrs or atkMoraleAttrs then
                    addAttr(obj, atkGatherAttrs)
                    addAttr(obj, atkMoraleAttrs)
                    obj.isSysAttrChange = true
                end
            else
                if defMoraleAttrs then
                    addAttr(obj, defMoraleAttrs)
                    obj.isSysAttrChange = true
                end
            end
        end
    end
end

function onFightEnd(human, result, type, cbParam, combatInfo)
    -- if result == CombatDefine.RESULT_WIN then
    --     challenge_Win(human, {cityId = human.AB_Battle_Cache.cityId, pointIdx = human.AB_Battle_Cache.pointIdx})
    -- end
    local args = {
        cityId = human.AB_Battle_Cache.cityId,
        pointIdx = human.AB_Battle_Cache.pointIdx,
        challengeRes = result
    }

    human.AB_Battle_Cache = nil

    challenge_End(human, args)
end