129 【战斗】战斗系统-服务端(优化技能表字段,增加技能及buff常用配置字段;优化被动触发及效果配置方式;技能冷却、buff持续时长计算支持;持续性buff效果结算支持;pve默认玩家先手;战锤消耗仅普攻怒技消耗;)
11个文件已修改
2个文件已添加
1327 ■■■■ 已修改文件
PySysDB/PySysDBPY.h 24 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/AttackLogic/AttackCommon.py 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/BattleObj.py 252 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/TurnAttack.py 289 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py 55 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py 88 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/GameSkills/SkillCommon.py 14 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/PassiveTrigger/PassiveEff_5001.py 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnBuff.py 185 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnBuffs/BuffAtkType_1001.py 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnPassive.py 138 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnSkill.py 195 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
PySysDB/PySysDBPY.h
@@ -61,6 +61,7 @@
{
    DWORD        _SkillID;    //技能ID
    DWORD        SkillTypeID;    //技能TypeID
    WORD        SkillLV;    //当前等级
    WORD        SkillMaxLV;    //最高等级
    char        SkillName;    //技能名
    BYTE        FuncType;    //功能分类
@@ -71,17 +72,34 @@
    BYTE        TagFriendly;    //敌我目标
    BYTE        TagAffect;    //目标细分
    BYTE        TagCount;    //目标个数
    BYTE        CalcType;    //计算方式
    WORD        SkillPer;    //技能万分比
    DWORD        SkillValue;    //技能固定值
    WORD        HappenRate;    //释放或添加几率
    WORD        LastTime;    //持续时间
    WORD        CoolDownTime;    //冷却时间
    WORD        Priority;    //优先级
    DWORD        EffectID1;    //效果ID1
    list        EffectValues1;    //效果值列表1
    BYTE        TriggerWay1;    //触发方式
    BYTE        TriggerSrc1;    //触发来源
    list        TriggerParams1;    //触发参数
    DWORD        EffectID2;    //效果ID2
    list        EffectValues2;    //效果值列表2
    BYTE        TriggerWay2;    //触发方式
    BYTE        TriggerSrc2;    //触发来源
    list        TriggerParams2;    //触发参数
    DWORD        EffectID3;    //效果ID3
    list        EffectValues3;    //效果值列表3
    BYTE        TriggerWay3;    //触发方式
    BYTE        TriggerSrc3;    //触发来源
    list        TriggerParams3;    //触发参数
    DWORD        ConnSkill;    //关联技能
    WORD        CoolDownTime;    //技能冷却时间
    list        IgnoreStates;    //无视限制列表
    list        BuffStates;    //Buff״ֵ̬
    WORD        LastTime;    //持续时间
    BYTE        LayerCnt;    //Buff层数
    BYTE        LayerMax;    //最大层数
    DWORD        BuffRepeat;    //Buff叠加规则
    DWORD        DieContinue;    //Buff死亡存在
    list        EnhanceSkillList;    //触发技能ID列表
    DWORD        FightPower;    //技能战斗力
};
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/AttackLogic/AttackCommon.py
@@ -2235,8 +2235,6 @@
            atkObj.SetDict(ChConfig.Def_PlayerKey_LastHurtNPCObjID, defObj.GetID())
        else:
            defObj.SetDict(ChConfig.Def_PlayerKey_LastAttackerObjID, atkObj.GetID())
    #TurnAttack.AddTurnObjHurtValue(atkObj, defObj, resultHurtType.HurtType, resultHurtType.RealHurtHP, resultHurtType.LostHP, curSkill)
    
    #if resultHurtType.RealHurtHP:
    #    PassiveBuffEffMng.OnPassiveSkillTrigger(defObj, atkObj, None, ChConfig.TriggerType_BeHurt, tick)
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/BattleObj.py
@@ -27,6 +27,139 @@
import TurnPassive
import TurnBuff
class PassiveEffManager():
    ## 被动效果管理器
    def __init__(self, batObj):
        self._batObj = batObj
        # 被影响的技能ID: 0为所有技能
        self._AffectSkillDict = {} # 被动技能 {(触发方式, 被影响的技能ID):{技能ID:[effID, ...], ...}, ...}
        self._AffectBuffDict = {} # 被动buff {(触发方式, 被影响的技能ID):{buffID:[effID, ...], ...}, ...}
        return
    def GetPassiveEffByTrigger(self, triggerWay, connSkill=None):
        '''获取可触发的效果列表,技能跟buff根据触发优先级按顺序触发,优先级越高越先执行,相同时技能优先
                        优先级之后有需要再扩展
        @return: [["skill/buff", skillID/buffID, effIDList], ...]
        '''
        connSkillID = connSkill.GetSkillTypeID() if connSkill else 0
        effList = []
        # 技能
        key = (triggerWay, connSkillID)
        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)
        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)
            effDict = self._AffectBuffDict.get(key, {})
            for buffID, effIDList in effDict.items():
                effList.append(["buff", buffID, effIDList])
        return effList
    def RefreshSkillPassiveEffect(self):
        self._AffectSkillDict = {}
        skillManager = self._batObj.GetSkillManager()
        for index in range(0, skillManager.GetSkillCount()):
            curSkill = skillManager.GetSkillByIndex(index)
            if not curSkill:
                continue
            for index in xrange(curSkill.GetEffectCount()):
                curEffect = curSkill.GetEffect(index)
                effectID = curEffect.GetEffectID()
                if effectID == 0:
                    continue
                self.AddSkillPassiveEffect(curSkill, curEffect)
        return self._AffectSkillDict
    def AddSkillPassiveEffect(self, curSkill, effect):
        ## 添加技能被动效果
        triggerWay = effect.GetTriggerWay()
        triggerSrc = effect.GetTriggerSrc()
        if not triggerWay or triggerSrc != 1:
            return
        skillID = curSkill.GetSkillID()
        connSkillID = curSkill.GetConnSkill()
        #priority = curSkill.GetPriority()
        effectID = effect.GetEffectID()
        key = (triggerWay, connSkillID)
        if key not in self._AffectSkillDict:
            self._AffectSkillDict[key] = {}
        effDict = self._AffectSkillDict[key]
        if skillID not in effDict:
            effDict[skillID] = []
        effDict[skillID].append(effectID)
        return
    def RefreshBuffPassiveEffect(self):
        self._AffectBuffDict = {}
        buffMgr = self._batObj.GetBuffManager()
        for index in range(buffMgr.GetBuffCount()):
            buff = buffMgr.GetBuffByIndex(index)
            if not buff:
                continue
            skillData = buff.GetSkillData()
            for index in xrange(skillData.GetEffectCount()):
                curEffect = skillData.GetEffect(index)
                effectID = curEffect.GetEffectID()
                if effectID == 0:
                    continue
                self.AddBuffPassiveEffect(buff, skillData, curEffect)
        return self._AffectBuffDict
    def AddBuffPassiveEffect(self, buff, skillData, effect):
        '''添加Buff被动效果
                            同个buff的技能ID如果叠加规则是独立的,那么可能同时存在多个相同技能效果的buff
                            如果触发效果,就要触发多次,所以buff的效果以buffID为key
        '''
        triggerWay = effect.GetTriggerWay()
        triggerSrc = effect.GetTriggerSrc()
        if not triggerWay or triggerSrc != 2:
            return
        buffID = buff.GetBuffID()
        connSkillID = skillData.GetConnSkill()
        #priority = skillData.GetPriority()
        effectID = effect.GetEffectID()
        key = (triggerWay, connSkillID)
        if key not in self._AffectBuffDict:
            self._AffectBuffDict[key] = {}
        effDict = self._AffectBuffDict[key]
        if buffID not in effDict:
            effDict[buffID] = []
        effDict[buffID].append(effectID)
        return
    def DelBuffPassiveEffect(self, buffID):
        ## 删除Buff被动效果
        for key, effDict in self._AffectBuffDict.items():
            if buffID not in effDict:
                continue
            effDict.pop(buffID)
            if not effDict:
                self._AffectBuffDict.pop(key)
        return
class HurtObj():
    ## 伤血统计
    
@@ -54,7 +187,7 @@
        return
    def HaveHurtType(self, hurtType):
        ## 判断是否存在某种伤血类型
        return self._hurtTypes&pow(2, hurtType)
        return self._hurtTypes & pow(2, hurtType)
    def GetHurtHP(self): return self._hurtHP
    def SetHurtHP(self, hurtHP): self._hurtHP = hurtHP
    def GetLostHP(self): return self._lostHP
@@ -66,26 +199,40 @@
    def GetBounceHP(self): return self._bounceHP
    def SetBounceHP(self, bounceHP): self._bounceHP = bounceHP
    
class Effect():
class SkillEffect():
    
    def __init__(self, effID, values):
    def __init__(self, effID, values, triggerWay=0, triggerSrc=0, triggerParams=None):
        self._effID = effID
        self._values = values
        self._triggerWay = triggerWay
        self._triggerSrc = triggerSrc
        self._triggerParams = triggerParams if triggerParams else []
        return
    
    def GetEffectID(self): return self._effID
    def GetEffectValue(self, index): return self._values[index] if len(self._values) > index else 0
    def GetEffectValueCount(self): return len(self._values)
    def GetTriggerWay(self): return self._triggerWay
    def GetTriggerSrc(self): return self._triggerSrc
    def GetTriggerParams(self, index): return self._triggerParams[index] if len(self._triggerParams) > index else 0
    
EmptyEffect = SkillEffect(0, [])
class SklllData():
    
    def __init__(self, ipyData):
        self._ipyData = ipyData
        self._effList = [] # [Effect, ...]
        self._effDict = {} # {effID:Effect, ...}
        for num in range(1, 1 + 3):
            effID = getattr(ipyData, "GetEffectID%s" % num)()
            values = getattr(ipyData, "GetEffectValues%s" % num)()
            self._effList.append(ObjPool.GetPoolMgr().acquire(Effect, effID, values))
            triggerWay = getattr(ipyData, "GetTriggerWay%s" % num)()
            triggerSrc = getattr(ipyData, "GetTriggerSrc%s" % num)()
            triggerParams = getattr(ipyData, "GetTriggerParams%s" % num)()
            effect = ObjPool.GetPoolMgr().acquire(SkillEffect, effID, values, triggerWay, triggerSrc, triggerParams)
            self._effList.append(effect)
            self._effDict[effID] = effect
        return
    
    def GetSkillID(self): return self._ipyData.GetSkillID()
@@ -101,12 +248,22 @@
    def GetTagSelf(self): return self._ipyData.GetTagSelf() # 是否含自己
    def GetTagAffect(self): return self._ipyData.GetTagAffect() # 目标细分
    def GetTagCount(self): return self._ipyData.GetTagCount() # 目标个数
    def GetHappenRate(self): return self._ipyData.GetHappenRate() # 释放或添加几率
    def GetLastTime(self): return self._ipyData.GetLastTime() # 持续时间
    def GetCoolDownTime(self): return self._ipyData.GetCoolDownTime()
    def GetCalcType(self): return self._ipyData.GetCalcType()
    def GetSkillPer(self): return self._ipyData.GetSkillPer()
    def GetSkillValue(self): return self._ipyData.GetSkillValue()
    def GetHappenRate(self): return self._ipyData.GetHappenRate() # 触发概率
    def GetEffect(self, index): return self._effList[index] if len(self._effList) > index else 0
    def GetEffectCount(self): return len(self._effList)
    def GetConnSkill(self): return self._ipyData.GetConnSkill() # 关联技能
    def GetEffectByID(self, effID): return self._effDict.get(effID, EmptyEffect)
    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 GetLastTime(self): return self._ipyData.GetLastTime() # 持续时间
    def GetLayerCnt(self): return self._ipyData.GetLayerCnt()
    def GetLayerMax(self): return self._ipyData.GetLayerMax()
    def GetBuffRepeat(self): return self._ipyData.GetBuffRepeat() # Buff叠加规则
    def GetDieContinue(self): return self._ipyData.GetDieContinue() # Buff死亡存在
    def GetEnhanceSkillList(self): return self._ipyData.GetEnhanceSkillList() # 额外触发的技能ID列表
    def GetFightPower(self): return self._ipyData.GetFightPower()
    
@@ -117,6 +274,7 @@
        self._buffID = 0
        self._ownerID = 0
        self._layer = 0
        self._calcTime = 0
        self._remainTime = 0
        self._valueList = []
        return
@@ -129,16 +287,19 @@
    def SetOwnerID(self, ownerID): self._ownerID = ownerID
    def GetLayer(self): return self._layer
    def SetLayer(self, layer): self._layer = layer
    def GetCalcTime(self): return self._calcTime
    def SetCalcTime(self, calcTime): self._calcTime = calcTime
    def GetRemainTime(self): return self._remainTime
    def SetRemainTime(self, remainTime): self._remainTime = remainTime
    def SetValueList(self, valueList): self._valueList = valueList
    def GetValue(self, index):
    def SetBuffValueList(self, valueList): self._valueList = valueList
    def GetBuffValue(self, index):
        return self._valueList[index] if len(self._valueList) > index else 0
    
class BuffManager():
    ## 战斗对象buff管理器
    
    def __init__(self):
    def __init__(self, batObj):
        self._batObj = batObj
        self._buffList = [] # [PyBuff, ...]
        self._buffIDDict = {} # {buffID:PyBuff, ...}
        self._skillTypeIDBuffIDs = {} # 技能TypeID对应的buff {skillTypeID:[buffID, ...], ...}
@@ -158,12 +319,8 @@
        return
    
    def GetBuffCount(self): return len(self._buffList)
    def GetBuffByIndex(self, index):
        buff = self._buffList[index]
        #if False:
        #    buff = PyBuff()
        return buff
    def GetBuffByIndex(self, index): return self._buffList[index]
    def AddBuff(self, skillID):
        buff = None
        ipyData = IpyGameDataPY.GetIpyGameData("Skill", skillID)
@@ -172,19 +329,18 @@
        skillTypeID = ipyData.GetSkillTypeID()
        self._buffID += 1
        
        buffID = self._buffID
        buff = ObjPool.GetPoolMgr().acquire(PyBuff, ipyData)
        buff.SetBuffID(self._buffID)
        buff.SetBuffID(buffID)
        
        self._buffList.append(buff)
        self._buffIDDict[self._buffID] = buff
        self._buffIDDict[buffID] = buff
        if skillTypeID not in self._skillTypeIDBuffIDs:
            self._skillTypeIDBuffIDs[skillTypeID] = []
        buffIDs = self._skillTypeIDBuffIDs[skillTypeID]
        if self._buffID not in buffIDs:
            buffIDs.append(self._buffID)
        if buffID not in buffIDs:
            buffIDs.append(buffID)
            
        #if False:
        #    buff = PyBuff()
        return buff
    
    def DelBuff(self, buffID):
@@ -202,14 +358,7 @@
            break
        return
    
    def GetBuff(self, buffID):
        buff = None
        if buffID in self._buffIDDict:
            buff = self._buffIDDict[buffID]
        #if False:
        #    buff = PyBuff()
        return buff
    def GetBuff(self, buffID): return self._buffIDDict.get(buffID, None)
    def FindBuffIDBySkillID(self, skillID):
        ## 返回该技能ID的所有buffID列表
        skillData = IpyGameDataPY.GetIpyGameData("Skill", skillID)
@@ -244,25 +393,34 @@
        if buffID not in buffIDList:
            return
        buffIDList.remove(buffID)
        if not len(buffIDList):
        if not buffIDList:
            self._buffStateDict.pop(state)
        GameWorld.DebugLog("    DelBuffState state=%s,buffID=%s,%s" % (state, buffID, self._buffStateDict))
        return
    
    def IsInBuffState(self, state):
        ## 是否处于某种状态下
        return state in self._buffStateDict and len(self._buffStateDict[state]) > 0
    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):
        self._skillData = ObjPool.GetPoolMgr().acquire(SklllData, ipyData)
        self._calcTime = 0
        self._remainTime = 0
        self._batType = 0 # 战斗类型,普通、连击、反击、追击等
        self._tagObjList = [] # 本次技能目标列表 [BatObj, ...]
        self._hurtList = [] # 本次伤血列表,可能同一个对象有多个伤害,如弹射等 [HurtObj, ...]
        self._bySkill = None # 由哪个技能触发的
        self._isEnhanceSkill = False # 是否由主技能额外触发的(非被动触发,即主技能的EnhanceSkillList字段中的技能)
        return
    def ResetUseRec(self):
        self._batType = 0
        self._tagObjList = []
        self._bySkill = None
        self._isEnhanceSkill = False
        self.ClearHurtObj()
        return
    
    def GetSkillID(self): return self._skillData.GetSkillID()
@@ -278,16 +436,28 @@
    def GetTagSelf(self): return self._skillData.GetTagSelf() # 是否含自己
    def GetTagAffect(self): return self._skillData.GetTagAffect() # 目标细分
    def GetTagCount(self): return self._skillData.GetTagCount() # 目标个数
    def GetHappenRate(self): return self._skillData.GetHappenRate() # 释放或添加几率
    def GetLastTime(self): return self._skillData.GetLastTime() # 持续时间
    def GetCoolDownTime(self): return self._skillData.GetCoolDownTime()
    def GetCalcType(self): return self._skillData.GetCalcType()
    def GetSkillPer(self): return self._skillData.GetSkillPer()
    def GetSkillValue(self): return self._skillData.GetSkillValue()
    def GetHappenRate(self): return self._skillData.GetHappenRate() # 触发概率
    def GetEffect(self, index): return self._skillData.GetEffect(index)
    def GetEffectCount(self): return self._skillData.GetEffectCount()
    def GetConnSkill(self): return self._skillData.GetConnSkill() # 关联技能
    def GetEffectByID(self, effID): return self._skillData.GetEffectByID()
    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 GetLastTime(self): return self._skillData.GetLastTime() # 持续时间
    def GetLayerCnt(self): return self._skillData.GetLayerCnt()
    def GetLayerMax(self): return self._skillData.GetLayerMax()
    def GetBuffRepeat(self): return self._skillData.GetBuffRepeat() # Buff叠加规则
    def GetDieContinue(self): return self._skillData.GetDieContinue() # Buff死亡存在
    def GetEnhanceSkillList(self): return self._skillData.GetEnhanceSkillList() # 额外触发的技能ID列表
    def GetFightPower(self): return self._skillData.GetFightPower()
    
    ## ---------------------------------- 非技能表内容 ----------------------------------
    def GetCalcTime(self): return self._calcTime
    def SetCalcTime(self, calcTime): self._calcTime = calcTime
    def GetRemainTime(self): return self._remainTime
    def SetRemainTime(self, remainTime): self._remainTime = remainTime
    def GetBatType(self): return self._batType
@@ -392,7 +562,8 @@
        self._skillUseCntDict = {} # 技能累计使用次数 {skillID:useCnt, ...}
        self._skillTurnUseCntDict = {} # 技能单回合累计使用次数 {skillID:useCnt, ...}
        self._skillMgr = ObjPool.GetPoolMgr().acquire(SkillManager)
        self._buffMgr = ObjPool.GetPoolMgr().acquire(BuffManager)
        self._buffMgr = ObjPool.GetPoolMgr().acquire(BuffManager, self)
        self._passiveEffMgr = ObjPool.GetPoolMgr().acquire(PassiveEffManager, self)
        
        # 统计
        self.hurtStat = 0 # 输出统计
@@ -460,6 +631,7 @@
    
    def GetSkillManager(self): return self._skillMgr
    def GetBuffManager(self):return self._buffMgr
    def GetPassiveEffManager(self):return self._passiveEffMgr
    
    def GetCanAttack(self):
        ## 可否被攻击
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/TurnAttack.py
@@ -35,6 +35,7 @@
import SkillCommon
import AttackCommon
import BattleObj
import TurnPassive
import TurnSkill
import TurnBuff
import ObjPool
@@ -43,6 +44,7 @@
import time
import json
TimelineSet = 10000 # 单回合最大时间轴
PosNumMax = 10 # 最大站位编号
ActionNumStart = -1 # 起始行动位置编号,一般是从1开始,如果有加主公、红颜等则扣除相应位置值,如从0或-1开始
@@ -67,6 +69,8 @@
        self.shapeType = 0 # 阵型
        self.fightPower = 0 # 阵容总战力
        self.posObjIDDict = {} # 站位对应战斗实体 {站位编号:batObjID, ...}, 站位编号小于0为非主战单位,如主公、红颜等
        self.lingshouObjIDDict = {} # 灵兽战斗单位 {位置编号:batObjID, ...}
        self.beautyObjIDDict = {} # 红颜战斗单位 {位置编号:batObjID, ...}
        self.actionNum = ActionNumStart # 行动位置,从1开始
        return
    
@@ -86,12 +90,16 @@
    
    def clearLineup(self):
        ## 清除阵容
        if not self.posObjIDDict:
            return
        batObjMgr = BattleObj.GetBatObjMgr()
        for objID in self.posObjIDDict.values():
            batObjMgr.delBatObj(objID)
        for objID in self.lingshouObjIDDict.values():
            batObjMgr.delBatObj(objID)
        for objID in self.beautyObjIDDict.values():
            batObjMgr.delBatObj(objID)
        self.posObjIDDict = {}
        self.lingshouObjIDDict = {}
        self.beautyObjIDDict = {}
        self.fightPower = 0
        return
    
@@ -151,6 +159,7 @@
        self.factionDict = {} # 战斗阵营 {faction:BatFaction, ...},一般是只有两个阵营,faction为1或2,每个阵营支持多个阵容
        self.actionSortList = [] # 阵容行动顺序 [[faction, num], ...]
        self.actionIndex = 0 # 行动顺序索引
        self.timeline = 0 # 时间轴节点  turnNum*1000+actionIndex*100++actionNum
        
        self.startTime = 0 # 开始时间戳,支持毫秒小数
        self.costTime = 0 # 单场战斗总耗时,支持毫秒小数
@@ -197,18 +206,35 @@
        for batFaction in self.factionDict.values():
            faction = batFaction.faction
            for num, batLineup in batFaction.lineupDict.items():
                isPlayer = 1 if batLineup.ownerID else 0 # 玩家阵容优先攻击
                fightPower = batLineup.fightPower
                sortValue = -(faction * 10 + num)
                sortList.append([fightPower, sortValue, faction, num])
                sortList.append([isPlayer, fightPower, sortValue, faction, num])
        sortList.sort(reverse=True) # 战力高的先手
        
        self.actionIndex = 0
        self.actionSortList = []
        for _, _, faction, num in sortList:
        for _, _, _, faction, num in sortList:
            self.actionSortList.append([faction, num])
            
        GameWorld.DebugLog("阵容战力排序[fp, sortV, f, n]: %s" % sortList)
        GameWorld.DebugLog("阵容战力排序[isPlayer, fp, sortV, f, n]: %s" % sortList)
        GameWorld.DebugLog("阵容行动顺序[f, n]: %s" % self.actionSortList)
        return
    def getTimeline(self): return self.timeline
    def setTimeline(self, turnNum):
        '''回合战斗的时间轴节点 ,即第几回合开始,每个回合支持9999个行动节点
        @param turnNum: 第x回合
        '''
        self.timeline = turnNum * TimelineSet + 0
        GameWorld.DebugLog("时间节点更新: %s" % self.timeline)
        OnTimelineChange(self)
        return
    def addTimeline(self):
        ## 每切换一个行动单位可视为一个行动节点,即代表单回合战斗中的某一个时间节点
        self.timeline += 1
        GameWorld.DebugLog("时间节点更新: %s" % self.timeline)
        OnTimelineChange(self)
        return
    
    def getBatFaction(self, faction=ChConfig.Def_FactionA):
@@ -263,6 +289,7 @@
    def startFight(self):
        ## 准备就绪,开始战斗
        self.state = FightState_Start
        self.setTimeline(1)
        self.syncInit()
        return
    
@@ -587,7 +614,7 @@
            skillManager.LearnSkillByID(skillID)
            
        batLineup.posObjIDDict[posNum] = objID
        GameWorld.DebugLog("AddBatObj ID:%s,faction:%s,num=%s,posNum=%s,skill=%s" % (objID, faction, num, posNum, skillIDList))
        GameWorld.DebugLog("AddBatObj ID:%s,%s,skill=%s" % (objID, GetObjName(batObj), skillIDList))
        batObj.InitBatAttr({int(k):v for k, v in attrDict.items()}, initXP)
        
    return
@@ -847,12 +874,15 @@
        ## 关卡boss是一次性处理完的,一般不可能走到这里,这边做下防范
        return
    
    # 以下均是处理关卡小怪分段实时战斗
    EntryLogic(turnFight)
    # 小怪战斗,每次消耗1个战锤
    fightPoint = max(curPlayer.GetFightPoint(), 1) # 主线战斗消耗倍值,默认1
    if not PlayerControl.HaveMoney(curPlayer, ShareDefine.TYPE_Price_Xiantao, fightPoint):
        GameWorld.DebugLog("回合开始时战锤不足!")
        return
    # 以下均是处理关卡小怪分段实时战斗
    EntryLogic(turnFight)
    
    # 按阵营阵容执行顺序,逐个遍历
    doCnt = 0
@@ -869,18 +899,19 @@
        if turnFight.turnStart < turnNum:
            GameWorld.DebugLog("执行行动: turnNum=%s, 回合开始" % (turnFight.turnNum))
            turnFight.syncState(FightState_Fighting)
            if not PlayerControl.HaveMoney(curPlayer, ShareDefine.TYPE_Price_Xiantao, fightPoint):
                GameWorld.DebugLog("回合开始时战锤不足!")
                return
            #if not PlayerControl.HaveMoney(curPlayer, ShareDefine.TYPE_Price_Xiantao, fightPoint):
            #    GameWorld.DebugLog("回合开始时战锤不足!")
            #    return
            turnFight.turnStart = turnNum
            turnFight.actionIndex = 0
            turnFight.addTimeline() # 每回合开始算一个时间节点
            for faction, num in turnFight.actionSortList:
                batFaction = turnFight.getBatFaction(faction)
                batLineup = batFaction.getBatlineup(num)
                batLineup.actionNum = ActionNumStart
                for objID in batLineup.posObjIDDict.values():
                    batObj = batObjMgr.getBatObj(objID)
                    TurnFightObjPerTurnStart(turnFight, batObj, turnNum)
                    TurnFightPerTurnBigStart(turnFight, batObj, turnNum)
                    
        if turnFight.actionIndex >= len(turnFight.actionSortList):
            turnFight.actionIndex = 0
@@ -896,10 +927,6 @@
            turnFight.actionIndex += 1
            continue
        
        if faction == ChConfig.Def_FactionA:
            if not PlayerControl.HaveMoney(curPlayer, ShareDefine.TYPE_Price_Xiantao, fightPoint):
                GameWorld.DebugLog("战锤不足!")
                return
        GameWorld.DebugLog("执行行动: turnNum=%s,faction=%s,num=%s,actionNum=%s" % (turnFight.turnNum, faction, num, batLineup.actionNum))
        
        # 主公
@@ -913,11 +940,13 @@
        # 武将
        elif batLineup.actionNum > 0:
            for posNum in range(batLineup.actionNum, PosNumMax + 1):
                turnFight.addTimeline() # 每个武将位算一个时间节点
                batLineup.actionNum = posNum
                if posNum not in batLineup.posObjIDDict:
                    continue
                objID = batLineup.posObjIDDict[posNum]
                batObj = batObjMgr.getBatObj(objID)
                TurnFightHeroTurnStart(turnFight, batObj, turnNum)
                if not OnObjAction(turnFight, batObj):
                    continue
                
@@ -948,21 +977,24 @@
    if len(overLineupList) >= len(turnFight.actionSortList):
        GameWorld.DebugLog("执行行动: turnNum=%s, 回合结束" % (turnFight.turnNum))
        if turnFight.turnEnd < turnNum:
            if not PlayerControl.HaveMoney(curPlayer, ShareDefine.TYPE_Price_Xiantao, fightPoint):
                GameWorld.DebugLog("回合结束时战锤不足!")
                return
            #if not PlayerControl.HaveMoney(curPlayer, ShareDefine.TYPE_Price_Xiantao, fightPoint):
            #    GameWorld.DebugLog("回合结束时战锤不足!")
            #    return
            turnFight.turnEnd = turnNum
            turnFight.addTimeline() # 每回合结束算一个时间节点
            for faction, num in turnFight.actionSortList:
                batFaction = turnFight.getBatFaction(faction)
                batLineup = batFaction.getBatlineup(num)
                for objID in batLineup.posObjIDDict.values():
                    pass
                    batObj = batObjMgr.getBatObj(objID)
                    TurnFightPerTurnBigEnd(turnFight, batObj, turnNum)
            if turnFight.checkOverByKilled():
                return
            
        if turnNum < turnFight.turnMax:
            turnFight.turnNum += 1
            turnFight.setTimeline(turnFight.turnNum) # 回合变更,直接设置新回合时间节点
        else:
            OnTurnAllOver(turnFight.guid)
            
@@ -978,10 +1010,12 @@
    for turnNum in range(1, turnMax + 1):
        turnFight.turnNum = turnNum
        GameWorld.DebugLog("【----- 回合制战斗轮次: %s -----】" % turnNum)
        turnFight.setTimeline(turnNum)
        if curPlayer:
            turnFight.syncState(FightState_Fighting)
            
        # 回合开始
        turnFight.addTimeline() # 每回合开始算一个时间节点
        for faction, num in turnFight.actionSortList:
            GameWorld.DebugLog("回合开始逻辑: turnNum=%s,faction=%s, num=%s" % (turnNum, faction, num))
            batFaction = turnFight.getBatFaction(faction)
@@ -989,19 +1023,19 @@
            batLineup.actionNum = 1
            for objID in batLineup.posObjIDDict.values():
                batObj = batObjMgr.getBatObj(objID)
                TurnFightObjPerTurnStart(turnFight, batObj, turnNum)
                TurnFightPerTurnBigStart(turnFight, batObj, turnNum)
                
        # 主公
        for faction, num in turnFight.actionSortList:
            GameWorld.DebugLog("主公逻辑: turnNum=%s,faction=%s, num=%s" % (turnNum, faction, num))
            batFaction = turnFight.getBatFaction(faction)
            batLineup = batFaction.getBatlineup(num)
        #for faction, num in turnFight.actionSortList:
        #    GameWorld.DebugLog("主公逻辑: turnNum=%s,faction=%s, num=%s" % (turnNum, faction, num))
        #    batFaction = turnFight.getBatFaction(faction)
        #    batLineup = batFaction.getBatlineup(num)
            
        # 红颜
        for faction, num in turnFight.actionSortList:
            GameWorld.DebugLog("红颜逻辑: turnNum=%s,faction=%s, num=%s" % (turnNum, faction, num))
            batFaction = turnFight.getBatFaction(faction)
            batLineup = batFaction.getBatlineup(num)
        #for faction, num in turnFight.actionSortList:
        #    GameWorld.DebugLog("红颜逻辑: turnNum=%s,faction=%s, num=%s" % (turnNum, faction, num))
        #    batFaction = turnFight.getBatFaction(faction)
        #    batLineup = batFaction.getBatlineup(num)
            
        if turnFight.checkOverByKilled():
            break
@@ -1015,11 +1049,13 @@
            batFaction = turnFight.getBatFaction(faction)
            batLineup = batFaction.getBatlineup(num)
            for posNum in range(batLineup.actionNum, PosNumMax + 1):
                turnFight.addTimeline() # 每个武将位算一个时间节点
                batLineup.actionNum = posNum + 1
                if posNum not in batLineup.posObjIDDict:
                    continue
                objID = batLineup.posObjIDDict[posNum]
                batObj = batObjMgr.getBatObj(objID)
                TurnFightHeroTurnStart(turnFight, batObj, turnNum)
                if not OnObjAction(turnFight, batObj):
                    continue
                
@@ -1031,13 +1067,15 @@
                turnFight.actionIndex += 1
                
        # 回合结束
        turnFight.addTimeline() # 每回合结束算一个时间节点
        for faction, num in turnFight.actionSortList:
            GameWorld.DebugLog("回合结束逻辑: turnNum=%s,faction=%s, num=%s" % (turnNum, faction, num))
            batFaction = turnFight.getBatFaction(faction)
            batLineup = batFaction.getBatlineup(num)
            for objID in batLineup.posObjIDDict.values():
                pass
                batObj = batObjMgr.getBatObj(objID)
                TurnFightPerTurnBigEnd(turnFight, batObj, turnNum)
        if turnFight.checkOverByKilled():
            break
        
@@ -1061,35 +1099,101 @@
        return
    GameWorld.DebugLog("执行进场逻辑...")
    
    batObjMgr = BattleObj.GetBatObjMgr()
    for faction, num in turnFight.actionSortList:
        batFaction = turnFight.getBatFaction(faction)
        batLineup = batFaction.getBatlineup(num)
        batLineup.actionNum = ActionNumStart
        for objID in batLineup.posObjIDDict.values():
            batObj = batObjMgr.getBatObj(objID)
            TurnPassive.OnTriggerPassiveEffect(turnFight, batObj, ChConfig.TriggerWay_FightStart)
    turnFight.enterLogic = True
    return
def TurnFightObjPerTurnStart(turnFight, batObj, turnNum):
    ## 回合制战斗实例 - 每回合开始时处理
def OnTimelineChange(turnFight):
    nowTimeline = turnFight.getTimeline()
    batObjMgr = BattleObj.GetBatObjMgr()
    for batFaction in turnFight.factionDict.values():
        for batLineup in batFaction.lineupDict.values():
            for objID in batLineup.posObjIDDict.values():
                batObj = batObjMgr.getBatObj(objID)
                if not batObj or batObj.GetHP() <= 0:
                    continue
                curID = batObj.GetID()
                skillManager = batObj.GetSkillManager()
                for index in range(0, skillManager.GetSkillCount()):
                    curSkill = skillManager.GetSkillByIndex(index)
                    if not curSkill:
                        continue
                    remainTime = curSkill.GetRemainTime()
                    if not remainTime:
                        continue
                    calcTimeline = curSkill.GetCalcTime()
                    passTurn = __calcPassturn(calcTimeline, nowTimeline, True)
                    if passTurn <= 0:
                        continue
                    skillID = curSkill.GetSkillID()
                    updRemainTime = max(0, remainTime - passTurn)
                    curSkill.SetRemainTime(updRemainTime)
                    curSkill.SetCalcTime(nowTimeline)
                    GameWorld.DebugLog("更新技能剩余回合数: curID=%s,skillID=%s,updRemainTime=%s,calcTimeline=%s,passTurn=%s"
                                       % (curID, skillID, updRemainTime, calcTimeline, passTurn))
                buffMgr = batObj.GetBuffManager()
                for index in range(buffMgr.GetBuffCount())[::-1]:
                    buff = buffMgr.GetBuffByIndex(index)
                    remainTime = buff.GetRemainTime()
                    if not remainTime:
                        # 永久buff不处理
                        continue
                    calcTimeline = buff.GetCalcTime()
                    passTurn = __calcPassturn(calcTimeline, nowTimeline, False)
                    if passTurn <= 0:
                        continue
                    updRemainTime = max(0, remainTime - passTurn)
                    buffID = buff.GetBuffID()
                    skillID = buff.GetSkillID()
                    GameWorld.DebugLog("更新buff剩余回合数: curID=%s,buffID=%s,skillID=%s,updRemainTime=%s,calcTimeline=%s,passTurn=%s"
                                       % (curID, buffID, skillID, updRemainTime, calcTimeline, passTurn))
                    if updRemainTime > 0:
                        buff.SetRemainTime(updRemainTime)
                        buff.SetCalcTime(nowTimeline)
                        TurnBuff.SyncBuffRefresh(turnFight, batObj, buff)
                    else:
                        TurnBuff.DoBuffDel(turnFight, batObj, buff)
    return
def __calcPassturn(calcTimeline, nowTimeline, equalOK):
    ## 计算已经过了的回合数
    # @param equalOK: 时间节点相同时是否算1回合,一般技能可以算,buff不算
    calcTurnNum = calcTimeline / TimelineSet
    calcTimeNode = calcTimeline % TimelineSet
    nowTurnNum = nowTimeline / TimelineSet
    nowTimeNode = nowTimeline % TimelineSet
    if equalOK:
        if nowTimeNode >= calcTimeNode:
            return max(0, nowTurnNum - calcTurnNum)
        return max(0, nowTurnNum - calcTurnNum - 1)
    else:
        if nowTimeNode > calcTimeNode:
            return max(0, nowTurnNum - calcTurnNum)
        return max(0, nowTurnNum - calcTurnNum - 1)
    return 0
def TurnFightPerTurnBigStart(turnFight, batObj, turnNum):
    ## 大回合开始时
    if not batObj:
        return
    
    if batObj.GetHP() <= 0:
        return
    
    curID = batObj.GetID()
    buffMgr = batObj.GetBuffManager()
    GameWorld.DebugLog("更新buff: curID=%s,buffCount=%s" % (curID, buffMgr.GetBuffCount()))
    for index in range(buffMgr.GetBuffCount())[::-1]:
        buff = buffMgr.GetBuffByIndex(index)
        curRemainTime = buff.GetRemainTime()
        if not curRemainTime:
            # 永久buff不处理
            continue
        buffID = buff.GetBuffID()
        skillID = buff.GetSkillID()
        updRemainTime = curRemainTime - 1
        GameWorld.DebugLog("    更新buff剩余回合数: buffID=%s,skillID=%s,updRemainTime=%s" % (buffID, skillID, updRemainTime))
        if updRemainTime > 0:
            buff.SetRemainTime(updRemainTime)
            TurnBuff.SyncBuffRefresh(turnFight, batObj, buff)
        else:
            TurnBuff.DoBuffDel(turnFight, batObj, buff)
    TurnPassive.OnTriggerPassiveEffect(turnFight, batObj, ChConfig.TriggerWay_BigTurnStart)
            
#    SetTimeline(gameObj, turnNum, 0)
#    # 重置连击、反击数
@@ -1126,6 +1230,28 @@
#    __logGameObjAttr(gameObj)
    return
def TurnFightPerTurnBigEnd(turnFight, batObj, turnNum):
    ## 大回合结束时
    if not batObj:
        return
    if batObj.GetHP() <= 0:
        return
    TurnPassive.OnTriggerPassiveEffect(turnFight, batObj, ChConfig.TriggerWay_BigTurnEnd)
    return
def TurnFightHeroTurnStart(turnFight, batObj, turnNum):
    ## 武将回合开始时
    if not batObj:
        return
    if batObj.GetHP() <= 0:
        return
    TurnPassive.OnTriggerPassiveEffect(turnFight, batObj, ChConfig.TriggerWay_HeroTurnStart)
    return
def AddTurnObjCureHP(curObj, srcObj, addValue, cureHP, skillID=0):
    ## 回合对象添加治疗值
    # @param curObj: 获得治疗的对象
@@ -1142,12 +1268,11 @@
        
    return
def AddTurnObjHurtValue(curBatObj, tagBatObj, hurtValue, lostHP, curSkill=None, isBounce=False):
def AddTurnObjHurtValue(curBatObj, tagBatObj, hurtValue, lostHP, skillID=0, isBounce=False):
    ## 回合对象添加伤害值
    # @param isBounce: 是否反弹伤害
    curID = curBatObj.GetID()
    tagID = tagBatObj.GetID()
    skillID = curSkill.GetSkillID() if curSkill else 0
    if curID != tagID:
        updStatValue = curBatObj.StatHurtValue(hurtValue)
        GameWorld.DebugLog("        统计伤血: curID=%s,tagID=%s,skillID=%s,hurtValue=%s,lostHP=%s,updStatValue=%s,tagHP=%s,isBounce=%s" 
@@ -1183,11 +1308,13 @@
    if not canAction:
        GameWorld.DebugLog("★回合%s %s 当前状态不可行动!" % (turnNum, objName))
        return
    atk = curBatObj.GetAtk()
    curXP = curBatObj.GetXP()
    GameWorld.DebugLog("★回合%s %s 行动 : atk=%s,curHP=%s/%s,curXP=%s" % (turnNum, objName, atk, curHP, curBatObj.GetMaxHP(), curXP))
    turnFight.syncObjAction(turnNum, objID)
    TurnPassive.OnTriggerPassiveEffect(turnFight, curBatObj, ChConfig.TriggerWay_HeroActionStart)
    
    xpMax = IpyGameDataPY.GetFuncCfg("AngerXP", 2) 
    skillManager = curBatObj.GetSkillManager()
@@ -1197,8 +1324,8 @@
        useSkill = skillManager.GetSkillByIndex(index)
        if not useSkill:
            continue
        if useSkill.GetFuncType() in [ChConfig.Def_SkillFuncType_AtkbackSkill]:
            #基础普攻不能主动释放,目前仅用于反击
        if useSkill.GetFuncType() not in [ChConfig.Def_SkillFuncType_TurnNormaSkill, ChConfig.Def_SkillFuncType_AngerSkill]:
            #只能主动释放普攻或怒技
            continue
        #被动技能无法使用
        if SkillCommon.isPassiveSkill(useSkill):
@@ -1222,9 +1349,10 @@
    for useInfo in useSkillList:
        useSkill = useInfo[-1]
        if TurnSkill.OnUseSkill(turnFight, curBatObj, useSkill):
            return True
            break
        
    return
    TurnPassive.OnTriggerPassiveEffect(turnFight, curBatObj, ChConfig.TriggerWay_HeroActionEnd)
    return True
def DoAttack(curBatObj, tagBatObj, tick, turnBattleType=ChConfig.TurnBattleType_Normal, useSkill=None):
#    curID = curBatObj.GetID()
@@ -1379,45 +1507,6 @@
    GameWorld.DebugLog("            可以连击: atkID=%s,comboNum=%s,comboRate=%s=(atkComboRate=%s - defComboReduce=%s)" 
                       % (atkObj.GetID(), comboNum, comboRate, atkComboRate, defComboReduce))
    return True
#def GetEnemyObj(curNPC, ruleType=0):
#    ## 获取一个敌对单位,针对所有敌对阵容主战单位,优先选择对位阵容单位,仅限活着的单位
#    # @param ruleType: 选择规则,默认0任意,1-最低血量;2-最高血量
#    objID = curNPC.GetID()
#    faction = GameObj.GetFaction(curNPC)
#    posInfo = curNPC.GetDictByKey(ChConfig.Def_Obj_Dict_TurnFightPosInfo)
#    num = posInfo / 100 # 阵容编号
#    posNum = posInfo % 100 # 所在阵容站位
#    turnFight = GetTurnFightMgr().getTurnFight(curNPC.GetTFGUID())
#    if not turnFight:
#        return
#
#    tagBatFaction = turnFight.getBatFaction(Def_FactionB if faction == Def_FactionA else Def_FactionA)
#
#    tagLineupNumList = [num] # 目标阵容选择顺序,优先对位阵容,再其他阵容
#    if num in tagBatFaction.lineupDict:
#        tagLineupNumList = [num]
#    for tagNum in tagBatFaction.lineupDict.keys():
#        if tagNum not in tagLineupNumList:
#            tagLineupNumList.append(tagNum)
#
#    batObjMgr = BattleObj.GetBatObjMgr()
#    for tagNum in tagLineupNumList:
#        tagLineup = tagBatFaction.getBatlineup(tagNum)
#        tagPosNumList = [posNum] # 优先对位位置,再其他位置按顺序遍历
#        pNumList = tagLineup.posObjIDDict.keys()
#        pNumList.sort()
#        for pNum in pNumList:
#            if pNum > 0 and pNum not in tagPosNumList:
#                tagPosNumList.append(pNum)
#        for pNum in tagPosNumList:
#            batObj = batObjMgr.getBatObj(objID)
#            if not batObj:
#                continue
#            if batObj.GetHP( )<= 0:
#                continue
#            return batObj
#    return
def SetObjKilled(turnFight, gameObj, killer=None, useSkill=None):
    objID = gameObj.GetID()
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
@@ -770,8 +770,6 @@
Def_Skill_Effect_BoomSeedHurt = 804 # BUFF种子单层伤害
Def_Skill_Effect_StoreBlood = 809 # 将期间受到的伤害总值,用于最后回血,不影响伤害
Def_Skill_Effect_AttackReplace = 1009  #攻击计算,野外小怪伤害替换1010 (2018-03-07增加精英怪)
Def_Skill_Effect_Cure = 1000  #治疗
Def_Skill_Effect_Anger = 1001  #怒气增减偷
Def_Skill_Effect_Attack = 1010  #攻击计算
Def_Skill_Effect_LayerCnt = 1011 # BUFF层级数量 A值层数;B值:10位-是否非叠加属性,个位-层数处理方式0递增1递减;C值: 是否攻击减层
Def_Skill_Effect_MasterBuff = 1012 # 主从技能(同步buff持续时间)
@@ -952,7 +950,7 @@
#伤害类型
(
HurtType_Fail,              # 失败 - 如概率没有触发 0
HurtType_Normal,            # 普通伤害 1
HurtType_Normal,            # 伤害 1
HurtTYpe_Recovery,          # 回血 2
HurtType_3,
HurtType_4,
@@ -1308,11 +1306,9 @@
Def_CureTypeList = (
Def_Cure_Attack, # 攻击 0
Def_Cure_MaxHP, # 最大生命值 1
Def_Cure_PNE, # 智力 2
Def_Cure_PHY, # 敏捷 3
Def_Cure_HurtValue, # 伤害值 4
Def_Cure_TagMaxHP, # 目标最大生命值 5
) = range(6)
Def_Cure_HurtValue, # 伤害值 2
Def_Cure_TagMaxHP, # 目标最大生命值 3
) = range(4)
#回魔类型(影响公式参数)
Def_RestoreTypeList = (
@@ -3141,26 +3137,18 @@
#玩家状态定义,不能超过31个,如超过,需扩展多个key支持
BatObjStateList = (
    BatObjState_Normal, # 无 0
    BatObjState_Freezed, # 定身状态 1
    BatObjState_Slow, # 减速状态 2
    BatObjState_LoseBlood, # 持续掉血状态 3
    BatObjState_Shield, # 麒麟佑身4
    BatObjState_DamBackShield, # 东皇附体5
    BatObjState_Sneer, # 嘲讽 6
    BatObjState_Stun, # 晕眩状态 7
    BatObjState_AddAtk, # 加攻状态 8
    BatObjState_WeakDef, # 减防状态 9
    BatObjState_LimitSkill, # 禁魔状态 10
    BatObjState_LimitAddHP, # 禁疗状态 11
    BatObjState_Blind, # 致盲状态 12
    BatObjState_Burn, # 灼烧 13
    BatObjState_LoseBlood2, # 职业2持续掉血状态 14
    BatObjState_LoseBlood3, # 职业3持续掉血状态 15
    BatObjState_MissSneerAtk, # 对嘲讽攻击免疫表现为miss 16
    BatObjState_BeInAir, # 浮空(做法同眩晕类) 17
    BatObjState_zqdlj, # 紫气东来金灵根技能状态 18
    BatObjState_Ice, # 寒冰状态(同减速) 19
) = range(20)
    BatObjState_Frozen, # 冰冻 1
    BatObjState_Cold, # 减速/寒冷 2
    BatObjState_Stun, # 眩晕 3
    BatObjState_Burn, # 灼烧 4
    BatObjState_Poison, # 中毒 5
    BatObjState_Bleeding, # 流血 6
    BatObjState_EasyHurt, # 易伤 7
    BatObjState_Wudi, # 无敌 8
    BatObjState_Sneer, # 嘲讽 9
    BatObjState_LimitSkill, # 沉默 10
    BatObjState_LimitAddHP, # 禁疗 11
) = range(12)
#玩家状态定义,不能超过31个,如超过,需扩展多个key支持
Def_PlayerStateList = (
@@ -4458,6 +4446,17 @@
#-------------------------------------------------------------------------------
# 被动触发方式
(
TriggerWay_FightStart, # 战斗开始时    1
TriggerWay_BigTurnStart, # 大回合开始时    2
TriggerWay_BigTurnEnd, # 大回合结束时    3
TriggerWay_HeroTurnStart, # 武将回合开始时    4
TriggerWay_HeroTurnEnd, # 武将回合开始时    5
TriggerWay_HeroActionStart, # 武将行动前    6
TriggerWay_HeroActionEnd, # 武将行动后    7
) = range(1, 1 + 7)
(
TriggerType_BeSuperHit, # 被暴击触发技能 1
TriggerType_BuffState,  # 进入4012的某个状态触发技能
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
@@ -50236,6 +50236,7 @@
                  ("SubCmd", c_ubyte),
                  ("ObjID", c_int),    
                  ("RefreshType", c_ushort),    # 同0418刷新类型,如血量、怒气
                  ("AttackTypes", c_int),    # 飘字类型汇总,支持多种类型并存,如无视防御且暴击同时被格挡,二进制或运算最终值;0-失败;1-普通;2-回血;5-格挡;6-无视防御;7-暴击;9-闪避
                  ("Value", c_int),    # 更新值
                  ("ValueEx", c_int),    # 更新值,如果是大数值的此值为整除亿部分
                  ("DiffType", c_ubyte),    # 变化类型,0-减少;1-增加
@@ -50261,6 +50262,7 @@
        self.SubCmd = 0x18
        self.ObjID = 0
        self.RefreshType = 0
        self.AttackTypes = 0
        self.Value = 0
        self.ValueEx = 0
        self.DiffType = 0
@@ -50282,6 +50284,7 @@
                                SubCmd:%s,
                                ObjID:%d,
                                RefreshType:%d,
                                AttackTypes:%d,
                                Value:%d,
                                ValueEx:%d,
                                DiffType:%d,
@@ -50295,6 +50298,7 @@
                                self.SubCmd,
                                self.ObjID,
                                self.RefreshType,
                                self.AttackTypes,
                                self.Value,
                                self.ValueEx,
                                self.DiffType,
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
@@ -86,6 +86,7 @@
                "Skill":(
                        ("DWORD", "SkillID", 1),
                        ("DWORD", "SkillTypeID", 0),
                        ("WORD", "SkillLV", 0),
                        ("WORD", "SkillMaxLV", 0),
                        ("char", "SkillName", 0),
                        ("BYTE", "FuncType", 0),
@@ -96,17 +97,34 @@
                        ("BYTE", "TagFriendly", 0),
                        ("BYTE", "TagAffect", 0),
                        ("BYTE", "TagCount", 0),
                        ("BYTE", "CalcType", 0),
                        ("WORD", "SkillPer", 0),
                        ("DWORD", "SkillValue", 0),
                        ("WORD", "HappenRate", 0),
                        ("WORD", "LastTime", 0),
                        ("WORD", "CoolDownTime", 0),
                        ("WORD", "Priority", 0),
                        ("DWORD", "EffectID1", 0),
                        ("list", "EffectValues1", 0),
                        ("BYTE", "TriggerWay1", 0),
                        ("BYTE", "TriggerSrc1", 0),
                        ("list", "TriggerParams1", 0),
                        ("DWORD", "EffectID2", 0),
                        ("list", "EffectValues2", 0),
                        ("BYTE", "TriggerWay2", 0),
                        ("BYTE", "TriggerSrc2", 0),
                        ("list", "TriggerParams2", 0),
                        ("DWORD", "EffectID3", 0),
                        ("list", "EffectValues3", 0),
                        ("BYTE", "TriggerWay3", 0),
                        ("BYTE", "TriggerSrc3", 0),
                        ("list", "TriggerParams3", 0),
                        ("DWORD", "ConnSkill", 0),
                        ("WORD", "CoolDownTime", 0),
                        ("list", "IgnoreStates", 0),
                        ("list", "BuffStates", 0),
                        ("WORD", "LastTime", 0),
                        ("BYTE", "LayerCnt", 0),
                        ("BYTE", "LayerMax", 0),
                        ("DWORD", "BuffRepeat", 0),
                        ("DWORD", "DieContinue", 0),
                        ("list", "EnhanceSkillList", 0),
                        ("DWORD", "FightPower", 0),
                        ),
@@ -2908,29 +2926,47 @@
        
    def GetSkillID(self): return self.attrTuple[0] # 技能ID DWORD
    def GetSkillTypeID(self): return self.attrTuple[1] # 技能TypeID DWORD
    def GetSkillMaxLV(self): return self.attrTuple[2] # 最高等级 WORD
    def GetSkillName(self): return self.attrTuple[3] # 技能名 char
    def GetFuncType(self): return self.attrTuple[4] # 功能分类 BYTE
    def GetSkillType(self): return self.attrTuple[5] # 技能类型 BYTE
    def GetHurtType(self): return self.attrTuple[6] # 伤害类型 BYTE
    def GetAtkType(self): return self.attrTuple[7] # 释放方式 BYTE
    def GetTagAim(self): return self.attrTuple[8] # 瞄准位置 BYTE
    def GetTagFriendly(self): return self.attrTuple[9] # 敌我目标 BYTE
    def GetTagAffect(self): return self.attrTuple[10] # 目标细分 BYTE
    def GetTagCount(self): return self.attrTuple[11] # 目标个数 BYTE
    def GetHappenRate(self): return self.attrTuple[12] # 释放或添加几率 WORD
    def GetLastTime(self): return self.attrTuple[13] # 持续时间 WORD
    def GetCoolDownTime(self): return self.attrTuple[14] # 冷却时间 WORD
    def GetPriority(self): return self.attrTuple[15] # 优先级 WORD
    def GetEffectID1(self): return self.attrTuple[16] # 效果ID1 DWORD
    def GetEffectValues1(self): return self.attrTuple[17] # 效果值列表1 list
    def GetEffectID2(self): return self.attrTuple[18] # 效果ID2 DWORD
    def GetEffectValues2(self): return self.attrTuple[19] # 效果值列表2 list
    def GetEffectID3(self): return self.attrTuple[20] # 效果ID3 DWORD
    def GetEffectValues3(self): return self.attrTuple[21] # 效果值列表3 list
    def GetConnSkill(self): return self.attrTuple[22] # 关联技能 DWORD
    def GetEnhanceSkillList(self): return self.attrTuple[23] # 触发技能ID列表 list
    def GetFightPower(self): return self.attrTuple[24] # 技能战斗力 DWORD
    def GetSkillLV(self): return self.attrTuple[2] # 当前等级 WORD
    def GetSkillMaxLV(self): return self.attrTuple[3] # 最高等级 WORD
    def GetSkillName(self): return self.attrTuple[4] # 技能名 char
    def GetFuncType(self): return self.attrTuple[5] # 功能分类 BYTE
    def GetSkillType(self): return self.attrTuple[6] # 技能类型 BYTE
    def GetHurtType(self): return self.attrTuple[7] # 伤害类型 BYTE
    def GetAtkType(self): return self.attrTuple[8] # 释放方式 BYTE
    def GetTagAim(self): return self.attrTuple[9] # 瞄准位置 BYTE
    def GetTagFriendly(self): return self.attrTuple[10] # 敌我目标 BYTE
    def GetTagAffect(self): return self.attrTuple[11] # 目标细分 BYTE
    def GetTagCount(self): return self.attrTuple[12] # 目标个数 BYTE
    def GetCalcType(self): return self.attrTuple[13] # 计算方式 BYTE
    def GetSkillPer(self): return self.attrTuple[14] # 技能万分比 WORD
    def GetSkillValue(self): return self.attrTuple[15] # 技能固定值 DWORD
    def GetHappenRate(self): return self.attrTuple[16] # 释放或添加几率 WORD
    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 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 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 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
# 武将表
class IPY_Hero():
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/GameSkills/SkillCommon.py
@@ -1283,8 +1283,6 @@
            AttackCommon.OnPVPDamage(attackerOwner, lostValue, curObj, "SkillLostHP")
        elif curObjType == IPY_GameWorld.gotNPC:
            AttackCommon.NPCAddObjInHurtList(attackerOwner, curObj, curObjHP_BeforeAttack, lostValue)
    #TurnAttack.AddTurnObjHurtValue(buffOwner, curObj, lostValue, lostHP, curSkill)
    
    #统一调用攻击结束动作
    if isDoAttackResult:
@@ -2075,12 +2073,12 @@
        cureBaseValue = GetCureBaseValue(userObj, curSkill)
    elif cureType == ChConfig.Def_Cure_MaxHP:
        cureBaseValue = GameObj.GetMaxHP(userObj)
    elif cureType == ChConfig.Def_Cure_PNE:
        cureBaseValue = userObj.GetPNE()
        addPer = curSkill.GetEffect(0).GetEffectValue(2)/float(ChConfig.Def_MaxRateValue)
        addExValue = GetCureBaseValue(userObj, curSkill)*addPer
    elif cureType == ChConfig.Def_Cure_PHY:
        cureBaseValue = GameObj.GetMaxHP(userObj)
    #elif cureType == ChConfig.Def_Cure_PNE:
    #    cureBaseValue = userObj.GetPNE()
    #    addPer = curSkill.GetEffect(0).GetEffectValue(2)/float(ChConfig.Def_MaxRateValue)
    #    addExValue = GetCureBaseValue(userObj, curSkill)*addPer
    #elif cureType == ChConfig.Def_Cure_PHY:
    #    cureBaseValue = GameObj.GetMaxHP(userObj)
    elif cureType == ChConfig.Def_Cure_HurtValue:
        cureBaseValue = GameObj.GetLastHurtValue(userObj)
    elif cureType == ChConfig.Def_Cure_TagMaxHP:
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/PassiveTrigger/PassiveEff_5001.py
New file
@@ -0,0 +1,47 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
##@package Skill.PassiveTrigger.PassiveEff_5001
#
# @todo:buff层数结算持续buff
# @author hxp
# @date 2025-08-19
# @version 1.0
#
# 详细描述: buff层数结算持续buff
#
#-------------------------------------------------------------------------------
#"""Version = 2025-08-19 16:00"""
#-------------------------------------------------------------------------------
import TurnBuff
def DoBuffEffectLogic(turnFight, batObj, curBuff, curEffect, connSkill):
    singleLayerCnt = max(1, curEffect.GetEffectValue(0)) # 单次消耗层数/次数
    noDel = curEffect.GetEffectValue(1) # 是否不扣除层数,默认0-扣除 1-不扣除
    isAll = curEffect.GetEffectValue(2) # 是否结算剩余全部层数/次数,默认0结算单次
    skillData = curBuff.GetSkillData()
    nowLayerCnt = curBuff.GetLayer()
    # 全部层级
    if isAll:
        logicCnt = nowLayerCnt / singleLayerCnt
        updLayerCnt = 0
    else:
        logicCnt = 1 # 执行逻辑次数
        updLayerCnt = nowLayerCnt - singleLayerCnt
    for _ in range(logicCnt):
        TurnBuff.DoBuffProcess(turnFight, batObj, curBuff)
    # 消耗层级,有限制层级的才进行消耗
    if not noDel and skillData.GetLayerCnt():
        curBuff.SetLayer(max(updLayerCnt, 0))
        if updLayerCnt <= 0:
            TurnBuff.DoBuffDel(turnFight, batObj, curBuff)
        else:
            TurnBuff.SyncBuffRefresh(turnFight, batObj, curBuff)
    return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnBuff.py
@@ -18,94 +18,100 @@
import ChConfig
import GameWorld
import ChPyNetSendPack
import SkillCommon
import TurnBuffs
import ObjPool
GameWorld.ImportAll("Script\\Skill\\", "TurnBuffs")
def OnAddBuff(turnFight, batObj, curSkill, buffOwner=None):
    skillID = curSkill.GetSkillID()
    bySkill = curSkill.GetBySkill()
def GetAddBuffValue(attacker, defender, curSkill):
    callFunc = GameWorld.GetExecFunc(TurnBuffs, "BuffAtkType_%d.%s" % (curSkill.GetAtkType(), "CalcBuffValue"))
    if not callFunc:
        return []
    return callFunc(attacker, defender, curSkill)
def OnAddBuff(turnFight, batObj, buffSkill, buffOwner=None):
    skillID = buffSkill.GetSkillID()
    bySkill = buffSkill.GetBySkill()
    relatedSkillID = bySkill.GetSkillID() if bySkill else 0
    curID = batObj.GetID()
    ownerID = buffOwner.GetID() if buffOwner else curID
    GameWorld.DebugLog("OnAddBuff: curID=%s,skillID=%s,ownerID=%s,relatedSkillID=%s" % (curID, skillID, ownerID, relatedSkillID))
    #检查是否几率触发,附加技能、被动触发的外层已检查过概率,不重复检查
    if not (curSkill.GetIsEnhanceSkill() or SkillCommon.isPassiveTriggerSkill(curSkill)):
        rate = curSkill.GetHappenRate()
        if rate and rate != ChConfig.Def_MaxRateValue and not GameWorld.CanHappen(rate, ChConfig.Def_MaxRateValue):
            GameWorld.DebugLog("    概率不触发buff!")
            return
    skillTypeID = curSkill.GetSkillTypeID()
    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))
    skillTypeID = buffSkill.GetSkillTypeID()
    # 先简单做下能加上即可
    buffMgr = batObj.GetBuffManager()
    buffIDList = buffMgr.FindBuffIDBySkillTypeID(skillTypeID)
    if buffIDList:
        GameWorld.DebugLog("    已经存在该buff: skillTypeID=%s,buffIDList=%s" % (skillTypeID, buffIDList))
        # buff堆叠逻辑
        return True
    
    buff = buffMgr.AddBuff(skillID)
    if not buff:
        GameWorld.DebugLog("    添加buff失败! skillID=%s" % skillID)
        return False
    GameWorld.DebugLog("    AddBuffOK. buffID=%s" % buff.GetBuffID())
    buff.SetOwnerID(ownerID)
    buff.SetRemainTime(curSkill.GetLastTime())
    #buff.SetLayer()
    SyncBuffRefresh(turnFight, batObj, buff, relatedSkillID)
    DoBuffAddOver(turnFight, batObj, curSkill, buff, buffOwner)
    __AddNewBuff(turnFight, batObj, buffMgr, buffSkill, buffValueList, buffOwner)
    return True
def SyncBuffRefresh(turnFight, curBatObj, curBuff, relatedSkillID=0):
    clientPack = ObjPool.GetPoolMgr().acquire(ChPyNetSendPack.tagSCBuffRefresh)
    clientPack.ObjID = curBatObj.GetID()
    clientPack.BuffID = curBuff.GetBuffID()
    clientPack.SkillID = curBuff.GetSkillID()
    clientPack.RelatedSkillID = relatedSkillID
    clientPack.LastTime = curBuff.GetRemainTime()
    clientPack.Layer = curBuff.GetLayer()
    clientPack.OwnerID = curBuff.GetOwnerID()
    turnFight.addBatPack(clientPack)
def __AddNewBuff(turnFight, batObj, buffMgr, buffSkill, buffValueList, buffOwner):
    skillID = buffSkill.GetSkillID()
    bySkill = buffSkill.GetBySkill()
    relatedSkillID = bySkill.GetSkillID() if bySkill else 0
    curID = batObj.GetID()
    ownerID = buffOwner.GetID()
    buff = buffMgr.AddBuff(skillID)
    if not buff:
        GameWorld.DebugLog("    添加buff失败! skillID=%s" % skillID, curID)
        return False
    buffID = buff.GetBuffID()
    GameWorld.DebugLog("    AddBuffOK. buffID=%s,skillID=%s,ownerID=%s,relatedSkillID=%s,timeline=%s"
                       % (buffID, skillID, ownerID, relatedSkillID, turnFight.getTimeline()), curID)
    buff.SetOwnerID(ownerID)
    buff.SetCalcTime(turnFight.getTimeline())
    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:
        SyncBuffRefresh(turnFight, batObj, buff, relatedSkillID)
    DoBuffAddOver(turnFight, batObj, buffSkill, buff, buffOwner)
    return
def SyncBuffDel(turnFight, curBatObj, buffID, relatedSkillID=0):
    clientPack = ObjPool.GetPoolMgr().acquire(ChPyNetSendPack.tagSCBuffDel)
    clientPack.ObjID = curBatObj.GetID()
    clientPack.BuffID = buffID
    clientPack.RelatedSkillID = relatedSkillID
    turnFight.addBatPack(clientPack)
    return
def DoBuffAddOver(turnFight, batObj, curSkill, addBuff, buffOwner=None):
def DoBuffAddOver(turnFight, batObj, buffSkill, addBuff, buffOwner):
    ## buff添加成功后处理
    
    isRefreshAttr = False # 是否刷属性
    skillData = addBuff.GetSkillData()
    #atkType = buffSkill.GetAtkType()
    #if atkType:
    #    callFunc = GameWorld.GetExecFunc(TurnBuffs, "BuffAtkType_%d.%s" % (atkType, "OnBuffAddOver"))
    #    if callFunc:
    #        callFunc(turnFight, batObj, buffSkill, addBuff, buffOwner)
    passiveEffMgr = batObj.GetPassiveEffManager()
    # buff效果加入
    for effectIndex in range(0, skillData.GetEffectCount()):
        curEffect = skillData.GetEffect(effectIndex)
    for effectIndex in range(0, buffSkill.GetEffectCount()):
        curEffect = buffSkill.GetEffect(effectIndex)
        effectID = curEffect.GetEffectID()
        if effectID == 0:
            continue
        
        if effectID in ChConfig.AttrIDList:
        if curEffect.GetTriggerWay():
            if curEffect.GetTriggerSrc() == 2:
                passiveEffMgr.AddBuffPassiveEffect(addBuff, buffSkill, curEffect)
        elif effectID in ChConfig.AttrIDList:
            isRefreshAttr = True
            
        callFunc = GameWorld.GetExecFunc(TurnBuffs, "Buff_%d.%s" % (effectID, "OnBuffAddOver"))
        if callFunc:
            GameWorld.DebugLog("OnBuffAddOver, objID=%s,buffID=%s,effectID=%s" % (batObj.GetID(), addBuff.GetBuffID(), effectID))
            callFunc(turnFight, batObj, curSkill, addBuff, curEffect, buffOwner)
        #被动触发的
        #triggerType = PassiveBuffEffMng.GetBuffTriggerTypeByEffectID(effectID)
        #if triggerType == -1:
        #    continue
        #passiveEff = PassiveBuffEffMng.GetPassiveEffManager().InitObjPassiveEff(curObj)
        #passiveEff.AddBuffInfoByEffect(curEffect, skillID, onwerID, onwerType)
        else:
            callFunc = GameWorld.GetExecFunc(TurnBuffs, "Buff_%d.%s" % (effectID, "OnBuffAddOver"))
            if callFunc:
                callFunc(turnFight, batObj, buffSkill, addBuff, curEffect, buffOwner)
    if isRefreshAttr:
        RefreshBuffAttr(batObj)
        
@@ -113,6 +119,9 @@
def DoBuffDel(turnFight, batObj, curBuff):
    ## 删除buff
    isRefreshAttr = False # 是否刷属性
    haveBuffPassiveEff = False
    
    buffMgr = batObj.GetBuffManager()
    buffID = curBuff.GetBuffID()
@@ -125,20 +134,40 @@
        if not effectID:
            continue
        
        callFunc = GameWorld.GetExecFunc(TurnBuffs, "Buff_%d.%s" % (effectID, "OnBuffDel"))
        if callFunc:
            callFunc(turnFight, batObj, curBuff, curEffect)
        if curEffect.GetTriggerWay():
            if curEffect.GetTriggerSrc() == 2:
                haveBuffPassiveEff = True
        elif effectID in ChConfig.AttrIDList:
            isRefreshAttr = True
            
    #passiveEff = PassiveBuffEffMng.GetPassiveEffManager().GetPassiveEff(curObj)
    #if passiveEff:
    #    passiveEff.DelBuffInfo(skillData)
        else:
            callFunc = GameWorld.GetExecFunc(TurnBuffs, "Buff_%d.%s" % (effectID, "OnBuffDel"))
            if callFunc:
                callFunc(turnFight, batObj, curBuff, curEffect)
    if haveBuffPassiveEff:
        batObj.GetPassiveEffManager().DelBuffPassiveEffect(buffID)
    buffStates = skillData.GetBuffStates()
    for buffState in buffStates:
        buffMgr.DelBuffState(buffState, buffID)
    # 最后删除buff、通知
    buffMgr.DelBuff(buffID)
    SyncBuffDel(turnFight, batObj, buffID)
    if isRefreshAttr:
        RefreshBuffAttr(batObj)
    return
def DoBuffProcess(turnFight, batObj, curBuff):
    skillData = curBuff.GetSkillData()
    callFunc = GameWorld.GetExecFunc(TurnBuffs, "BuffAtkType_%d.%s" % (skillData.GetAtkType(), "DoBuffProcess"))
    if callFunc:
        callFunc(turnFight, batObj, curBuff)
    return
def RefreshBuffAttr(batObj):
    ''' 刷新buff属性,如果有涉及到buff属性变更的,只能全部buff重新刷
    '''
@@ -206,3 +235,23 @@
    GameWorld.DebugLog("    befHP=%s/%s, aftHP=%s/%s" % (befHP, befMaxHP, aftHP, aftMaxHP))
    GameWorld.DebugLog("    最终属性 ID:%s,atk=%s,def=%s,hp=%s/%s" % (objID, batObj.GetAtk(), batObj.GetDef(), aftHP, aftMaxHP))
    return
def SyncBuffRefresh(turnFight, curBatObj, curBuff, relatedSkillID=0):
    clientPack = ObjPool.GetPoolMgr().acquire(ChPyNetSendPack.tagSCBuffRefresh)
    clientPack.ObjID = curBatObj.GetID()
    clientPack.BuffID = curBuff.GetBuffID()
    clientPack.SkillID = curBuff.GetSkillID()
    clientPack.RelatedSkillID = relatedSkillID
    clientPack.LastTime = curBuff.GetRemainTime()
    clientPack.Layer = curBuff.GetLayer()
    clientPack.OwnerID = curBuff.GetOwnerID()
    turnFight.addBatPack(clientPack)
    return
def SyncBuffDel(turnFight, curBatObj, buffID, relatedSkillID=0):
    clientPack = ObjPool.GetPoolMgr().acquire(ChPyNetSendPack.tagSCBuffDel)
    clientPack.ObjID = curBatObj.GetID()
    clientPack.BuffID = buffID
    clientPack.RelatedSkillID = relatedSkillID
    turnFight.addBatPack(clientPack)
    return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnBuffs/BuffAtkType_1001.py
New file
@@ -0,0 +1,34 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
##@package Skill.TurnBuffs.BuffAtk_1001
#
# @todo:buff持续攻击
# @author hxp
# @date 2025-08-19
# @version 1.0
#
# 详细描述: buff持续攻击
#
#-------------------------------------------------------------------------------
#"""Version = 2025-08-19 16:00"""
#-------------------------------------------------------------------------------
import TurnSkill
def CalcBuffValue(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]
def DoBuffProcess(turnFight, batObj, curBuff):
    ## 执行单次逻辑
    hurtValue = curBuff.GetBuffValue(0) # 单次伤害
    hurtTypes = curBuff.GetBuffValue(1)
    TurnSkill.DoDOTAttack(turnFight, batObj, curBuff, hurtValue, hurtTypes)
    return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnPassive.py
@@ -17,9 +17,143 @@
import GameWorld
import PassiveTrigger
import ChConfig
GameWorld.ImportAll("Script\\Skill\\", "PassiveTrigger")
def RefreshPassive(batObj):
    return
    ''' 刷新被动效果,一般可能存在于技能或buff中
    '''
    passiveEffMgr = batObj.GetPassiveEffManager()
    skillEffInfo = passiveEffMgr.RefreshSkillPassiveEffect()
    buffEffInfo = passiveEffMgr.RefreshBuffPassiveEffect()
    skillEffInfo and GameWorld.DebugLog("    被动技能效果: %s" % skillEffInfo)
    buffEffInfo and GameWorld.DebugLog("    被动Buff效果: %s" % buffEffInfo)
    return
def OnTriggerPassiveEffect(turnFight, batObj, triggerType, connSkill=None):
    ''' 触发被动效果,可能触发技能、buff,需根据优先级触发
    '''
    passiveEffMgr = batObj.GetPassiveEffManager()
    effInfoList = passiveEffMgr.GetPassiveEffByTrigger(triggerType, connSkill=connSkill)
    if not effInfoList:
        return
    # [["skill/buff", skillID/buffID, effIDList], ...]
    GameWorld.DebugLog("触发被动: triggerType=%s,objID=%s,%s" % (triggerType, batObj.GetID(), effInfoList))
    for effInfo in effInfoList:
        sign = effInfo[0]
        if sign == "skill":
            skillID, effIDList = effInfo[1:]
            __doTriggerPassiveEffectBySkill(turnFight, batObj, skillID, effIDList, connSkill)
        elif sign == "buff":
            buffID, effIDList = effInfo[1:]
            __doTriggerPassiveEffectByBuff(turnFight, batObj, buffID, effIDList, connSkill)
    return
def __doTriggerPassiveEffectBySkill(turnFight, batObj, skillID, effIDList, connSkill=None):
    return
def __doTriggerPassiveEffectByBuff(turnFight, batObj, buffID, effIDList, connSkill=None):
    buffMgr = batObj.GetBuffManager()
    curBuff = buffMgr.GetBuff(buffID)
    if not curBuff:
        return
    skillData = curBuff.GetSkillData()
    for effID in effIDList:
        curEffect = skillData.GetEffectByID(effID)
        if not curEffect:
            continue
        pyName = "PassiveEff_%s" % effID
        callFunc = GameWorld.GetExecFunc(PassiveTrigger, "%s.%s" % (pyName, "DoBuffEffectLogic"))
        if not callFunc:
            continue
        callFunc(turnFight, batObj, curBuff, curEffect, connSkill)
    return
def GetTriggerPassiveValue(batObj, triggerType, tagObj=None, useSkill=None):
    ''' 获取触发被动的值,一般用于某种条件下才会产生的值,如xx情况下属性变化 或 xx情况下是否发生什么
    @return: 触发的值,0-没有触发或本身触发的值为0;大于0-触发的具体值
    '''
    return 0
#    attacker = FindRealAttacker(attacker)
#    if not attacker:
#        return 0
#
#    stopPassiveSkill = False   # 被动技能不能再触发被动技能,但可以触发天赋技能
#    if useSkill and SkillCommon.isPassiveSkill(useSkill) and isStopPassiveSkill:
#        #GameWorld.DebugLog("被动技能不能再次触发被动技能")
#        #return 0
#        if not PassPassiveLimit(useSkill):
#            stopPassiveSkill = True
#
#
#    passiveEff = GetPassiveEffManager().GetPassiveEff(attacker)
#    if not passiveEff:
#        return 0
#    buffDict = passiveEff.GetBuffsByTriggerType(triggerType)
#    if not buffDict:
#        return 0
#
#    # 当前战斗关系 pvp pve
#    battleRelationType = AttackCommon.GetBattleRelationType(attacker, defender)
#    if not AttackCommon.CheckBattleRelationType(attacker, defender, useSkill, battleRelationType):
#        return 0
#
#    useSkillID = useSkill.GetSkillID() if useSkill else 0
#    #tick = GameWorld.GetGameWorld().GetTick()
#    curValue = 0
#
#    for skillID, effectList in buffDict.items():
#        if skillID == useSkillID:
#            continue
#        curSkill = GameWorld.GetGameData().GetSkillBySkillID(skillID)
#        if not curSkill:
#            continue
#
#        if not IsValidPassiveSkill(curSkill):
#            continue
#
#        triggerCount = 0 # 成功触发次数
#        for effectInfo in effectList:
#            if stopPassiveSkill and curSkill.GetFuncType() != ChConfig.Def_SkillFuncType_GiftSkill:
#                # 只有天赋才可以再次被触发
#                continue
#            passiveEffect = effectInfo[0]
#            # 被动触发的技能
#            pyName = "PassiveBuff_%s"%passiveEffect.GetEffectID()
#
#            callFunc = GameWorld.GetExecFunc(PassiveBuff, "%s.%s" % (pyName, "CheckCanHappen"))
#            if not callFunc:
#                continue
#
#            # 条件不满足
#            if not callFunc(attacker, defender, passiveEffect, skillID, useSkill=useSkill, ownerID=effectInfo[1], ownerType=effectInfo[2]):
#                continue
#
#            callFunc = GameWorld.GetExecFunc(PassiveBuff, "%s.%s" % (pyName, "GetValue"))
#            if callFunc is None:
#                continue
#
#            # 如被动技能:千幻冥炎真实伤害从2变4倍
#            #curValue += GetPassiveSkillValueByTriggerType(attacker, defender, curSkill, ChConfig.TriggerType_PassiveBuffValue)
#            value = callFunc(attacker, defender, passiveEffect)
#            if triggerType in TriggerValueMaxList:
#                curValue = max(curValue, value) # 取最大值
#            elif triggerType in TriggerValueMinList:
#                if not curValue:
#                    curValue = value
#                elif value > 0:
#                    curValue = min(curValue, value) # 取最小值
#            else:
#                curValue += value
#
#            triggerCount += 1
#
#        if triggerCount:
#            OnTriggerBuffDel(attacker, curSkill, triggerCount)
#
#    return curValue
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnSkill.py
@@ -65,14 +65,19 @@
        tagAffect = useSkill.GetTagAffect()
        tagCount = useSkill.GetTagCount()
        tagObjList = GetSkillTags(turnFight, curBatObj, tagAim, tagFriendly, tagAffect, tagCount)
    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))
        rate = useSkill.GetHappenRate()
        if rate and rate != ChConfig.Def_MaxRateValue:
            for tagObj in tagObjList[::-1]:
                if not GameWorld.CanHappen(rate, ChConfig.Def_MaxRateValue):
                    tagObjList.remove(tagObj)
    if not tagObjList:
        # 可扩展其他目标选择,如复活技能没有死亡单位时则使用另外的效果
        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))
    # 以下为技能可以使用的处理,之后的逻辑默认技能使用成功
    
    poolMgr = ObjPool.GetPoolMgr()
@@ -117,10 +122,7 @@
        turnFight.addBatPack(clientPack)
        
    # 最后重置、回收对象
    useSkill.SetTagObjList([])
    useSkill.SetBySkill(None) # 需重置,防止被误回收
    useSkill.SetIsEnhanceSkill(False)
    useSkill.ClearHurtObj()
    useSkill.ResetUseRec()
    if usePoolSkill:
        poolMgr.release(useSkill)
    return True
@@ -311,9 +313,19 @@
    if atkType == 5:
        return
    
    # 6 怒气增减偷
    # 怒气增
    if atkType == 6:
        SkillModule_6(turnFight, curBatObj, useSkill)
        SkillModule_6(turnFight, curBatObj, useSkill, "Increase")
        return
    # 怒气减
    if atkType == 7:
        SkillModule_6(turnFight, curBatObj, useSkill, "Reduce")
        return
    # 怒气偷
    if atkType == 8:
        SkillModule_6(turnFight, curBatObj, useSkill, "Steal")
        return
    
    return
@@ -357,7 +369,7 @@
    DoAttackResult(turnFight, curBatObj, useSkill)
    return
def SkillModule_6(turnFight, curBatObj, useSkill):
def SkillModule_6(turnFight, curBatObj, useSkill, opType):
    ## 怒气增减偷
    
    curID = curBatObj.GetID()
@@ -365,24 +377,22 @@
    bySkill = useSkill.GetBySkill()
    relatedSkillID = bySkill.GetSkillID() if bySkill else 0
    
    angerPer, angerValue, calcType = 0, 0, 0
    effect = SkillCommon.GetSkillEffectByEffectID(useSkill, ChConfig.Def_Skill_Effect_Anger)
    if effect:
        angerPer = effect.GetEffectValue(0)
        angerValue = effect.GetEffectValue(1)
        calcType = effect.GetEffectValue(2)
    #cureType = useSkill.GetCalcType()
    skillPer = useSkill.GetSkillPer()
    skillValue = useSkill.GetSkillValue()
    xpMax = IpyGameDataPY.GetFuncCfg("AngerXP", 2)
    calcValue = int(xpMax * angerPer / 10000.0 + angerValue)
    calcValue = int(xpMax * skillPer / 10000.0 + skillValue)
    attrID = ChConfig.AttrID_XP
    
    GameWorld.DebugLog("怒气增减偷: curID=%s,calcValue=%s,skillID=%s,angerPer=%s,angerValue=%s,calcType=%s,relatedSkillID=%s"
                       % (curID, calcValue, skillID, angerPer, angerValue, calcType, relatedSkillID))
    GameWorld.DebugLog("怒气%s: curID=%s,calcValue=%s,skillID=%s,skillPer=%s,skillValue=%s,relatedSkillID=%s"
                       % (opType, curID, calcValue, skillID, skillPer, skillValue, relatedSkillID))
    curStealTotal = 0
    for tagBatObj in useSkill.GetTagObjList():
        
        tagID = tagBatObj.GetID()
        # 减
        if calcType == 2:
        if opType == "Reduce":
            diffType = 0
            tagXP = tagBatObj.GetXP()
            diffValue = min(tagXP, calcValue) # 取较小值,不足时剩多少减多少
@@ -392,7 +402,7 @@
            Sync_PropertyRefreshView(turnFight, tagBatObj, attrID, updValue, diffValue, diffType, skillID, relatedSkillID)
            
        # ͵
        elif calcType == 3:
        elif opType == "Steal":
            diffType = 0
            tagXP = tagBatObj.GetXP()
            diffValue = min(tagXP, calcValue) # 取较小值,不足时剩多少减多少
@@ -419,14 +429,14 @@
        diffValue = curStealTotal
        updValue = curXP + diffValue
        curBatObj.SetXP(updValue, False)
        GameWorld.DebugLog("    偷总怒气: curID=%s,curStealTotal=%s,curXP=%s,updXP=%s" % (curID, curStealTotal, curXP, updValue))
        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):
    '''执行攻击结果,技能、buff通用
    '''执行攻击结果
    @param curBatObj: 施法方或buff归属方
    '''
    
@@ -437,7 +447,10 @@
            
    skillID = useSkill.GetSkillID()
    curBatObj.AddSkillUseCnt(skillID)
    if useSkill.GetCoolDownTime():
        useSkill.SetCalcTime(turnFight.getTimeline())
        useSkill.SetRemainTime(useSkill.GetCoolDownTime())
    # 需先通知伤血 - 前端按顺序优先表现技能释放内容,
    isEnhanceSkill = useSkill.GetIsEnhanceSkill()
    if not isEnhanceSkill or len(useSkill.GetHurtObjList()):
@@ -446,31 +459,43 @@
        __doCostZhanchui(turnFight, curBatObj, useSkill)
        __doSkillUserAnger(turnFight, curBatObj, useSkill)
        
    DoBeAttackOver(turnFight, curBatObj, useSkill)
    # 最后处理反击 或 连击
    return
def DoBeAttackOver(turnFight, curBatObj, useSkill):
    '''被攻击结果
    @param curBatObj: 施法方或buff归属方
    '''
    isTurnNormalSkill = SkillCommon.isTurnNormalSkill(useSkill)
    isAngerSkill = SkillCommon.isAngerSkill(useSkill)
    # 统计死亡
    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):
            if hurtObj.GetObjID() == tagID and not hurtObj.HaveHurtType(ChConfig.HurtTYpe_Recovery) and (isTurnNormalSkill or isAngerSkill):
                __doSkillHurtAnger(tagObj, hurtObj.GetLostHP(), useSkill)
        if tagObj.GetHP() <= 0:
            killObjIDList.append(tagID)
            TurnAttack.SetObjKilled(turnFight, tagObj, curBatObj, useSkill)
    if curBatObj.GetHP() <= 0:
    if curBatObj and curBatObj.GetHP() <= 0:
        TurnAttack.SetObjKilled(turnFight, curBatObj)
        
    # 结算副本相关的攻击结果,仅主动发起玩家阵容武将触发
    curPlayer = turnFight.curPlayer
    if curPlayer and curBatObj.GetOwnerID() == curPlayer.GetPlayerID():
    if curPlayer and curBatObj and curBatObj.GetOwnerID() == curPlayer.GetPlayerID():
        FBLogic.OnPlayerLineupAttackResult(curPlayer, curBatObj, killObjIDList, useSkill, turnFight.mapID, turnFight.funcLineID)
        
    # 额外触发技能
    __doUseEnhanceSkill(turnFight, curBatObj, useSkill)
    
    # 循环触发被动,待扩展
    # 最后处理反击 或 连击
    
    return
@@ -490,12 +515,12 @@
    
    costZhanchui = 0
    batType = useSkill.GetBatType()
    if batType != ChConfig.TurnBattleType_Normal:
        # 暂定仅常规主动点击行为的需要扣除战锤(与前端手动战斗点击的触发点同步),被动触发的暂定不扣
        return
    if SkillCommon.isAngerSkill(useSkill):
        costZhanchui = IpyGameDataPY.GetFuncCfg("ZhanchuiCost", 2)
    elif batType == ChConfig.TurnBattleType_Combo:
        costZhanchui = IpyGameDataPY.GetFuncCfg("ZhanchuiCost", 3)
    elif batType == ChConfig.TurnBattleType_AtkBack:
        costZhanchui = IpyGameDataPY.GetFuncCfg("ZhanchuiCost", 4)
    elif SkillCommon.isTurnNormalSkill(useSkill):
        costZhanchui = IpyGameDataPY.GetFuncCfg("ZhanchuiCost", 1)
        
@@ -546,8 +571,10 @@
    return
def __doUseEnhanceSkill(turnFight, curBatObj, useSkill):
    if not curBatObj:
        return
    if useSkill.GetIsEnhanceSkill():
        GameWorld.DebugLog("自身为额外触发的技能不再触发额外技能! skillID=%s" % useSkill.GetSkillID())
        #GameWorld.DebugLog("自身为额外触发的技能不再触发额外技能! skillID=%s" % useSkill.GetSkillID())
        return
    enhanceSkillIDList = useSkill.GetEnhanceSkillList()
    if not enhanceSkillIDList:
@@ -564,7 +591,7 @@
        if enhanceSkillData.GetTagAim() == ChConfig.SkillTagAim_MainSkill:
            GameWorld.DebugLog("    额外触发技能,继承主技能目标! enhanceSkillID=%s" % enhanceSkillID)
            # 额外触发的技能直接在外层检查概率,如果都没有触发则不需要再处理
            enhanceRate = enhanceSkillData.GetHappenRate()
            enhanceRate = enhanceSkillData.GetHappenRate()
            enchanceTagObjList = []
            for tagObj in tagObjList:
                tagID = tagObj.GetID()
@@ -605,21 +632,11 @@
    atkObj = attacker
    atkID = atkObj.GetID()
    defID = defObj.GetID()
    skillID = curSkill.GetSkillID()
    hurtObj = curSkill.AddHurtObj(defID)
    
    #检查是否几率触发,附加技能、被动触发的外层已检查过概率,不重复检查
    if not (curSkill.GetIsEnhanceSkill() or SkillCommon.isPassiveTriggerSkill(curSkill)): # 额外触发的技能概率在触发时判断
        rate = curSkill.GetHappenRate()
        if rate and rate != ChConfig.Def_MaxRateValue and not GameWorld.CanHappen(rate, ChConfig.Def_MaxRateValue):
            #GameWorld.Log('检查是否几率触发 = %s失败 = %s'%(rate, useSkill.GetSkillName()))
            #放这里,兼容群攻时如果该技能是有概率的,则每个目标单独判断
            hurtObj.AddHurtType(ChConfig.HurtType_Fail)
            hurtObj.SetCurHP(defObj.GetHP())
            return hurtObj
    effect = SkillCommon.GetSkillEffectByEffectID(curSkill, ChConfig.Def_Skill_Effect_Attack)
    atkSkillValue = 0
    atkSkillPer = effect.GetEffectValue(0) if effect else 0
    atkSkillPer = curSkill.GetSkillPer()
    atkSkillValue = curSkill.GetSkillValue()
    
    dHP = defObj.GetHP()                # 防守方当前血量
    dMaxHP = defObj.GetMaxHP()          # 防守方最大血量
@@ -653,11 +670,11 @@
    #吸血
    CalcSuckBlood(atkObj, defObj, hurtObj, curSkill)
    
    TurnAttack.AddTurnObjHurtValue(atkObj, defObj, hurtValue, lostHP, curSkill)
    return hurtObj
    TurnAttack.AddTurnObjHurtValue(atkObj, defObj, hurtValue, lostHP, skillID)
    return
def CalcHurtHP(atkObj, defObj, curSkill, atkSkillValue, atkSkillPer, **atkwargs):
    '''计算伤害
def CalcHurtHP(atkObj, defObj, curSkill, atkSkillValue, atkSkillPer, **kwargs):
    '''计算伤害,默认按攻击计算
    '''
    pmType = GetPMType(atkObj, curSkill)
    ignoreDef = IsIgnoreDef(curSkill)
@@ -669,7 +686,7 @@
    isTurnNormalSkill = SkillCommon.isTurnNormalSkill(curSkill)
    isAngerSkill = SkillCommon.isAngerSkill(curSkill)
    isAtkbackSkill = SkillCommon.isAtkbackSkill(curSkill)
    isDot = ("damageoftime" in kwargs)
    angerOverflow = 0 # 怒气溢出值
    
    mustHit = False
@@ -690,7 +707,11 @@
        
    hurtTypes = pow(2, ChConfig.HurtType_Normal)
    
    #calcType = curSkill.GetCalcType() 目前暂时按攻击算伤害,之后可以扩展其他
    isSuperHit = False # 是否暴击
    if isDot:
        isSuperHit = False
    if isSuperHit:
        hurtTypes |= pow(2, ChConfig.HurtType_SuperHit)
        
@@ -741,15 +762,13 @@
    aFinalDamPer /= 10000.0
    dFinalDamPerDef /= 10000.0
    
    GameWorld.DebugLog("伤血计算: atkID=%s,defID=%s,skillID=%s,atkSkillPer=%s,aAtk=%s,dDef=%s,dHP=%s,hurtTypes=%s" 
                       % (atkID, defID, skillID, atkSkillPer, aAtk, dDef, dHP, hurtTypes))
    
    if "hurtFormulaKey" in atkwargs:
        aBurnValue = atkwargs.get('burnValue', 0)
        aBurnPer = atkwargs.get('burnPer', 0)
        hurtFormulaKey = atkwargs.get('hurtFormulaKey', None)
    # 持续性伤害
    if isDot:
        hurtValue = eval(IpyGameDataPY.GetFuncCompileCfg("DOTFormula", 1))
        GameWorld.DebugLog("    持续技能伤害=%s" % (hurtValue))
    elif isTurnNormalSkill:
        hurtValue = eval(IpyGameDataPY.GetFuncCompileCfg("HurtFormula", 1))
        GameWorld.DebugLog("    普攻技能伤害=%s" % (hurtValue))
@@ -812,9 +831,9 @@
    ''' 计算治疗值
    '''
    cureBaseValue = 0     #治疗基础值
    effect = SkillCommon.GetSkillEffectByEffectID(curSkill, ChConfig.Def_Skill_Effect_Cure)
    skillPer = effect.GetEffectValue(0) if effect else 0
    cureType = effect.GetEffectValue(1) if effect else 0
    cureType = curSkill.GetCalcType()
    skillPer = curSkill.GetSkillPer()
    #skillValue = curSkill.GetSkillValue()
    
    #获得基础治疗值
    if cureType == ChConfig.Def_Cure_Attack:
@@ -838,7 +857,7 @@
        #curePer += GameObj.GetCurePer(userObj)
        #if enemyObj:
        #    cureDefPer += GameObj.GetCureDefPer(enemyObj)
    skillPer /= float(ChConfig.Def_MaxRateValue)
    curePer /= float(ChConfig.Def_MaxRateValue)
    cureDefPer /= float(ChConfig.Def_MaxRateValue)
@@ -854,6 +873,52 @@
    GameWorld.DebugLog("计算治疗值(%s):skillID=%s,cureType=%s,baseValue=%s,skillPer=%s,curePer=%s,cureDefPer=%s,angerOverflow=%s" 
                       % (cureHP, curSkill.GetSkillID(), cureType, baseValue, skillPer, curePer, cureDefPer, angerOverflow))
    return cureHP
def DoDOTAttack(turnFight, batObj, curBuff, hurtValue, hurtTypes):
    ## 执行单次dot逻辑
    skillID = curBuff.GetSkillID()
    skillIpyData = IpyGameDataPY.GetIpyGameData("Skill", skillID)
    if not skillIpyData:
        return
    buffID = curBuff.GetBuffID()
    ownerID = curBuff.GetOwnerID()
    buffOwner = BattleObj.GetBatObjMgr().getBatObj(ownerID) # 攻击方
    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()))
    poolMgr = ObjPool.GetPoolMgr()
    useSkill = poolMgr.acquire(BattleObj.PySkill, skillIpyData)
    useSkill.SetTagObjList(tagObjList)
    useSkill.ClearHurtObj()
    remainHP = max(0, dHP - hurtValue) # 剩余血量
    lostHP = dHP - remainHP # 实际掉血量
    defObj.SetHP(remainHP)
    hurtObj = useSkill.AddHurtObj(defID)
    hurtObj.SetHurtTypes(hurtTypes)
    hurtObj.SetHurtHP(hurtValue)
    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)
    useSkill.ResetUseRec()
    poolMgr.release(useSkill)
    return
def Sync_UseSkill(turnFight, curBatObj, useSkill):
    ## 通知释放技能
@@ -881,13 +946,14 @@
    turnFight.addBatPack(clientPack)
    return
def Sync_PropertyRefreshView(turnFight, curBatObj, attrID, value, diffValue, diffType=0, skillID=0, relatedSkillID=0):
def Sync_PropertyRefreshView(turnFight, curBatObj, attrID, value, diffValue, diffType=0, skillID=0, relatedSkillID=0, hurtTypes=0):
    '''通知对象属性刷新展示B418
    @param attrID: 通知变化的属性ID
    @param diffValue: 变化值
    @param diffType: 变化类型,0-减少;1-增加
    @param skillID: 使用的技能表ID,即哪个技能的效果
    @param relatedSkillID: 关联的技能ID,一般是主技能ID,非主技能额外触发的为0
    @param hurtTypes: 飘字类型汇总,支持多种类型并存,如无视防御且暴击同时被格挡,二进制或运算最终值;0-失败;1-普通;2-回血;5-格挡;6-无视防御;7-暴击;9-闪避
    '''
    if attrID not in ChConfig.CDBRefresh_AttrIDDict:
        return
@@ -896,6 +962,7 @@
    clientPack = poolMgr.acquire(ChPyNetSendPack.tagSCObjPropertyRefreshView)
    clientPack.ObjID = curBatObj.GetID()
    clientPack.RefreshType = refreshType
    clientPack.AttackTypes = hurtTypes
    if isBig:
        clientPack.Value = value % ShareDefine.Def_PerPointValue
        clientPack.ValueEx = value / ShareDefine.Def_PerPointValue