From 2bca56e5df150d46e0f218a4e1af5e3dd81a0bcb Mon Sep 17 00:00:00 2001
From: hxp <ale99527@vip.qq.com>
Date: 星期四, 16 五月 2024 16:40:44 +0800
Subject: [PATCH] 10159 [新增]异兽入侵

---
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_AlineInvade.py |  168 ++++++++++++++++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBLogic.py                         |   40 ++++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py                                    |    5 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerBillboard.py                         |    9 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/TurnAttack.py                              |  214 +++++++++++++--------
 ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldAlineInvade.py                                 |   65 ++++++
 ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldProcess.py                                     |    3 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py                                  |   27 ++
 ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py                                                            |    1 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCCommon.py                                  |   15 +
 PySysDB/PySysDBPY.h                                                                                                   |   10 +
 ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/BillboardData.py                                           |    4 
 ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py                                                         |    3 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py                                       |    9 
 14 files changed, 484 insertions(+), 89 deletions(-)

diff --git a/PySysDB/PySysDBPY.h b/PySysDB/PySysDBPY.h
index 3a98ca9..de4ed87 100644
--- a/PySysDB/PySysDBPY.h
+++ b/PySysDB/PySysDBPY.h
@@ -2949,3 +2949,13 @@
 	list		EquipColorRateList;	//产出装备品质概率列表,[0品质万分率, 1品质万分率, ...]
 	list		ExAwardItemRateList;	//每次砍树概率额外产出道具饼图,[[万分率,[物品ID,个数]], ...]
 };
+
+//异兽入侵
+
+struct tagAlineInvade
+{
+	BYTE		_BoxNum;	//奖励盒子编号
+	DWORD		NeedHurtValue;	//下个盒子所需伤血
+	list		BoxAwardWeightList;	//本盒子奖励权重饼图[[权重, [物品ID,个数,是否拍品]], ...]
+	dict		BossAttrPlusInfo;	//Boss在该盒子情况下属性强化
+};
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py b/ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py
index 418be3e..357b744 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py
@@ -597,6 +597,7 @@
             ShareDefine.Def_BT_CharmWeek                : 100,           #魅力周榜
             ShareDefine.Def_BT_CharmDay                 : 100,           #魅力日榜
             ShareDefine.Def_BT_BossTrialSubmit          : 1000,          #boss凭证 (boss历练活动)
+            ShareDefine.Def_BT_AlineInvade              : 1000,          #异兽入侵
             }
 
 #排行榜保存类型(和BillboardType匹配), 默认保存, 如果不保存,可配置进去
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/BillboardData.py b/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/BillboardData.py
index 62f6ba8..2c2b838 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/BillboardData.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/BillboardData.py
@@ -25,7 +25,7 @@
         GameWorld.DebugAnswer(curPlayer, errInfo)
     GameWorld.DebugAnswer(curPlayer, "新增榜单假数据: BillboardData 类型 条数 比较值1 可选参数(比较值2 常规值1 常规值2)")
     GameWorld.DebugAnswer(curPlayer, "删除榜单假数据: BillboardData 类型")
-    GameWorld.DebugAnswer(curPlayer, "榜单类型:0-战力,1-龙魂,2-灵瑶,4-等级,5-坐骑,6-灵宠,7-符印,8-脱机,9-境界,19-助战")
+    GameWorld.DebugAnswer(curPlayer, "榜单类型:0-战力,1-龙魂,2-灵瑶,4-等级,5-坐骑,6-灵宠,7-符印,8-脱机,9-境界,19-助战,34-异兽")
     GameWorld.DebugAnswer(curPlayer, "开服活动榜类型:11-强化,12-坐骑,13-宝石,14-冲级,15-境界,16-战力,18-符印,20-神兵,21-充值,22-灵宠,24-灵根,25-升星")
     GameWorld.DebugAnswer(curPlayer, "运营活动榜类型:17-仙界盛典,23-仙界盛典2,33-boss凭证")
     GameWorld.DebugAnswer(curPlayer, "魅力榜单类型:30-总榜,31-周榜,32-日榜")
@@ -83,7 +83,7 @@
     for i in xrange(count):
         dataPlayerID = curDataCount + 1 + i
         dataPlayerName = "%s%s" % (FakeName, i)
-        dataCmpValue1 = max(0, cmpValue1 - i)
+        dataCmpValue1 = max(0, cmpValue1 - i) if not cmpValue2 else cmpValue1
         dataCmpValue2 = max(0, cmpValue2 - i)
         PlayerBillboard.UpdatePlayerBillboard(dataPlayerID, dataPlayerName, curPlayerOpInfo, billboardIndex, bType2, value1, value2, dataCmpValue1, autoSort, dataCmpValue2)
         
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldAlineInvade.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldAlineInvade.py
new file mode 100644
index 0000000..dbf0a51
--- /dev/null
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldAlineInvade.py
@@ -0,0 +1,65 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package GameWorldAlineInvade
+#
+# @todo:异兽入侵
+# @author hxp
+# @date 2024-05-16
+# @version 1.0
+#
+# 详细描述: 异兽入侵
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2024-05-16 16:00"""
+#-------------------------------------------------------------------------------
+
+import GameWorld
+import ShareDefine
+import PlayerCompensation
+import IpyGameDataPY
+
+def DoOnDay():
+    GiveDayHurtAward()
+    return
+
+def GiveDayHurtAward():
+    GameWorld.Log("异兽入侵每日结算奖励")
+    billBoard = GameWorld.GetBillboard().FindBillboard(ShareDefine.Def_BT_AlineInvade)
+    if not billBoard:
+        return
+    billboradAwardDict = IpyGameDataPY.GetFuncEvalCfg("AlineInvade", 2, {})
+    
+    orderList = []
+    for orderStr in billboradAwardDict.keys():
+        orderList.append(int(orderStr))
+    orderList.sort()
+    GameWorld.Log("    奖励名次列表: %s" % orderList)
+    
+    awardOrder = orderList[0]
+    billboardCount, billboardMaxCount = billBoard.GetCount(), billBoard.GetMaxCount()
+    GameWorld.Log("    榜单数据数! billboardCount=%s,billboardMaxCount=%s" % (billboardCount, billboardMaxCount))
+    for index in xrange(billboardCount):
+        billBoardData = billBoard.At(index)
+        if not billBoardData:
+            continue
+        order = index + 1
+        
+        if order > awardOrder:
+            nextOrderIndex = orderList.index(awardOrder) + 1
+            if nextOrderIndex >= len(orderList):
+                break
+            awardOrder = orderList[nextOrderIndex]
+            
+        playerID = billBoardData.GetID()
+        #GameWorld.DebugLog("order=%s,playerID=%s,awardOrder=%s" % (order, playerID, awardOrder))
+        if playerID < 10000:
+            continue
+        
+        awardList = billboradAwardDict[str(awardOrder)]
+        PlayerCompensation.SendMailByKey("AlineInvadeHurtRank", [playerID], awardList, [order])
+        
+    billBoard.Clear()
+    return
+
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldProcess.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldProcess.py
index dd18751..8fa0ef5 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldProcess.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldProcess.py
@@ -112,6 +112,7 @@
 import CrossBillboard
 import CrossChampionship
 import GameWorldMineArea
+import GameWorldAlineInvade
 #---------------------------------------------------------------------
 
 #---------------------------------------------------------------------
@@ -184,6 +185,8 @@
     PlayerLove.DoOnDay()
     # 云购
     CrossLuckyCloudBuy.DoOnDay()
+    # 异兽入侵
+    GameWorldAlineInvade.DoOnDay()
     return
 
 def OnDayEx(tick):
diff --git a/ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py b/ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py
index 1e6ae67..9a4be7d 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py
@@ -809,9 +809,10 @@
     Def_BT_CharmWeek, #魅力周榜
     Def_BT_CharmDay, #魅力日榜
     Def_BT_BossTrialSubmit,                   #提交boss凭证榜 (boss历练活动)
+    Def_BT_AlineInvade,                       #异兽入侵
     
     Def_BT_Max, #排行榜最大类型
-) = range(0, 33 + 2) 
+) = range(0, 34 + 2) 
 
 ''' 跨服排行榜类型, 从 150 开始
 与本服榜单存储的是不一样的数据库表格,理论上类型可以和本服榜单类型重复,为了做下区分防误导,跨服榜单从 150 开始
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/TurnAttack.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/TurnAttack.py
index b837393..fce553b 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/TurnAttack.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/TurnAttack.py
@@ -54,6 +54,72 @@
 RebornType_ShentongSkill, # 神通复活 - 由主角自己触发,灵宠触发的神通技能归为灵宠复活
 ) = range(1, 1 + 3)
 
+Def_FactionA = 1
+Def_FactionB = 2
+
+class TurnFightBattle():
+    
+    def __init__(self):
+        self.CleaerBat()
+        return
+    
+    def CleaerBat(self):
+        self.curPlayer = None
+        self.mapID = 0
+        self.funcLineID = 0
+        self.tagType = 0
+        self.tagID = 0
+        self.valueList = []
+        
+        self.factionObjListDict = {} # 阵营所有战斗实例,包含主体、灵宠 {阵营:[obj, ...], ...}
+        self.factionMainObjListDict = {} # 阵营所有战斗主体, {阵营:[obj, ...], ...}
+        self.objTotalHurtDict = {} # 战斗实例累计输出 {objID:totalHurtValue, ...}
+        self.factionTotalHurtDict = {} # 阵营累计输出 {faction:totalHurtValue, ...}
+        self.fbData = {} # 战斗关联副本自定义相关数据 {key:value, ...}
+        return
+    
+    def SetBattle(self, curPlayer, mapID, funcLineID, tagType, tagID, valueList):
+        self.curPlayer = curPlayer
+        self.mapID = mapID
+        self.funcLineID = funcLineID
+        self.tagType = tagType
+        self.tagID = tagID
+        self.valueList = valueList
+        return
+    
+    def SetFactionObj(self, faction, objList, mainObjList):
+        self.factionObjListDict[faction] = objList
+        self.factionMainObjListDict[faction] = mainObjList
+        return
+    
+    def GetTagMainObj(self):
+        ## 获取对方战斗主体
+        if Def_FactionB not in self.factionMainObjListDict:
+            return
+        mainObjList = self.factionMainObjListDict[Def_FactionB]
+        if not mainObjList:
+            return
+        return mainObjList[0]
+    
+    def AddObjHurtValue(self, curObj, hurtValue):
+        objID = curObj.GetID()
+        faction = GameObj.GetFaction(curObj)
+        updHurtValue = self.objTotalHurtDict.get(objID, 0) + hurtValue
+        self.objTotalHurtDict[objID] = updHurtValue
+        
+        factionHurtValue = self.factionTotalHurtDict.get(faction, 0) + hurtValue
+        self.factionTotalHurtDict[faction] = factionHurtValue
+        
+        # 玩家阵营
+        if faction == Def_FactionA:
+            FBLogic.OnTurnFightPlayerFactionHurt(self.curPlayer, self.mapID, self.funcLineID, curObj, hurtValue, factionHurtValue)
+        return updHurtValue
+    
+g_turnFightBattle = TurnFightBattle()
+def GetTurnFightBattle():
+    global g_turnFightBattle
+    return g_turnFightBattle
+
 def GetObjName(gameObj):
     objName = gameObj.GetName()
     faction = GameObj.GetFaction(gameObj)
@@ -61,7 +127,7 @@
     curID = gameObj.GetDictByKey(ChConfig.Def_NPC_Dict_MirrorPlayerID)
     if not curID and gameObj.GetGameObjType() == IPY_GameWorld.gotNPC:
         curID = gameObj.GetNPCID()
-    return "%s%s %s[%s-%s]" % ("A" if faction == 1 else "B", fightPlaceNum, objName, gameObj.GetID(), curID)
+    return "%s%s %s[%s-%s]" % ("A" if faction == Def_FactionA else "B", fightPlaceNum, objName, gameObj.GetID(), curID)
 
 #// B4 10 回合制战斗 #tagCMTurnFight
 #
@@ -178,62 +244,12 @@
         factionInfoB = {"npcID":npcID, "pet":petCacheInfo, "skillIDExList":skillIDExList}
     else:
         return
-        
-    fightRet = ProcessAutoTurnFight(mapID, funcLineID, tagType, tagID, factionInfoA, factionInfoB, tick, curPlayer)
-    if not fightRet:
-        return
-    isWin, turnNum, turnMax, factionTotalHurtDict, playbackID = fightRet
     
-    needSendGameServer, awardItemList, overInfoEx = False, [], {}
-    overRet = FBLogic.OnTurnFightOver(curPlayer, mapID, funcLineID, tagType, tagID, valueList, fightRet)
-    if overRet != None:
-        needSendGameServer, awardItemList, overInfoEx = overRet
-        
-    if needSendGameServer or mapID in ChConfig.Def_TFMapID_SendToGameServer:
-        SendToGameServer_TurnFight(curPlayer, "TurnFightOver", [mapID, funcLineID, tagType, tagID, valueList, fightRet, awardItemList])
-        
-    overMsg = {"isWin":isWin, FBCommon.Over_itemInfo:FBCommon.GetJsonItemList(awardItemList), "totalHurt":factionTotalHurtDict.get(1, 0)}
-    playbackID and overMsg.update({"playbackID":playbackID})
-    overInfoEx and overMsg.update(overInfoEx)
-    SyncTurnFightState(curPlayer, mapID, funcLineID, tagType, tagID, FightState_Award, turnNum, turnMax, overMsg)
-    return
-
-def GetPlayerFactionInfoByCache(playerID):
-    ## 根据玩家缓存数据获取对阵玩家阵营信息字典
-    PropDict, PlusDict = PlayerViewCacheTube.GetPlayerPropPlusDictByID(playerID, True) # 从缓存中获取,强刷一次最新属性
-    skillIDList = []
-    SkillInfo = PlusDict.get("SkillInfo", {})
-    for _, skillLVDict in SkillInfo.items():
-        for skillID, _ in skillLVDict.items():
-            skillID = GameWorld.ToIntDef(skillID)
-            skillData = GameWorld.GetGameData().GetSkillBySkillID(skillID)
-            if not skillData:
-                continue
-            skillIDList.append(skillID)
-    return {"playerID":playerID, "pet":PlusDict.get("Pet"), "skillIDList":skillIDList, "ModelMark":PropDict.get("ModelMark", 0)}
-
-def ProcessAutoTurnFight(mapID, funcLineID, tagType, tagID, factionInfoA, factionInfoB, tick, syncPlayer=None, isSavePlayback=False):
-    ''' 处理自动回合战斗过程,仅做战斗流程处理,不做及其他功能逻辑
-    @param mapID: 可视为功能ID
-    @param funcLineID: 对功能ID的扩展
-    @param factionInfoA: A方阵营信息,playerID 和 npcID 二选一 {"playerID":主体玩家镜像ID, "npcID":主体NPCID, "pet":[{出战灵宠信息兼容玩家缓存的灵宠信息k:v, ...}, ...]}
-    @param factionInfoB: B方阵营信息
-    @param syncPlayer: 需要通知的玩家,可能为None,注意仅做通知用,该玩家可能和AB阵营无任何关系
-    @param isSavePlayback: 是否保存战斗回放
-    @return: None-无结果;或 (isWin, turnNum, turnMax, factionTotalHurtDict)
-                        isWin: 是否获胜
-                        turnNum: 打了几回合
-                        factionTotalHurtDict: 双方伤血统计
-    '''
-    if syncPlayer:
-        syncPlayer.SetCanAttack(False) # 该玩家设置为不可被攻击
-        playerID = syncPlayer.GetPlayerID()
-        sightLevel, posX, posY = playerID, syncPlayer.GetPosX(), syncPlayer.GetPosY()
-    else:
-        playerID = 0
-        sightLevel, posX, posY = 99, 192, 109 # 系统默认处理的层级及坐标
-        
-    factionA, factionB, mainRolePlace = 1, 2, 1
+    curPlayer.SetCanAttack(False) # 该玩家设置为不可被攻击
+    playerID = curPlayer.GetPlayerID()
+    sightLevel, posX, posY = playerID, curPlayer.GetPosX(), curPlayer.GetPosY()
+    
+    factionA, factionB, mainRolePlace = Def_FactionA, Def_FactionB, 1
     objRetA = __SummonFactionObjs(factionA, mainRolePlace, factionInfoA, sightLevel, posX, posY)
     objRetB = __SummonFactionObjs(factionB, mainRolePlace, factionInfoB, sightLevel, posX, posY)
     objA, petObjListA, factionSyncInfoA = objRetA if objRetA else (None, [], {})
@@ -243,6 +259,11 @@
         for gameObj in fightObjList:
             TurnFightObjOverReset(gameObj, tick)
         return
+    
+    tfBattle = GetTurnFightBattle()
+    tfBattle.CleaerBat()
+    tfBattle.SetBattle(curPlayer, mapID, funcLineID, tagType, tagID, valueList)
+    
     playerIDA = objA.GetDictByKey(ChConfig.Def_NPC_Dict_MirrorPlayerID) # 可能为0,非玩家镜像时为0
     playerIDB = objB.GetDictByKey(ChConfig.Def_NPC_Dict_MirrorPlayerID) # 可能为0,非玩家镜像时为0
     
@@ -255,6 +276,8 @@
     factionListA = petObjListA + [objA]
     factionListB = petObjListB + [objB]
     atkFactionList = [factionListA, factionListB]
+    tfBattle.SetFactionObj(factionA, factionListA, [objA])
+    tfBattle.SetFactionObj(factionB, factionListB, [objB])
     
     # 设置战斗主体
     objA.SetDict(ChConfig.Def_Obj_Dict_TurnEnemyID, objB.GetID())
@@ -266,8 +289,8 @@
             if not gameObj:
                 continue
             faction = GameObj.GetFaction(gameObj)
-            tagGameObj = objB if faction == 1 else objA
-            TurnFightObjStartInit(playerID, gameObj, tagGameObj, tick)
+            tagGameObj = objB if faction == Def_FactionA else objA
+            TurnFightObjStartInit(mapID, playerID, gameObj, tagGameObj, tick)
             
     #一个回合攻击顺序,为了后续逻辑统一,都是先确定好顺序
     sortType = 2 # 攻击顺序排序方式
@@ -284,19 +307,19 @@
             for factionObjList in atkFactionList:
                 fightObjList.append(factionObjList[i])
                 
-    SyncTurnFightState(syncPlayer, mapID, funcLineID, tagType, tagID, FightState_PrepareOK, msg=[factionSyncInfoA, factionSyncInfoB])
+    SyncTurnFightState(curPlayer, mapID, funcLineID, tagType, tagID, FightState_PrepareOK, msg=[factionSyncInfoA, factionSyncInfoB])
     
     isWin = None
     for turnNum in range(1, turnMax + 1):
         GameWorld.DebugLog("【----- 回合制战斗轮次: %s -----】" % turnNum)
-        SyncTurnFightState(syncPlayer, mapID, funcLineID, tagType, tagID, FightState_Fighting, turnNum, turnMax)
+        SyncTurnFightState(curPlayer, mapID, funcLineID, tagType, tagID, FightState_Fighting, turnNum, turnMax)
         
         # 回合开始: 做一些每回合重置逻辑或者某些根据回合触发的效果等
         for gameObj in fightObjList:
             if not gameObj:
                 continue
             faction = GameObj.GetFaction(gameObj)
-            tagGameObj = objB if faction == 1 else objA
+            tagGameObj = objB if faction == Def_FactionA else objA
             TurnFightObjPerTurnStart(gameObj, tagGameObj, turnNum, tick)
             
         isWin = CheckIswin(objA, objB)
@@ -314,7 +337,7 @@
                 
             objType = gameObj.GetGameObjType()
             objID = gameObj.GetID()
-            SyncTurnFightObjAction(syncPlayer, turnNum, objType, objID)
+            SyncTurnFightObjAction(curPlayer, turnNum, objType, objID)
             
             if GameObj.GetHP(gameObj) <= 0:
                 # 复活时机在自己行动节点
@@ -325,7 +348,7 @@
             objName = GetObjName(gameObj)
             curHP = GameObj.GetHP(gameObj)
             
-            tagGameObj = objB if faction == 1 else objA
+            tagGameObj = objB if faction == Def_FactionA else objA
             tagObjType = tagGameObj.GetGameObjType()
             tagObjID = tagGameObj.GetID()
             tagHP = GameObj.GetHP(tagGameObj)
@@ -343,20 +366,19 @@
         if isWin != None:
             break
         
+    isWin = FBLogic.OnTurnFightIsWin(curPlayer, mapID, funcLineID, tagType, tagID, valueList, isWin)
     GameWorld.DebugLog("--- 战斗结束处理 --- isWin=%s" % isWin)
     isWin = 1 if isWin else 0
     
     # 统计总伤害
-    factionTotalHurtDict = {}
+    factionTotalHurtDict = tfBattle.factionTotalHurtDict
     for gameObj in fightObjList:
         if not gameObj:
             continue
         faction = GameObj.GetFaction(gameObj)
         objName = GetObjName(gameObj)
         objID = gameObj.GetID()
-        totalHurtEx = gameObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnTotalHurtEx) * ChConfig.Def_PerPointValue
-        totalHurt = gameObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnTotalHurt) + totalHurtEx
-        factionTotalHurtDict[faction] = factionTotalHurtDict.get(faction, 0) + totalHurt
+        totalHurt = tfBattle.objTotalHurtDict.get(objID, 0)
         GameWorld.DebugLog("%s objID=%s,faction=%s, 总输出: %s" % (objName, objID, faction, totalHurt))
     for faction, totalHurt in factionTotalHurtDict.items():
         GameWorld.DebugLog("faction=%s, 阵营总输出: %s" % (faction, totalHurt))
@@ -364,19 +386,51 @@
     GameWorld.DebugLog("A剩余血量: %s / %s" % (GameObj.GetHP(objA), GameObj.GetMaxHP(objA)))
     GameWorld.DebugLog("B剩余血量: %s / %s" % (GameObj.GetHP(objB), GameObj.GetMaxHP(objB)))
     
-    SyncTurnFightState(syncPlayer, mapID, funcLineID, tagType, tagID, FightState_FightEnd, turnNum, turnMax)
-    
-    for gameObj in fightObjList:
-        TurnFightObjOverReset(gameObj, tick)
+    SyncTurnFightState(curPlayer, mapID, funcLineID, tagType, tagID, FightState_FightEnd, turnNum, turnMax)
         
     playbackID = 0 # 战斗回放ID,可根据该ID查看回放
     #playbackInfo = "" # 战斗回放信息
-    if isSavePlayback:
-        pass
+    #if isSavePlayback:
+    #    pass
     
     GameWorld.DebugLog("===== 回合制战斗结束: mapID=%s,funcLineID=%s,playerIDA=%s,playerIDB=%s,isWin=%s" 
                        % (mapID, funcLineID, playerIDA, playerIDB, isWin))
-    return isWin, turnNum, turnMax, factionTotalHurtDict, playbackID
+    
+    # 战斗结束后处理
+    fightRet = [isWin, turnNum, turnMax, factionTotalHurtDict, playbackID]
+    
+    needSendGameServer, awardItemList, overInfoEx = False, [], {}
+    overRet = FBLogic.OnTurnFightOver(curPlayer, mapID, funcLineID, tagType, tagID, valueList, fightRet)
+    if overRet != None:
+        needSendGameServer, awardItemList, overInfoEx = overRet
+        
+    if needSendGameServer or mapID in ChConfig.Def_TFMapID_SendToGameServer:
+        SendToGameServer_TurnFight(curPlayer, "TurnFightOver", [mapID, funcLineID, tagType, tagID, valueList, fightRet, awardItemList])
+        
+    overMsg = {"isWin":isWin, FBCommon.Over_itemInfo:FBCommon.GetJsonItemList(awardItemList), "totalHurt":factionTotalHurtDict.get(Def_FactionA, 0)}
+    playbackID and overMsg.update({"playbackID":playbackID})
+    overInfoEx and overMsg.update(overInfoEx)
+    SyncTurnFightState(curPlayer, mapID, funcLineID, tagType, tagID, FightState_Award, turnNum, turnMax, overMsg)
+    
+    # 都处理完毕了,回收对象,重置数据
+    for gameObj in fightObjList:
+        TurnFightObjOverReset(gameObj, tick)
+    tfBattle.CleaerBat()
+    return
+
+def GetPlayerFactionInfoByCache(playerID):
+    ## 根据玩家缓存数据获取对阵玩家阵营信息字典
+    PropDict, PlusDict = PlayerViewCacheTube.GetPlayerPropPlusDictByID(playerID, True) # 从缓存中获取,强刷一次最新属性
+    skillIDList = []
+    SkillInfo = PlusDict.get("SkillInfo", {})
+    for _, skillLVDict in SkillInfo.items():
+        for skillID, _ in skillLVDict.items():
+            skillID = GameWorld.ToIntDef(skillID)
+            skillData = GameWorld.GetGameData().GetSkillBySkillID(skillID)
+            if not skillData:
+                continue
+            skillIDList.append(skillID)
+    return {"playerID":playerID, "pet":PlusDict.get("Pet"), "skillIDList":skillIDList, "ModelMark":PropDict.get("ModelMark", 0)}
 
 def __SummonFactionObjs(faction, mainRolePlace, objInfo, sightLevel, posX, posY):
     '''召唤阵营战斗实例
@@ -608,15 +662,14 @@
     gameObj.SetDict(ChConfig.Def_Obj_Dict_TurnFightTimeline, turnNum * 100 + actionNum)
     return
 
-def TurnFightObjStartInit(playerID, gameObj, tagObj, tick):
+def TurnFightObjStartInit(mapID, playerID, gameObj, tagObj, tick):
     ## 回合制战斗实例初始化
     if not gameObj:
         return
     mainRolePlace = gameObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnFightMainRolePlace)
+    gameObj.SetDict(ChConfig.Def_Obj_Dict_TurnFightMapID, mapID)
     gameObj.SetDict(ChConfig.Def_Obj_Dict_TurnFightID, playerID)
     gameObj.SetDict(ChConfig.Def_Obj_Dict_TurnRebornCount, 0)
-    gameObj.SetDict(ChConfig.Def_Obj_Dict_TurnTotalHurt, 0)
-    gameObj.SetDict(ChConfig.Def_Obj_Dict_TurnTotalHurtEx, 0)
     gameObj.SetDict(ChConfig.Def_Obj_Dict_TurnSkillSuccessPetState, 0)
     gameObj.SetDict(ChConfig.Def_Obj_Dict_TurnAttackOverPetState, 0)
     SetTimeline(gameObj, 1, 0)
@@ -839,15 +892,12 @@
 def AddTurnObjHurtValue(curObj, tagObj, hurtType, hurtValue, lostHP, curSkill=None):
     if not curObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnFightTimeline):
         return
+    tfBattle = GetTurnFightBattle()
     curID = curObj.GetID()
     tagID = tagObj.GetID()
     skillID = curSkill.GetSkillID() if curSkill else 0
-    totalHurtEx = curObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnTotalHurtEx) * ChConfig.Def_PerPointValue
-    totalHurt = curObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnTotalHurt) + totalHurtEx
     if curID != tagID:
-        totalHurt += hurtValue
-        curObj.SetDict(ChConfig.Def_Obj_Dict_TurnTotalHurt, totalHurt % ChConfig.Def_PerPointValue)
-        curObj.SetDict(ChConfig.Def_Obj_Dict_TurnTotalHurtEx, totalHurt / ChConfig.Def_PerPointValue)
+        totalHurt = tfBattle.AddObjHurtValue(curObj, hurtValue)
         GameWorld.DebugLog("        伤血: curTD=%s,tagID=%s,skillID=%s,hurtType=%s,hurtValue=%s,totalHurt=%s,lostHP=%s,tagHP=%s" 
                            % (curID, tagID, skillID, hurtType, hurtValue, totalHurt, lostHP, GameObj.GetHP(tagObj)))
     else:
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
index 26d88ef..23d19ad 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
@@ -1883,6 +1883,7 @@
 #回合战斗自定义地图ID
 Def_TFMapID_MineArea = 1 # 福地 1
 Def_TFMapID_Adventure = 5000 # 冒险
+Def_TFMapID_AlineInvade = 5010 # 异兽入侵
 
 #回合战斗自定义地图需要发送GameServer的列表
 Def_TFMapID_SendToGameServer = [Def_TFMapID_MineArea, Def_FBMapID_ArenaBattle]
@@ -2018,6 +2019,7 @@
                 'Love':[Def_FBMapID_Love],#情缘副本
                 'CrossBattlefield':[Def_FBMapID_CrossBattlefield], #跨服战场
                 'MineArea':[Def_TFMapID_MineArea], #福地
+                'AlineInvade':[Def_TFMapID_AlineInvade], #异兽入侵
                 'Adventure':[Def_TFMapID_Adventure], #冒险
                 }
 
@@ -3101,14 +3103,13 @@
 #---Obj字典-------
 Def_Obj_Dict_Faction = 'Faction' # 所属阵营
 Def_Obj_Dict_TurnFightID = 'TurnFightID' # 回合制战斗所属玩家ID
+Def_Obj_Dict_TurnFightMapID = 'TurnFightMapID' # 回合制战斗所属MapID
 Def_Obj_Dict_TurnFightTimeline = 'TurnFightTimeline' # 回合制战斗时间线: 回合数*100+行动编号节点
 Def_Obj_Dict_TurnFightMainRolePlace = 'TurnFightMainRolePlace' # 回合制战斗主体位置,可用于支持单阵营多主体,最终胜负由主体存活状态决定
 Def_Obj_Dict_TurnRebornCount = 'TurnRebornCount' # 回合战斗已复活次数
 Def_Obj_Dict_TurnComboNum = 'TurnComboNum' # 本回合已累计连击次数
 Def_Obj_Dict_TurnAtkBackNum = 'TurnAtkBackNum' # 本回合已累计反击次数
 Def_Obj_Dict_TurnBattleType = 'TurnBattleType' # 本次攻击战斗类型:TurnBattleType_xxx
-Def_Obj_Dict_TurnTotalHurt = 'TurnTotalHurt' # 本回合制战斗总伤害,求余亿部分
-Def_Obj_Dict_TurnTotalHurtEx = 'TurnTotalHurtEx' # 本回合制战斗总伤害,整除亿部分
 Def_Obj_Dict_FightPetPlaceNum = 'FightPetPlaceNum' # 出战灵宠上阵位置,1~n
 Def_Obj_Dict_FightPetQuality = 'FightPetQuality' # 出战灵宠品质
 Def_Obj_Dict_TurnEnemyID = 'TurnEnemyID' # 回合制战斗对手实例ID
@@ -4453,6 +4454,10 @@
 Def_PDict_MineTreasureState = "MineTreasureState" # 聚宝盆激活状态,按类型位运算记录是否已激活
 Def_PDict_MineTreasureAward = "MineTreasureAward" # 聚宝盆奖励状态,按类型位运算记录是否已领取
 Def_PDict_MineTreasureProgess = "MineTreasureProgess_%s" # 聚宝盆进度值,参数(聚宝盆类型)
+
+#异兽入侵
+Def_PDict_AlineInvadeHurtTotalEx = "AlineInvadeHurtTotalEx" #本日累计伤害,整除亿部分
+Def_PDict_AlineInvadeHurtTotal = "AlineInvadeHurtTotal" #本日累计伤害,求余亿部分
 #-------------------------------------------------------------------------------
 #可以从07 41封包购买的背包类型,和对应字典{背包类型:[字典key, 默认格子数]}
 
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBLogic.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBLogic.py
index 6e6480a..bf7e890 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBLogic.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBLogic.py
@@ -1263,6 +1263,22 @@
         return {}
     return ret
 
+def GetLogicMapID(curObj=None):
+    if curObj:
+        tfMapID = curObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnFightMapID)
+        if tfMapID:
+            return tfMapID
+    return GameWorld.GetMap().GetMapID()
+
+def CalcFBNPCPlusAttr(curNPC):
+    ## 副本NPC增加属性
+    # @return: 增加的属性信息 {attrID:value, ...}
+    do_FBLogic_ID = __GetFBLogic_MapID(GetLogicMapID(curNPC))
+    callFunc = GameWorld.GetExecFunc(FBProcess, "GameLogic_%s.%s" % (do_FBLogic_ID, "CalcFBNPCPlusAttr"))
+    if not callFunc:
+        return {}
+    return callFunc(curNPC)
+
 ## 获得副本LoadIng时间
 #  @param 占领人
 #  @param 被占领的NPC
@@ -2437,6 +2453,18 @@
     
     return callFunc(curPlayer, mapID, funcLineID, tagType, tagID, valueList)
 
+def OnTurnFightIsWin(curPlayer, mapID, funcLineID, tagType, tagID, valueList, isWin):
+    ## 回合战斗副本是否获胜
+    
+    do_FBLogic_ID = __GetFBLogic_MapID(mapID)
+    
+    callFunc = GameWorld.GetExecFunc(FBProcess, "GameLogic_%s.%s" % (do_FBLogic_ID, "OnTurnFightIsWin"))
+    
+    if callFunc == None:
+        return isWin
+    
+    return callFunc(curPlayer, mapID, funcLineID, tagType, tagID, valueList, isWin)
+
 def OnTurnFightOver(curPlayer, mapID, funcLineID, tagType, tagID, valueList, fightRet):
     ## 回合战斗结束
     # @return: 是否需要同步GameServer, 奖励列表, 同步结果信息
@@ -2462,4 +2490,16 @@
     
     return callFunc(curPlayer, mapID, funcLineID, tagType, tagID, valueList, fightRet, awardItemList, ret)
 
+def OnTurnFightPlayerFactionHurt(curPlayer, mapID, funcLineID, hurtObj, hurtValue, factionHurtValue):
+    ## 回合战斗玩家阵营伤害变更
+    
+    do_FBLogic_ID = __GetFBLogic_MapID(mapID)
+    
+    callFunc = GameWorld.GetExecFunc(FBProcess, "GameLogic_%s.%s" % (do_FBLogic_ID, "OnTurnFightPlayerFactionHurt"))
+    
+    if callFunc == None:
+        return
+    
+    return callFunc(curPlayer, mapID, funcLineID, hurtObj, hurtValue, factionHurtValue)
+
     
\ No newline at end of file
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_AlineInvade.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_AlineInvade.py
new file mode 100644
index 0000000..f0b1cd4
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_AlineInvade.py
@@ -0,0 +1,168 @@
+#!/usr/bin/python
+# -*- coding: GBK -*-
+#-------------------------------------------------------------------------------
+#
+##@package GameWorldLogic.FBProcess.GameLogic_AlineInvade
+#
+# @todo:异兽入侵
+# @author hxp
+# @date 2024-05-16
+# @version 1.0
+#
+# 详细描述: 异兽入侵
+#
+#-------------------------------------------------------------------------------
+#"""Version = 2024-05-16 16:00"""
+#-------------------------------------------------------------------------------
+
+import ChConfig
+import NPCCommon
+import TurnAttack
+import IpyGameDataPY
+import PlayerBillboard
+import ItemControler
+import PlayerControl
+import GameWorld
+import FBCommon
+
+def OnFBPlayerOnDay(curPlayer):
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_AlineInvadeHurtTotalEx, 0)
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_AlineInvadeHurtTotal, 0)
+    return
+
+def OnTurnFightRequest(curPlayer, mapID, funcLineID, tagType, tagID, valueList):
+    ## 回合战斗请求 - 地图验证
+    weekNPCIDList = IpyGameDataPY.GetFuncEvalCfg("AlineInvade", 1)
+    curTime = GameWorld.GetCurrentTime()
+    curWeekday = curTime.weekday()
+    bossID = weekNPCIDList[curWeekday % len(weekNPCIDList)]
+    if tagType != ChConfig.TurnBattle_TagType_NPC or tagID != bossID:
+        GameWorld.ErrLog("异兽入侵目标bossID错误,无法挑战! curWeekday=%s,bossID=%s,tagType=%s,tagID=%s" 
+                         % (curWeekday, bossID, tagType, tagID), curPlayer.GetPlayerID())
+        return False
+    return True
+
+def OnTurnFightPlayerFactionHurt(curPlayer, mapID, funcLineID, hurtObj, hurtValue, factionHurtValue):
+    ## 回合战斗玩家阵营伤害变更
+    
+    tfBattle = TurnAttack.GetTurnFightBattle()
+    fbData = tfBattle.fbData
+    
+    boxNum = fbData.get("boxNum", 0) # 当前盒子数
+    fbData["boxHurt"] = boxHurt = fbData.get("boxHurt", 0) + hurtValue # 当前盒子已累计伤害
+    
+    ipyData = IpyGameDataPY.GetIpyGameData("AlineInvade", boxNum)
+    if not ipyData:
+        return
+    needHurtValue = ipyData.GetNeedHurtValue()
+    
+    isBoxNumChange = False
+    if boxHurt >= needHurtValue:
+        isBoxNumChange = True
+        boxHurt = factionHurtValue
+        ipyDataMgr = IpyGameDataPY.IPY_Data()
+        for index in range(ipyDataMgr.GetAlineInvadeCount()):
+            ipyData = ipyDataMgr.GetAlineInvadeByIndex(index)
+            boxNum = ipyData.GetBoxNum()
+            needHurtValue = ipyData.GetNeedHurtValue()
+            if boxHurt >= needHurtValue:
+                boxHurt -= needHurtValue
+            else:
+                break
+            
+    fbData["boxNum"] = boxNum
+    fbData["boxHurt"] = boxHurt
+    fbData["totalHurt"] = factionHurtValue
+    
+    helpDict = {FBCommon.Over_dataMapID:tfBattle.mapID, FBCommon.Over_dataMapID:tfBattle.funcLineID}
+    helpDict.update(fbData)
+    FBCommon.Notify_FBHelp(curPlayer, helpDict)
+    
+    if not isBoxNumChange:
+        return
+    
+    tagNPC = tfBattle.GetTagMainObj()
+    if tagNPC:
+        GameWorld.DebugLog("boxNum变更: %s" % (boxNum))
+        NPCCommon.NPCControl(tagNPC).RefreshNPCAttrState()
+        
+    return
+
+def CalcFBNPCPlusAttr(curNPC):
+    ## 副本NPC增加属性
+    # @return: 增加的属性信息 {attrID:value, ...}
+    plusAttrDict = {}
+    tfBattle = TurnAttack.GetTurnFightBattle()
+    boxNum = tfBattle.fbData.get("boxNum", 0)
+    
+    ipyData = IpyGameDataPY.GetIpyGameData("AlineInvade", boxNum)
+    if ipyData:
+        plusAttrDict = ipyData.GetBossAttrPlusInfo()
+        
+    return plusAttrDict
+
+def OnTurnFightIsWin(curPlayer, mapID, funcLineID, tagType, tagID, valueList, isWin):
+    ## 回合战斗副本是否获胜
+    if isWin == False:
+        return isWin
+    # 只要不被击败就算赢
+    return True
+
+def OnTurnFightOver(curPlayer, mapID, funcLineID, tagType, tagID, valueList, fightRet):
+    ## 回合战斗结束
+    # @return: 是否需要同步GameServer, 奖励列表, 同步结果信息
+    needSendGameServer = False
+    isWin = fightRet[0]
+    
+    # 无论胜利与否都算参与,扣次数
+    FBCommon.OnFBJoin(curPlayer, mapID, funcLineID)
+    FBCommon.AddEnterFBCount(curPlayer, ChConfig.Def_TFMapID_AlineInvade)
+    
+    tfBattle = TurnAttack.GetTurnFightBattle()
+    fbData = tfBattle.fbData
+    
+    playerID = curPlayer.GetPlayerID()
+    GameWorld.DebugLog("异兽入侵结算: isWin=%s,fbData=%s" % (isWin, fbData), playerID)
+    boxNum = fbData.get("boxNum", 0) # 当前盒子数
+    totalHurt = fbData.get("totalHurt", 0) # 总伤害
+    
+    awardItemDict = {}
+    ipyDataMgr = IpyGameDataPY.IPY_Data()
+    for index in range(ipyDataMgr.GetAlineInvadeCount()):
+        ipyData = ipyDataMgr.GetAlineInvadeByIndex(index)
+        if boxNum < ipyData.GetBoxNum():
+            break
+        awardWeightList = ipyData.GetBoxAwardWeightList()
+        if not awardWeightList:
+            continue
+        awardItem = GameWorld.GetResultByWeightList(awardWeightList)
+        if not awardItem:
+            continue
+        itemID = awardItem[0]
+        itemCount = awardItem[1]
+        awardItemDict[itemID] = awardItemDict.get(itemID, 0) + itemCount
+        
+    isAuctionItem = 0
+    awardItemList = []
+    for itemID, itemCount in awardItemDict.items():
+        awardItemList.append([itemID, itemCount, isAuctionItem])
+    ItemControler.GivePlayerItemOrMail(curPlayer, awardItemList, event=["AlineInvade", False, {"boxNum":boxNum, "totalHurt":totalHurt}])
+    
+    # 同步本日累计伤害榜单
+    totalHurtTodayEx = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_AlineInvadeHurtTotalEx)
+    totalHurtToday = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_AlineInvadeHurtTotal)
+    totalHurtToday += totalHurtTodayEx * ChConfig.Def_PerPointValue
+    
+    updTotalHurtToday = totalHurtToday + totalHurt
+    updTotalHurtTodayEx = updTotalHurtToday / ChConfig.Def_PerPointValue
+    updTotalHurtToday = updTotalHurtToday % ChConfig.Def_PerPointValue
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_AlineInvadeHurtTotalEx, updTotalHurtTodayEx)
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_AlineInvadeHurtTotal, updTotalHurtToday)
+    GameWorld.DebugLog("更新今日累伤: totalHurtToday=%s,addHurt=%s,updTotalHurtTodayEx=%s,updTotalHurtToday=%s" 
+                       % (totalHurtToday, totalHurt, updTotalHurtTodayEx, updTotalHurtToday), playerID)
+    PlayerBillboard.UpdateAlineInvadeBillboard(curPlayer)
+    
+    overInfoEx = fbData
+    return needSendGameServer, awardItemList, overInfoEx
+
+
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
index 80a2fd5..13aeb13 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
@@ -2286,6 +2286,13 @@
                         ("list", "EquipColorRateList", 0),
                         ("list", "ExAwardItemRateList", 0),
                         ),
+
+                "AlineInvade":(
+                        ("BYTE", "BoxNum", 1),
+                        ("DWORD", "NeedHurtValue", 0),
+                        ("list", "BoxAwardWeightList", 0),
+                        ("dict", "BossAttrPlusInfo", 0),
+                        ),
                 }
 
 
@@ -5682,6 +5689,18 @@
     def GetLVUPNeedTime(self): return self.attrTuple[2] # 升级下一级所需所需秒 DWORD
     def GetEquipColorRateList(self): return self.attrTuple[3] # 产出装备品质概率列表,[0品质万分率, 1品质万分率, ...] list
     def GetExAwardItemRateList(self): return self.attrTuple[4] # 每次砍树概率额外产出道具饼图,[[万分率,[物品ID,个数]], ...] list
+
+# 异兽入侵
+class IPY_AlineInvade():
+    
+    def __init__(self):
+        self.attrTuple = None
+        return
+        
+    def GetBoxNum(self): return self.attrTuple[0] # 奖励盒子编号 BYTE
+    def GetNeedHurtValue(self): return self.attrTuple[1] # 下个盒子所需伤血 DWORD
+    def GetBoxAwardWeightList(self): return self.attrTuple[2] # 本盒子奖励权重饼图[[权重, [物品ID,个数,是否拍品]], ...] list
+    def GetBossAttrPlusInfo(self): return self.attrTuple[3] # Boss在该盒子情况下属性强化 dict
 
 
 def Log(msg, playerID=0, par=0):
@@ -5966,6 +5985,7 @@
         self.__LoadFileData("CustomAward", onlyCheck)
         self.__LoadFileData("Zhanling", onlyCheck)
         self.__LoadFileData("TreeLV", onlyCheck)
+        self.__LoadFileData("AlineInvade", onlyCheck)
         Log("IPY_DataMgr ReloadOK! onlyCheck=%s" % onlyCheck)
         return
     
@@ -7766,6 +7786,13 @@
     def GetTreeLVByIndex(self, index):
         self.CheckLoadData("TreeLV")
         return self.ipyTreeLVCache[index]
+
+    def GetAlineInvadeCount(self):
+        self.CheckLoadData("AlineInvade")
+        return self.ipyAlineInvadeLen
+    def GetAlineInvadeByIndex(self, index):
+        self.CheckLoadData("AlineInvade")
+        return self.ipyAlineInvadeCache[index]
 
 IPYData = IPY_DataMgr()
 def IPY_Data(): return IPYData
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCCommon.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCCommon.py
index 05fe156..ba0508d 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCCommon.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCCommon.py
@@ -77,6 +77,8 @@
 import GameObj
 import ChNPC
 import PassiveBuffEffMng
+import CalcNoLineEffect
+import CalcLineEffect
 
 import random
 import math
@@ -4157,6 +4159,19 @@
         else:
             DoNPCAttrStrengthen(curNPC, isReborn)
             
+        #其他功能属性
+        otherAttrList = [{} for _ in range(4)]
+        #副本增加属性
+        plusAttrDict = FBLogic.CalcFBNPCPlusAttr(curNPC)
+        for attrID, attrValue in plusAttrDict.items():
+            if not attrValue or not attrID:
+                continue
+            PlayerControl.CalcAttrDict_Type(attrID, attrValue, otherAttrList)
+        #GameWorld.DebugLog("NPC plusAttrDict=%s" % plusAttrDict)
+        #GameWorld.DebugLog("NPC otherAttrList=%s" % otherAttrList)
+        CalcNoLineEffect.ChangeNPCAttrInNoLineEffectList(curNPC, otherAttrList[ChConfig.CalcAttr_BattleNoline])
+        CalcLineEffect.ChangeNPCAttrInLineEffectList(curNPC, otherAttrList[ChConfig.CalcAttr_Battle])
+        
         #计算buf对战斗属性的改变
         allAttrList = SkillShell.CalcBuffer_NPCBattleEffect(curNPC)
         
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerBillboard.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerBillboard.py
index 256a2db..4d478b9 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerBillboard.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerBillboard.py
@@ -52,6 +52,7 @@
     
     if isAll:
         UpdateRuneTowerBillboard(curPlayer)
+        UpdateAlineInvadeBillboard(curPlayer)
         
         #UpdateTJGBillboard(curPlayer, minuteExp) 脱机效率可不更新
         
@@ -221,6 +222,14 @@
     UpdatePlayerBillboard(curPlayer, ShareDefine.Def_BT_TrialTower, passLV) 
     return
 
+def UpdateAlineInvadeBillboard(curPlayer):
+    ##更新异兽入侵排行榜
+    totalHurtTodayEx = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_AlineInvadeHurtTotalEx)
+    totalHurtToday = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_AlineInvadeHurtTotal)
+    if not totalHurtToday and not totalHurtTodayEx:
+        return
+    UpdatePlayerBillboard(curPlayer, ShareDefine.Def_BT_AlineInvade, totalHurtTodayEx, totalHurtToday)
+    return
 
 def UpdateTJGBillboard(curPlayer, minuteExp):
     ##脱机效率榜
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
index c6eed60..9a4be7d 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
@@ -809,9 +809,10 @@
     Def_BT_CharmWeek, #魅力周榜
     Def_BT_CharmDay, #魅力日榜
     Def_BT_BossTrialSubmit,                   #提交boss凭证榜 (boss历练活动)
+    Def_BT_AlineInvade,                       #异兽入侵
     
     Def_BT_Max, #排行榜最大类型
-) = range(0, 33 + 2) 
+) = range(0, 34 + 2) 
 
 ''' 跨服排行榜类型, 从 150 开始
 与本服榜单存储的是不一样的数据库表格,理论上类型可以和本服榜单类型重复,为了做下区分防误导,跨服榜单从 150 开始
@@ -1207,7 +1208,7 @@
 GameFuncID_FaQi = 199           # 法器
 GameFuncID_LianTi = 207         # 炼体
 GameFuncID_Championship = 210   # 排位
-GameFuncID_MineArea = 223   	# 福地
+GameFuncID_MineArea = 223       # 福地
 # 以下为暂时无用的
 GameFuncID_Truck = 33           # 运镖
 GameFuncID_RunDaily = 34        # 日常跑环

--
Gitblit v1.8.0