129 【战斗】战斗系统-服务端(朱恒技能;增加效果5007-偷取目标身上增益类型buff;增加GM命令TurnFight-可设置主线战斗中战斗对象相关属性、击杀等;修复技能对象释放bug;)
4个文件已修改
2个文件已添加
343 ■■■■■ 已修改文件
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/BattleObj.py 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/TurnFight.py 179 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ObjPool.py 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/PassiveTrigger/PassiveEff_5007.py 59 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnBuff.py 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnSkill.py 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/BattleObj.py
@@ -37,6 +37,11 @@
        self._AffectBuffDict = {} # 被动buff {(触发方式, 有效来源):{buffID:[effID, ...], ...}, ...}
        return
    
    def onRelease(self):
        ## 回收前处理,主要处理一些其他不需要释放的对象池对象,防止被连同误回收
        self._batObj = None
        return
    def GetPassiveEffByTrigger(self, triggerWay, connSkill=None, connSkillTypeID=0, connBuff=None):
        '''获取可触发的效果列表,技能跟buff根据触发优先级按顺序触发,优先级越高越先执行,相同时技能优先
                        优先级之后有需要再扩展
@@ -226,6 +231,10 @@
        self.Clear()
        return
    
    def onRelease(self):
        ## 回收前处理,主要处理一些其他不需要释放的对象池对象,防止被连同误回收
        return
    def Clear(self):
        self._objID = 0
        self._hurtTypes = 0 # 本次伤血类型,如闪避、暴击、格挡等,通过二进制或运算得到最终值,支持多种同时出现,如暴击的同时被格挡
@@ -271,6 +280,10 @@
        #self._triggerParams = triggerParams if triggerParams else []
        return
    
    def onRelease(self):
        ## 回收前处理,主要处理一些其他不需要释放的对象池对象,防止被连同误回收
        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)
@@ -294,6 +307,10 @@
            effect = ObjPool.GetPoolMgr().acquire(SkillEffect, effID, values, triggerWay, triggerSrc)
            self._effList.append(effect)
            self._effDict[(effID, triggerWay)] = effect
        return
    def onRelease(self):
        ## 回收前处理,主要处理一些其他不需要释放的对象池对象,防止被连同误回收
        return
    
    def GetIpyData(self): return self._ipyData
@@ -345,6 +362,10 @@
        self._value3 = 0
        return
    
    def onRelease(self):
        ## 回收前处理,主要处理一些其他不需要释放的对象池对象,防止被连同误回收
        return
    def GetSkillData(self): return self._skillData
    def GetSkillID(self): return self._skillData.GetSkillID()
    def GetBuffID(self): return self._buffID
@@ -383,6 +404,11 @@
        self._buffStateDict = {} # buff影响的状态 {state:[buffID, ...], ...}
        self._buffID = 0 # 该对象的唯一buffID,递增,不同对象buffID可重复,buffID非skillID,不同buffID的skillID可能一样
        # 该项目设定同一个对象可能同时存在多个相同skillID的buff,独立算CD
        return
    def onRelease(self):
        ## 回收前处理,主要处理一些其他不需要释放的对象池对象,防止被连同误回收
        self._batObj = None
        return
    
    def ClearBuff(self):
@@ -529,7 +555,14 @@
        self._parryTagIDDict = {} # 单次连续连击中对方已格挡次数 {tagID:parryNum, ...}
        return
    
    def onRelease(self):
        ## 回收前处理,主要处理一些其他不需要释放的对象池对象,防止被连同误回收
        self.ResetUseRec()
        return
    def ResetUseRec(self):
        ## 重置技能使用记录
        ## 注:有用到对象池相关对象的一定要重置,不然再回收技能对象时会连同该技能下的所有用到的对象池对象一并回收,导致后续使用对象错误
        self._batType = 0
        self._tagObjList = []
        self._killObjList = []
@@ -540,6 +573,7 @@
        return
    
    def GetObjID(self): return self._objID
    def GetSkillData(self): return self._skillData
    def GetSkillID(self): return self._skillData.GetSkillID()
    def GetSkillTypeID(self): return self._skillData.GetSkillTypeID()
    def GetSkillLV(self): return self._skillData.GetSkillLV()
@@ -654,6 +688,11 @@
        self._skillDict = {} # {skillID:PySkill, ...}
        return
    
    def onRelease(self):
        ## 回收前处理,主要处理一些其他不需要释放的对象池对象,防止被连同误回收
        self._batObj = None
        return
    def SkillReset(self):
        poolMgr = ObjPool.GetPoolMgr()
        for skill in self._skillList:
@@ -743,6 +782,10 @@
        self.cureStat = 0 # 治疗统计
        return
    
    def onRelease(self):
        ## 回收前处理,主要处理一些其他不需要释放的对象池对象,防止被连同误回收
        return
    def InitBatAttr(self, initAttrDict, initXP=0):
        '''初始化战斗属性
        @param initAttrDict: 已经算好的在阵容中的属性,包含羁绊、阵容属性等,战斗中只要计算buff属性即可
@@ -775,6 +818,20 @@
            self._passiveEffMgr.RefreshSkillPassiveEffect()
        return
    
    def GMSetBatAttr(self, attrID, attrValue):
        ## GM设置战斗属性
        self._initAttrDict[attrID] = attrValue # 需要同步设置初始化属性,防止刷属性后被重置
        if attrID == ChConfig.AttrID_HP:
            self.SetHP(attrValue, True)
            if attrValue > self.GetMaxHP():
                self._initAttrDict[ChConfig.AttrID_MaxHP] = attrValue
                self.SetMaxHP(attrValue, True)
        elif attrID == ChConfig.AttrID_XP:
            self.SetXP(attrValue, True)
        else:
            self.SetBatAttrValue(attrID, attrValue)
        return
    def ResetBattleEffect(self):
        self._batAttrDict = {}
        self._batAttrDict.update(self._initAttrDict)
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/TurnFight.py
New file
@@ -0,0 +1,179 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
##@package GM.Commands.TurnFight
#
# @todo:回合战斗
# @author hxp
# @date 2025-09-25
# @version 1.0
#
# 详细描述: 回合战斗
#
#-------------------------------------------------------------------------------
#"""Version = 2025-09-25 17:30"""
#-------------------------------------------------------------------------------
import ChConfig
import GameWorld
import ChPyNetSendPack
import NetPackCommon
import TurnAttack
import BattleObj
FactionList = [1, 2]
## GM命令执行入口
#  @param curPlayer 当前玩家
#  @param msgList 参数列表
#  @return None
#  @remarks 函数详细说明.
def OnExec(curPlayer, msgList):
    if not msgList:
        GameWorld.DebugAnswer(curPlayer, "设置属性: TurnFight a 属性ID 值 [阵营 位置] ")
        GameWorld.DebugAnswer(curPlayer, "击杀目标: TurnFight k 阵营 [位置 ...] ")
        GameWorld.DebugAnswer(curPlayer, "输出明细: TurnFight p [阵营 位置] ")
        GameWorld.DebugAnswer(curPlayer, "阵营: 1-左边;2-右边")
        GameWorld.DebugAnswer(curPlayer, "位置: 1~6号位")
        GameWorld.DebugAnswer(curPlayer, "属性ID: 6-攻,7-防,8-HPMax,9-HP,12-怒")
        return
    value = msgList[0]
    if value == "a":
        __doSetAttr(curPlayer, msgList)
    elif value == "k":
        __doKillObj(curPlayer, msgList)
    elif value == "p":
        __printInfo(curPlayer, msgList)
    return
def __doSetAttr(curPlayer, msgList):
    ## 设置属性
    attrID = msgList[1] if len(msgList) > 1 else 1
    attrValue = msgList[2] if len(msgList) > 2 else 1
    faction = msgList[3] if len(msgList) > 3 else 1
    posNum = msgList[4] if len(msgList) > 4 else 1
    if faction not in FactionList:
        GameWorld.DebugAnswer(curPlayer, "阵营: 1-左边;2-右边")
        return
    mainFightMgr = TurnAttack.GetMainFightMgr(curPlayer)
    turnFight = mainFightMgr.turnFight
    if not turnFight.isInFight():
        GameWorld.DebugAnswer(curPlayer, "主线非战斗中")
        return
    batFaction = turnFight.getBatFaction(faction)
    batLineup = batFaction.getBatlineup(1)
    objID = batLineup.posObjIDDict.get(posNum)
    batObj = None
    batObjMgr = BattleObj.GetBatObjMgr()
    if objID:
        batObj = batObjMgr.getBatObj(objID)
    if not batObj:
        GameWorld.DebugAnswer(curPlayer, "不存在该战斗对象:阵营:%s,位置:%s" % (faction, posNum))
        return
    if not batObj.IsAlive():
        GameWorld.DebugAnswer(curPlayer, "该对象已被击杀:阵营:%s,位置:%s" % (faction, posNum))
        return
    if attrID not in ChConfig.AttrIDList:
        GameWorld.DebugAnswer(curPlayer, "不存在该属性ID:%s" % (attrID))
        return
    objName = TurnAttack.GetObjName(batObj)
    GameWorld.DebugAnswer(curPlayer, "%s" % (objName))
    batObj.GMSetBatAttr(attrID, attrValue)
    if attrID == ChConfig.AttrID_HP:
        GameWorld.DebugAnswer(curPlayer, "设置生命:%s/%s" % (batObj.GetHP(), batObj.GetMaxHP()))
    elif attrID == ChConfig.AttrID_XP:
        GameWorld.DebugAnswer(curPlayer, "设置怒气:%s" % (batObj.GetXP()))
    else:
        GameWorld.DebugAnswer(curPlayer, "设置属性ID:%s,V=%s" % (attrID, attrValue))
    return
def __doKillObj(curPlayer, msgList):
    faction = msgList[1] if len(msgList) > 1 else 2
    posNumList = msgList[2:]
    if faction not in FactionList:
        GameWorld.DebugAnswer(curPlayer, "阵营: 1-左边;2-右边")
        return
    mainFightMgr = TurnAttack.GetMainFightMgr(curPlayer)
    turnFight = mainFightMgr.turnFight
    if not turnFight.isInFight():
        GameWorld.DebugAnswer(curPlayer, "主线非战斗中")
        return
    clientPack = ChPyNetSendPack.tagSCTurnFightReportSign()
    clientPack.Sign = 0
    batObjMgr = BattleObj.GetBatObjMgr()
    batFaction = turnFight.getBatFaction(faction)
    batLineup = batFaction.getBatlineup(1)
    for posNum in posNumList:
        objID = batLineup.posObjIDDict.get(posNum)
        if not objID:
            continue
        batObj = batObjMgr.getBatObj(objID)
        if not batObj:
            GameWorld.DebugAnswer(curPlayer, "不存在该战斗对象:阵营:%s,位置:%s" % (faction, posNum))
            continue
        if not batObj.IsAlive():
            GameWorld.DebugAnswer(curPlayer, "该对象已被击杀:阵营:%s,位置:%s" % (faction, posNum))
            continue
        GameWorld.DebugAnswer(curPlayer, "击杀: %s" % TurnAttack.GetObjName(batObj))
        TurnAttack.SetObjKilled(turnFight, batObj)
    turnFight.checkOverByKilled()
    clientPack.Sign = 1
    NetPackCommon.SendFakePack(curPlayer, clientPack)
    return
def __printInfo(curPlayer, msgList):
    ## 输出信息
    faction = msgList[1] if len(msgList) > 1 else 0
    posNum = msgList[2] if len(msgList) > 2 else 0
    factionList = [faction] if faction else FactionList
    posNumList = [posNum] if posNum else range(1, 1 + 6)
    mainFightMgr = TurnAttack.GetMainFightMgr(curPlayer)
    turnFight = mainFightMgr.turnFight
    if not turnFight.isInFight():
        GameWorld.DebugAnswer(curPlayer, "主线非战斗中")
        return
    batObjMgr = BattleObj.GetBatObjMgr()
    for faction in factionList:
        if faction not in FactionList:
            GameWorld.DebugAnswer(curPlayer, "阵营: 1-左边;2-右边")
            continue
        GameWorld.DebugAnswer(curPlayer, "---------- 【阵营%s】 ----------" % faction)
        batFaction = turnFight.getBatFaction(faction)
        batLineup = batFaction.getBatlineup(1)
        for posNum in posNumList:
            objID = batLineup.posObjIDDict.get(posNum)
            if not objID:
                continue
            batObj = batObjMgr.getBatObj(objID)
            objName = TurnAttack.GetObjName(batObj)
            GameWorld.DebugAnswer(curPlayer, "--- %s%s" % (objName, "" if batObj.IsAlive() else " [被击杀]"))
            GameWorld.DebugAnswer(curPlayer, "HP:%s/%s, Atk:%s, Def:%s" % (batObj.GetHP(), batObj.GetMaxHP(), batObj.GetAtk(), batObj.GetDef()))
            attrDict = batObj.GetBatAttrDict()
            GameWorld.DebugAnswer(curPlayer, "属性:%s" % attrDict)
            skillMgr = batObj.GetSkillManager()
            skillIDList = skillMgr.GetSkillIDList()
            GameWorld.DebugAnswer(curPlayer, "技能: %s,%s" % (len(skillIDList), skillIDList))
            buffMgr = batObj.GetBuffManager()
            GameWorld.DebugAnswer(curPlayer, "Buff: %s" % buffMgr.GetBuffCount())
            for index in range(buffMgr.GetBuffCount()):
                buff = buffMgr.GetBuffByIndex(index)
                GameWorld.DebugAnswer(curPlayer, "ID:%s,SkillID:%s,回合:%s,层:%s,V:%s"
                                      % (buff.GetBuffID(), buff.GetSkillID(), buff.GetRemainTime(), buff.GetLayer(),
                                         [buff.GetValue1(), buff.GetValue2(), buff.GetValue3()]
                                         ))
    return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ObjPool.py
@@ -93,6 +93,9 @@
        visited = set([obj_id])  # 初始化已访问集合
        
        try:
            ### 回收前处理,主要处理一些其他不需要释放的对象池对象,防止被连同误回收
            if hasattr(obj, 'onRelease'):
                obj.onRelease()
            # 1. 递归释放嵌套对象池对象
            self._recursive_release(obj, visited)
            # 2. 释放当前对象
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/PassiveTrigger/PassiveEff_5007.py
New file
@@ -0,0 +1,59 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
##@package Skill.PassiveTrigger.PassiveEff_5007
#
# @todo:偷取目标身上增益类型buff(技能类型3、5)
# @author hxp
# @date 2025-09-25
# @version 1.0
#
# 详细描述: 偷取目标身上增益类型buff(技能类型3、5)
#
#-------------------------------------------------------------------------------
#"""Version = 2025-09-25 17:30"""
#-------------------------------------------------------------------------------
import TurnBuff
import ChConfig
import GameWorld
import random
def DoSkillEffectLogic(turnFight, batObj, tagObj, effSkill, curEffect, connSkill, connBuff, **kwargs):
    stealCnt = max(1, curEffect.GetEffectValue(0)) # 偷取个数
    checkInStateList = curEffect.GetEffectValue(1) # 可附加验证处于xx状态 [状态1, 状态2, ...]
    if checkInStateList:
        if not tagObj.CheckInState(checkInStateList):
            GameWorld.DebugLog("目标不在以下状态不能偷: tagID=%s,checkInStateList=%s" % (tagObj.GetID(), checkInStateList))
            return
    plsBuffList = []
    buffMgr = tagObj.GetBuffManager()
    for index in range(buffMgr.GetBuffCount()):
        buff = buffMgr.GetBuffByIndex(index)
        skillData = buff.GetSkillData()
        if skillData.GetSkillType() not in [ChConfig.Def_SkillType_LstPlsBuff, ChConfig.Def_SkillType_PlsBuff]:
            continue
        plsBuffList.append(buff)
    if not plsBuffList:
        GameWorld.DebugLog("目标没有增益buff: tagID=%s" % (tagObj.GetID()))
        return
    random.shuffle(plsBuffList) # 随机
    for tagBuff in plsBuffList:
        if stealCnt <= 0:
            break
        skillID = tagBuff.GetSkillID()
        buffOwner = batObj
        GameWorld.DebugLog("͵ȡbuff: tagID=%s,tagBuffID=%s" % (tagObj.GetID(), tagBuff.GetBuffID()))
        addBuff = TurnBuff.DoAddBuffBySkillID(turnFight, batObj, skillID, buffOwner, connSkill, isSync=False)
        if not addBuff:
            continue
        stealCnt -= 1
        TurnBuff.CopyBuff(turnFight, batObj, addBuff, tagBuff, connSkill, True)
        TurnBuff.DoBuffDel(turnFight, tagObj, tagBuff)
    return True
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnBuff.py
@@ -32,7 +32,24 @@
        return []
    return callFunc(turnFight, attacker, defender, curSkill)
def DoAddBuffBySkillID(turnFight, batObj, skillID, buffOwner=None, bySkill=None, afterLogic=False):
def CopyBuff(turnFight, curBatObj, curBuff, tagBuff, bySkill=None, isNewAdd=False):
    '''拷贝buff数据,不含目标buffID、归属,并刷新时间
    '''
    skillData = curBuff.GetSkillData()
    curBuff.SetCalcTime(turnFight.getTimeline())
    curBuff.SetRemainTime(max(tagBuff.GetRemainTime(), skillData.GetLastTime()))
    curBuff.SetLayer(max(tagBuff.GetLayer(), skillData.GetLayerMax()))
    curBuff.SetValue1(tagBuff.GetValue1())
    curBuff.SetValue2(tagBuff.GetValue2())
    curBuff.SetValue3(tagBuff.GetValue3())
    GameWorld.DebugLog("    拷贝buff: curBuffID=%s,tagBuffID=%s,Remain=%s,Layer=%s,Value=%s"
                       % (curBuff.GetBuffID(), tagBuff.GetBuffID(), curBuff.GetRemainTime(), curBuff.GetLayer(),
                          [curBuff.GetValue1(), curBuff.GetValue2(), curBuff.GetValue3()]))
    relatedSkillID = bySkill.GetSkillID() if bySkill else 0
    SyncBuffRefresh(turnFight, curBatObj, curBuff, relatedSkillID, isNewAdd)
    return
def DoAddBuffBySkillID(turnFight, batObj, skillID, buffOwner=None, bySkill=None, afterLogic=False, isSync=True):
    ## 根据技能ID添加buff
    if not skillID:
        return
@@ -45,12 +62,12 @@
    useSkill = poolMgr.acquire(BattleObj.PySkill, skillIpyData, ownerID)
    useSkill.SetTagObjList(tagObjList)
    
    isOK = OnAddBuff(turnFight, batObj, useSkill, buffOwner, bySkill, afterLogic)
    addBuff = OnAddBuff(turnFight, batObj, useSkill, buffOwner, bySkill, afterLogic, isSync=isSync)
    
    poolMgr.release(useSkill)
    return isOK
    return addBuff
def OnAddBuff(turnFight, batObj, buffSkill, buffOwner=None, bySkill=None, afterLogic=False):
def OnAddBuff(turnFight, batObj, buffSkill, buffOwner=None, bySkill=None, afterLogic=False, isSync=True):
    skillID = buffSkill.GetSkillID()
    bySkill = buffSkill.GetBySkill() if not bySkill else bySkill
    relatedSkillID = bySkill.GetSkillID() if bySkill else 0
@@ -64,14 +81,14 @@
        and batObj.CheckInState(ChConfig.BatObjState_Wudi):
        GameWorld.DebugLog("无敌状态下免疫该buff: curID=%s,skillID=%s,ownerID=%s,relatedSkillID=%s" 
                           % (curID, skillID, ownerID, relatedSkillID))
        return False
        return
    
    #被动触发免疫控制buff
    if buffSkill.GetSkillType() == ChConfig.Def_SkillType_Action:
        if TurnPassive.GetTriggerEffectValue(turnFight, batObj, buffOwner, ChConfig.PassiveEff_ImmuneControlBuff, buffSkill):
            GameWorld.DebugLog("血量低于百分x时免疫控制buff: curID=%s,skillID=%s,ownerID=%s,relatedSkillID=%s,hp:%s/%s" 
                               % (curID, skillID, ownerID, relatedSkillID, batObj.GetHP(), batObj.GetMaxHP()))
            return False
            return
        
    buffValueList = GetAddBuffValue(turnFight, buffOwner, batObj, buffSkill)
    
@@ -154,17 +171,16 @@
            buff.SetBuffValueList(buffValueList)
            if afterLogic and bySkill:
                bySkill.AddAfterLogic(ChConfig.AfterLogic_AddBuff, [batObj, buff, buffOwner])
            else:
            elif isSync:
                SyncBuffRefresh(turnFight, batObj, buff, relatedSkillID, isNewAdd=True)
                
            if nowLayerCnt != updLayerCnt:
                RefreshBuffEffect(turnFight, batObj, buff, False)
            return True
            return buff
        
    __addNewBuff(turnFight, batObj, buffMgr, buffSkill, buffValueList, buffOwner, bySkill, afterLogic, setLayerCnt=addLayerCnt)
    return True
    return __addNewBuff(turnFight, batObj, buffMgr, buffSkill, buffValueList, buffOwner, bySkill, afterLogic, setLayerCnt=addLayerCnt, isSync=isSync)
def __addNewBuff(turnFight, batObj, buffMgr, buffSkill, buffValueList, buffOwner, bySkill=None, afterLogic=False, setLayerCnt=0):
def __addNewBuff(turnFight, batObj, buffMgr, buffSkill, buffValueList, buffOwner, bySkill=None, afterLogic=False, setLayerCnt=0, isSync=True):
    curID = batObj.GetID()
    skillID = buffSkill.GetSkillID()
    buff = buffMgr.AddBuff(skillID)
@@ -188,11 +204,11 @@
        
    if afterLogic and bySkill:
        bySkill.AddAfterLogic(ChConfig.AfterLogic_AddBuff, [batObj, buff, buffOwner])
    else:
    elif isSync:
        SyncBuffRefresh(turnFight, batObj, buff, relatedSkillID, isNewAdd=True)
        
    RefreshBuffEffect(turnFight, batObj, buff, True)
    return
    return buff
def RefreshBuffEffect(turnFight, batObj, curBuff, isNewBuff=False):
    ## 刷新buff效果
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/TurnSkill.py
@@ -676,6 +676,9 @@
    if not tagObj:
        return
    
    if not tagObj.IsAlive():
        return
    tagID = tagObj.GetID()
    canAtkbackDictTypeList = IpyGameDataPY.GetFuncEvalCfg("ParryCfg", 2)
    if tagObj.GetAtkDistType() not in canAtkbackDictTypeList: