From 5b34b20562dab2b5e82b90be18285345057c12ce Mon Sep 17 00:00:00 2001
From: hxp <ale99527@vip.qq.com>
Date: 星期二, 19 八月 2025 15:52:15 +0800
Subject: [PATCH] 129 【战斗】战斗系统-服务端(优化技能表字段,增加技能及buff常用配置字段;优化被动触发及效果配置方式;技能冷却、buff持续时长计算支持;持续性buff效果结算支持;pve默认玩家先手;战锤消耗仅普攻怒技消耗;)

---
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/PassiveTrigger/PassiveEff_5001.py |   47 ++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py                      |    4 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/TurnAttack.py                    |  289 ++++++++----
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnSkill.py                      |  195 +++++--
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/AttackLogic/AttackCommon.py      |    2 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnBuff.py                       |  185 +++++--
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/BattleObj.py                     |  252 +++++++++-
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py                        |   88 ++-
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnPassive.py                    |  138 +++++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnBuffs/BuffAtkType_1001.py     |   34 +
 PySysDB/PySysDBPY.h                                                                                         |   24 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/GameSkills/SkillCommon.py         |   14 
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py                             |   55 +-
 13 files changed, 986 insertions(+), 341 deletions(-)

diff --git a/PySysDB/PySysDBPY.h b/PySysDB/PySysDBPY.h
index cdae0ca..f6ad6a6 100644
--- a/PySysDB/PySysDBPY.h
+++ b/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;	//技能战斗力
 };
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/AttackLogic/AttackCommon.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/AttackLogic/AttackCommon.py
index 0774adf..76ed1de 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/AttackLogic/AttackCommon.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/AttackLogic/AttackCommon.py
@@ -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)
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/BattleObj.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/BattleObj.py
index cd9560f..f546b05 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/BattleObj.py
+++ b/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):
         ## 可否被攻击
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/TurnAttack.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/TurnAttack.py
index 4e600cb..31df10d 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/TurnAttack.py
+++ b/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()
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
index 9abacf7..4e35cc3 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
+++ b/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的某个状态触发技能
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
index ab67681..5fabeab 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py
+++ b/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,
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
index 833d812..65817b5 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
+++ b/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():
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/GameSkills/SkillCommon.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/GameSkills/SkillCommon.py
index 6276416..f04ff00 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/GameSkills/SkillCommon.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/GameSkills/SkillCommon.py
@@ -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:
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/PassiveTrigger/PassiveEff_5001.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/PassiveTrigger/PassiveEff_5001.py
new file mode 100644
index 0000000..c5e745b
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/PassiveTrigger/PassiveEff_5001.py
@@ -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
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnBuff.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnBuff.py
index adfc47f..27ddea2 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnBuff.py
+++ b/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
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnBuffs/BuffAtkType_1001.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnBuffs/BuffAtkType_1001.py
new file mode 100644
index 0000000..5cdb4f1
--- /dev/null
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnBuffs/BuffAtkType_1001.py
@@ -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
+
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnPassive.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnPassive.py
index 24321a0..c1e7a9b 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnPassive.py
+++ b/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
\ No newline at end of file
+    ''' 刷新被动效果,一般可能存在于技能或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
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnSkill.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnSkill.py
index b41a26b..b35f747 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnSkill.py
+++ b/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

--
Gitblit v1.8.0