From 986730e2725816f2eb9ad6fd645c513de931aa41 Mon Sep 17 00:00:00 2001
From: hxp <ale99527@vip.qq.com>
Date: 星期三, 21 一月 2026 11:52:04 +0800
Subject: [PATCH] 129 【战斗】战斗系统-服务端(命格技能七杀、皇灵、贪狼、司命、破军、天机;增加绝对闪避及抗性属性 81 82;格挡buff支持层级;)

---
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnSkill.py |  399 +++++++++++++++++++++++++++++++++++++++++++++++---------
 1 files changed, 330 insertions(+), 69 deletions(-)

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 019e82f..3636b76 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnSkill.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnSkill.py
@@ -38,6 +38,11 @@
     ght = useSkill.GetHurtType() % 10
     if ght == IPY_GameWorld.ghtMag: # 做配置兼容用,优先验证法伤,否则默认物伤
         return IPY_GameWorld.ghtMag
+    if ght == 3: # 由触发的技能决定
+        bySkill = useSkill.GetBySkill()
+        if bySkill:
+            #GameWorld.DebugLogEx("物法类型取触发的技能: useSkillID=%s,bySkillID=%s", useSkill.GetSkillID(), bySkill.GetSkillID())
+            return GetPMType(batObj, bySkill)
     return IPY_GameWorld.ghtPhy
 
 def IsIgnoreDef(useSkill):
@@ -60,6 +65,19 @@
         return
     
     skillType = useSkill.GetSkillType()
+    byBatObj = kwargs.pop("byBatObj", None)
+    if useSkill.GetFuncType() == ChConfig.Def_SkillFuncType_MinggeSkill:
+        if useSkill.GetSkillType() in ChConfig.Def_HurtSkill_List:
+            if not byBatObj:
+                return
+            GameWorld.DebugLogEx("命格攻击类技能施法方算触发者! mgObjID=%s,byObjID=%s,skillID=%s", curBatObj.GetID(), byBatObj.GetID(), skillID)
+            curBatObj = byBatObj
+        else:
+            # 因为命格攻击类技能修改了施法者,后续如果有子技能触发会变成还是变更后的施法者,导致命格全体buff可能存在多个施法来源,可能导致bug
+            batLineup = curBatObj.GetTFBatLineup()
+            curBatObj = batLineup.getMinggeObj()
+            GameWorld.DebugLogEx("命格非攻击类技能强制施法者为命格自己! mgObjID=%s,skillID=%s", curBatObj.GetID(), skillID)
+            
     byTriggerWay = kwargs["byTriggerWay"] if "byTriggerWay" in kwargs else 0 # 不使用参数名 triggerWay, 防止传递过程中参数混乱
     if not curBatObj.IsAlive():
         if skillType == ChConfig.Def_SkillType_Revive:
@@ -86,7 +104,7 @@
             GameWorld.DebugLogEx("技能使用处于buff状态限制中! skillID=%s,buffStateGroups=%s,limitState=%s", skillID, buffStateGroups, limitState)
             return
         
-    if CheckSkillUseCntLimit(curBatObj, useSkill):
+    if CheckSkillUseCntLimit(turnFight, curBatObj, useSkill):
         return
     
     #没有指定目标,则按技能自身的目标逻辑
@@ -145,8 +163,8 @@
     angerOverflow = curBatObj.GetAngerOverflow()
     
     bySkillID = bySkill.GetSkillID() if bySkill else 0
-    GameWorld.DebugLogEx("◆使用技能: curID=%s,skillID=%s,tagCnt=%s,batType=%s,bySkillID=%s,HP:%s/%s,angerOverflow=%s,curXP=%s,oneActionUseCnt=%s", 
-                         objID, skillID, len(tagObjList), batType, bySkillID, curBatObj.GetHP(), curBatObj.GetMaxHP(), angerOverflow, curXP, oneActionUseCnt)
+    GameWorld.DebugLogEx("◆使用技能: skillID=%s,curID=%s,tagCnt=%s,batType=%s,bySkillID=%s,HP:%s/%s,angerOverflow=%s,curXP=%s,oneActionUseCnt=%s", 
+                         skillID, objID, len(tagObjList), batType, bySkillID, curBatObj.GetHP(), curBatObj.GetMaxHP(), angerOverflow, curXP, oneActionUseCnt)
     # 以下为技能可以使用的处理,之后的逻辑默认技能使用成功
     
     if isinstance(useSkill, IpyGameDataPY.IPY_Skill):
@@ -158,6 +176,8 @@
     useSkill.SetBatType(batType)
     useSkill.SetBySkill(bySkill)
     useSkill.SetByBuff(byBuff)
+    # 注:理论上原先的 byFriendObj 都可以直接用这个,但是旧的代码先不修改了,后续的累计敌军、友军之类的触发可以统一使用 byBatObj
+    useSkill.SetByBatObj(kwargs.pop("byBatObj", None))
     useSkill.SetByTriggerWay(byTriggerWay)
     
     isTurnNormalSkill = SkillCommon.isTurnNormalSkill(useSkill)
@@ -185,7 +205,7 @@
     if SkillCommon.IsBuff(useSkill):
         __doAddBuff(turnFight, curBatObj, useSkill, **kwargs)
     else:
-        __doUseSkill(turnFight, curBatObj, useSkill)
+        __doUseSkill(turnFight, curBatObj, useSkill, **kwargs)
         
     DoAttackResult(turnFight, curBatObj, useSkill, **kwargs)
     
@@ -201,7 +221,7 @@
     useSkill.ResetUseRec()
     return True
 
-def CheckSkillUseCntLimit(batObj, useSkill):
+def CheckSkillUseCntLimit(turnFight, batObj, useSkill):
     ## 检查技能使用次数是否受限
     # @return: 是否受限,None-没有受限效果,False-不受限,True-受限了
     if not hasattr(useSkill, "GetEffectByID"):
@@ -214,12 +234,14 @@
     
     skillID = useSkill.GetSkillID()
     if useCntLimit:
+        useCntLimit += TurnPassive.GetTriggerEffectValue(turnFight, batObj, None, ChConfig.PassiveEff_AddSkillUseCntLimit, useSkill, LimitByTurnAll=1)
         useCnt = batObj.GetSkillUseCnt(skillID)
         if useCnt >= useCntLimit:
             GameWorld.DebugLogEx("技能每场战斗使用次数受限! skillID=%s,useCnt=%s >= %s", skillID, useCnt, useCntLimit)
             return True
         
     if turnUseCntLimit:
+        turnUseCntLimit += TurnPassive.GetTriggerEffectValue(turnFight, batObj, None, ChConfig.PassiveEff_AddSkillUseCntLimit, useSkill, LimitByTurnPer=1)
         turnUseCnt = batObj.GetSkillTurnUseCnt(skillID)
         if turnUseCnt >= turnUseCntLimit:
             GameWorld.DebugLogEx("技能每大回合使用次数受限! skillID=%s,turnUseCnt=%s >= %s", skillID, turnUseCnt, turnUseCntLimit)
@@ -376,13 +398,14 @@
                     colNumList.insert(0, specInColNum)
                     
             GameWorld.DebugLogEx("纵排: colNumList=%s,specObjID-PosNum=%s-%s", colNumList, specObjID, specObjPosNum)
+            posObjIDDict = batLineup.getPosObjIDDict()
             for col in colNumList:
                 for row in range(1, 1 + ChConfig.TurnFightRows):
                     pNum = (row - 1) * ChConfig.TurnFightCols + col
                     #GameWorld.DebugLogEx("    col=%s,row=%s,pNum=%s", col, row, pNum)
-                    if pNum not in batLineup.posObjIDDict:
+                    if pNum not in posObjIDDict:
                         continue
-                    tagObjID = batLineup.posObjIDDict[pNum]
+                    tagObjID = posObjIDDict[pNum]
                     tagBatObj = batObjMgr.getBatObj(tagObjID)
                     if not __skillTagFilter(curBatObj, tagBatObj, tagAffect, isNoSelf):
                         continue
@@ -401,13 +424,14 @@
                 
             GameWorld.DebugLogEx("全部: colNumList=%s,specObjID-PosNum=%s-%s", colNumList, specObjID, specObjPosNum)
             # 按前排优先原则
+            posObjIDDict = batLineup.getPosObjIDDict()
             for row in range(1, 1 + ChConfig.TurnFightRows):
                 for col in colNumList:
                     pNum = (row - 1) * ChConfig.TurnFightCols + col
                     #GameWorld.DebugLogEx("    col=%s,row=%s,pNum=%s", col, row, pNum)
-                    if pNum not in batLineup.posObjIDDict:
+                    if pNum not in posObjIDDict:
                         continue
-                    tagObjID = batLineup.posObjIDDict[pNum]
+                    tagObjID = posObjIDDict[pNum]
                     tagBatObj = batObjMgr.getBatObj(tagObjID)
                     if not __skillTagFilter(curBatObj, tagBatObj, tagAffect, isNoSelf):
                         continue
@@ -425,6 +449,11 @@
     if tagAffect == ChConfig.SkillTagAffect_HPLowest:
         aimObjList.sort(key=lambda o:(o.GetHP()), reverse=False)
         #GameWorld.DebugLogEx("血量最低排序: %s", [[o.GetID(), o.GetHP(), o.GetMaxHP()] for o in aimObjList])
+        
+    # 血量百分比最低
+    elif tagAffect == ChConfig.SkillTagAffect_HPPerLowest:
+        aimObjList.sort(key=lambda o:(o.GetHP() / float(o.GetMaxHP())), reverse=False)
+        #GameWorld.DebugLogEx("血量百分比最低排序: %s", [[o.GetID(), o.GetHP(), o.GetMaxHP(), o.GetHP() / float(o.GetMaxHP())] for o in aimObjList])
         
     # 血量最高
     elif tagAffect == ChConfig.SkillTagAffect_HPHighest:
@@ -534,7 +563,7 @@
     batObjMgr = BattleObj.GetBatObjMgr()
     for num in lineupNumList:
         batLineup = batFaction.getBatlineup(num)
-        for tagID in batLineup.posObjIDDict.values():
+        for tagID in batLineup.getBatHeroObjIDList():
             tagObj = batObjMgr.getBatObj(tagID)
             if tagObj.IsAlive() and tagObj.CheckInState(checkInStates):
                 return lineupNum, changeTagSet
@@ -570,19 +599,80 @@
         
     GameWorld.DebugLogEx("前后排: rowNumList=%s,colNumList=%s,specObjID-PosNum=%s-%s", rowNumList, colNumList, specObjID, specObjPosNum)
     aimObjList = []
+    posObjIDDict = batLineup.getPosObjIDDict()
     for row in rowNumList:
         for col in colNumList:
             pNum = (row - 1) * ChConfig.TurnFightCols + col
             #GameWorld.DebugLogEx("    row=%s,col=%s,pNum=%s", row, col, pNum)
-            if pNum not in batLineup.posObjIDDict:
+            if pNum not in posObjIDDict:
                 continue
-            tagObjID = batLineup.posObjIDDict[pNum]
+            tagObjID = posObjIDDict[pNum]
             tagBatObj = batObjMgr.getBatObj(tagObjID)
             if not __skillTagFilter(curBatObj, tagBatObj, tagAffect, isNoSelf):
                 continue
             aimObjList.append(tagBatObj)
         if aimObjList:
             break
+        
+    return aimObjList
+
+def __getSameRowObjList(tagObj):
+    ## 获取目标对应的同排对象列表,只算活着的
+    
+    posNum = tagObj.GetPosNum()
+    inRowNum = ChConfig.GetInRowNum(posNum)
+    inColNum = ChConfig.GetInColNum(posNum)
+    # 优先目标所在纵,为主目标
+    colNumList = range(1, 1 + ChConfig.TurnFightCols)
+    if inColNum in colNumList:
+        colNumList.remove(inColNum)
+        colNumList.insert(0, inColNum)
+        
+    row = inRowNum # 目标玩家所在横排
+    
+    batObjMgr = BattleObj.GetBatObjMgr()
+    batLineup = tagObj.GetTFBatLineup()
+    aimObjList = []
+    posObjIDDict = batLineup.getPosObjIDDict()
+    for col in colNumList:
+        pNum = (row - 1) * ChConfig.TurnFightCols + col
+        if pNum not in posObjIDDict:
+            continue
+        tagObjID = posObjIDDict[pNum]
+        tagBatObj = batObjMgr.getBatObj(tagObjID)
+        if not tagBatObj.IsAlive():
+            continue
+        aimObjList.append(tagBatObj)
+        
+    return aimObjList
+
+def __getSameColObjList(tagObj):
+    ## 获取目标对应的同列对象列表,只算活着的
+    
+    posNum = tagObj.GetPosNum()
+    inRowNum = ChConfig.GetInRowNum(posNum)
+    inColNum = ChConfig.GetInColNum(posNum)
+    
+    rowNumList = range(1, 1 + ChConfig.TurnFightRows)
+    if inRowNum in rowNumList:
+        rowNumList.remove(inRowNum)
+        rowNumList.insert(0, inRowNum)
+        
+    col = inColNum # 目标玩家所在纵排
+    
+    batObjMgr = BattleObj.GetBatObjMgr()
+    batLineup = tagObj.GetTFBatLineup()
+    aimObjList = []
+    posObjIDDict = batLineup.getPosObjIDDict()
+    for row in range(1, 1 + ChConfig.TurnFightRows):
+        pNum = (row - 1) * ChConfig.TurnFightCols + col
+        if pNum not in posObjIDDict:
+            continue
+        tagObjID = posObjIDDict[pNum]
+        tagBatObj = batObjMgr.getBatObj(tagObjID)
+        if not tagBatObj.IsAlive():
+            continue
+        aimObjList.append(tagBatObj)
         
     return aimObjList
 
@@ -630,12 +720,13 @@
         colNumList.insert(0, inColNum)
         
     # 按前排优先原则
+    posObjIDDict = batLineup.getPosObjIDDict()
     for row in range(ChConfig.TurnFightRows):
         for col in colNumList:
             pNum = row * ChConfig.TurnFightCols + col
-            if pNum not in batLineup.posObjIDDict:
+            if pNum not in posObjIDDict:
                 continue
-            tagObjID = batLineup.posObjIDDict[pNum]
+            tagObjID = posObjIDDict[pNum]
             tagBatObj = batObjMgr.getBatObj(tagObjID)
             if not __skillTagFilter(curBatObj, tagBatObj, tagAffect, isNoSelf=True):
                 continue
@@ -679,7 +770,7 @@
         
     return
 
-def __doUseSkill(turnFight, curBatObj, useSkill):
+def __doUseSkill(turnFight, curBatObj, useSkill, **kwargs):
     
     atkType = useSkill.GetAtkType()
     GameWorld.DebugLogEx("__doUseSkill: curID=%s,skillID=%s,atkType=%s", curBatObj.GetID(), useSkill.GetSkillID(), atkType)
@@ -689,7 +780,7 @@
     
     # 通用攻击
     if atkType == 1:
-        SkillModule_1(turnFight, curBatObj, useSkill)
+        SkillModule_1(turnFight, curBatObj, useSkill, **kwargs)
     # 治疗
     if atkType == 2:
         SkillModule_2(turnFight, curBatObj, useSkill)
@@ -784,7 +875,7 @@
     Sync_PropertyRefreshView(turnFight, curBatObj, ChConfig.AttrID_HP, updHP, diffValue, diffType, skillID, relatedSkillID, hurtTypes)
     return
 
-def SkillModule_1(turnFight, curBatObj, useSkill):
+def SkillModule_1(turnFight, curBatObj, useSkill, **kwargs):
     ## 通用攻击,单攻、群攻
     
     addPer = 0
@@ -800,7 +891,10 @@
             addPer = addPerMax
         GameWorld.DebugLogEx("司马懿特殊潜能技能额外增加比例: frozenCnt=%s,addPer=%s" % (frozenCnt, addPer))
         
-    addBatDamPer = TurnPassive.GetTriggerEffectValue(turnFight, curBatObj, None, ChConfig.PassiveEff_AddBatDamPerByLayer, useSkill)
+    addBatDamPer = 0
+    if "addBatDamPer" in kwargs:
+        addBatDamPer += kwargs.pop("addBatDamPer", 0)
+    addBatDamPer += TurnPassive.GetTriggerEffectValue(turnFight, curBatObj, None, ChConfig.PassiveEff_AddBatDamPerByLayer, useSkill)
     
     # 计算伤害
     calcHurtResults = []
@@ -1327,6 +1421,8 @@
     # 优先处理afterLogic,可再预先汇总一些会触发被动的信息
     relatedSkillID = useSkill.GetSkillID()
     delBuffAfterEffList = [] # buff消失后要触发的被动,一般用于后置处理的逻辑
+    beControlledHardDict = {} # 受控目标 {objID:buff, ...}
+    beDotBuffDict = {} # 被添加dot的目标 {objID:buff, ...}
     afterLogicList = useSkill.GetAfterLogicList()
     for logicType, logicData in afterLogicList:
         if logicType == ChConfig.AfterLogic_DelBuff:
@@ -1345,6 +1441,15 @@
             buff = logicData[1]
             TurnBuff.SyncBuffRefresh(turnFight, buffObj, buff, relatedSkillID)
             
+        # 统计添加buff需要触发的被动
+        elif logicType == ChConfig.AfterLogic_TriggerAddBuff:
+            triggerType, batObj, buff, buffOwner = logicData
+            if buffOwner.GetID() == curID:
+                if triggerType == ChConfig.TriggerWay_BeControlledHard:
+                    beControlledHardDict[batObj.GetID()] = buff
+                elif triggerType == ChConfig.TriggerWay_AddDOTBuff:
+                    beDotBuffDict[batObj.GetID()] = buff
+                    
     # 统计击杀
     killObjList = [] # 击杀其他阵营目标列表
     dieObjList = [] # 死亡的单位列表,包含友方单位或自己
@@ -1367,7 +1472,7 @@
     
     # 统计伤血,可能单个技能对同一目标造成多次伤害
     totalHurtValue = 0
-    isSuckHP = False
+    suckObjIDList = [] # 吸血的对象ID列表
     missObjIDList, immuneObjIDList = [], [] # 闪避、免疫对象ID列表
     stunObjIDList, superHitObjIDList, parryObjIDList = [], [], []
     beHurtObjIDList = [] # 受伤的对象ID列表
@@ -1425,9 +1530,10 @@
             if tagObj not in caorenProtectList:
                 caorenProtectList.append(tagObj)
                 
-        if hurtObj.GetSuckHP() > 0:
-            isSuckHP = True
-            
+        if hurtObj.GetSuckHP() > 0 and not hurtObj.HaveHurtType(ChConfig.HurtAtkType_PoisonCureSuck):
+            if hurtObjID not in suckObjIDList:
+                suckObjIDList.append(hurtObjID)
+                
     # 判断自己死亡,因为反弹、平摊伤害的原因,有可能自己干死自己
     if curObj.IsAlive() and curObj.GetHP() <= 0:
         if curObj.CanNoDead():
@@ -1447,7 +1553,7 @@
         DoHeroSpecialty(turnFight, curObj, ChConfig.HeroSpecialty_SuperHit, relatedSkillID)
     if stunObjIDList:
         DoHeroSpecialty(turnFight, curObj, ChConfig.HeroSpecialty_Stun, relatedSkillID)
-    if isSuckHP:
+    if suckObjIDList:
         DoHeroSpecialty(turnFight, curObj, ChConfig.HeroSpecialty_SuckHP, relatedSkillID)
         
     # 结算副本相关的攻击结果,仅主动发起玩家阵容武将触发
@@ -1462,6 +1568,10 @@
         __DoCurSkillEff(turnFight, curObj, useSkill, effIgnoreObjIDList, isUseSkill)
     
     # ========== 以下触发被动 ==========
+    
+    curBatLineup = curObj.GetTFBatLineup()
+    curMGObj = curBatLineup.getMinggeObj()
+    mgTriggerWayList = [] # 命格本次技能已触发方式列表,命格固定只触发一次
     
     # buff消失后置处理的被动,优先处理,如破盾,区别于被动方式  ChConfig.TriggerWay_BuffDel(立即触发)
     for buffObjID, buff, tagObjID, afterTriggerData in delBuffAfterEffList:
@@ -1486,7 +1596,7 @@
             batFaction = turnFight.getBatFaction(faction)
             for lineupNum in batFaction.lineupDict.keys():
                 batLineup = batFaction.getBatlineup(lineupNum)
-                for lineupObjID in batLineup.posObjIDDict.values():
+                for lineupObjID in batLineup.getBatHeroObjIDList():
                     lineupObj = batObjMgr.getBatObj(lineupObjID)
                     if not lineupObj.IsAlive():
                         continue
@@ -1509,10 +1619,13 @@
         TurnBuff.DoBuffByRevive(turnFight, tagObj)
         TurnPassive.OnTriggerPassiveEffect(turnFight, tagObj, ChConfig.TriggerWay_Revive, curObj, connSkill=useSkill)
         TurnPassive.OnTriggerPassiveEffect(turnFight, tagObj, ChConfig.TriggerWay_InBattlefield, curObj, connSkill=useSkill)
+    if reviveObjList and curMGObj:
+        tagObj = reviveObjList[0]
+        TurnPassive.OnTriggerPassiveEffect(turnFight, curMGObj, ChConfig.TriggerWay_Revive, tagObj, connSkill=useSkill, byFriendObj=curObj)
         
     # 曹仁防护触发,暂写死
     for tagObj in caorenProtectList:
-        tagBatLineup = tagObj.GetBatLineup()
+        tagBatLineup = tagObj.GetTFBatLineup()
         caorenObj = tagBatLineup.getHeroObj(ChConfig.HeroID_Caoren) # 获取被防护目标阵容的曹仁
         if not caorenObj or not caorenObj.IsAlive():
             continue
@@ -1527,7 +1640,6 @@
     triggerOne = False
     batType = useSkill.GetBatType()
     isAttackDirect = (isUseSkill and SkillCommon.isAttackDirectSkill(useSkill)) # 是否直接攻击
-    curBatLineup = None
     for tagObj in tagObjListAll:
         tagID = tagObj.GetID()
         
@@ -1535,7 +1647,11 @@
         if tagID in missObjIDList:
             TurnPassive.OnTriggerPassiveEffect(turnFight, curObj, ChConfig.TriggerWay_BeMiss, tagObj, connSkill=useSkill)
             TurnPassive.OnTriggerPassiveEffect(turnFight, tagObj, ChConfig.TriggerWay_Miss, curObj, connSkill=useSkill)
-            
+            tagMGObj = tagObj.GetTFBatLineup().getMinggeObj()
+            if tagMGObj and ChConfig.TriggerWay_Miss not in mgTriggerWayList:
+                mgTriggerWayList.append(ChConfig.TriggerWay_Miss)
+                TurnPassive.OnTriggerPassiveEffect(turnFight, tagMGObj, ChConfig.TriggerWay_Miss, curObj, connSkill=useSkill, byBatObj=tagObj)
+                
         # 免疫
         if tagID in immuneObjIDList:
             TurnPassive.OnTriggerPassiveEffect(turnFight, tagObj, ChConfig.TriggerWay_ImmuneHurt, curObj, connSkill=useSkill)
@@ -1548,7 +1664,7 @@
         # 掉血时
         if tagID in beHurtObjIDList:
             TurnPassive.OnTriggerPassiveEffect(turnFight, tagObj, ChConfig.TriggerWay_BeHurt, curObj, connSkill=useSkill)
-            #TurnPassive.OnTriggerPassiveEffect(turnFight, curObj, ChConfig.TriggerWay_HurtTag, tagObj, connSkill=useSkill) 暂时用不到先屏蔽
+            TurnPassive.OnTriggerPassiveEffect(turnFight, curObj, ChConfig.TriggerWay_HurtTag, tagObj, connSkill=useSkill)
             
         #  受到任意效果时(除直接攻击外的任意效果,如buff、dot、治疗、额外怒技)
         if not isAttackDirect:
@@ -1583,24 +1699,65 @@
         if tagID in stunObjIDList:
             TurnPassive.OnTriggerPassiveEffect(turnFight, curObj, ChConfig.TriggerWay_Stun, tagObj, connSkill=useSkill)
             TurnPassive.OnTriggerPassiveEffect(turnFight, tagObj, ChConfig.TriggerWay_BeStun, curObj, connSkill=useSkill)
+            if curMGObj and ChConfig.TriggerWay_Stun not in mgTriggerWayList:
+                mgTriggerWayList.append(ChConfig.TriggerWay_Stun)
+                TurnPassive.OnTriggerPassiveEffect(turnFight, curMGObj, ChConfig.TriggerWay_Stun, tagObj, connSkill=useSkill, byBatObj=curObj)
+                
+        # 控制
+        if tagID in beControlledHardDict:
+            buff = beControlledHardDict[tagID]
+            if buff.GetCurBuffState() == ChConfig.BatObjState_Frozen:
+                if curMGObj and ChConfig.TriggerWay_Frozen not in mgTriggerWayList:
+                    mgTriggerWayList.append(ChConfig.TriggerWay_Frozen)
+                    TurnPassive.OnTriggerPassiveEffect(turnFight, curMGObj, ChConfig.TriggerWay_Frozen, tagObj, connSkill=useSkill, byBatObj=curObj)
+            TurnPassive.OnTriggerPassiveEffect(turnFight, tagObj, ChConfig.TriggerWay_BeControlledHard, curObj, connSkill=useSkill, connBuff=buff)
             
+        # 附加dot
+        if tagID in beDotBuffDict:
+            if curMGObj and ChConfig.TriggerWay_AddDOTBuff not in mgTriggerWayList:
+                mgTriggerWayList.append(ChConfig.TriggerWay_AddDOTBuff)
+                TurnPassive.OnTriggerPassiveEffect(turnFight, curMGObj, ChConfig.TriggerWay_AddDOTBuff, tagObj, connSkill=useSkill, byBatObj=curObj)
+                
         # 暴击
         if tagID in superHitObjIDList:
             TurnPassive.OnTriggerPassiveEffect(turnFight, curObj, ChConfig.TriggerWay_SuperHit, tagObj, connSkill=useSkill)
             TurnPassive.OnTriggerPassiveEffect(turnFight, tagObj, ChConfig.TriggerWay_BeSuperHit, curObj, connSkill=useSkill)
-            
+            if curMGObj and ChConfig.TriggerWay_SuperHit not in mgTriggerWayList:
+                mgTriggerWayList.append(ChConfig.TriggerWay_SuperHit)
+                TurnPassive.OnTriggerPassiveEffect(turnFight, curMGObj, ChConfig.TriggerWay_SuperHit, tagObj, connSkill=useSkill, byBatObj=curObj)
+                
         # 格挡
         if tagID in parryObjIDList:
             TurnPassive.OnTriggerPassiveEffect(turnFight, curObj, ChConfig.TriggerWay_BeParry, tagObj, connSkill=useSkill)
             TurnPassive.OnTriggerPassiveEffect(turnFight, tagObj, ChConfig.TriggerWay_Parry, curObj, connSkill=useSkill)
-            
+            tagMGObj = tagObj.GetTFBatLineup().getMinggeObj()
+            if tagMGObj and ChConfig.TriggerWay_Parry not in mgTriggerWayList:
+                mgTriggerWayList.append(ChConfig.TriggerWay_Parry)
+                TurnPassive.OnTriggerPassiveEffect(turnFight, tagMGObj, ChConfig.TriggerWay_Parry, curObj, connSkill=useSkill, byBatObj=tagObj)
+                
+        # 吸血
+        if tagID in suckObjIDList:
+            if not triggerOne:
+                TurnPassive.OnTriggerPassiveEffect(turnFight, curObj, ChConfig.TriggerWay_SuckHPOne, tagObj, connSkill=useSkill)
+            TurnPassive.OnTriggerPassiveEffect(turnFight, tagObj, ChConfig.TriggerWay_BeSuckHP, curObj, connSkill=useSkill)
+            if curMGObj and ChConfig.TriggerWay_SuckHPOne not in mgTriggerWayList:
+                mgTriggerWayList.append(ChConfig.TriggerWay_SuckHPOne)
+                TurnPassive.OnTriggerPassiveEffect(turnFight, curMGObj, ChConfig.TriggerWay_SuckHPOne, tagObj, connSkill=useSkill, byBatObj=curObj)
+                
         # 连击
         if batType == ChConfig.TurnBattleType_Combo:
             TurnPassive.OnTriggerPassiveEffect(turnFight, curObj, ChConfig.TriggerWay_Combo, tagObj, connSkill=useSkill)
             TurnPassive.OnTriggerPassiveEffect(turnFight, tagObj, ChConfig.TriggerWay_BeCombo, curObj, connSkill=useSkill)
+            if curMGObj and ChConfig.TriggerWay_Combo not in mgTriggerWayList:
+                mgTriggerWayList.append(ChConfig.TriggerWay_Combo)
+                TurnPassive.OnTriggerPassiveEffect(turnFight, curMGObj, ChConfig.TriggerWay_Combo, tagObj, connSkill=useSkill, byBatObj=curObj)
         # 追击
         elif batType == ChConfig.TurnBattleType_Pursue:
             TurnPassive.OnTriggerPassiveEffect(turnFight, curObj, ChConfig.TriggerWay_Pursue, tagObj, connSkill=useSkill)
+            if isAttackDirect:
+                if curMGObj and ChConfig.TriggerWay_PursueAtk not in mgTriggerWayList:
+                    mgTriggerWayList.append(ChConfig.TriggerWay_PursueAtk)
+                    TurnPassive.OnTriggerPassiveEffect(turnFight, curMGObj, ChConfig.TriggerWay_PursueAtk, tagObj, connSkill=useSkill, byBatObj=curObj)
             TurnPassive.OnTriggerPassiveEffect(turnFight, tagObj, ChConfig.TriggerWay_BePursue, curObj, connSkill=useSkill)
         # 反击
         elif batType == ChConfig.TurnBattleType_AtkBack:
@@ -1609,10 +1766,8 @@
             
             
         # 敌友方
-        if isAttackDirect or batType in [ChConfig.TurnBattleType_Combo, ChConfig.TurnBattleType_Pursue] or isDotHurt:
-            if not curBatLineup:
-                curBatLineup = curObj.GetBatLineup()
-            for lineupObjID in curBatLineup.posObjIDDict.values():
+        if isAttackDirect or batType in [ChConfig.TurnBattleType_Combo, ChConfig.TurnBattleType_Pursue] or isDotHurt or tagID in beControlledHardDict:
+            for lineupObjID in curBatLineup.getBatHeroObjIDList():
                 lineupObj = batObjMgr.getBatObj(lineupObjID)
                 if not lineupObj.IsAlive():
                     continue
@@ -1628,6 +1783,10 @@
                     if not triggerOne:
                         TurnPassive.OnTriggerPassiveEffect(turnFight, lineupObj, ChConfig.TriggerWay_FriendDotHurt, tagObj, connSkill=useSkill, byFriendObj=curObj)
                         
+                # 敌方被控时
+                if tagID in beControlledHardDict and lineupObj.GetFaction() != tagObj.GetFaction():
+                    TurnPassive.OnTriggerPassiveEffect(turnFight, lineupObj, ChConfig.TriggerWay_EnemyBeControlledHard, tagObj, connSkill=useSkill)
+                    
                 # 连击
                 if batType == ChConfig.TurnBattleType_Combo:
                     TurnPassive.OnTriggerPassiveEffect(turnFight, lineupObj, ChConfig.TriggerWay_FriendCombo, tagObj, connSkill=useSkill, byFriendObj=curObj)
@@ -1652,9 +1811,7 @@
     if not batFaction:
         return
     batLineup = batFaction.getBatlineup(1)
-    if ChConfig.HeroID_Dongbai not in batLineup.heroObjIDDict:
-        return
-    dongbaiObj = BattleObj.GetBatObjMgr().getBatObj(batLineup.heroObjIDDict[ChConfig.HeroID_Dongbai])
+    dongbaiObj = batLineup.getHeroObj(ChConfig.HeroID_Dongbai)
     if not dongbaiObj or dongbaiObj.IsAlive():
         return
     skill = dongbaiObj.GetSkillManager().FindSkillByID(ChConfig.SkillID_DongbaiRevive)
@@ -1832,6 +1989,10 @@
             GameWorld.DebugLogEx("有击杀目标时该技能无效! enhanceSkillID=%s", enhanceSkillID)
             return
         
+    if checkHeroSex:
+        if TurnPassive.GetTriggerEffectValue(turnFight, curBatObj, None, ChConfig.PassiveEff_IgnoreSex, connSkillTypeID=enhanceSkillData.GetSkillTypeID(), connSkillID=enhanceSkillID):
+            checkHeroSex = 0
+            
     # 继承主技能目标
     if enhanceSkillData.GetTagAim() == ChConfig.SkillTagAim_MainSkill:
         GameWorld.DebugLogEx("继承主技能目标! enhanceSkillID=%s", enhanceSkillID)
@@ -1906,7 +2067,7 @@
     @param effectID: 被动效果ID
     注:可能由A引起触发B技能的效果释放技能C
     '''
-    if not passiveSkill:
+    if not passiveSkill or not batObj:
         return
     if isinstance(passiveSkill, int):
         passiveSkillID = passiveSkill
@@ -1962,6 +2123,20 @@
         GameWorld.DebugLogEx("被动触发技能,针对来源友军! effSkillID=%s,effectID=%s,passiveSkillID=%s,bySkillID=%s,byFriendID=%s", 
                              effSkillID, effectID, passiveSkillID, bySkillID, byFriendObj.GetID())
         isOK = OnUseSkill(turnFight, batObj, passiveSkill, passiveTagObjList, batType=batType, bySkill=connSkill, byBuff=connBuff, **kwargs)
+    # 继承主技能目标同横排 11
+    elif tagAim == ChConfig.SkillTagAim_MainSkillRow:
+        if not tagObj:
+            return
+        GameWorld.DebugLogEx("被动触发技能,针对目标同排对象! effSkillID=%s,effectID=%s,passiveSkillID=%s,bySkillID=%s", effSkillID, effectID, passiveSkillID, bySkillID)
+        passiveTagObjList = __getSameRowObjList(tagObj)
+        isOK = OnUseSkill(turnFight, batObj, passiveSkill, passiveTagObjList, batType=batType, bySkill=connSkill, byBuff=connBuff, **kwargs)
+    # 继承主技能目标同纵排 12
+    elif tagAim == ChConfig.SkillTagAim_MainSkillCol:
+        if not tagObj:
+            return
+        GameWorld.DebugLogEx("被动触发技能,针对目标同纵对象! effSkillID=%s,effectID=%s,passiveSkillID=%s,bySkillID=%s", effSkillID, effectID, passiveSkillID, bySkillID)
+        passiveTagObjList = __getSameColObjList(tagObj)
+        isOK = OnUseSkill(turnFight, batObj, passiveSkill, passiveTagObjList, batType=batType, bySkill=connSkill, byBuff=connBuff, **kwargs)
     else:
         GameWorld.DebugLogEx("被动触发技能,重新锁定目标! effSkillID=%s,effectID=%s,passiveSkillID=%s,bySkillID=%s", effSkillID, effectID, passiveSkillID, bySkillID)
         isOK = OnUseSkill(turnFight, batObj, passiveSkill, batType=batType, bySkill=connSkill, byBuff=connBuff, **kwargs)
@@ -1972,8 +2147,8 @@
     '''按公式计算伤害,默认按攻击计算
     '''
     
-    #mapID = turnFight.mapID
     skillID = curSkill.GetSkillID()
+    #mapID = turnFight.mapID
     pmType = GetPMType(atkObj, curSkill)
     ignoreDef = IsIgnoreDef(curSkill)
     batType = curSkill.GetBatType()
@@ -1993,26 +2168,31 @@
     isAngerSkill = SkillCommon.isAngerSkill(curSkill)
     isDot = ("damageoftime" in kwargs)
     
-    mustHit = False # 是否必命中
-    if not isTurnNormalSkill: # 仅普攻判断是否闪避
-        mustHit = True
-        
-    angerOverflow = atkObj.GetAngerOverflow() # 怒气溢出值
-    if isAngerSkill:
-        curXP = atkObj.GetXP()
-        GameWorld.DebugLogEx("怒技攻击! curXP=%s,angerOverflow=%s", curXP, angerOverflow)
-        
-    #命中公式 攻击方类型不同,公式不同
-    if not mustHit and not curSkill.GetEffectByID(ChConfig.SkillEff_MustHit) and not defObj.IsInControlledHard():
+    # 常规闪避 - 仅针对普攻
+    if isTurnNormalSkill and not curSkill.GetEffectByID(ChConfig.SkillEff_MustHit) and not defObj.IsInControlledHard():
         aMissRateDef = atkObj.GetBatAttrValue(ChConfig.AttrID_MissRateDef) #atkObj.GetHit() # 抗闪避率 - 命中
         dMissRate = defObj.GetBatAttrValue(ChConfig.AttrID_MissRate) # 闪避率
         missNum = curSkill.GetTagMissNum(defID)
         missRate = eval(IpyGameDataPY.GetFuncCompileCfg("MissCfg", 1))
         if GameWorld.CanHappen(missRate):
             GameWorld.DebugLogEx("闪避了! missRate=%s,dMissRate=%s,aMissRateDef=%s,missNum=%s", missRate, dMissRate, aMissRateDef, missNum)
-            curSkill.SetTagMissNum(defID, missRate + 1)
+            curSkill.SetTagMissNum(defID, missNum + 1)
             return 0, pow(2, ChConfig.HurtAtkType_Miss)
         
+    # 绝对闪避 - 除dot外的所有技能,因为绝对闪避不触发常规闪避的被动,所以在常规闪避后判断
+    if not isDot:
+        aMissRateDef = atkObj.GetBatAttrValue(ChConfig.AttrID_AbsoluteMissRateDef)
+        dMissRate = defObj.GetBatAttrValue(ChConfig.AttrID_AbsoluteMissRate)
+        missNum = curSkill.GetTagMissNum(defID)
+        if dMissRate > 0:
+            missRate = eval(IpyGameDataPY.GetFuncCompileCfg("MissCfg", 1))
+            if GameWorld.CanHappen(missRate):
+                GameWorld.DebugLogEx("绝对闪避了! missRate=%s,dAbsoluteMissRate=%s,aAbsoluteMissRateDef=%s,missNum=%s", missRate, dMissRate, aMissRateDef, missNum)
+                curSkill.SetTagMissNum(defID, missNum + 1)
+                return 0, pow(2, ChConfig.HurtAtkType_AbsoluteMiss)
+            
+    angerOverflow = atkObj.GetAngerOverflow() # 怒气溢出值
+    
     hurtTypes = pow(2, ChConfig.HurtAtkType_Hurt)
     
     isSuperHit, isParry, isStun = False, False, False
@@ -2033,7 +2213,6 @@
         aSuperDamPer += TurnPassive.GetTriggerEffectValue(turnFight, atkObj, defObj, ChConfig.AttrID_SuperDamPer, curSkill)
         
         dSuperDamPerDef = defObj.GetBatAttrValue(ChConfig.AttrID_SuperDamPerDef)
-        GameWorld.DebugLogEx("aSuperDamPer=%s,dSuperDamPerDef=%s", aSuperDamPer, dSuperDamPerDef)
         
     if isParry:
         hurtTypes |= pow(2, ChConfig.HurtAtkType_Parry)
@@ -2061,6 +2240,32 @@
     aFinalDamPer += TurnPassive.GetTriggerEffectValue(turnFight, atkObj, defObj, ChConfig.PassiveEff_AddFinalDamPer, curSkill)
     aFinalDamPer += TurnPassive.GetTriggerEffectValue(turnFight, atkObj, defObj, ChConfig.AttrID_FinalDamPer, curSkill)
     
+    #招架  - 无视攻击方最终增伤百分比
+    dZhaojia = defObj.GetBatAttrValue(ChConfig.AttrID_Zhaojia)
+    aZhaojiaDef = atkObj.GetBatAttrValue(ChConfig.AttrID_ZhaojiaDef)
+    if dZhaojia > aZhaojiaDef:
+        perMoreValue, perReduce = IpyGameDataPY.GetFuncEvalCfg("ZhaojiaCfg", 1) # 每高与对方抗贯穿x值无视y%最终减伤
+        reducePer = (dZhaojia - aZhaojiaDef) / float(perMoreValue) * perReduce
+        reduceMin, reduceMax = IpyGameDataPY.GetFuncEvalCfg("ZhaojiaCfg", 2) # 最小无视百分比|最大无视百分比
+        if reducePer >= reduceMin and GameWorld.CanHappen(IpyGameDataPY.GetFuncCfg("ZhaojiaCfg", 3)):
+            reducePer = min(reducePer, reduceMax)
+            hurtTypes |= pow(2, ChConfig.HurtAtkType_Zhaojia)
+            aFinalDamPer = int(aFinalDamPer * (100 - reducePer) / 100.0) # 按百分比减少
+            GameWorld.DebugLogEx("dZhaojia=%s,aZhaojiaDef=%s,reducePer=%s,aFinalDamPer=%s", dZhaojia, aZhaojiaDef, reducePer, aFinalDamPer)
+            
+    #贯穿  - 无视防守方最终减伤百分比
+    aGuanchuan = atkObj.GetBatAttrValue(ChConfig.AttrID_Guanchuan)
+    dGuanchuanDef = defObj.GetBatAttrValue(ChConfig.AttrID_GuanchuanDef)
+    if aGuanchuan > dGuanchuanDef:
+        perMoreValue, perReduce = IpyGameDataPY.GetFuncEvalCfg("GuanchuanCfg", 1) # 每高与对方抗贯穿x值无视y%最终减伤
+        reducePer = (aGuanchuan - dGuanchuanDef) / float(perMoreValue) * perReduce
+        reduceMin, reduceMax = IpyGameDataPY.GetFuncEvalCfg("GuanchuanCfg", 2) # 最小无视百分比|最大无视百分比
+        if reducePer >= reduceMin and GameWorld.CanHappen(IpyGameDataPY.GetFuncCfg("GuanchuanCfg", 3)):
+            reducePer = min(reducePer, reduceMax)
+            hurtTypes |= pow(2, ChConfig.HurtAtkType_Guanchuan)
+            dFinalDamPerDef = int(dFinalDamPerDef * (100 - reducePer) / 100.0) # 按百分比减少
+            GameWorld.DebugLogEx("aGuanchuan=%s,dGuanchuanDef=%s,reducePer=%s,dFinalDamPerDef=%s", aGuanchuan, dGuanchuanDef, reducePer, dFinalDamPerDef)   
+            
     aNormalSkillPer, dNormalSkillPerDef = 0, 0
     if isTurnNormalSkill:
         aNormalSkillPer = atkObj.GetBatAttrValue(ChConfig.AttrID_NormalSkillPer) # 普技增伤
@@ -2123,7 +2328,6 @@
     if turnFight.isPVP() > 0:
         aPVPDamPer = atkObj.GetBatAttrValue(ChConfig.AttrID_PVPDamPer)
         dPVPDamPerDef = defObj.GetBatAttrValue(ChConfig.AttrID_PVPDamPerDef)
-        GameWorld.DebugLogEx("PVP aPVPDamPer=%s,dPVPDamPerDef=%s", aPVPDamPer, dPVPDamPerDef)
         
     # 所有万分率参数统一除10000.0
     atkSkillPer /= 10000.0
@@ -2152,19 +2356,30 @@
     
     if calcType != ChConfig.Def_Calc_Attack:
         aAtk = GetCalcBaseValue(calcType, atkObj, defObj, curSkill)
-    GameWorld.DebugLogEx("伤血计算: atkID=%s,defID=%s,skillID=%s,atkSkillPer=%s,calcType=%s,aAtk=%s,dDef=%s,dHP=%s/%s,hurtTypes=%s,aBatDamPer=%s,aFinalDamPer=%s", 
-                         atkID, defID, skillID, atkSkillPer, calcType, aAtk, dDef, dHP, dMaxHP, hurtTypes, aBatDamPer, aFinalDamPer)
-    #GameWorld.DebugLogEx("aCountry=%s,dCountry=%s,aCountryDamPer=%s,dCountryDamPerDef=%s", aCountry, dCountry, aCountryDamPer, dCountryDamPerDef)
-    
+    GameWorld.DebugLogEx("伤血计算: atkID=%s,defID=%s,skillID=%s,atkSkillPer=%s,calcType=%s,aAtk=%s,dDef=%s,dHP=%s/%s,hurtTypes=%s,aBatDamPer=%s,dBatDamPerDef=%s,aFinalDamPer=%s,dFinalDamPerDef=%s", 
+                         atkID, defID, skillID, atkSkillPer, calcType, aAtk, dDef, dHP, dMaxHP, hurtTypes, aBatDamPer, dBatDamPerDef, aFinalDamPer, dFinalDamPerDef)
+    if isSuperHit:
+        GameWorld.DebugLogEx("    暴击 aSuperDamPer=%s,dSuperDamPerDef=%s", aSuperDamPer, dSuperDamPerDef)
+    if aPMDamPer or dPMDamPerDef:
+        GameWorld.DebugLogEx("    物法 aPMDamPer=%s,dPMDamPerDef=%s,pmType=%s", aPMDamPer, dPMDamPerDef, pmType)
+    if aComboDamPer or dComboDamPerDef:
+        GameWorld.DebugLogEx("    连击 aComboDamPer=%s,dComboDamPerDef=%s", aComboDamPer, dComboDamPerDef)
+    if aPursueDamPer or dPursueDamPerDef:
+        GameWorld.DebugLogEx("    追击 aPursueDamPer=%s,dPursueDamPerDef=%s", aPursueDamPer, dPursueDamPerDef)
+    if aPVPDamPer or dPVPDamPerDef:
+        GameWorld.DebugLogEx("    PVP aPVPDamPer=%s,dPVPDamPerDef=%s", aPVPDamPer, dPVPDamPerDef)
+    if aCountryDamPer or dCountryDamPerDef:
+        GameWorld.DebugLogEx("    国家 aCountry=%s,dCountry=%s,aCountryDamPer=%s,dCountryDamPerDef=%s", aCountry, dCountry, aCountryDamPer, dCountryDamPerDef)
+        
     if isTurnNormalSkill:
         hurtValue = eval(IpyGameDataPY.GetFuncCompileCfg("HurtFormula", 1))
         GameWorld.DebugLogEx("    普攻技能伤害=%s,aNormalSkillPer=%s,dNormalSkillPerDef=%s", hurtValue, aNormalSkillPer, dNormalSkillPerDef)
     elif isAngerSkill:
         hurtValue = eval(IpyGameDataPY.GetFuncCompileCfg("HurtFormula", 2))
-        GameWorld.DebugLogEx("    怒气技能伤害=%s,aAngerSkillPer=%s,dAngerSkillPerDef=%s", hurtValue, aAngerSkillPer, dAngerSkillPerDef)
+        GameWorld.DebugLogEx("    怒气技能伤害=%s,aAngerSkillPer=%s,dAngerSkillPerDef=%s,angerOverflow=%s,curXP=%s", hurtValue, aAngerSkillPer, dAngerSkillPerDef, angerOverflow, atkObj.GetXP())
     elif isDot:
         hurtValue = eval(IpyGameDataPY.GetFuncCompileCfg("DOTFormula", 1))
-        GameWorld.DebugLogEx("    持续技能伤害=%s" % (hurtValue))
+        GameWorld.DebugLogEx("    持续技能伤害=%s,aDOTPer=%s,dDOTPerDef=%s", hurtValue, aDOTPer, dDOTPerDef)
     elif calcType == ChConfig.Def_Calc_ByBuffValue:
         hurtValue = eval(IpyGameDataPY.GetFuncCompileCfg("CalcTypeFormula", 2))
         GameWorld.DebugLogEx("    按最后一次buff值计算伤害=%s,calcType=%s,LastHurt=%s", hurtValue, calcType, aAtk)
@@ -2194,14 +2409,25 @@
         GameWorld.DebugLogEx("    伤害最高限制: hurtValue=%s,hurtAtkPerMax=%s,aAtk=%s", hurtValue, hurtAtkPerMax, aAtk)
         
     # 均摊
-    hurtShareEff = curSkill.GetEffectByID(ChConfig.SkillEff_HurtShare)
-    if hurtShareEff:
+    if HaveShareEff(atkObj, curSkill):
         tagCnt = max(1, len(curSkill.GetTagObjList()))
         hurtValue = hurtValue / tagCnt
         GameWorld.DebugLogEx("    目标均摊伤害: hurtValue=%s,tagCnt=%s", hurtValue, tagCnt)
         
     hurtValue = max(1, int(hurtValue)) # 负值、保底防范,放最后
     return hurtValue, hurtTypes
+
+def HaveShareEff(atkObj, curSkill):
+    ## 玩家技能是否有分摊效果: 均摊伤害/治疗/承伤盾值
+    hurtShareEff = curSkill.GetEffectByID(ChConfig.SkillEff_HurtShare)
+    if not hurtShareEff:
+        return False
+    needLearnSkillID = hurtShareEff.GetEffectValue(0)
+    if needLearnSkillID:
+        if not atkObj.GetSkillManager().FindSkillByID(needLearnSkillID):
+            GameWorld.DebugLogEx("所需技能未学习,分摊效果不生效! skillID=%s,needLearnSkillID=%s", curSkill.GetSkillID(), needLearnSkillID)
+            return False
+    return True
 
 def GetAddSkillPer(turnFight, atkObj, defObj, curSkill):
     ## 获取额外增加的技能万分比
@@ -2216,7 +2442,6 @@
 
 def CanSuperHit(turnFight, atkObj, defObj, curSkill):
     if TurnPassive.GetTriggerEffectValue(turnFight, atkObj, defObj, ChConfig.PassiveEff_MustSuperHit, curSkill):
-        GameWorld.DebugLogEx("目标血量低于百分x时必定暴击: defID=%s,hp:%s/%s", defObj.GetID(), defObj.GetHP(), defObj.GetMaxHP())
         return True
     
     aSuperHitRate = atkObj.GetBatAttrValue(ChConfig.AttrID_SuperHitRate)
@@ -2461,12 +2686,10 @@
                          faction, lineupNum, hurtValueDict, immuneHurtDict)
     # 按优先级顺序处理拥有分摊效果的武将
     for effHeroID in effHeroIDList:
-        if effHeroID not in batLineup.heroObjIDDict:
-            continue
-        objID = batLineup.heroObjIDDict[effHeroID]
-        batObj = batObjMgr.getBatObj(objID)
+        batObj = batLineup.getHeroObj(effHeroID)
         if not batObj or not batObj.IsAlive():
             continue
+        objID = batObj.GetID()
         buffMgr = batObj.GetBuffManager()
         
         inHurt = objID in hurtValueDict # 光环里的人员是否有受伤
@@ -2700,7 +2923,9 @@
     damBackPer = 0
     buffMgr = defObj.GetBuffManager()
     for buff in buffMgr.FindBuffListByState(ChConfig.BatObjState_DamBackShield):
-        damBackPer += buff.GetValue1()
+        damBackPer += buff.GetValue1() * max(1, buff.GetLayer())
+        connSkillTypeID = buff.GetSkillTypeID()
+        damBackPer += TurnPassive.GetTriggerEffectValue(turnFight, defObj, atkObj, ChConfig.PassiveEff_AddDamBackPerByBuffLayer, connSkillTypeID=connSkillTypeID)
         
     if damBackPer <= 0:
         return
@@ -2820,8 +3045,7 @@
         cureHP = int(cureHP * multiValue)
         GameWorld.DebugLogEx("    治疗倍值: cureHP=%s,multiValue=%s", cureHP, multiValue)
         
-    hurtShareEff = curSkill.GetEffectByID(ChConfig.SkillEff_HurtShare)
-    if hurtShareEff:
+    if HaveShareEff(userObj, curSkill):
         tagCnt = max(1, len(curSkill.GetTagObjList()))
         cureHP = cureHP / tagCnt
         GameWorld.DebugLogEx("    目标均摊治疗: cureHP=%s,tagCnt=%s", cureHP, tagCnt)
@@ -2923,6 +3147,43 @@
     useSkill.ResetUseRec()
     return
 
+def DoHurtExAtk(turnFight, atkObj, defObj, hurtValue, skillID, hurtTypes=0):
+    ## 额外结算指定伤害
+    skillIpyData = IpyGameDataPY.GetIpyGameData("Skill", skillID)
+    if not skillIpyData:
+        return
+    
+    atkID = atkObj.GetID()
+    defID = defObj.GetID()
+    
+    # 结算需要同步标签
+    useTag = "Skill_%s_%s_Dot_%s" % (atkID, skillID, atkObj.GetIncrementValue()) # 复用dot的标签
+    Sync_TurnFightTag(turnFight, useTag, 0)
+    
+    dHP = defObj.GetHP()
+    dMaxHP = defObj.GetMaxHP()
+    GameWorld.DebugLogEx("额外结算指定伤害: atkID=%s,defID=%s,skillID=%s,hurtValue=%s,,dHP=%s/%s", 
+                         atkID, defID, skillID, hurtValue, dHP, dMaxHP)
+    
+    useSkill = BattleObj.PySkill(skillIpyData, atkID)
+    useSkill.SetTagObjList([defObj])
+    useSkill.SetBatType(ChConfig.TurnBattleType_Dot) # 要修改表现的话等前端同步修改
+    
+    hurtTypes |= pow(2, ChConfig.HurtAtkType_Hurt) # 确保有基础的伤害类型
+    hurtValue, hurtTypes, immuneHurt = CalcHurtWithBuff(turnFight, atkObj, defObj, hurtValue, hurtTypes)
+    calcHurtResults = [[defObj, hurtValue, hurtTypes, immuneHurt]]
+    DoSkillHurtHP(turnFight, atkObj, useSkill, calcHurtResults, "HurtExAtk")
+    
+    Sync_UseSkill(turnFight, atkObj, useSkill)
+    
+    DoBeAttackResult(turnFight, atkObj, useSkill)
+    
+    # 通知结束标签
+    Sync_TurnFightTag(turnFight, useTag, 1)
+    
+    useSkill.ResetUseRec()
+    return True
+
 def Sync_TurnFightTag(turnFight, useTag, sign):
     ## 通知技能标签
     clientPack = ChPyNetSendPack.tagSCTurnFightTag()

--
Gitblit v1.8.0