From b0a1a6c78f4f7b3a2b83544b9e1bb664878179fc Mon Sep 17 00:00:00 2001
From: hxp <ale99527@vip.qq.com>
Date: 星期三, 07 一月 2026 19:26:40 +0800
Subject: [PATCH] 129 【战斗】战斗系统-服务端(支持查看NPC属性;)

---
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini               |    6 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py       |   60 ++++++++++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py   |  184 ++++++++++++++++++++++++++++++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/TurnAttack.py |   87 ++++++++++++++
 4 files changed, 333 insertions(+), 4 deletions(-)

diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
index 8419b3a..52ab244 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
@@ -1205,7 +1205,7 @@
 Writer = hxp
 Releaser = hxp
 RegType = 0
-RegisterPackCount = 3
+RegisterPackCount = 4
 
 PacketCMD_1=0xB4
 PacketSubCMD_1=0x10
@@ -1219,6 +1219,10 @@
 PacketSubCMD_3=0x14
 PacketCallFunc_3=OnTurnFightReportView
 
+PacketCMD_4=0xB4
+PacketSubCMD_4=0x16
+PacketCallFunc_4=OnViewNPCAttr
+
 ;仙树
 [PlayerTree]
 ScriptName = Player\PlayerTree.py
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 cc9639b..5829731 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/TurnAttack.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/TurnAttack.py
@@ -646,11 +646,12 @@
     lineupInfo = {"PlayerID":playerID, "FightPower":lineup.fightPower, "ShapeType":lineup.shapeType, "Hero":heroDict}
     return lineupInfo
 
-def GetNPCLineupInfo(lineupID, strongerLV=0, difficulty=0, isLog=True):
+def GetNPCLineupInfo(lineupID, strongerLV=0, difficulty=0, isLog=True, viewNPCID=0):
     ## 获取NPC阵容信息
     # @param lineupID: 阵容ID
     # @param npcLV: 成长NPC等级
     # @param difficulty: 成长NPC难度系数
+    # @param viewNPCID: 查看指定的NPCID,供前端查询NPC属性用
     # @return: 阵容全部信息json字典,前端通用格式    
     lineupInfo = GetGMTestNPCLineupInfo(lineupID, strongerLV, difficulty)
     if lineupInfo:
@@ -668,10 +669,14 @@
         npcID = getattr(ipyData, "GetPosNPCID%s" % posNum)()
         if not npcID:
             continue
+        if viewNPCID and viewNPCID != npcID:
+            continue
         battleDict = GetNPCBattleDict(ipyData, npcID, strongerLV, difficulty, isLog)
         if not battleDict:
             continue
         heroDict[str(posNum)] = battleDict
+        if viewNPCID:
+            break
         
     lineupInfo = {"NPCLineupID":lineupID, "Hero":heroDict, "BossID":bossID, "BossPosView":bossPosView}
     return lineupInfo
@@ -850,8 +855,8 @@
                   "SkinID":skinID,
                   "LV":npcLV,
                   "Star":star,
-                  #"BreakLV":breakLV,
-                  #"AwakeLV":awakeLV,
+                  "BreakLV":breakLV,
+                  "AwakeLV":awakeLV,
                   "AttrDict":{str(k):v for k, v in batAttrDict.items() if v > 0},
                   "SkillIDList":skillIDList,
                   }
@@ -2185,6 +2190,82 @@
     PlayerControl.NotifyCode(curPlayer, "FightReportExpired")
     return
 
+#// B4 16 查看NPC属性 #tagCSViewNPCAttr
+#
+#struct    tagCSViewNPCAttr
+#{
+#    tagHead        Head;
+#    DWORD        MapID;        // 自定义地图ID,可用于绑定战斗地图场景功能(如主线boss、爬塔、竞技场等)
+#    DWORD        FuncLineID;    // MapID对应的扩展值,如具体某个关卡等
+#    DWORD        ViewNPCID;    // 指定查看某个NPCID,发0则查看该关卡阵容所有NPC
+#};
+def OnViewNPCAttr(index, clientData, tick):
+    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+    mapID = clientData.MapID
+    funcLineID = clientData.FuncLineID
+    viewNPCID = clientData.ViewNPCID    
+    SyncLineupNPCAttr(curPlayer, mapID, funcLineID, viewNPCID)
+    return
+
+def SyncLineupNPCAttr(curPlayer, mapID, funcLineID, viewNPCID=0):
+    lineupIDList = []
+    strongerLV, difficulty = 0, 0
+    
+    if mapID == ChConfig.Def_FBMapID_MainBoss:
+        chapterID = funcLineID / 100
+        levelNum = funcLineID % 100
+        levelIpyData = IpyGameDataPY.GetIpyGameData("MainLevel", chapterID, levelNum)
+        if not levelIpyData:
+            return
+        lineupIDList = levelIpyData.GetBossLineupIDList() # Boss波阵容ID列表,小队1阵容ID|小队2阵容ID|...
+        strongerLV = levelIpyData.GetNPCLV()
+        difficulty = levelIpyData.GetDifficulty()
+        
+    else:
+        fbLineIpyData = FBCommon.GetFBLineIpyData(mapID, funcLineID)
+        if fbLineIpyData:
+            lineupIDList = fbLineIpyData.GetLineupIDList()
+            strongerLV = fbLineIpyData.GetNPCLV()
+            difficulty = fbLineIpyData.GetDifficulty()
+        else:
+            ret = FBLogic.GetFBNPCLineupInfo(curPlayer, mapID, funcLineID)
+            if not ret:
+                return
+            lineupIDList, strongerLV, difficulty = ret
+            
+    if not lineupIDList:
+        return
+    
+    npcAttrList = []
+    for lineupID in lineupIDList:
+        lineupInfo = GetNPCLineupInfo(lineupID, strongerLV, difficulty, False, viewNPCID=viewNPCID)
+        if not lineupInfo:
+            continue
+        heroDict = lineupInfo["Hero"]
+        for posNum, attrInfo in heroDict.items():
+            posNum = int(posNum)
+            npcAttr = ChPyNetSendPack.tagSCViewNPCAttr()
+            npcAttr.PosNum = posNum
+            npcAttr.NPCID = attrInfo["NPCID"]
+            npcAttr.HeroID = attrInfo["HeroID"]
+            npcAttr.LV = attrInfo["LV"]
+            npcAttr.Star = attrInfo["Star"]
+            npcAttr.BreakLV = attrInfo["BreakLV"]
+            npcAttr.AwakeLV = attrInfo["AwakeLV"]
+            npcAttr.AttrMsg = json.dumps(attrInfo["AttrDict"], ensure_ascii=False).replace(" ", "")
+            npcAttr.AttrLen = len(npcAttr.AttrMsg)
+            npcAttrList.append(npcAttr)
+    if not npcAttrList:
+        return
+    clientPack = ChPyNetSendPack.tagSCViewNPCAttrRet()
+    clientPack.MapID = mapID
+    clientPack.FuncLineID = funcLineID
+    clientPack.ViewNPCID = viewNPCID
+    clientPack.NPCAttrList = npcAttrList
+    clientPack.NPCCnt = len(clientPack.NPCAttrList)
+    NetPackCommon.SendFakePack(curPlayer, clientPack)
+    return
+
 def SyncTurnFightReport(curPlayer, guid, reprot):
     ## 通知完整战报
     clientPack = ChPyNetSendPack.tagSCTurnFightReport()
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
index 4aacc12..5345c6c 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetPack.py
@@ -15177,6 +15177,66 @@
 
 
 #------------------------------------------------------
+# B4 16 查看NPC属性 #tagCSViewNPCAttr
+
+class  tagCSViewNPCAttr(Structure):
+    _pack_ = 1
+    _fields_ = [
+                  ("Cmd", c_ubyte),
+                  ("SubCmd", c_ubyte),
+                  ("MapID", c_int),    # 自定义地图ID,可用于绑定战斗地图场景功能(如主线boss、爬塔、竞技场等)
+                  ("FuncLineID", c_int),    # MapID对应的扩展值,如具体某个关卡等
+                  ("ViewNPCID", c_int),    # 指定查看某个NPCID,发0则查看该关卡阵容所有NPC
+                  ]
+
+    def __init__(self):
+        self.Clear()
+        self.Cmd = 0xB4
+        self.SubCmd = 0x16
+        return
+
+    def ReadData(self, stringData, _pos=0, _len=0):
+        self.Clear()
+        memmove(addressof(self), stringData[_pos:], self.GetLength())
+        return _pos + self.GetLength()
+
+    def Clear(self):
+        self.Cmd = 0xB4
+        self.SubCmd = 0x16
+        self.MapID = 0
+        self.FuncLineID = 0
+        self.ViewNPCID = 0
+        return
+
+    def GetLength(self):
+        return sizeof(tagCSViewNPCAttr)
+
+    def GetBuffer(self):
+        return string_at(addressof(self), self.GetLength())
+
+    def OutputString(self):
+        DumpString = '''// B4 16 查看NPC属性 //tagCSViewNPCAttr:
+                                Cmd:%s,
+                                SubCmd:%s,
+                                MapID:%d,
+                                FuncLineID:%d,
+                                ViewNPCID:%d
+                                '''\
+                                %(
+                                self.Cmd,
+                                self.SubCmd,
+                                self.MapID,
+                                self.FuncLineID,
+                                self.ViewNPCID
+                                )
+        return DumpString
+
+
+m_NAtagCSViewNPCAttr=tagCSViewNPCAttr()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagCSViewNPCAttr.Cmd,m_NAtagCSViewNPCAttr.SubCmd))] = m_NAtagCSViewNPCAttr
+
+
+#------------------------------------------------------
 # B5 18 拍卖行修改关注物品 #tagCGAttentionAuctionItemChange
 
 class  tagCGAttentionAuctionItemChange(Structure):
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
index 7763c91..c144fc7 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
@@ -38649,6 +38649,190 @@
 
 
 #------------------------------------------------------
+# B4 32 查看NPC属性结果 #tagSCViewNPCAttrRet
+
+class  tagSCViewNPCAttr(Structure):
+    PosNum = 0    #(BYTE PosNum)// 在本阵容中的站位,从1开始
+    NPCID = 0    #(DWORD NPCID)// 战斗NPCID,不同的实例ID对应的NPCID可能一样
+    HeroID = 0    #(DWORD HeroID)// 武将ID,玩家或NPC均可能有,如果有值则外观相关以该武将为准,否则以NPCID为准
+    LV = 0    #(WORD LV)// 等级,玩家的武将等级或NPC成长等级,等级显示以该值为准
+    Star = 0    #(BYTE Star)// 星级
+    BreakLV = 0    #(BYTE BreakLV)// 突破
+    AwakeLV = 0    #(BYTE AwakeLV)// 觉醒
+    AttrLen = 0    #(WORD AttrLen)
+    AttrMsg = ""    #(String AttrMsg)// 属性信息 {"属性ID":value, ...}
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        self.PosNum,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.NPCID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.HeroID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.LV,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        self.Star,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.BreakLV,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.AwakeLV,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        self.AttrLen,_pos = CommFunc.ReadWORD(_lpData, _pos)
+        self.AttrMsg,_pos = CommFunc.ReadString(_lpData, _pos,self.AttrLen)
+        return _pos
+
+    def Clear(self):
+        self.PosNum = 0
+        self.NPCID = 0
+        self.HeroID = 0
+        self.LV = 0
+        self.Star = 0
+        self.BreakLV = 0
+        self.AwakeLV = 0
+        self.AttrLen = 0
+        self.AttrMsg = ""
+        return
+
+    def GetLength(self):
+        length = 0
+        length += 1
+        length += 4
+        length += 4
+        length += 2
+        length += 1
+        length += 1
+        length += 1
+        length += 2
+        length += len(self.AttrMsg)
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteBYTE(data, self.PosNum)
+        data = CommFunc.WriteDWORD(data, self.NPCID)
+        data = CommFunc.WriteDWORD(data, self.HeroID)
+        data = CommFunc.WriteWORD(data, self.LV)
+        data = CommFunc.WriteBYTE(data, self.Star)
+        data = CommFunc.WriteBYTE(data, self.BreakLV)
+        data = CommFunc.WriteBYTE(data, self.AwakeLV)
+        data = CommFunc.WriteWORD(data, self.AttrLen)
+        data = CommFunc.WriteString(data, self.AttrLen, self.AttrMsg)
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                PosNum:%d,
+                                NPCID:%d,
+                                HeroID:%d,
+                                LV:%d,
+                                Star:%d,
+                                BreakLV:%d,
+                                AwakeLV:%d,
+                                AttrLen:%d,
+                                AttrMsg:%s
+                                '''\
+                                %(
+                                self.PosNum,
+                                self.NPCID,
+                                self.HeroID,
+                                self.LV,
+                                self.Star,
+                                self.BreakLV,
+                                self.AwakeLV,
+                                self.AttrLen,
+                                self.AttrMsg
+                                )
+        return DumpString
+
+
+class  tagSCViewNPCAttrRet(Structure):
+    Head = tagHead()
+    MapID = 0    #(DWORD MapID)// 自定义地图ID,可用于绑定战斗地图场景功能(如主线关卡、主线boss、爬塔、竞技场等)
+    FuncLineID = 0    #(DWORD FuncLineID)// MapID对应的扩展值,如具体某个关卡等
+    ViewNPCID = 0    #(DWORD ViewNPCID)// 指定查看某个NPCID,发0则查看该关卡阵容所有NPC
+    NPCCnt = 0    #(BYTE NPCCnt)
+    NPCAttrList = list()    #(vector<tagSCViewNPCAttr> NPCAttrList)
+    data = None
+
+    def __init__(self):
+        self.Clear()
+        self.Head.Cmd = 0xB4
+        self.Head.SubCmd = 0x32
+        return
+
+    def ReadData(self, _lpData, _pos=0, _Len=0):
+        self.Clear()
+        _pos = self.Head.ReadData(_lpData, _pos)
+        self.MapID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.FuncLineID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.ViewNPCID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
+        self.NPCCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos)
+        for i in range(self.NPCCnt):
+            temNPCAttrList = tagSCViewNPCAttr()
+            _pos = temNPCAttrList.ReadData(_lpData, _pos)
+            self.NPCAttrList.append(temNPCAttrList)
+        return _pos
+
+    def Clear(self):
+        self.Head = tagHead()
+        self.Head.Clear()
+        self.Head.Cmd = 0xB4
+        self.Head.SubCmd = 0x32
+        self.MapID = 0
+        self.FuncLineID = 0
+        self.ViewNPCID = 0
+        self.NPCCnt = 0
+        self.NPCAttrList = list()
+        return
+
+    def GetLength(self):
+        length = 0
+        length += self.Head.GetLength()
+        length += 4
+        length += 4
+        length += 4
+        length += 1
+        for i in range(self.NPCCnt):
+            length += self.NPCAttrList[i].GetLength()
+
+        return length
+
+    def GetBuffer(self):
+        data = ''
+        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
+        data = CommFunc.WriteDWORD(data, self.MapID)
+        data = CommFunc.WriteDWORD(data, self.FuncLineID)
+        data = CommFunc.WriteDWORD(data, self.ViewNPCID)
+        data = CommFunc.WriteBYTE(data, self.NPCCnt)
+        for i in range(self.NPCCnt):
+            data = CommFunc.WriteString(data, self.NPCAttrList[i].GetLength(), self.NPCAttrList[i].GetBuffer())
+        return data
+
+    def OutputString(self):
+        DumpString = '''
+                                Head:%s,
+                                MapID:%d,
+                                FuncLineID:%d,
+                                ViewNPCID:%d,
+                                NPCCnt:%d,
+                                NPCAttrList:%s
+                                '''\
+                                %(
+                                self.Head.OutputString(),
+                                self.MapID,
+                                self.FuncLineID,
+                                self.ViewNPCID,
+                                self.NPCCnt,
+                                "..."
+                                )
+        return DumpString
+
+
+m_NAtagSCViewNPCAttrRet=tagSCViewNPCAttrRet()
+ChNetPackDict[eval("0x%02x%02x"%(m_NAtagSCViewNPCAttrRet.Head.Cmd,m_NAtagSCViewNPCAttrRet.Head.SubCmd))] = m_NAtagSCViewNPCAttrRet
+
+
+#------------------------------------------------------
 # B5 04 拍卖行新上架拍品 #tagGCAddAuctionItemInfo
 
 class  tagGCAddAuctionItem(Structure):

--
Gitblit v1.8.0