ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_SealDemon.py
@@ -18,130 +18,75 @@
import FBCommon
import GameWorld
import IPY_GameWorld
import GameWorldProcess
import IpyGameDataPY
import ChConfig
import PyGameData
import PlayerControl
import NPCCommon
import ItemCommon
import ChPyNetSendPack
import ShareDefine
import EventShell
import NPCCustomRefresh
import PlayerSuccess
import PlayerActivity
import NetPackCommon
import PlayerVip
import PlayerMagicWeapon
import GameObj
import PlayerBossReborn
import PlayerFairyCeremony
import PlayerNewFairyCeremony
import PlayerWeekParty
import PlayerActLogin
import EventReport
import PlayerTeam
import NPCHurtManager
import GameWorldProcess
import PetControl
import AttackCommon
FBDict_StartTick = 'FBDict_StartTick%s' #开始时间
FBDict_Speed = 'FBDict_Speed%s' #掉血速度 /s
FBDict_RemainHP = 'FBDict_RemainHP%s' #剩余时间
#当前副本地图的状态
(
FB_Step_Open, # 副本开启
FB_Step_Fighting, # 副本进行中
FB_Step_Over, # 副本结束
FB_Step_Close, # 关闭状态
) = range(4)
FBPlayerDict_EncourageLV = 'FBPlayerDict_EncourageLV'   # 鼓舞等级
FBDict_IsOver = 'FBDict_IsOver' #是否已结算, 结算时的tick
FBPlayerDict_Rank = "FBPlayerDict_Rank" # 玩家排名
g_npcHurtDict = {}
def OnFBPlayerOnLogin(curPlayer):
    if not GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_Player_Dict_VersionFix, ChConfig.Def_VerFix_FMTDouble):
        GameWorld.SetDictValueByBit(curPlayer, ChConfig.Def_Player_Dict_VersionFix, ChConfig.Def_VerFix_FMTDouble, 1)
        needViplv = IpyGameDataPY.GetFuncCfg('DemonJarSpecial')
        if curPlayer.GetVIPLv() >= needViplv:
            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_FMTOldDouble, 1)
            GameWorld.DebugLog('1.3版本前可以双倍挑战')
    NotifyFMTDouble(curPlayer)
    return
## 是否能够通过活动查询进入
#  @param curPlayer 玩家实例
#  @param mapID 地图ID
#  @param lineID 线路id
#  @param tick 时间戳
#  @return 布尔值
def OnEnterFBEvent(curPlayer, mapID, lineID, tick):
    IsDouble = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_FMTDouble)
    newbielineList = IpyGameDataPY.GetFuncEvalCfg('SealDemonNewbieLine')
    if IsDouble and lineID not in newbielineList:
        enterCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_EnterFbCntDay % mapID)
        maxCnt = FBCommon.GetEnterFBMaxCnt(curPlayer, mapID)
        if enterCnt + 2 > maxCnt:
            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 tick 时间戳
##  @return 布尔值
## 查询地图是否开启
#def OnCanOpen(tick):
#    return True
##查询是否可以进入地图
# @param ask:请求结构体(IPY_BMChangeMapAsk)
# @param tick:时间戳
# @return IPY_GameWorld.cme 枚举
## 查询是否可以进入地图
def OnChangeMapAsk(ask, tick):
    return IPY_GameWorld.cmeAccept
##开启副本
# @param tick 时间戳
# @return 返回值无意义
# @remarks 开启副本
## 开启副本
def OnOpenFB(tick):
    mapID = GameWorld.GetMap().GetMapID()
    if mapID == ChConfig.Def_FBMapID_SealDemonEx:
        return
    lineID = GameWorld.GetGameWorld().GetPropertyID() - 1
    bossID = CurFBLineBOSSID(lineID)
    key = ShareDefine.Def_Notify_WorldKey_GameWorldBossReborn % bossID
    GameWorld.GetGameWorld().SetGameWorldDict(key, 1)
    GameWorld.DebugLog('    ˢBOSSbossID=%s' % bossID)
    refreshIDList = FBCommon.GetFBLineRefreshNPC(ChConfig.Def_FBMapID_SealDemon, lineID)
    if refreshIDList:
        for refreshID in refreshIDList:
            NPCCustomRefresh.SetNPCRefreshByID(refreshID)
    FBCommon.SetFBStep(FB_Step_Fighting, tick)
    return
## 进副本
#  @param curPlayer
#  @param tick
#  @return None
def DoEnterFB(curPlayer, tick):
    playerID = curPlayer.GetPlayerID()
    mapID = GameWorld.GetMap().GetMapID()
    if mapID == ChConfig.Def_FBMapID_SealDemonEx:
        lineID = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_ReqFBFuncLine)
        FBCommon.SetFBPropertyMark(lineID)
    else:
        lineID = GameWorld.GetGameWorld().GetPropertyID() - 1
    lineID = GameWorld.GetGameWorld().GetPropertyID() - 1
    playerCnt = GameWorld.GetGameWorld().GetMapCopyPlayerManager().GetPlayerCount()
    GameWorld.DebugLog("DoEnterFB...playerCnt=%s,lineID=%s" % (playerCnt, lineID), playerID)
    if lineID < 0:
    gameFB = GameWorld.GetGameFB()
    if gameFB.GetFBStep() != FB_Step_Fighting:
        PlayerControl.PlayerLeaveFB(curPlayer)
        return
    hadDelTicket = FBCommon.GetHadDelTicket(curPlayer)
    if not hadDelTicket:
        FBCommon.SetHadDelTicket(curPlayer)
@@ -150,22 +95,7 @@
            posX, posY = IpyGameDataPY.GetFuncEvalCfg('SealDemonFirstPos')
            GameWorld.ResetPlayerPos(curPlayer, posX, posY)
        EventReport.WriteEvent_FB(curPlayer, ChConfig.Def_FBMapID_SealDemon, 0, ChConfig.CME_Log_Start)
        newbielineList = IpyGameDataPY.GetFuncEvalCfg('SealDemonNewbieLine')
        if lineID not in newbielineList:
            pass
#            FBCommon.AddEnterFBCount(curPlayer, ChConfig.Def_FBMapID_SealDemon)
#            # 每日活动
#            PlayerActivity.AddDailyActionFinishCnt(curPlayer, ShareDefine.DailyActionID_SealDemon)
        else:
            hasEnter = GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_Player_Dict_PlayerFBStar_MapId, lineID, False, [ChConfig.Def_FBMapID_SealDemon])
            if hasEnter:
                GameWorld.DebugLog("    已进入过该新手线路 %s" % lineID, playerID)
                PlayerControl.PlayerLeaveFB(curPlayer)
                return
        UpdateHurtInfo(curPlayer, 0, True)
    UpdateHPReduceSpeed(tick)
    gameFB = GameWorld.GetGameFB()
    # 上鼓舞buff
    encourageLV = gameFB.GetPlayerGameFBDictByKey(playerID, FBPlayerDict_EncourageLV)
    if encourageLV > 0:
@@ -173,283 +103,152 @@
    else:
        FBCommon.SendFBEncourageInfo(curPlayer, encourageLV)
        
    #DoFBHelp(curPlayer, tick)
    return
##关闭副本
# @param tick 时间戳
# @return 无意义
# @remarks
## 关闭副本
def OnCloseFB(tick):
    gameWorld = GameWorld.GetGameWorld()
    lineID = gameWorld.GetPropertyID() - 1
    gameWorld.SetGameWorldDict(FBDict_StartTick % lineID, 0)
    gameWorld.SetGameWorldDict(FBDict_Speed % lineID, 0)
    gameWorld.SetGameWorldDict(FBDict_RemainHP % lineID, 0)
    gameWorld.SetPropertyID(0)
    #GameWorld.GetGameWorld().SetPropertyID(0)
    return
##玩家退出副本
# @param curPlayer 玩家实例
# @param tick 时间戳
# @return 无意义
## 玩家退出副本
def DoExitFB(curPlayer, tick):
    global g_npcHurtDict
    gameWorld = GameWorld.GetGameWorld()
    # 清除鼓舞buff
    FBCommon.ClearEncourageBuff(curPlayer, tick)
    #最后一人
    if gameWorld.GetMapCopyPlayerManager().GetPlayerCount() == 1:
        mapID = GameWorld.GetMap().GetMapID()
        if mapID != ChConfig.Def_FBMapID_SealDemonEx:#单人的不管
            lineID = gameWorld.GetPropertyID() - 1
            PyGameData.g_sealDemonPlayerHurtDict[lineID] = {}
            g_npcHurtDict[lineID] = {}
            gameWorld.SetGameWorldDict(FBDict_StartTick % lineID, 0)
            GameWorld.GetGameFB().ClearGameFBDict()
            GameWorldProcess.CloseFB(tick)
            return
    UpdateHPReduceSpeed(tick, True)
    return
##玩家主动离开副本.
# @param curPlayer 玩家实例
# @param tick 时间戳
# @return 返回值无意义
## 玩家主动离开副本.
def DoPlayerLeaveFB(curPlayer, tick):
    FBCommon.SetHadDelTicket(curPlayer, 0)
    #主动退出的去掉排行榜信息
    lineID = GameWorld.GetGameWorld().GetPropertyID() - 1
    playerHurtDict = PyGameData.g_sealDemonPlayerHurtDict.get(lineID, {})
    playerHurtDict.pop(curPlayer.GetPlayerID(), 0)
    PyGameData.g_sealDemonPlayerHurtDict[lineID] = playerHurtDict
    #最后一人
    if GameWorld.GetGameWorld().GetMapCopyPlayerManager().GetPlayerCount() == 1:
        GameWorldProcess.CloseFB(tick)
    return
##玩家切换地图
## 玩家切换地图
def DoPlayerChangeMapLogic(curPlayer):
    FBCommon.SetHadDelTicket(curPlayer, 0)
    return
## 是否副本复活
#  @param None
#  @return 是否副本复活
def OnPlayerReborn():
    return True
## 获得副本帮助信息
#  @param curPlayer 当前玩家(被通知对象)
#  @param tick 当前时间
#  @return None
def DoFBHelp(curPlayer, tick):
    #伤害排行信息
    hurtInfo = []
    lineID = GameWorld.GetGameWorld().GetPropertyID() - 1
    playerHurtList = PyGameData.g_sealDemonPlayerHurtDict.get(lineID, {}).items()
    npcHurtList = g_npcHurtDict.get(lineID, {}).items()
    syncHurtList = (playerHurtList + npcHurtList)[:5]
    syncHurtList.sort(key=lambda asd:asd[1][1], reverse=True)
    for i, info in enumerate(syncHurtList, 1):
        playerName, hurt = info[1]
        hurtDict = {}
        hurtDict["rank"] = i
        hurtDict["playerName"] = playerName
        hurtDict["hurt"] = hurt % ChConfig.Def_PerPointValue
        hurtDict["hurtEx"] = hurt / ChConfig.Def_PerPointValue
        hurtInfo.append(hurtDict)
    myRank = __GetSelfHurtRank(curPlayer)
    if myRank and myRank > 5:
        hurtDict = {}
        hurtDict["rank"] = myRank
        info = playerHurtList[myRank - 1]
        playerName, hurt = info[1]
        hurtDict["playerName"] = playerName
        hurtDict["hurt"] = hurt % ChConfig.Def_PerPointValue
        hurtDict["hurtEx"] = hurt / ChConfig.Def_PerPointValue
        hurtInfo.append(hurtDict)
    curSpeed = GameWorld.GetGameWorld().GetGameWorldDictByKey(FBDict_Speed % lineID)
    remainHP = GetBossRemainHP(lineID, tick)
    totalHP = __GetBossTotalHP()
    hpReduceSpeed = curSpeed * 10000 / totalHP if totalHP else 0
    remainHPPer = min(100, remainHP * 100 / totalHP) if totalHP else 0
    fbHelpDict = {FBCommon.Help_lineID:lineID, "hurtInfo":hurtInfo, 'hpReduceSpeed':hpReduceSpeed, 'remainHPPer':remainHPPer}
    GameWorld.DebugLog("DoFBHelp: %s" % fbHelpDict, curPlayer.GetPlayerID())
    FBCommon.Notify_FBHelp(curPlayer, fbHelpDict)
    return
def __GetSelfHurtRank(curPlayer):
    #获取自己的排名
    playerName = curPlayer.GetName()
    lineID = GameWorld.GetGameWorld().GetPropertyID() - 1
    playerHurtList = __GetSortHurtList(lineID)
    myRank = 0
    for i, info in enumerate(playerHurtList):
        if playerName == info[1][0]:
            myRank = i + 1
            break
    return myRank
## 副本行为
#  @param curPlayer 玩家
#  @param actionType 行为类型
#  @param actionInfo 行为信息
#  @param tick 当前时间
#  @return None
def DoFBAction(curPlayer, actionType, actionInfo, tick):
    if actionType == 0:
        FBCommon.FbEncourageBuff(curPlayer, FBPlayerDict_EncourageLV, actionInfo, tick)
    return
## 玩家对NPC造成伤害
#  @param curPlayer 当前玩家
#  @param curNPC
#  @param hurtHP
#  @return None
def DoFB_Player_HurtNPC(curPlayer, curNPC, hurtHP):
    UpdateHurtInfo(curPlayer, hurtHP)
    return
#
def UpdateHurtInfo(curPlayer, hurtHP, isAdd=False):
    mapID = GameWorld.GetMap().GetMapID()
    if mapID == ChConfig.Def_FBMapID_SealDemonEx:
        return
    lineID = GameWorld.GetGameWorld().GetPropertyID() - 1
    playerName = curPlayer.GetName()
    playerID = curPlayer.GetPlayerID()
    playerHurtDict = PyGameData.g_sealDemonPlayerHurtDict.get(lineID, {})
    if playerID not in playerHurtDict:
        if not isAdd:
            return
        playerHurtDict[playerID] = [playerName, hurtHP]
    else:
        playerHurtDict[playerID][1] += hurtHP
    PyGameData.g_sealDemonPlayerHurtDict[lineID] = playerHurtDict
    return
## 玩家对NPC造成伤害
#  @param curPlayer 当前玩家
#  @param curNPC
#  @param hurtHP
#  @return None
def DoFB_NPC_HurtNPC(curNPC, tagNPC, hurtHP):
    global g_npcHurtDict
    lineID = GameWorld.GetGameWorld().GetPropertyID() - 1
    npcID = curNPC.GetNPCID()
    guardNPCIDList = __GetGuardNPCIDList(lineID)
    if npcID not in guardNPCIDList:
        return
    npcHurtDict = g_npcHurtDict.get(lineID, {})
    if npcID not in npcHurtDict:
        npcName = curNPC.GetName().decode(ShareDefine.Def_Game_Character_Encoding).encode(GameWorld.GetCharacterEncoding())
        npcHurtDict[npcID] = [npcName, hurtHP]
    else:
        npcHurtDict[npcID][1] += hurtHP
    g_npcHurtDict[lineID] = npcHurtDict
    return
def __GetGuardNPCIDList(lineID):
    guardNPCIDList = []
    refreshIDList = FBCommon.GetFBLineRefreshNPC(ChConfig.Def_FBMapID_SealDemon, lineID)
    if refreshIDList:
        for refreshID in refreshIDList:
            ipyData = IpyGameDataPY.GetIpyGameData("NPCCustomRefresh", refreshID)
            if not ipyData:
                continue
            npcID = ipyData.GetRefreshNPCID()
            guardNPCIDList.append(npcID)
    return guardNPCIDList
##---副本总逻辑计时器---
# @param tick:时间戳
# @return 无意义
# @remarks 副本总逻辑计时器
## 副本总逻辑计时器
def OnProcess(tick):
    gameFB = GameWorld.GetGameFB()
    overTick = gameFB.GetGameFBDictByKey(FBDict_IsOver)
    # 结算20秒后强制关闭副本, 防止玩家不捡东西导致不结算,强关后地板上的东西会邮件发放给玩家
    if overTick and tick - overTick >= ChConfig.Def_FBPickupItemTime:
        GameWorld.Log("强制踢出玩家关闭副本: overTick=%s,tick=%s" % (overTick, tick))
        FBCommon.DoLogic_FBKickAllPlayer()
        return
    mapID = GameWorld.GetMap().GetMapID()
    if mapID == ChConfig.Def_FBMapID_SealDemonEx:
        return
    lineID = GameWorld.GetGameWorld().GetPropertyID() - 1
    if lineID <0:
        return
    gameWorld = GameWorld.GetGameWorld()
    startTick = gameWorld.GetGameWorldDictByKey(FBDict_StartTick % lineID)
    if not startTick:
        return
    FBCommon.NotifyCopyMapPlayerFBHelp(tick, DoFBHelp, 5000)
    __CheckBossHP(tick)
    
    return
def __CheckBossHP(tick):
    gameFB = GameWorld.GetGameFB()
    isOver = gameFB.GetGameFBDictByKey(FBDict_IsOver)
    lineID = GameWorld.GetGameWorld().GetPropertyID() - 1
    newbielineList = IpyGameDataPY.GetFuncEvalCfg('SealDemonNewbieLine')
    isNewbieLine = lineID in newbielineList
    if not isOver and GetBossRemainHP(lineID, tick) == 0:
        guardNPCIDList = __GetGuardNPCIDList(lineID)
        bossID = CurFBLineBOSSID(lineID)
        curBoss = GameWorld.FindNPCByNPCID(bossID)
        dropPosX, dropPosY = 0, 0
        if curBoss:
            dropPosX, dropPosY = curBoss.GetPosX(), curBoss.GetPosY()
        #结束 设置BOSS死亡
        FBCommon.ClearFBNPC(guardNPCIDList)
        FBCommon.NotifyCopyMapPlayerFBHelp(tick, DoFBHelp, 0)
        GameWorld.DebugLog('结束 设置BOSS死亡 lineID=%s' % lineID)
        playerHurtList = __GetSortHurtList(lineID)
        if not isNewbieLine:
            if playerHurtList:
                killerName, hurtValue = playerHurtList[0][1]
                NPCCommon.GameServer_KillGameWorldBoss(bossID, killerName, hurtValue)
            msgList = [bossID, 0]
            GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(0, 0, 0, 'GameWorldBossState',
                                                                '%s' % (msgList), len(str(msgList)))
            bosskey = ShareDefine.Def_Notify_WorldKey_GameWorldBossReborn % bossID
            GameWorld.GetGameWorld().SetGameWorldDict(bosskey, 0)
        __DoLogicSealDemonOver(1, tick, dropPosX, dropPosY)
        gameFB.SetGameFBDict(FBDict_IsOver, tick)
    fbStep = GameWorld.GetGameFB().GetFBStep()
    # 副本结束
    if fbStep == FB_Step_Over:
        __DoLogic_FB_Over(tick)
        
    return
def __GetSortHurtList(lineID):
    playerHurtDict = PyGameData.g_sealDemonPlayerHurtDict.get(lineID, {})
    playerHurtList = sorted(playerHurtDict.iteritems(), key=lambda asd:asd[1][1], reverse=True)
    return playerHurtList
def __DoLogic_FB_Over(tick):
    # 间隔未到
    if tick - GameWorld.GetGameFB().GetFBStepTick() < ChConfig.Def_FBPickupItemTime:
        return
    #副本关闭
    GameWorldProcess.CloseFB(tick)
    FBCommon.SetFBStep(FB_Step_Close, tick)
    return
def __DoLogicSealDemonOver(isPass, tick, dropPosX, dropPosY):
    #结算
## 检查是否可攻击, 主判定不可攻击的情况,其他逻辑由外层决定
#  @param attacker 攻击方
#  @param defender 防守方
#  @return bool
def CheckCanAttackTagObjInFB(attacker, defender):
    gameFB = GameWorld.GetGameFB()
    if gameFB.GetFBStep() != FB_Step_Fighting:
        return False
    lineID = GameWorld.GetGameWorld().GetPropertyID() - 1
    if defender.GetGameObjType() == IPY_GameWorld.gotNPC and defender.GetNPCID() == CurFBLineBOSSID(lineID):
        atkObjType = attacker.GetGameObjType()
        if atkObjType == IPY_GameWorld.gotPlayer:
            return NPCHurtManager.CheckPlayerCanAttackFBNPC(attacker, defender, ChConfig.Def_FBMapID_SealDemon, True)
        elif atkObjType == IPY_GameWorld.gotNPC:
            if PetControl.IsPet(attacker) or attacker.GetGameNPCObjType()== IPY_GameWorld.gnotSummon:
                ownerPlayer = AttackCommon.GetAttackPlayer(attacker)[0]
                if not ownerPlayer:
                    return False
                return NPCHurtManager.CheckPlayerCanAttackFBNPC(ownerPlayer, defender, ChConfig.Def_FBMapID_SealDemon)
    return True
def DoFB_Npc_KillNPC(attacker, curNPC, tick):
    __FBNPCOnKilled(curNPC, tick)
    return
def DoFB_Player_KillNPC(curPlayer, curNPC, tick):
    __FBNPCOnKilled(curNPC, tick)
    return
## 执行副本杀怪逻辑
def __FBNPCOnKilled(curNPC, tick):
    lineID = GameWorld.GetGameWorld().GetPropertyID() - 1
    bossID = CurFBLineBOSSID(lineID)
    if curNPC.GetNPCID() != bossID:
        return
    FBCommon.SetFBStep(FB_Step_Over, tick)
    dropPosX, dropPosY = curNPC.GetPosX(), curNPC.GetPosY()
    GameWorld.DebugLog('结束设置BOSS死亡 lineID=%s' % lineID)
    NPCCommon.GameServe_GameWorldBossState(bossID, 0)
    npcHurtList = NPCHurtManager.GetPlayerHurtList(curNPC)
    if not npcHurtList:
        GameWorld.ErrLog("没有伤血列表!lineID=%s,bossID=%s" % (lineID, bossID))
        return
    isPass = 1
    gameFB = GameWorld.GetGameFB()
    mapID = GameWorld.GetMap().GetMapID()
    lineID = GameWorld.GetGameWorld().GetPropertyID() - 1
    leaveTick = FBCommon.GetFBLineStepTime(mapID, lineID) * 1000
    playerHurtList = __GetSortHurtList(lineID)
    playerManager = GameWorld.GetPlayerManager()
    for rank, hurtInfo in enumerate(playerHurtList, 1):
        playerID = hurtInfo[0]
        curPlayer = playerManager.FindPlayerByID(playerID)
    copyMapPlayerManager = GameWorld.GetMapCopyPlayerManager()
    for index in xrange(npcHurtList.GetHurtCount()):
        hurtObj = npcHurtList.GetHurtAt(index)
        hurtID = hurtObj.GetValueID()
        hurtType = hurtObj.GetValueType()
        
        if curPlayer:
        playerIDList = []
        if hurtType == ChConfig.Def_NPCHurtTypePlayer:
            playerIDList = [hurtID]
        elif hurtType == ChConfig.Def_NPCHurtTypeTeam:
            teamID = hurtID
            mapTeamPlayerIDList = PlayerTeam.GetMapTeamPlayerIDList(teamID)
            for teamPlayerID in mapTeamPlayerIDList:
                if not npcHurtList.IsNoAssistPlayer(teamPlayerID):
                    continue
                playerIDList.append(teamPlayerID)
        else:
            continue
        rank = index + 1
        if rank == 1:
            NPCCommon.GameServer_KillGameWorldBoss(bossID, hurtObj.GetHurtName(), hurtObj.GetHurtValue())
        for playerID in playerIDList:
            curPlayer = copyMapPlayerManager.FindPlayerByID(playerID)
            if curPlayer == None:
                continue
            gameFB.SetPlayerGameFBDict(playerID, FBPlayerDict_Rank, rank)
            if not dropPosX or not dropPosY:
                dropPosX, dropPosY = curPlayer.GetPosX(), curPlayer.GetPosY()
@@ -461,67 +260,48 @@
                FBCommon.NotifyFBOver(curPlayer, ChConfig.Def_FBMapID_SealDemon, lineID, isPass, overDict)
            else:
                curPlayer.Sync_TimeTick(ChConfig.tttPickupItem, 0, ChConfig.Def_FBPickupItemTime, True)
        else:
            leaveTick = PlayerControl.GetPlayerLeaveServerTick(playerID)
            if not leaveTick:
                continue
            if tick - leaveTick > ChConfig.Def_PlayerOfflineProtectTime:
                #离线超过3分钟的不给奖励
                continue
            msgStr = str([playerID, lineID, rank])
            GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(0, 0, 0, 'SealDemonOver', msgStr, len(msgStr))
    return
def GiveSealDemonAward(curPlayer, lineID, rank, isMail=False, isClientSend=False, dropItemMapInfo=[]):
    newbielineList = IpyGameDataPY.GetFuncEvalCfg('SealDemonNewbieLine')
    isNewbieLine = lineID in newbielineList
    sealDemonIpyData = GetSealDemonIpyData(lineID)
    if not sealDemonIpyData:
        return {}
    prizeMultiple = 1
    addCnt = 1
    if isNewbieLine:
        hasEnter = GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_Player_Dict_PlayerFBStar_MapId, lineID, False, [ChConfig.Def_FBMapID_SealDemon])
        if hasEnter:
            #已给过
            return {}
        newbieLineStar = GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_Player_Dict_PlayerFBStar_MapId, lineID, False, [ChConfig.Def_FBMapID_SealDemon])
        # 新手本改为可重复进入
#        hasEnter = GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_Player_Dict_PlayerFBStar_MapId, lineID, False, [ChConfig.Def_FBMapID_SealDemon])
#        if hasEnter:
#            #已给过
#            return {}
    elif isClientSend:
        return {}
    else:
        prizeMultiple = 2 if rank == 1 else 1 # 第一名执行双倍掉落奖励,其他一次
        isDouble = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_FMTDouble)
        if isDouble:
            addCnt = 2
        #prizeMultiple = 2 if rank == 1 else 1 # 第一名执行双倍掉落奖励,其他一次
        prizeMultiple = 1 # 去除第一名双倍逻辑,改为放在额外奖励产出
    equipList = []
    prizeItemDict ={}
    prizeItemDict = {}
    bossID = CurFBLineBOSSID(lineID)
    #for _ in xrange(addCnt):
    jsonItemList, totalExp, totalMoney = NPCCommon.GiveKillNPCDropPrize(curPlayer, ChConfig.Def_FBMapID_SealDemon, {bossID:addCnt},
                                                                        mailTypeKey="SealDemonMail", isMail=isMail, prizeMultiple=prizeMultiple,
                                                                        dropItemMapInfo=dropItemMapInfo)
    extraItemList = sealDemonIpyData.GetOwnerAwardItemEx() * addCnt if rank == 1 else []
    jsonItemList, totalExp, totalMoney = NPCCommon.GiveKillNPCDropPrize(curPlayer, ChConfig.Def_FBMapID_SealDemon, {bossID:addCnt},
                                                                        mailTypeKey="SealDemonMail", isMail=isMail, extraItemList=extraItemList, prizeMultiple=prizeMultiple,
                                                                        dropItemMapInfo=dropItemMapInfo, isVirtualDrop=isClientSend)
    for jsonItem in jsonItemList:
        if 'UserData' in jsonItem:
            equipList.append(jsonItem)
        else:
            itemID, itemCnt = jsonItem['ItemID'], jsonItem.get('Count',1)
            prizeItemDict[itemID] = prizeItemDict.get(itemID,0)+itemCnt
            itemID, itemCnt = jsonItem['ItemID'], jsonItem.get('Count', 1)
            prizeItemDict[itemID] = prizeItemDict.get(itemID, 0) + itemCnt
    
    GameWorld.DebugLog("封魔坛结算奖励: lineID=%s,bossID=%s,rank=%s,totalExp=%s,totalMoney=%s,jsonItemList=%s" 
                       % (lineID, bossID, rank, totalExp, totalMoney, jsonItemList), curPlayer.GetPlayerID())
    
    prizeItemList = equipList + FBCommon.GetJsonItemList(prizeItemDict.items())
    #===============================================================================================
    # if not isMail:
    #    for itemDict in prizeItemList:
    #        itemID = itemDict["ItemID"]
    #        itemData = GameWorld.GetGameData().GetItemByTypeID(itemID)
    #        if not itemData:
    #            continue
    #        userData = itemDict.get("UserData", '')
    #        equipInfo = [itemData.GetEquipPlace(), ItemCommon.GetItemClassLV(itemData), itemData.GetItemColor(),
    #                 itemData.GetItemQuality(), userData]
    #        mapID = ChConfig.Def_FBMapID_SealDemon
    #        NPCCommon.SendGameServerGoodItemRecord(mapID, bossID, curPlayer.GetName(),
    #                                               curPlayer.GetPlayerID(), itemID, equipInfo)
    #===============================================================================================
    
    if rank == 1:
        PlayerSuccess.DoAddSuccessProgress(curPlayer, ShareDefine.SuccType_FMTFirst, addCnt)
@@ -531,25 +311,29 @@
    PlayerSuccess.DoAddSuccessProgress(curPlayer, ShareDefine.SuccType_KillSpecificNPC, addCnt, [bossID])
    #新手线路的更新进去记录
    newbielineList = IpyGameDataPY.GetFuncEvalCfg('SealDemonNewbieLine')
    GameWorld.SetDictValueByBit(curPlayer, ChConfig.Def_Player_Dict_PlayerFBStar_MapId, lineID, 1, False, [ChConfig.Def_FBMapID_SealDemon])
    if lineID in newbielineList:
        FBCommon.Sync_FBPlayerFBInfoData(curPlayer, ChConfig.Def_FBMapID_SealDemon) # 同步信息
    if isNewbieLine:
        # 未过关不扣次数
        if newbieLineStar:
            FBCommon.AddEnterFBCount(curPlayer, ChConfig.Def_FBMapID_SealDemon, addCnt)
        else:
            FBCommon.Sync_FBPlayerFBInfoData(curPlayer, ChConfig.Def_FBMapID_SealDemon) # 同步信息
    else:
        FBCommon.AddEnterFBCount(curPlayer, ChConfig.Def_FBMapID_SealDemon, addCnt)
    # 每日活动
    PlayerActivity.AddDailyActionFinishCnt(curPlayer, ShareDefine.DailyActionID_SealDemon, addCnt)
    EventShell.EventRespons_FBEvent(curPlayer, "sealdemon_%s" % (lineID+1))
    EventShell.EventRespons_FBEvent(curPlayer, "sealdemon_%s" % (lineID + 1))
    EventShell.EventRespons_FBEvent(curPlayer, "sealdemon_0")
    #任务
    if rank == 1 and lineID >= 4:
        EventShell.EventRespons_SealDemon(curPlayer)
    
    PlayerMagicWeapon.SetMWPrivilegeData(curPlayer, ChConfig.MWPrivilege_SealDemonAddAttr, addCnt, True)
    PlayerBossReborn.AddBossRebornActionCnt(curPlayer, ChConfig.Def_BRAct_FMT, addCnt)
    PlayerFairyCeremony.AddFCPartyActionCnt(curPlayer, ChConfig.Def_PPAct_FMT, addCnt)
    PlayerNewFairyCeremony.AddFCPartyActionCnt(curPlayer, ChConfig.Def_PPAct_FMT, addCnt)
    PlayerWeekParty.AddWeekPartyActionCnt(curPlayer, ChConfig.Def_WPAct_FMT, addCnt)
    PlayerActLogin.AddLoginAwardActionCnt(curPlayer, ChConfig.Def_LoginAct_FMT, addCnt)
    return prizeItemList
def OnPickUpItem(curPlayer, curItem, tick):
@@ -566,7 +350,7 @@
            isIn = False
            for itemInfo in PyGameData.g_fbPickUpItemDict[playerID]:
                if itemInfo["ItemID"] == jsonItem["ItemID"] and itemInfo.get("IsBind") == jsonItem.get("IsBind"):
                    itemInfo["Count"] = itemInfo.get("Count", 1)+ jsonItem.get("Count", 1)
                    itemInfo["Count"] = itemInfo.get("Count", 1) + jsonItem.get("Count", 1)
                    isIn = True
                    break
            if not isIn:
@@ -603,84 +387,27 @@
def OnClientEndFB(curPlayer, mapID, lineID, dataList):
    #客户端副本发送结束
    GameWorld.DebugLog('封魔坛 客户端副本发送结束mapID=%s,lineID=%s,dataList=%s' % (mapID,lineID,dataList), curPlayer.GetPlayerID())
    GameWorld.DebugLog('封魔坛 客户端副本发送结束mapID=%s,lineID=%s,dataList=%s' % (mapID, lineID, dataList), curPlayer.GetPlayerID())
    rank, hurt = dataList[:2]
    prizeItemList = GiveSealDemonAward(curPlayer, lineID, rank, False, True, [curPlayer.GetPosX(), curPlayer.GetPosY(), True])
    if rank == 1:
    if rank == 1 and prizeItemList:
        bossID = CurFBLineBOSSID(lineID)
        NPCCommon.GameServer_KillGameWorldBoss(bossID, curPlayer.GetName(), hurt, False)
    if not prizeItemList:
        leaveTick = FBCommon.GetFBLineStepTime(mapID, lineID) * 1000
        GameWorld.Log("没有奖励,直接通知前端结算!mapID=%s,lineID=%s" % (mapID, lineID), curPlayer.GetPlayerID())
        curPlayer.Sync_TimeTick(IPY_GameWorld.tttLeaveMap, 0, leaveTick, True)
        overDict = {FBCommon.Over_rank:rank, FBCommon.Over_itemInfo:prizeItemList}
        FBCommon.NotifyFBOver(curPlayer, ChConfig.Def_FBMapID_SealDemon, lineID, 1, overDict)
        return
    gameFB = GameWorld.GetGameFB()
    tick = GameWorld.GetGameWorld().GetTick()
    gameFB.SetGameFBDict(FBDict_IsOver, tick)
    gameFB.SetPlayerGameFBDict(curPlayer.GetPlayerID(), FBPlayerDict_Rank, rank)
    curPlayer.Sync_TimeTick(ChConfig.tttPickupItem, 0, ChConfig.Def_FBPickupItemTime, True)
    #GameWorld.Log("通知前端结算!mapID=%s,lineID=%s" % (mapID, lineID), curPlayer.GetPlayerID())
    overDict = {FBCommon.Over_rank:rank, FBCommon.Over_itemInfo:prizeItemList}
    FBCommon.NotifyFBOver(curPlayer, mapID, lineID, 1, overDict)
    PlayerControl.SetCustomMap(curPlayer, 0, 0)
    return
def UpdateHPReduceSpeed(tick, isExit=False):
    mapID = GameWorld.GetMap().GetMapID()
    if mapID == ChConfig.Def_FBMapID_SealDemonEx:
        return
    playerCnt = GameWorld.GetGameWorld().GetMapCopyPlayerManager().GetPlayerCount()
    playerCnt = playerCnt - 1 if isExit else playerCnt
    if playerCnt <=0:
        return
    lineID = GameWorld.GetGameWorld().GetPropertyID() - 1
    if lineID < 0:
        return
    gameWorld = GameWorld.GetGameWorld()
    startTick = gameWorld.GetGameWorldDictByKey(FBDict_StartTick % lineID)
    lastSpeed = gameWorld.GetGameWorldDictByKey(FBDict_Speed % lineID)
    remainHP = gameWorld.GetGameWorldDictByKey(FBDict_RemainHP % lineID)
    curSpeed = int(min(1 + 0.08 * (playerCnt - 1), 1.8) * 1000)
    if not startTick:
        startTick = tick
        lastSpeed = curSpeed
        remainHP = __GetBossTotalHP()
    remainHP = max(0, int((remainHP - (tick - startTick) / 1000.0 * lastSpeed)))
    gameWorld.SetGameWorldDict(FBDict_StartTick % lineID, tick)
    gameWorld.SetGameWorldDict(FBDict_Speed % lineID, curSpeed)
    gameWorld.SetGameWorldDict(FBDict_RemainHP % lineID, remainHP)
    GameWorld.DebugLog('    curSpeed=%s, remainHP=%s, passTime=%s, lastSpeed=%s' % (curSpeed, remainHP, tick - startTick, lastSpeed))
    FBCommon.NotifyCopyMapPlayerFBHelp(tick, DoFBHelp, 0)
    return
def __GetBossTotalHP():
    lineID = GameWorld.GetGameWorld().GetPropertyID() - 1
    bossID = CurFBLineBOSSID(lineID)
    ipyData = IpyGameDataPY.GetIpyGameData('SealDemon', bossID)
    if not ipyData:
        return 0
    return ipyData.GetKillTime() * 1000
def GetBossRemainHP(lineID, tick):
    gameWorld = GameWorld.GetGameWorld()
    
    startTick = gameWorld.GetGameWorldDictByKey(FBDict_StartTick % lineID)
    lastSpeed = gameWorld.GetGameWorldDictByKey(FBDict_Speed % lineID)
    remainHP = gameWorld.GetGameWorldDictByKey(FBDict_RemainHP % lineID)
    if not startTick:
        startTick = tick
        remainHP = __GetBossTotalHP()
    else:
        remainHP = max(0, int((remainHP - (tick - startTick) / 1000.0 * lastSpeed)))
    return remainHP
def GetBossRemainHPPer(lineID, tick):
    remainHP = GetBossRemainHP(lineID, tick)
    totalHP = __GetBossTotalHP()
    if not totalHP:
        return 0
    return remainHP * 100 / totalHP
def GetBossRemainHPPer(copyMapID, funcLineID, tick):
    bossID = CurFBLineBOSSID(funcLineID)
    curBoss = GameWorld.FindNPCByNPCIDEx(copyMapID, bossID)
    if not curBoss:
        return 100
    return GameObj.GetHP(curBoss) * 100 / GameObj.GetMaxHP(curBoss)
def CurFBLineBOSSID(lineID= -1):
    #该分线刷的BOSSID
@@ -694,6 +421,14 @@
    bossID = ipyData.GetNPCID()
    return bossID
def GetSealDemonIpyData(lineID= -1):
    #该分线刷的BOSSID
    if lineID == -1:
        lineID = GameWorld.GetGameWorld().GetPropertyID() - 1
    if lineID == -1:
        return
    return IpyGameDataPY.GetIpyGameDataByCondition('SealDemon', {'LineID':lineID})
##玩家死亡.
# @param curPlayer:死亡的玩家 
# @param tick 时间戳
@@ -701,7 +436,6 @@
# @remarks 玩家主动离开副本.
def DoPlayerDead(curPlayer):
    return
#// B1 03 设置封魔坛多倍击杀 #tagCMSetFMTDouble
#
@@ -711,19 +445,5 @@
#    BYTE        IsDouble;        //是否双倍
#};
def SetFMTDouble(playerIndex, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(playerIndex)
    if GameWorld.GetMap().GetMapID() == ChConfig.Def_FBMapID_SealDemon:
        return
    if not curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_FMTOldDouble) and not PlayerVip.GetPrivilegeValue(curPlayer, ChConfig.VIPPrivilege_FMTDouble):
        return
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_FMTDouble, clientData.IsDouble)
    NotifyFMTDouble(curPlayer)
    return
def NotifyFMTDouble(curPlayer):
    packData = ChPyNetSendPack.tagMCFMTDoubleState()
    packData.IsDouble = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_FMTDouble)
    packData.OldDouble = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_FMTOldDouble)
    NetPackCommon.SendFakePack(curPlayer, packData)
    return