ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCHurtManager.py
@@ -30,6 +30,7 @@
import ShareDefine
import PlayerTeam
import NPCCommon
import FBCommon
import ChConfig
import time
@@ -44,6 +45,7 @@
        self.__hurtType = ChConfig.Def_NPCHurtTypePlayer # 均默认是玩家
        self.__hurtName = ""
        self.__hurtValue = 0
        self.__isFriend = 0
        return
    
    def GetValueID(self): return self.__hurtID
@@ -54,6 +56,8 @@
    def SetHurtName(self, hurtName): self.__hurtName = hurtName
    def GetHurtValue(self): return self.__hurtValue
    def SetHurtValue(self, hurtValue): self.__hurtValue = hurtValue
    def GetIsFriend(self): return self.__isFriend
    def SetIsFriend(self, isFriend): self.__isFriend = isFriend
    
class PlayerHurtList():
    ''' 伤血列表, 类似 IPY_GameObj.IPY_PlayerHurtList
@@ -71,6 +75,9 @@
        
        self.__hurtSortList = []
        self.__hurtDict = {} # 伤血列表实例字典,实际的NPC伤血列表实例,可能不是玩家{(hurtID, hurtType):HurtValueObj, ...}
        self.__assistAwardItemID = 0 # 协助奖励礼盒ID
        self.__assistAwardResult = {} # {playerID:{assistPlayerID:{协助玩家信息数据字典}, ...}}
        return
    
    def Clear(self):
@@ -87,11 +94,11 @@
    def OnDelete(self):
        # 删除伤血列表,NPC死亡调用
        
        cancelPlayerIDList = self.__noAssitPlayerIDDict.keys()
        if cancelPlayerIDList:
        noAssistPlayerIDList = self.__noAssitPlayerIDDict.keys()
        if noAssistPlayerIDList:
            mapID = GameWorld.GetMap().GetMapID()
            queryData = [mapID, self.lineID, self.npcID, self.objID, "OnBossDead", cancelPlayerIDList]
            PlayerAssist.QueryGameServer_PlayerAssist(0, "OnCancelBossRequestAssist", queryData)
            queryData = [mapID, self.lineID, self.npcID, self.objID, noAssistPlayerIDList, self.__assistAwardItemID, self.__assistAwardResult]
            PlayerAssist.QueryGameServer_PlayerAssist(0, "OnBossAssistOver", queryData)
            
        return
    
@@ -124,7 +131,7 @@
            hurtPlayer.SetHurtName(playerName)
        return hurtPlayer
    
    def AddAssistPlayer(self, assistPlayerID, assistPlayerName, tagPlayerID, tagPlayerName, tagTeamID):
    def AddAssistPlayer(self, assistPlayerID, assistPlayerName, isFriend, tagPlayerID, tagPlayerName, tagTeamID):
        ## 添加助战玩家
        # @param assistPlayerID: 协助玩家ID
        # @param tagPlayerID: 目标玩家ID,即发布协助的玩家ID
@@ -138,8 +145,8 @@
                             % (assistPlayerID, tagPlayerID), self.npcID, self.lineID)
            return
        
        GameWorld.DebugLog("新增协助玩家: assistPlayerID=%s,tagPlayerID=%s,tagTeamID=%s"
                           % (assistPlayerID, tagPlayerID, tagTeamID), self.npcID, self.lineID)
        GameWorld.DebugLog("新增协助玩家: assistPlayerID=%s,tagPlayerID=%s,tagTeamID=%s,isFriend=%s"
                           % (assistPlayerID, tagPlayerID, tagTeamID, isFriend), self.npcID, self.lineID)
        
        if assistPlayerID in self.__noAssitPlayerIDDict:
            GameWorld.DebugLog("原来为常规玩家,需要先删除!", self.npcID, self.lineID)
@@ -150,6 +157,8 @@
            assistPlayerIDList.append(assistPlayerID)
        self.__assistPlayerIDDict[assistPlayerID] = tagPlayerID
        
        assistHurtPlayer = self.__GetHurtPlayer(assistPlayerID, assistPlayerName)
        assistHurtPlayer.SetIsFriend(isFriend)
        GameWorld.DebugLog("    self.__noAssitPlayerIDDict=%s" % (self.__noAssitPlayerIDDict), self.npcID, self.lineID)
        GameWorld.DebugLog("    self.__assistPlayerIDDict=%s" % (self.__assistPlayerIDDict), self.npcID, self.lineID)
        return
@@ -177,9 +186,8 @@
            # 地图删除的同步GameServer
            if isMapServerDel:
                mapID = GameWorld.GetMap().GetMapID()
                cancelPlayerIDList = [playerID]
                queryData = [mapID, self.lineID, self.npcID, self.objID, reason, cancelPlayerIDList]
                PlayerAssist.QueryGameServer_PlayerAssist(0, "OnCancelBossRequestAssist", queryData)
                queryData = [mapID, self.lineID, self.npcID, self.objID, reason]
                PlayerAssist.QueryGameServer_PlayerAssist(playerID, "OnCancelBossRequestAssist", queryData)
                
        # 协助玩家
        elif playerID in self.__assistPlayerIDDict:
@@ -258,6 +266,29 @@
    def IsAssistPlayer(self, playerID):
        ## 是否助战伤血玩家
        return playerID in self.__assistPlayerIDDict
    def IsAssistRelation(self, playerID, tagPlayerID):
        ## 玩家双方是否存在协助关系
        # A协助B
        if playerID in self.__assistPlayerIDDict:
            if self.__assistPlayerIDDict[playerID] == tagPlayerID:
                #GameWorld.DebugLog("%s 协助  %s" % (playerID, tagPlayerID))
                return True
        # B协助A
        elif tagPlayerID in self.__assistPlayerIDDict:
            if self.__assistPlayerIDDict[tagPlayerID] == playerID:
                #GameWorld.DebugLog("%s 协助  %s" % (tagPlayerID, playerID))
                return True
        # 协助同一个玩家
        for assPlayerIDList in self.__noAssitPlayerIDDict.values():
            if playerID in assPlayerIDList and tagPlayerID in assPlayerIDList:
                #GameWorld.DebugLog("协助同一玩家! %s %s" % (playerID, tagPlayerID))
                return True
        return False
    
    def OnHurtPlayerEnterTeam(self, playerID, playerName, befTeamID, newTeam, tick):
        ''' 伤血玩家加入队伍
@@ -423,12 +454,10 @@
        # @return: atkPlayer, hurtID, hurtType
        
        curNPC = self.curNPC
        if not self.__hurtDict:
            return
        
        if not isDead:
            if refreshInterval and tick - curNPC.GetDictByKey(ChConfig.Def_NPC_Dict_LastRefreshHurtTick) < refreshInterval:
                return self.__GetAtkObjByHurtList()
                return self.__GetAtkObjByHurtList(isDead)
            
        curNPC.SetDict(ChConfig.Def_NPC_Dict_LastRefreshHurtTick, tick)
        
@@ -464,7 +493,7 @@
            
        isInHurt = self.__hurtSortList != []
        curNPC.SetDict(ChConfig.Def_NPC_Dict_InHurtProtect, isInHurt)
        return self.__GetAtkObjByHurtList()
        return self.__GetAtkObjByHurtList(isDead)
    
    def __UnAssistPlayerHurtValidLogic(self, playerID, refreshPoint, tick):
        ## 非协助玩家伤血有效性检查逻辑
@@ -580,7 +609,7 @@
                
        return
    
    def __GetAtkObjByHurtList(self):
    def __GetAtkObjByHurtList(self, isDead):
        '''第一个可攻击的最大伤血对象,也是实际的归属者或队伍
        因为玩家伤血掉线、死亡有一定时间的保留机制,故最大伤血不一定是可攻击目标(归属者)
        注意: 该规则必须与最终算归属的规则一致,不然可能导致归属错乱
@@ -590,7 +619,7 @@
        atkPlayer, atkHurtType, atkHurtID = None, 0, 0
        curNPC = self.curNPC
        refreshPoint = curNPC.GetRefreshPosAt(curNPC.GetCurRefreshPointIndex())
        for hurtObj in self.__hurtSortList:
        for rank, hurtObj in enumerate(self.__hurtSortList, 1):
            
            hurtID = hurtObj.GetValueID()
            hurtType = hurtObj.GetValueType()
@@ -613,6 +642,7 @@
            else:
                continue
            
            playerDisableReason = {}
            maxHurtValue = 0
            for playerID in playerIDList:
                
@@ -621,15 +651,19 @@
                    continue
                
                if player.GetHP() <= 0 or player.GetPlayerAction() == IPY_GameWorld.paDie:
                    playerDisableReason[playerID] = "dead"
                    continue
                
                if not player.GetVisible() or player.GetSightLevel() != curNPC.GetSightLevel():
                    playerDisableReason[playerID] = "no visible or sightLevel different"
                    continue
                
                if not self.__GetIsInRefreshPoint(player.GetPosX(), player.GetPosY(), refreshPoint):
                    playerDisableReason[playerID] = "not in boss area"
                    continue
                
                if playerID not in self.__hurtPlayerDict:
                    playerDisableReason[playerID] = "no hurt"
                    continue
                hurtPlayer = self.__hurtPlayerDict[playerID]
                hurtValue = hurtPlayer.GetHurtValue()                
@@ -640,6 +674,9 @@
            if maxHurtValue:
                return atkPlayer, atkHurtType, atkHurtID
            
            if rank == 1 and isDead:
                GameWorld.Log("boss死亡时,第一名团队没有归属权! playerDisableReason=%s" % playerDisableReason)
        return atkPlayer, atkHurtType, atkHurtID
    
    def __GetIsInRefreshPoint(self, curPosX, curPosY, refreshPoint):
@@ -710,34 +747,80 @@
        ''' 执行协助奖励逻辑
        '''
        
        liheItemID = 2244 # 感谢礼盒物品ID,暂山寨,感谢系统再修改
        self.__assistAwardResult = {}
        
        liheItemID, assistMoney = 0, 0
        mapAssistGiftDict = IpyGameDataPY.GetFuncEvalCfg("AssistAward", 2, {})
        mapID = FBCommon.GetRecordMapID(GameWorld.GetMap().GetMapID())
        if str(mapID) in mapAssistGiftDict:
            liheItemID, assistMoney = mapAssistGiftDict[str(mapID)]
        else:
            killBossCntLimitDict = IpyGameDataPY.GetFuncEvalCfg('KillBossCntLimit')
            index = GameWorld.GetDictValueByKey(killBossCntLimitDict, self.npcID)
            if index == None:
                return
            bossAssistGiftDict = IpyGameDataPY.GetFuncEvalCfg("AssistAward", 1, {})
            if str(index) not in bossAssistGiftDict:
                GameWorld.DebugLog("该boss没有协助额外奖励!index=%s" % index, self.npcID)
                return
            liheItemID, assistMoney = bossAssistGiftDict[str(index)]
        if not liheItemID or not assistMoney:
            GameWorld.DebugLog("该副本或boss没有协助额外奖励!mapID=%s" % (mapID), self.npcID)
            return
        self.__assistAwardItemID = liheItemID
        fbType = GameWorld.GetMap().GetMapFBTypeByMapID(mapID)
        GameWorld.DebugLog("执行协助奖励逻辑", self.npcID, self.lineID)
        copyPlayerManager = GameWorld.GetMapCopyPlayerManager()
        for playerID, assistPlayerIDList in self.__noAssitPlayerIDDict.items():
            if not assistPlayerIDList:
                GameWorld.DebugLog("发布方没有发布协助,不给奖励: playerID=%s" % playerID, self.npcID, self.lineID)
                GameWorld.DebugLog("发布方没有发布协助,不处理: playerID=%s" % playerID, self.npcID, self.lineID)
                continue
            
            player = copyPlayerManager.FindPlayerByID(playerID)
            if player:
                GameWorld.DebugLog("发布方给感谢礼盒奖励: playerID=%s" % playerID, self.npcID, self.lineID)
                ItemControler.GivePlayerItemOrMail(player, [[liheItemID, 1, 0]])
            else:
                GameWorld.DebugLog("发布方离线或不在本地图,不给感谢礼盒奖励: playerID=%s" % playerID, self.npcID, self.lineID)
            noAssistPlayer = copyPlayerManager.FindPlayerByID(playerID)
            assistAwardPlayerDict = {}
            # 即使发布方不在线,协助方完成后也可获得活跃令奖励,只是不一定获得礼盒感谢奖励(礼盒感谢奖励需双方都在线)
            for assistPlayerID in assistPlayerIDList:
                assistHurtPlayer = self.__GetHurtPlayer(assistPlayerID)
                if not assistHurtPlayer.GetHurtValue():
                    GameWorld.DebugLog("协助方没有输出,不给奖励: assistPlayerID=%s" % assistPlayerID, self.npcID, self.lineID)
                    continue
                assPlayer = copyPlayerManager.FindPlayerByID(assistPlayerID)
                if not assPlayer:
                assistPlayer = copyPlayerManager.FindPlayerByID(assistPlayerID)
                if not assistPlayer:
                    GameWorld.DebugLog("协助方离线或不在本地图,不给活跃令奖励: assistPlayerID=%s" % assistPlayerID, self.npcID, self.lineID)
                    continue
                GameWorld.DebugLog("协助方给活跃令奖励: assistPlayerID=%s" % assistPlayerID, self.npcID, self.lineID)
                PlayerControl.GiveMoney(assPlayer, ShareDefine.TYPE_Price_FamilyActivity, 35)
                isFriend = assistHurtPlayer.GetIsFriend()
                assistMoneyType = ShareDefine.TYPE_Price_FamilyActivity
                addAssistMoney = PlayerAssist.AddTodayAssistMoney(assistPlayer, assistMoneyType, assistMoney, isFriend)
                GameWorld.DebugLog("协助方给活跃令奖励: assistPlayerID=%s,assistMoney=%s,isFriend=%s,addAssistMoney=%s"
                                   % (assistPlayerID, assistMoney, isFriend, addAssistMoney), self.npcID, self.lineID)
                if fbType == IPY_GameWorld.fbtNull:
                    PlayerControl.NotifyCode(assistPlayer, "AssistSuccess")
                else:
                    overDict = {FBCommon.Over_isAssist:1, FBCommon.Over_money:FBCommon.GetJsonMoneyList({assistMoneyType:addAssistMoney}),
                                FBCommon.Over_itemInfo:[]}
                    FBCommon.NotifyFBOver(assistPlayer, mapID, PlayerControl.GetFBFuncLineID(assistPlayer), 1, overDict)
                    assistPlayer.Sync_TimeTick(IPY_GameWorld.tttLeaveMap, 0, 10000, True)
                if noAssistPlayer:
                    todayGiftCount = assistPlayer.NomalDictGetProperty(ChConfig.Def_PDict_GetThanksGiftCount % liheItemID)
                    assistAwardPlayerDict[assistPlayerID] = {"PlayerName":assistPlayer.GetPlayerName(), "Job":assistPlayer.GetJob(),
                                                             "LV":assistPlayer.GetLV(), "RealmLV":assistPlayer.GetOfficialRank(),
                                                             "TodayGiftCount":todayGiftCount}
                    notifyParam = [assistPlayer.GetPlayerName(), noAssistPlayer.GetPlayerName(), mapID, self.curNPC.GetLV(), self.npcID]
                    PlayerControl.FamilyNotify(assistPlayer.GetFamilyID(), "AssistBossFinish", notifyParam)
            if not noAssistPlayer or not assistAwardPlayerDict:
                GameWorld.DebugLog("发布方离线或无有效协助玩家在线,不给感谢礼盒奖励: playerID=%s" % playerID, self.npcID, self.lineID)
                continue
            GameWorld.DebugLog("发布方给感谢礼盒奖励: playerID=%s" % playerID, self.npcID, self.lineID)
            ItemControler.GivePlayerItemOrMail(noAssistPlayer, [[liheItemID, 1, 0]])
            self.__assistAwardResult[playerID] = assistAwardPlayerDict
        return
    
    def __CmpHurtValue(self, hurtObjA, hurtObjB):
@@ -778,13 +861,15 @@
        bossHurtInfoPack.HurtValueList = hurtValueList
        bossHurtInfoPack.HurtCount = len(hurtValueList)
        
        curNPC = self.curNPC
        assistHurtValueListDict = {}
        copyPlayerManager = GameWorld.GetMapCopyPlayerManager()
        for playerID in syncPlayerIDList:
            player = copyPlayerManager.FindPlayerByID(playerID)
            if not player:
                continue
            if not player.CanSeeOther(curNPC):
                continue
            if playerID in self.__noAssitPlayerIDDict:
                assTagPlayerID = playerID
            elif playerID in self.__assistPlayerIDDict:
@@ -825,9 +910,17 @@
def OnPlayerLeaveMap(curPlayer):
    ## 玩家离开地图处理
    
    mapID = curPlayer.GetMapID()
    mapType = GameWorld.GetMap().GetMapFBType()
    changeMapID = curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_ChangeMapID)
    changeLineID = curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_ChangeLineID)
    playerID = curPlayer.GetPlayerID()
    for hurtList in PyGameData.g_npcHurtDict.values():
        if hurtList.IsNoAssistPlayer(playerID) or hurtList.IsAssistPlayer(playerID):
            if mapType == IPY_GameWorld.fbtNull and mapID == changeMapID and changeLineID == hurtList.lineID:
                #GameWorld.DebugLog("玩家同地图切线,当前伤血lineID为目标线路,不清伤血!changeLineID=%s" % changeLineID, playerID)
                continue
            GameWorld.DebugLog("玩家离开地图, 删除boss伤血玩家!npcID=%s" % (hurtList.npcID), playerID)
            hurtList.DelHurtPlayer(playerID, "LeaveMap")
            break
@@ -863,11 +956,19 @@
    defendHurtList.Clear()
    return
def GetBossLineID(npcID):
    sealDemonIpyData = IpyGameDataPY.GetIpyGameDataNotLog("SealDemon", npcID)
    if sealDemonIpyData:
        lineID = sealDemonIpyData.GetLineID()
    else:
        lineID = GameWorld.GetGameWorld().GetLineID()
    return lineID
def DeletePlayerHurtList(curNPC):
    ## 删除伤血列表
    lineID = GameWorld.GetGameWorld().GetLineID()
    objID = curNPC.GetID()
    npcID = curNPC.GetNPCID()
    lineID = GetBossLineID(npcID)
    key = (lineID, objID, npcID)
    if key in PyGameData.g_npcHurtDict:
        hurtList =PyGameData.g_npcHurtDict.pop(key)
@@ -877,9 +978,9 @@
def GetPlayerHurtList(curNPC):
    ## 获取伤血列表,可能为None
    lineID = GameWorld.GetGameWorld().GetLineID()
    objID = curNPC.GetID()
    npcID = curNPC.GetNPCID()
    lineID = GetBossLineID(npcID)
    return GetPlayerHurtListEx(lineID, objID, npcID)
def GetPlayerHurtListEx(lineID, objID, npcID):
    ## 获取伤血列表,可能为None
@@ -888,13 +989,19 @@
    if key not in PyGameData.g_npcHurtDict:
        ## 只统计最大伤血归属的boss
        npcData = GameWorld.GetGameData().FindNPCDataByID(npcID)
        if not npcData:
        if not npcData or not ChConfig.IsGameBoss(npcData):
            return defendHurtList
        if not npcData.GetIsBoss() or NPCCommon.GetDropOwnerType(npcData) != ChConfig.DropOwnerType_MaxHurt:
            return defendHurtList
        if NPCCommon.GetDropOwnerType(npcData) != ChConfig.DropOwnerType_MaxHurt:
            mapID = GameWorld.GetMap().GetMapID()
            if mapID not in [ChConfig.Def_FBMapID_SealDemon]:
                return defendHurtList
        defendHurtList = PlayerHurtList(lineID, objID, npcID)
        PyGameData.g_npcHurtDict[key] = defendHurtList
    defendHurtList = PyGameData.g_npcHurtDict[key]
    if not defendHurtList.curNPC:
        hurtList = PyGameData.g_npcHurtDict.pop(key)
        hurtList.OnDelete()
        return
    return defendHurtList
def OnNPCHurtPlayerEnterTeam(playerID, playerName, befTeamID, newTeam, tick):
@@ -939,6 +1046,8 @@
    return True
def RefreshHurtList(curNPC, tick, refreshInterval=3000, isDead=False):
    ## 刷新伤血列表
    # @return: atkPlayer, ownerType, ownerID
    defendHurtList = GetPlayerHurtList(curNPC)
    if not defendHurtList:
        return
@@ -951,3 +1060,27 @@
        return False
    return defendHurtList.IsAssistPlayer(playerID)
def IsAssistRelation(curPlayer, tagPlayer):
    ## 双方是否协助关系
    playerID = curPlayer.GetPlayerID()
    tagPlayerID = tagPlayer.GetPlayerID()
    for hurtList in PyGameData.g_npcHurtDict.values():
        if hurtList.IsAssistRelation(playerID, tagPlayerID):
            return True
    return False
def CheckPlayerCanAttackFBNPC(curPlayer, curNPC, mapID, isNotify=False):
    ## 检查玩家可否攻击有副本次数的NPC
    enterCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_EnterFbCntDay % mapID)
    if enterCnt < FBCommon.GetEnterFBMaxCnt(curPlayer, mapID):
        return True
    # 没有次数的,如果是助战玩家也可攻击
    if IsAssistPlayer(curPlayer.GetPlayerID(), curNPC):
        return True
    if isNotify:
        PlayerControl.NotifyCode(curPlayer, "AttackFBBossLimit")
    return False