129 【战斗】战斗系统-服务端(技能触发来源触发逻辑优化;增加承伤盾支持,0428通知buff相关值;增加嘲讽支持,优化技能选择目标逻辑;增加连击、反击、格挡、暴击、通用击晕支持;)
12个文件已修改
3个文件已添加
1519 ■■■■■ 已修改文件
PySysDB/PySysDBPY.h 10 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/BattleObj.py 157 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/TurnAttack.py 224 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py 66 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py 32 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/GameSkills/SkillCommon.py 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/PassiveTrigger/PassiveEff_5001.py 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/PassiveTrigger/PassiveEff_5010.py 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/PassiveTrigger/PassiveEff_5011.py 58 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnBuff.py 112 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnBuffs/BuffAtkType_1001.py 11 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnBuffs/BuffAtkType_1003.py 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnPassive.py 34 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnSkill.py 697 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
PySysDB/PySysDBPY.h
@@ -79,22 +79,21 @@
    DWORD        EffectID1;    //效果ID1
    list        EffectValues1;    //效果值列表1
    BYTE        TriggerWay1;    //触发方式
    BYTE        TriggerSrc1;    //触发来源
    BYTE        TriggerSrc1;    //有效来源
    list        TriggerParams1;    //触发参数
    DWORD        EffectID2;    //效果ID2
    list        EffectValues2;    //效果值列表2
    BYTE        TriggerWay2;    //触发方式
    BYTE        TriggerSrc2;    //触发来源
    BYTE        TriggerSrc2;    //有效来源
    list        TriggerParams2;    //触发参数
    DWORD        EffectID3;    //效果ID3
    list        EffectValues3;    //效果值列表3
    BYTE        TriggerWay3;    //触发方式
    BYTE        TriggerSrc3;    //触发来源
    BYTE        TriggerSrc3;    //有效来源
    list        TriggerParams3;    //触发参数
    DWORD        ConnSkill;    //关联技能
    WORD        CoolDownTime;    //技能冷却时间
    list        IgnoreStates;    //无视限制列表
    list        BuffStates;    //Buff״ֵ̬
    BYTE        CurBuffState;    //Buff״ֵ̬
    WORD        LastTime;    //持续时间
    BYTE        LayerCnt;    //Buff层数
    BYTE        LayerMax;    //最大层数
@@ -102,6 +101,7 @@
    DWORD        DieContinue;    //Buff死亡存在
    list        EnhanceSkillList;    //触发技能ID列表
    DWORD        FightPower;    //技能战斗力
    char        SkillMotionName; //技能动作名
};
//武将表
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/BattleObj.py
@@ -33,37 +33,41 @@
    def __init__(self, batObj):
        self._batObj = batObj
        # 被影响的技能ID: 0为所有技能
        self._AffectSkillDict = {} # 被动技能 {(触发方式, 被影响的技能ID):{技能ID:[effID, ...], ...}, ...}
        self._AffectBuffDict = {} # 被动buff {(触发方式, 被影响的技能ID):{buffID:[effID, ...], ...}, ...}
        self._AffectSkillDict = {} # 被动技能 {(触发方式, 有效来源):{技能ID:[effID, ...], ...}, ...}
        self._AffectBuffDict = {} # 被动buff {(触发方式, 有效来源):{buffID:[effID, ...], ...}, ...}
        return
    
    def GetPassiveEffByTrigger(self, triggerWay, connSkill=None):
    def GetPassiveEffByTrigger(self, triggerWay, connSkillTypeID=0):
        '''获取可触发的效果列表,技能跟buff根据触发优先级按顺序触发,优先级越高越先执行,相同时技能优先
                        优先级之后有需要再扩展
        @return: [["skill/buff", skillID/buffID, effIDList], ...]
        '''
        connSkillID = connSkill.GetSkillTypeID() if connSkill else 0
        effList = []
        # 优先取关联技能的
        if connSkillTypeID and connSkillTypeID not in [ChConfig.TriggerSrc_Skill, ChConfig.TriggerSrc_Buff]:
        # 技能
        key = (triggerWay, connSkillID)
            key = (triggerWay, connSkillTypeID)
        if key in self._AffectSkillDict:
            effDict = self._AffectSkillDict[key]
            for skillID, effIDList in effDict.items():
                effList.append(["skill", skillID, effIDList])
        if connSkillID != 0:
            key = (triggerWay, 0)
            effDict = self._AffectSkillDict.get(key, {})
            for skillID, effIDList in effDict.items():
                effList.append(["skill", skillID, effIDList])
                
        # buff
        key = (triggerWay, connSkillID)
            key = (triggerWay, connSkillTypeID)
        if key in self._AffectBuffDict:
            effDict = self._AffectBuffDict[key]
            for buffID, effIDList in effDict.items():
                effList.append(["buff", buffID, effIDList])
        if connSkillID != 0:
            key = (triggerWay, 0)
        # 所有技能有效的
        key = (triggerWay, ChConfig.TriggerSrc_Skill)
        effDict = self._AffectSkillDict.get(key, {})
        for skillID, effIDList in effDict.items():
            effList.append(["skill", skillID, effIDList])
        # 所有buff有效的
        key = (triggerWay, ChConfig.TriggerSrc_Buff)
            effDict = self._AffectBuffDict.get(key, {})
            for buffID, effIDList in effDict.items():
                effList.append(["buff", buffID, effIDList])
@@ -91,16 +95,16 @@
        ## 添加技能被动效果
        triggerWay = effect.GetTriggerWay()
        triggerSrc = effect.GetTriggerSrc()
        if not triggerWay or triggerSrc != 1:
        if not triggerWay:
            return
        if triggerSrc == ChConfig.TriggerSrc_Buff:
            # buff有效的不加进来
            return
        
        skillID = curSkill.GetSkillID()
        connSkillID = curSkill.GetConnSkill()
        #priority = curSkill.GetPriority()
        effectID = effect.GetEffectID()
        
        key = (triggerWay, connSkillID)
        key = (triggerWay, triggerSrc)
        if key not in self._AffectSkillDict:
            self._AffectSkillDict[key] = {}
        effDict = self._AffectSkillDict[key]
@@ -133,15 +137,16 @@
        '''
        triggerWay = effect.GetTriggerWay()
        triggerSrc = effect.GetTriggerSrc()
        if not triggerWay or triggerSrc != 2:
        if not triggerWay:
            return
        if triggerSrc == ChConfig.TriggerSrc_Skill:
            # 技能有效的不加进来
            return
        
        buffID = buff.GetBuffID()
        connSkillID = skillData.GetConnSkill()
        #priority = skillData.GetPriority()
        effectID = effect.GetEffectID()
        key = (triggerWay, connSkillID)
        key = (triggerWay, triggerSrc)
        if key not in self._AffectBuffDict:
            self._AffectBuffDict[key] = {}
        effDict = self._AffectBuffDict[key]
@@ -170,7 +175,8 @@
    def Clear(self):
        self._objID = 0
        self._hurtTypes = 0 # 本次伤血类型,如闪避、暴击、格挡等,通过二进制或运算得到最终值,支持多种同时出现,如暴击的同时被格挡
        self._hurtHP = 0 # 伤血值
        self._hurtHP = 0 # 公式最终计算的伤害值,一般用于飘血
        self._realHurtHP = 0 # 真实伤血值,被承伤盾抵扣后的可伤血的值
        self._lostHP = 0 # 实际掉血值
        self._curHP = 0 # 更新血量
        self._suckHP = 0 # 吸血量
@@ -190,6 +196,8 @@
        return self._hurtTypes & pow(2, hurtType) 
    def GetHurtHP(self): return self._hurtHP
    def SetHurtHP(self, hurtHP): self._hurtHP = hurtHP
    def GetRealHurtHP(self): return self._realHurtHP
    def SetRealHurtHP(self, realHurtHP): self._realHurtHP = realHurtHP
    def GetLostHP(self): return self._lostHP
    def SetLostHP(self, lostHP): self._lostHP = lostHP
    def GetCurHP(self): return self._curHP
@@ -235,6 +243,7 @@
            self._effDict[effID] = effect
        return
    
    def GetIpyData(self): return self._ipyData
    def GetSkillID(self): return self._ipyData.GetSkillID()
    def GetSkillTypeID(self): return self._ipyData.GetSkillTypeID()
    def GetSkillLV(self): return self._ipyData.GetSkillLV()
@@ -259,7 +268,7 @@
    def GetConnSkill(self): return self._ipyData.GetConnSkill()
    def GetCoolDownTime(self): return self._ipyData.GetCoolDownTime()
    def GetIgnoreStates(self): return self._ipyData.GetIgnoreStates() # 无视限制列表
    def GetBuffStates(self): return self._ipyData.GetBuffStates()
    def GetCurBuffState(self): return self._ipyData.GetCurBuffState()
    def GetLastTime(self): return self._ipyData.GetLastTime() # 持续时间
    def GetLayerCnt(self): return self._ipyData.GetLayerCnt()
    def GetLayerMax(self): return self._ipyData.GetLayerMax()
@@ -267,6 +276,7 @@
    def GetDieContinue(self): return self._ipyData.GetDieContinue() # Buff死亡存在
    def GetEnhanceSkillList(self): return self._ipyData.GetEnhanceSkillList() # 额外触发的技能ID列表
    def GetFightPower(self): return self._ipyData.GetFightPower()
    def GetSkillMotionName(self): return self._ipyData.GetSkillMotionName()
    
class PyBuff():
    
@@ -277,7 +287,9 @@
        self._layer = 0
        self._calcTime = 0
        self._remainTime = 0
        self._valueList = []
        self._value1 = 0 # 值需要通知前端,开发时注意20亿问题
        self._value2 = 0
        self._value3 = 0
        return
    
    def GetSkillData(self): return self._skillData
@@ -292,9 +304,20 @@
    def SetCalcTime(self, calcTime): self._calcTime = calcTime
    def GetRemainTime(self): return self._remainTime
    def SetRemainTime(self, remainTime): self._remainTime = remainTime
    def SetBuffValueList(self, valueList): self._valueList = valueList
    def GetBuffValue(self, index):
        return self._valueList[index] if len(self._valueList) > index else 0
    def SetBuffValueList(self, valueList):
        for index, value in enumerate(valueList):
            if index == 0:
                self.SetValue1(value)
            elif index == 1:
                self.SetValue2(value)
            elif index == 2:
                self.SetValue3(value)
    def GetValue1(self): return self._value1
    def SetValue1(self, value): self._value1 = value
    def GetValue2(self): return self._value2
    def SetValue2(self, value): self._value2 = value
    def GetValue3(self): return self._value3
    def SetValue3(self, value): self._value3 = value
    
class BuffManager():
    ## 战斗对象buff管理器
@@ -336,6 +359,7 @@
        
        self._buffList.append(buff)
        self._buffIDDict[buffID] = buff
        #GameWorld.DebugLog("ObjBuff:%s, AddBuff buffID=%s, %s, %s, %s, %s, %s" % (self._batObj.GetID(), buffID, buff, len(self._buffList), len(self._buffIDDict), self._buffList, self._buffIDDict))
        if skillTypeID not in self._skillTypeIDBuffIDs:
            self._skillTypeIDBuffIDs[skillTypeID] = []
        buffIDs = self._skillTypeIDBuffIDs[skillTypeID]
@@ -344,12 +368,15 @@
            
        return buff
    
    def DelBuff(self, buffID):
    def DelBuff(self, buffID, release=True):
        if buffID not in self._buffIDDict:
            #GameWorld.DebugLog("ObjBuff:%s, DelBuff not in self._buffIDDict, buffID=%s, %s" % (self._batObj.GetID(), buffID, self._buffIDDict.keys()))
            return
        #GameWorld.DebugLog("ObjBuff:%s, DelBuff %s, buffID=%s, dict:%s, len:%s, list:%s" % (self._batObj.GetID(), release, buffID, self._buffIDDict, len(self._buffList), self._buffList))
        buff = self._buffIDDict.pop(buffID)
        if buff in self._buffList:
            self._buffList.remove(buff)
        #GameWorld.DebugLog("    ObjBuff:%s, buffID=%s, dict:%s, len:%s, dictKeys:%s, list:%s" % (self._batObj.GetID(), buffID, len(self._buffIDDict), len(self._buffList), self._buffIDDict.keys(), self._buffList))
        for skillTypeID, buffIDList in self._skillTypeIDBuffIDs.items():
            if buffID not in buffIDList:
                continue
@@ -357,17 +384,19 @@
            if not buffIDList:
                self._skillTypeIDBuffIDs.pop(skillTypeID)
            break
        if release:
            ObjPool.GetPoolMgr().release(buff)
        return
    
    def GetBuff(self, buffID): return self._buffIDDict.get(buffID, None)
    def FindBuffIDBySkillID(self, skillID):
        ## 返回该技能ID的所有buffID列表
    def FindBuffBySkillID(self, skillID):
        ## 返回该技能ID的所有buff列表
        skillData = IpyGameDataPY.GetIpyGameData("Skill", skillID)
        if not skillData:
            return []
        return self.FindBuffIDBySkillTypeID(skillData.GetSkillTypeID())
    def FindBuffIDBySkillTypeID(self, skillTypeID):
        ## 返回该技能TypeID的所有buffID列表
        return self.FindBuffBySkillTypeID(skillData.GetSkillTypeID())
    def FindBuffBySkillTypeID(self, skillTypeID):
        ## 返回该技能TypeID的所有buff列表
        if skillTypeID not in self._skillTypeIDBuffIDs:
            return []
        buffs = []
@@ -402,7 +431,6 @@
    def IsInBuffState(self, state): return state in self._buffStateDict ## 是否处于某种状态下
    def GetStateBuffIDList(self, state): return self._buffStateDict.get(state, []) # 获取某种状态的所有buffID列表
    
class PySkill():
    
    def __init__(self, ipyData):
@@ -413,14 +441,14 @@
        self._tagObjList = [] # 本次技能目标列表 [BatObj, ...]
        self._hurtList = [] # 本次伤血列表,可能同一个对象有多个伤害,如弹射等 [HurtObj, ...]
        self._bySkill = None # 由哪个技能触发的
        self._isEnhanceSkill = False # 是否由主技能额外触发的(非被动触发,即主技能的EnhanceSkillList字段中的技能)
        self._afterLogicList = [] # 技能释放后需要处理逻辑 [[logicType, logicParams], ...]
        return
    
    def ResetUseRec(self):
        self._batType = 0
        self._tagObjList = []
        self._bySkill = None
        self._isEnhanceSkill = False
        self._afterLogicList = []
        self.ClearHurtObj()
        return
    
@@ -444,11 +472,11 @@
    def GetHappenRate(self): return self._skillData.GetHappenRate() # 触发概率
    def GetEffect(self, index): return self._skillData.GetEffect(index)
    def GetEffectCount(self): return self._skillData.GetEffectCount()
    def GetEffectByID(self, effID): return self._skillData.GetEffectByID()
    def GetEffectByID(self, effID): return self._skillData.GetEffectByID(effID)
    def GetConnSkill(self): return self._skillData.GetConnSkill()
    def GetCoolDownTime(self): return self._skillData.GetCoolDownTime()
    def GetIgnoreStates(self): return self._skillData.GetIgnoreStates() # 无视限制列表
    def GetBuffStates(self): return self._skillData.GetBuffStates()
    def GetCurBuffState(self): return self._skillData.GetCurBuffState()
    def GetLastTime(self): return self._skillData.GetLastTime() # 持续时间
    def GetLayerCnt(self): return self._skillData.GetLayerCnt()
    def GetLayerMax(self): return self._skillData.GetLayerMax()
@@ -456,6 +484,7 @@
    def GetDieContinue(self): return self._skillData.GetDieContinue() # Buff死亡存在
    def GetEnhanceSkillList(self): return self._skillData.GetEnhanceSkillList() # 额外触发的技能ID列表
    def GetFightPower(self): return self._skillData.GetFightPower()
    def GetSkillMotionName(self): return self._skillData.GetSkillMotionName()
    
    ## ---------------------------------- 非技能表内容 ----------------------------------
    def GetCalcTime(self): return self._calcTime
@@ -464,12 +493,18 @@
    def SetRemainTime(self, remainTime): self._remainTime = remainTime
    def GetBatType(self): return self._batType
    def SetBatType(self, batType): self._batType = batType
    def GetIsEnhanceSkill(self): return self._isEnhanceSkill
    def SetIsEnhanceSkill(self, isEnhanceSkill): self._isEnhanceSkill = isEnhanceSkill
    def GetBySkill(self): return self._bySkill
    def SetBySkill(self, bySkill): self._bySkill = bySkill
    def GetTagObjList(self): return self._tagObjList # 技能目标列表
    def SetTagObjList(self, tagObjList): self._tagObjList = tagObjList
    def GetAfterLogicList(self): return self._afterLogicList
    def AddAfterLogic(self, logicType, logicData):
        '''添加技能释放后需要处理额外逻辑
        @param logicType: 逻辑类型
        @param logicData: 逻辑对应的数据
        '''
        self._afterLogicList.append([logicType, logicData])
        return
    def ClearHurtObj(self):
        ## 清空伤血统计
        poolMgr = ObjPool.GetPoolMgr()
@@ -550,6 +585,7 @@
        self.ownerID = 0 # 所属玩家ID,可能为0,0代表非玩家的战斗实体
        self.heroID = 0
        self.skinID = 0
        self.atkDistType = 0
        self.lv = 1
        self.fightPower = 0
        self.faction = 0 # 所属阵营,一般只有双方阵营, 1 或 2,发起方默认1
@@ -557,6 +593,7 @@
        self.posNum = 0 # 所在阵容站位
        self._hp = 0 # 当前生命值
        self._xp = 0 # 当前怒气值
        self._isAlive = True # 是否活着
        self._initAttrDict = {} # 初始化时的属性,固定不变,初始化时已经算好的属性  {attrID:value, ...}
        self._batAttrDict = {} # 实际战斗属性,包含buff层级的实际属性
        self._skillTempAttrDict = {} # 某次技能释放中临时的属性增减 {attrID:+-value, ...}
@@ -605,6 +642,8 @@
    def GetID(self): return self.objID
    def GetName(self): return self.objName
    def SetName(self, name): self.objName = name
    def GetAtkDistType(self): return self.atkDistType
    def SetAtkDistType(self, atkDistType): self.atkDistType = atkDistType
    def GetNPCID(self): return self.npcID # 如果是NPC战斗单位,则该值非0
    def SetNPCID(self, npcID): self.npcID = npcID # 设置所属的NPCID
    def GetOwnerID(self): return self.ownerID # 如果是玩家战斗单位,则该值非0,为所属玩家ID
@@ -646,7 +685,41 @@
        ## 是否处于某种状态下
        return self._buffMgr.IsInBuffState(state)
    
    def IsInControlled(self):
        ## 是否被控制中
        for state in ChConfig.InControlledStateList:
            if self.IsInState(state):
                return True
        return False
    def CanAction(self):
        ## 是否可以行动
        if not self.IsAlive():
            return False
        if self.IsInControlled():
            return False
        return True
    def GetSneerTagObj(self):
        ## 获取被嘲讽的目标,如果存在则一定是活着的目标
        buffIDList = self._buffMgr.GetStateBuffIDList(ChConfig.BatObjState_Sneer)
        if not buffIDList:
            return
        objMgr = GetBatObjMgr()
        for buffID in buffIDList:
            buff = self._buffMgr.GetBuff(buffID)
            if not buff:
                continue
            tagObj = objMgr.getBatObj(buff.GetOwnerID())
            if tagObj and tagObj.IsAlive(): # 活着才有效
                return tagObj
        return
    # 战斗属性
    def IsAlive(self): return self._isAlive # 是否活着
    def SetDead(self):
        self._isAlive = False
        self._hp = 0
    def GetMaxHP(self): return self._batAttrDict.get(ChConfig.AttrID_MaxHP, 0)
    def SetMaxHP(self, maxHP, isNotify=False):
        self._batAttrDict[ChConfig.AttrID_MaxHP] = maxHP
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/TurnAttack.py
@@ -267,12 +267,12 @@
                    batObj = batObjMgr.getBatObj(objID)
                    if not batObj:
                        continue
                    if batObj.GetHP() > 0:
                    if batObj.IsAlive():
                        allKilled = False
                        break
                    
            if allKilled:
                self.winFaction = ChConfig.Def_FactionA if faction == ChConfig.Def_FactionB else ChConfig.Def_FactionA
                self.winFaction = ChConfig.Def_FactionA if faction == ChConfig.Def_FactionB else ChConfig.Def_FactionB
                DoTurnFightOver(self.guid)
                return self.winFaction
            
@@ -556,7 +556,7 @@
    
    batObjMgr = BattleObj.GetBatObjMgr()
    initXP = IpyGameDataPY.GetFuncCfg("AngerXP", 1)
    atkBackSkillIDList = IpyGameDataPY.GetFuncEvalCfg("ParryCfg", 3)
    atkBackSkillIDList = IpyGameDataPY.GetFuncEvalCfg("ParryCfg", 2)
    for posNumKey, heroInfo in heroDict.items():
        posNum = int(posNumKey)
        
@@ -597,6 +597,7 @@
        batObj.SetLineupPos(posNum, num)
        batObj.SetFightPower(fightPower)
        batObj.SetLV(lv)
        batObj.SetAtkDistType(atkDistType)
        if npcID:
            batObj.SetNPCID(npcID)
        elif lineupPlayerID:
@@ -1112,6 +1113,7 @@
    return
def OnTimelineChange(turnFight):
    ## 每个时间节点变化时处理
    
    nowTimeline = turnFight.getTimeline()
    
@@ -1120,8 +1122,14 @@
        for batLineup in batFaction.lineupDict.values():
            for objID in batLineup.posObjIDDict.values():
                batObj = batObjMgr.getBatObj(objID)
                if not batObj or batObj.GetHP() <= 0:
                #GameWorld.DebugLog("OnTimelineChange! objID=%s" % (objID))
                if not batObj or not batObj.IsAlive():
                    continue
                batObj.SetDict(ChConfig.Def_Obj_Dict_TurnComboNum, 0)
                batObj.SetDict(ChConfig.Def_Obj_Dict_TurnMissNum, 0)
                batObj.SetDict(ChConfig.Def_Obj_Dict_TurnParryNum, 0)
                curID = batObj.GetID()
                skillManager = batObj.GetSkillManager()
                for index in range(0, skillManager.GetSkillCount()):
@@ -1148,10 +1156,12 @@
                    remainTime = buff.GetRemainTime()
                    if not remainTime:
                        # 永久buff不处理
                        #GameWorld.DebugLog("    永久buff不处理! curID=%s,index=%s,skillID=%s" % (curID, index, buff.GetSkillID()))
                        continue
                    calcTimeline = buff.GetCalcTime()
                    passTurn = __calcPassturn(calcTimeline, nowTimeline, False)
                    if passTurn <= 0:
                        #GameWorld.DebugLog("    passTurn <= 0 passTurn=%s,calcTimeline=%s,nowTimeline=%s,skillID=%s" % (passTurn, calcTimeline, nowTimeline, buff.GetSkillID()))
                        continue
                    
                    updRemainTime = max(0, remainTime - passTurn)
@@ -1194,40 +1204,6 @@
        return
    
    TurnPassive.OnTriggerPassiveEffect(turnFight, batObj, ChConfig.TriggerWay_BigTurnStart)
#    SetTimeline(gameObj, turnNum, 0)
#    # 重置连击、反击数
#    gameObj.SetDict(ChConfig.Def_Obj_Dict_TurnComboNum, 0)
#    gameObj.SetDict(ChConfig.Def_Obj_Dict_TurnAtkBackNum, 0)
#    gameObj.SetDict(ChConfig.Def_Obj_Dict_TurnParryNum, 0)
#    gameObj.SetDict(ChConfig.Def_Obj_Dict_TurnMissNum, 0)
#    gameObj.SetDict(ChConfig.Def_Obj_Dict_TurnAtkAddXPCount, 0)
#    gameObj.SetDict(ChConfig.Def_Obj_Dict_TurnXPUseState, 0)
#    gameObj.SetDict(ChConfig.Def_PlayerKey_AttrFaintCD, 0) # 击晕CD
#
#    objType = gameObj.GetGameObjType()
#    objID = gameObj.GetID()
#    objName = GetObjName(gameObj)
#    GameWorld.DebugLog("ObjPerTurnStart: 回合%s, %s objType-ID-HP(%s-%s-%s)" % (turnNum, objName, objType, objID, GameObj.GetHP(gameObj)))
#
#    # 每回合开始减技能CD
#    skillManager = gameObj.GetSkillManager()
#    for i in range(skillManager.GetSkillCount()):
#        skill = skillManager.GetSkillByIndex(i)
#        remainTime = skill.GetRemainTime()
#        if not remainTime:
#            continue
#        skillID = skill.GetSkillID()
#        updRemainTime = max(0, remainTime - ChConfig.Def_PerTurnTick)
#        skill.SetRemainTime(updRemainTime)
#        GameWorld.DebugLog("    skillID=%s,remainTime=%s,updRemainTime=%s" % (skillID, remainTime, updRemainTime))
#
#    # 刷新定时处理的buff效果
#    SkillShell.ProcessPersistBuff(gameObj, tick)
#
#    PassiveBuffEffMng.OnPassiveSkillTrigger(gameObj, tagObj, None, ChConfig.TriggerType_TurnNum, tick)
#
#    __logGameObjAttr(gameObj)
    return
def TurnFightPerTurnBigEnd(turnFight, batObj, turnNum):
@@ -1271,6 +1247,8 @@
def AddTurnObjHurtValue(curBatObj, tagBatObj, hurtValue, lostHP, skillID=0, isBounce=False):
    ## 回合对象添加伤害值
    # @param isBounce: 是否反弹伤害
    if hurtValue <= 0:
        return
    curID = curBatObj.GetID()
    tagID = tagBatObj.GetID()
    if curID != tagID:
@@ -1279,7 +1257,7 @@
                       % (curID, tagID, skillID, hurtValue, lostHP, updStatValue, tagBatObj.GetHP(), isBounce))
        
        if tagBatObj:
            updStatValue = tagBatObj.StatDefValue(lostHP)
            updStatValue = tagBatObj.StatDefValue(hurtValue)
            GameWorld.DebugLog("        统计承伤: curID=%s,tagID=%s,skillID=%s,hurtValue=%s,lostHP=%s,updStatValue=%s,curHP=%s,isBounce=%s" 
                           % (tagID, curID, skillID, hurtValue, lostHP, updStatValue, tagBatObj.GetHP(), isBounce))
            
@@ -1303,8 +1281,7 @@
    objName = GetObjName(curBatObj)
    
    # 是否可行动状态判断
    canAction = True
    canAction = curBatObj.CanAction()
    if not canAction:
        GameWorld.DebugLog("★回合%s %s 当前状态不可行动!" % (turnNum, objName))
        return
@@ -1338,6 +1315,9 @@
        if SkillCommon.isAngerSkill(useSkill):
            if curXP < xpMax:
                continue
            if curBatObj.IsInState(ChConfig.BatObjState_Sneer):
                GameWorld.DebugLog("嘲讽状态下,无法主动释放怒技!") # 可被动释放怒技,如怒技追击
                continue
            useCnt = -1 # xp技能优先释放
        else:
            useCnt = curBatObj.GetSkillUseCnt(skillID)
@@ -1354,166 +1334,12 @@
    TurnPassive.OnTriggerPassiveEffect(turnFight, curBatObj, ChConfig.TriggerWay_HeroActionEnd)
    return True
def DoAttack(curBatObj, tagBatObj, tick, turnBattleType=ChConfig.TurnBattleType_Normal, useSkill=None):
#    curID = curBatObj.GetID()
#    npcID = curBatObj.GetNPCID()
#    objName = GetObjName(curBatObj)
#    GameWorld.DebugLog("    ● %s DoAttack: curID=%s,,turnBattleType=%s" % (objName, curID, turnBattleType))
#
#    atkOK = False
#    curBatObj.SetDict(ChConfig.Def_Obj_Dict_TurnBattleType, turnBattleType)
#
#    if turnBattleType == ChConfig.TurnBattleType_AtkBack:
#        if not tagBatObj:
#            return
#        skillManager = curBatObj.GetSkillManager()
#        for index in range(0, skillManager.GetSkillCount()):
#            skill = skillManager.GetSkillByIndex(index)
#            if not skill:
#                continue
#            if skill.GetFuncType() == ChConfig.Def_SkillFuncType_AtkbackSkill:
#                useSkill = skill
#                break
#        atkOK = SkillShell.DoLogic_UseSkill(curBatObj, tagBatObj, useSkill, tick)
#    elif turnBattleType == ChConfig.TurnBattleType_Combo:
#        if not tagBatObj:
#            return
#        atkOK = SkillShell.DoLogic_UseSkill(curBatObj, tagBatObj, useSkill, tick)
#    else:
#        curXP = GameObj.GetXP(curBatObj)
#        xpMax = IpyGameDataPY.GetFuncCfg("AngerXP", 2)
#        skillManager = curBatObj.GetSkillManager()
#        useSkillList = []
#        #GameWorld.DebugLog('skillCount=%s' % skillManager.GetSkillCount(), npcID)
#        for index in range(0, skillManager.GetSkillCount()):
#            useSkill = skillManager.GetSkillByIndex(index)
#            if not useSkill:
#                continue
#            if useSkill.GetFuncType() in [ChConfig.Def_SkillFuncType_AtkbackSkill]:
#                #基础普攻不能主动释放,目前仅用于反击
#                continue
#            #被动技能无法使用
#            if SkillCommon.isPassiveSkill(useSkill):
#                continue
#            #还在冷却时间内无法释放
#            if useSkill.GetRemainTime():
#                continue
#            skillID = useSkill.GetSkillID()
#            # 常规攻击优先xp
#            if SkillCommon.isAngerSkill(useSkill) and turnBattleType == ChConfig.TurnBattleType_Normal:
#                if curXP < xpMax:
#                    continue
#                useCnt = -1 # xp技能优先释放
#            else:
#                useCnt = curBatObj.GetDictByKey(ChConfig.Def_NPC_Dict_SkillUseCnt % skillID) # 该技能已使用次数
#            useSkillList.append([useCnt, index, skillID, useSkill])
#
#        useSkillList.sort() # 按使用次数优先升序排,使用次数低的优先判断使用
#        #GameWorld.DebugLog('    技能使用顺序 = useSkillList%s' % str(useSkillList), npcID)
#
#        for useInfo in useSkillList:
#            useSkill = useInfo[-1]
#            #skillID = useSkill.GetSkillID()
#            atkOK, tagBatObj = OnUseSkill(curBatObj, useSkill, tick)
#            if atkOK:
#                break
#
#    curBatObj.SetDict(ChConfig.Def_Obj_Dict_TurnBattleType, 0) # 无论攻击成功与否都重置战斗类型
#
#    tagID = 0
#    tagHP = 0
#    if tagObj:
#        tagID = tagObj.GetID()
#        tagHP = GameObj.GetHP(tagObj)
#    GameWorld.DebugLog('        atkOK=%s,tagID=%s,tagHP=%s' % (atkOK, tagID, tagHP), npcID)
#    if not atkOK:
#        return
#
#    if not tagObj:
#        return
#
#    if GameObj.GetFaction(curNPC) == GameObj.GetFaction(tagObj):
#        # 同阵营直接返回,不处理连击、反击
#        return True
#
#    curHP = GameObj.GetHP(curNPC)
#    tagHP = GameObj.GetHP(tagObj)
#    tagID = tagObj.GetID()
#    GameWorld.DebugLog("            curID-HP=(%s-%s),tagID-HP=(%s-%s)" % (curID, curHP, tagID, tagHP))
#    if tagHP <= 0 or curHP <= 0:
#        return True
#
#    # 反击,反击可打断连击,所以优先判断
#    if CanAtkBack(curNPC, tagObj):
#        DoAttack(tagObj, curNPC, tick, ChConfig.TurnBattleType_AtkBack)
#        return True
#
#    # 连击
#    if CanCombo(curNPC, tagObj):
#        DoAttack(curNPC, tagObj, tick, ChConfig.TurnBattleType_Combo, useSkill)
#
    return True
def CanAtkBack(atkObj, defObj):
    ## 可否反击
    posNum = atkObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnFightPosInfo) % 100
    if posNum <= 0:
        GameWorld.DebugLog("            被非主战单位攻击时无法触发反击: atkID=%s,posNum=%s" % (atkObj.GetID(), posNum))
        return False
    atkDistType = AttackCommon.GetAtkDistType(defObj)
    if atkDistType == ChConfig.AtkDistType_Long:
        if not IpyGameDataPY.GetFuncCfg("ParryCfg", 2):
            GameWorld.DebugLog("            远程单位不可反击: defID=%s" % (defObj.GetID()))
            return False
    defAtkBackRate = GameObj.GetAtkBackRate(defObj) # 防方反击率
    atkBackNum = defObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnAtkBackNum) # 已反击次数
    if atkBackNum > 10:
        # 内置最高反击数防范
        return False
    if atkBackNum > 0:
        validPerList = IpyGameDataPY.GetFuncEvalCfg("TurnFight", 4)
        vaildPer = validPerList[atkBackNum - 1] if len(validPerList) >= atkBackNum else 0
        defAtkBackRate = int(defAtkBackRate * vaildPer / 100.0)
    atkAtkBackDefRate = GameObj.GetAtkBackDefRate(atkObj) # 攻方抵抗反击率
    atkBackRate = max(0, defAtkBackRate - atkAtkBackDefRate)
    if atkBackRate <= 0 or not GameWorld.CanHappen(atkBackRate):
        GameWorld.DebugLog("            无法反击: defID=%s,atkBackNum=%s,atkBackRate=%s=(defAtkBackRate=%s - atkAtkBackDefRate=%s)"
                           % (defObj.GetID(), atkBackNum, atkBackRate, defAtkBackRate, atkAtkBackDefRate))
        return False
    GameWorld.DebugLog("            可以反击: defID=%s,atkBackNum=%s,atkBackRate=%s=(defAtkBackRate=%s - atkAtkBackDefRate=%s)"
                       % (defObj.GetID(), atkBackNum, atkBackRate, defAtkBackRate, atkAtkBackDefRate))
    return True
def CanCombo(atkObj, defObj):
    ## 可否连击
    atkComboRate = GameObj.GetComboRate(atkObj) # 攻方连击率
    comboNum = atkObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnComboNum) # 已连击次数
    if comboNum > 10:
        # 内置最高连击数防范
        return False
    if comboNum > 0:
        validPerList = IpyGameDataPY.GetFuncEvalCfg("TurnFight", 3)
        vaildPer = validPerList[comboNum - 1] if len(validPerList) >= comboNum else 0
        atkComboRate = int(atkComboRate * vaildPer / 100.0)
    defComboReduce = GameObj.GetComboDefRate(defObj) # 防方抵抗连击率
    comboRate = max(0, atkComboRate - defComboReduce)
    if comboRate <= 0 or not GameWorld.CanHappen(comboRate):
        GameWorld.DebugLog("            无法连击: atkID=%s,comboNum=%s,comboRate=%s=(atkComboRate=%s - defComboReduce=%s)"
                           % (atkObj.GetID(), comboNum, comboRate, atkComboRate, defComboReduce))
        return False
    GameWorld.DebugLog("            可以连击: atkID=%s,comboNum=%s,comboRate=%s=(atkComboRate=%s - defComboReduce=%s)"
                       % (atkObj.GetID(), comboNum, comboRate, atkComboRate, defComboReduce))
    return True
def SetObjKilled(turnFight, gameObj, killer=None, useSkill=None):
    objID = gameObj.GetID()
    GameWorld.DebugLog("        %s 回合战斗主体被击杀: curID=%s" % (GetObjName(gameObj), objID))
    gameObj.SetHP(0)
    killerObjID = killer.GetID() if killer else 0
    skillID = useSkill.GetSkillID() if useSkill else 0
    GameWorld.DebugLog("        %s 回合战斗主体被击杀: curID=%s,killerObjID=%s,skillID=%s" % (GetObjName(gameObj), objID, killerObjID, skillID))
    gameObj.SetDead()
    
    clientPack = ObjPool.GetPoolMgr().acquire(ChPyNetSendPack.tagMCTurnFightObjDead)
    clientPack.ObjID = objID
@@ -1551,7 +1377,7 @@
    
    turnFight.costTime = time.time() - turnFight.startTime
    winFaction = turnFight.winFaction
    GameWorld.DebugLog("--- 战斗结束处理 --- %s, winFaction=%s, costTime=%ss" % (guid, winFaction, turnFight.costTime))
    GameWorld.DebugLog("--- 战斗结束处理 ---, winFaction=%s, costTime=%ss, %s" % (winFaction, turnFight.costTime, guid))
    
    # 统计明细
    batObjMgr = BattleObj.GetBatObjMgr()
@@ -1577,7 +1403,7 @@
                atkHurt = batObj.hurtStat
                defHurt = batObj.defStat
                cureHP = batObj.cureStat
                GameWorld.DebugLog("    Pos:%s ID=%s-%s-%s,,HP=%s/%s, 输出=%s,承伤=%s,治疗=%s"
                GameWorld.DebugLog("    Pos:%s ID=%s,npcID=%s,heroID=%s,HP=%s/%s, 输出=%s,承伤=%s,治疗=%s"
                                   % (posNum, objID, npcID, heroID, batObj.GetHP(), batObj.GetMaxHP(), atkHurt, defHurt, cureHP))
                lineupStatInfo[str(posNum)] = {"ObjID":objID, "HeroID":heroID, "NPCID":npcID, "AtkHurt":atkHurt, "DefHurt":defHurt, "CureHP":cureHP}
                
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
@@ -954,8 +954,11 @@
Def_SkillID_Peace = 23048   # 玩家间和平buff
#----------------------------------------------------------------------
#战斗类型
Def_ChanceDefRate = 2000    # 抵御伤害概率, 目前固定20%概率
#技能释放后需要额外处理逻辑
AfterLogic_DelBuff = "DelBuff"
AfterLogic_AddBuff = "AddBuff"
AfterLogic_SyncBuff = "SyncBuff"
#伤害类型
(
@@ -1312,6 +1315,17 @@
CampType_Justice = ShareDefine.CampType_Justice  # 正义
CampType_Evil = ShareDefine.CampType_Evil  # 邪恶
#buff释放类型
BuffAtkType_DamageShield = 1003 # 承伤盾
#计算类型
Def_CalcTypeList = (
Def_Calc_Attack, # 攻击 0
Def_Calc_MaxHP, # 最大生命值 1
Def_Calc_HurtValue, # 伤害值 2
Def_Calc_TagMaxHP, # 目标最大生命值 3
) = range(4)
#治疗类型(影响公式参数)
Def_CureTypeList = (
Def_Cure_Attack, # 攻击 0
@@ -1339,6 +1353,22 @@
Def_Skill_HappenState_LuckyHit = 0x0004  # 必会心一击
Def_Skill_HappenState_ThumpHit = 0x0008  # 必重击
# 回合战斗行列数
TurnFightRows = 2
TurnFightCols = 3
def GetInColNum(posNum):
    ## 获取站位编号所在列编号
    # @param posNum: 在阵容中的站位 1 ~ n
    # @return:  1 ~ 总列数
    return (posNum - 1) % TurnFightCols + 1
def GetInRowNum(posNum):
    ## 获取站位编号所在行编号
    # @param posNum: 在阵容中的站位 1 ~ n
    # @return:  1 ~ 总行数
    return (posNum - 1) / TurnFightCols + 1
# 技能目标 - 瞄准范围
(
SkillTagAim_All, # 全部 0
@@ -1356,7 +1386,8 @@
SkillTagAffect_HPLowest, # 血量最低 1
SkillTagAffect_HPHighest, # 血量最高 2
SkillTagAffect_Death, # 死亡单位 3
) = range(4)
SkillTagAffect_UncontrolledPriority, # 未被控制优先 4
) = range(5)
#技能施法目标
Def_UseSkillAim_Type = 3
@@ -3060,11 +3091,13 @@
# 回合攻击战斗类型
(
TurnBattleType_Normal, # 常规攻击
TurnBattleType_Combo, # 连击
TurnBattleType_AtkBack, # 反击
TurnBattleType_Pursue , # 追击
) = range(4)
TurnBattleType_Normal, # 常规攻击 0
TurnBattleType_Combo, # 连击 1
TurnBattleType_AtkBack, # 反击 2
TurnBattleType_Pursue, # 追击 3
TurnBattleType_Enhance, # 额外技能 4
TurnBattleType_Passive, # 被动技能 5
) = range(6)
Def_PerTurnTick = 1000 # 每回合等同于常规tick时长
@@ -3158,7 +3191,11 @@
    BatObjState_Sneer, # 嘲讽 9
    BatObjState_LimitSkill, # 沉默 10
    BatObjState_LimitAddHP, # 禁疗 11
) = range(12)
    BatObjState_Stone, # 石化 12
) = range(13)
# 被控制的状态列表,无法行动,处于某些控制类buff影响状态下,如晕眩,冰冻,石化
InControlledStateList = [BatObjState_Frozen, BatObjState_Stun, BatObjState_Stone]
#玩家状态定义,不能超过31个,如超过,需扩展多个key支持
Def_PlayerStateList = (
@@ -4465,7 +4502,16 @@
TriggerWay_HeroTurnEnd, # 武将回合开始时    5
TriggerWay_HeroActionStart, # 武将行动前    6
TriggerWay_HeroActionEnd, # 武将行动后    7
) = range(1, 1 + 7)
TriggerWay_CalcTagInState, # 攻击计算时对方处于xx状态时(参数:状态1|2|...)一般用于攻击时属性计算  8
TriggerWay_AttackOverTagInState, # 攻击计算后对方处于xx状态时(参数:状态1|2|...)一般用于攻击后触发效果  9
TriggerWay_AttackOverDirect, # 直接攻击后 (非buff攻击)10
TriggerWay_BeAttackedDirect, # 受到直接攻击时 (非buff攻击)11
TriggerWay_ShieldBroken, # 承伤盾被击破时 12
) = range(1, 1 + 12)
# 被动触发有效来源
TriggerSrc_Skill = 1
TriggerSrc_Buff = 2
(
TriggerType_BeSuperHit, # 被暴击触发技能 1
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
@@ -49970,6 +49970,9 @@
                  ("LastTime", c_int),    # 剩余时长毫秒/回合数
                  ("Layer", c_ushort),    # 层数,不需要默认0
                  ("OwnerID", c_int),    # buff来源者,即施法方
                  ("Value1", c_int),
                  ("Value2", c_int),
                  ("Value3", c_int),
                  ]
    def __init__(self):
@@ -49993,6 +49996,9 @@
        self.LastTime = 0
        self.Layer = 0
        self.OwnerID = 0
        self.Value1 = 0
        self.Value2 = 0
        self.Value3 = 0
        return
    def GetLength(self):
@@ -50011,7 +50017,10 @@
                                RelatedSkillID:%d,
                                LastTime:%d,
                                Layer:%d,
                                OwnerID:%d
                                OwnerID:%d,
                                Value1:%d,
                                Value2:%d,
                                Value3:%d
                                '''\
                                %(
                                self.Cmd,
@@ -50022,7 +50031,10 @@
                                self.RelatedSkillID,
                                self.LastTime,
                                self.Layer,
                                self.OwnerID
                                self.OwnerID,
                                self.Value1,
                                self.Value2,
                                self.Value3
                                )
        return DumpString
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
@@ -116,10 +116,9 @@
                        ("BYTE", "TriggerWay3", 0),
                        ("BYTE", "TriggerSrc3", 0),
                        ("list", "TriggerParams3", 0),
                        ("DWORD", "ConnSkill", 0),
                        ("WORD", "CoolDownTime", 0),
                        ("list", "IgnoreStates", 0),
                        ("list", "BuffStates", 0),
                        ("BYTE", "CurBuffState", 0),
                        ("WORD", "LastTime", 0),
                        ("BYTE", "LayerCnt", 0),
                        ("BYTE", "LayerMax", 0),
@@ -127,6 +126,7 @@
                        ("DWORD", "DieContinue", 0),
                        ("list", "EnhanceSkillList", 0),
                        ("DWORD", "FightPower", 0),
                        ("char", "SkillMotionName", 0),
                        ),
                "Hero":(
@@ -2989,29 +2989,29 @@
    def GetEffectID1(self): return self.attrTuple[17] # 效果ID1 DWORD
    def GetEffectValues1(self): return self.attrTuple[18] # 效果值列表1 list
    def GetTriggerWay1(self): return self.attrTuple[19] # 触发方式 BYTE
    def GetTriggerSrc1(self): return self.attrTuple[20] # 触发来源 BYTE
    def GetTriggerSrc1(self): return self.attrTuple[20] # 有效来源 BYTE
    def GetTriggerParams1(self): return self.attrTuple[21] # 触发参数 list
    def GetEffectID2(self): return self.attrTuple[22] # 效果ID2 DWORD
    def GetEffectValues2(self): return self.attrTuple[23] # 效果值列表2 list
    def GetTriggerWay2(self): return self.attrTuple[24] # 触发方式 BYTE
    def GetTriggerSrc2(self): return self.attrTuple[25] # 触发来源 BYTE
    def GetTriggerSrc2(self): return self.attrTuple[25] # 有效来源 BYTE
    def GetTriggerParams2(self): return self.attrTuple[26] # 触发参数 list
    def GetEffectID3(self): return self.attrTuple[27] # 效果ID3 DWORD
    def GetEffectValues3(self): return self.attrTuple[28] # 效果值列表3 list
    def GetTriggerWay3(self): return self.attrTuple[29] # 触发方式 BYTE
    def GetTriggerSrc3(self): return self.attrTuple[30] # 触发来源 BYTE
    def GetTriggerSrc3(self): return self.attrTuple[30] # 有效来源 BYTE
    def GetTriggerParams3(self): return self.attrTuple[31] # 触发参数 list
    def GetConnSkill(self): return self.attrTuple[32] # 关联技能 DWORD
    def GetCoolDownTime(self): return self.attrTuple[33] # 技能冷却时间 WORD
    def GetIgnoreStates(self): return self.attrTuple[34] # 无视限制列表 list
    def GetBuffStates(self): return self.attrTuple[35] # Buff״ֵ̬ list
    def GetLastTime(self): return self.attrTuple[36] # 持续时间 WORD
    def GetLayerCnt(self): return self.attrTuple[37] # Buff层数 BYTE
    def GetLayerMax(self): return self.attrTuple[38] # 最大层数 BYTE
    def GetBuffRepeat(self): return self.attrTuple[39] # Buff叠加规则 DWORD
    def GetDieContinue(self): return self.attrTuple[40] # Buff死亡存在 DWORD
    def GetEnhanceSkillList(self): return self.attrTuple[41] # 触发技能ID列表 list
    def GetFightPower(self): return self.attrTuple[42] # 技能战斗力 DWORD
    def GetCoolDownTime(self): return self.attrTuple[32] # 技能冷却时间 WORD
    def GetIgnoreStates(self): return self.attrTuple[33] # 无视限制列表 list
    def GetCurBuffState(self): return self.attrTuple[34] # Buff״ֵ̬ BYTE
    def GetLastTime(self): return self.attrTuple[35] # 持续时间 WORD
    def GetLayerCnt(self): return self.attrTuple[36] # Buff层数 BYTE
    def GetLayerMax(self): return self.attrTuple[37] # 最大层数 BYTE
    def GetBuffRepeat(self): return self.attrTuple[38] # Buff叠加规则 DWORD
    def GetDieContinue(self): return self.attrTuple[39] # Buff死亡存在 DWORD
    def GetEnhanceSkillList(self): return self.attrTuple[40] # 触发技能ID列表 list
    def GetFightPower(self): return self.attrTuple[41] # 技能战斗力 DWORD
    def GetSkillMotionName(self): return self.attrTuple[42] # 技能动作名 char
# 武将表
class IPY_Hero():
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/GameSkills/SkillCommon.py
@@ -1848,6 +1848,10 @@
    #0通哟  1 PVP类型  2PVE类型  
    return curSkill.GetHurtType() % 10
def isDamageShieldSkill(skillData):
    ## 是否承伤盾技能
    return skillData.GetAtkType() == ChConfig.BuffAtkType_DamageShield
def isAngerSkill(curSkill):
    ## 是否怒气技能
    return curSkill and curSkill.GetFuncType() == ChConfig.Def_SkillFuncType_AngerSkill
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/PassiveTrigger/PassiveEff_5001.py
@@ -17,7 +17,7 @@
import TurnBuff
def DoBuffEffectLogic(turnFight, batObj, curBuff, curEffect, connSkill):
def DoBuffEffectLogic(turnFight, batObj, tagObj, curBuff, curEffect, connSkill):
    singleLayerCnt = max(1, curEffect.GetEffectValue(0)) # 单次消耗层数/次数
    noDel = curEffect.GetEffectValue(1) # 是否不扣除层数,默认0-扣除 1-不扣除
    isAll = curEffect.GetEffectValue(2) # 是否结算剩余全部层数/次数,默认0结算单次
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/PassiveTrigger/PassiveEff_5010.py
New file
@@ -0,0 +1,69 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
##@package Skill.PassiveTrigger.PassiveEff_5010
#
# @todo:攻击方触发释放技能(可继承主技能目标或重新设置目标)
# @author hxp
# @date 2025-08-25
# @version 1.0
#
# 详细描述: 攻击方触发释放技能(可继承主技能目标或重新设置目标)
#
#-------------------------------------------------------------------------------
#"""Version = 2025-08-25 12:00"""
#-------------------------------------------------------------------------------
import TurnSkill
import IpyGameDataPY
import GameWorld
import ChConfig
def DoSkillEffectLogic(turnFight, batObj, tagObj, effSkill, curEffect, connSkill):
    effectID = curEffect.GetEffectID()
    skillID = curEffect.GetEffectValue(0)
    if not skillID:
        passiveSkill = effSkill
    else:
        passiveSkill = IpyGameDataPY.GetIpyGameData("Skill", skillID)
    if not passiveSkill:
        return
    passiveSkillID = passiveSkill.GetSkillID()
    tagObjList = connSkill.GetTagObjList() if connSkill else []
    # 继承主技能目标
    if passiveSkill.GetTagAim() == ChConfig.SkillTagAim_MainSkill and tagObjList:
        happenRate = passiveSkill.GetHappenRate()
        GameWorld.DebugLog("被动触发技能,继承主技能目标! effectID=%s,passiveSkillID=%s,happenRate=%s" % (effectID, passiveSkillID, happenRate))
        passiveTagObjList = []
        for tagObj in tagObjList:
            tagID = tagObj.GetID()
            if tagObj.GetHP() <= 0:
                GameWorld.DebugLog("    已被击杀不触发: tagID=%s" % (tagID))
                continue
            inHurt = False
            for hurtObj in connSkill.GetHurtObjList():
                if hurtObj.GetObjID() != tagID:
                    continue
                if not hurtObj.GetHurtHP() or hurtObj.HaveHurtType(ChConfig.HurtType_Miss):
                    continue
                inHurt = True
                break
            if not inHurt:
                GameWorld.DebugLog("    没有伤血不触发: tagID=%s" % (tagID))
                continue
            if happenRate and happenRate != ChConfig.Def_MaxRateValue and not GameWorld.CanHappen(happenRate, ChConfig.Def_MaxRateValue):
                GameWorld.DebugLog("    概率不触发: tagID=%s,happenRate=%s" % (tagID, happenRate))
                continue
            passiveTagObjList.append(tagObj)
        if passiveTagObjList:
            TurnSkill.OnUseSkill(turnFight, batObj, passiveSkill, passiveTagObjList, batType=ChConfig.TurnBattleType_Passive, bySkill=connSkill)
    else:
        GameWorld.DebugLog("被动触发技能,重新锁定目标! effectID=%s,passiveSkillID=%s" % (effectID, passiveSkillID))
        TurnSkill.OnUseSkill(turnFight, batObj, passiveSkill, batType=ChConfig.TurnBattleType_Passive, bySkill=connSkill)
    return
def DoBuffEffectLogic(turnFight, batObj, tagObj, curBuff, curEffect, connSkill):
    return DoSkillEffectLogic(turnFight, batObj, tagObj, None, curEffect, connSkill)
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/PassiveTrigger/PassiveEff_5011.py
New file
@@ -0,0 +1,58 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
##@package Skill.PassiveTrigger.PassiveEff_5011
#
# @todo:被击方触发释放技能(对攻击方或重新设置目标)
# @author hxp
# @date 2025-08-25
# @version 1.0
#
# 详细描述: 被击方触发释放技能(对攻击方或重新设置目标)
#
#-------------------------------------------------------------------------------
#"""Version = 2025-08-25 12:00"""
#-------------------------------------------------------------------------------
import TurnSkill
import IpyGameDataPY
import GameWorld
import ChConfig
def DoSkillEffectLogic(turnFight, batObj, tagObj, effSkill, curEffect, connSkill):
    effectID = curEffect.GetEffectID()
    skillID = curEffect.GetEffectValue(0)
    if not skillID:
        passiveSkill = effSkill
    else:
        passiveSkill = IpyGameDataPY.GetIpyGameData("Skill", skillID)
    if not passiveSkill:
        return
    passiveSkillID = passiveSkill.GetSkillID()
    # 继承主技能目标
    if passiveSkill.GetTagAim() == ChConfig.SkillTagAim_MainSkill:
        happenRate = passiveSkill.GetHappenRate()
        GameWorld.DebugLog("被动触发技能,继承主技能目标! effectID=%s,passiveSkillID=%s,happenRate=%s" % (effectID, passiveSkillID, happenRate))
        tagObjList = [tagObj]
        passiveTagObjList = []
        for tagObj in tagObjList:
            tagID = tagObj.GetID()
            if tagObj.GetHP() <= 0:
                GameWorld.DebugLog("    已被击杀不触发: tagID=%s" % (tagID))
                continue
            if happenRate and happenRate != ChConfig.Def_MaxRateValue and not GameWorld.CanHappen(happenRate, ChConfig.Def_MaxRateValue):
                GameWorld.DebugLog("    概率不触发: tagID=%s,happenRate=%s" % (tagID, happenRate))
                continue
            passiveTagObjList.append(tagObj)
        if passiveTagObjList:
            TurnSkill.OnUseSkill(turnFight, batObj, passiveSkill, passiveTagObjList, batType=ChConfig.TurnBattleType_Passive, bySkill=connSkill)
    else:
        GameWorld.DebugLog("被动触发技能,重新锁定目标! effectID=%s,passiveSkillID=%s" % (effectID, passiveSkillID))
        TurnSkill.OnUseSkill(turnFight, batObj, passiveSkill, batType=ChConfig.TurnBattleType_Passive, bySkill=connSkill)
    return
def DoBuffEffectLogic(turnFight, batObj, tagObj, curBuff, curEffect, connSkill):
    return DoSkillEffectLogic(turnFight, batObj, tagObj, None, curEffect, connSkill)
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnBuff.py
@@ -18,44 +18,70 @@
import ChConfig
import GameWorld
import ChPyNetSendPack
import IpyGameDataPY
import TurnBuffs
import BattleObj
import ObjPool
GameWorld.ImportAll("Script\\Skill\\", "TurnBuffs")
def GetAddBuffValue(attacker, defender, curSkill):
def GetAddBuffValue(turnFight, attacker, defender, curSkill):
    callFunc = GameWorld.GetExecFunc(TurnBuffs, "BuffAtkType_%d.%s" % (curSkill.GetAtkType(), "CalcBuffValue"))
    if not callFunc:
        return []
    return callFunc(attacker, defender, curSkill)
    return callFunc(turnFight, attacker, defender, curSkill)
def OnAddBuff(turnFight, batObj, buffSkill, buffOwner=None):
def DoAddBuffBySkillID(turnFight, batObj, skillID, buffOwner=None, bySkill=None, afterLogic=False):
    ## 根据技能ID添加buff
    if not skillID:
        return
    skillIpyData = IpyGameDataPY.GetIpyGameData("Skill", skillID)
    if not skillIpyData:
        return
    tagObjList = [batObj]
    poolMgr = ObjPool.GetPoolMgr()
    useSkill = poolMgr.acquire(BattleObj.PySkill, skillIpyData)
    useSkill.SetTagObjList(tagObjList)
    OnAddBuff(turnFight, batObj, useSkill, buffOwner, bySkill, afterLogic)
    poolMgr.release(useSkill)
    return
def OnAddBuff(turnFight, batObj, buffSkill, buffOwner=None, bySkill=None, afterLogic=False):
    skillID = buffSkill.GetSkillID()
    bySkill = buffSkill.GetBySkill()
    bySkill = buffSkill.GetBySkill() if not bySkill else bySkill
    relatedSkillID = bySkill.GetSkillID() if bySkill else 0
    curID = batObj.GetID()
    if not buffOwner:
        buffOwner = batObj
    ownerID = buffOwner.GetID()
    buffValueList = GetAddBuffValue(buffOwner, batObj, buffSkill)
    GameWorld.DebugLog("OnAddBuff: curID=%s,skillID=%s,ownerID=%s,relatedSkillID=%s,buffValueList=%s" % (curID, skillID, ownerID, relatedSkillID, buffValueList))
    buffValueList = GetAddBuffValue(turnFight, buffOwner, batObj, buffSkill)
    GameWorld.DebugLog("OnAddBuff: curID=%s,skillID=%s,atkType=%s,buffValueList=%s,ownerID=%s,relatedSkillID=%s"
                       % (curID, skillID, buffSkill.GetAtkType(), buffValueList, ownerID, relatedSkillID))
    
    skillTypeID = buffSkill.GetSkillTypeID()
    # 先简单做下能加上即可
    buffMgr = batObj.GetBuffManager()
    buffIDList = buffMgr.FindBuffIDBySkillTypeID(skillTypeID)
    if buffIDList:
        GameWorld.DebugLog("    已经存在该buff: skillTypeID=%s,buffIDList=%s" % (skillTypeID, buffIDList))
        # buff堆叠逻辑
    buffList = buffMgr.FindBuffBySkillTypeID(skillTypeID)
    if buffList:
        # buff堆叠逻辑,待处理,先直接通知
        for buff in buffList:
            if not buff:
                continue
            GameWorld.DebugLog("    已经存在该buff: buffID=%s,skillTypeID=%s" % (buff.GetBuffID(), skillTypeID))
            if afterLogic and bySkill:
                bySkill.AddAfterLogic(ChConfig.AfterLogic_AddBuff, [batObj, buff, buffOwner])
            else:
                SyncBuffRefresh(turnFight, batObj, buff, relatedSkillID)
        
        return True
    
    __AddNewBuff(turnFight, batObj, buffMgr, buffSkill, buffValueList, buffOwner)
    __AddNewBuff(turnFight, batObj, buffMgr, buffSkill, buffValueList, buffOwner, bySkill, afterLogic)
    return True
def __AddNewBuff(turnFight, batObj, buffMgr, buffSkill, buffValueList, buffOwner):
def __AddNewBuff(turnFight, batObj, buffMgr, buffSkill, buffValueList, buffOwner, bySkill=None, afterLogic=False):
    skillID = buffSkill.GetSkillID()
    bySkill = buffSkill.GetBySkill()
    relatedSkillID = bySkill.GetSkillID() if bySkill else 0
    curID = batObj.GetID()
    ownerID = buffOwner.GetID()
@@ -71,11 +97,13 @@
    buff.SetRemainTime(buffSkill.GetLastTime())
    buff.SetLayer(buffSkill.GetLayerCnt())
    buff.SetBuffValueList(buffValueList)
    buffStates = buffSkill.GetBuffStates()
    for buffState in buffStates:
        buffMgr.AddBuffState(buffState, buffID)
    isNotify = True
    if isNotify:
    curBuffState = buffSkill.GetCurBuffState()
    if curBuffState:
        buffMgr.AddBuffState(curBuffState, buffID)
    if afterLogic and bySkill:
        bySkill.AddAfterLogic(ChConfig.AfterLogic_AddBuff, [batObj, buff, buffOwner])
    else:
        SyncBuffRefresh(turnFight, batObj, buff, relatedSkillID)
        
    DoBuffAddOver(turnFight, batObj, buffSkill, buff, buffOwner)
@@ -101,7 +129,7 @@
            continue
        
        if curEffect.GetTriggerWay():
            if curEffect.GetTriggerSrc() == 2:
            if curEffect.GetTriggerSrc() != ChConfig.TriggerSrc_Skill:
                passiveEffMgr.AddBuffPassiveEffect(addBuff, buffSkill, curEffect)
                
        elif effectID in ChConfig.AttrIDList:
@@ -117,12 +145,24 @@
        
    return
def DoBuffDel(turnFight, batObj, curBuff):
    ## 删除buff
def DoBuffDel(turnFight, batObj, curBuff, relatedSkill=None, afterLogic=False, tagObj=None):
    '''删除buff
    @param relatedSkill: 关联的技能
    @param afterLogic: 是否需要在关联技能处理完毕后才处理删除后续逻辑,如通知,触发被动等
    @param tagObj: 由谁引起的buff删除
    '''
    release = True
    isSync = True
    relatedSkillID = relatedSkill.GetSkillID() if relatedSkill else 0
    if afterLogic and relatedSkill:
        release = False
        isSync = False
    
    isRefreshAttr = False # 是否刷属性
    haveBuffPassiveEff = False
    
    buffObjID = batObj.GetID()
    buffMgr = batObj.GetBuffManager()
    buffID = curBuff.GetBuffID()
    skillData = curBuff.GetSkillData()
@@ -135,7 +175,7 @@
            continue
        
        if curEffect.GetTriggerWay():
            if curEffect.GetTriggerSrc() == 2:
            if curEffect.GetTriggerSrc() != ChConfig.TriggerSrc_Skill:
                haveBuffPassiveEff = True
                
        elif effectID in ChConfig.AttrIDList:
@@ -149,16 +189,27 @@
    if haveBuffPassiveEff:
        batObj.GetPassiveEffManager().DelBuffPassiveEffect(buffID)
        
    buffStates = skillData.GetBuffStates()
    for buffState in buffStates:
        buffMgr.DelBuffState(buffState, buffID)
    curBuffState = skillData.GetCurBuffState()
    if curBuffState:
        buffMgr.DelBuffState(curBuffState, buffID)
        
    # 最后删除buff、通知
    buffMgr.DelBuff(buffID)
    SyncBuffDel(turnFight, batObj, buffID)
    buffMgr.DelBuff(buffID, release)
    if isSync:
        SyncBuffDel(turnFight, buffObjID, buffID, relatedSkillID)
    if afterLogic and relatedSkill:
        tagObjID = tagObj.GetID() if tagObj else buffObjID
        relatedSkill.AddAfterLogic(ChConfig.AfterLogic_DelBuff, [buffObjID, curBuff, tagObjID])
    
    if isRefreshAttr:
        RefreshBuffAttr(batObj)
    return
def DoBuffDelAfterLogicOver(turnFight, buffObjID, curBuff, relatedSkill):
    ## buff删除后续处理逻辑处理完毕
    relatedSkillID = relatedSkill.GetSkillID() if relatedSkill else 0
    SyncBuffDel(turnFight, buffObjID, curBuff.GetBuffID(), relatedSkillID)
    ObjPool.GetPoolMgr().release(curBuff)
    return
def DoBuffProcess(turnFight, batObj, curBuff):
@@ -245,12 +296,15 @@
    clientPack.LastTime = curBuff.GetRemainTime()
    clientPack.Layer = curBuff.GetLayer()
    clientPack.OwnerID = curBuff.GetOwnerID()
    clientPack.Value1 = curBuff.GetValue1()
    clientPack.Value2 = curBuff.GetValue2()
    clientPack.Value3 = curBuff.GetValue3()
    turnFight.addBatPack(clientPack)
    return
def SyncBuffDel(turnFight, curBatObj, buffID, relatedSkillID=0):
def SyncBuffDel(turnFight, objID, buffID, relatedSkillID=0):
    clientPack = ObjPool.GetPoolMgr().acquire(ChPyNetSendPack.tagSCBuffDel)
    clientPack.ObjID = curBatObj.GetID()
    clientPack.ObjID = objID
    clientPack.BuffID = buffID
    clientPack.RelatedSkillID = relatedSkillID
    turnFight.addBatPack(clientPack)
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnBuffs/BuffAtkType_1001.py
@@ -16,19 +16,20 @@
#-------------------------------------------------------------------------------
import TurnSkill
import ChConfig
def CalcBuffValue(attacker, defender, curSkill):
def CalcBuffValue(turnFight, attacker, defender, curSkill):
    #calcType = curSkill.GetCalcType()
    skillPer = curSkill.GetSkillPer()
    skillValue = curSkill.GetSkillValue()
    
    hurtValue, hurtTypes = TurnSkill.CalcHurtHP(attacker, defender, curSkill, skillValue, skillPer, damageoftime=1)
    return [hurtValue, hurtTypes]
    hurtValue, hurtTypes = TurnSkill.CalcHurtHP(turnFight, attacker, defender, curSkill, skillValue, skillPer, damageoftime=1)
    return [hurtValue % ChConfig.Def_PerPointValue, hurtValue / ChConfig.Def_PerPointValue, hurtTypes]
def DoBuffProcess(turnFight, batObj, curBuff):
    ## 执行单次逻辑
    hurtValue = curBuff.GetBuffValue(0) # 单次伤害
    hurtTypes = curBuff.GetBuffValue(1)
    hurtValue = curBuff.GetValue1() + curBuff.GetValue2() * ChConfig.Def_PerPointValue # 单次伤害
    hurtTypes = curBuff.GetValue3()
    TurnSkill.DoDOTAttack(turnFight, batObj, curBuff, hurtValue, hurtTypes)
    return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnBuffs/BuffAtkType_1003.py
New file
@@ -0,0 +1,27 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
##@package Skill.TurnBuffs.BuffAtkType_1003
#
# @todo:承伤护盾
# @author hxp
# @date 2025-08-25
# @version 1.0
#
# 详细描述: 承伤护盾
#
#-------------------------------------------------------------------------------
#"""Version = 2025-08-25 12:00"""
#-------------------------------------------------------------------------------
import TurnSkill
import ChConfig
def CalcBuffValue(turnFight, attacker, defender, curSkill):
    calcType = curSkill.GetCalcType()
    skillPer = curSkill.GetSkillPer()
    skillValue = curSkill.GetSkillValue()
    baseValue = TurnSkill.GetCalcBaseValue(calcType, attacker, defender)
    shieldValue = int(baseValue * skillPer / 10000.0) + skillValue
    return [shieldValue % ChConfig.Def_PerPointValue, shieldValue / ChConfig.Def_PerPointValue]
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnPassive.py
@@ -31,31 +31,49 @@
    buffEffInfo and GameWorld.DebugLog("    被动Buff效果: %s" % buffEffInfo)
    return
def OnTriggerPassiveEffect(turnFight, batObj, triggerType, connSkill=None):
def OnTriggerPassiveEffect(turnFight, batObj, triggerType, tagObj=None, connSkill=None, connSkillTypeID=0):
    ''' 触发被动效果,可能触发技能、buff,需根据优先级触发
    '''
    passiveEffMgr = batObj.GetPassiveEffManager()
    effInfoList = passiveEffMgr.GetPassiveEffByTrigger(triggerType, connSkill=connSkill)
    if not connSkillTypeID and connSkill:
        connSkillTypeID = connSkill.GetSkillTypeID()
    effInfoList = passiveEffMgr.GetPassiveEffByTrigger(triggerType, connSkillTypeID)
    if not effInfoList:
        return
    # [["skill/buff", skillID/buffID, effIDList], ...]
    GameWorld.DebugLog("触发被动: triggerType=%s,objID=%s,%s" % (triggerType, batObj.GetID(), effInfoList))
    tagID = tagObj.GetID() if tagObj else 0
    GameWorld.DebugLog("触发被动: triggerType=%s,objID=%s,tagID=%s,%s" % (triggerType, batObj.GetID(), tagID, effInfoList))
    for effInfo in effInfoList:
        sign = effInfo[0]
        if sign == "skill":
            skillID, effIDList = effInfo[1:]
            __doTriggerPassiveEffectBySkill(turnFight, batObj, skillID, effIDList, connSkill)
            __doTriggerPassiveEffectBySkill(turnFight, batObj, tagObj, skillID, effIDList, connSkill)
            
        elif sign == "buff":
            buffID, effIDList = effInfo[1:]
            __doTriggerPassiveEffectByBuff(turnFight, batObj, buffID, effIDList, connSkill)
            __doTriggerPassiveEffectByBuff(turnFight, batObj, tagObj, buffID, effIDList, connSkill)
            
    return
def __doTriggerPassiveEffectBySkill(turnFight, batObj, skillID, effIDList, connSkill=None):
def __doTriggerPassiveEffectBySkill(turnFight, batObj, tagObj, skillID, effIDList, connSkill=None):
    skillMgr = batObj.GetSkillManager()
    effSkill = skillMgr.FindSkillByID(skillID)
    if not effSkill:
    return
def __doTriggerPassiveEffectByBuff(turnFight, batObj, buffID, effIDList, connSkill=None):
    for effID in effIDList:
        curEffect = effSkill.GetEffectByID(effID)
        if not curEffect:
            continue
        pyName = "PassiveEff_%s" % effID
        callFunc = GameWorld.GetExecFunc(PassiveTrigger, "%s.%s" % (pyName, "DoSkillEffectLogic"))
        if not callFunc:
            continue
        callFunc(turnFight, batObj, tagObj, effSkill, curEffect, connSkill)
    return
def __doTriggerPassiveEffectByBuff(turnFight, batObj, tagObj, buffID, effIDList, connSkill=None):
    buffMgr = batObj.GetBuffManager()
    curBuff = buffMgr.GetBuff(buffID)
    if not curBuff:
@@ -70,7 +88,7 @@
        callFunc = GameWorld.GetExecFunc(PassiveTrigger, "%s.%s" % (pyName, "DoBuffEffectLogic"))
        if not callFunc:
            continue
        callFunc(turnFight, batObj, curBuff, curEffect, connSkill)
        callFunc(turnFight, batObj, tagObj, curBuff, curEffect, connSkill)
        
    return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnSkill.py
@@ -24,6 +24,7 @@
import ChPyNetSendPack
import PlayerControl
import ShareDefine
import TurnPassive
import TurnAttack
import TurnBuff
import ObjPool
@@ -44,7 +45,7 @@
    ## 是否无视防御
    return useSkill.GetHurtType() / 10 == 1 # 2为真伤,待扩展
def OnUseSkill(turnFight, curBatObj, useSkill, tagObjList=None, batType=ChConfig.TurnBattleType_Normal, bySkill=None, isEnhanceSkill=False):
def OnUseSkill(turnFight, curBatObj, useSkill, tagObjList=None, batType=ChConfig.TurnBattleType_Normal, bySkill=None):
    '''使用技能通用入口
    @param useSkill: 使用的技能,注意并不一定是身上的技能,可能只是 SkillData 表数据
    @param bySkill: 由哪个技能额外触发的,比如附加触发的技能或被动技能均可能由某个技能触发
@@ -76,8 +77,8 @@
        return
    
    bySkillID = bySkill.GetSkillID() if bySkill else 0
    GameWorld.DebugLog("使用技能: curID=%s,skillID=%s,tagCnt=%s,batType=%s,bySkillID=%s,isEnhanceSkill=%s"
                       % (curBatObj.GetID(), skillID, len(tagObjList), batType, bySkillID, isEnhanceSkill))
    GameWorld.DebugLog("使用技能: curID=%s,skillID=%s,tagCnt=%s,batType=%s,bySkillID=%s"
                       % (curBatObj.GetID(), skillID, len(tagObjList), batType, bySkillID))
    # 以下为技能可以使用的处理,之后的逻辑默认技能使用成功
    
    poolMgr = ObjPool.GetPoolMgr()
@@ -87,11 +88,10 @@
        # 统一使用 BattleObj.PySkill
        useSkill = poolMgr.acquire(BattleObj.PySkill, useSkill)
        
    useSkill.ResetUseRec()
    useSkill.SetTagObjList(tagObjList)
    useSkill.SetBatType(batType)
    useSkill.SetBySkill(bySkill)
    useSkill.SetIsEnhanceSkill(isEnhanceSkill)
    useSkill.ClearHurtObj()
    
    curBatObj.ClearSkillTempAttr()
    for tagObj in tagObjList:
@@ -99,7 +99,11 @@
        
    objID = curBatObj.GetID()
    useTag = ""
    if not isEnhanceSkill:
    #这个技能是Buff
    if SkillCommon.IsBuff(useSkill):
        __doAddBuff(turnFight, curBatObj, useSkill)
    else:
        # 因为可能触发连击,所以标记需带上累计使用技能次数,确保唯一
        useTag = "Skill_%s_%s_%s" % (objID, skillID, curBatObj.GetSkillUseCnt(skillID) + 1)
        clientPack = poolMgr.acquire(ChPyNetSendPack.tagSCTurnFightTag)
@@ -108,11 +112,9 @@
        clientPack.Sign = 0
        turnFight.addBatPack(clientPack)
        
    #这个技能是Buff
    if SkillCommon.IsBuff(useSkill):
        __doAddBuff(turnFight, curBatObj, useSkill)
    else:
        __doUseSkill(turnFight, curBatObj, useSkill)
    DoAttackResult(turnFight, curBatObj, useSkill)
        
    if useTag:
        clientPack = poolMgr.acquire(ChPyNetSendPack.tagSCTurnFightTag)
@@ -120,6 +122,9 @@
        clientPack.Len = len(clientPack.Tag)
        clientPack.Sign = 1
        turnFight.addBatPack(clientPack)
    # 处理反击 或 连击
    DoCombo(turnFight, curBatObj, useSkill)
        
    # 最后重置、回收对象
    useSkill.ResetUseRec()
@@ -129,16 +134,26 @@
def GetSkillTags(turnFight, curBatObj, tagAim, tagFriendly, tagAffect, tagCount):
    ## 获取技能目标    
    # @return: [主目标, 目标2, ...]
    curFaction = curBatObj.GetFaction()
    
    # 自己,直接返回
    if tagAim == ChConfig.SkillTagAim_Self:
        return [curBatObj]
    
    sneerObj = None # 嘲讽目标
    sneerObjID, sneerObjPosNum = 0, 0
    if tagFriendly:
        tagFaction = curFaction
    else:
        tagFaction = ChConfig.Def_FactionB if curFaction == ChConfig.Def_FactionA else ChConfig.Def_FactionA
        sneerObj = curBatObj.GetSneerTagObj() # 被嘲讽的目标,对敌的强制锁定被嘲讽目标
    sneerObjFirst = True # 嘲讽目标优先
    if sneerObj:
        sneerObjID = sneerObj.GetID()
        sneerObjPosNum = sneerObj.GetPosNum()
        
    batObjMgr = BattleObj.GetBatObjMgr()
    lineupNum = curBatObj.GetLineupNum()
@@ -159,84 +174,68 @@
        
        # 对位
        if tagAim == ChConfig.SkillTagAim_Relative:
            posNumList = [posNum] # 优先对位位置,再其他位置按顺序遍历
            pNumList = batLineup.posObjIDDict.keys()
            pNumList.sort()
            for pNum in pNumList:
                if pNum > 0 and pNum not in posNumList:
                    posNumList.append(pNum)
            for pNum in posNumList:
                if pNum not in batLineup.posObjIDDict:
                    continue
                tagObjID = batLineup.posObjIDDict[pNum]
                tagBatObj = batObjMgr.getBatObj(tagObjID)
                if not __skillTagFilter(tagBatObj, tagAffect):
                    continue
                aimObjList.append(tagBatObj) # 对位的默认只选1个
                break
            if sneerObj:
                aimObjList.append(sneerObj)
            else:
                relativeObj = __GetRelativeObjDefault(batObjMgr, curBatObj, posNum, batLineup)
                if relativeObj:
                    aimObjList.append(relativeObj)
            
        # 前排
        elif tagAim == ChConfig.SkillTagAim_FrontRow:
            # 优先前排,如果没有则后排亦是前排
            for pNumList in [[1, 2, 3], [4, 5, 6]]:
                hasObj = False
                for pNum in pNumList:
                    if pNum not in batLineup.posObjIDDict:
                        continue
                    tagObjID = batLineup.posObjIDDict[pNum]
                    tagBatObj = batObjMgr.getBatObj(tagObjID)
                    if not __skillTagFilter(tagBatObj, tagAffect):
                        continue
                    hasObj = True
                    aimObjList.append(tagBatObj)
                if hasObj:
                    break
            aimObjList = __getRowAimObjList(batObjMgr, posNum, sneerObj, batLineup, tagAffect, False)
                
        # 后排
        elif tagAim == ChConfig.SkillTagAim_BackRow:
            # 优先后排,如果没有则前排亦是后排
            for pNumList in [[4, 5, 6], [1, 2, 3]]:
                hasObj = False
                for pNum in pNumList:
                    if pNum not in batLineup.posObjIDDict:
                        continue
                    tagObjID = batLineup.posObjIDDict[pNum]
                    tagBatObj = batObjMgr.getBatObj(tagObjID)
                    if not __skillTagFilter(tagBatObj, tagAffect):
                        continue
                    hasObj = True
                    aimObjList.append(tagBatObj)
                if hasObj:
                    break
            aimObjList = __getRowAimObjList(batObjMgr, posNum, sneerObj, batLineup, tagAffect, True)
                
        # 竖排/纵排
        elif tagAim == ChConfig.SkillTagAim_Vertical:
            verticalNumList = [[1, 4], [2, 5], [3, 6]]
            for pNumList in verticalNumList:
                # 优先对位排
                if posNum in pNumList:
                    verticalNumList.remove(pNumList)
                    verticalNumList.insert(0, pNumList)
                    break
            for pNumList in verticalNumList:
                hasObj = False
                for pNum in pNumList:
            # 优先自己所在纵
            inColNum = ChConfig.GetInColNum(posNum)
            colNumList = range(1, 1 + ChConfig.TurnFightCols)
            if inColNum in colNumList:
                colNumList.remove(inColNum)
                colNumList.insert(0, inColNum)
            # 优先嘲讽所在纵
            if sneerObj:
                sneerInColNum = ChConfig.GetInColNum(sneerObjPosNum)
                if sneerInColNum in colNumList:
                    colNumList.remove(sneerInColNum)
                    colNumList.insert(0, sneerInColNum)
            GameWorld.DebugLog("纵排: colNumList=%s,sneerObjID-PosNum=%s-%s" % (colNumList, sneerObjID, sneerObjPosNum))
            for col in colNumList:
                for row in range(1, 1 + ChConfig.TurnFightRows):
                    pNum = (row - 1) * ChConfig.TurnFightCols + col
                    #GameWorld.DebugLog("    col=%s,row=%s,pNum=%s" % (col, row, pNum))
                    if pNum not in batLineup.posObjIDDict:
                        continue
                    tagObjID = batLineup.posObjIDDict[pNum]
                    tagBatObj = batObjMgr.getBatObj(tagObjID)
                    if not __skillTagFilter(tagBatObj, tagAffect):
                        continue
                    hasObj = True
                    aimObjList.append(tagBatObj)
                if hasObj:
                if aimObjList:
                    break
                
        # 其他,默认全部
        else:
            pNumList = batLineup.posObjIDDict.keys()
            for pNum in pNumList:
                if pNum <= 0:
            inColNum = ChConfig.GetInColNum(posNum) # 玩家所在纵列
            # 优先自己所在纵
            colNumList = range(1, 1 + ChConfig.TurnFightCols)
            if inColNum in colNumList:
                colNumList.remove(inColNum)
                colNumList.insert(0, inColNum)
            GameWorld.DebugLog("全部: colNumList=%s,sneerObjID-PosNum=%s-%s" % (colNumList, sneerObjID, sneerObjPosNum))
            # 按前排优先原则
            for row in range(1, 1 + ChConfig.TurnFightRows):
                for col in colNumList:
                    pNum = (row - 1) * ChConfig.TurnFightCols + col
                    #GameWorld.DebugLog("    col=%s,row=%s,pNum=%s" % (col, row, pNum))
                    if pNum not in batLineup.posObjIDDict:
                    continue
                tagObjID = batLineup.posObjIDDict[pNum]
                tagBatObj = batObjMgr.getBatObj(tagObjID)
@@ -249,33 +248,150 @@
    if tagAffect == ChConfig.SkillTagAffect_HPLowest:
        aimObjList.sort(key=lambda o:(o.GetHP()), reverse=False)
        #GameWorld.DebugLog("血量最低排序: %s" % [[o.GetID(), o.GetHP(), o.GetMaxHP()] for o in aimObjList])
        aimObjList = aimObjList[:tagCount]
        
    # 血量最高
    elif tagAffect == ChConfig.SkillTagAffect_HPHighest:
        aimObjList.sort(key=lambda o:(o.GetHP()), reverse=True)
        #GameWorld.DebugLog("血量最高排序: %s" % [[o.GetID(), o.GetHP(), o.GetMaxHP()] for o in aimObjList])
        aimObjList = aimObjList[:tagCount]
    # 未被控制优先
    elif tagAffect == ChConfig.SkillTagAffect_UncontrolledPriority:
        sneerObjFirst = False
        aimObjList.sort(key=lambda o:(o.IsInControlled()))
        GameWorld.DebugLog("未被控制优先: %s" % [[o.GetID(), o.IsInControlled()] for o in aimObjList])
        
    else:
        # 范围目标超过个数,则随机取
        if tagCount and len(aimObjList) > tagCount:
            random.shuffle(aimObjList)
    # 嘲讽优先
    if sneerObjFirst and sneerObj:
        if sneerObj in aimObjList and aimObjList.index(sneerObj) != 0:
            aimObjList.remove(sneerObj)
            aimObjList.insert(0, sneerObj)
    if tagCount and len(aimObjList) > tagCount:
            aimObjList = aimObjList[:tagCount]
            
    return aimObjList
def __getRowAimObjList(batObjMgr, posNum, sneerObj, batLineup, tagAffect, rowReverse):
    ## 获取行排目标对象列表
    # @param rowReverse: 是否后排优先原则
    # 前后排顺序
    if rowReverse:
        rowNumList = range(1, 1 + ChConfig.TurnFightRows)[::-1]
    else:
        rowNumList = range(1, 1 + ChConfig.TurnFightRows)
    # 优先嘲讽对象所在行
    sneerObjID, sneerObjPosNum = 0, 0
    if sneerObj:
        sneerObjID = sneerObj.GetID()
        sneerObjPosNum = sneerObj.GetPosNum()
        sneerInRowNum = ChConfig.GetInRowNum(sneerObjPosNum) # 所在行排
        if sneerInRowNum in rowNumList:
            rowNumList.remove(sneerInRowNum)
            rowNumList.insert(0, sneerInRowNum)
    inColNum = ChConfig.GetInColNum(posNum) # 玩家所在纵列
    # 优先自己所在纵,为主目标
    colNumList = range(1, 1 + ChConfig.TurnFightCols)
    if inColNum in colNumList:
        colNumList.remove(inColNum)
        colNumList.insert(0, inColNum)
    GameWorld.DebugLog("前后排: rowNumList=%s,colNumList=%s,sneerObjID-PosNum=%s-%s" % (rowNumList, colNumList, sneerObjID, sneerObjPosNum))
    aimObjList = []
    for row in rowNumList:
        for col in colNumList:
            pNum = (row - 1) * ChConfig.TurnFightCols + col
            #GameWorld.DebugLog("    row=%s,col=%s,pNum=%s" % (row, col, pNum))
            if pNum not in batLineup.posObjIDDict:
                continue
            tagObjID = batLineup.posObjIDDict[pNum]
            tagBatObj = batObjMgr.getBatObj(tagObjID)
            if not __skillTagFilter(tagBatObj, tagAffect):
                continue
            aimObjList.append(tagBatObj)
        if aimObjList:
            break
    return aimObjList
def GetRelativeObj(turnFight, curBatObj):
    '''获取对位目标,嘲讽时优先对位嘲讽目标
    对位目标用途:
    1. 对位目标并不代表仅攻击该目标
    2. 攻击时根据技能攻击目标范围优先攻击对位目标所在的横排或纵排
    3. 对位目标可用于判断连击、弱疗
    '''
    sneerObj = curBatObj.GetSneerTagObj()
    if sneerObj:
        # 有嘲讽目标优先直接对位
        return sneerObj
    curFaction = curBatObj.GetFaction()
    # 默认对位敌对阵营
    tagFaction = ChConfig.Def_FactionB if curFaction == ChConfig.Def_FactionA else ChConfig.Def_FactionA
    batObjMgr = BattleObj.GetBatObjMgr()
    lineupNum = curBatObj.GetLineupNum()
    posNum = curBatObj.GetPosNum()
    batFaction = turnFight.getBatFaction(tagFaction)
    lineupNumList = [lineupNum] # 敌方优先对位阵容,再其他阵容,支持多阵容对战
    for tagNum in batFaction.lineupDict.keys():
        if tagNum not in lineupNumList:
            lineupNumList.append(tagNum)
    for num in lineupNumList:
        batLineup = batFaction.getBatlineup(num)
        relativeObj = __GetRelativeObjDefault(batObjMgr, curBatObj, posNum, batLineup)
        if relativeObj:
            return relativeObj
    # 理论上只要战斗没有结束,一定会有对位目标,这里默认返回自己,外层可不需要判断是否存在对位目标
    return curBatObj
def __GetRelativeObjDefault(batObjMgr, curBatObj, posNum, batLineup):
    ## 获取在某一阵营中的默认对位目标
    tagAffect = ChConfig.SkillTagAffect_None # 默认对位目标不需要细分目标,默认规则即可
    inColNum = ChConfig.GetInColNum(posNum) # 玩家所在纵列
    # 优先自己所在纵
    colNumList = range(1, 1 + ChConfig.TurnFightCols)
    if inColNum in colNumList:
        colNumList.remove(inColNum)
        colNumList.insert(0, inColNum)
    # 按前排优先原则
    for row in range(ChConfig.TurnFightRows):
        for col in colNumList:
            pNum = row * ChConfig.TurnFightCols + col
            if pNum not in batLineup.posObjIDDict:
                continue
            tagObjID = batLineup.posObjIDDict[pNum]
            tagBatObj = batObjMgr.getBatObj(tagObjID)
            if not __skillTagFilter(tagBatObj, tagAffect):
                continue
            return tagBatObj
    return
def __skillTagFilter(tagBatObj, tagAffect):
    ## 技能目标过滤器
    # @return: 是否允许添加该单位
    if not tagBatObj:
        return False
    if tagAffect != ChConfig.SkillTagAffect_Death and tagBatObj.GetHP() <= 0:
    if tagAffect != ChConfig.SkillTagAffect_Death and not tagBatObj.IsAlive():
        return False
    if tagAffect == ChConfig.SkillTagAffect_Death and tagBatObj.GetHP() > 0:
    if tagAffect == ChConfig.SkillTagAffect_Death and tagBatObj.IsAlive():
        return False
    if not tagBatObj.GetCanAttack():
        return False
    #if not tagBatObj.GetCanAttack(): 策划要求不可攻击的对象也要可选中
    #    return False
    return True
def __doAddBuff(turnFight, curBatObj, useSkill):
@@ -284,7 +400,6 @@
    for tagBatObj in useSkill.GetTagObjList():
        TurnBuff.OnAddBuff(turnFight, tagBatObj, useSkill, buffOwner=curBatObj)
        
    DoAttackResult(turnFight, curBatObj, useSkill)
    return
def __doUseSkill(turnFight, curBatObj, useSkill):
@@ -294,50 +409,36 @@
    # 通用攻击
    if atkType == 1:
        SkillModule_1(turnFight, curBatObj, useSkill)
        return
    # 治疗
    if atkType == 2:
        SkillModule_2(turnFight, curBatObj, useSkill)
        return
    # 复活
    if atkType == 3:
        return
    elif atkType == 3:
        pass
    # 多次攻击(锁目标多次伤害,非前端的多段飘血)
    if atkType == 4:
        return
    elif atkType == 4:
        pass
    # 弹射(多次攻击,切换目标)
    if atkType == 5:
        return
    elif atkType == 5:
        pass
    # 怒气增
    if atkType == 6:
    elif atkType == 6:
        SkillModule_6(turnFight, curBatObj, useSkill, "Increase")
        return
    # 怒气减
    if atkType == 7:
    elif atkType == 7:
        SkillModule_6(turnFight, curBatObj, useSkill, "Reduce")
        return
    # 怒气偷
    if atkType == 8:
    elif atkType == 8:
        SkillModule_6(turnFight, curBatObj, useSkill, "Steal")
        return
    
    return
def SkillModule_1(turnFight, curBatObj, useSkill):
    ## 通用攻击,单攻、群攻
    
    #执行攻击结果
    for tagBatObj in useSkill.GetTagObjList():
        __doSkillHurtHP(curBatObj, tagBatObj, useSkill)
        __doSkillHurtHP(turnFight, curBatObj, tagBatObj, useSkill)
        
    DoAttackResult(turnFight, curBatObj, useSkill)
    return
def SkillModule_2(turnFight, curBatObj, useSkill):
@@ -366,7 +467,6 @@
        
        TurnAttack.AddTurnObjCureHP(tagBatObj, curBatObj, cureHP, realCureHP, skillID)
        
    DoAttackResult(turnFight, curBatObj, useSkill)
    return
def SkillModule_6(turnFight, curBatObj, useSkill, opType):
@@ -432,7 +532,6 @@
        GameWorld.DebugLog("    加总怒气: curID=%s,curStealTotal=%s,curXP=%s,updXP=%s" % (curID, curStealTotal, curXP, updValue))
        Sync_PropertyRefreshView(turnFight, curBatObj, attrID, updValue, diffValue, diffType, skillID, relatedSkillID)
        
    DoAttackResult(turnFight, curBatObj, useSkill)
    return
def DoAttackResult(turnFight, curBatObj, useSkill):
@@ -451,51 +550,191 @@
        useSkill.SetCalcTime(turnFight.getTimeline())
        useSkill.SetRemainTime(useSkill.GetCoolDownTime())
        
    # 需先通知伤血 - 前端按顺序优先表现技能释放内容,
    isEnhanceSkill = useSkill.GetIsEnhanceSkill()
    if not isEnhanceSkill or len(useSkill.GetHurtObjList()):
    # 需先技能使用 - 前端按顺序优先表现技能释放内容,前端需要动作或有伤血则通知
    if useSkill.GetSkillMotionName() or len(useSkill.GetHurtObjList()):
        Sync_UseSkill(turnFight, curBatObj, useSkill)
    if not isEnhanceSkill:
        __doCostZhanchui(turnFight, curBatObj, useSkill)
        __doSkillUserAnger(turnFight, curBatObj, useSkill)
        
    DoBeAttackOver(turnFight, curBatObj, useSkill)
    DoBeAttackResult(turnFight, curBatObj, useSkill)
    return
    
    # 最后处理反击 或 连击
def DoCombo(turnFight, curBatObj, useSkill):
    '''
        格挡、反击、连击规则
        1. 所有武将或怪物均可能产生格挡,群攻时格挡一对一判断,均可能产生格挡
        2. 仅普攻时可被反击,反判断本次技能目标中的主目标(即对位目标)是否产生格挡,且是近战武将,是的话可反击
        连击:
        1. 仅普攻可连击,反击打断连击
        2. 非对敌技能,如奶妈回血普攻,判断对位目标抗连属性是否可连击
        3. 对敌技能,判断本次技能目标中的主目标(即对位目标)抗连属性是否可连击
        对敌技能主目标:
                单体: 默认该目标
                嘲讽: 优先被嘲讽的目标
                横排: 优先该排中与自己同列的,否则按顺序
                纵排: 优先前面的单位
    '''
    if not SkillCommon.isTurnNormalSkill(useSkill):
        #GameWorld.DebugLog("非普攻不处理反击连击")
        return
    tagFriendly = useSkill.GetTagFriendly()
    if tagFriendly:
        tagObj = GetRelativeObj(turnFight, curBatObj)
    else:
        tagObjList = useSkill.GetTagObjList()
        if not tagObjList:
            return
        tagObj = tagObjList[0] # 第一个默认为主目标,技能对象选择逻辑时决定主目标
        atkBackSkill = __getCanAtkBackSkill(useSkill, tagObj)
        if atkBackSkill:
            # 可以反击,打断连击
            GameWorld.DebugLog("● %s 【反击】" % TurnAttack.GetObjName(tagObj))
            OnUseSkill(turnFight, tagObj, atkBackSkill, [curBatObj], ChConfig.TurnBattleType_AtkBack)
            return
    if not tagObj:
        return
    if CanCombo(curBatObj, tagObj):
        # 连击根据技能目标配置逻辑重新选择目标
        GameWorld.DebugLog("● %s 【连击】" % TurnAttack.GetObjName(curBatObj))
        OnUseSkill(turnFight, curBatObj, useSkill, batType=ChConfig.TurnBattleType_Combo)
    
    return
def DoBeAttackOver(turnFight, curBatObj, useSkill):
def __getCanAtkBackSkill(useSkill, tagObj):
    ## 获取是否可反击及反击技能
    if not tagObj:
        return
    tagID = tagObj.GetID()
    if tagObj.GetAtkDistType() != ChConfig.AtkDistType_Short:
        GameWorld.DebugLog("非近战不可反击! tagID=%s" % tagID)
        return
    canAtkBack = False
    for hurtObj in useSkill.GetHurtObjList():
        if hurtObj.GetObjID() != tagID:
            continue
        if hurtObj.HaveHurtType(ChConfig.HurtType_Parry): # 格挡时可反击
            canAtkBack = True
            break
    if not canAtkBack:
        GameWorld.DebugLog("没有格挡不可反击! tagID=%s" % tagID)
        return
    skillManager = tagObj.GetSkillManager()
    for index in range(0, skillManager.GetSkillCount()):
        useSkill = skillManager.GetSkillByIndex(index)
        if not useSkill:
            continue
        if useSkill.GetFuncType() == ChConfig.Def_SkillFuncType_AtkbackSkill:
            GameWorld.DebugLog("可以反击! tagID=%s" % tagID)
            return useSkill
    return
def CanCombo(atkObj, defObj):
    ## 可否连击
    comboNum = atkObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnComboNum)
    aComboRate = atkObj.GetBatAttrValue(ChConfig.AttrID_ComboRate)
    dComboRateDef = defObj.GetBatAttrValue(ChConfig.AttrID_ComboRateDef)
    happenRate = eval(IpyGameDataPY.GetFuncCompileCfg("ComboCfg", 1))
    if GameWorld.CanHappen(happenRate):
        GameWorld.DebugLog("可以连击! atkID=%s,happenRate=%s,aComboRate=%s,dComboRateDef=%s,comboNum=%s"
                           % (atkObj.GetID(), happenRate, aComboRate, dComboRateDef, comboNum))
        atkObj.SetDict(ChConfig.Def_Obj_Dict_TurnComboNum, comboNum + 1)
        return True
    GameWorld.DebugLog("无法连击! atkID=%s,happenRate=%s,aComboRate=%s,dComboRateDef=%s,comboNum=%s"
                       % (atkObj.GetID(), happenRate, aComboRate, dComboRateDef, comboNum))
    return False
def DoBeAttackResult(turnFight, curObj, useSkill):
    '''被攻击结果
    @param curBatObj: 施法方或buff归属方
    @param curObj: 施法方或buff归属方
    '''
    
    curID = curObj.GetID()
    isTurnNormalSkill = SkillCommon.isTurnNormalSkill(useSkill)
    isAngerSkill = SkillCommon.isAngerSkill(useSkill)
    
    # 统计死亡
    batObjMgr = BattleObj.GetBatObjMgr()
    # 优先处理afterLogic,可再预先汇总一些会触发被动的信息
    relatedSkillID = useSkill.GetSkillID()
    shieldBrokenList = [] # 记录盾破
    afterLogicList = useSkill.GetAfterLogicList()
    for logicType, logicData in afterLogicList:
        if logicType == ChConfig.AfterLogic_DelBuff:
            buffObjID, buff, tagObjID = logicData
            buffSkillData = buff.GetSkillData()
            buffSkillTypeID = buffSkillData.GetSkillTypeID()
            TurnBuff.DoBuffDelAfterLogicOver(turnFight, buffObjID, buff, useSkill)
            if SkillCommon.isDamageShieldSkill(buffSkillData):
                shieldBrokenList.append([buffObjID, tagObjID, buffSkillTypeID])
        elif logicType == ChConfig.AfterLogic_AddBuff:
            batObj, buff, _ = logicData
            TurnBuff.SyncBuffRefresh(turnFight, batObj, buff, relatedSkillID)
        elif logicType == ChConfig.AfterLogic_SyncBuff:
            buffObj, buff, _, _ = logicData
            TurnBuff.SyncBuffRefresh(turnFight, buffObj, buff, relatedSkillID)
    # 统计结果
    killObjIDList = [] # 击杀的目标ID列表
    for tagObj in useSkill.GetTagObjList():
        tagID = tagObj.GetID()
        # 可能单个技能对同一目标造成多次伤害,所以这里遍历,如弹射等
        for hurtObj in useSkill.GetHurtObjList():
            if hurtObj.GetObjID() == tagID and not hurtObj.HaveHurtType(ChConfig.HurtTYpe_Recovery) and (isTurnNormalSkill or isAngerSkill):
                __doSkillHurtAnger(tagObj, hurtObj.GetLostHP(), useSkill)
        if tagObj.GetHP() <= 0:
        if tagObj.IsAlive() and tagObj.GetHP() <= 0:
            killObjIDList.append(tagID)
            TurnAttack.SetObjKilled(turnFight, tagObj, curBatObj, useSkill)
    if curBatObj and curBatObj.GetHP() <= 0:
        TurnAttack.SetObjKilled(turnFight, curBatObj)
            TurnAttack.SetObjKilled(turnFight, tagObj, curObj, useSkill)
    if curObj and curObj.IsAlive() and curObj.GetHP() <= 0:
        TurnAttack.SetObjKilled(turnFight, curObj)
    # 可能单个技能对同一目标造成多次伤害
    missObjIDList = []
    for hurtObj in useSkill.GetHurtObjList():
        hurtObjID = hurtObj.GetObjID()
        tagObj = batObjMgr.getBatObj(hurtObjID)
        if not tagObj:
            continue
        if not hurtObj.HaveHurtType(ChConfig.HurtTYpe_Recovery) and (isTurnNormalSkill or isAngerSkill) and tagObj.IsAlive():
            __doSkillHurtAnger(tagObj, hurtObj.GetLostHP(), useSkill)
        if hurtObj.HaveHurtType(ChConfig.HurtType_Miss):
            missObjIDList.append(hurtObjID)
        
    # 结算副本相关的攻击结果,仅主动发起玩家阵容武将触发
    curPlayer = turnFight.curPlayer
    if curPlayer and curBatObj and curBatObj.GetOwnerID() == curPlayer.GetPlayerID():
        FBLogic.OnPlayerLineupAttackResult(curPlayer, curBatObj, killObjIDList, useSkill, turnFight.mapID, turnFight.funcLineID)
    if curPlayer and curObj and curObj.GetOwnerID() == curPlayer.GetPlayerID():
        FBLogic.OnPlayerLineupAttackResult(curPlayer, curObj, killObjIDList, useSkill, turnFight.mapID, turnFight.funcLineID)
        
    # 额外触发技能
    __doUseEnhanceSkill(turnFight, curBatObj, useSkill)
    __doUseEnhanceSkill(turnFight, curObj, useSkill)
    
    # 循环触发被动,待扩展
    # ========== 以下触发被动 ==========
    # 破盾时
    for buffObjID, tagObjID, buffSkillTypeID in shieldBrokenList:
        buffObj = batObjMgr.getBatObj(buffObjID)
        tagObj = batObjMgr.getBatObj(tagObjID)
        TurnPassive.OnTriggerPassiveEffect(turnFight, buffObj, ChConfig.TriggerWay_ShieldBroken, tagObj, connSkillTypeID=buffSkillTypeID)
    for tagObj in useSkill.GetTagObjList():
        tagID = tagObj.GetID()
        if tagID == curID or tagID in missObjIDList:
            # 自己或对方闪避了不再触发被动
            continue
        TurnPassive.OnTriggerPassiveEffect(turnFight, curObj, ChConfig.TriggerWay_AttackOverTagInState, tagObj, connSkill=useSkill)
        # 直接攻击
        if not SkillCommon.IsBuff(useSkill):
            TurnPassive.OnTriggerPassiveEffect(turnFight, curObj, ChConfig.TriggerWay_AttackOverDirect, tagObj, connSkill=useSkill)
            TurnPassive.OnTriggerPassiveEffect(turnFight, tagObj, ChConfig.TriggerWay_BeAttackedDirect, curObj, connSkill=useSkill)
    
    return
@@ -573,15 +812,13 @@
def __doUseEnhanceSkill(turnFight, curBatObj, useSkill):
    if not curBatObj:
        return
    if useSkill.GetIsEnhanceSkill():
    if useSkill.GetBatType() == ChConfig.TurnBattleType_Enhance:
        #GameWorld.DebugLog("自身为额外触发的技能不再触发额外技能! skillID=%s" % useSkill.GetSkillID())
        return
    enhanceSkillIDList = useSkill.GetEnhanceSkillList()
    if not enhanceSkillIDList:
        return
    GameWorld.DebugLog("额外触发的技能! skillID=%s,enhanceSkillIDList=%s" % (useSkill.GetSkillID(), enhanceSkillIDList))
    # 根据触发技能的特点决定是触发一次还是 触发多次
    # 群体BUFF的请参考 IsPlayerUseSkill 客户端决定对象,一样可以实现同样效果
    tagObjList = useSkill.GetTagObjList()
    for enhanceSkillID in enhanceSkillIDList:
        enhanceSkillData = IpyGameDataPY.GetIpyGameData("Skill", enhanceSkillID)
@@ -602,7 +839,7 @@
                for hurtObj in useSkill.GetHurtObjList():
                    if hurtObj.GetObjID() != tagID:
                        continue
                    if not hurtObj.GetHurtHP() or hurtObj.HaveHurtType(ChConfig.HurtType_Miss):
                    if hurtObj.HaveHurtType(ChConfig.HurtType_Miss):
                        continue
                    inHurt = True
                    break
@@ -616,16 +853,16 @@
                enchanceTagObjList.append(tagObj)
                
            if enchanceTagObjList:
                OnUseSkill(turnFight, curBatObj, enhanceSkillData, enchanceTagObjList, bySkill=useSkill, isEnhanceSkill=True)
                OnUseSkill(turnFight, curBatObj, enhanceSkillData, enchanceTagObjList, batType=ChConfig.TurnBattleType_Enhance, bySkill=useSkill)
                
            continue
        
        GameWorld.DebugLog("    额外触发技能,重新锁定目标! enhanceSkillID=%s" % enhanceSkillID)
        OnUseSkill(turnFight, curBatObj, enhanceSkillData, bySkill=useSkill, isEnhanceSkill=True)
        OnUseSkill(turnFight, curBatObj, enhanceSkillData, batType=ChConfig.TurnBattleType_Enhance, bySkill=useSkill)
        
    return
def __doSkillHurtHP(attacker, defObj, curSkill):
def __doSkillHurtHP(turnFight, attacker, defObj, curSkill):
    ## 执行技能伤血,只计算伤血,其他逻辑等技能同步后再处理
    # @return: None - 没有执行成功,即忽略该目标
    
@@ -647,33 +884,32 @@
        pass
    
    else:
        hurtValue, hurtTypes = CalcHurtHP(atkObj, defObj, curSkill, atkSkillValue, atkSkillPer)
        # 各种减伤 吸收盾处理
        #hurtValue = CalcHurtHPWithBuff(atkObj, defObj, hurtValue, curSkill, tick)
        hurtValue, hurtTypes = CalcHurtHP(turnFight, atkObj, defObj, curSkill, atkSkillValue, atkSkillPer)
        hurtValue, realHurtHP = CalcHurtHPWithBuff(turnFight, atkObj, defObj, curSkill, hurtValue)
        
        #伤害结构体
        hurtObj.SetHurtTypes(hurtTypes)
        hurtObj.SetHurtHP(hurtValue)
        remainHP = min(dMaxHP, max(0, dHP - hurtValue)) # 剩余血量
        hurtObj.SetRealHurtHP(realHurtHP)
        remainHP = min(dMaxHP, max(0, dHP - realHurtHP)) # 剩余血量
        
    remainHP = int(remainHP)    #防范
    lostHP = dHP - remainHP # 实际掉血量
    hurtObj.SetLostHP(lostHP)
    hurtObj.SetCurHP(remainHP)
    defObj.SetHP(remainHP)
    GameWorld.DebugLog("    伤血: atkID=%s,defID=%s,hurtValue=%s,lostHP=%s,%s/%s" % (atkID, defID, hurtValue, lostHP, defObj.GetHP(), defObj.GetMaxHP()))
    GameWorld.DebugLog("    伤血: atkID=%s,defID=%s,hurtValue=%s,realHurtHP=%s,lostHP=%s,%s/%s"
                       % (atkID, defID, hurtValue, realHurtHP, lostHP, defObj.GetHP(), defObj.GetMaxHP()))
    TurnAttack.AddTurnObjHurtValue(atkObj, defObj, hurtValue, lostHP, skillID)
    
    #反弹伤害
    CalcBounceHP(atkObj, defObj, hurtObj, curSkill)
    CalcBounceHP(turnFight, atkObj, defObj, hurtObj, curSkill)
    
    #吸血
    CalcSuckBlood(atkObj, defObj, hurtObj, curSkill)
    TurnAttack.AddTurnObjHurtValue(atkObj, defObj, hurtValue, lostHP, skillID)
    return
def CalcHurtHP(atkObj, defObj, curSkill, atkSkillValue, atkSkillPer, **kwargs):
def CalcHurtHP(turnFight, atkObj, defObj, curSkill, atkSkillValue, atkSkillPer, **kwargs):
    '''计算伤害,默认按攻击计算
    '''
    pmType = GetPMType(atkObj, curSkill)
@@ -696,6 +932,9 @@
        angerOverflow = max(atkObj.GetXP() - IpyGameDataPY.GetFuncCfg("AngerXP", 2), 0)
        GameWorld.DebugLog("XP必命中! curXP=%s,angerOverflow=%s" % (curXP, angerOverflow))
        
    if isDot:
        mustHit = True
    #命中公式 攻击方类型不同,公式不同
    if not mustHit:
        aMissRateDef = atkObj.GetBatAttrValue(ChConfig.AttrID_MissRateDef) #atkObj.GetHit() # 抗闪避率 - 命中
@@ -703,19 +942,26 @@
        missNum = defObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnMissNum)
        missRate = eval(IpyGameDataPY.GetFuncCompileCfg("MissCfg", 1))
        if GameWorld.CanHappen(missRate):
            GameWorld.DebugLog("闪避了! missRate=%s,dMissRate=%s,aMissRateDef=%s,missNum=%s" % (missRate, dMissRate, aMissRateDef, missNum))
            defObj.SetDict(ChConfig.Def_Obj_Dict_TurnMissNum, missRate + 1)
            return 0, pow(2, ChConfig.HurtType_Miss)
        
    hurtTypes = pow(2, ChConfig.HurtType_Normal)
    
    #calcType = curSkill.GetCalcType() 目前暂时按攻击算伤害,之后可以扩展其他
    
    isSuperHit = False # 是否暴击
    if isDot:
        isSuperHit = False
    isSuperHit, isParry = False, False
    aSuperDamPer, dSuperDamPerDef = 0, 0
    if not isDot:
        isSuperHit = CanSuperHit(atkObj, defObj) # 是否暴击
        isParry = (isTurnNormalSkill and CanParry(atkObj, defObj)) # 是否格挡,仅针对普攻
        CanStun(turnFight, atkObj, defObj, curSkill) # 是否击晕
    if isSuperHit:
        hurtTypes |= pow(2, ChConfig.HurtType_SuperHit)
        aSuperDamPer = atkObj.GetBatAttrValue(ChConfig.AttrID_SuperDamPer)
        dSuperDamPerDef = atkObj.GetBatAttrValue(ChConfig.AttrID_SuperDamPerDef)
        
    isParry = False # 是否格挡
    if isParry:
        hurtTypes |= pow(2, ChConfig.HurtType_Parry)
        
@@ -723,7 +969,7 @@
        hurtTypes |= pow(2, ChConfig.HurtType_IgnoreDef)
        
    #参与运算的数值
    rand = random.random()                #种子数 0~1
    #rand = random.random()                #种子数 0~1
    
    aAtk = atkObj.GetBatAttrValue(ChConfig.AttrID_Atk) # 攻击方最大攻击
    
@@ -759,6 +1005,8 @@
    dAngerSkillPerDef /= 10000.0
    aPMDamPer /= 10000.0
    dPMDamPerDef /= 10000.0
    aSuperDamPer /= 10000.0
    dSuperDamPerDef /= 10000.0
    aFinalDamPer /= 10000.0
    dFinalDamPerDef /= 10000.0
    
@@ -782,35 +1030,132 @@
        hurtValue = eval(IpyGameDataPY.GetFuncCompileCfg("HurtFormula", 4))
        GameWorld.DebugLog("    其他伤害=%s" % (hurtValue))
        
    hurtValue = max(1, int(hurtValue)) # 负值、保底防范
    if isParry:
        parryReduceRatio = IpyGameDataPY.GetFuncCfg("ParryCfg", 3)
        hurtValue = hurtValue * (1 - parryReduceRatio)
        GameWorld.DebugLog("    格挡后伤害=%s,parryReduceRatio=%s" % (hurtValue, parryReduceRatio))
    
    hurtValue = max(1, int(hurtValue)) # 负值、保底防范
    return hurtValue, hurtTypes
def CalcBounceHP(atkObj, defObj, hurtObj, curSkill):
def CanSuperHit(atkObj, defObj):
    aSuperHitRate = atkObj.GetBatAttrValue(ChConfig.AttrID_SuperHitRate)
    dSuperHitRateDef = defObj.GetBatAttrValue(ChConfig.AttrID_SuperHitRateDef)
    happenRate = eval(IpyGameDataPY.GetFuncCompileCfg("SuperHitCfg", 1))
    if GameWorld.CanHappen(happenRate):
        GameWorld.DebugLog("暴击了: happenRate=%s,aSuperHitRate=%s,dSuperHitRateDef=%s" % (happenRate, aSuperHitRate, dSuperHitRateDef))
        return True
    return False
def CanStun(turnFight, atkObj, defObj, curSkill):
    aStunRate = atkObj.GetBatAttrValue(ChConfig.AttrID_StunRate)
    dStunRateDef = defObj.GetBatAttrValue(ChConfig.AttrID_StunRateDef)
    happenRate = eval(IpyGameDataPY.GetFuncCompileCfg("StunCfg", 1))
    if not GameWorld.CanHappen(happenRate):
        return False
    GameWorld.DebugLog("击晕了: happenRate=%s,aStunRate=%s,dStunRateDef=%s" % (happenRate, aStunRate, dStunRateDef))
    stunSkillID = IpyGameDataPY.GetFuncCfg("StunCfg", 2)
    TurnBuff.DoAddBuffBySkillID(turnFight, defObj, stunSkillID, atkObj, curSkill, afterLogic=True)
    return True
def CanParry(atkObj, defObj):
    if defObj.IsInControlled():
        #被控制无法格挡
        return False
    aParryRateDef = atkObj.GetBatAttrValue(ChConfig.AttrID_ParryRateDef)
    dParryRate = defObj.GetBatAttrValue(ChConfig.AttrID_ParryRate)
    parryNum = defObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnParryNum)
    happenRate = eval(IpyGameDataPY.GetFuncCompileCfg("ParryCfg", 1))
    if GameWorld.CanHappen(happenRate):
        GameWorld.DebugLog("格挡了: happenRate=%s,aParryRateDef=%s,dParryRate=%s,parryNum=%s" % (happenRate, aParryRateDef, dParryRate, parryNum))
        defObj.SetDict(ChConfig.Def_Obj_Dict_TurnParryNum, parryNum + 1)
        return True
    return False
def CalcHurtHPWithBuff(turnFight, atkObj, defObj, curSkill, hurtValue):
    ## 计算伤害后,因各种buff和状态的影响处理
    # @return: hurtValue, realHurtHP
    if hurtValue <= 0:
        return 0, 0
    # 减伤盾减伤, 会改变 hurtValue
    hurtValue = max(0, hurtValue)
    # 承伤盾承伤,剩余时间短的优先承伤,承伤不影响输出,相当于额外的HP,仅用于抵扣掉血,仅 改变 realHurtHP
    realHurtHP = hurtValue
    shieldBuffList = []
    buffMgr = defObj.GetBuffManager()
    for index in range(buffMgr.GetBuffCount()):
        buff = buffMgr.GetBuffByIndex(index)
        skillData = buff.GetSkillData()
        # 承伤盾
        if SkillCommon.isDamageShieldSkill(skillData):
            remainTime = buff.GetRemainTime() # 剩余回合
            if not skillData.GetLastTime():
                remainTime = 999 # 永久盾
            buffValue = buff.GetValue1() + buff.GetValue2() * ChConfig.Def_PerPointValue # 剩余盾值
            shieldBuffList.append([remainTime, buffValue, buff])
    if shieldBuffList:
        shieldBuffList.sort()
        for _, buffValue, buff in shieldBuffList:
            if realHurtHP <= 0:
                break
            buffID = buff.GetBuffID()
            if realHurtHP < buffValue:
                damageShieldValue = realHurtHP
            else:
                damageShieldValue = buffValue
            GameWorld.DebugLog("    承伤盾: buffID=%s,buffValue=%s,realHurtHP=%s,damageShieldValue=%s" % (buffID, buffValue, realHurtHP, damageShieldValue))
            realHurtHP -= damageShieldValue # 承伤值
            if damageShieldValue >= buffValue:
                GameWorld.DebugLog("        删除盾: buffID=%s,realHurtHP=%s" % (buffID, realHurtHP))
                TurnBuff.DoBuffDel(turnFight, defObj, buff, relatedSkill=curSkill, afterLogic=True, tagObj=atkObj)
            else:
                updShieldValue = buffValue - damageShieldValue
                GameWorld.DebugLog("        更新盾值: updShieldValue=%s,realHurtHP=%s" % (updShieldValue, realHurtHP))
                buff.SetValue1(updShieldValue % ChConfig.Def_PerPointValue)
                buff.SetValue2(updShieldValue / ChConfig.Def_PerPointValue)
                curSkill.AddAfterLogic(ChConfig.AfterLogic_SyncBuff, [defObj, buff, atkObj, "ReduceShieldValue"])
    return hurtValue, max(0, realHurtHP)
def CalcBounceHP(turnFight, atkObj, defObj, hurtObj, curSkill):
    '''计算反弹反弹伤害
    '''
    if not atkObj.GetCanAttack():
        return
    
    bounceHP = int(hurtObj.GetHurtHP() * random.uniform(0.1, 0.2))
    if bounceHP <= 0:
        return
    
    remainHP = atkObj.GetHP() - bounceHP # 反弹允许弹到负值,如果最终吸血没有吸到正值则算死亡
    GameWorld.DebugLog("    反弹伤害=%s,%s/%s" % (bounceHP, atkObj.GetHP(), atkObj.GetMaxHP()))
    bounceHP, realBounceHP = CalcHurtHPWithBuff(turnFight, defObj, atkObj, curSkill, bounceHP)
    if bounceHP <= 0:
        return
    hurtObj.SetBounceHP(bounceHP)
    atkObj.SetHP(remainHP)
    GameWorld.DebugLog("    反弹伤害=%s,remainHP=%s/%s" % (bounceHP, remainHP, atkObj.GetMaxHP()))
    
    TurnAttack.AddTurnObjHurtValue(defObj, atkObj, bounceHP, bounceHP, isBounce=True)
    if realBounceHP > 0:
        remainHP = atkObj.GetHP() - realBounceHP # 反弹允许弹到负值,如果最终吸血没有吸到正值则算死亡
        atkObj.SetHP(remainHP)
        GameWorld.DebugLog("        bounceHP=%s,realBounceHP=%s,%s/%s" % (bounceHP, realBounceHP, atkObj.GetHP(), atkObj.GetMaxHP()))
    TurnAttack.AddTurnObjHurtValue(defObj, atkObj, bounceHP, realBounceHP, isBounce=True)
    return
def CalcSuckBlood(atkObj, defObj, hurtObj, curSkill):
    '''计算吸血
    '''
    
    suckHP = int(hurtObj.GetHurtHP() * random.uniform(0.1, 0.2))
    hurtHP = hurtObj.GetHurtHP()
    if hurtHP <= 1:
        return
    
    aSuckHPPer = atkObj.GetBatAttrValue(ChConfig.AttrID_SuckHPPer)
    dSuckHPPerDef = defObj.GetBatAttrValue(ChConfig.AttrID_SuckHPPerDef)
    suckHP = int(eval(IpyGameDataPY.GetFuncCompileCfg("SuckHPCfg", 1)))
    if suckHP <= 0:
        return
    
@@ -821,7 +1166,7 @@
    
    hurtObj.SetSuckHP(suckHP)
    atkObj.SetHP(remainHP)
    GameWorld.DebugLog("    吸血=%s,remainHP=%s/%s" % (suckHP, remainHP, maxHP))
    GameWorld.DebugLog("    吸血=%s,remainHP=%s/%s,aSuckHPPer=%s,dSuckHPPerDef=%s" % (suckHP, remainHP, maxHP, aSuckHPPer, dSuckHPPerDef))
    
    # 吸血暂定算治疗
    TurnAttack.AddTurnObjCureHP(atkObj, atkObj, suckHP, cureHP)
@@ -830,20 +1175,11 @@
def CalcCureHP(userObj, tagObj, curSkill, largeNum=False):
    ''' 计算治疗值
    '''
    cureBaseValue = 0     #治疗基础值
    cureType = curSkill.GetCalcType()
    skillPer = curSkill.GetSkillPer()
    #skillValue = curSkill.GetSkillValue()
    
    #获得基础治疗值
    if cureType == ChConfig.Def_Cure_Attack:
        cureBaseValue = userObj.GetAtk()
    elif cureType == ChConfig.Def_Cure_MaxHP:
        cureBaseValue = userObj.GetMaxHP()
    #elif cureType == ChConfig.Def_Cure_HurtValue:
    #    cureBaseValue = GameObj.GetLastHurtValue(userObj)
    elif cureType == ChConfig.Def_Cure_TagMaxHP:
        cureBaseValue = 0 if not tagObj else tagObj.GetMaxHP()
    cureBaseValue = GetCalcBaseValue(cureType, userObj, tagObj)
        
    #skillPer += PassiveBuffEffMng.GetPassiveSkillValueByTriggerType(userObj, None, curSkill, ChConfig.TriggerType_AddHP)
    
@@ -874,6 +1210,18 @@
                       % (cureHP, curSkill.GetSkillID(), cureType, baseValue, skillPer, curePer, cureDefPer, angerOverflow))
    return cureHP
def GetCalcBaseValue(calcType, curObj, tagObj):
    ##获得基础计算值
    if calcType == ChConfig.Def_Calc_Attack:
        baseValue = curObj.GetAtk()
    elif calcType == ChConfig.Def_Calc_MaxHP:
        baseValue = curObj.GetMaxHP()
    #elif cureType == ChConfig.Def_Calc_HurtValue:
    #    baseValue = GameObj.GetLastHurtValue(userObj)
    elif calcType == ChConfig.Def_Calc_TagMaxHP:
        baseValue = 0 if not tagObj else tagObj.GetMaxHP()
    return baseValue
def DoDOTAttack(turnFight, batObj, curBuff, hurtValue, hurtTypes):
    ## 执行单次dot逻辑
    skillID = curBuff.GetSkillID()
@@ -887,34 +1235,39 @@
    atkObj = buffOwner
    defObj = batObj
    
    tagObjList = [defObj]
    dHP = defObj.GetHP()
    defID = defObj.GetID()
    GameWorld.DebugLog("结算dot: defID=%s,buffID=%s,skillID=%s,ownerID=%s,hurtValue=%s,hurtTypes=%s,dHP=%s/%s"
                       % (defID, buffID, skillID, ownerID, hurtValue, hurtTypes, dHP, defObj.GetMaxHP()))
    tagObjList = [defObj]
    
    poolMgr = ObjPool.GetPoolMgr()
    useSkill = poolMgr.acquire(BattleObj.PySkill, skillIpyData)
    useSkill.SetTagObjList(tagObjList)
    useSkill.ClearHurtObj()
    hurtObj = useSkill.AddHurtObj(defID)
    
    remainHP = max(0, dHP - hurtValue) # 剩余血量
    dHP = defObj.GetHP()
    GameWorld.DebugLog("结算dot: defID=%s,buffID=%s,skillID=%s,ownerID=%s,hurtValue=%s,hurtTypes=%s,dHP=%s"
                       % (defID, buffID, skillID, ownerID, hurtValue, hurtTypes, dHP))
    hurtValue, realHurtHP = CalcHurtHPWithBuff(turnFight, atkObj, defObj, useSkill, hurtValue)
    # dot的反弹、吸血待定
    remainHP = max(0, dHP - realHurtHP) # 剩余血量
    lostHP = dHP - remainHP # 实际掉血量
    defObj.SetHP(remainHP)
    
    hurtObj = useSkill.AddHurtObj(defID)
    GameWorld.DebugLog("    hurtValue=%s,realHurtHP=%s,lostHP=%s,%s/%s" % (hurtValue, realHurtHP, lostHP, defObj.GetHP(), defObj.GetMaxHP()))
    hurtObj.SetHurtTypes(hurtTypes)
    hurtObj.SetHurtHP(hurtValue)
    hurtObj.SetRealHurtHP(realHurtHP)
    hurtObj.SetLostHP(lostHP)
    hurtObj.SetCurHP(remainHP)
    # dot的反弹、吸血待定
    
    TurnAttack.AddTurnObjHurtValue(atkObj, batObj, hurtValue, lostHP, skillID)
    
    Sync_PropertyRefreshView(turnFight, defObj, ChConfig.AttrID_HP, remainHP, hurtValue, diffType=0, skillID=skillID, hurtTypes=hurtTypes)
    
    DoBeAttackOver(turnFight, atkObj, useSkill)
    DoBeAttackResult(turnFight, atkObj, useSkill)
    
    useSkill.ResetUseRec()
    poolMgr.release(useSkill)