hxp
2023-09-29 2a659639d74889599ed54458863a2f7b31ff4eff
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_FamilyBoss.py
@@ -2,210 +2,168 @@
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
#-------------------------------------------------------------------------------
#
##@package GameWorldLogic.FBProcess.GameLogic_FamilyBoss
#
# @todo:战盟boss副本
# @author xdh
# @date 2018-02-08
# @todo:战盟boss副本/仙盟试炼
# @author hxp
# @date 2023-09-29
# @version 1.0
#
# 详细描述: 战盟boss副本
# 详细描述: 战盟boss副本/仙盟试炼
#
#---------------------------------------------------------------------
#"""Version = 2018-02-08 17:20"""
#---------------------------------------------------------------------
#-------------------------------------------------------------------------------
#"""Version = 2023-09-29 02:00"""
#-------------------------------------------------------------------------------
import FBCommon
import GameWorldProcess
import GameWorld
import IPY_GameWorld
import PlayerControl
import GameWorld
import PlayerTongTianLing
import NPCCustomRefresh
import ChPyNetSendPack
import ItemControler
import NetPackCommon
import IpyGameDataPY
import PlayerFamily
import ShareDefine
import EventReport
import SkillCommon
import PyGameData
import BuffSkill
import ChConfig
import math
#当前副本地图的状态
(
FB_Step_Open, # 地图开启
FB_Step_MapPrepare, # 地图准备
FB_Step_Fighting, # 战斗中
FB_Step_LeaveTime, # 自由时间(还可进入)
FB_Step_LeaveTime1, # 自由时间(不可进入)
FB_Step_LeaveTime, # 自由时间
FB_Step_Over, # 副本关闭
) = range(6)
) = range(5)
#---战盟副本---
FamilyBossFB_Star = 'FamilyBossFB_Star' #评级
Map_FamilyBossFB_FamilyID = "FamilyBossFB_FamilyID"     # 对应的家族id
(
Def_Time_MapPrepare, # 准备时间, 秒
Def_Time_Fight, # 持续时间, 秒
Def_Time_Leave, # 结束时间, 秒
Def_StarTime, # 星级对应耗时配置, 秒
) = range(4)
def GetFamilyBossFBTimeCfg():return FBCommon.GetFBLineStepTime(ChConfig.Def_FBMapID_FamilyBossMap, 0)
def GameServerOpenFamilyBoss(familyID, openCount):
    if familyID in PyGameData.g_familyBossOpenCountDict:
        curOpenCount = PyGameData.g_familyBossOpenCountDict[familyID]
        if curOpenCount == openCount:
            return
    PyGameData.g_familyBossOpenCountDict[familyID] = openCount
    if familyID in PyGameData.g_familyBossPlayer:
        PyGameData.g_familyBossPlayer.pop(familyID)
    GameWorld.DebugLog("开启仙盟Boss: familyID=%s,openCount=%s" % (familyID, openCount))
    return
def AddFamilyBossPlayer(curPlayer):
    familyID = curPlayer.GetFamilyID()
    if not familyID:
        return
    if familyID not in PyGameData.g_familyBossOpenCountDict:
        return
    openCount = PyGameData.g_familyBossOpenCountDict[familyID]
    familyPlayerList = PyGameData.g_familyBossPlayer.get(familyID, [])
    playerID = curPlayer.GetPlayerID()
    if playerID in familyPlayerList:
        return
    familyPlayerList.append(playerID)
    PyGameData.g_familyBossPlayer[familyID] = familyPlayerList
    GameWorld.DebugLog("仙盟参与玩家: %s" % PyGameData.g_familyBossPlayer)
    EventReport.WriteEvent_FB(curPlayer, ChConfig.Def_FBMapID_FamilyBossMap, openCount, ChConfig.CME_Log_Start)
    PlayerTongTianLing.AddTongTianTaskValue(curPlayer, ChConfig.TTLTaskType_FamilyBoss, 1)
    return
##开启副本
# @param tick 时间戳
# @return 返回值无意义
# @remarks 开启副本
def OnOpenFB(tick):
    gameFB = GameWorld.GetGameFB()
    gameFB.SetGameFBDict(Map_FamilyBossFB_FamilyID, 0)
    gameFB.SetGameFBDict(FamilyBossFB_Star, 0)
    return
##关闭副本
# @param tick 时间戳
# @return 无意义
# @remarks
def OnCloseFB(tick):
    #副本踢出玩家
    # 通知GameServer副本结束
    gameFB = GameWorld.GetGameFB()
    familyID = gameFB.GetGameFBDictByKey(Map_FamilyBossFB_FamilyID)
#    msgStr = str([familyID, 0])
#    GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(0, 0, 0, 'FamilyBossFBState', msgStr, len(msgStr))
class BattlePlayer():
    
    if familyID in PyGameData.g_familyBossOpenCountDict:
        PyGameData.g_familyBossOpenCountDict.pop(familyID)
        GameWorld.DebugLog("移除仙盟开启boss数:%s" % PyGameData.g_familyBossOpenCountDict)
    if familyID in PyGameData.g_familyBossPlayer:
        PyGameData.g_familyBossPlayer.pop(familyID)
        GameWorld.DebugLog("移除仙盟参与玩家:%s" % PyGameData.g_familyBossPlayer)
    def __init__(self, playerID):
        self.playerID = playerID
        self.hurtValue = 0 # 当前累计伤害
        self.hurtValueLast = 0 # 上次同步结算时伤害
        self.fightTickTotal = 0 # 累计战斗tick
        self.statsTick = 0 # 统计tick
        return
    def onEnter(self, curPlayer, tick):
        hurtValue = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FamilyBossHurtValue)
        hurtValuePoint = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FamilyBossHurtValuePoint)
        self.hurtValue = hurtValuePoint * ChConfig.Def_PerPointValue + hurtValue
        self.hurtValueLast = self.hurtValue
        self.fightTickTotal = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FamilyBossFightSeconds) * 1000
        self.statsTick = tick
        return
def OnFBPlayerOnLogin(curPlayer):
    SyncFamilyBossPlayerInfo(curPlayer)
    return
def OnFBPlayerOnDay(curPlayer):
    playerID = curPlayer.GetPlayerID()
    hurtValue = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FamilyBossHurtValue)
    hurtValuePoint = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FamilyBossHurtValuePoint)
    hurtValueTotal = hurtValuePoint * ChConfig.Def_PerPointValue + hurtValue
    rewardRecord = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FamilyBossHurtAward)
    #仙盟伤血奖励GameServer处理补发
    #GameWorld.DebugLog("仙盟boss伤血过天. hurtValueTotal=%s,rewardRecord=%s" % (hurtValueTotal, rewardRecord), playerID)
    ipyDataMgr = IpyGameDataPY.IPY_Data()
    for index in range(ipyDataMgr.GetFamilyBossHurtAwardCount()):
        ipyData = ipyDataMgr.GetFamilyBossHurtAwardByIndex(index)
        if ipyData.GetAwardType() != 1:
            continue
        needHurtTotal = ipyData.GetNeedHurtTotal()
        if hurtValueTotal < needHurtTotal:
            #GameWorld.DebugLog("    伤血不足,不补发该奖励! needHurtTotal=%s" % needHurtTotal, playerID)
            continue
        recordIndex = ipyData.GetRecordIndex()
        if rewardRecord & pow(2, recordIndex):
            #GameWorld.DebugLog("    该个人奖励已领奖! recordIndex=%s,rewardRecord=%s" % (recordIndex, rewardRecord), playerID)
            continue
        
        paramList = [needHurtTotal]
        awardItemList = ipyData.GetAwardItemList()
        PlayerControl.SendMailByKey("FamilyBossHurtAward", [playerID], awardItemList, paramList)
        #GameWorld.DebugLog("    邮件补发伤血奖励! recordIndex=%s" % recordIndex, playerID)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FamilyBossHurtValue, 0)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FamilyBossHurtValuePoint, 0)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FamilyBossFightSeconds, 0)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FamilyBossHurtAward, 0)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FamilyBossHurtAwardFamily, 0)
    SyncFamilyBossPlayerInfo(curPlayer)
    return
def GetBattlePlayer(playerID):
    if playerID in PyGameData.g_familyBossHurtPlayerDict:
        batPlayer = PyGameData.g_familyBossHurtPlayerDict[playerID]
    else:
        batPlayer = BattlePlayer(playerID)
        PyGameData.g_familyBossHurtPlayerDict[playerID] = batPlayer
    return batPlayer
def OnOpenFB(tick):
    return
def OnCloseFB(tick):
    GameWorld.GetGameWorld().SetPropertyID(0)
    FBCommon.DoLogic_FBKickAllPlayer()
    return
## 是否能够通过活动查询进入
#  @param curPlayer 玩家实例
#  @param mapID 地图ID
#  @param lineID 线路id
#  @param tick 时间戳
#  @return 布尔值
def OnEnterFBEvent(curPlayer, mapID, lineID, tick):
    return __CheckEnter(curPlayer, mapID)
##进入副本检查
#  @param curPlayer 玩家实例
#  @param mapID 地图ID
#  @param lineID 线路id
# @return None
def __CheckEnter(curPlayer, mapID):
    # 是否有战盟
    if curPlayer.GetFamilyID() <= 0:
        GameWorld.DebugLog("没有战盟,不能进入战盟boss副本!")
        GameWorld.DebugLog("没有战盟,不能进入战盟boss副本!", curPlayer.GetPlayerID())
        return False
    playerID = curPlayer.GetPlayerID()
    fightSeconds = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FamilyBossFightSeconds) # 已战斗时长
    fightSecondsMax = IpyGameDataPY.GetFuncCfg("FamilyBossFB", 1)
    if fightSeconds >= fightSecondsMax:
        GameWorld.DebugLog("已经达到仙盟boss战斗时长上限,无法进入. fightSeconds=%s" % fightSeconds, playerID)
        return False
    
    return True
##副本玩家进入点
# @param curPlayer 玩家实例
# @param mapID 地图ID
# @param lineId 分线ID
# @param ipyEnterPosInfo 功能线路IPY配置坐标信息
# @param tick 时间戳
# @return posX, posY, 随机半径(可选)
def OnGetFBEnterPos(curPlayer, mapID, lineId, ipyEnterPosInfo, tick):
    return ipyEnterPosInfo
##是否可以进入
# @param ask 请求结构体
# @param tick 时间戳
# @return TChangeMapError
# @remarks 验证家族是否在今天的家族战表
def OnChangeMapAsk(ask, tick):
    return IPY_GameWorld.cmeAccept
##玩家进入副本
# @param curPlayer 玩家实例
# @param tick 时间戳
# @return 无意义
# @remarks 玩家进入副本
def DoEnterFB(curPlayer, tick):
    mapID = GameWorld.GetGameWorld().GetMapID()
    if not __CheckEnter(curPlayer, mapID):
        PlayerControl.PlayerLeaveFB(curPlayer)
        return
    playerID = curPlayer.GetPlayerID()
    gameFB = GameWorld.GetGameFB()
    fbStep = gameFB.GetFBStep()
    
    if fbStep == FB_Step_Open:
        FBCommon.SetFBStep(FB_Step_MapPrepare, tick)
        familyID = curPlayer.GetFamilyID()
        gameFB.SetGameFBDict(Map_FamilyBossFB_FamilyID, familyID)
        msgStr = str([familyID, 1])
        GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(0, 0, 0, 'FamilyBossFBState', msgStr, len(msgStr))
    familyBossFBCfg = GetFamilyBossFBTimeCfg()
    fbStep = gameFB.GetFBStep()
    if fbStep == FB_Step_MapPrepare:
        #初始化并通知等待倒计时
        __EnterFBInPrepare(curPlayer, familyBossFBCfg[Def_Time_MapPrepare] * 1000, gameFB, tick)
    elif fbStep == FB_Step_Fighting:
        #通知进入时间
        notifyTick = max(familyBossFBCfg[Def_Time_Fight] * 1000 - (tick - gameFB.GetFBStepTick()), 0)
        curPlayer.Sync_TimeTick(IPY_GameWorld.tttTowerTake, 0, notifyTick, True)
        __UpdFamilyBossFBStar(tick, True, curPlayer)
    elif fbStep == FB_Step_LeaveTime:
        notifyTick = max(familyBossFBCfg[Def_Time_Leave] * 1000 - (tick - gameFB.GetFBStepTick()), 0)
        curPlayer.Sync_TimeTick(IPY_GameWorld.tttLeaveMap, 0, notifyTick, True)
    DoFBHelp(curPlayer, tick)
    batPlayer = GetBattlePlayer(playerID)
    batPlayer.onEnter(curPlayer, tick)
    GameWorld.DebugLog("DoEnterFB: fbStep=%s,fightTickTotal=%s,hurtValue=%s" % (fbStep, batPlayer.fightTickTotal, batPlayer.hurtValue), playerID)
    
    AddFamilyBossPlayer(curPlayer)
    fightSecondsMax = IpyGameDataPY.GetFuncCfg("FamilyBossFB", 1)
    remainTick = fightSecondsMax * 1000 - batPlayer.fightTickTotal
    if remainTick <= 0:
        PlayerControl.PlayerLeaveFB(curPlayer)
        return
    if fbStep != FB_Step_Fighting:
        __SetFBToFight(tick)
    curPlayer.Sync_TimeTick(IPY_GameWorld.tttAddUpTime, 0, remainTick, True)\
    statsFBMemberHurt(tick, 1)
    return
def __SetFBToFight(tick):
    FBCommon.SetFBStep(FB_Step_Fighting, tick)
    refreshMark, bossID = FBCommon.GetFBLineRefreshNPC(ChConfig.Def_FBMapID_FamilyBossMap, 0)
    if not GameWorld.FindNPCByNPCID(bossID):
        NPCCustomRefresh.SetNPCRefresh(refreshMark, [bossID])
    return
##副本定时器
# @param tick 时间戳
@@ -214,217 +172,142 @@
def OnProcess(tick):
    fbStep = GameWorld.GetGameFB().GetFBStep()
    
    if fbStep == FB_Step_MapPrepare:
        __DoLogic_MapPrepare(tick)
    elif fbStep == FB_Step_Fighting:
    if fbStep == FB_Step_Fighting:
        __DoLogic_MapFighting(tick)
    elif fbStep == FB_Step_LeaveTime:
        __DoLogic_MapLeave(tick)
    elif fbStep == FB_Step_LeaveTime1:
        __DoLogic_MapLeave(tick)
    return
## 更新当前副本星级
def __UpdFamilyBossFBStar(tick, isForce=False, curPlayer=None):
    gameFB = GameWorld.GetGameFB()
    curStar = gameFB.GetGameFBDictByKey(FamilyBossFB_Star)
    if curStar == 1:
        return curStar
    useSecond = int(math.ceil((tick - gameFB.GetFBStepTick()) / 1000.0))
    familyBossFBCfg = GetFamilyBossFBTimeCfg()
    starTimeList = familyBossFBCfg[Def_StarTime]
    diffSecond = 0
    updStar = 1 # 默认至少1星
    for star, starTime in enumerate(starTimeList, 2):
        if useSecond <= starTime:
            updStar = star
            diffSecond = starTime-useSecond
    if curStar == updStar and not isForce:
        return curStar
        
    gameFB.SetGameFBDict(FamilyBossFB_Star, updStar)
    GameWorld.DebugLog("__UpdFamilyBossFBStar useSecond=%s,curStar=%s,updStar=%s, diffSecond=%s"
                       % (useSecond, curStar, updStar, diffSecond))
    if curPlayer:
        DoFBHelp(curPlayer, tick)
        if updStar != 1:
            curPlayer.Sync_TimeTick(IPY_GameWorld.tttFlagTake, 0, diffSecond * 1000, True)
    else:
        playerManager = GameWorld.GetMapCopyPlayerManager()
        for index in xrange(playerManager.GetPlayerCount()):
            curPlayer = playerManager.GetPlayerByIndex(index)
            if not curPlayer:
                continue
            DoFBHelp(curPlayer, tick)
            if updStar != 1:
                curPlayer.Sync_TimeTick(IPY_GameWorld.tttFlagTake, 0, diffSecond * 1000, True)
    return updStar
def __EnterFBInPrepare(curPlayer, downTime, gameFB, tick, notifyEff=False):
    #通知准备倒计时
    notifyTick = max(downTime - (tick - gameFB.GetFBStepTick()), 0)
    curPlayer.Sync_TimeTick(IPY_GameWorld.tttWaitStart, 0, notifyTick, True)
    if notifyEff:
        curPlayer.Sync_TimeTick(IPY_GameWorld.tttAddUpTime, 0, notifyTick, True)
    return
def __DoLogic_MapPrepare(tick):
    invadeCfg = GetFamilyBossFBTimeCfg()
    if tick - GameWorld.GetGameFB().GetFBStepTick() < invadeCfg[Def_Time_MapPrepare] * 1000:
        return
    __OnFamilyBossFBStart(tick)
    return
def __DoLogic_MapFighting(tick):
    invadeCfg = GetFamilyBossFBTimeCfg()
    if tick - GameWorld.GetGameFB().GetFBStepTick() >= invadeCfg[Def_Time_Fight] * 1000:
        __DoFamilyBossFBOver(tick, False)
        return
    __UpdFamilyBossFBStar(tick)
    return
def __DoLogic_MapLeave(tick):
    gameFB = GameWorld.GetGameFB()
    invadeCfg = GetFamilyBossFBTimeCfg()
    remianTime = invadeCfg[Def_Time_Leave] * 1000 - (tick - GameWorld.GetGameFB().GetFBStepTick())
    if remianTime > 0:
        fbStep = gameFB.GetFBStep()
        if remianTime < 5000 and fbStep == FB_Step_LeaveTime:
            gameFB.SetFBStep(FB_Step_LeaveTime1)
            familyID = gameFB.GetGameFBDictByKey(Map_FamilyBossFB_FamilyID)
            msgStr = str([familyID, 0])
            GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(0, 0, 0, 'FamilyBossFBState', msgStr, len(msgStr))
    lastTick = gameFB.GetGameFBDictByKey(ChConfig.Def_FB_NotifyFBHelpTick)
    if tick - lastTick < 5000:
        return
    # 时间到,踢出还在副本的玩家等...
    GameWorldProcess.CloseFB(tick)
    FBCommon.SetFBStep(FB_Step_Over, tick)
    FBCommon.DoLogic_FBKickAllPlayer()
    gameFB.SetGameFBDict(ChConfig.Def_FB_NotifyFBHelpTick, tick)
    statsFBMemberHurt(tick)
    return
def __OnFamilyBossFBStart(tick):
    FBCommon.SetFBStep(FB_Step_Fighting, tick)
    refreshMark, bossID = FBCommon.GetFBLineRefreshNPC(ChConfig.Def_FBMapID_FamilyBossMap, 0)
    NPCCustomRefresh.SetNPCRefresh(refreshMark, [bossID])
    # 战盟频道通知开始
    familyBossFBCfg = GetFamilyBossFBTimeCfg()
    FBCommon.Sync_Player_TimeTick(IPY_GameWorld.tttTowerTake, familyBossFBCfg[Def_Time_Fight] * 1000)
def statsFBMemberHurt(tick, statsType=0, exitPlayerID=0):
    ## 统计副本仙盟成员伤害
    # statsType 0-常规;1-玩家进入;2-玩家退出
    
    __UpdFamilyBossFBStar(tick)
    return
def __DoFamilyBossFBOver(tick, isKill):
    # 副本结束逻辑
    gameFB = GameWorld.GetGameFB()
    if gameFB.GetFBStep() == FB_Step_LeaveTime:
        return
    GameWorld.DebugLog("处理仙盟BOSS副本结束逻辑")
    invadeCfg = GetFamilyBossFBTimeCfg()
    FBCommon.SetFBStep(FB_Step_LeaveTime, tick)
    familyID = gameFB.GetGameFBDictByKey(Map_FamilyBossFB_FamilyID)
    msgStr = str([familyID, 2])
    GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(0, 0, 0, 'FamilyBossFBState', msgStr, len(msgStr))
    fightMemCount = 0
    familyID = GameWorld.GetGameWorld().GetPropertyID()
    playerManager = GameWorld.GetMapCopyPlayerManager()
    for index in xrange(playerManager.GetPlayerCount()):
        curPlayer = playerManager.GetPlayerByIndex(index)
        if not curPlayer:
            continue
        playerID = curPlayer.GetPlayerID()
        if playerID != exitPlayerID:
            fightMemCount += 1
    needMemCount, skillTypeID = IpyGameDataPY.GetFuncEvalCfg("FamilyBossFB", 2)
    
    grade = gameFB.GetGameFBDictByKey(FamilyBossFB_Star)
    GameWorld.Log("仙盟BOSS副本结算: familyID=%s, grade=%s" % (familyID, grade), familyID)
    leaveTick = invadeCfg[Def_Time_Leave] * 1000
    copyMapPlayerManager = GameWorld.GetMapCopyPlayerManager()
    playerCount = copyMapPlayerManager.GetPlayerCount()
    for i in xrange(playerCount):
        curPlayer = copyMapPlayerManager.GetPlayerByIndex(i)
        if curPlayer == None or curPlayer.IsEmpty():
    fightSecondsMax = IpyGameDataPY.GetFuncCfg("FamilyBossFB", 1)
    addFamilyHurt = 0
    for index in xrange(playerManager.GetPlayerCount()):
        curPlayer = playerManager.GetPlayerByIndex(index)
        if not curPlayer:
            continue
        
        curPlayer.Sync_TimeTick(IPY_GameWorld.tttLeaveMap, 0, leaveTick, True)
        if isKill:
            PlayerFamily.AddFamilyActivity(curPlayer, ShareDefine.FamilyActive_BOSS)
        playerID = curPlayer.GetPlayerID()
        batPlayer = GetBattlePlayer(playerID)
        hurtValue = batPlayer.hurtValue
        addHurtValue = max(0, hurtValue - batPlayer.hurtValueLast)
        batPlayer.hurtValueLast = hurtValue
        
    if isKill:
        doCountRate = eval(IpyGameDataPY.GetFuncCompileCfg("FamilyBOSSDropRule", 1))
        doCountAdd = eval(IpyGameDataPY.GetFuncCompileCfg("FamilyBOSSDropRule", 2))
        FBCommon.SetNPCDropDoCountRate(gameFB, doCountRate, doCountAdd)
        passTick = tick - batPlayer.statsTick
        if passTick > 0:
            batPlayer.fightTickTotal += passTick
        batPlayer.statsTick = tick
        fightSeconds = batPlayer.fightTickTotal / 1000
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FamilyBossHurtValue, hurtValue % ChConfig.Def_PerPointValue)
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FamilyBossHurtValuePoint, hurtValue / ChConfig.Def_PerPointValue)
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FamilyBossFightSeconds, fightSeconds)
        addFamilyHurt += addHurtValue
        #GameWorld.DebugLog("仙盟玩家伤血统计: fightSeconds=%s,hurtValue=%s,addHurtValue=%s, %s" % (fightSeconds, hurtValue, addHurtValue, addFamilyHurt), playerID)
        # 帮助信息
        helpDict = {"hurtValue":hurtValue, "fightSeconds":fightSeconds, "fightMemCount":fightMemCount}
        FBCommon.Notify_FBHelp(curPlayer, helpDict)
        if playerID == exitPlayerID:
            BuffSkill.DelBuffBySkillID(curPlayer, skillTypeID, tick)
            SyncFamilyBossPlayerInfo(curPlayer)
        elif fightSeconds >= fightSecondsMax:
            GameWorld.DebugLog("    没有战斗时长了,踢出副本", playerID)
            PlayerControl.PlayerLeaveFB(curPlayer)
        else:
            # 处理buff
            __parseFightBuff(curPlayer, fightMemCount, needMemCount, skillTypeID, tick)
    SendGameServer("FBMemberHurt", [statsType, familyID, fightMemCount, addFamilyHurt])
    return
def __parseFightBuff(curPlayer, fightMemCount, needMemCount, skillTypeID, tick):
    if fightMemCount < needMemCount:
        #GameWorld.DebugLog("    人数不足战斗buff", curPlayer.GetPlayerID())
        BuffSkill.DelBuffBySkillID(curPlayer, skillTypeID, tick)
        return
    skillLV = fightMemCount - needMemCount + 1
    findBuff = SkillCommon.FindBuffByID(curPlayer, skillTypeID)[0]
    if findBuff and findBuff.GetSkill().GetSkillLV() == skillLV:
        #GameWorld.DebugLog("    战斗buff等级不变.skillTypeID=%s,skillLV=%s" % (skillTypeID, skillLV), curPlayer.GetPlayerID())
        return
    #GameWorld.DebugLog("    战斗buff等级改变.skillTypeID=%s,skillLV=%s" % (skillTypeID, skillLV), curPlayer.GetPlayerID())
    BuffSkill.DelBuffBySkillID(curPlayer, skillTypeID, tick)
    SkillCommon.AddBuffBySkillType(curPlayer, skillTypeID, tick, skillLV)
    return
def OnEnterFamily(curPlayer):
    #进入仙盟时补同步领奖状态到GameServer
    SendGameServer_FamilyHurtAwardStateFamily(curPlayer)
    return
def SendGameServer_FamilyHurtAwardStateFamily(curPlayer):
    playerID = curPlayer.GetPlayerID()
    familyID = curPlayer.GetFamilyID()
    hurtAwardStateFamily = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FamilyBossHurtAwardFamily)
    SendGameServer("FamilyHurtAwardStateFamily", [familyID, playerID, hurtAwardStateFamily])
    return
##玩家退出副本
def DoExitFB(curPlayer, tick):
    statsFBMemberHurt(tick, 2, curPlayer.GetPlayerID())
    return
##玩家主动离开副本.
def DoPlayerLeaveFB(curPlayer, tick):
    return
## 玩家对NPC造成伤害
def DoFB_Player_HurtNPC(curPlayer, curNPC, hurtHP):
    familyID = curPlayer.GetFamilyID()
    if not familyID:
        return
    bossID = FBCommon.GetFBLineRefreshNPC(ChConfig.Def_FBMapID_FamilyBossMap, 0)[1]
    if bossID != curNPC.GetNPCID():
        return
    playerID = curPlayer.GetPlayerID()
    batPlayer = GetBattlePlayer(playerID)
    batPlayer.hurtValue += hurtHP
    #GameWorld.DebugLog("增加伤血: familyID=%s,hurtHP=%s, %s" % (familyID, hurtHP, batPlayer.hurtValue), playerID)
    return
## 是否副本复活
#  @param None
#  @return 是否副本复活
def OnPlayerReborn():
    return True
## 重置副本复活玩家坐标点
# @param None
# @return 无意义
def OnResetFBRebornPlacePos(curPlayer, rebornPlace, tick):
    ipyEnterPosInfo = FBCommon.GetFBLineEnterPosInfo(ChConfig.Def_FBMapID_FamilyBossMap, 0)
    posX, posY = ipyEnterPosInfo[:2]
    curPlayer.ResetPos(posX, posY)
    return
##玩家退出家族处理
# @param curPlayer 玩家实例
# @param tick 时间戳
# @return 返回值无意义
def OnLeaveFamily(curPlayer, tick):
    #GameWorld.DebugLog("OnLeaveFamily...")
    #curPlayerID = curPlayer.GetPlayerID()
    PlayerControl.PlayerLeaveFB(curPlayer)
    return
##获得副本帮助信息
# @param curPlayer 玩家实例
# @param tick 时间戳
# @return 无意义
# @remarks 用于通知阵营比分条
def DoFBHelp(curPlayer, tick):
    helpDict = {}
    gameFB = GameWorld.GetGameFB()
    curStar = gameFB.GetGameFBDictByKey(FamilyBossFB_Star)
    helpDict[FBCommon.Help_grade] = curStar
    FBCommon.Notify_FBHelp(curPlayer, helpDict)
    return
## 执行副本杀怪逻辑
#  @param curPlayer 杀怪的人
#  @param curNPC 被杀的怪
#  @param tick 当前时间
#  @return None
def DoFB_Player_KillNPC(curPlayer, curNPC, tick):
    bossID = curNPC.GetNPCID()
    refreshMark, refreshBossID = FBCommon.GetFBLineRefreshNPC(ChConfig.Def_FBMapID_FamilyBossMap, 0)
    if bossID != refreshBossID:
        return
    GameWorld.DebugLog('仙盟BOSS已被击杀!')
#    # 全服广播
#    PlayerControl.WorldNotify(0, "jiazu_liubo_202580", [curPlayer.GetFamilyName(), mapID, bossID])
    __DoFamilyBossFBOver(tick, True)
    return
## 检查是否可攻击, 主判定不可攻击的情况,其他逻辑由外层决定
#  @param attacker 攻击方
#  @param defender 防守方
#  @return bool
def CheckCanAttackTagObjInFB(attacker, defender):
    gameFB = GameWorld.GetGameFB()
    if gameFB.GetFBStep() != FB_Step_Fighting:
@@ -432,5 +315,95 @@
    return True
def GetFamilyBossHurtAward(curPlayer, awardType, awardIndex):
    ## awardType 1-个人;2-仙盟
    awardIndex = GameWorld.ToIntDef(awardIndex)
    playerID = curPlayer.GetPlayerID()
    ipyData = IpyGameDataPY.GetIpyGameData("FamilyBossHurtAward", awardType, awardIndex)
    if not ipyData:
        return
    needHurtTotal = ipyData.GetNeedHurtTotal()
    awardItemList = ipyData.GetAwardItemList()
    familyID = curPlayer.GetFamilyID()
    if awardType == 2:
        if not familyID:
            return
        rewardRecord = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FamilyBossHurtAwardFamily)
        if rewardRecord & pow(2, awardIndex):
            GameWorld.DebugLog("仙盟boss伤血仙盟奖励已领奖!awardIndex=%s,rewardRecord=%s" % (awardIndex, rewardRecord), playerID)
            return
        SendGameServer("FamilyHurtAwardReq", [familyID, awardType, awardIndex, needHurtTotal, awardItemList], playerID)
        return
    hurtValue = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FamilyBossHurtValue)
    hurtValuePoint = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FamilyBossHurtValuePoint)
    hurtValueTotal = hurtValuePoint * ChConfig.Def_PerPointValue + hurtValue
    if hurtValueTotal < needHurtTotal:
        GameWorld.DebugLog("仙盟boss伤血个人奖励伤血不足不能领取: awardIndex=%s,hurtValueTotal=%s < %s" % (awardIndex, hurtValueTotal, needHurtTotal), playerID)
        return
    rewardRecord = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FamilyBossHurtAward)
    if rewardRecord & pow(2, awardIndex):
        GameWorld.DebugLog("仙盟boss伤血个人奖励已领奖!awardIndex=%s,rewardRecord=%s" % (awardIndex, rewardRecord), playerID)
        return
    updRewardRecord = rewardRecord | pow(2, awardIndex)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FamilyBossHurtAward, updRewardRecord)
    GameWorld.DebugLog("仙盟boss伤血仙盟奖励发放: familyID=%s,awardType=%s,awardIndex=%s,updRewardRecord=%s,awardItemList=%s"
                       % (familyID, awardType, awardIndex, updRewardRecord, awardItemList), playerID)
    event = ["FamilyBossHurtAward", False, {"awardType":awardType, "awardIndex":awardIndex}]
    ItemControler.GivePlayerItemOrMail(curPlayer, awardItemList, None, event)
    SyncFamilyBossPlayerInfo(curPlayer)
    return
def SendGameServer(msgType, msgData, playerID=0):
    msgInfo = str([msgType, msgData])
    GameWorld.DebugLog("仙盟boss试炼同步GameServer: msgType=%s,%s" % (msgType, msgData), playerID)
    GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(playerID, 0, 0, "FamilyBoss", msgInfo, len(msgInfo))
    return
def GameServer_FamilyBossInfo(curPlayer, resultList):
    playerID = curPlayer.GetPlayerID()
    msgType, msgData = resultList[:2]
    GameWorld.Log("仙盟Boss试炼GameServer返回: %s" % str(resultList), playerID)
    if msgType == "FamilyHurtAwardReq":
        familyID, awardType, awardIndex, needHurtTotal, awardItemList = msgData
        hurtValueTotal = resultList[2]
        if hurtValueTotal < needHurtTotal:
            GameWorld.DebugLog("仙盟boss伤血仙盟奖励伤血不足不能领取: awardIndex=%s,hurtValueTotal=%s < %s" % (awardIndex, hurtValueTotal, needHurtTotal), playerID)
            return
        rewardRecord = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FamilyBossHurtAwardFamily)
        if rewardRecord & pow(2, awardIndex):
            GameWorld.DebugLog("仙盟boss伤血仙盟奖励返回时已领奖!awardIndex=%s,rewardRecord=%s" % (awardIndex, rewardRecord), playerID)
            return
        updRewardRecord = rewardRecord | pow(2, awardIndex)
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FamilyBossHurtAwardFamily, updRewardRecord)
        GameWorld.DebugLog("仙盟boss伤血仙盟奖励发放: familyID=%s,awardType=%s,awardIndex=%s,updRewardRecord=%s,awardItemList=%s"
                           % (familyID, awardType, awardIndex, updRewardRecord, awardItemList), playerID)
        event = ["FamilyBossHurtAward", False, {"awardType":awardType, "awardIndex":awardIndex}]
        ItemControler.GivePlayerItemOrMail(curPlayer, awardItemList, None, event)
        SendGameServer_FamilyHurtAwardStateFamily(curPlayer)
        SyncFamilyBossPlayerInfo(curPlayer)
    return
def SyncFamilyBossPlayerInfo(curPlayer):
    clientPack = ChPyNetSendPack.tagMCFamilyBosFBPlayerInfo()
    clientPack.Clear()
    clientPack.HurtTotal = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FamilyBossHurtValue)
    clientPack.HurtTotalPoint = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FamilyBossHurtValuePoint)
    clientPack.FightSeconds = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FamilyBossFightSeconds)
    clientPack.HurtAwardState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FamilyBossHurtAward)
    clientPack.HurtAwardStateFamily = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FamilyBossHurtAwardFamily)
    NetPackCommon.SendFakePack(curPlayer, clientPack)
    return