From ae8371301b81bfae8de95d2ecbe52a50df8c7f06 Mon Sep 17 00:00:00 2001
From: hxp <ale99527@vip.qq.com>
Date: 星期三, 06 十二月 2023 10:04:12 +0800
Subject: [PATCH] 9811 【BT9】【后端】逐鹿万界

---
 ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py                                                              |   26 +
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py                                           |    8 
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py                                                         |    6 
 ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerEventCounter.py                                                  |    3 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCAI/AICommon.py                                    |    6 
 ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmMsg.py                                               |    4 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py                                         |   32 +
 ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py                                                                   |    9 
 ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossActionControl.py                                          |   25 +
 PySysDB/PySysDBPY.h                                                                                                          |   12 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_CrossFamilyFlagwar.py |  969 ++++++++++++++++++++++++++++++++++++++++++
 ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossFamilyFlagwar.py                                          |  207 +++++++++
 ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py                                                                |    8 
 PySysDB/PySysDBG.h                                                                                                           |   10 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py                                              |    7 
 15 files changed, 1,325 insertions(+), 7 deletions(-)

diff --git a/PySysDB/PySysDBG.h b/PySysDB/PySysDBG.h
index 85968ac..76663f5 100644
--- a/PySysDB/PySysDBG.h
+++ b/PySysDB/PySysDBG.h
@@ -925,6 +925,16 @@
 	BYTE		_CopyMapID;	//虚拟线路ID
 };
 
+//跨服分区地图逐鹿万界
+
+struct tagCrossFamilyFlagwarZoneMap
+{
+	BYTE		ZoneID;	//分区ID
+	DWORD		_MapID;	//场景地图ID
+	DWORD		_DataMapID;	//数据地图ID
+	BYTE		_CopyMapID;	//虚拟线路ID
+};
+
 //周狂欢活动时间表
 
 struct tagActWeekParty
diff --git a/PySysDB/PySysDBPY.h b/PySysDB/PySysDBPY.h
index 17d2ce4..3a625fa 100644
--- a/PySysDB/PySysDBPY.h
+++ b/PySysDB/PySysDBPY.h
@@ -2250,6 +2250,18 @@
 	WORD		PosY;	//坐标Y
 };
 
+//跨服分区地图逐鹿万界
+
+struct tagCrossFamilyFlagwarZoneMap
+{
+	BYTE		ZoneID;	//分区ID
+	DWORD		_MapID;	//场景地图ID
+	DWORD		_DataMapID;	//数据地图ID
+	BYTE		_CopyMapID;	//虚拟线路ID
+	WORD		PosX;	//坐标X
+	WORD		PosY;	//坐标Y
+};
+
 //聚魂表
 
 struct tagGatherSoul
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py b/ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py
index f2fe0b7..484f2b5 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py
@@ -707,6 +707,8 @@
 Def_FBMapID_CrossGrasslandXian = 32050
 #跨服战场
 Def_FBMapID_CrossBattlefield = 32060
+#跨服仙盟夺旗战/逐鹿万界
+Def_FBMapID_CrossFamilyFlagwar = 32090
 #情缘副本
 Def_FBMapID_Love = 31300
 
@@ -728,7 +730,14 @@
 #跨服分区对应地图配置表名 - 仅适用于固定地图及虚拟分线的跨服玩法
 Def_CrossZoneMapTableName = {Def_FBMapID_CrossPenglai:"CrossPenglaiZoneMap",
                              Def_FBMapID_CrossDemonLand:"CrossDemonLandZoneMap",
+                             Def_FBMapID_CrossFamilyFlagwar:"CrossFamilyFlagwarZoneMap",
                              }
+
+#跨服日常活动对应需要直接开启副本线路地图的,仅适用于固定分区的日常,不包含动态分配线路及有特定分配规则的地图
+Def_CrossDailyMap = {
+                     ShareDefine.CrossDailyActionID_FamilyWarFlag:Def_FBMapID_CrossFamilyFlagwar,
+                     }
+
 #需要动态分配线路的跨服地图
 Def_CrossDynamicLineMap = [Def_FBMapID_CrossDemonKing, Def_FBMapID_CrossGrasslandLing, Def_FBMapID_CrossGrasslandXian]
 
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossActionControl.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossActionControl.py
index c402b90..534b2d2 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossActionControl.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossActionControl.py
@@ -24,6 +24,7 @@
 import CrossActCTGBillboard
 import CrossRealmMsg
 import PyGameData
+import PlayerFB
 import ChConfig
 
 import datetime
@@ -838,6 +839,10 @@
             continue
         
         if state:
+            if dailyActionID in ChConfig.Def_CrossDailyMap:
+                # 开启对应日常地图分区线路
+                __openCrossDailyMap(ChConfig.Def_CrossDailyMap[dailyActionID])
+                
             if dailyActionID == ShareDefine.CrossDailyActionID_YaomoBoss:
                 GameWorld.SendMapServerMsgEx(ShareDefine.Def_Notify_WorldKey_ActionBossRebornSign % dailyActionID, int(time.time()))
                 
@@ -855,6 +860,26 @@
         
     return
 
+def __openCrossDailyMap(mapID):
+    if mapID not in ChConfig.Def_CrossZoneMapTableName:
+        return
+    zoneTypeName = ChConfig.Def_CrossZoneMapTableName[mapID]
+    ipyDataMgr = IpyGameDataPY.IPY_Data()
+    if zoneTypeName and hasattr(ipyDataMgr, "Get%sCount" % zoneTypeName):
+        realMapInfo = {}
+        for index in range(getattr(ipyDataMgr, "Get%sCount" % zoneTypeName)()):
+            ipyData = getattr(ipyDataMgr, "Get%sByIndex" % zoneTypeName)(index)
+            zoneID = ipyData.GetZoneID()
+            realMapID = ipyData.GetMapID()
+            copyMapID = ipyData.GetCopyMapID()
+            if realMapID not in realMapInfo:
+                realMapInfo[realMapID] = []
+            copyPropertyList = realMapInfo[realMapID]
+            copyPropertyList.append([copyMapID, zoneID])
+        for realMapID, copyPropertyList in realMapInfo.items():
+            PlayerFB.SendMapOpenFBEx(realMapID, copyPropertyList)
+    return
+
 def SendMapServerCrossDailyActionState():
     # 地图启动成功时通知本日进行中的日常活动状态
     
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossFamilyFlagwar.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossFamilyFlagwar.py
new file mode 100644
index 0000000..4babf90
--- /dev/null
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossFamilyFlagwar.py
@@ -0,0 +1,207 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package CrossFamilyFlagwar
+#
+# @todo:跨服仙盟夺旗战/逐鹿万界
+# @author hxp
+# @date 2023-04-25
+# @version 1.0
+#
+# 详细描述: 跨服仙盟夺旗战
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2023-04-25 15:30"""
+#-------------------------------------------------------------------------------
+
+import GameWorld
+import CrossRealmMsg
+import IpyGameDataPY
+import CrossBillboard
+import PlayerCompensation
+import CrossRealmPlayer
+import PlayerControl
+import PyDataManager
+import ShareDefine
+import ChConfig
+
+def DoOnWeekEx():
+    
+    if not GameWorld.IsCrossServer():
+        return
+    
+    billboardMgr = PyDataManager.GetCrossBillboardManager()
+    groupList = billboardMgr.GetBillboardGroupList(ShareDefine.Def_CBT_FamilyFlagwarWeek)
+    for billboardType, groupValue1, groupValue2 in groupList:
+        billboardObj = billboardMgr.GetCrossBillboard(billboardType, groupValue1, groupValue2)
+        zoneID = groupValue1
+        zoneIpyData = CrossRealmPlayer.GetCrossZoneIpyDataByZoneID(ChConfig.Def_FBMapID_CrossFamilyFlagwar, zoneID)
+        serverGroupIDList = zoneIpyData.GetServerGroupIDList() if zoneIpyData else []
+        
+        syncFamilyList = []
+        for index in range(billboardObj.GetCount()):
+            billboardData = billboardObj.At(index)
+            familyID = billboardData.ID
+            familyRank = index + 1
+            syncFamilyList.append([familyRank, familyID])
+            
+        billboardObj.ClearData()
+        
+        # 通知子服
+        sendMsg = {"zoneID":zoneID, "syncFamilyList":syncFamilyList, "isWeek":True}
+        CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_FamilyFlagwarOver, sendMsg, serverGroupIDList)
+        
+    return
+
+def MapServer_CrossFamilyFlagwarOver(msgList):
+    ## 地图结算
+    
+    zoneID, battleFamilyList = msgList
+    GameWorld.Log("跨服仙盟夺旗战/逐鹿万界地图同步结果: zoneID=%s" % zoneID, zoneID)
+    
+    billboardMgr = PyDataManager.GetCrossBillboardManager()
+    groupValue1 = zoneID
+    billboardObj = billboardMgr.GetCrossBillboard(ShareDefine.Def_CBT_FamilyFlagwar, groupValue1)
+    billboardObj.ClearData() # 单场榜每次更新前重置
+    
+    billboardObjWeek = billboardMgr.GetCrossBillboard(ShareDefine.Def_CBT_FamilyFlagwarWeek, groupValue1)
+    
+    syncFamilyList = []
+    championFamilyName = ""
+    for familyInfo in battleFamilyList:
+        familyRank, familyID, familyName, familyScore, battlePlayerList = familyInfo
+        
+        if familyRank == 1:
+            championFamilyName = familyName
+            
+        billboardDataWeek = billboardObjWeek.FindByID(familyID)
+        weekScore = billboardDataWeek.CmpValue if billboardDataWeek else 0
+        weekScore += familyScore
+        
+        dataID, name1, name2 = familyID, familyName, ""
+        type2, value1, value2 = 0, 0, 0
+        
+        # 周总榜
+        cmpValue = weekScore
+        CrossBillboard.UpdCrossBillboard(ShareDefine.Def_CBT_FamilyFlagwarWeek, groupValue1, dataID, name1, name2, type2, value1, value2, cmpValue)
+        
+        # 单场榜
+        cmpValue = familyScore
+        CrossBillboard.UpdCrossBillboard(ShareDefine.Def_CBT_FamilyFlagwar, groupValue1, dataID, name1, name2, type2, value1, value2, cmpValue)
+        
+        syncFamilyList.append([familyRank, familyID, familyScore, battlePlayerList])
+        
+    billboardObj.SortData()
+    billboardObjWeek.SortData()
+    
+    zoneIpyData = CrossRealmPlayer.GetCrossZoneIpyDataByZoneID(ChConfig.Def_FBMapID_CrossFamilyFlagwar, zoneID)
+    serverGroupIDList = zoneIpyData.GetServerGroupIDList() if zoneIpyData else []
+    
+    # 通知子服
+    sendMsg = {"zoneID":zoneID, "syncFamilyList":syncFamilyList}
+    CrossRealmMsg.SendMsgToClientServer(ShareDefine.CrossServerMsg_FamilyFlagwarOver, sendMsg, serverGroupIDList)
+    
+    # 结算广播
+    if championFamilyName:
+        PlayerControl.WorldNotifyCross(serverGroupIDList, 0, "CrossFamilyFlagwarFlagOver", [championFamilyName])
+        
+    return
+
+def CrossServerMsg_FamilyFlagwarOver(msgData):
+    ## 子服收到 结算结果同步
+    
+    if "isWeek" in msgData:
+        __doFamilyFlagwarOverWeek(msgData)
+        return
+    
+    #zoneID = msgData["zoneID"]
+    syncFamilyList = msgData["syncFamilyList"]
+    
+    playerScoreAwardDict = IpyGameDataPY.GetFuncEvalCfg("CrossFamilyFlagwarAward", 1, {}) # 单场个人累计积分对应奖励物品列表 {"积分":[[物品ID,个数,是否拍品], ...], ...} 
+    playerScoreIntAwardDict = {int(k):v for k, v in playerScoreAwardDict.items()}
+    
+    playerHurtAwardDict = IpyGameDataPY.GetFuncEvalCfg("CrossFamilyFlagwarAward", 2, {}) # 单场个人累计伤害对应奖励物品列表 {"伤害":[[物品ID,个数,是否拍品], ...], ...}
+    playerHurtIntAwardDict = {int(k):v for k, v in playerHurtAwardDict.items()}
+    
+    # 单场仙盟积分排名奖励列表 {"名次":[[[参与奖物品ID,个数,是否拍品], ...], [仙盟奖物品ID,个数,是否拍品], ...]], ...}
+    # 未参与的玩家只有仙盟奖励,没有参与奖
+    familyRankAwardDict = IpyGameDataPY.GetFuncEvalCfg("CrossFamilyFlagwarAward", 3, {})
+    familyRankIntAwardDict = {int(k):v for k, v in familyRankAwardDict.items()}
+    
+    for familyInfo in syncFamilyList:
+        familyRank, familyID, familyScore, battlePlayerList = familyInfo
+        family = GameWorld.GetFamilyManager().FindFamily(familyID)
+        if not family:
+            ## 找不到的不处理,可能不是本服的仙盟
+            continue
+        
+        # 所有成员
+        memPlayerIDList = []
+        for i in range(family.GetCount()):
+            member = family.GetAt(i)
+            memPlayerIDList.append(member.GetPlayerID())
+            
+        joinPlayerIDList = []
+        for playerInfo in battlePlayerList:
+            playerID, score, hurtTotal = playerInfo
+            joinPlayerIDList.append(playerID)
+            
+            # 个人累计积分奖励
+            for scoreNeed, itemList in playerScoreIntAwardDict.items():
+                if score < scoreNeed:
+                    continue
+                PlayerCompensation.SendMailByKey("CrossFamilyFlagwarPlayerScore", [playerID], itemList, [scoreNeed])
+                
+            # 个人累计伤害奖励
+            for hurtNeed, itemList in playerHurtIntAwardDict.items():
+                if hurtTotal < hurtNeed:
+                    continue
+                PlayerCompensation.SendMailByKey("CrossFamilyFlagwarPlayerHurt", [playerID], itemList, [hurtNeed])
+                
+        if familyScore:
+            pass
+        
+        rankAwardList = GameWorld.GetOrderValueByDict(familyRankIntAwardDict, familyRank, False)
+        if rankAwardList and len(rankAwardList) == 2:
+            # 参与奖励
+            addItemList = rankAwardList[0]
+            paramList = [familyRank]
+            PlayerCompensation.SendMailByKey("CrossFamilyFlagwarRankJoin", joinPlayerIDList, addItemList, paramList)
+            
+            # 全员奖励
+            addItemList = rankAwardList[1]
+            paramList = [familyRank]
+            PlayerCompensation.SendMailByKey("CrossFamilyFlagwarRank", memPlayerIDList, addItemList, paramList)
+        else:
+            GameWorld.ErrLog("逐鹿万界找不到仙盟对应名次奖励! familyRank=%s,familyID=%s" % (familyRank, familyID))
+            
+    return
+
+def __doFamilyFlagwarOverWeek(msgData):
+    
+    syncFamilyList = msgData["syncFamilyList"]
+    
+    weekRankAwardDict = IpyGameDataPY.GetFuncEvalCfg("CrossFamilyFlagwarAward", 4, {}) # 每周仙盟累计积分排名奖励列表 {"名次":[[物品ID,个数,是否拍品], ...], ...}
+    weekRankIntAwardDict = {int(k):v for k, v in weekRankAwardDict.items()}
+    
+    for familyInfo in syncFamilyList:
+        familyRank, familyID = familyInfo
+        family = GameWorld.GetFamilyManager().FindFamily(familyID)
+        if not family:
+            ## 找不到的不处理,可能不是本服的仙盟
+            continue
+        
+        # 所有成员
+        memPlayerIDList = []
+        for i in range(family.GetCount()):
+            member = family.GetAt(i)
+            memPlayerIDList.append(member.GetPlayerID())
+            
+        awardItemList = GameWorld.GetOrderValueByDict(weekRankIntAwardDict, familyRank, False)
+        if awardItemList:
+            paramList = [familyRank]
+            PlayerCompensation.SendMailByKey("CrossFamilyFlagwarRankWeek", memPlayerIDList, awardItemList, paramList)
+            
+    return
+
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmMsg.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmMsg.py
index 20b9244..3295f48 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmMsg.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/CrossRealmMsg.py
@@ -25,6 +25,7 @@
 import PlayerCompensation
 import CrossActionControl
 import CrossActAllRecharge
+import CrossFamilyFlagwar
 import CrossChampionship
 import CrossBattlefield
 import CrossBillboard
@@ -351,6 +352,9 @@
         elif msgType == ShareDefine.CrossServerMsg_BattlefieldOver:
             CrossBattlefield.CrossServerMsg_BattlefieldOver(msgData)
             
+        elif msgType == ShareDefine.CrossServerMsg_FamilyFlagwarOver:
+            CrossFamilyFlagwar.CrossServerMsg_FamilyFlagwarOver(msgData)
+            
         elif msgType == ShareDefine.CrossServerMsg_ChampionshipState:
             CrossChampionship.CrossServerMsg_ChampionshipState(msgData)
             
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py b/ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py
index 74c8c16..fbf5d9e 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py
@@ -750,6 +750,13 @@
                         ("BYTE", "CopyMapID", 1),
                         ),
 
+                "CrossFamilyFlagwarZoneMap":(
+                        ("BYTE", "ZoneID", 0),
+                        ("DWORD", "MapID", 1),
+                        ("DWORD", "DataMapID", 1),
+                        ("BYTE", "CopyMapID", 1),
+                        ),
+
                 "ActWeekParty":(
                         ("DWORD", "CfgID", 1),
                         ("char", "ActMark", 0),
@@ -2447,6 +2454,21 @@
     def GetDataMapID(self): return self.DataMapID # 数据地图ID
     def GetCopyMapID(self): return self.CopyMapID # 虚拟线路ID
 
+# 跨服分区地图逐鹿万界
+class IPY_CrossFamilyFlagwarZoneMap():
+    
+    def __init__(self):
+        self.ZoneID = 0
+        self.MapID = 0
+        self.DataMapID = 0
+        self.CopyMapID = 0
+        return
+        
+    def GetZoneID(self): return self.ZoneID # 分区ID
+    def GetMapID(self): return self.MapID # 场景地图ID
+    def GetDataMapID(self): return self.DataMapID # 数据地图ID
+    def GetCopyMapID(self): return self.CopyMapID # 虚拟线路ID
+
 # 周狂欢活动时间表
 class IPY_ActWeekParty():
     
@@ -3007,6 +3029,8 @@
         self.ipyCrossPenglaiZoneMapLen = len(self.ipyCrossPenglaiZoneMapCache)
         self.ipyCrossDemonLandZoneMapCache = self.__LoadFileData("CrossDemonLandZoneMap", IPY_CrossDemonLandZoneMap)
         self.ipyCrossDemonLandZoneMapLen = len(self.ipyCrossDemonLandZoneMapCache)
+        self.ipyCrossFamilyFlagwarZoneMapCache = self.__LoadFileData("CrossFamilyFlagwarZoneMap", IPY_CrossFamilyFlagwarZoneMap)
+        self.ipyCrossFamilyFlagwarZoneMapLen = len(self.ipyCrossFamilyFlagwarZoneMapCache)
         self.ipyActWeekPartyCache = self.__LoadFileData("ActWeekParty", IPY_ActWeekParty)
         self.ipyActWeekPartyLen = len(self.ipyActWeekPartyCache)
         self.ipyActLoginAwardCache = self.__LoadFileData("ActLoginAward", IPY_ActLoginAward)
@@ -3347,6 +3371,8 @@
     def GetCrossPenglaiZoneMapByIndex(self, index): return self.ipyCrossPenglaiZoneMapCache[index]
     def GetCrossDemonLandZoneMapCount(self): return self.ipyCrossDemonLandZoneMapLen
     def GetCrossDemonLandZoneMapByIndex(self, index): return self.ipyCrossDemonLandZoneMapCache[index]
+    def GetCrossFamilyFlagwarZoneMapCount(self): return self.ipyCrossFamilyFlagwarZoneMapLen
+    def GetCrossFamilyFlagwarZoneMapByIndex(self, index): return self.ipyCrossFamilyFlagwarZoneMapCache[index]
     def GetActWeekPartyCount(self): return self.ipyActWeekPartyLen
     def GetActWeekPartyByIndex(self, index): return self.ipyActWeekPartyCache[index]
     def GetActLoginAwardCount(self): return self.ipyActLoginAwardLen
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerEventCounter.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerEventCounter.py
index 3a107ee..c869c49 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerEventCounter.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerEventCounter.py
@@ -33,6 +33,7 @@
 import PlayerDuJie
 import PlayerCharm
 import CrossBattlefield
+import CrossFamilyFlagwar
 import CrossChampionship
 import CrossYaomoBoss
 #---------------------------------------------------------------------
@@ -141,6 +142,8 @@
     GameWorldArena.OnWeekEx()
     # 跨服战场
     CrossBattlefield.DoOnWeekEx()
+    # 逐鹿万界
+    CrossFamilyFlagwar.DoOnWeekEx()
     
     playerManager = GameWorld.GetPlayerManager()
     for i in xrange(playerManager.GetPlayerCount()):
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py
index e290111..23652a3 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py
@@ -74,6 +74,7 @@
 import CrossRealmPK
 import CrossChampionship
 import CrossBattlefield
+import CrossFamilyFlagwar
 import CrossActAllRecharge
 import ChPyNetSendPack
 import NetPackCommon
@@ -671,6 +672,11 @@
         CrossBattlefield.MapServer_CrossBattlefieldOver(eval(resultName))
         return
     
+    # 跨服仙盟夺旗战/逐鹿万界 结算
+    if callName =="CrossFamilyFlagwarOver":
+        CrossFamilyFlagwar.MapServer_CrossFamilyFlagwarOver(eval(resultName))
+        return
+    
     # 跨服妖魔boss伤害结算
     if callName =="CrossYaomoBossHurtInfo":
         CrossYaomoBoss.MapServer_CrossYaomoBossHurtInfo(eval(resultName))
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py b/ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py
index 1e462d0..a1c76d3 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py
@@ -812,7 +812,9 @@
 Def_CBT_BattlefieldWScore, # 跨服战场每周积分榜  153
 Def_CBT_BattlefieldWScoreLastWeek, # 跨服战场上周积分榜  154
 Def_CBT_YaomoBossHurt, # 跨服妖魔boss最新一次伤血排名  155
-) = range(150, 155 + 1)
+Def_CBT_FamilyFlagwar, # 逐鹿万界 - 单场榜  156
+Def_CBT_FamilyFlagwarWeek, # 逐鹿万界 - 周总榜  157
+) = range(150, 157 + 1)
 
 #职业对应战力排行榜类型
 JobFightPowerBillboardDict = {
@@ -1486,6 +1488,7 @@
 CrossServerMsg_ActAllRechargeInfo = "ActAllRechargeInfo"# 跨服全民充值信息
 CrossServerMsg_CrossDailyActionState = "CrossDailyActionState" # 跨服日常任务状态信息
 CrossServerMsg_CrossYaomoBossHurtInfo = "CrossYaomoBossHurtInfo" # 跨服妖魔boss玩家伤害信息
+CrossServerMsg_FamilyFlagwarOver = "FamilyFlagwarOver"  # 逐鹿万界结算信息
 
 # 子服发送跨服信息定义
 ClientServerMsg_ServerInitOK = "ServerInitOK"           # 子服启动成功
@@ -1776,7 +1779,8 @@
 # 跨服每日活动编号定义, 从150开始
 CrossDailyActionIDList = (
 CrossDailyActionID_YaomoBoss, # 妖魔boss 150
-) = range(150, 150 + 1)
+CrossDailyActionID_FamilyWarFlag, # 跨服仙盟夺旗战/逐鹿万界 151
+) = range(150, 150 + 2)
 
 # 成就类型定义
 SuccessTypeList = (
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
index 5482ec3..9c95841 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
@@ -1853,6 +1853,8 @@
 Def_FBMapID_CrossGrasslandXian = 32050
 #跨服战场
 Def_FBMapID_CrossBattlefield = 32060
+#跨服仙盟夺旗战/逐鹿万界
+Def_FBMapID_CrossFamilyFlagwar = 32090
 #竞技场战斗
 Def_FBMapID_ArenaBattle = 31290
 #情缘副本
@@ -1864,7 +1866,7 @@
 #注册上传跨服服务器数据后直接进入跨服服务器的地图
 RegisterEnter_CrossServerMapIDList = [Def_FBMapID_CrossPenglai, Def_FBMapID_CrossDemonLand, Def_FBMapID_CrossDemonKing, 
                                       Def_FBMapID_CrossGrasslandLing, Def_FBMapID_CrossGrasslandXian, Def_FBMapID_CrossBattlefield,
-                                      Def_FBMapID_CrossChampionship,
+                                      Def_FBMapID_CrossChampionship, Def_FBMapID_CrossFamilyFlagwar,
                                       ]
 #跨服地图
 Def_CrossMapIDList = RegisterEnter_CrossServerMapIDList + [Def_FBMapID_CrossRealmPK]
@@ -1878,10 +1880,12 @@
                          Def_FBMapID_CrossGrasslandXian:"CrossZonePK",
                          Def_FBMapID_CrossBattlefield:"CrossZonePK",
                          Def_FBMapID_CrossChampionship:"CrossZonePK",
+                         Def_FBMapID_CrossFamilyFlagwar:"CrossZoneComm",
                          }
 #跨服分区对应地图配置表名 - 仅适用于固定地图及虚拟分线的跨服玩法
 Def_CrossZoneMapTableName = {Def_FBMapID_CrossPenglai:"CrossPenglaiZoneMap",
                              Def_FBMapID_CrossDemonLand:"CrossDemonLandZoneMap",
+                             Def_FBMapID_CrossFamilyFlagwar:"CrossFamilyFlagwarZoneMap",
                              }
 #需要动态分配线路的跨服地图
 Def_CrossDynamicLineMap = [Def_FBMapID_CrossDemonKing, Def_FBMapID_CrossGrasslandLing, Def_FBMapID_CrossGrasslandXian, Def_FBMapID_CrossBattlefield, Def_FBMapID_CrossChampionship]
@@ -1988,6 +1992,7 @@
                 'FairyTreasure':[Def_FBMapID_FairyTreasure],#缥缈宝藏
                 'Love':[Def_FBMapID_Love],#情缘副本
                 'CrossBattlefield':[Def_FBMapID_CrossBattlefield], #跨服战场
+                'CrossFamilyFlagwar':[Def_FBMapID_CrossFamilyFlagwar], #跨服仙盟夺旗战/逐鹿万界
                 }
 
 #特殊副本ID, 由系统分配, 进入时候不验证IsMapCopyFull
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_CrossFamilyFlagwar.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_CrossFamilyFlagwar.py
new file mode 100644
index 0000000..c67aae2
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_CrossFamilyFlagwar.py
@@ -0,0 +1,969 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package GameWorldLogic.FBProcess.GameLogic_CrossFamilyFlagwar
+#
+# @todo:跨服仙盟夺旗战/逐鹿万界
+# @author hxp
+# @date 2023-04-25
+# @version 1.0
+#
+# 详细描述: 跨服仙盟夺旗战
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2023-04-25 15:30"""
+#-------------------------------------------------------------------------------
+
+import ChConfig
+import FBCommon
+import GameWorld
+import ShareDefine
+import IPY_GameWorld
+import IpyGameDataPY
+import GameWorldProcess
+import DataRecordPack
+import PlayerControl
+import SkillCommon
+import BuffSkill
+import AICommon
+import GameObj
+import GameMap
+
+import operator
+import time
+
+#当前副本地图的状态
+(
+FB_Step_Open, # 地图开启
+FB_Step_Prepare, # 地图准备
+FB_Step_Fighting, # 战斗中
+FB_Step_LeaveTime, # 自由时间
+FB_Step_Over, # 副本关闭
+) = range(5)
+
+(
+Time_Prepare, # 副本准备时间 0
+Time_Fight, # 副本战斗时间 1
+Time_Leave, # 副本离开时间 2
+) = range(3)
+
+FightRefreshInterval = 5000 # 战斗阶段刷新处理间隔,毫秒
+
+GameFBData_BattleMgr = "BattleMgr"
+
+## 战场管理类
+class BattleMgr():
+    
+    def __init__(self):
+        self.zoneID = 0
+        self.battlePlayerDict = {} # 参与战斗的玩家 {playerID:BattlePlayer, ...}
+        self.battleFamilyDict = {} # 参与战斗的仙盟 {familyID:BattleFamily, ...}
+        self.battleFamilySortList = [] # 参与战斗的仙盟积分排名列表 [BattleFamily, ...]
+        
+        self.allotRebornPointInfo = {} # 已经分配的复活点,一个复活点可能多个仙盟共用 {index:[familyID, ...], ...}
+        
+        self.playerFlagDict = {} # 玩家获得战旗 {playerID:flagNPC, ...}
+        
+        self.worldHelpDict = {} # 未通知的世界变更信息
+        return
+    
+    def sortBattleFamilyScore(self):
+        self.battleFamilySortList = self.battleFamilyDict.values()
+        self.battleFamilySortList.sort(key=operator.attrgetter("score", "scoreSortTime"), reverse=True)
+        return
+    
+    def getBattleFamily(self, familyID):
+        if familyID in self.battleFamilyDict:
+            batFamily = self.battleFamilyDict[familyID]
+        else:        
+            batFamily = BattleFamily(familyID)
+            self.battleFamilyDict[familyID] = batFamily
+        return batFamily
+    
+    def getBattlePlayer(self, playerID):
+        if playerID in self.battlePlayerDict:
+            batPlayer = self.battlePlayerDict[playerID]
+        else:        
+            batPlayer = BattlePlayer(playerID)
+            self.battlePlayerDict[playerID] = batPlayer
+        return batPlayer
+    
+    def addBattleFamily(self, familyID, name):
+        batFamily = self.getBattleFamily(familyID)
+        batFamily.name = name
+        self.__allotRebornPoint(familyID)
+        return batFamily
+    
+    def __allotRebornPoint(self, familyID):
+        batFamily = self.getBattleFamily(familyID)
+        for familyIDList in self.allotRebornPointInfo.values():
+            if familyID in familyIDList:
+                return
+        allotIndex = -1
+        allotAlreadyIndexs = self.allotRebornPointInfo.keys()
+        rebornPointList = IpyGameDataPY.GetFuncEvalCfg("CrossFamilyFlagwar", 2)
+        if len(rebornPointList) > len(allotAlreadyIndexs):
+            # 还有空余点未分配,直接分配空余点
+            for index, _ in enumerate(rebornPointList):
+                if index not in allotAlreadyIndexs:
+                    allotIndex = index
+                    break
+        
+        if allotIndex == -1:
+            # 没有空余点了,与其他仙盟共用,分配一个最少仙盟的复活点
+            leastIDCount = 99999
+            for index, familyIDList in self.allotRebornPointInfo.items():
+                if len(familyIDList) < leastIDCount and index < len(rebornPointList):
+                    leastIDCount = len(familyIDList)
+                    allotIndex = index
+                                
+        rebornPoint = rebornPointList[allotIndex]
+        if len(rebornPoint) != 3:
+            GameWorld.ErrLog("复活点配置异常! index=%s, %s" % (allotIndex, rebornPoint))
+            return
+        
+        if allotIndex not in self.allotRebornPointInfo:
+            self.allotRebornPointInfo[allotIndex] = []
+        familyIDList = self.allotRebornPointInfo[allotIndex]
+        familyIDList.append(familyID)
+        
+        batFamily.rebornPoint = rebornPoint
+        GameWorld.Log("分配仙盟复活点: familyID=%s,allotIndex=%s,rebornPoint=%s,allotRebornPointInfo=%s" 
+                      % (familyID, allotIndex, rebornPoint, self.allotRebornPointInfo), self.zoneID)
+        return True
+    
+    def setPlayerFlag(self, playerID, flagNPC):
+        self.playerFlagDict[playerID] = flagNPC
+        
+        npcID = flagNPC.GetNPCID()
+        batPlayer = self.getBattlePlayer(playerID)
+        flagOwner = self.worldHelpDict.get("flagOwner", {})
+        flagOwner[npcID] = [playerID, batPlayer.name]
+        self.worldHelpDict["flagOwner"] = flagOwner
+        return
+    
+    def popPlayerFlag(self, playerID):
+        self.playerFlagDict.pop(playerID, None)
+        
+        flagOwner = self.worldHelpDict.get("flagOwner", {})
+        for npcID, playerInfo in flagOwner.items():
+            if playerID == playerInfo[0]:
+                flagOwner.pop(npcID, None)
+                break
+        return
+    
+    def getWorldHelpInfo(self, isAll, familyID):
+        helpInfo = {}
+        if not isAll:
+            helpInfo = self.worldHelpDict
+        else:
+            flagOwner = {}
+            for playerID, flagNPC in self.playerFlagDict.items():
+                npcID = flagNPC.GetNPCID()
+                batPlayer = self.getBattlePlayer(playerID)
+                flagOwner[npcID] = [playerID, batPlayer.name]
+            helpInfo = {"flagOwner":flagOwner}
+            
+        # 取自身仙盟及前后名次仙盟信息
+        familyIndex = -1
+        familyList = []
+        for index, batFamily in enumerate(self.battleFamilySortList):
+            if familyID == batFamily.familyID:
+                familyIndex = index
+                break
+        # 第一名默认取前3名
+        if familyIndex == 0:
+            familyList = self.battleFamilySortList[:3]
+        # 第一名默认取前3名
+        elif familyIndex == len(self.battleFamilySortList) - 1:
+            familyList = self.battleFamilySortList[-3:]
+        elif familyIndex > 0:
+            familyList = self.battleFamilySortList[familyIndex - 1:familyIndex + 2]
+        for i, batFamily in enumerate(familyList):
+            familyList[i] = [batFamily.familyID, batFamily.score, batFamily.name]
+        helpInfo["familyList"] = familyList
+        return {"world":helpInfo}
+    
+## 战场仙盟类
+class BattleFamily():
+    
+    def __init__(self, familyID):
+        self.familyID = familyID
+        self.name = ""
+        self.score = 0 # 积分
+        self.scoreSortTime = 0 # 积分变更排序time值,用于同积分时,先到排名靠前
+        self.rebornPoint = [130, 300, 10] # 复活点坐标 [x,y,r],这里为默认值,防止没有分配到报错等
+        
+        self.battlePlayerIDList = [] # 参与战斗的仙盟玩家ID列表 [playerID, ...]
+        self.battlePlayerSortList = [] # 参与战斗的仙盟玩家积分排名列表 [BattlePlayer, ...]
+        
+        self.homePlayerIDList = [] # 在复活点里的玩家
+        
+        self.familyHelpDict = {} # 未通知的仙盟变更信息
+        return
+    
+    def addJoinPlayer(self, playerID):
+        if playerID not in self.battlePlayerIDList:
+            self.battlePlayerIDList.append(playerID)
+        self.familyHelpDict["playerCount"] = len(self.battlePlayerIDList)
+        return
+    
+    def setPlayerToRebornPoint(self, curPlayer):
+        if not self.rebornPoint:
+            return
+        randPosX, randPosY, maxDist = self.rebornPoint
+        posPoint = GameMap.GetEmptyPlaceInAreaEx(randPosX, randPosY, 3, maxDist)
+        curPlayer.ResetPos(posPoint.GetPosX(), posPoint.GetPosY())
+        return
+    
+    def sortBattlePlayerScore(self):
+        if len(self.battlePlayerIDList) != len(self.battlePlayerSortList):
+            self.battlePlayerSortList = []
+            mgr = GetBattleMgr()
+            for playerID in self.battlePlayerIDList:
+                batPlayer = mgr.getBattlePlayer(playerID)
+                self.battlePlayerSortList.append(batPlayer)
+        self.battlePlayerSortList.sort(key=operator.attrgetter("score", "scoreSortTime"), reverse=True)
+        return
+    
+    def addFamilyScore(self, addValue):
+        ## 增加积分
+        if addValue <= 0:
+            return
+        self.score = max(0, self.score + addValue)
+        self.familyHelpDict["score"] = self.score
+        calcTime = 3471264000 #GameWorld.ChangeTimeStrToNum("2080-01-01 00:00:00")
+        self.scoreSortTime = max(0, calcTime - int(time.time()))
+        #GameWorld.DebugLog("    增加仙盟积分: familyID=%s,addValue=%s,updScore=%s" % (self.familyID, addValue, self.score))
+        return
+    
+    def getFamilyHelpInfo(self, isAll):
+        helpInfo = {}
+        if not isAll:
+            helpInfo = self.familyHelpDict
+        else:
+            helpInfo = {"score":self.score, "playerCount":len(self.battlePlayerIDList)}
+        return {"family":helpInfo}
+    
+## 战场玩家类
+class BattlePlayer():
+    
+    def __init__(self, playerID):
+        self.playerID = playerID
+        self.name = ""
+        self.familyID = 0
+        self.familyName = ""
+        self.accID = ""
+        self.job = 1
+        self.realmLV = 0
+        self.fightPower = 0
+        
+        self.restoreHPTick = 0 # 营地回血tick
+        self.healthRebornCount = 0 # 原地健康复活次数
+        self.continueKillCount = 0 # 连杀次数
+        
+        self.score = 0 # 积分
+        self.scoreSortTime = 0 # 积分变更排序time值,用于同积分时,先到排名靠前
+        self.hurtTotal = 0 # 累计伤害
+        
+        self.onlineCalcTick = 0 # 在线计算tick
+        self.outsideFlagTick = 0 # 超出战旗范围计算tick
+        self.outsideFlagNotifySecond = 0 # 通知超出范围秒
+        
+        self.playerHelpDict = {} # 未通知的玩家变更信息
+        return
+    
+    def doPlayerEnter(self, curPlayer, tick):   
+        self.familyID = curPlayer.GetFamilyID()
+        self.familyName = curPlayer.GetFamilyName()
+        self.job = curPlayer.GetJob()
+        self.accID = curPlayer.GetAccID()
+        self.name = curPlayer.GetPlayerName()
+        self.realmLV = curPlayer.GetOfficialRank()
+        self.fightPower = PlayerControl.GetFightPower(curPlayer)
+        
+        self.onlineCalcTick = tick
+        return
+    
+    def addPlayerScore(self, addValue):
+        if addValue <= 0:
+            return
+        self.score = max(0, self.score + addValue)
+        calcTime = 3471264000 #GameWorld.ChangeTimeStrToNum("2080-01-01 00:00:00")
+        self.scoreSortTime = max(0, calcTime - int(time.time()))
+        #GameWorld.DebugLog("    增加玩家积分: playerID=%s,addValue=%s,updScore=%s" % (self.playerID, addValue, self.score))
+        self.playerHelpDict.update({"score":self.score})
+        return
+    
+    def addHealthRebornCount(self):
+        self.healthRebornCount += 1
+        self.playerHelpDict["healthRebornCount"] = self.healthRebornCount
+        return
+    
+    def getPlayerHelpInfo(self, isAll):
+        helpInfo = {}
+        if not isAll:
+            helpInfo = self.playerHelpDict
+        else:
+            helpInfo = {"score":self.score, "healthRebornCount":self.healthRebornCount}
+        return {"player":helpInfo}
+    
+def GetBattleMgr():
+    mgr = FBCommon.GetGameFBData(GameFBData_BattleMgr)
+    if not mgr:
+        mgr = BattleMgr()
+        FBCommon.SetGameFBData(GameFBData_BattleMgr, mgr)
+    return mgr
+
+def GetBFStepTime(): return IpyGameDataPY.GetFuncEvalCfg("CrossFamilyFlagwar", 1) # 阶段时间
+
+def OnOpenFB(tick):
+    FBCommon.SetGameFBData(GameFBData_BattleMgr, None)
+    
+    mgr = GetBattleMgr()
+    mgr.zoneID = GameWorld.GetGameWorld().GetPropertyID()
+    
+    FBCommon.SetFBStep(FB_Step_Prepare, tick)
+    return
+
+def OnCloseFB(tick):
+    GameWorld.GetGameWorld().SetPropertyID(0)
+    FBCommon.SetGameFBData(GameFBData_BattleMgr, None)
+    #FBCommon.ClearFBNPC()
+    return
+
+
+def OnEnterFBEvent(curPlayer, mapID, lineID, tick):
+    if GameWorld.IsCrossServer():
+        return True
+    
+    if not curPlayer.GetFamilyID():
+        GameWorld.DebugLog("无仙盟无法进入: mapID=%s" % mapID)
+        return False
+    
+    if not GameWorld.GetGameWorld().GetGameWorldDictByKey(ShareDefine.Def_Notify_WorldKey_CrossDailyActionState % ShareDefine.CrossDailyActionID_FamilyWarFlag):
+        GameWorld.DebugLog("非活动中,无法进入: CrossDailyActionID=%s" % ShareDefine.CrossDailyActionID_FamilyWarFlag)
+        return False
+    
+    return True
+
+def OnChangeMapAsk(ask, tick):
+    return IPY_GameWorld.cmeAccept
+
+##副本玩家进入点, 玩家分散在半径3格范围
+def OnGetFBEnterPos(curPlayer, mapID, lineId, ipyEnterPosInfo, tick):
+    return ipyEnterPosInfo
+
+def DoEnterFB(curPlayer, tick):    
+    gameFB = GameWorld.GetGameFB()
+    fbStep = gameFB.GetFBStep()
+    playerID = curPlayer.GetPlayerID()
+    familyID = curPlayer.GetFamilyID()
+    familyName = curPlayer.GetFamilyName()
+    mgr = GetBattleMgr()
+        
+    if fbStep not in [FB_Step_Prepare, FB_Step_Fighting] or not familyID:
+        GameWorld.Log("DoEnterFB... fbStep=%s,familyID=%s,playerID=%s PlayerLeaveFB" % (fbStep, familyID, playerID), mgr.zoneID)
+        PlayerControl.PlayerLeaveFB(curPlayer)
+        return
+    
+    GameWorld.Log("DoEnterFB... fbStep=%s,familyID=%s,playerID=%s" % (fbStep, familyID, playerID), mgr.zoneID)
+    
+    #--- 测试 ---
+#    testFamilyCount = 50
+#    if len(mgr.battleFamilyDict) < testFamilyCount:
+#        import random
+#        for i in range(testFamilyCount):
+#            fakeID = i + 10
+#            fakeName = "假名字%s" % fakeID
+#            fakeName = fakeName.decode(ShareDefine.Def_Game_Character_Encoding).encode(GameWorld.GetCharacterEncoding())
+#            fakeFamily = mgr.addBattleFamily(fakeID, fakeName)
+#            fakeFamily.addFamilyScore(random.randint(1000, 1500))
+    #-----------
+    
+    batFamily = mgr.addBattleFamily(familyID, familyName)
+    
+    batPlayer = mgr.getBattlePlayer(playerID)
+    batPlayer.doPlayerEnter(curPlayer, tick)
+    
+    batFamily.addJoinPlayer(playerID)
+    batFamily.setPlayerToRebornPoint(curPlayer)
+    
+    if fbStep == FB_Step_Prepare:
+        notify_tick = GetBFStepTime()[Time_Prepare] * 1000 - (tick - GameWorld.GetGameFB().GetFBStepTick())
+        curPlayer.Sync_TimeTick(IPY_GameWorld.tttWaitStart, 0, max(notify_tick, 0), True)
+        
+    elif fbStep == FB_Step_Fighting:
+        notify_tick = GetBFStepTime()[Time_Fight] * 1000 - (tick - GameWorld.GetGameFB().GetFBStepTick())
+        curPlayer.Sync_TimeTick(IPY_GameWorld.tttTowerTake, 0, max(notify_tick, 0), True)
+        
+    NotifyCrossFamilyFlagHelp(True, curPlayer)
+    return
+
+def NotifyCrossFamilyFlagHelp(isAll=False, curPlayer=None, helpEx=None):
+    ## 广播战场帮助信息,针对所有玩家
+    
+    mgr = GetBattleMgr()
+    
+    if curPlayer:
+        __notifyPlayerHelp(curPlayer, mgr, isAll, helpEx)
+    else:
+        playerManager = GameWorld.GetMapCopyPlayerManager()
+        for index in xrange(playerManager.GetPlayerCount()):
+            player = playerManager.GetPlayerByIndex(index)
+            if not player:
+                continue
+            playerID = player.GetPlayerID()
+            if playerID not in mgr.battlePlayerDict:
+                #GameWorld.DebugLog("还未加入战斗,暂不处理! playerID=%s" % playerID)
+                continue
+            __notifyPlayerHelp(player, mgr, isAll, helpEx)
+            
+        # 重置未通知的
+        mgr.worldHelpDict = {}
+        for familyID in mgr.battleFamilyDict.keys():
+            batFamily = mgr.getBattleFamily(familyID)
+            batFamily.familyHelpDict = {}
+            
+    return
+
+def __notifyPlayerHelp(curPlayer, mgr, isAll, helpEx):
+    if not mgr:
+        mgr = GetBattleMgr()
+        
+    playerID = curPlayer.GetPlayerID()
+    batPlayer = mgr.getBattlePlayer(playerID)
+    batFamily = mgr.getBattleFamily(batPlayer.familyID)
+    
+    helpDict = {}
+    helpDict.update(mgr.getWorldHelpInfo(isAll, batPlayer.familyID))
+    helpDict.update(batFamily.getFamilyHelpInfo(isAll))
+    helpDict.update(batPlayer.getPlayerHelpInfo(isAll))
+    
+    if helpEx:
+        helpDict.update(helpEx)
+        
+    GameWorld.DebugLog("FBHelp: %s" % helpDict, playerID)
+    FBCommon.Notify_FBHelp(curPlayer, helpDict)
+    batPlayer.playerHelpDict = {}
+    return
+
+
+##获得副本帮助信息, 用于通知阵营比分条
+def DoFBHelp(curPlayer, tick):
+    return
+
+##玩家退出副本
+def DoExitFB(curPlayer, tick):
+    gameFB = GameWorld.GetGameFB()
+    fbStep = gameFB.GetFBStep()
+    if fbStep != FB_Step_Fighting:
+        return
+        
+    mgr = GetBattleMgr()
+    playerID = curPlayer.GetPlayerID()
+    GameWorld.Log("DoExitFB... playerID=%s,fbStep=%s" % (playerID, fbStep), mgr.zoneID)
+    
+    batPlayer = mgr.getBattlePlayer(playerID)
+    batPlayer.onlineCalcTick = 0
+    return
+
+##玩家主动离开副本.
+def DoPlayerLeaveFB(curPlayer, tick):
+    return
+
+##副本总逻辑计时器
+# @param tick 时间戳
+# @return 无意义
+# @remarks 副本总逻辑计时器
+def OnProcess(tick):
+    fbStep = GameWorld.GetGameFB().GetFBStep()
+    
+    # 副本准备
+    if fbStep == FB_Step_Prepare:
+        __DoLogic_FB_Prepare(fbStep, tick)
+        
+    # 副本进行中
+    elif fbStep == FB_Step_Fighting:
+        __DoLogic_FB_Fighting(tick)
+        
+    # 副本结束
+    elif fbStep == FB_Step_LeaveTime:
+        __DoLogic_FB_Leave(tick)
+        
+    return
+
+
+def __DoLogic_FB_Prepare(fbStep, tick):
+    
+    remaindTick = GetBFStepTime()[Time_Prepare] * 1000 - (tick - GameWorld.GetGameFB().GetFBStepTick())
+    if remaindTick > 0:
+        return
+    
+    FBCommon.SetFBStep(FB_Step_Fighting, tick)
+    
+    mgr = GetBattleMgr()
+    fightTime = GetBFStepTime()[Time_Fight] * 1000
+    playerManager = GameWorld.GetMapCopyPlayerManager()
+    for index in xrange(playerManager.GetPlayerCount()):
+        curPlayer = playerManager.GetPlayerByIndex(index)
+        playerID = curPlayer.GetPlayerID()
+        if not playerID:
+            continue
+        if playerID not in mgr.battlePlayerDict:
+            #GameWorld.DebugLog("还未加入战斗,暂不处理! playerID=%s" % playerID)
+            continue
+        curPlayer.Sync_TimeTick(IPY_GameWorld.tttTowerTake, 0, fightTime, True)
+        
+        batPlayer = mgr.getBattlePlayer(playerID)
+        batPlayer.onlineCalcTick = tick # 开始战斗重新统计在线收益
+        
+        batFamily = mgr.getBattleFamily(batPlayer.familyID)
+        batFamily.setPlayerToRebornPoint(curPlayer)
+        
+    NotifyCrossFamilyFlagHelp(True)
+    #PlayerControl.FBNotify("CrossBattlefieldStartFighting")
+    return
+
+def __DoLogic_FB_Fighting(tick):
+    
+    passTick = tick - GameWorld.GetGameFB().GetFBStepTick()
+    remaindTick = GetBFStepTime()[Time_Fight] * 1000 - passTick
+    if remaindTick > 0:
+        __refreshFamilyHome(tick)
+        __refreshFlagoutside(tick)
+        
+        gameFB = GameWorld.GetGameFB()
+        lastTick = gameFB.GetGameFBDictByKey(ChConfig.Def_FB_NotifyFBHelpTick)
+        if tick - lastTick >= FightRefreshInterval:
+            gameFB.SetGameFBDict(ChConfig.Def_FB_NotifyFBHelpTick, tick)
+            refreshCrossFamilyFlagwar(tick)
+            NotifyCrossFamilyFlagHelp()
+        return
+    
+    DoOver(tick)
+    return
+
+def __DoLogic_FB_Leave(tick):
+    remaindTick = GetBFStepTime()[Time_Leave] * 1000 - (tick - GameWorld.GetGameFB().GetFBStepTick())
+    if remaindTick > 0:
+        return
+    
+    FBCommon.DoLogic_FBKickAllPlayer()
+    GameWorldProcess.CloseFB(tick)
+    FBCommon.SetFBStep(FB_Step_Over, tick)
+    return
+
+def __refreshFamilyHome(tick):
+    # 刷新营地相关,如回血等
+    
+    restoreHPPerBySecond = IpyGameDataPY.GetFuncCfg("CrossFamilyFlagwar", 3) # 每秒回血百分比
+    
+    mgr = GetBattleMgr()
+    copyMapMgr = GameWorld.GetMapCopyPlayerManager()
+    for familyID in mgr.battleFamilyDict.keys():
+        batFamily = mgr.getBattleFamily(familyID)
+        safePosX, safePosY, safeRadius = batFamily.rebornPoint
+        
+        for playerID in batFamily.homePlayerIDList[::-1]:
+            curPlayer = copyMapMgr.FindPlayerByID(playerID)
+            if not curPlayer:
+                continue
+            
+            batPlayer = mgr.getBattlePlayer(playerID)
+            
+            if GameWorld.GetDist(curPlayer.GetPosX(), curPlayer.GetPosY(), safePosX, safePosY) > safeRadius:
+                batFamily.homePlayerIDList.remove(playerID)
+                batPlayer.restoreHPTick = 0
+                continue
+            
+            # 营地回血
+            restoreSeconds = (tick - batPlayer.restoreHPTick) / 1000.0 if batPlayer.restoreHPTick else 1 # 首次保底1秒
+            if restoreSeconds < 1:
+                continue
+            maxHP = GameObj.GetMaxHP(curPlayer)
+            if GameObj.GetHP(curPlayer) < maxHP:
+                restoreHP = int(maxHP * restoreHPPerBySecond / 100.0 * round(restoreSeconds, 1))
+                SkillCommon.SkillAddHP(curPlayer, 0, restoreHP)
+            batPlayer.restoreHPTick = tick
+            
+    return
+
+def __refreshFlagoutside(tick):
+    # 刷新战旗出界
+    
+    mgr = GetBattleMgr()
+    
+    if not mgr.playerFlagDict:
+        return
+    
+    outsideR, protectSeconds = IpyGameDataPY.GetFuncEvalCfg("CrossFamilyFlagwarFlag", 4)
+    
+    copyMapMgr = GameWorld.GetMapCopyPlayerManager()
+    for playerID, flagNPC in mgr.playerFlagDict.items():
+        curPlayer = copyMapMgr.FindPlayerByID(playerID)
+        if not curPlayer:
+            # 找不到玩家,直接归还战旗
+            setFlagOwner(flagNPC, None, tick)
+            continue
+        
+        flagPosX, flagPosY = flagNPC.GetPosX(), flagNPC.GetPosY()
+        batPlayer = mgr.getBattlePlayer(playerID)
+        if GameWorld.GetDist(curPlayer.GetPosX(), curPlayer.GetPosY(), flagPosX, flagPosY) <= outsideR:
+            batPlayer.outsideFlagTick = 0
+            batPlayer.outsideFlagNotifySecond = 0
+        else:
+            if not batPlayer.outsideFlagTick:
+                batPlayer.outsideFlagTick = tick
+                continue
+            passSeconds = (tick - batPlayer.outsideFlagTick) / 1000
+            if passSeconds < protectSeconds:
+                remainSecond = protectSeconds - passSeconds
+                if remainSecond != batPlayer.outsideFlagNotifySecond:
+                    batPlayer.outsideFlagNotifySecond = remainSecond
+                    PlayerControl.NotifyCode(curPlayer, "CrossFamilyFlagwarOutsideflag", [flagNPC.GetNPCID(), remainSecond])
+                continue
+            setFlagOwner(flagNPC, None, tick)
+    return
+
+def setFlagOwner(flagNPC, newOwner, tick):
+    
+    if not flagNPC:
+        return
+    
+    ownerBuffDict = IpyGameDataPY.GetFuncEvalCfg("CrossFamilyFlagwarFlag", 5, {})
+    
+    flagNPCID = flagNPC.GetNPCID()
+    flagType = getFlagType(flagNPC)
+    if not flagType:
+        return
+    
+    mgr = GetBattleMgr()
+    copyMapMgr = GameWorld.GetMapCopyPlayerManager()
+    GameWorld.DebugLog("设置战旗归属: flagNPCID=%s,flagType=%s" % (flagNPCID, flagType), mgr.zoneID)
+    
+    for oldPlayerID, npc in mgr.playerFlagDict.items():
+        if not npc or flagNPCID != npc.GetNPCID():
+            continue
+        GameWorld.DebugLog("    移除旧归属: flagNPCID=%s,oldPlayerID=%s" % (flagNPCID, oldPlayerID), mgr.zoneID)
+        mgr.popPlayerFlag(oldPlayerID)
+        oldOwner = copyMapMgr.FindPlayerByID(oldPlayerID)
+        if oldOwner:
+            PlayerControl.NotifyCode(oldOwner, "CrossFamilyFlagwarFlagDrop", [flagNPCID])
+            # 删除归属buff
+            for delBuffID in ownerBuffDict.values():
+                BuffSkill.DelBuffBySkillID(oldOwner, delBuffID, tick)
+                
+    if newOwner:
+        newPlayerID = newOwner.GetPlayerID()
+        
+        # 已经有战旗,判断战旗类型,高级可替换低级
+        if newPlayerID in mgr.playerFlagDict:
+            bodyFlagNPC = mgr.playerFlagDict[newPlayerID]
+            bodyFlagType = getFlagType(bodyFlagNPC)
+            bodyFlagNPCID = bodyFlagNPC.GetNPCID()
+            if bodyFlagType >= flagType:
+                GameWorld.DebugLog("    新归属者已有高级战旗,保留原归属: bodyFlagNPCID=%s,bodyFlagType=%s >= flagType=%s" 
+                                   % (bodyFlagNPCID, bodyFlagType, flagType), mgr.zoneID)
+                setFlagOwnerNone(flagNPC)
+                return
+            GameWorld.DebugLog("    新归属者已有低级战旗,先归还原低级战旗: bodyFlagNPCID=%s,bodyFlagType=%s < flagType=%s" 
+                               % (bodyFlagNPCID, bodyFlagType, flagType), mgr.zoneID)
+            setFlagOwner(bodyFlagNPC, None, tick)
+            
+        batPlayer = mgr.getBattlePlayer(newPlayerID)
+        batFamily = mgr.getBattleFamily(batPlayer.familyID)
+        
+        batPlayer.outsideFlagTick = 0
+        mgr.setPlayerFlag(newPlayerID, flagNPC)
+        
+        PlayerControl.NotifyCode(newOwner, "CrossFamilyFlagwarFlagOwn", [flagNPCID])
+        
+        # 归属积分
+        ownScoreDict = IpyGameDataPY.GetFuncEvalCfg("CrossFamilyFlagwarFlag", 2, {})
+        ownPlayerScore, ownFamilyScore = ownScoreDict.get(flagType, [0, 0])
+        batPlayer.addPlayerScore(ownPlayerScore)
+        batFamily.addFamilyScore(ownFamilyScore)
+        
+        # 归属buff
+        ownerBuffID = ownerBuffDict.get(flagType, 0)
+        if ownerBuffID:
+            SkillCommon.AddBuffBySkillType_NoRefurbish(newOwner, ownerBuffID, tick)
+            
+        flagNPC.SetVisible(False)
+        
+        GameWorld.DebugLog("    更新新归属: flagNPCID=%s,newPlayerID=%s,ownerBuffID=%s" % (flagNPCID, newPlayerID, ownerBuffID), mgr.zoneID)
+        
+    # 没有新归属,归还战旗
+    else:
+        GameWorld.DebugLog("    没有新归属,归还战旗: flagNPCID=%s" % flagNPCID, mgr.zoneID)
+        setFlagOwnerNone(flagNPC)
+        
+    return
+
+def setFlagOwnerNone(flagNPC):
+    GameWorld.DebugLog("    setFlagOwnerNone: npcID=%s" % flagNPC.GetNPCID())
+    flagNPC.SetVisible(True)
+    return
+
+def refreshCrossFamilyFlagwar(tick):
+    ## 刷新战场相关
+    
+    olPlayerScore, olFamilyScore = IpyGameDataPY.GetFuncEvalCfg("CrossFamilyFlagwarScore", 2) # 玩家在战场时每秒固定获得  个人得分|仙盟得分
+    flagTimeScoreDict = IpyGameDataPY.GetFuncEvalCfg("CrossFamilyFlagwarFlag", 3, {})
+    
+    mgr = GetBattleMgr()
+    
+    copyMapMgr = GameWorld.GetMapCopyPlayerManager()
+    for familyID in mgr.battleFamilyDict.keys():
+        batFamily = mgr.getBattleFamily(familyID)
+        
+        batFamily.battlePlayerSortList = []
+        
+        safePosX, safePosY, safeRadius = batFamily.rebornPoint
+        for playerID in batFamily.battlePlayerIDList:
+            batPlayer = mgr.getBattlePlayer(playerID)
+            batFamily.battlePlayerSortList.append(batPlayer)
+            
+            curPlayer = copyMapMgr.FindPlayerByID(playerID)
+            if not curPlayer:
+                continue
+            onlineTimes = 0
+            # 累计参与战斗时长
+            if batPlayer.onlineCalcTick:
+                onlineTimes = max(0, tick - batPlayer.onlineCalcTick) / 1000
+                batPlayer.onlineCalcTick = tick
+                
+                batPlayer.addPlayerScore(onlineTimes * olPlayerScore)
+                batFamily.addFamilyScore(onlineTimes * olFamilyScore)
+                
+            # 回营地
+            if GameWorld.GetDist(curPlayer.GetPosX(), curPlayer.GetPosY(), safePosX, safePosY) <= safeRadius:
+                if playerID not in batFamily.homePlayerIDList:
+                    batFamily.homePlayerIDList.append(playerID)
+                    
+            # 战旗定时积分
+            if playerID in mgr.playerFlagDict:
+                flagType = getFlagType(mgr.playerFlagDict[playerID])
+                ftPlayerScore, ftFamilyScore = flagTimeScoreDict.get(flagType, [0, 0])
+                
+                batPlayer.addPlayerScore(onlineTimes * ftPlayerScore)
+                batFamily.addFamilyScore(onlineTimes * ftFamilyScore)
+                
+        batFamily.sortBattlePlayerScore()
+        
+    # 放最后排序,上面的逻辑可能还会加分
+    mgr.sortBattleFamilyScore()
+    return
+
+def getFlagType(curNPC):
+    if not curNPC:
+        return 0
+    
+    npcID = curNPC.GetNPCID()
+    flagTypeDict = IpyGameDataPY.GetFuncEvalCfg("CrossFamilyFlagwarFlag", 1, {})
+    for ft, npcIDList in flagTypeDict.items():
+        if npcID in npcIDList:
+            return ft
+    return 0
+
+##是否可以夺旗
+def OnCanCollect(curPlayer, curNPC, tick):
+    gameFB = GameWorld.GetGameFB()
+    fbStep = gameFB.GetFBStep()
+    
+    # 非战斗阶段不可采集
+    if fbStep != FB_Step_Fighting:
+        return False
+    
+    playerID = curPlayer.GetPlayerID()
+    mgr = GetBattleMgr()
+    
+    if playerID in mgr.playerFlagDict:
+        ownerFlagType = getFlagType(mgr.playerFlagDict[playerID])
+        if ownerFlagType >= getFlagType(curNPC):
+            GameWorld.Log("已经拥有更高级的战旗,无法采集! ownerFlagType=%s >= %s" % (ownerFlagType, getFlagType(curNPC)), playerID)
+            return False
+        
+    return True
+
+## 开始采集
+def OnBeginCollect(curPlayer, curNPC):
+    return
+
+## 退出采集
+def OnExitCollect(curPlayer, curNPC):
+    #if not curNPC or not hasattr(curNPC, "GetNPCID"):
+    #    return
+    return
+
+##玩家收集成功(塔, 旗)
+def OnCollectOK(curPlayer, npcID, tick):
+    #GameWorld.DebugLog("OnCollectOK npcID=%s" % npcID, curPlayer.GetPlayerID())
+    tagObj = curPlayer.GetActionObj()
+    if not tagObj:
+        return
+    if tagObj.GetGameObjType() != IPY_GameWorld.gotNPC:
+        return
+        
+    curNPC = GameWorld.GetNPCManager().GetNPCByIndex(tagObj.GetIndex())
+    #npcID = curNPC.GetNPCID()
+    flagType = getFlagType(curNPC)
+    AICommon.ClearPlayerPreparing(curNPC, curPlayer, "CrossFamilyFlagwarCollectOKSlow")
+    
+    if flagType:
+        setFlagOwner(curNPC, curPlayer, tick)
+        
+    return
+
+## PVP伤害相关
+def OnPVPDamage(curPlayer, damageValue, tagPlayer, tick):
+    playerID = curPlayer.GetPlayerID()
+    
+    mgr = GetBattleMgr()
+    batPlayer = mgr.getBattlePlayer(playerID)
+    batPlayer.hurtTotal += damageValue
+    
+    #GameWorld.DebugLog("OnPVPDamage: damageValue=%s,hurtTotal=%s" % (damageValue, batPlayer.hurtTotal), playerID)
+    return
+
+##处理副本中杀死玩家逻辑
+def DoFBOnKill_Player(curPlayer, defender, tick):
+    playerID = curPlayer.GetPlayerID()
+    defPlayerID = defender.GetPlayerID()
+    #GameWorld.DebugLog("DoFBOnKill_Player playerID=%s,defPlayerID=%s" % (playerID, defPlayerID))
+    
+    mgr = GetBattleMgr()
+    
+    killPlayerScore, killFamilyScore = IpyGameDataPY.GetFuncEvalCfg("CrossFamilyFlagwarScore", 1) # 击杀玩家 个人得分|仙盟得分
+    batPlayer = mgr.getBattlePlayer(playerID)
+    batFamily = mgr.getBattleFamily(batPlayer.familyID)
+    
+    batPlayer.addPlayerScore(killPlayerScore)
+    batFamily.addFamilyScore(killFamilyScore)
+    
+    # 获得对方战旗归属
+    if defPlayerID in mgr.playerFlagDict:
+        setFlagOwner(mgr.playerFlagDict[defPlayerID], curPlayer, tick)
+    return True
+
+def OnCanFBReborn(curPlayer, rebornType):
+    playerID = curPlayer.GetPlayerID()
+    if rebornType == ChConfig.rebornType_Health:
+        mgr = GetBattleMgr()
+        playerID = curPlayer.GetPlayerID()
+        batPlayer = mgr.getBattlePlayer(playerID)
+        
+        healthRebornMax = IpyGameDataPY.GetFuncCfg("CrossFamilyFlagwarReborn", 1)
+        if healthRebornMax and batPlayer.healthRebornCount >= healthRebornMax:
+            GameWorld.Log("已达原地健康复活次数上限! playerID=%s" % playerID, mgr.zoneID)
+            return False
+        
+    return True
+
+def OnPlayerReborn():
+    ## 是否副本复活
+    return True
+
+## 玩家复活后处理
+def OnPlayerRebornOver(curPlayer, rebornType):
+    mgr = GetBattleMgr()
+    playerID = curPlayer.GetPlayerID()
+    batPlayer = mgr.getBattlePlayer(playerID)
+    
+    if rebornType == ChConfig.rebornType_Health:
+        batPlayer.addHealthRebornCount()
+    else:
+        # 非原地
+        batFamily = mgr.getBattleFamily(curPlayer.GetFamilyID())
+        batFamily.setPlayerToRebornPoint(curPlayer)
+        
+        batPlayer.continueKillCount = 0 # 中断连杀数
+        
+    FBCommon.Notify_FBHelp(curPlayer, batPlayer.getPlayerHelpInfo(False))
+    return
+
+def DoOver(tick):
+    
+    mgr = GetBattleMgr()
+    zoneID = mgr.zoneID
+        
+    gameFB = GameWorld.GetGameFB()
+    gameWorld = GameWorld.GetGameWorld()
+    copyMapID = gameWorld.GetCopyMapID()
+    
+    fbStep = gameFB.GetFBStep()
+    if fbStep > FB_Step_Fighting:
+        GameWorld.ErrLog("跨服仙盟夺旗战触发重复结算,不处理! zoneID=%s,copyMapID=%s" % (mgr.zoneID, copyMapID), zoneID)
+        return
+    FBCommon.SetFBStep(FB_Step_LeaveTime, tick)
+    
+    GameWorld.Log("跨服仙盟夺旗战结算! zoneID=%s,copyMapID=%s" % (mgr.zoneID, copyMapID), zoneID)
+    
+    refreshCrossFamilyFlagwar(tick) # 结算前强刷一次
+    NotifyCrossFamilyFlagHelp(True)
+    
+    leaveTime = GetBFStepTime()[Time_Leave] * 1000
+    
+    copyMapMgr = GameWorld.GetMapCopyPlayerManager()
+    
+    drDict = {"mapID":GameWorld.GetMap().GetMapID(), "realMapID":gameWorld.GetRealMapID(), "copyMapID":copyMapID, "zoneID":zoneID}
+    drBatFamilyList = []
+    
+    battleFamilyList = []
+    for familyRank, batFamily in enumerate(mgr.battleFamilySortList, 1):
+        familyID = batFamily.familyID
+        #batFamily = mgr.getBattleFamily(familyID)
+        familyScore = batFamily.score
+        familyName = batFamily.name
+        GameWorld.Log("familyRank=%s,familyID=%s,familyScore=%s" % (familyRank, familyID, familyScore), zoneID)
+        
+        overPlayerList = [] # 同步前端结算
+        drPlayerList = [] # 流向记录
+        battlePlayerList = [] # 同步GameServer结算
+        
+        for playerRank, batPlayer in enumerate(batFamily.battlePlayerSortList, 1):
+            playerID = batPlayer.playerID
+            #batPlayer = mgr.getBattlePlayer(playerID)
+            
+            score = batPlayer.score
+            #job = batPlayer.job
+            #realmLV = batPlayer.realmLV
+            name = batPlayer.name
+            
+            hurtTotal = batPlayer.hurtTotal
+            
+            GameWorld.Log("     familyID=%s,playerRank=%s,playerID=%s,score=%s,hurtTotal=%s,accID=%s" 
+                          % (familyID, playerRank, playerID, score, hurtTotal, batPlayer.accID), zoneID)
+            
+            overPlayerList.append([name, score])
+            battlePlayerList.append([playerID, score, hurtTotal])
+            drPlayerList.append({"playerID":playerID, "accID":batPlayer.accID, "playerRank":playerRank, "score":score, "hurtTotal":hurtTotal})
+            
+        overDict = {"familyScore":familyScore, "familyRank":familyRank, "playerList":overPlayerList}
+        for playerRank, batPlayer in enumerate(batFamily.battlePlayerSortList, 1):
+            playerID = batPlayer.playerID
+            player = copyMapMgr.FindPlayerByID(playerID)
+            if not player:
+                continue
+            player.Sync_TimeTick(IPY_GameWorld.tttLeaveMap, 0, leaveTime, True)
+            
+            lineID = 0
+            overDict.update({"familyScore":familyScore, "familyRank":familyRank})
+            FBCommon.NotifyFBOver(player, ChConfig.Def_FBMapID_CrossFamilyFlagwar, lineID, True, overDict)
+            
+        battleFamilyList.append([familyRank, familyID, familyName, familyScore, battlePlayerList])
+        drBatFamilyList.append({"familyID":familyID, "familyScore":familyScore, "familyRank":familyRank, "drPlayerList":drPlayerList})
+        
+    # 同步GameServer 比赛结果
+    msgInfo = str([zoneID, battleFamilyList])
+    GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(0, 0, 0, "CrossFamilyFlagwarOver", msgInfo, len(msgInfo))
+    
+    # 记录流向
+    drDict["batFamilyList"] = drBatFamilyList
+    DataRecordPack.SendEventPack("CrossFamilyFlagwarOver", drDict)
+    return
+
+
+
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
index d5ab22b..3bb46a8 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
@@ -1760,6 +1760,15 @@
                         ("WORD", "PosY", 0),
                         ),
 
+                "CrossFamilyFlagwarZoneMap":(
+                        ("BYTE", "ZoneID", 0),
+                        ("DWORD", "MapID", 1),
+                        ("DWORD", "DataMapID", 1),
+                        ("BYTE", "CopyMapID", 1),
+                        ("WORD", "PosX", 0),
+                        ("WORD", "PosY", 0),
+                        ),
+
                 "GatherSoul":(
                         ("DWORD", "ItemID", 1),
                         ("list", "AttrType", 0),
@@ -5840,6 +5849,25 @@
     def GetPosX(self): return self.PosX # 坐标X
     def GetPosY(self): return self.PosY # 坐标Y
 
+# 跨服分区地图逐鹿万界
+class IPY_CrossFamilyFlagwarZoneMap():
+    
+    def __init__(self):
+        self.ZoneID = 0
+        self.MapID = 0
+        self.DataMapID = 0
+        self.CopyMapID = 0
+        self.PosX = 0
+        self.PosY = 0
+        return
+        
+    def GetZoneID(self): return self.ZoneID # 分区ID
+    def GetMapID(self): return self.MapID # 场景地图ID
+    def GetDataMapID(self): return self.DataMapID # 数据地图ID
+    def GetCopyMapID(self): return self.CopyMapID # 虚拟线路ID
+    def GetPosX(self): return self.PosX # 坐标X
+    def GetPosY(self): return self.PosY # 坐标Y
+
 # 聚魂表
 class IPY_GatherSoul():
     
@@ -7164,6 +7192,8 @@
         self.ipyCrossPenglaiZoneMapLen = len(self.ipyCrossPenglaiZoneMapCache)
         self.ipyCrossDemonLandZoneMapCache = self.__LoadFileData("CrossDemonLandZoneMap", IPY_CrossDemonLandZoneMap)
         self.ipyCrossDemonLandZoneMapLen = len(self.ipyCrossDemonLandZoneMapCache)
+        self.ipyCrossFamilyFlagwarZoneMapCache = self.__LoadFileData("CrossFamilyFlagwarZoneMap", IPY_CrossFamilyFlagwarZoneMap)
+        self.ipyCrossFamilyFlagwarZoneMapLen = len(self.ipyCrossFamilyFlagwarZoneMapCache)
         self.ipyGatherSoulCache = self.__LoadFileData("GatherSoul", IPY_GatherSoul)
         self.ipyGatherSoulLen = len(self.ipyGatherSoulCache)
         self.ipyGatherSoulCompoundCache = self.__LoadFileData("GatherSoulCompound", IPY_GatherSoulCompound)
@@ -7782,6 +7812,8 @@
     def GetCrossPenglaiZoneMapByIndex(self, index): return self.ipyCrossPenglaiZoneMapCache[index]
     def GetCrossDemonLandZoneMapCount(self): return self.ipyCrossDemonLandZoneMapLen
     def GetCrossDemonLandZoneMapByIndex(self, index): return self.ipyCrossDemonLandZoneMapCache[index]
+    def GetCrossFamilyFlagwarZoneMapCount(self): return self.ipyCrossFamilyFlagwarZoneMapLen
+    def GetCrossFamilyFlagwarZoneMapByIndex(self, index): return self.ipyCrossFamilyFlagwarZoneMapCache[index]
     def GetGatherSoulCount(self): return self.ipyGatherSoulLen
     def GetGatherSoulByIndex(self, index): return self.ipyGatherSoulCache[index]
     def GetGatherSoulCompoundCount(self): return self.ipyGatherSoulCompoundLen
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCAI/AICommon.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCAI/AICommon.py
index 23c9aa9..c71773f 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCAI/AICommon.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCAI/AICommon.py
@@ -223,7 +223,7 @@
 #  @param curNPC 当前NPC
 #  @return None
 #  @remarks 清空NPC伤血列表, 并清空玩家Loading进度条状态
-def ClearPlayerPreparing(curNPC, srcPlayer=None):
+def ClearPlayerPreparing(curNPC, srcPlayer=None, notifyKey=""):
     curNPC_HurtList = curNPC.GetPlayerHurtList()
     for i in range(curNPC_HurtList.GetHurtCount()):
         hurtValue = curNPC_HurtList.GetHurtAt(i)
@@ -254,7 +254,9 @@
         
         #设置空闲状态
         PlayerControl.ChangePlayerAction(curPlayer, IPY_GameWorld.paNull)
-    
+        if notifyKey:
+            PlayerControl.NotifyCode(curPlayer, notifyKey, [curNPC.GetNPCID()])
+            
     #清空这个NPC的伤血列表
     curNPC_HurtList.Clear()
 
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
index 1e462d0..a1c76d3 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
@@ -812,7 +812,9 @@
 Def_CBT_BattlefieldWScore, # 跨服战场每周积分榜  153
 Def_CBT_BattlefieldWScoreLastWeek, # 跨服战场上周积分榜  154
 Def_CBT_YaomoBossHurt, # 跨服妖魔boss最新一次伤血排名  155
-) = range(150, 155 + 1)
+Def_CBT_FamilyFlagwar, # 逐鹿万界 - 单场榜  156
+Def_CBT_FamilyFlagwarWeek, # 逐鹿万界 - 周总榜  157
+) = range(150, 157 + 1)
 
 #职业对应战力排行榜类型
 JobFightPowerBillboardDict = {
@@ -1486,6 +1488,7 @@
 CrossServerMsg_ActAllRechargeInfo = "ActAllRechargeInfo"# 跨服全民充值信息
 CrossServerMsg_CrossDailyActionState = "CrossDailyActionState" # 跨服日常任务状态信息
 CrossServerMsg_CrossYaomoBossHurtInfo = "CrossYaomoBossHurtInfo" # 跨服妖魔boss玩家伤害信息
+CrossServerMsg_FamilyFlagwarOver = "FamilyFlagwarOver"  # 逐鹿万界结算信息
 
 # 子服发送跨服信息定义
 ClientServerMsg_ServerInitOK = "ServerInitOK"           # 子服启动成功
@@ -1776,7 +1779,8 @@
 # 跨服每日活动编号定义, 从150开始
 CrossDailyActionIDList = (
 CrossDailyActionID_YaomoBoss, # 妖魔boss 150
-) = range(150, 150 + 1)
+CrossDailyActionID_FamilyWarFlag, # 跨服仙盟夺旗战/逐鹿万界 151
+) = range(150, 150 + 2)
 
 # 成就类型定义
 SuccessTypeList = (

--
Gitblit v1.8.0