hxp
2024-12-26 22c964784d465c77365c2495f6d43117618d8482
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_CrossRealmPK.py
@@ -15,561 +15,64 @@
#"""Version = 2018-12-21 18:00"""
#-------------------------------------------------------------------------------
import ChPlayer
import GameWorld
import IPY_GameWorld
import PlayerControl
import GameWorldProcess
import IpyGameDataPY
import SkillCommon
import FBCommon
import ChConfig
import MirrorAttack
import PlayerCrossRealmPK
import GameObj
(
Def_Time_MaxWait, # 最长等待时间, 秒
Def_Time_MapPrepare, # 准备时间, 秒
Def_Time_Fight, # 战斗时间, 秒
Def_Time_Protect, # 保护时间,秒,玩家战斗中掉线保护时长
Def_Time_Leave, # 结束退出时间, 秒
) = range(5)
# 当前副本地图的状态
(
FB_State_Open,
FB_State_Waiting, # 等待对手阶段
FB_State_MapPrepare, # 地图准备
FB_State_Fight, # 战斗阶段
FB_State_Reborn, # 复活阶段
FB_State_Leave, # 离开阶段
FB_State_Close, # 关闭阶段
) = range(7)
# 对战结束类型定义
(
Def_OverType_LackPlayer, # 缺少对手
Def_OverType_PlayerExit, # 对手退出(视为认输)
Def_OverType_Kill, # 击杀对手
Def_OverType_TimeOut, # PK时间超时
) = range(4)
# 副本相关字典key
GameFBDict_FBPlayerID = "FBD_FBPlayerID_%s" # 玩家ID, 参数, 进入顺序
GameFBDict_PlayerWinCnt = "FBD_PlayerWinCnt_%s" # 玩家已获胜次数, 参数[playerID]
GameFBDict_PlayerLeaveTick = "FBD_PlayerLeaveTick_%s" # 玩家已获胜次数, 参数[playerID]
FBPDict_PVPDamage = "FBPD_PVPDamage" # 玩家伤害输出
FBPDict_PVPDamUpdTick = "FBPD_PVPDamUpdTick" # 更新伤害tick
FBPDict_ResetPosX = "FBPD_ResetPosX" # 玩家重置坐标X
FBPDict_ResetPosY = "FBPD_ResetPosY" # 玩家重置坐标Y
FBPDict_RoundNum = "FBPD_RoundNum" # 玩家当前所属回合数
FB_RoundNum = "FB_RoundNum" # 副本当前回合数
FB_RoundWinPlayerID = "FB_RoundWinPlayerID_%s" # 回合获胜玩家ID, 参数[回合数]
## 是否能够通过活动查询进入
def OnEnterFBEvent(curPlayer, mapID, lineID, tick):
###处理副本中杀死玩家逻辑
def DoFBOnKill_Player(atkobj, defender, tick):
    GameWorld.DebugLog("镜像切磋击杀玩家: defID=%s" % (defender.GetID()), atkobj.GetID())
    return True
#def OnGetFBEnterPos(curPlayer, mapID, lineId, ipyEnterPosInfo, tick):
#    posDict = {117401:(40,37), 117403:(10, 7)}
#    return posDict.get(curPlayer.GetPlayerID())
## 玩家进入副本
def DoEnterFB(curPlayer, tick):
    playerID = curPlayer.GetPlayerID()
    playerVSRoomID = curPlayer.GetVsRoomId()
    roomID = GameWorld.GetGameWorld().GetPropertyID()
    gameFB = GameWorld.GetGameFB()
    fbStep = gameFB.GetFBStep()
    GameWorld.Log("DoEnterFB fbRoomID=%s,playerVSRoomID=%s,fbStep=%s" % (roomID, playerVSRoomID, fbStep), playerID)
def OnMirrorBattleRequest(curPlayer, mapID, funcLineID):
    ## 镜像战斗请求
    
    if gameFB.GetGameFBDictByKey(GameFBDict_PlayerLeaveTick % playerID):
        GameWorld.Log("    玩家离线保护时间内上线!", playerID)
        gameFB.SetGameFBDict(GameFBDict_PlayerLeaveTick % playerID, 0)
        playerManager = GameWorld.GetMapCopyPlayerManager()
        for index in xrange(playerManager.GetPlayerCount()):
            player = playerManager.GetPlayerByIndex(index)
            if player and player.GetPlayerID() != curPlayer.GetPlayerID():
                player.Sync_TimeTick(ChConfig.tttPlayerLeave, 0, 0, True)
    fbRoundNum = gameFB.GetGameFBDictByKey(FB_RoundNum)
    playerRoundNum = gameFB.GetPlayerGameFBDictByKey(playerID, FBPDict_RoundNum)
    if playerRoundNum and fbRoundNum and playerRoundNum != fbRoundNum:
        # 一般是掉线时上个回合已经结束了
        GameWorld.DebugLog("玩家进入副本时与当前副本回合数不一致时,重置状态!fbRoundNum=%s,playerRoundNum=%s"
                           % (fbRoundNum, playerRoundNum), playerID)
        gameFB.SetPlayerGameFBDict(playerID, FBPDict_RoundNum, fbRoundNum)
        __ResetPlayerState(gameFB, curPlayer, playerID)
    if fbStep >= FB_State_Leave or not roomID or not playerVSRoomID or roomID != playerVSRoomID:
        PlayerControl.PlayerLeaveFB(curPlayer)
        return
    PlayerControl.SetSight(curPlayer, ChConfig.Def_PlayerSight_Default * 3)
    # 非战斗阶段,通知动态障碍点
    if fbStep < FB_State_Fight:
        FBCommon.SyncDynamicBarrierState(IpyGameDataPY.GetFuncEvalCfg("CrossRealmPKFB", 2), 1, curPlayer) # 准备期间有动态障碍点
    fbTimeList = IpyGameDataPY.GetFuncEvalCfg("CrossRealmPKFB", 1)
    if fbStep == FB_State_Open:
        gameFB.SetGameFBDict(GameFBDict_FBPlayerID % 1, playerID)
        gameFB.SetPlayerGameFBDict(playerID, FBPDict_ResetPosX, curPlayer.GetPosX())
        gameFB.SetPlayerGameFBDict(playerID, FBPDict_ResetPosY, curPlayer.GetPosY())
        gameFB.SetPlayerGameFBDict(playerID, FBPDict_RoundNum, 1)
        FBCommon.SetFBStep(FB_State_Waiting, tick)
        GameWorld.Log("    第一个进入,阵营1,设置副本进入等待对手阶段!roomID=%s" % (roomID), playerID)
        __ResetPlayerState(gameFB, curPlayer, playerID)
        curPlayer.Sync_TimeTick(ChConfig.tttWaitPlayer, 0, fbTimeList[Def_Time_MaxWait] * 1000, True)
        sendMsg = str([roomID])
        GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(0, 0, 0, "CrossPKRoomOpen", sendMsg, len(sendMsg))
    elif fbStep == FB_State_Waiting:
        playerIDA = gameFB.GetGameFBDictByKey(GameFBDict_FBPlayerID % 1)
        playerIDB = gameFB.GetGameFBDictByKey(GameFBDict_FBPlayerID % 2)
        if not playerIDB and playerIDA != playerID:
            gameFB.SetGameFBDict(GameFBDict_FBPlayerID % 2, playerID)
            gameFB.SetPlayerGameFBDict(playerID, FBPDict_ResetPosX, curPlayer.GetPosX())
            gameFB.SetPlayerGameFBDict(playerID, FBPDict_ResetPosY, curPlayer.GetPosY())
            gameFB.SetPlayerGameFBDict(playerID, FBPDict_RoundNum, 1)
            GameWorld.Log("    第二个进入的玩家!阵营2,roomID=%s" % (roomID), playerID)
            __ResetPlayerState(gameFB, curPlayer, playerID)
        if GameWorld.GetMapCopyPlayerManager().GetPlayerCount() == 2:
            GameWorld.Log("    两个人都在,设置副本进入战斗倒计时阶段!roomID=%s" % (roomID), playerID)
            FBCommon.SetFBStep(FB_State_MapPrepare, tick)
            FBCommon.Sync_Player_TimeTick(ChConfig.tttWaitStart, fbTimeList[Def_Time_MapPrepare] * 1000)
            gameFB.SetGameFBDict(FB_RoundNum, 1)
        else:
            GameWorld.Log("    对手不在,继续等待!roomID=%s" % (roomID), playerID)
    elif fbStep == FB_State_MapPrepare:
        notify_tick = fbTimeList[Def_Time_MapPrepare] * 1000 - (tick - GameWorld.GetGameFB().GetFBStepTick())
        curPlayer.Sync_TimeTick(ChConfig.tttWaitStart, 0, max(notify_tick, 0), True)
    elif fbStep == FB_State_Fight:
        notify_tick = fbTimeList[Def_Time_Fight] * 1000 - (tick - GameWorld.GetGameFB().GetFBStepTick())
        curPlayer.Sync_TimeTick(ChConfig.tttTowerTake, 0, max(notify_tick, 0), True)
    FBCommon.Notify_FBHelp(curPlayer, __GetFBHelpInfo())
    PlayerControl.DelLimitSuperBuff(curPlayer, tick)
    PlayerControl.PlayerControl(curPlayer).RefreshPlayerAttrState()
    return
def __GetFBHelpInfo():
    gameFB = GameWorld.GetGameFB()
    roundWinerIDList = []
    roundNum = gameFB.GetGameFBDictByKey(FB_RoundNum)
    for roundNum in xrange(1, roundNum + 1):
        winnerID = gameFB.GetGameFBDictByKey(FB_RoundWinPlayerID % roundNum)
        if not winnerID:
            break
        roundWinerIDList.append(winnerID)
    return {"roundNum":roundNum, "roundWinerIDList":roundWinerIDList}
## 玩家退出副本
def DoExitFB(curPlayer, tick):
    # 结算时间
    gameFB = GameWorld.GetGameFB()
    fbStep = gameFB.GetFBStep()
    if fbStep >= FB_State_Leave:
    if not PlayerCrossRealmPK.CheckCanMatch(curPlayer):
        return
    
    playerID = curPlayer.GetPlayerID()
    gameFB.SetGameFBDict(GameFBDict_PlayerLeaveTick % playerID, tick)
    GameWorld.Log("玩家战斗阶段下线!playerID=%s,waitPlayerID=%s" % (playerID, playerID))
    ## 通知对方,对手掉线
    playerManager = GameWorld.GetMapCopyPlayerManager()
    for index in xrange(playerManager.GetPlayerCount()):
        player = playerManager.GetPlayerByIndex(index)
        if player and player.GetPlayerID() != curPlayer.GetPlayerID():
            fbTimeList = IpyGameDataPY.GetFuncEvalCfg("CrossRealmPKFB", 1)
            player.Sync_TimeTick(ChConfig.tttPlayerLeave, 0, max(fbTimeList[Def_Time_Protect] * 1000, 0), True)
    return
##玩家主动离开副本.
def DoPlayerLeaveFB(curPlayer, tick):
    gameFB = GameWorld.GetGameFB()
    fbStep = gameFB.GetFBStep()
    if fbStep <= FB_State_Waiting or fbStep >= FB_State_Leave:
    if not PlayerCrossRealmPK.CheckHavePKCount(curPlayer):
        return
    leavePlayerID = curPlayer.GetPlayerID()
    roomID = GameWorld.GetGameWorld().GetPropertyID()
    playerIDA = gameFB.GetGameFBDictByKey(GameFBDict_FBPlayerID % 1)
    playerIDB = gameFB.GetGameFBDictByKey(GameFBDict_FBPlayerID % 2)
    loser, loserID = curPlayer, leavePlayerID
    winnerID = playerIDA if playerIDB == loserID else playerIDB
    winner = GameWorld.GetMapCopyPlayerManager().FindPlayerByID(winnerID)
    GameWorld.Log("玩家主动退出,直接算输! roomID=%s,leavePlayerID=%s,loserID=%s,winnerID=%s" % (roomID, leavePlayerID, loserID, winnerID))
    __DoFBPKAllOver(winner, winnerID, loser, loserID, Def_OverType_PlayerExit, tick)
    return
## 获得副本帮助信息
def DoFBHelp(curPlayer, tick):
    return
## 副本总逻辑计时器
def OnProcess(tick):
    gameFB = GameWorld.GetGameFB()
    fbStep = gameFB.GetFBStep()
    if fbStep == FB_State_Waiting:
        __DoLogic_Waiting(tick)
    elif fbStep == FB_State_MapPrepare:
        if not __CheckLeaveProtectTimeout(tick):
            __DoLogic_MapPrepare(tick)
    elif fbStep == FB_State_Fight:
        if not __CheckLeaveProtectTimeout(tick):
            __DoLogic_MapFight(tick)
    elif fbStep == FB_State_Reborn:
        __DoLogic_Reborn(tick)
    elif fbStep == FB_State_Leave:
        __DoLogic_LeaveTime(tick)
    return
##等待玩家进入阶段处理
def __DoLogic_Waiting(tick):
    fbTimeList = IpyGameDataPY.GetFuncEvalCfg("CrossRealmPKFB", 1)
    if tick - GameWorld.GetGameFB().GetFBStepTick() < fbTimeList[Def_Time_MaxWait] * 1000:
        return
    winner, winnerID, loser, loserID = __GetTimeoutWinerInfo(tick)
    # 对手没来,直接获胜
    roomID = GameWorld.GetGameWorld().GetPropertyID()
    GameWorld.Log("战前等待对手阶段超时,直接结束!roomID=%s,winnerID=%s,loserID=%s" % (roomID, winnerID, loserID))
    __DoFBPKAllOver(winner, winnerID, loser, loserID, Def_OverType_LackPlayer, tick)
    return
def __CheckLeaveProtectTimeout(tick):
    gameFB = GameWorld.GetGameFB()
    playerIDA = gameFB.GetGameFBDictByKey(GameFBDict_FBPlayerID % 1)
    playerIDB = gameFB.GetGameFBDictByKey(GameFBDict_FBPlayerID % 2)
    playerLeaveTickA = gameFB.GetGameFBDictByKey(GameFBDict_PlayerLeaveTick % playerIDA)
    playerLeaveTickB = gameFB.GetGameFBDictByKey(GameFBDict_PlayerLeaveTick % playerIDB)
    if not playerLeaveTickA and not playerLeaveTickB:
        return
    fbTimeList = IpyGameDataPY.GetFuncEvalCfg("CrossRealmPKFB", 1)
    if playerLeaveTickA > playerLeaveTickB:
        if tick - playerLeaveTickA < fbTimeList[Def_Time_Protect] * 1000:
            return
    else:
        if tick - playerLeaveTickB < fbTimeList[Def_Time_Protect] * 1000:
            return
    winner, winnerID, loser, loserID = __GetTimeoutWinerInfo(tick)
    # 对手没来,直接获胜
    roomID = GameWorld.GetGameWorld().GetPropertyID()
    GameWorld.Log("战斗中对手离线超时,直接结束!roomID=%s,winnerID=%s,loserID=%s" % (roomID, winnerID, loserID))
    __DoFBPKAllOver(winner, winnerID, loser, loserID, Def_OverType_PlayerExit, tick)
    return True
def __GetTimeoutWinerInfo(tick):
    ''' 时间超时,获取获胜的玩家
                    战斗阶段有两个玩家时优先比较输出
                    其他情况则在线玩家获胜,如果没有玩家在线,则最迟离线的获胜
    '''
    winner, winnerID, loser, loserID = None, 0, None, 0
    roomID = GameWorld.GetGameWorld().GetPropertyID()
    gameFB = GameWorld.GetGameFB()
    fbStep = gameFB.GetFBStep()
    copyMapPlayerManager = GameWorld.GetMapCopyPlayerManager()
    playerIDA = gameFB.GetGameFBDictByKey(GameFBDict_FBPlayerID % 1)
    playerIDB = gameFB.GetGameFBDictByKey(GameFBDict_FBPlayerID % 2)
    # 战斗阶段有两个玩家时优先比较输出
    if fbStep == FB_State_Fight and copyMapPlayerManager.GetPlayerCount() == 2:
        # 时间到还没分出胜负, 根据以下规则决定胜负,这里用玩家ID处理,防止结算时都掉线了导致没有结果
        # 伤害输出 > 优先到达时间 > 剩余HP > 最大HP > playerID
        GameWorld.Log("两个人都在线,根据超时规则判断胜负玩家! roomID=%s" % (roomID))
        playerInfoList = []
        for playerID in [playerIDA, playerIDB]:
            player = copyMapPlayerManager.FindPlayerByID(playerID)
            # 还是离线时间的,走掉线逻辑,越晚掉线的赢;需要加这个逻辑主要是因为当玩家没有触发完整登录流程导致玩家在线但是没有触发DoEnter
            playerLeaveTick = gameFB.GetGameFBDictByKey(GameFBDict_PlayerLeaveTick % playerID)
            if playerLeaveTick:
                pvpDamage, sortTick, curHP, curMaxHP = 0, 0, 0, 0
                playerInfoList.append([pvpDamage, sortTick, curHP, curMaxHP, playerLeaveTick, playerID, player])
                GameWorld.Log("PK超时: playerLeaveTick=%s" % (playerLeaveTick), playerID)
                continue
            pvpDamage = gameFB.GetPlayerGameFBDictByKey(playerID, FBPDict_PVPDamage)
            pvpDamTick = gameFB.GetPlayerGameFBDictByKey(playerID, FBPDict_PVPDamUpdTick)
            sortTick = tick - pvpDamTick
            curHP = 0 if not player else GameObj.GetHP(player)
            curMaxHP = 0 if not player else GameObj.GetMaxHP(player)
            playerInfoList.append([pvpDamage, sortTick, curHP, curMaxHP, playerLeaveTick, playerID, player])
            GameWorld.Log("PK超时: pvpDamge=%s,pvpDamTick=%s,tick=%s,sortTick=%s,HP=%s/%s,playerLeaveTick=%s"
                          % (pvpDamage, pvpDamTick, tick, sortTick, curHP, curMaxHP, playerLeaveTick), playerID)
        playerInfoList.sort(reverse=True)
        GameWorld.Log("PK超时, 进入结算!playerInfoList=%s" % str(playerInfoList))
        winner = playerInfoList[0][-1] if len(playerInfoList) > 0 else None
        loser = playerInfoList[1][-1] if len(playerInfoList) > 1 else None
        winnerID = 0 if not winner else winner.GetPlayerID()
        loserID = 0 if not loser else loser.GetPlayerID()
        return winner, winnerID, loser, loserID
    # 其他情况则在线玩家获胜,如果没有玩家在线,则最迟离线的获胜
    for i in xrange(copyMapPlayerManager.GetPlayerCount()):
        player = copyMapPlayerManager.GetPlayerByIndex(i)
        if player == None or player.IsEmpty():
            continue
        playerID = player.GetPlayerID()
        if playerID not in [playerIDA, playerIDB]:
            GameWorld.ErrLog("副本中玩家不在进入的玩家ID里,不处理! roomID=%s,playerID=%s" % (roomID, playerID))
            continue
        winner = player
        winnerID = player.GetPlayerID()
        GameWorld.Log("超时结算,玩家在线,直接获胜: roomID=%s,winnerID=%s" % (roomID, winnerID))
        break
    if not winner:
        playerLeaveTickA = gameFB.GetGameFBDictByKey(GameFBDict_PlayerLeaveTick % playerIDA)
        playerLeaveTickB = gameFB.GetGameFBDictByKey(GameFBDict_PlayerLeaveTick % playerIDB)
        GameWorld.Log("超时结算,没有玩家在线,后离线的获胜: playerLeaveTickA=%s,playerLeaveTickB=%s" % (playerLeaveTickA, playerLeaveTickB))
        # 离线tick较大的就是比较晚离线的
        if playerLeaveTickA > playerLeaveTickB:
            winnerID = playerIDA
            loserID = playerIDB
        else:
            winnerID = playerIDB
            loserID = playerIDA
    else:
        loserID = playerIDB if playerIDA == winnerID else playerIDA
    return winner, winnerID, loser, loserID
##副本准备时间
def __DoLogic_MapPrepare(tick):
    fbTimeList = IpyGameDataPY.GetFuncEvalCfg("CrossRealmPKFB", 1)
    GameWorld.DebugLog("__DoLogic_MapPrepare ... %s" % fbTimeList[Def_Time_MapPrepare])
    if tick - GameWorld.GetGameFB().GetFBStepTick() < fbTimeList[Def_Time_MapPrepare] * 1000:
        return
    FBCommon.SetFBStep(FB_State_Fight, tick)
    FBCommon.Sync_Player_TimeTick(ChConfig.tttTowerTake, fbTimeList[Def_Time_Fight] * 1000)
    FBCommon.SyncDynamicBarrierState(IpyGameDataPY.GetFuncEvalCfg("CrossRealmPKFB", 2), 0)
    # 通知回合开始
    helpDict = __GetFBHelpInfo()
    helpDict["isStart"] = 1
    copyMapPlayerManager = GameWorld.GetMapCopyPlayerManager()
    for i in xrange(copyMapPlayerManager.GetPlayerCount()):
        player = copyMapPlayerManager.GetPlayerByIndex(i)
        if player == None or player.IsEmpty():
            continue
        FBCommon.Notify_FBHelp(player, helpDict)
    return
##战斗阶段
def __DoLogic_MapFight(tick):
    fbTimeList = IpyGameDataPY.GetFuncEvalCfg("CrossRealmPKFB", 1)
    if tick - GameWorld.GetGameFB().GetFBStepTick() < fbTimeList[Def_Time_Fight] * 1000:
        return
    winner, winnerID, loser, loserID = __GetTimeoutWinerInfo(tick)
    roomID = GameWorld.GetGameWorld().GetPropertyID()
    GameWorld.Log("PK超时, 进入结算! roomID=%s,winnerID=%s,loserID=%s" % (roomID, winnerID, loserID))
    __DoLogicAddPlayerWinCnt(winner, winnerID, loser, loserID, Def_OverType_TimeOut, tick)
    return
##复活阶段阶段
def __DoLogic_Reborn(tick):
    gameFB = GameWorld.GetGameFB()
    helpDict = __GetFBHelpInfo()
    fbTimeList = IpyGameDataPY.GetFuncEvalCfg("CrossRealmPKFB", 1)
    prepareTime = fbTimeList[Def_Time_MapPrepare] * 1000
    helpDict["prepareTime"] = prepareTime
    roundNum = gameFB.GetGameFBDictByKey(FB_RoundNum)
    winnerID = gameFB.GetGameFBDictByKey(FB_RoundWinPlayerID % roundNum)
    nextRoundNum = gameFB.GetGameFBDictByKey(FB_RoundNum) + 1
    gameFB.SetGameFBDict(FB_RoundNum, nextRoundNum)
    copyMapPlayerManager = GameWorld.GetMapCopyPlayerManager()
    for i in xrange(copyMapPlayerManager.GetPlayerCount()):
        player = copyMapPlayerManager.GetPlayerByIndex(i)
        if player == None or player.IsEmpty():
            continue
        playerID = player.GetPlayerID()
        gameFB.SetPlayerGameFBDict(playerID, FBPDict_RoundNum, nextRoundNum)
        if player.GetPlayerAction() == IPY_GameWorld.paDie or GameObj.GetHP(player) <= 0:
            GameWorld.DebugLog("复活玩家...", player.GetPlayerID())
            ChPlayer.PlayerRebornByType(player, ChConfig.rebornType_System, tick, isAddSuperBuff=False)
            __ResetPlayerState(gameFB, player, playerID)
        elif winnerID and playerID != winnerID:
            GameWorld.DebugLog("平局,输的玩家回满血!", playerID)
            __ResetPlayerState(gameFB, player, playerID)
        else:
            __ResetPlayerState(gameFB, player, playerID, False)
        FBCommon.Notify_FBHelp(player, helpDict)
    GameWorld.Log("开始下一回合: nextRoundNum=%s" % (nextRoundNum))
    # 重置伤害输出
    playerIDA = gameFB.GetGameFBDictByKey(GameFBDict_FBPlayerID % 1)
    playerIDB = gameFB.GetGameFBDictByKey(GameFBDict_FBPlayerID % 2)
    gameFB.SetPlayerGameFBDict(playerIDA, FBPDict_PVPDamage, 0)
    gameFB.SetPlayerGameFBDict(playerIDA, FBPDict_PVPDamUpdTick, tick)
    gameFB.SetPlayerGameFBDict(playerIDB, FBPDict_PVPDamage, 0)
    gameFB.SetPlayerGameFBDict(playerIDB, FBPDict_PVPDamUpdTick, tick)
    # 进入准备倒计时,开始下一局准备
    FBCommon.SetFBStep(FB_State_MapPrepare, tick)
    #FBCommon.Sync_Player_TimeTick(ChConfig.tttWaitStart, prepareTime)
    return
##比赛结束的空闲时间
def __DoLogic_LeaveTime(tick):
    fbTimeList = IpyGameDataPY.GetFuncEvalCfg("CrossRealmPKFB", 1)
    if tick - GameWorld.GetGameFB().GetFBStepTick() < fbTimeList[Def_Time_Leave] * 1000:
        return
    FBCommon.SetFBStep(FB_State_Close, tick)
    GameWorldProcess.CloseFB(tick)
    return
## PVP伤害相关
def OnPVPDamage(curPlayer, damageValue, tagPlayer, tick):
    playerID = curPlayer.GetPlayerID()
    tagPlayerID = tagPlayer.GetPlayerID()
    gameFB = GameWorld.GetGameFB()
    curPlayerDamage = gameFB.GetPlayerGameFBDictByKey(playerID, FBPDict_PVPDamage)
    updDamage = min(ChConfig.Def_UpperLimit_DWord, curPlayerDamage + damageValue)
    gameFB.SetPlayerGameFBDict(playerID, FBPDict_PVPDamage, updDamage)
    gameFB.SetPlayerGameFBDict(playerID, FBPDict_PVPDamUpdTick, tick)
    GameWorld.DebugLog("OnPVPDamage playerID=%s,tagPlayerID=%s,damageValue=%s,updDamage=%s,tick=%s"
                       % (playerID, tagPlayerID, damageValue, updDamage, tick))
    #helpDict = {"PVPDamage":[playerID, updDamage, tick]}
    #FBCommon.Notify_FBHelp(curPlayer, helpDict)
    #FBCommon.Notify_FBHelp(tagPlayer, helpDict)
    return
##处理副本中杀死玩家逻辑
def DoFBOnKill_Player(curPlayer, defender, tick):
    winnerID = curPlayer.GetPlayerID()
    loserID = defender.GetPlayerID()
    roomID = GameWorld.GetGameWorld().GetPropertyID()
    GameWorld.Log("DoFBOnKill_Player roomID=%s,winnerID=%s,loserID=%s" % (roomID, winnerID, loserID), winnerID)
    if GameWorld.GetGameFB().GetFBStep() != FB_State_Fight:
        return
    __DoLogicAddPlayerWinCnt(curPlayer, winnerID, defender, loserID, Def_OverType_Kill, tick)
    return True
def __DoLogicAddPlayerWinCnt(winner, winnerID, loser, loserID, overType, tick):
    gameFB = GameWorld.GetGameFB()
    roomID = GameWorld.GetGameWorld().GetPropertyID()
    winnerWinCnt = gameFB.GetGameFBDictByKey(GameFBDict_PlayerWinCnt % winnerID)
    updWinCnt = winnerWinCnt + 1
    gameFB.SetGameFBDict(GameFBDict_PlayerWinCnt % winnerID, updWinCnt)
    roundNum = gameFB.GetGameFBDictByKey(FB_RoundNum)
    gameFB.SetGameFBDict(FB_RoundWinPlayerID % roundNum, winnerID)
    GameWorld.Log("回合结束: roomID=%s,roundNum=%s,winnerID=%s,loserID=%s,updWinCnt=%s" % (roomID, roundNum, winnerID, loserID, updWinCnt))
    isOver = (updWinCnt >= IpyGameDataPY.GetFuncCfg("CrossRealmPKFB", 3))
    if not isOver:
        if winner:
            clearDeBuff = False
            # 胜利者马上清除负面buff,防止死亡导致回合表现异常,如中毒
            for buffType in [IPY_GameWorld.bfDeBuff, IPY_GameWorld.bfProcessDeBuff, IPY_GameWorld.bfActionBuff]:
                buffTuple = SkillCommon.GetBuffManagerByBuffType(winner, buffType)
                if buffTuple:
                    buffState = buffTuple[0]
                    buffCount = buffState.GetBuffCount()
                    if buffCount:
                        clearDeBuff = True
                        buffState.Clear()
                        GameWorld.DebugLog("胜者马上清除 buffType=%s,buffCount=%s" % (buffType, buffCount), winner.GetPlayerID())
            if clearDeBuff:
                PlayerControl.PlayerControl(winner).RefreshAllState()
        FBCommon.SetFBStep(FB_State_Reborn, tick)
        return
    GameWorld.Log("    已达到最大胜场,获得最终胜利!winnerID=%s" % winnerID)
    __DoFBPKAllOver(winner, winnerID, loser, loserID, overType, tick)
    return
def __ResetPlayerState(gameFB, player, playerID, resetAttr=True):
    posX = gameFB.GetPlayerGameFBDictByKey(playerID, FBPDict_ResetPosX)
    posY = gameFB.GetPlayerGameFBDictByKey(playerID, FBPDict_ResetPosY)
    player.ResetPos(posX, posY)
    if not resetAttr:
        return
    if GameObj.GetHP(player) != GameObj.GetMaxHP(player):
        GameObj.SetHP(player, GameObj.GetMaxHP(player))
    if PlayerControl.GetProDef(player) != PlayerControl.GetMaxProDef(player):
        PlayerControl.SetProDef(player, PlayerControl.GetMaxProDef(player))
    SkillCommon.ResetAllSkillCD(player)
    return
## 跨服PK结束处理,注意 winner、loser 参数可能为None
def __DoFBPKAllOver(winner, winnerID, loser, loserID, overType, tick):
    gameFB = GameWorld.GetGameFB()
    roundWinerIDList = []
    roundNum = gameFB.GetGameFBDictByKey(FB_RoundNum)
    for roundNum in xrange(1, roundNum + 1):
        roundWinerIDList.append(gameFB.GetGameFBDictByKey(FB_RoundWinPlayerID % roundNum))
    #副本状态进入关闭倒计时
    fbTimeList = IpyGameDataPY.GetFuncEvalCfg("CrossRealmPKFB", 1)
    FBCommon.Sync_Player_TimeTick(ChConfig.tttLeaveMap, fbTimeList[Def_Time_Leave] * 1000)
    FBCommon.SetFBStep(FB_State_Leave, tick)
    #发送一条消息到GameServer通知PK对战结束,因为地图可能对手没来导致没有失败玩家ID,所以结算统一在GameServer处理
    overType = 1 if overType in [Def_OverType_LackPlayer, Def_OverType_PlayerExit] else 0
    roomID = GameWorld.GetGameWorld().GetPropertyID()
    sendMsg = str([roomID, winnerID, loserID, roundWinerIDList, overType])
    GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(0, 0, 0, "CrossPKOver", sendMsg, len(sendMsg))
    GameWorld.Log("PK结算SendToGameServer: roomID=%s,winnerID=%s,loserID=%s,roundWinerIDList=%s,overType=%s"
                  % (roomID, winnerID, loserID, roundWinerIDList, overType))
    return
#关系有3层,无-友好-敌人
def CheckPlayersRelation_IsFriend(curPlayer, curTagPlayer):
    return not CanAttackPlayer(curPlayer, curTagPlayer)
##副本中,攻击队友逻辑
def DoCanAttackTeamer(curPlayer, curTagPlayer):
    return CanAttackPlayer(curPlayer, curTagPlayer)
##副本中,是否可攻击
def CanAttackPlayer(curPlayer, curTagPlayer):
    fbStep = GameWorld.GetGameFB().GetFBStep()
    if fbStep != FB_State_Fight:
        GameWorld.DebugLog("非战斗阶段,不可攻击!")
        return False
    
    return True
def OnMirrorBattleOver(battleID):
    ## 镜像战斗结束
    battle = MirrorAttack.GetMirrorBattleByID(battleID)
    if not battle:
        return
    isLogout = battle.isLogout
    mapID = battle.mapID
    funcLineID = battle.funcLineID
    winFaction = battle.winFaction
    curPlayerID = battle.requestID # 副本所属玩家ID,该玩家不一定参与实际战斗
    curIsWin = 0
    tagPlayerID = 0
    GameWorld.DebugLog("镜像战斗结算: mapID=%s,funcLineID=%s,winFaction=%s,isLogout=%s" % (mapID, funcLineID, winFaction, isLogout), battleID)
    playerMgr = GameWorld.GetMapCopyPlayerManager()
    for playerID, faction in battle.playerFactionDict.items():
        curPlayer = playerMgr.FindPlayerByID(playerID)
        if not curPlayer:
            continue
        realPlayerID = curPlayer.GetRealPlayerID()
        isWin = (faction == winFaction)
        GameWorld.DebugLog("剩余血量: %s/%s,playerID=%s,realPlayerID=%s,faction=%s,isWin=%s"
                           % (GameObj.GetHP(curPlayer), GameObj.GetMaxHP(curPlayer), playerID, realPlayerID, faction, isWin), battleID)
        if isWin and faction == 1:
            curIsWin = 1
        if faction != 1 and not tagPlayerID:
            tagPlayerID = realPlayerID
    if not curPlayerID:
        return
    curPlayer = playerMgr.FindPlayerByID(curPlayerID)
    if not curPlayer:
        return
    PlayerCrossRealmPK.SendPKOver(curPlayer, tagPlayerID, curIsWin)
    return