ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/FBCommon.py
@@ -16,34 +16,22 @@
import IPY_GameWorld
import PlayerControl
import ItemCommon
import GameMap
import NPCCommon
import ReadChConfig
import BuffSkill
import ChPyNetSendPack
import NetPackCommon
import SkillCommon
import IpyGameDataPY
import PlayerFB
import ShareDefine
import EventReport
import PlayerFamily
import PlayerActivity
import ItemControler
import PlayerSuccess
import GameFuncComm
import PyGameData
import GameObj
import FBLogic
import ChConfig
import PlayerGoldInvest
import ObjPool
import datetime
import random
import json
import math
import time
import copy
#---------------------------------------------------------------------
#全局变量
Def_VSFB_CanEnter = 'VSFB_CanEnter'                   #可以进入
@@ -125,29 +113,25 @@
def GetFBLineEnterPosInfo(mapID, lineID, fbLineIpyData=None):
    # 坐标信息
    return [10,10]
def GetPassAwardList(mapID, lineID):
    # 过关奖励
    fbLineIpyData = GetFBLineIpyData(mapID, lineID)
    return [] if not fbLineIpyData else fbLineIpyData.GetPassAwardList()
def GetSweepAwardList(mapID, lineID, sweepCnt):
    # 扫荡奖励
    fbLineIpyData = GetFBLineIpyData(mapID, lineID)
    if not fbLineIpyData:
        fbLineIpyData = GetFBLineIpyData(mapID, lineID)
    return None if not fbLineIpyData else fbLineIpyData.GetEnterPosInfo()
def GetFBLineStepTime(mapID, lineID=0):
    # 阶段时间信息
    fbLineIpyData = GetFBLineIpyData(mapID, lineID)
    return None if not fbLineIpyData else fbLineIpyData.GetStepTime()
def GetFBLineRefreshNPC(mapID, lineID=0):
    # 刷怪信息
    fbLineIpyData = GetFBLineIpyData(mapID, lineID)
    return None if not fbLineIpyData else fbLineIpyData.GetRefreshNPC()
def GetFBLineGrade(mapID, lineID=0):
    # 评级规则信息
    fbLineIpyData = GetFBLineIpyData(mapID, lineID)
    return None if not fbLineIpyData else fbLineIpyData.GetGradeInfo()
def GetFBLineReward(mapID, lineID):
    # 奖励信息;支持扫荡取奖励
    fbLineIpyData = GetFBLineIpyData(mapID, lineID)
    return None if not fbLineIpyData else fbLineIpyData.GetRewardInfo()
def GetFBGradeRewardRateList(mapID):
    fbIpyData = GetFBIpyData(mapID)
    return [] if not fbIpyData else fbIpyData.GetRewardRate()
        return []
    awardItemList = fbLineIpyData.GetSweepAwardList()
    if not awardItemList:
        awardItemList = fbLineIpyData.GetPassAwardList()
    sweepItemList = []
    for itemInfo in awardItemList:
        itemID, itemCount = itemInfo[:2]
        sweepItemList.append([itemID, itemCount * sweepCnt])
    return sweepItemList
def GetFBFuncOpenState(dataMapID):
    ## 获取副本开启状态 @return: 0-关闭;1-开启
@@ -165,38 +149,40 @@
def IsFBPass(curPlayer, mapID, lineID):
    ## 副本线路是否已过关
    passLineID = 0
    if mapID == ChConfig.Def_FBMapID_Main:
        return PlayerControl.IsMainLevelPass(curPlayer, lineID)
    
    ipyData = IpyGameDataPY.GetIpyGameDataNotLog('FBGeneralTrain', mapID, lineID)
    if ipyData:
        passLineID = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_FBPassLineID % mapID)
    else:
        grade = GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_Player_Dict_PlayerFBStar_MapId, lineID, False, [mapID])
    if mapID in ChConfig.PassByStarMapIDList:
        grade = GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_Player_Dict_FBStar, lineID, False, [mapID])
        if grade:
            return True
    if passLineID >= lineID:
        return True
    else:
        passLineID = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_FBPassLineID % mapID)
        if passLineID >= lineID:
            return True
    return False
def SetFBPass(curPlayer, mapID, funcLineID, isNotify=True):
    passLineID = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_FBPassLineID % mapID)
    if funcLineID > passLineID:
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_FBPassLineID % mapID, funcLineID)
    if isNotify:
        Sync_FBPlayerFBInfoData(curPlayer, mapID)
    return
def CheckCanEnterFBComm(curPlayer, mapID, lineID, fbIpyData, fbLineIpyData, reqEnterCnt=1, isNotify=True, isTeamAsk=False):
    # 可否进入副本通用检查, 扫荡通用
    playerID = curPlayer.GetPlayerID()
    
    if not FBLogic.OnNeedCheckCanEnterFBComm(curPlayer, mapID, lineID):
        return ShareDefine.EntFBAskRet_OK
    # 总表通用检查
    if fbIpyData:
        #开服天开放检查
        if not GetFBFuncOpenState(mapID):
            GameWorld.Log("当前时间未开放该副本!mapID=%s" % (mapID), playerID)
            if isNotify:
                PlayerControl.NotifyCode(curPlayer, "FBIsNotOpen")
            return ShareDefine.EntFBAskRet_FBClose
        #if not GetFBFuncOpenState(mapID):
        #    GameWorld.Log("当前时间未开放该副本!mapID=%s" % (mapID), playerID)
        #    if isNotify:
        #        PlayerControl.NotifyCode(curPlayer, "FBIsNotOpen")
        #    return ShareDefine.EntFBAskRet_FBClose
        
        #进入次数判断
        canEnter, notifyMark = __CheckCanEnterFBByTime(curPlayer, mapID, lineID, fbIpyData, reqEnterCnt, isTeamAsk)
@@ -205,35 +191,23 @@
                PlayerControl.NotifyCode(curPlayer, notifyMark, [mapID])
            return ShareDefine.EntFBAskRet_NoEnterCnt
        
        #进入CD判断
        if CheckIsEnterCD(curPlayer, mapID):
            if isNotify:
                PlayerControl.NotifyCode(curPlayer, "SingleEnterCD", [mapID])
            return ShareDefine.EntFBAskRet_EnterCD
    # 功能线路通用检查
    if fbLineIpyData:
        #等级判断
        curLV = curPlayer.GetLV()
        lvLimitMin = fbLineIpyData.GetLVLimitMin()
        lvLimitMax = fbLineIpyData.GetLVLimitMax()
        if lvLimitMin and curLV < lvLimitMin:
            GameWorld.Log("玩家等级不足, 无法进入副本!mapID=%s,lineID=%s,curLV(%s) < lvLimitMin(%s)" 
                          % (mapID, lineID, curLV, lvLimitMin), playerID)
            if isNotify:
                PlayerControl.NotifyCode(curPlayer, "FbLV", [mapID])
            return ShareDefine.EntFBAskRet_LVLimit
        if lvLimitMax and curLV > lvLimitMax:
            GameWorld.Log("玩家等级超过, 无法进入副本!mapID=%s,lineID=%s,curLV(%s) > lvLimitMax(%s)"
                          % (mapID, lineID, curLV, lvLimitMax), playerID)
            if isNotify:
                PlayerControl.NotifyCode(curPlayer, "FbLV", [mapID])
            return ShareDefine.EntFBAskRet_LVLimit
        
        #门票判断
        if not GetFBEnterTicket(curPlayer, mapID, lineID, fbLineIpyData, reqEnterCnt, isTeamAsk)[0]:
            if isNotify:
                PlayerControl.NotifyCode(curPlayer, "GeRen_chenxin_157069", [mapID])
            return ShareDefine.EntFBAskRet_NoTicket
        #if not GetFBEnterTicket(curPlayer, mapID, lineID, fbLineIpyData, reqEnterCnt, isTeamAsk)[0]:
        #    if isNotify:
        #        PlayerControl.NotifyCode(curPlayer, "GeRen_chenxin_157069", [mapID])
        #    return ShareDefine.EntFBAskRet_NoTicket
        
    return ShareDefine.EntFBAskRet_OK
@@ -244,42 +218,39 @@
        return True, ""
    
    #playerID = curPlayer.GetPlayerID()
    enterCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_EnterFbCntDay % mapID)
    enterCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_FbEnterCnt % mapID)
    maxCnt = GetEnterFBMaxCnt(curPlayer, mapID)
    if enterCnt + reqEnterCnt <= maxCnt:
        return True, ""
    
    ### 以下是到达次数上限后的处理
    fbType = GameWorld.GetMap().GetMapFBTypeByMapID(mapID)
    if mapID in ChConfig.UnPassFreeMapIDList and not IsFBPass(curPlayer, mapID, lineID):
        return True, ""
    
    # 单人副本达到次数后不可再进入
    if fbType == IPY_GameWorld.fbtSingle:
        #GameWorld.Log("已达到当日最大进入次数!单人副本 mapID=%s,enterCnt=%s,reqEnterCnt=%s,maxTimes=%s,maxCnt=%s"
        #              % (mapID, enterCnt, reqEnterCnt, maxTimes, maxCnt), playerID)
        return False, "GeRen_chenxin_268121"
#    ### 以下是到达次数上限后的处理
#    fbType = GameWorld.GetMap().GetMapFBTypeByMapID(mapID)
#
#    # 单人副本达到次数后不可再进入
#    if fbType == IPY_GameWorld.fbtSingle:
#        #GameWorld.Log("已达到当日最大进入次数!单人副本 mapID=%s,enterCnt=%s,reqEnterCnt=%s,maxTimes=%s,maxCnt=%s"
#        #              % (mapID, enterCnt, reqEnterCnt, maxTimes, maxCnt), playerID)
#        return False, "GeRen_chenxin_268121"
#
#    # 组队副本
#    if fbType == IPY_GameWorld.fbtTeam:
#        # 可助战的不可单人进入助战,可发起匹配
#        if not isTeamAsk and (not curPlayer.GetTeamID() or curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_TeamMemCount) <= 1):
#            #GameWorld.Log("已达到当日最大进入次数!组队副本不可单人助战! mapID=%s,enterCnt=%s,reqEnterCnt=%s,maxTimes=%s,maxCnt=%s"
#            #              % (mapID, enterCnt, reqEnterCnt, maxTimes, maxCnt), playerID)
#            return False, "TeamSingleEnter"
#
#    if mapID not in ChConfig.Def_NoLimitEnterCntMap:
#        #GameWorld.Log("已达到当日最大进入次数! mapID=%s,enterCnt=%s,reqEnterCnt=%s,maxTimes=%s,maxCnt=%s"
#        #              % (mapID, enterCnt, reqEnterCnt, maxTimes, maxCnt), playerID)
#        return False, "GeRen_chenxin_268121"
    
    # 组队副本
    if fbType == IPY_GameWorld.fbtTeam:
        # 无助战的不可再进入
        if not fbIpyData.GetHelpPoint():
            #GameWorld.Log("已达到当日最大进入次数!组队副本 mapID=%s,enterCnt=%s,reqEnterCnt=%s,maxTimes=%s,maxCnt=%s"
            #              % (mapID, enterCnt, reqEnterCnt, maxTimes, maxCnt), playerID)
            return False, "GeRen_chenxin_268121"
        # 可助战的不可单人进入助战,可发起匹配
        if not isTeamAsk and (not curPlayer.GetTeamID() or curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_TeamMemCount) <= 1):
            #GameWorld.Log("已达到当日最大进入次数!组队副本不可单人助战! mapID=%s,enterCnt=%s,reqEnterCnt=%s,maxTimes=%s,maxCnt=%s"
            #              % (mapID, enterCnt, reqEnterCnt, maxTimes, maxCnt), playerID)
            return False, "TeamSingleEnter"
    elif mapID not in ChConfig.Def_NoLimitEnterCntMap:
        #GameWorld.Log("已达到当日最大进入次数! mapID=%s,enterCnt=%s,reqEnterCnt=%s,maxTimes=%s,maxCnt=%s"
        #              % (mapID, enterCnt, reqEnterCnt, maxTimes, maxCnt), playerID)
        return False, "GeRen_chenxin_268121"
    # 周进入次数暂不做,待扩展...
    return True, ""
    GameWorld.DebugLog("可进入次数不足: mapID=%s, lineID=%s, enterCnt(%s) + reqEnterCnt(%s) <= maxCnt=%s"
                       % (mapID, lineID, enterCnt, reqEnterCnt, maxCnt))
    return False, "GeRen_chenxin_268121"
## 获取副本进入门票信息
#  @param curPlayer 玩家实例
@@ -288,38 +259,39 @@
#  @return [是否可进, [[门票索引列表, delCnt], ...], 删除个数, 是否有绑定, 扣钱信息]
def GetFBEnterTicket(curPlayer, mapID, lineID=0, fbLineIpyData=None, reqEnterCnt=1, isTeamAsk=False):
    #门票判断
    if not fbLineIpyData:
        fbLineIpyData = GetFBLineIpyData(mapID, lineID)
    ticketID = fbLineIpyData.GetTicketID()
    if not ticketID:
        return True, [], 0, False, []
    ticketCostCntList = fbLineIpyData.GetTicketCostCnt()
    if not ticketCostCntList:
        GameWorld.ErrLog("没有配置门票消耗!mapID=%s,lineID=%s" % (mapID, lineID), curPlayer.GetPlayerID())
        return False, [], 0, False, []
    enterCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_EnterFbCntDay % mapID)
    costCnt = ticketCostCntList[-1] if enterCnt >= len(ticketCostCntList) else ticketCostCntList[enterCnt]
    totalCostCnt = costCnt*reqEnterCnt
    if not totalCostCnt:
        GameWorld.ErrLog("没有配置门票消耗!mapID=%s,lineID=%s" % (mapID, lineID), curPlayer.GetPlayerID())
        return False, [], 0, False, []
    itemPack = curPlayer.GetItemManager().GetPack(IPY_GameWorld.rptItem)
    enough, indexList, hasBind, lackCnt = ItemCommon.GetItem_FromPack_ByID_ExEx(ticketID, itemPack, totalCostCnt)
    if not enough:
        ticketPrice = fbLineIpyData.GetTicketPrice()
        if ticketPrice and not isTeamAsk: #组队进组队副本时必须要有门票道具
            costMoney = ticketPrice * lackCnt
            costMoneyList = PlayerControl.HaveMoneyEx(curPlayer, ShareDefine.TYPE_Price_Gold_Paper_Money, costMoney)
            return bool(costMoneyList), indexList, totalCostCnt, hasBind, costMoneyList
        GameWorld.DebugLog("门票不足, 无法进入副本!mapID=%s,lineID=%s,ticketID=%s,reqEnterCnt=%s,totalCostCnt=%s"
                      % (mapID, lineID, ticketID, reqEnterCnt, totalCostCnt), curPlayer.GetPlayerID())
        return False, [], 0, False, []
    return enough, indexList, totalCostCnt, hasBind, []
    return True, [], 0, False, []
#    if not fbLineIpyData:
#        fbLineIpyData = GetFBLineIpyData(mapID, lineID)
#
#    ticketID = fbLineIpyData.GetTicketID()
#    if not ticketID:
#        return True, [], 0, False, []
#
#    ticketCostCntList = fbLineIpyData.GetTicketCostCnt()
#    if not ticketCostCntList:
#        GameWorld.ErrLog("没有配置门票消耗!mapID=%s,lineID=%s" % (mapID, lineID), curPlayer.GetPlayerID())
#        return False, [], 0, False, []
#
#    enterCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_FbEnterCnt % mapID)
#    costCnt = ticketCostCntList[-1] if enterCnt >= len(ticketCostCntList) else ticketCostCntList[enterCnt]
#    totalCostCnt = costCnt*reqEnterCnt
#    if not totalCostCnt:
#        GameWorld.ErrLog("没有配置门票消耗!mapID=%s,lineID=%s" % (mapID, lineID), curPlayer.GetPlayerID())
#        return False, [], 0, False, []
#
#    itemPack = curPlayer.GetItemManager().GetPack(IPY_GameWorld.rptItem)
#    enough, indexList, hasBind, lackCnt = ItemCommon.GetItem_FromPack_ByID_ExEx(ticketID, itemPack, totalCostCnt)
#    if not enough:
#        ticketPrice = fbLineIpyData.GetTicketPrice()
#        if ticketPrice and not isTeamAsk: #组队进组队副本时必须要有门票道具
#            costMoney = ticketPrice * lackCnt
#            costMoneyList = PlayerControl.HaveMoneyEx(curPlayer, ShareDefine.TYPE_Price_Gold_Paper_Money, costMoney)
#            return bool(costMoneyList), indexList, totalCostCnt, hasBind, costMoneyList
#        GameWorld.DebugLog("门票不足, 无法进入副本!mapID=%s,lineID=%s,ticketID=%s,reqEnterCnt=%s,totalCostCnt=%s"
#                      % (mapID, lineID, ticketID, reqEnterCnt, totalCostCnt), curPlayer.GetPlayerID())
#        return False, [], 0, False, []
#
#    return enough, indexList, totalCostCnt, hasBind, []
## 获取副本进入门票信息
#  @param curPlayer 玩家实例
@@ -482,15 +454,6 @@
    GameWorld.GetGameFB().SetPlayerGameFBDict(curPlayer.GetID(), ChConfig.FBPlayerDict_IsDelTicket, delSign)
    return
## 自定义场景阶段
def GetCustomMapStep(curPlayer, mapID, lineID):
    return curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_CustomMapStep % (mapID, lineID))
def SetCustomMapStep(curPlayer, mapID, lineID, step):
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_CustomMapStep % (mapID, lineID), step)
    if step == ChConfig.CustomMapStep_Over:
        PlayerControl.SetCustomMap(curPlayer, 0, 0)
    return
def GetCurSingleFBPlayer():
    ''' 获取当前单人副本玩家 '''
    curPlayer = None
@@ -564,44 +527,6 @@
            FBLogic.DoFBHelp(curPlayer, tick)
            if updGrade != lowest:
                curPlayer.Sync_TimeTick(timeType, 0, diffSecond * 1000, True)
    return updGrade
def UpdateCustomFBGrade(curPlayer, tick, gradeTimeList, timeType=IPY_GameWorld.tttFlagTake):
    '''更新当前副本星级、评级
    @param gradeTimeList: 评级分段时间列表,单位秒 [最高评级可用时间, 下级可用时间, ..., 最低级可用时间]
    @param curPlayer: 触发的玩家,一般是DoEnter时调用,会同步更新一次副本评级并将信息通知该玩家
    @note: 星级:1-1星;2-2星 ...            [60, 20, 10]
            评级:1-D;2-C;3-B;4-A;5-S;    [60, 30, 30, 20, 10]
    '''
    lowest = 1
    curGrade = curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_ClientCustomSceneGrade)
    #最后一个评级了,不再处理
    if curGrade == lowest:
        return curGrade
    fbStepTick = curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_ClientCustomSceneStepTick)
    useSecond = int((tick - fbStepTick) / 1000.0) # 战斗阶段已耗总秒数
    diffSecond = 0
    updGrade = len(gradeTimeList)
    gSecondTotal = 0
    for gSecond in gradeTimeList:
        gSecondTotal += gSecond
        diffSecond = gSecondTotal - useSecond
        # 还在当前评级段
        if diffSecond > 0:
            break
        updGrade -= 1 # 用时超过当前评级段,降级
    updGrade = max(lowest, updGrade) # 保底最低级
    if curGrade == updGrade:
        return curGrade
    curPlayer.SetDict(ChConfig.Def_PlayerKey_ClientCustomSceneGrade, updGrade)
    GameWorld.DebugLog("UpdateCustomFBGrade useSecond=%s,gradeTimeList=%s,curGrade=%s,updGrade=%s,diffSecond=%s"
                       % (useSecond, gradeTimeList, curGrade, updGrade, diffSecond))
    Notify_FBHelp(curPlayer, {Help_grade:updGrade})
    if updGrade != lowest:
        curPlayer.Sync_TimeTick(timeType, 0, diffSecond * 1000, True)
    return updGrade
def NotifyFBOver(curPlayer, dataMapID, lineID, isPass, overDict={}):
@@ -1574,67 +1499,22 @@
## ---------------------------------- TD ---------------------------------------
def GetEnterFBMaxCnt(curPlayer, mapID):
    ## 获取副本最大可进入次数: 基本次数 + 时间已恢复次数 + VIP额外次数 + 购买次数 + 找回次数 + 使用道具增加次数
    ## 获取副本最大可进入次数: 基本次数 + 广告次数 + 购买次数 + 使用道具增加次数 + 其他
    fbIpyData = GetFBIpyData(mapID)
    if not fbIpyData:
        return 0
    maxTimes = fbIpyData.GetDayTimes()
    MWPrivilegeID = fbIpyData.GetExtraTimesMWPriID()
    mwAddCnt = 0#wmpIpyData.GetEffectValue() if wmpIpyData else 0
    extraTimesVIPPriID = fbIpyData.GetExtraTimesVIPPriID()
    extraCnt = 0
    buyCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_BuyFbCntDay % mapID)
    recoverFbCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_RecoverFbCnt % mapID)
    itemAddCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_ItemAddFbCnt % mapID)
    regainFbCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_RegainFbCnt % mapID)
    adCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_FBADCnt % mapID)
    buyCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_FBBuyCnt % mapID)
    itemCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_FBItemCnt % mapID)
    investFBCnt = PlayerGoldInvest.GetAddFBCnt(curPlayer, mapID)
    maxCnt = maxTimes + regainFbCnt + extraCnt + buyCnt + recoverFbCnt + mwAddCnt + itemAddCnt + investFBCnt
    maxCnt = maxTimes + adCnt + buyCnt + itemCnt + investFBCnt
    return maxCnt
def GetFBDetailCntInfo(curPlayer, mapID):
    #返回FB剩余正常次数、时间恢复次数、vip额外次数、已买次数、道具增加次数、未买次数
    fbIpyData = GetFBIpyData(mapID)
    enterCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_EnterFbCntDay % mapID)
    maxTimes = fbIpyData.GetDayTimes()
    maxRegainFbCnt = 0
    recoverIntervalDict = IpyGameDataPY.GetFuncEvalCfg('FBCntRegainInterval', 1)
    if str(mapID) in recoverIntervalDict:
        maxRegainFbCnt = recoverIntervalDict[str(mapID)][0]
    MWPrivilegeID = fbIpyData.GetExtraTimesMWPriID()
    mwAddCnt = 0#wmpIpyData.GetEffectValue() if wmpIpyData else 0
    maxTimes += mwAddCnt #法宝增加的次数加到基础次数里
    extraTimesVIPPriID = fbIpyData.GetExtraTimesVIPPriID()
    extraCnt = 0
    buyCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_BuyFbCntDay % mapID)
    recoverFbCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_RecoverFbCnt % mapID)
    itemAddCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_ItemAddFbCnt % mapID)
    #先用找回来的次数,再用Vip额外次数,再用每日刷新次数、时间恢复次数、和Vip买回来的次数,最后用卷轴加的次数
    cntList = [recoverFbCnt, extraCnt, maxTimes, maxRegainFbCnt, buyCnt, itemAddCnt]
    rCntList = copy.deepcopy(cntList)
    sumCnt = 0
    for i, cnt in enumerate(cntList):
        sumCnt += cnt
        rCntList[i] = max(0, sumCnt - enterCnt)
        if enterCnt <= sumCnt:
            break
    rRecoverFbCnt, rExtraCnt, rCommonCnt, rRegainFbCnt, rBuyCnt, rItemAddCnt = rCntList
    #未买次数
    buyTimesVIPPriID = fbIpyData.GetBuyTimesVIPPriID()
    canBuyCnt = 0
    noBuyCnt = max(0, canBuyCnt - buyCnt)
    return [[rCommonCnt, rRegainFbCnt, rExtraCnt, rBuyCnt, rItemAddCnt, noBuyCnt], [maxTimes, maxRegainFbCnt, extraCnt, canBuyCnt, 10000, canBuyCnt]]
## 玩家进入副本次数
#  @param curPlayer 玩家实例
#  @param fbID 副本id
#  @return bool
def GetEnterFBCount(curPlayer, fbID, lineBit=-1):
    ## 玩家进入副本次数
    fbID = GetRecordMapID(fbID)
    enterCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_EnterFbCntDay % fbID)
    enterCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_FbEnterCnt % fbID)
    if lineBit >= 0:
        return GameWorld.GetDataByDigitPlace(enterCnt, lineBit)
    return enterCnt
@@ -1642,24 +1522,19 @@
def AddFBCntByItem(curPlayer, itemID, mapID, addCnt):
    ## 物品增加副本次数
    mapID = GetRecordMapID(mapID)
    itemAddCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_ItemAddFbCnt % mapID)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_ItemAddFbCnt % mapID, itemAddCnt + addCnt)
    itemAddCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_FBItemCnt % mapID)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_FBItemCnt % mapID, itemAddCnt + addCnt)
    Sync_FBPlayerFBInfoData(curPlayer, mapID)
    PlayerControl.NotifyCode(curPlayer, 'AddActivityCount_1', [itemID, mapID, addCnt])
    OnFBCountChangeEffectRecoverCount(curPlayer, mapID)
    return
## 增加玩家进入副本次数
#  @param curPlayer 玩家实例
#  @param fbID 副本id
#  @param addCount 增加次数
#  @return 返回值无意义
def AddEnterFBCount(curPlayer, fbID, addCount=1, lineBit=-1, isFree=False):
    ## 增加玩家进入副本次数
    ## @param isFree: 是否免费进入的,免费的不增加实际进入次数,但需要触发进入次数额外处理,如活跃、成就等
    addCountEx = addCount
    #addCountEx = addCount
    addCount = 0 if isFree else addCount
    fbID = GetRecordMapID(fbID)
    enterCntKey = ChConfig.Def_Player_Dict_EnterFbCntDay % fbID
    enterCntKey = ChConfig.Def_Player_Dict_FbEnterCnt % fbID
    enterCnt = curPlayer.NomalDictGetProperty(enterCntKey)
    if lineBit >= 0:
        curLineEnterCnt = GameWorld.GetDataByDigitPlace(enterCnt, lineBit)
@@ -1674,180 +1549,21 @@
        addCount = updCnt-enterCnt
        PlayerControl.NomalDictSetProperty(curPlayer, enterCntKey, updCnt)
        
        PlayerActivity.OnEnterFBActivity(curPlayer, fbID, updCnt, addCountEx)
        PlayerSuccess.AddEnterFBSuccess(curPlayer, fbID, addCountEx)
        #PlayerActivity.OnEnterFBActivity(curPlayer, fbID, updCnt, addCountEx)
        #PlayerSuccess.AddEnterFBSuccess(curPlayer, fbID, addCountEx)
        updValue = updCnt
    enterCntTotalKey = ChConfig.Def_Player_Dict_EnterFbCntTotal % fbID
    enterCntTotal = min(curPlayer.NomalDictGetProperty(enterCntTotalKey) + addCount, ChConfig.Def_UpperLimit_DWord)
    PlayerControl.NomalDictSetProperty(curPlayer, enterCntTotalKey, enterCntTotal)
    GameWorld.DebugLog("    AddEnterFBCount fbID=%s, addCount=%s, lineBit=%s, enterCnt=%s,updValue=%s,enterCntTotal=%s"
                       % (fbID, addCount, lineBit, enterCnt, updValue, enterCntTotal), curPlayer.GetPlayerID())
    GameWorld.DebugLog("    AddEnterFBCount fbID=%s, addCount=%s, lineBit=%s, enterCnt=%s,updValue=%s"
                       % (fbID, addCount, lineBit, enterCnt, updValue), curPlayer.GetPlayerID())
    Sync_FBPlayerFBInfoData(curPlayer, fbID)
    OnFBCountChangeEffectRecoverCount(curPlayer, fbID)
    return True
def OnFBCountChangeEffectRecoverCount(curPlayer, mapID):
    ## 副本相关次数变更,包含增加、扣除等影响副本按时间恢复次数相关逻辑处理
    recoverIntervalDict = IpyGameDataPY.GetFuncEvalCfg('FBCntRegainInterval', 1)
    if str(mapID) not in recoverIntervalDict:
        return
    maxCanRecoverCnt, recoverInterval = recoverIntervalDict[str(mapID)]
    curRegainFbCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_RegainFbCnt % mapID) # 当前已恢复次数
    if curRegainFbCnt >= maxCanRecoverCnt:
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_FbCntRegainStartTime % mapID, 0)
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_FbCntRegainTotalTime % mapID, 0)
        GameWorld.DebugLog("副本时间恢复次数已达当日上限!")
    else:
        curTime = int(time.time())
        fbIpyData = GetFBIpyData(mapID)
        maxFreeTimes = fbIpyData.GetDayTimes() # 常规封顶次数
        enterCnt = GetEnterFBCount(curPlayer, mapID) # 已经进入次数
        maxCnt = GetEnterFBMaxCnt(curPlayer, mapID) # 当前可用最大次数
        remainCanEnterCnt = maxCnt - enterCnt # 剩余可进入次数
        regainStartTime = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_FbCntRegainStartTime % mapID)
        passTime = curTime - regainStartTime
        # 到达常规次数上限,暂时恢复时间
        if remainCanEnterCnt >= maxFreeTimes:
            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_FbCntRegainStartTime % mapID, 0)
            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_FbCntRegainTotalTime % mapID, 0)
            GameWorld.DebugLog("副本时间恢复次数已达常规次数!")
        elif passTime < recoverInterval:
            pass
            #GameWorld.DebugLog("副本时间恢复次数还未到达恢复CD!")
        else:
            if not regainStartTime:
                updRegainTotalTime = recoverInterval
            else:
                updRegainTotalTime = recoverInterval - passTime % recoverInterval
            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_FbCntRegainStartTime % mapID, curTime)
            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_FbCntRegainTotalTime % mapID, updRegainTotalTime)
            GameWorld.DebugLog("副本还可按时间恢复次数!curTime=%s,regainStartTime=%s,passTime=%s,updRegainTotalTime=%s"
                               % (curTime, regainStartTime, passTime, updRegainTotalTime))
    NotifyFBCntRegainInfo(curPlayer, [mapID])
    return
def RegainFBCntProcess(curPlayer):
    ## 按时间恢复副本次数
    curTime = int(time.time())
    recoverIntervalDict = IpyGameDataPY.GetFuncEvalCfg('FBCntRegainInterval', 1)
    for mapIDStr, recoverInfo in recoverIntervalDict.items():
        mapID = int(mapIDStr)
        maxCanRecoverCnt, recoverInterval = recoverInfo
        curRegainFbCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_RegainFbCnt % mapID) # 当前已恢复次数
        if maxCanRecoverCnt and curRegainFbCnt >= maxCanRecoverCnt:
            #GameWorld.DebugLog("已到达副本恢复次数上限!mapID=%s,curRegainFbCnt(%s) >= maxCanRecoverCnt(%s)" % (mapID, curRegainFbCnt, maxCanRecoverCnt))
            continue
        fbIpyData = GetFBIpyData(mapID)
        maxFreeTimes = fbIpyData.GetDayTimes() # 常规封顶次数
        enterCnt = GetEnterFBCount(curPlayer, mapID) # 已经进入次数
        maxCnt = GetEnterFBMaxCnt(curPlayer, mapID) # 当前可用最大次数
        remainCanEnterCnt = maxCnt - enterCnt # 剩余可进入次数
        if remainCanEnterCnt >= maxFreeTimes:
            #GameWorld.DebugLog("可进入次数已经到达常规封顶次数!mapID=%s,remainCanEnterCnt=%s" % (mapID, remainCanEnterCnt))
            continue
        regainStartTime = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_FbCntRegainStartTime % mapID)
        if not regainStartTime:
            #GameWorld.DebugLog("还未设置副本恢复次数倒计时!mapID=%s" % mapID)
            continue
        needTime = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_FbCntRegainTotalTime % mapID)
        passTime = curTime - regainStartTime
        if passTime < needTime:
            continue
        remainTime = passTime - needTime # 扣除恢复单次后剩余的时间,离线上线后可能一次性恢复多次
        recoverCnt = 1 + remainTime / recoverInterval # 倒计时时间可恢复总次数
        realRecoverCnt = min(maxFreeTimes - remainCanEnterCnt, recoverCnt) # 实际最大可恢复总次数
        if maxCanRecoverCnt:
            realRecoverCnt = min(realRecoverCnt, maxCanRecoverCnt - curRegainFbCnt)
        if realRecoverCnt <= 0:
            continue
        # 更新时间倒计时已恢复次数
        updRegainFbCnt = curRegainFbCnt + realRecoverCnt
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_RegainFbCnt % mapID, updRegainFbCnt)
        OnFBCountChangeEffectRecoverCount(curPlayer, mapID)
    return
def NotifyFBCntRegainInfo(curPlayer, syncMapIDList=[]):
    ##通知副本次数恢复剩余时间
    recoverIntervalDict = IpyGameDataPY.GetFuncEvalCfg('FBCntRegainInterval', 1) # {mapID:[次数, 每次间隔], ...}
    if not recoverIntervalDict:
        return
    if not syncMapIDList:
        syncMapIDList = [int(mapIDStr) for mapIDStr in recoverIntervalDict.keys()]
    infoList = []
    curTime = int(time.time())
    for mapID in syncMapIDList:
        if str(mapID) not in recoverIntervalDict:
            continue
        mapInfo = ChPyNetSendPack.tagMCFBCntRegain()
        mapInfo.Clear()
        mapInfo.DataMapID = mapID
        lastRegainTime = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_FbCntRegainStartTime % mapID)
        needTime = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_FbCntRegainTotalTime % mapID)
        passTime = curTime - lastRegainTime
        mapInfo.RemainTime = max(0, needTime - passTime)
        mapInfo.RegainCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_RegainFbCnt % mapID)
        infoList.append(mapInfo)
    if not infoList:
        return
    regainData = ChPyNetSendPack.tagMCFBCntRegainRemainTime()
    regainData.Clear()
    regainData.InfoList = infoList
    regainData.Cnt = len(regainData.InfoList)
    NetPackCommon.SendFakePack(curPlayer, regainData)
    return
def SetIsHelpFight(curPlayer):
    ##设置是否助战 注意!需要在增加副本次数之前设置
    mapID = GameWorld.GetMap().GetMapID()
    mapID = GetRecordMapID(mapID)
    enterCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_EnterFbCntDay % mapID)
    maxCnt = GetEnterFBMaxCnt(curPlayer, mapID)
    if enterCnt >= maxCnt:
        GameWorld.GetGameFB().SetPlayerGameFBDict(curPlayer.GetID(), ChConfig.FBPlayerDict_IsHelpFight, 1)
        return True
    return False
def GetIsHelpFight(curPlayer):
    ##获取是否助战
    return GameWorld.GetGameFB().GetPlayerGameFBDictByKey(curPlayer.GetID(), ChConfig.FBPlayerDict_IsHelpFight)
def FBOnWeek(curPlayer, onWeekType):
    mapIDInfo = []
    ipyDataMgr = IpyGameDataPY.IPY_Data()
    for i in xrange(ipyDataMgr.GetFBFuncCount()):
        ipyData = ipyDataMgr.GetFBFuncByIndex(i)
        mapID = ipyData.GetDataMapID()
        weekTimes = ipyData.GetWeekTimes()
        # 没有周次数限制的不处理
        if not weekTimes:
            continue
        # 重置类型不同的不处理
        if ipyData.GetWeekResetType() != onWeekType:
            continue
        # 重置周次数
        enterCntWeekKey = ChConfig.Def_Player_Dict_EnterFbCntWeek % mapID
        if curPlayer.NomalDictGetProperty(enterCntWeekKey):
            PlayerControl.NomalDictSetProperty(curPlayer, enterCntWeekKey, 0)
            mapIDInfo.append(mapID)
    if mapIDInfo:
        Sync_FBPlayerFBInfoData(curPlayer, mapIDInfo)
    return
## 玩家通用副本OnDay处理
#  @param curPlayer: 玩家实例
#  @return: None
def FBOnDay(curPlayer, onDayType):
    GameWorld.Log("副本过天处理,FBOnDay...", curPlayer.GetPlayerID())
    if onDayType != ShareDefine.Def_OnEventType:
        return
    FBLogic.OnFBPlayerOnDay(curPlayer, onDayType) # 在重置次数之前,可用于处理资源找回
    
    mapIDInfo = []
@@ -1855,57 +1571,18 @@
    for i in xrange(ipyDataMgr.GetFBFuncCount()):
        ipyData = ipyDataMgr.GetFBFuncByIndex(i)
        mapID = ipyData.GetDataMapID()
        dayTimes = ipyData.GetDayTimes()
        enterCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_FbEnterCnt % mapID)
        # 没有日次数限制的不处理
        if not dayTimes and not ipyData.GetBuyTimesVIPPriID() and not ipyData.GetExtraTimesVIPPriID() and not ipyData.GetExtraTimesMWPriID():
            #GameWorld.DebugLog("    不需要重置的副本,mapID=%s,dayTimes=%s,vipBuyPriID=%s,vipExtraTime=%s"
            #                   % (mapID, dayTimes, ipyData.GetBuyTimesVIPPriID(), ipyData.GetExtraTimesVIPPriID()))
        if not enterCnt and not ipyData.GetDayTimes() and not ipyData.GetPayCntMax():
            continue
        # 重置类型不同的不处理
        if ipyData.GetDayResetType() != onDayType:
            #GameWorld.DebugLog("    重置时间点不同,不处理,mapID=%s" % mapID)
            continue
        maxCnt = GetEnterFBMaxCnt(curPlayer, mapID)
        # 进入次数
        enterCntKey = ChConfig.Def_Player_Dict_EnterFbCntDay % mapID
        enterCnt = curPlayer.NomalDictGetProperty(enterCntKey)
        PlayerControl.NomalDictSetProperty(curPlayer, enterCntKey, 0)
        # 购买次数
        buyCntKey = ChConfig.Def_Player_Dict_BuyFbCntDay % mapID
        buyCnt = curPlayer.NomalDictGetProperty(buyCntKey)
        PlayerControl.NomalDictSetProperty(curPlayer, buyCntKey, 0)
        # 找回次数
        recoverCntKey = ChConfig.Def_Player_Dict_RecoverFbCnt % mapID
        recoverCnt = curPlayer.NomalDictGetProperty(recoverCntKey)
        PlayerControl.NomalDictSetProperty(curPlayer, recoverCntKey, 0)
        # 物品增加次数
        itemAddCntKey = ChConfig.Def_Player_Dict_ItemAddFbCnt % mapID
        itemAddCnt = curPlayer.NomalDictGetProperty(itemAddCntKey)
        PlayerControl.NomalDictSetProperty(curPlayer, itemAddCntKey, 0)
        # 时间恢复次数
        regainFBCntKey = ChConfig.Def_Player_Dict_RegainFbCnt % mapID
        regainFBCnt = curPlayer.NomalDictGetProperty(regainFBCntKey)
        PlayerControl.NomalDictSetProperty(curPlayer, regainFBCntKey, 0)
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_FbCntRegainStartTime % mapID, 0)
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_FbCntRegainTotalTime % mapID, 0)
        GameWorld.DebugLog("    重置:mapID=%s,dayTimes=%s,buyCnt=%s,recoverCnt=%s,itemAddCnt=%s,regainFBCnt=%s,maxCnt=%s,enterCnt=%s"
                           % (mapID, dayTimes, buyCnt, recoverCnt, itemAddCnt, regainFBCnt, maxCnt, enterCnt))
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_FbEnterCnt % mapID, 0)
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_FBADCnt % mapID, 0)
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_FBBuyCnt % mapID, 0)
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_FBItemCnt % mapID, 0)
        mapIDInfo.append(mapID)
        
    if mapIDInfo:
        Sync_FBPlayerFBInfoData(curPlayer, mapIDInfo)
        Sync_FBPlayerFBBuyCount(curPlayer, mapIDInfo)
        NotifyFBCntRegainInfo(curPlayer, mapIDInfo)
    
    return
@@ -1915,27 +1592,6 @@
def FBOnLogin(curPlayer):
    FBLogic.OnFBPlayerOnLogin(curPlayer)
    Sync_FBPlayerFBInfoData(curPlayer)
    SyncFBEnterTick(curPlayer)
    Sync_FBPlayerFBBuyCount(curPlayer)
    #PlayerFB.Sync_PubFBSweepData(curPlayer)
    NotifyFBCntRegainInfo(curPlayer)
    #判断副本里离线超过一定时间则退出副本
    CheckFBPlayerOffine(curPlayer)
    return
def CheckFBPlayerOffine(curPlayer):
    mapid = curPlayer.GetMapID()
    ipyData = GetFBIpyData(mapid)
    if not ipyData:
        return
    OfflineTime = ipyData.GetOfflineTime()
    if not OfflineTime:
        return
    leaveServerSecond = PlayerControl.GetPlayerLeaveServerSecond(curPlayer) #离线时间秒
    if leaveServerSecond >= OfflineTime:
        GameWorld.DebugLog('判断副本里离线超过一定时间则退出副本 leaveServerSecond=%s'%leaveServerSecond)
        PlayerControl.PlayerLeaveFB(curPlayer)
    return
#//A5 75 购买副本进入次数#tagCMBuyEnterCount
@@ -1945,381 +1601,38 @@
#    tagHead        Head;
#    DWORD        FBID;   // 副本ID
#};
def BuyFBEnterCount(playerIndex, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(playerIndex)
    mapID = clientData.FBID
    if mapID == ChConfig.Def_FBMapID_Love:
        coupleID = PlayerControl.GetCoupleID(curPlayer)
        if not coupleID:
            GameWorld.DebugLog("没有伴侣无法购买情缘副本次数!")
            return
    ipyData = GetFBIpyData(mapID)
    if not ipyData:
        return
    canBuyCnt = 0
    canBuyCnt = ipyData.GetPayCntMax()
    canBuyCnt += PlayerGoldInvest.GetAddFBBuyCnt(curPlayer, mapID)
    GameWorld.DebugLog("购买副本进入次数: mapID=%s,canBuyCnt=%s" % (mapID, canBuyCnt))
    if canBuyCnt <= 0:
        GameWorld.DebugLog("mapID:%s 不可以购买进入次数"%mapID)
        return
    hasBuyCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_BuyFbCntDay % mapID)
    maxDayTimes = ipyData.GetDayTimes()
    maxCnt = GetEnterFBMaxCnt(curPlayer, mapID)
    enterCnt = GetEnterFBCount(curPlayer, mapID)
    if mapID == ChConfig.Def_FBMapID_SealDemon and maxDayTimes and maxCnt - enterCnt >= maxDayTimes:
        GameWorld.DebugLog('当前次数已满,无需购买。。')
        return
    hasBuyCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_FBBuyCnt % mapID)
    GameWorld.DebugLog("购买副本进入次数: mapID=%s,canBuyCnt=%s,hasBuyCnt=%s" % (mapID, canBuyCnt, hasBuyCnt))
    if hasBuyCnt >= canBuyCnt:
        GameWorld.DebugLog("购买次数已经用完mapID=%s,hasBuyCnt=%s >= canBuyCnt=%s" % (mapID, hasBuyCnt, canBuyCnt))
        GameWorld.DebugLog("副本购买次数已经用完! mapID=%s,hasBuyCnt=%s >= canBuyCnt=%s" % (mapID, hasBuyCnt, canBuyCnt))
        return
    costGoldDict = IpyGameDataPY.GetFuncEvalCfg('BuyFBCntCost', 1, {})
    costGold = costGoldDict.get(str(mapID), '0')
    costGold = eval(costGold)
    costMoneyTypeInfo = IpyGameDataPY.GetFuncEvalCfg('BuyFBCntCost', 2, {})
    costType = costMoneyTypeInfo.get(str(mapID), ShareDefine.TYPE_Price_Gold_Paper_Money)
    if costGold <= 0:
        GameWorld.DebugLog("没有配置购买副本次数消耗货币数! mapID=%s,costType=%s,costGold=%s" % (mapID, costType, costGold))
    costType = ipyData.GetPayMoneyType()
    payMoneyList = ipyData.GetPayMoneyValues()
    if not costType or not payMoneyList:
        GameWorld.DebugLog("没有配置购买副本次数消耗货币数! mapID=%s,costType=%s,payMoneyList=%s" % (mapID, costType, payMoneyList))
        return
    costMoneyList = PlayerControl.HaveMoneyEx(curPlayer, costType, costGold)
    #GameWorld.Log('costMoneyList=%s,costGold=%s'%(costMoneyList,costGold))
    if not costMoneyList:
    costMoney = payMoneyList[hasBuyCnt] if len(payMoneyList) > hasBuyCnt else payMoneyList[-1]
    if not PlayerControl.PayMoney(curPlayer, costType, costMoney, ChConfig.Def_Cost_BuyFBCnt, {"MapID":mapID}):
        return
    infoDict = {"MapID":mapID}
    for moneyType, moneyNum in costMoneyList:
        if not PlayerControl.PayMoney(curPlayer, moneyType, moneyNum, ChConfig.Def_Cost_BuyFBCnt, infoDict):
            GameWorld.DebugLog("仙玉不足!costGold=%s" % costGold)
            return
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_BuyFbCntDay % mapID, hasBuyCnt + 1)
    Sync_FBPlayerFBBuyCount(curPlayer, [mapID])
    PlayerControl.NotifyCode(curPlayer, 'FBEnterTimeBuy', [mapID])
    OnFBCountChangeEffectRecoverCount(curPlayer, mapID)
    if mapID == ChConfig.Def_FBMapID_Love:
        coupleID = PlayerControl.GetCoupleID(curPlayer)
        if coupleID:
            addItemList = IpyGameDataPY.GetFuncEvalCfg("LoveFB", 3)
            paramList = [curPlayer.GetPlayerName()]
            PlayerControl.SendMailByKey("BuyLoveFBCntCoupleMail", [coupleID], addItemList, paramList)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_FBBuyCnt % mapID, hasBuyCnt + 1)
    Sync_FBPlayerFBInfoData(curPlayer, mapID)
    return
#---------------------------------------------------------------------
## 副本开启提示(几分钟)
#  @param openTimeList 开启时间列表[(开启时钟,开启分钟), ]
#  @param notifyMsg 提示mark
#  @param notifyTimeList 提示时间列表
#  @param mergeMinOSD 该提示针对跨服子服有效的最小开服天, >=0时有限制
#  @param mergeMaxOSD 该提示针对跨服子服有效的最大开服天, >=0时有限制
#  @param mergeMapInfo 该提示所属的跨服活动地图信息, 主要用于不同子服对应所跨的活动地图ID
#  @return None
def FBOpenNotify(openTimeList, notifyMsg, notifyTimeList, mapID = 0, mergeMinOSD=-1,
                 mergeMaxOSD=-1, mergeMapInfo=[]):
    # 只在第一线中提示
    if GameWorld.GetGameWorld().GetCurGameWorldIndex() != 0 or not notifyTimeList:
def AddFBADCnt(curPlayer, mapID):
    fbIpyData = GetFBIpyData(mapID)
    if not fbIpyData:
        return
    curTime = datetime.datetime.today()
    nextTime = curTime + datetime.timedelta(hours=1)
    curYear, curMonth, curDay, curHour = curTime.year, curTime.month, curTime.day, curTime.hour
    nextYear, nextMonth, nextDay, nextHour = nextTime.year, nextTime.month, nextTime.day, nextTime.hour
    startTimeStrFormat = "%s-%s-%s %s:%s:%s"
    # 需要提示的最大分钟
    maxNotifyMinute = max(notifyTimeList)
    remaindMinute = -1
    for hour, minute in openTimeList:
        # 当前小时的和下一个小时才有可能需要提示
        if hour not in [curHour, nextHour]:
            continue
        # 获取本次比较的开启时间
        if hour == curHour:
            startTimeStr = startTimeStrFormat % (curYear, curMonth, curDay, hour, minute, "00")
        else:
            startTimeStr = startTimeStrFormat % (nextYear, nextMonth, nextDay, hour, minute, "00")
        # 字符串转化为datetime
        startTime = datetime.datetime.strptime(startTimeStr, ChConfig.TYPE_Time_Format)
        # 还剩多少时间开启
        remainTime = startTime - curTime
        # 计算剩余秒数
        seconds = remainTime.seconds
        # 计算剩余分钟,提前一秒通知
        remaindMinute = (seconds - 1) / 60 + 1
        if 0 < remaindMinute <= maxNotifyMinute:
            break
    # 在配置中需要提示,且未提示过
    if remaindMinute in notifyTimeList \
    and remaindMinute != GameWorld.GetGameFB().GetGameFBDictByKey(ChConfig.Map_FBDict_NotifyOpen):
        if mapID > 0:
            msgParamList = [remaindMinute, mapID]
        else:
            msgParamList = [remaindMinute]
        PlayerControl.WorldNotify(0, notifyMsg, msgParamList, 0, mergeMinOSD, mergeMaxOSD, mergeMapInfo)
        GameWorld.GetGameFB().SetGameFBDict(ChConfig.Map_FBDict_NotifyOpen, remaindMinute)
    return
## 判断当前是否时副本进场时间(准备时间)
#  @param openTimeList 开启时间列表[(开启时钟,开启分钟), ]
#  @param prepareSeconds 准备时间(秒)
#  @return bool
def CheckIsFBPrepareTime(openTimeList, prepareSeconds):
    curTime = GameWorld.GetCurrentTime()
    prevTime = curTime - datetime.timedelta(hours=1)
    curYear, curMonth, curDay, curHour = curTime.year, curTime.month, curTime.day, curTime.hour
    prevYear, prevMonth, prevDay, prevHour = prevTime.year, prevTime.month, prevTime.day, prevTime.hour
    startTimeStrFormat = "%s-%s-%s %s:%s:%s"
    for hour, minute in openTimeList:
        # 当前小时的和上一小时才有可能时进入时间
        if hour not in [curHour, prevHour]:
            continue
        # 获取本次比较的开启时间
        if hour == curHour:
            startTimeStr = startTimeStrFormat % (curYear, curMonth, curDay, hour, minute, "00")
        else:
            startTimeStr = startTimeStrFormat % (prevYear, prevMonth, prevDay, hour, minute, "00")
        # 字符串转化为datetime
        startTime = datetime.datetime.strptime(startTimeStr, ChConfig.TYPE_Time_Format)
        # 距开始时间的时间差
        pastTime = curTime - startTime
        # 换算成秒数
        pastSeconds = pastTime.seconds
        # 如果在规定准备秒数内,则返回True
        if 0 <= pastSeconds <= prepareSeconds:
            return True
    return False
## 副本行为 - 鼓舞buff
#  @param curPlayer 玩家
#  @param key 副本玩家字典key
#  @param encourageType 金钱类型
#  @param tick 当前时间
#  @param isMaxlv 是否直接满级
#  @return None
def FbEncourageBuff(curPlayer, key, encourageType, tick, ownerID=0):
    #GameWorld.Log("FbEncourageBuff moneyType=%s" % (moneyType))
    curMapID = curPlayer.GetMapID()
    curMapID = GetRecordMapID(curMapID)
    ipyData = IpyGameDataPY.GetIpyGameData('FbEncourage', curMapID, encourageType)
    if not ipyData:
        return
    maxCnt = ipyData.GetInspireMaxLV()
    gameFB = GameWorld.GetGameFB()
    ownerID = ownerID or curPlayer.GetID()
    encourageLV = gameFB.GetPlayerGameFBDictByKey(ownerID, key)
    encourageCntKey = 'FbEncourageCnt_%s' % encourageType
    encourageCnt = gameFB.GetPlayerGameFBDictByKey(ownerID, encourageCntKey)
    maxLV = IpyGameDataPY.GetFuncEvalCfg('FBEncourageBuff', 2, {}).get(curMapID, 0)
    if encourageLV >= maxLV:
        PlayerControl.NotifyCode(curPlayer, "GeRen_chenxin_93643")
        return
    if encourageCnt >= maxCnt:
        if encourageType == IPY_GameWorld.TYPE_Price_Silver_Money:
            PlayerControl.NotifyCode(curPlayer, "Xjmj_CopperInspireFull")
        else:
            PlayerControl.NotifyCode(curPlayer, "GeRen_chenxin_93643")
        return
    encourageCost = eval(ipyData.GetMoneyCount())
    costMoneyList = PlayerControl.HaveMoneyEx(curPlayer, encourageType, encourageCost)
    if not costMoneyList:
        return
    # 扣除鼓舞消耗
    infoDict = {"MapID":curMapID}
    for moneyType, moneyCnt in costMoneyList:
        if not PlayerControl.PayMoney(curPlayer, moneyType, moneyCnt, ChConfig.Def_Cost_FBEncourage, infoDict):
            return
    buffTypeID = IpyGameDataPY.GetFuncEvalCfg('FBEncourageBuff', 1, {}).get(curMapID, ChConfig.Def_SkillID_FBEncourageBuff)
    skillBuffID = buffTypeID + encourageLV
    skillBuff = GameWorld.GetGameData().GetSkillBySkillID(skillBuffID)
    if not skillBuff:
        GameWorld.Log("FbEncourageBuff   找不到技能%s" % skillBuffID)
        return
    buffType = SkillCommon.GetBuffType(skillBuff)
    gameFB.SetPlayerGameFBDict(ownerID, key, encourageLV+1)
    gameFB.SetPlayerGameFBDict(ownerID, encourageCntKey, encourageCnt+1)
    #GameWorld.Log("FbEncourageBuff encourage nextLV=%s success" % encourageLV)
    addHurtNum = IpyGameDataPY.GetFuncEvalCfg('FBEncourageBuff', 3, {}).get(curMapID, 0)
    if curMapID == ChConfig.Def_FBMapID_AllFamilyBoss:
        #给副本里所有盟成员提示
        playerManager = GameWorld.GetMapCopyPlayerManager()
        for index in xrange(playerManager.GetPlayerCount()):
            player = playerManager.GetPlayerByIndex(index)
            if not player:
                continue
            if player.GetFamilyID() != ownerID:
                continue
            BuffSkill.DoAddBuff(player, buffType, skillBuff, tick)
            PlayerControl.NotifyCode(player, "AllianceBossText2", [curPlayer.GetName(), encourageLV+1])
            SendFBEncourageInfo(player, encourageLV+1, ownerID)
            if player.GetID() == curPlayer.GetID():
                PlayerSuccess.DoAddSuccessProgress(curPlayer, ShareDefine.SuccType_FBEncourage, 1, [curMapID])
    else:
        BuffSkill.DoAddBuff(curPlayer, buffType, skillBuff, tick)
        PlayerControl.NotifyCode(curPlayer, "GeRen_chenxin_628920", [(encourageLV+1)*addHurtNum])
        SendFBEncourageInfo(curPlayer, encourageLV+1, ownerID)
        #成就
        PlayerSuccess.DoAddSuccessProgress(curPlayer, ShareDefine.SuccType_FBEncourage, 1, [curMapID])
    return True
## 添加副本鼓舞buff,一般用于玩家掉线后,在规定时间内重新上线回到副本时重新上buff
#  @param curPlayer 玩家
#  @param key 副本玩家字典key
#  @param tick 当前时间
#  @return None
def AddFbEncourageBuff(curPlayer, key, tick, ownerID=0):
    curPlayerID = curPlayer.GetID()
    GameWorld.Log("AddFbEncourageBuff() curPlayerID=%s" % curPlayerID)
    ownerID = ownerID or curPlayer.GetID()
    gameFB = GameWorld.GetGameFB()
    encourageLV = gameFB.GetPlayerGameFBDictByKey(ownerID, key)
    if not encourageLV:
        return
    mapID = GameWorld.GetMap().GetMapID()
    mapID = GetRecordMapID(mapID)
    buffTypeID = IpyGameDataPY.GetFuncEvalCfg('FBEncourageBuff', 1, {}).get(mapID, ChConfig.Def_SkillID_FBEncourageBuff)
    skillBuffID = buffTypeID + encourageLV -1
    skillBuff = GameWorld.GetGameData().GetSkillBySkillID(skillBuffID)
    if not skillBuff:
        GameWorld.Log("FbEncourageBuff   找不到技能%s" % skillBuffID)
        return
    buffType = SkillCommon.GetBuffType(skillBuff)
    BuffSkill.DoAddBuff(curPlayer, buffType, skillBuff, tick)
    SendFBEncourageInfo(curPlayer, encourageLV, ownerID)
    return
## 清除鼓舞buff
#  @param curPlayer 玩家
#  @param tick 当前时间
#  @return True - 清除成功 ; False - 无该buff
def ClearEncourageBuff(curPlayer, tick):
    for buffTypeID in list(set(IpyGameDataPY.GetFuncEvalCfg('FBEncourageBuff', 1, {}).values())):
        if BuffSkill.DelBuffBySkillID(curPlayer, buffTypeID, tick):
            playerControl = PlayerControl.PlayerControl(curPlayer)
            playerControl.RefreshPlayerAttrByBuff()
            GameWorld.Log("ClearEncourageBuff() True")
            return True
    GameWorld.Log("ClearEncourageBuff() False")
    return False
## 发送副本鼓舞信息
#  @param curPlayer 玩家
#  @return None
def SendFBEncourageInfo(curPlayer, lv, ownerID=0):
    #//A3 0A 副本鼓舞信息通知 #tagMCFBEncourageInfo
    curMapID = curPlayer.GetMapID()
    curMapID = GetRecordMapID(curMapID)
    ipyDataList = IpyGameDataPY.GetIpyGameDataByCondition('FbEncourage', {'DataMapID':curMapID}, True)
    if not ipyDataList:
        return
    encourageInfo = ChPyNetSendPack.tagMCFBEncourageInfo()
    encourageInfo.Clear()
    encourageInfo.InfoList = []
    encourageCntKey = 'FbEncourageCnt_%s'
    gameFB = GameWorld.GetGameFB()
    ownerID = ownerID or curPlayer.GetID()
    for ipyData in ipyDataList:
        inspireType = ipyData.GetInspireType()
        packData = ChPyNetSendPack.tagMCFBEncourageCnt()
        packData.MoneyType = inspireType
        packData.EncourageCnt = gameFB.GetPlayerGameFBDictByKey(ownerID, encourageCntKey % inspireType)
        encourageInfo.InfoList.append(packData)
    encourageInfo.Cnt = len(encourageInfo.InfoList)
    NetPackCommon.SendFakePack(curPlayer, encourageInfo)
    return
## 获取玩家所在副本区域福利倍值
#  @param curPlayer 玩家
#  @return 倍值-默认为1
def GetAreaRewardMultiple(curPlayer):
    return max(1, curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_AreaRewardMultiple))
## 设置玩家所在副本区域福利倍值
#  @param curPlayer 玩家
#  @param value 更新倍值
#  @return
def SetAreaRewardMultiple(curPlayer, value):
    curPlayer.SetDict(ChConfig.Def_PlayerKey_AreaRewardMultiple, value)
    return
## 检查是否进入副本CD中
#  @param curPlayer 玩家
#  @param mapID
#  @return True-CD中,不可进入;False-非CD中,可进入
def CheckIsEnterCD(curPlayer, mapID):
    return GetFBEnterCD(curPlayer, mapID) > 0
## 获取进入副本CD时间
#  @param curPlayer 玩家
#  @param mapID
#  @return <=0 代表没有CD, >0表示还剩下的CD tick
def GetFBEnterCD(curPlayer, mapID):
    mapID = GetRecordMapID(mapID)
    enterCDDict = IpyGameDataPY.GetFuncEvalCfg('FBEnterCD', 1)
    if mapID not in enterCDDict:
        return 0
    lvLimitDict = IpyGameDataPY.GetFuncEvalCfg('FBEnterCD', 3)
    if mapID in lvLimitDict:
        if curPlayer.GetLV() >= lvLimitDict[mapID]:
            return 0
    cdTick = enterCDDict[mapID]
    lastEnterTick = GetFBPDictValue(curPlayer, ChConfig.Def_PDict_LastEnterFBTick % mapID)
    if not lastEnterTick:
        return 0
    timeNum = GameWorld.ChangeTimeStrToNum(GameWorld.GetCurrentDataTimeStr())
    passTick = max(0, timeNum - lastEnterTick)
    curCDTick = max(0, cdTick - passTick)
    if curCDTick > 0:
        GameWorld.DebugLog("副本进入CD中!mapID=%s,timeNum=%s,lastEnterTick=%s,passTick=%s,剩余=%s"
                           % (mapID, timeNum, lastEnterTick, passTick, curCDTick))
    return curCDTick
## 更新玩家进入副本时间
#  @param curPlayer 玩家
#  @param tick 更新值
#  @return
def UpdateFBEnterTick(curPlayer):
    mapID = GameWorld.GetMap().GetMapID()
    mapID = GetRecordMapID(mapID)
    enterCDDict = IpyGameDataPY.GetFuncEvalCfg('FBEnterCD', 1)
    if mapID not in enterCDDict:
        return
    timeNum = GameWorld.ChangeTimeStrToNum(GameWorld.GetCurrentDataTimeStr())
    SetFBPDictValue(curPlayer, ChConfig.Def_PDict_LastEnterFBTick % mapID, timeNum)
    GameWorld.DebugLog("UpdateFBEnterTick mapID=%s,timeNum=%s" % (mapID, timeNum))
    SyncFBEnterTick(curPlayer, mapID)
    adCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_FBADCnt % mapID)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_FBADCnt % mapID, adCnt + 1)
    Sync_FBPlayerFBInfoData(curPlayer, mapID)
    return
## 获取记录值的mapID
@@ -2327,42 +1640,42 @@
#  @return
#  @remarks 一般用于几张地图公用一份存储记录,如组队副本进入次数,CD时间等数据需共享
def GetRecordMapID(mapID):
    DataMapIDDict = IpyGameDataPY.GetConfigEx("DataMapIDDict")
    if not DataMapIDDict:
        mIDToDataMapIDDict = {} # 场景ID对应功能地图ID
        dMapIDDict = {}
        ipyDataMgr = IpyGameDataPY.IPY_Data()
        for i in xrange(ipyDataMgr.GetFBLineCount()):
            ipyData = ipyDataMgr.GetFBLineByIndex(i)
            dMapID = ipyData.GetDataMapID()
            mID = ipyData.GetMapID()
            mIDList= dMapIDDict.get(dMapID, [])
            if mID not in mIDList:
                mIDList.append(mID)
                dMapIDDict[dMapID] = mIDList
            dMIDList= mIDToDataMapIDDict.get(mID, [])
            if dMapID not in dMIDList:
                dMIDList.append(dMapID)
                mIDToDataMapIDDict[mID] = dMIDList
        unMIDList = []
        for mID, dMIDList in mIDToDataMapIDDict.items():
            if len(dMIDList) > 1:
                unMIDList.append(mID)
                #GameWorld.DebugLog("----------- 同个场景对应到多个功能地图的,视为无意义的地图! mID=%s, to dMIDList=%s" % (mID, dMIDList))
        for dMapID, mIDList in dMapIDDict.items():
            for unMID in unMIDList:
                if unMID in mIDList:
                    mIDList.remove(unMID)
            if len(mIDList) <= 1:
                dMapIDDict.pop(dMapID)
        DataMapIDDict = IpyGameDataPY.SetConfigEx("DataMapIDDict", dMapIDDict)
        #GameWorld.Log("加载DataMapIDDict=%s" % DataMapIDDict)
    for dataMapID, mapIDList in DataMapIDDict.items():
        if mapID in mapIDList:
            return dataMapID
#    DataMapIDDict = IpyGameDataPY.GetConfigEx("DataMapIDDict")
#    if not DataMapIDDict:
#        mIDToDataMapIDDict = {} # 场景ID对应功能地图ID
#        dMapIDDict = {}
#        ipyDataMgr = IpyGameDataPY.IPY_Data()
#        for i in xrange(ipyDataMgr.GetFBLineCount()):
#            ipyData = ipyDataMgr.GetFBLineByIndex(i)
#            dMapID = ipyData.GetDataMapID()
#            mID = ipyData.GetMapID()
#            mIDList= dMapIDDict.get(dMapID, [])
#            if mID not in mIDList:
#                mIDList.append(mID)
#                dMapIDDict[dMapID] = mIDList
#
#            dMIDList= mIDToDataMapIDDict.get(mID, [])
#            if dMapID not in dMIDList:
#                dMIDList.append(dMapID)
#                mIDToDataMapIDDict[mID] = dMIDList
#
#        unMIDList = []
#        for mID, dMIDList in mIDToDataMapIDDict.items():
#            if len(dMIDList) > 1:
#                unMIDList.append(mID)
#                #GameWorld.DebugLog("----------- 同个场景对应到多个功能地图的,视为无意义的地图! mID=%s, to dMIDList=%s" % (mID, dMIDList))
#        for dMapID, mIDList in dMapIDDict.items():
#            for unMID in unMIDList:
#                if unMID in mIDList:
#                    mIDList.remove(unMID)
#            if len(mIDList) <= 1:
#                dMapIDDict.pop(dMapID)
#        DataMapIDDict = IpyGameDataPY.SetConfigEx("DataMapIDDict", dMapIDDict)
#        #GameWorld.Log("加载DataMapIDDict=%s" % DataMapIDDict)
#
#    for dataMapID, mapIDList in DataMapIDDict.items():
#        if mapID in mapIDList:
#            return dataMapID
    return mapID
def GetGeneralTrainMapIDList():
@@ -2381,53 +1694,8 @@
        
    return GeneralTrainMapIDList
def GetClientCustomScene():
    ## 获取前端自定义副本场景
    mapIDList = GetGeneralTrainMapIDList()
    return mapIDList + ChConfig.ClientCustomSceneList
## 同步进入副本时间
#  @param curPlayer 玩家
#  @param syncMapID 同步的地图,默认0为全部
#  @return None
def SyncFBEnterTick(curPlayer, syncMapID=0):
    enterCDDict = IpyGameDataPY.GetFuncEvalCfg('FBEnterCD', 1)
    if not enterCDDict:
        return
    timeNum = GameWorld.ChangeTimeStrToNum(GameWorld.GetCurrentDataTimeStr())
    enterList = ChPyNetSendPack.tagMCFBEnterTickList()
    enterList.Clear()
    enterList.EnterTickList = []
    for mapID in enterCDDict.keys():
        if syncMapID not in [0, mapID]:
            continue
        lastEnterTick = GetFBPDictValue(curPlayer, ChConfig.Def_PDict_LastEnterFBTick % mapID)
        # 修正副本CD时间
        if timeNum < lastEnterTick:
            SetFBPDictValue(curPlayer, ChConfig.Def_PDict_LastEnterFBTick % mapID, timeNum)
            lastEnterTick = timeNum
            GameWorld.DebugLog("修正玩家副本CD时间 mapID=%s,timeNum=%s" % (mapID, timeNum), curPlayer.GetPlayerID())
        enterTickObj = ChPyNetSendPack.tagMCFBEnterTick()
        enterTickObj.Clear()
        enterTickObj.MapID = mapID
        enterTickObj.LastEnterTick = lastEnterTick#max(enterCDDict.get(mapID) - (timeNum - lastEnterTick), 0)
        enterList.EnterTickList.append(enterTickObj)
    enterList.Cnt = len(enterList.EnterTickList)
    NetPackCommon.SendFakePack(curPlayer, enterList)
    return
## 通知个人通用副本信息
#  @param curPlayer: 玩家实例
#  @param runTime: 已经进行时间
#  @return: None
def Sync_FBPlayerFBInfoData(curPlayer, mapIDInfo=None):
    ## 通知个人通用副本信息
    if not mapIDInfo:
        ipyDataMgr = IpyGameDataPY.IPY_Data()
        mapIDList = [ipyDataMgr.GetFBFuncByIndex(i).GetDataMapID() for i in xrange(ipyDataMgr.GetFBFuncCount())]
@@ -2436,76 +1704,25 @@
            return
        mapIDList = [mapIDInfo] if type(mapIDInfo) == int else mapIDInfo
        
    fbInfoData = ChPyNetSendPack.tagMCPlayerFBInfoData()
    fbInfoData.Clear()
    fbInfoData.FBDataCnt = len(mapIDList)
    fbInfoData.FBDataList = []
    clientPack = ObjPool.GetPoolMgr().acquire(ChPyNetSendPack.tagSCFBInfoList)
    clientPack.FBDataList = []
    
    for mID in mapIDList:
        mapInfo = ChPyNetSendPack.tagMCFBInfo()
        mapInfo.Clear()
        mapInfo.FBID = mID
        mapInfo.EnterCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_EnterFbCntDay % mID)
        mapInfo.EnterCntTotal = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_EnterFbCntTotal % mID)
        mapInfo.RecoverCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_RecoverFbCnt % mID)
        mapInfo.ItemAddCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_ItemAddFbCnt % mID)
        mapInfo.PassLineID = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_FBPassLineID % mID)
    for mapID in mapIDList:
        fbInfo = ObjPool.GetPoolMgr().acquire(ChPyNetSendPack.tagSCFBInfo)
        fbInfo.MapID = mapID
        fbInfo.EnterCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_FbEnterCnt % mapID)
        fbInfo.ADAddCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_FBADCnt % mapID)
        fbInfo.BuyAddCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_FBBuyCnt % mapID)
        fbInfo.ItemAddCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_FBItemCnt % mapID)
        fbInfo.PassLineID = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_FBPassLineID % mapID)
        for keyNum in range(ChConfig.Def_FBStar_MaxKeyCnt):
            gradeValue = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_PlayerFBStar_MapId % (mID, keyNum))
            mapInfo.PassGrade.append(gradeValue)
        mapInfo.PassGradeCnt = len(mapInfo.PassGrade)
        #GameWorld.DebugLog("FBID:%s---:%s"%(mapInfo.FBID,mapInfo.EnterCnt))
        fbInfoData.FBDataList.append(mapInfo)
            gradeValue = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_FBStar % (mapID, keyNum))
            fbInfo.PassGrade.append(gradeValue)
        fbInfo.PassGradeCnt = len(fbInfo.PassGrade)
        clientPack.FBDataList.append(fbInfo)
        
    NetPackCommon.SendFakePack(curPlayer, fbInfoData)
    return
#// A3 BD 通知玩家购买副本进入次数 #tagMCBuyEnterInfo
#
#struct    tagMCBuyEnterInfo
#{
#    tagHead            Head;
#    BYTE        FBCount;    // 副本个数
#    DWORD            tagMCFBInfo[FBCount];    // 副本信息
#};
#
#struct    tagMCBuyInfo
#{
#    tagHead            Head;
#    DWORD            FBID;        // 副本ID
#    BYTE        BuyCount;    // 已购买次数
#};
## 通知个人购买副本次数信息
#  @param curPlayer: 玩家实例
#  @param runTime: 已经进行时间
#  @return: None
def Sync_FBPlayerFBBuyCount(curPlayer, mapIDList=[]):
    if not mapIDList:
        mapIDList = []
        ipyDataMgr = IpyGameDataPY.IPY_Data()
        for i in xrange(ipyDataMgr.GetFBFuncCount()):
            ipyData = ipyDataMgr.GetFBFuncByIndex(i)
            if not ipyData.GetBuyTimesVIPPriID():
                continue
            mapIDList.append(ipyData.GetDataMapID())
    fbInfoData = ChPyNetSendPack.tagMCBuyEnterInfo()
    fbInfoData.Clear()
    fbInfoData.FBInfo = []
    for mID in mapIDList:
        mapInfo = ChPyNetSendPack.tagMCBuyInfo()
        mapInfo.Clear()
        mapInfo.FBID = mID
        mapInfo.BuyCount = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_BuyFbCntDay % mID)
        fbInfoData.FBInfo.append(mapInfo)
        #GameWorld.DebugLog("FBID:%s---BuyCount:%s"%(mapInfo.FBID,mapInfo.BuyCount))
    fbInfoData.FBCount = len(fbInfoData.FBInfo)
    if fbInfoData.FBCount > 0:
        NetPackCommon.SendFakePack(curPlayer, fbInfoData)
    clientPack.FBDataCnt = len(clientPack.FBDataList)
    NetPackCommon.SendFakePack(curPlayer, clientPack)
    return
## 根据人数分组
@@ -2541,100 +1758,6 @@
            group.extend(tmpList[gi])
            
    return groupList
def ClearAreaRewardRecord(playerID):
    ##清除战场区域福利记录
    gameWorld = GameWorld.GetGameWorld()
    gameWorld.SetGameWorldDict(ChConfig.Map_Player_AreaReward_GetCnt%playerID, 0)
    gameWorld.SetGameWorldDict(ChConfig.Map_Player_AreaReward_GetExp%playerID, 0)
    gameWorld.SetGameWorldDict(ChConfig.Map_Player_AreaReward_GetExpPoint%playerID, 0)
    gameWorld.SetGameWorldDict(ChConfig.Map_Player_AreaReward_GetZhenQiTotal%playerID, 0)
    gameWorld.SetGameWorldDict(ChConfig.Map_Player_AreaReward_GetTechPoint%playerID, 0)
    return
##战场区域福利逻辑
# @param tick 时间戳
# @return 无意义
def DoLogicAreaReward(cfgKeyName, tick, needAlive=False):
    gameFB = GameWorld.GetGameFB()
    gameWorld = GameWorld.GetGameWorld()
    rewardInterval = IpyGameDataPY.GetFuncCfg(cfgKeyName, 2)
    rewardFormatDict = IpyGameDataPY.GetFuncEvalCfg(cfgKeyName)
    getCntLimit = IpyGameDataPY.GetFuncCfg(cfgKeyName, 3)
    lastAwardTick = gameFB.GetGameFBDictByKey(ChConfig.Map_FBDict_LastAreaRewardTick)
    if tick - lastAwardTick < rewardInterval:
        return
    gameFB.SetGameFBDict(ChConfig.Map_FBDict_LastAreaRewardTick, tick)
    GameWorld.DebugLog("给战场福利 tick=%s,needAlive=%s" % (tick, needAlive))
    # 更新玩家战场持续时间
    playerManager = GameWorld.GetMapCopyPlayerManager()
    for index in xrange(playerManager.GetPlayerCount()):
        curPlayer = playerManager.GetPlayerByIndex(index)
        if not curPlayer:
            continue
        if needAlive and GameObj.GetHP(curPlayer) <= 0:
            continue
        playerID = curPlayer.GetPlayerID()
        if getCntLimit:
            getCnt = gameWorld.GetGameWorldDictByKey(ChConfig.Map_Player_AreaReward_GetCnt%playerID)
            if getCnt >= getCntLimit:
                continue
            gameWorld.SetGameWorldDict(ChConfig.Map_Player_AreaReward_GetCnt%playerID, getCnt + 1)
        multiple = GetAreaRewardMultiple(curPlayer) # 福利倍数
        reLV = curPlayer.GetLV()
        reExp = PlayerControl.GetPlayerReExp(curPlayer)
        playerControl = PlayerControl.PlayerControl(curPlayer)
        if "Exp" in rewardFormatDict:
            addExp = eval(rewardFormatDict["Exp"])
            addExp = playerControl.AddExp(addExp)
            if addExp > 0:
                totalExp = GetFBAreaRewardExp(gameWorld, playerID) + addExp
                gameWorld.SetGameWorldDict(ChConfig.Map_Player_AreaReward_GetExp%playerID, totalExp % ChConfig.Def_PerPointValue)
                gameWorld.SetGameWorldDict(ChConfig.Map_Player_AreaReward_GetExpPoint%playerID, totalExp / ChConfig.Def_PerPointValue)
        if "ZhenQi" in rewardFormatDict:
            addZhenQi = eval(rewardFormatDict["ZhenQi"])
            PlayerControl.PlayerAddZhenQi(curPlayer, addZhenQi, True, True, "FB")
            totalZhenQi = gameWorld.GetGameWorldDictByKey(ChConfig.Map_Player_AreaReward_GetZhenQiTotal%playerID)
            totalZhenQi += addZhenQi
            gameWorld.SetGameWorldDict(ChConfig.Map_Player_AreaReward_GetZhenQiTotal%playerID, totalZhenQi)
        #GameWorld.DebugLog("    战场福利 倍区=%s,reLV=%s,reExp=%s,addExp=%s,addZQ=%s,totalExp=%s,totalZQ=%s"
        #                   % (multiple, reLV, reExp, addExp, addZhenQi, totalExp, totalZhenQi), playerID)
    return
def GetFBAreaRewardExp(gameWorld, playerID):
    exp = gameWorld.GetGameWorldDictByKey(ChConfig.Map_Player_AreaReward_GetExp%playerID)
    expPoint = gameWorld.GetGameWorldDictByKey(ChConfig.Map_Player_AreaReward_GetExpPoint%playerID)
    return expPoint * ChConfig.Def_PerPointValue + exp
def GetFBAreaRewardZhenQi(gameWorld, playerID):
    return gameWorld.GetGameWorldDictByKey(ChConfig.Map_Player_AreaReward_GetZhenQiTotal%playerID)
def GetFBAreaRewardTechPoint(gameWorld, playerID):
    return gameWorld.GetGameWorldDictByKey(ChConfig.Map_Player_AreaReward_GetTechPoint%playerID)
def NotifyCopyMapPlayerFBHelp(tick, fbHelpFunc, interval=10000, befLogicFunc=None):
    gameFB = GameWorld.GetGameFB()
    lastTick = gameFB.GetGameFBDictByKey(ChConfig.Def_FB_NotifyFBHelpTick)
    if tick - lastTick < interval:
        return
    gameFB.SetGameFBDict(ChConfig.Def_FB_NotifyFBHelpTick, tick)
    if befLogicFunc:
        befLogicFunc(tick)
    playerManager = GameWorld.GetMapCopyPlayerManager()
    for index in xrange(playerManager.GetPlayerCount()):
        curPlayer = playerManager.GetPlayerByIndex(index)
        if not curPlayer:
            continue
        fbHelpFunc(curPlayer, tick)
    return
def GetCrossDynamicLineMapZoneID():
    ## 获取跨服动态线路地图本线路跨服分区