From 9b67e4335f655af8c8aef8aa1e7d41e509c50b76 Mon Sep 17 00:00:00 2001
From: hxp <ale99527@vip.qq.com>
Date: 星期五, 12 九月 2025 17:38:35 +0800
Subject: [PATCH] 129 【战斗】战斗系统-服务端(反击改为使用普攻,去除通用反击技能设定;武将特长支持;)

---
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/BattleObj.py                |    3 +
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py                   |    4 +
 PySysDB/PySysDBPY.h                                                                                    |    1 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/TurnAttack.py               |   11 +----
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/GameSkills/SkillCommon.py    |    4 --
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnSkill.py                 |   55 ++++++++++++++++++++++-----
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/AttackLogic/AttackCommon.py |   22 -----------
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py                        |   17 ++++++--
 8 files changed, 67 insertions(+), 50 deletions(-)

diff --git a/PySysDB/PySysDBPY.h b/PySysDB/PySysDBPY.h
index a59137e..c86794f 100644
--- a/PySysDB/PySysDBPY.h
+++ b/PySysDB/PySysDBPY.h
@@ -143,6 +143,7 @@
 	dict		BatAttrDict;	//其他战斗属性字典 {"属性ID":值, ...}
 	list		FetterIDList;	//羁绊ID列表
 	BYTE		RecruitBySelf;	// 招募需要本体
+	BYTE		Specialty;	// 武将特长
 };
 
 //武将星级天赋表
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/AttackLogic/AttackCommon.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/AttackLogic/AttackCommon.py
index ce0b1a0..f1d7758 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/AttackLogic/AttackCommon.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/AttackLogic/AttackCommon.py
@@ -433,28 +433,6 @@
     #NPC读表取
     return attack.GetHurtType()
 
-def GetAtkDistType(curObj):
-    ## 获取是近战还是远程,默认近战
-    if curObj.GetGameObjType() != IPY_GameWorld.gotNPC:
-        return ChConfig.AtkDistType_Short
-    
-    playerID = curObj.GetDictByKey(ChConfig.Def_Obj_Dict_LineupPlayerID)
-    if not playerID:
-        return ChConfig.AtkDistType_Short
-    
-    heroID = curObj.GetDictByKey(ChConfig.Def_Obj_Dict_HeroID)
-    if heroID:
-        heroIpyData = IpyGameDataPY.GetIpyGameData("Hero", heroID)
-        if heroIpyData:
-            return heroIpyData.GetAtkDistType()
-        
-    npcID = curObj.GetNPCID()
-    npcDataEx = NPCCommon.GetNPCDataPy(npcID)
-    if npcDataEx:
-        return npcDataEx.GetAtkDistType()
-    
-    return ChConfig.AtkDistType_Short
-
 #--------------------------------------------------------------------------
 ## 设置玩家进入战斗状态
 #  @param defender 当前玩家(被攻击了)
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/BattleObj.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/BattleObj.py
index b0984f2..483b08e 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/BattleObj.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/BattleObj.py
@@ -599,6 +599,7 @@
         self.skinID = 0
         self.country = 0
         self.atkDistType = 0
+        self.specialty = 0 # 特长
         self.sex = 0
         self.lv = 1
         self.fightPower = 0
@@ -668,6 +669,8 @@
     def SetCountry(self, country): self.country = country
     def GetAtkDistType(self): return self.atkDistType
     def SetAtkDistType(self, atkDistType): self.atkDistType = atkDistType
+    def GetSpecialty(self): return self.specialty
+    def SetSpecialty(self, specialty): self.specialty = specialty
     def GetSex(self): return self.sex
     def SetSex(self, sex): self.sex = sex
     def GetNPCID(self): return self.npcID # 如果是NPC战斗单位,则该值非0
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 18ffeee..ee92f50 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/TurnAttack.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/TurnAttack.py
@@ -728,11 +728,9 @@
     
     batObjMgr = BattleObj.GetBatObjMgr()
     initXP = IpyGameDataPY.GetFuncCfg("AngerXP", 1)
-    atkBackSkillIDList = IpyGameDataPY.GetFuncEvalCfg("ParryCfg", 2)
     for posNumKey, heroInfo in heroDict.items():
         posNum = int(posNumKey)
         
-        atkBackSkillID = 0 # 反击技能ID
         fightPower = 0
         skillIDList = [] # 战斗对象可能改变属性或技能,重新创建,防止误修改来源值
         attrDict = {}
@@ -744,6 +742,7 @@
         lv = heroInfo.get("LV", 1)
         heroIpyData = IpyGameDataPY.GetIpyGameData("Hero", heroID) if heroID else None
         if heroIpyData:
+            specialty = heroIpyData.GetSpecialty()
             atkDistType = heroIpyData.GetAtkDistType()
             objName = heroIpyData.GetName()
             country = heroIpyData.GetCountry()
@@ -759,6 +758,7 @@
             if not npcDataEx:
                 continue
             if not heroIpyData:
+                specialty = 0
                 atkDistType = npcDataEx.GetAtkDistType()
                 objName = npcDataEx.GetNPCName()
                 country = npcDataEx.GetCountry()
@@ -779,16 +779,11 @@
         batObj.SetFightPower(fightPower)
         batObj.SetLV(lv)
         batObj.SetAtkDistType(atkDistType)
+        batObj.SetSpecialty(specialty)
         batObj.SetCountry(country)
         batObj.SetSex(sex)
         batObj.SetHero(heroID, skinID)
         
-        if atkDistType == ChConfig.AtkDistType_Short:
-            atkBackSkillID = atkBackSkillIDList[0] if len(atkBackSkillIDList) > 0 else 0
-        elif atkDistType == ChConfig.AtkDistType_Long:
-            atkBackSkillID = atkBackSkillIDList[1] if len(atkBackSkillIDList) > 1 else 0
-        if atkBackSkillID:
-            skillIDList.append(atkBackSkillID)
         skillManager = batObj.GetSkillManager()
         skillManager.SkillReset()
         for skillID in skillIDList:
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
index 356ab3b..ad78879 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
@@ -960,9 +960,9 @@
 HurtType_3,
 HurtType_4,
 HurtType_Parry,             # 格挡 5
-HurtType_IgnoreDef,         # 无视防御 6
+HurtType_IgnoreDef,         # 无视防御/真实伤害 6
 HurtType_SuperHit,          # 暴击 7
-HurtType_8,
+HurtType_Stun,              # 击晕 8 仅算概率触发的击晕,技能额外击晕效果的不算
 HurtType_Miss,              # 闪避 9
 ) = range(10)
 
@@ -4979,8 +4979,7 @@
 Def_SkillFuncType_TurnNormaSkill,  #1 普攻技能
 Def_SkillFuncType_AngerSkill,  #2 怒气技能
 Def_SkillFuncType_PotentialSkill,  #3 潜能技能
-Def_SkillFuncType_AtkbackSkill,  #4 反击技能
-) = range(5)
+) = range(4)
 
 # MMO项目 - 先保留,重新定义从1000开始,后续可陆续删除
 (Def_SkillFuncType_Common, #0为通用技能
@@ -5028,6 +5027,16 @@
 AtkDistType_Long, # 远程
 ) = range(1, 1 + 2)
 
+# 武将特长
+HeroSpecialtyList = (
+HeroSpecialty_Stun,         # 击晕 1
+HeroSpecialty_SuperHit,     # 暴击 2
+HeroSpecialty_Combo,        # 连击 3
+HeroSpecialty_Miss,         # 闪避 4
+HeroSpecialty_Parry,        # 格挡 5
+HeroSpecialty_SuckHP,       # 吸血 6
+) = range(1, 1 + 6)
+
 # 经验倍率限制类型
 (
 ExpRateLimitType_Recover, # 资源找回
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
index a7b8e5e..ac11826 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
@@ -163,6 +163,7 @@
                         ("dict", "BatAttrDict", 0),
                         ("list", "FetterIDList", 0),
                         ("BYTE", "RecruitBySelf", 0),
+                        ("BYTE", "Specialty", 0),
                         ),
 
                 "HeroTalent":(
@@ -2736,7 +2737,8 @@
     def GetHPInheritPer(self): return self.attrTuple[11] # 生命继承 WORD
     def GetBatAttrDict(self): return self.attrTuple[12] # 其他战斗属性字典 {"属性ID":值, ...} dict
     def GetFetterIDList(self): return self.attrTuple[13] # 羁绊ID列表 list
-    def GetRecruitBySelf(self): return self.attrTuple[14] #  招募需要本体 BYTE
+    def GetRecruitBySelf(self): return self.attrTuple[14] #  招募需要本体 BYTE
+    def GetSpecialty(self): return self.attrTuple[15] #  武将特长 BYTE
 
 # 武将星级天赋表
 class IPY_HeroTalent():
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/GameSkills/SkillCommon.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/GameSkills/SkillCommon.py
index 5560b0a..93f395e 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/GameSkills/SkillCommon.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/GameSkills/SkillCommon.py
@@ -1860,10 +1860,6 @@
     ## 是否回合普攻技能,区别与无技能的普通A一下,该普攻同样可以有各种技能效果,只是他属于普攻
     return curSkill and curSkill.GetFuncType() == ChConfig.Def_SkillFuncType_TurnNormaSkill
 
-def isAtkbackSkill(curSkill):
-    ## 是否反击技能
-    return curSkill and curSkill.GetFuncType() == ChConfig.Def_SkillFuncType_AtkbackSkill
-
 ## 检查技能是否为被动技能, 用于控制不可释放技能
 def isPassiveSkill(curSkill):
     return curSkill.GetSkillType() in [ChConfig.Def_SkillType_Passive,
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnSkill.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnSkill.py
index a763895..c670c0e 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnSkill.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnSkill.py
@@ -605,6 +605,7 @@
     if CanCombo(curBatObj, tagObj):
         # 连击根据技能目标配置逻辑重新选择目标
         GameWorld.DebugLog("● %s 【连击】" % TurnAttack.GetObjName(curBatObj))
+        DoHeroSpecialty(turnFight, curBatObj, ChConfig.HeroSpecialty_Combo, useSkill.GetSkillID())
         OnUseSkill(turnFight, curBatObj, useSkill, batType=ChConfig.TurnBattleType_Combo)
         
     return
@@ -615,8 +616,9 @@
         return
     
     tagID = tagObj.GetID()
-    if tagObj.GetAtkDistType() != ChConfig.AtkDistType_Short:
-        GameWorld.DebugLog("非近战不可反击! tagID=%s" % tagID)
+    canAtkbackDictTypeList = IpyGameDataPY.GetFuncEvalCfg("ParryCfg", 2)
+    if tagObj.GetAtkDistType() not in canAtkbackDictTypeList:
+        GameWorld.DebugLog("该远近类型武将不可反击! tagID=%s,AtkDistType=%s not in %s" % (tagID, tagObj.GetAtkDistType(), canAtkbackDictTypeList))
         return
     
     canAtkBack = False
@@ -636,7 +638,7 @@
         useSkill = skillManager.GetSkillByIndex(index)
         if not useSkill:
             continue
-        if useSkill.GetFuncType() == ChConfig.Def_SkillFuncType_AtkbackSkill:
+        if useSkill.GetFuncType() == ChConfig.Def_SkillFuncType_TurnNormaSkill: # 使用普攻反击
             GameWorld.DebugLog("可以反击! tagID=%s" % tagID)
             return useSkill
     return
@@ -702,6 +704,7 @@
         TurnAttack.SetObjKilled(turnFight, curObj)
         
     # 统计伤血,可能单个技能对同一目标造成多次伤害
+    isSuperHit, isStun, isSuckHP = False, False, False
     missObjIDList = []
     for hurtObj in useSkill.GetHurtObjList():
         hurtObjID = hurtObj.GetObjID()
@@ -712,7 +715,23 @@
             __doSkillHurtAnger(tagObj, hurtObj.GetLostHP(), useSkill)
         if hurtObj.HaveHurtType(ChConfig.HurtType_Miss):
             missObjIDList.append(hurtObjID)
-            
+            DoHeroSpecialty(turnFight, tagObj, ChConfig.HeroSpecialty_Miss, relatedSkillID)
+        if hurtObj.HaveHurtType(ChConfig.HurtType_Parry):
+            DoHeroSpecialty(turnFight, tagObj, ChConfig.HeroSpecialty_Parry, relatedSkillID)
+        if hurtObj.HaveHurtType(ChConfig.HurtType_SuperHit):
+            isSuperHit = True
+        if hurtObj.HaveHurtType(ChConfig.HurtType_Stun):
+            isStun = True
+        if hurtObj.GetSuckHP() > 0:
+            isSuckHP = True
+    # 群攻只触发一次特长
+    if isSuperHit:
+        DoHeroSpecialty(turnFight, curObj, ChConfig.HeroSpecialty_SuperHit, relatedSkillID)
+    if isStun:
+        DoHeroSpecialty(turnFight, curObj, ChConfig.HeroSpecialty_Stun, relatedSkillID)
+    if isSuckHP:
+        DoHeroSpecialty(turnFight, curObj, ChConfig.HeroSpecialty_SuckHP, relatedSkillID)
+        
     # 结算副本相关的攻击结果,仅主动发起玩家阵容武将触发
     curPlayer = turnFight.curPlayer
     if curPlayer and curObj and curObj.GetOwnerID() == curPlayer.GetPlayerID():
@@ -784,7 +803,7 @@
     ## 技能释放者怒气相关
     if SkillCommon.isAngerSkill(useSkill):
         curBatObj.SetXP(0)
-    elif SkillCommon.isTurnNormalSkill(useSkill):
+    elif SkillCommon.isTurnNormalSkill(useSkill) and useSkill.GetBatType() == ChConfig.TurnBattleType_Normal:
         addXP = IpyGameDataPY.GetFuncCfg("AngerXP", 3)
         AddTurnFightXP(curBatObj, addXP, "skillID:%s" % useSkill.GetSkillID())
     return
@@ -812,6 +831,21 @@
     updXP = curXP + addXP
     gameObj.SetXP(updXP)
     GameWorld.DebugLog("        更新XP: curID=%s,curXP=%s,addXP=%s,updXP=%s,reason=%s" % (gameObj.GetID(), curXP, addXP, updXP, reason))
+    return
+
+def DoHeroSpecialty(turnFight, gameObj, specialty, relatedSkillID=0):
+    ## 执行武将特长
+    if gameObj.GetSpecialty() != specialty:
+        return
+    specialtyAddXPDict = IpyGameDataPY.GetFuncEvalCfg("AngerXP", 5, {})
+    if str(specialty) not in specialtyAddXPDict:
+        return
+    addXP = specialtyAddXPDict[str(specialty)]
+    curXP = gameObj.GetXP()
+    updXP = curXP + addXP
+    gameObj.SetXP(updXP, False)
+    GameWorld.DebugLog("        特长加XP: curID=%s,curXP=%s,addXP=%s,updXP=%s,特性=%s" % (gameObj.GetID(), curXP, addXP, updXP, specialty))
+    Sync_PropertyRefreshView(turnFight, gameObj, ChConfig.AttrID_XP, updXP, addXP, diffType=1, relatedSkillID=relatedSkillID)
     return
 
 def __DoCurSkillEff(turnFight, curObj, useSkill, missObjIDList):
@@ -999,7 +1033,6 @@
     skillID = curSkill.GetSkillID()
     isTurnNormalSkill = SkillCommon.isTurnNormalSkill(curSkill)
     isAngerSkill = SkillCommon.isAngerSkill(curSkill)
-    isAtkbackSkill = SkillCommon.isAtkbackSkill(curSkill)
     isDot = ("damageoftime" in kwargs)
     angerOverflow = 0 # 怒气溢出值
     
@@ -1028,12 +1061,12 @@
     
     #calcType = curSkill.GetCalcType() 目前暂时按攻击算伤害,之后可以扩展其他
     
-    isSuperHit, isParry = False, False
+    isSuperHit, isParry, isStun = False, False, False
     aSuperDamPer, dSuperDamPerDef = 0, 0
     if not isDot:
         isSuperHit = CanSuperHit(atkObj, defObj) # 是否暴击
         isParry = (isTurnNormalSkill and CanParry(atkObj, defObj)) # 是否格挡,仅针对普攻
-        CanStun(turnFight, atkObj, defObj, curSkill) # 是否击晕
+        isStun = CanStun(turnFight, atkObj, defObj, curSkill) # 是否击晕
         
     if isSuperHit:
         hurtTypes |= pow(2, ChConfig.HurtType_SuperHit)
@@ -1045,6 +1078,9 @@
         
     if ignoreDef:
         hurtTypes |= pow(2, ChConfig.HurtType_IgnoreDef)
+        
+    if isStun:
+        hurtTypes |= pow(2, ChConfig.HurtType_Stun)
         
     #参与运算的数值
     #rand = random.random()                #种子数 0~1
@@ -1101,9 +1137,6 @@
     elif isAngerSkill:
         hurtValue = eval(IpyGameDataPY.GetFuncCompileCfg("HurtFormula", 2))
         GameWorld.DebugLog("    怒气技能伤害=%s" % (hurtValue))
-    elif isAtkbackSkill:
-        hurtValue = eval(IpyGameDataPY.GetFuncCompileCfg("HurtFormula", 3))
-        GameWorld.DebugLog("    反击伤害=%s" % (hurtValue))
     else:
         hurtValue = eval(IpyGameDataPY.GetFuncCompileCfg("HurtFormula", 4))
         GameWorld.DebugLog("    其他伤害=%s" % (hurtValue))

--
Gitblit v1.8.0