129 【战斗】战斗系统-服务端(诸葛果技能;追击支持;优化连击追击;程序内置限制单武将单次行动中每个对象累计使用技能次数20次;)
| | |
| | | self._hurtList = [] # 本次伤血列表,可能同一个对象有多个伤害,如弹射等 [HurtObj, ...]
|
| | | self._bySkill = None # 由哪个技能触发的
|
| | | self._afterLogicList = [] # 技能释放后需要处理逻辑 [[logicType, logicParams], ...]
|
| | | |
| | | # 连击相关
|
| | | self._comboState = 0 # 连击状态 0-未重置,1-初始化连击相关可连击,2-连击已中断
|
| | | self._comboNum = 0 # 连击次数
|
| | | self._missTagIDDict = {} # 单次连续连击中对方已闪避次数 {tagID:missNum, ...}
|
| | | self._parryTagIDDict = {} # 单次连续连击中对方已格挡次数 {tagID:parryNum, ...}
|
| | | return
|
| | |
|
| | | def ResetUseRec(self):
|
| | |
| | | return hurtObj
|
| | | def GetHurtObjList(self): return self._hurtList
|
| | |
|
| | | def __commboClear(self):
|
| | | ## 连击相关清空
|
| | | self._comboState = 0
|
| | | self._comboNum = 0
|
| | | self._missTagIDDict = {}
|
| | | self._parryTagIDDict = {}
|
| | | return
|
| | | |
| | | def ComboCheckStart(self, force=False):
|
| | | ## 检查并设置开始连击相关,一般是开始使用技能时调用
|
| | | if not force:
|
| | | if self._comboState == 1:
|
| | | #GameWorld.DebugLog("连击进行中,不重置")
|
| | | return
|
| | | self.__commboClear()
|
| | | self._comboState = 1 # 设置已初始化连击相关
|
| | | #GameWorld.DebugLog("连击重置")
|
| | | return
|
| | | |
| | | def ComboEnable(self): return self._comboState == 1 ## 可否执行连击相关
|
| | | |
| | | def ComboInterrupt(self):
|
| | | ## 连击中断,概率不再触发连击时需要设置中断
|
| | | self._comboState = 2
|
| | | return
|
| | | |
| | | def GetComboNum(self): return self._comboNum # 已连击次数
|
| | | def SetComboNum(self, comboNum): self._comboNum = comboNum
|
| | | def GetTagMissNum(self, tagID): return self._missTagIDDict.get(tagID, 0)
|
| | | def SetTagMissNum(self, tagID, missNum): self._missTagIDDict[tagID] = missNum
|
| | | def GetTagParryNum(self, tagID): return self._parryTagIDDict.get(tagID, 0)
|
| | | def SetTagParryNum(self, tagID, parryNum): self._parryTagIDDict[tagID] = parryNum
|
| | | |
| | | class SkillManager():
|
| | | ## 战斗对象技能管理器
|
| | |
|
| | |
| | | self.timeline = 0 # 时间轴节点 turnNum*1000+actionIndex*100++actionNum
|
| | | self.startTime = 0 # 开始时间戳,支持毫秒小数
|
| | | self.costTime = 0 # 单场战斗总耗时,支持毫秒小数
|
| | | self._oneActionUseSkillCntDict = {} # 某对象行动开始后所有对象累计使用技能次数,用于单对象单次行动中限制每个对象的最高触发技能次数 {objID:useCnt, ...}
|
| | |
|
| | | # pve 多小队 - 一般只有PVE用到
|
| | | self.lineupIndex = 0 # 当前小队索引
|
| | |
| | | else:
|
| | | ObjPool.GetPoolMgr().release(clientPack)
|
| | | return
|
| | | |
| | | def ResetOneActionUseSkillCnt(self): self._oneActionUseSkillCntDict = {}
|
| | | def GetOneActionUseSkillCnt(self, objID): return self._oneActionUseSkillCntDict.get(objID, 0)
|
| | | def SetOneActionUseSkillCnt(self, objID, useCnt):
|
| | | self._oneActionUseSkillCntDict[objID] = useCnt
|
| | | return useCnt
|
| | |
|
| | | class TurnFightMgr():
|
| | | ## 回合战斗管理器
|
| | |
| | | batLineup.actionNum = ActionNumStart
|
| | | for objID in batLineup.posObjIDDict.values():
|
| | | batObj = batObjMgr.getBatObj(objID)
|
| | | turnFight.ResetOneActionUseSkillCnt()
|
| | | TurnPassive.OnTriggerPassiveEffect(turnFight, batObj, ChConfig.TriggerWay_FightStart)
|
| | |
|
| | | turnFight.enterLogic = True
|
| | |
| | | #GameWorld.DebugLog("OnTimelineChange! objID=%s" % (objID))
|
| | | if not batObj or not batObj.IsAlive():
|
| | | continue
|
| | | |
| | | batObj.SetDict(ChConfig.Def_Obj_Dict_TurnComboNum, 0)
|
| | | batObj.SetDict(ChConfig.Def_Obj_Dict_TurnMissNum, 0)
|
| | | batObj.SetDict(ChConfig.Def_Obj_Dict_TurnParryNum, 0)
|
| | |
|
| | | curID = batObj.GetID()
|
| | | skillManager = batObj.GetSkillManager()
|
| | |
| | | if batObj.GetHP() <= 0:
|
| | | return
|
| | |
|
| | | turnFight.ResetOneActionUseSkillCnt()
|
| | | TurnPassive.OnTriggerPassiveEffect(turnFight, batObj, ChConfig.TriggerWay_BigTurnStart)
|
| | | return
|
| | |
|
| | |
| | | return
|
| | |
|
| | | GameWorld.DebugLog("---[武将回合开始时] : curID=%s,curHP=%s/%s" % (batObj.GetID(), batObj.GetHP(), batObj.GetMaxHP()))
|
| | | turnFight.ResetOneActionUseSkillCnt()
|
| | | TurnPassive.OnTriggerPassiveEffect(turnFight, batObj, ChConfig.TriggerWay_HeroTurnStart)
|
| | | return
|
| | |
|
| | |
| | | Def_Obj_Dict_SkinID = 'SkinID' # 该战斗NPC所绑定的武将皮肤ID,一般仅玩家阵容有
|
| | | Def_Obj_Dict_TurnFightPosInfo = 'TurnFightPosInfo' # 回合制站位: 阵营编号*100+阵型站位,阵型站位为0时代表非主战单位
|
| | | Def_Obj_Dict_TurnFightTimeline = 'TurnFightTimeline' # 回合制战斗时间线: 回合数*100+行动编号节点
|
| | | Def_Obj_Dict_TurnComboNum = 'TurnComboNum' # 单次累计连击次数
|
| | | Def_Obj_Dict_TurnAtkBackNum = 'TurnAtkBackNum' # 单次累计反击次数
|
| | | Def_Obj_Dict_TurnParryNum = 'TurnParryNum' # 单次累计格挡次数
|
| | | Def_Obj_Dict_TurnMissNum = 'TurnMissNum' # 单次累计闪避次数
|
| | | Def_Obj_Dict_TurnBattleType = 'TurnBattleType' # 本次攻击战斗类型:TurnBattleType_xxx
|
| | |
|
| | |
| | | def CanHappen(rate, maxRate=ShareDefine.Def_MaxRateValue):
|
| | | if rate <= 0:
|
| | | return 0
|
| | | if random.randint(0, maxRate -1) < rate:
|
| | | if rate >= maxRate or random.randint(0, maxRate -1) < rate:
|
| | | return 1
|
| | |
|
| | | return 0
|
New file |
| | |
| | | #!/usr/bin/python
|
| | | # -*- coding: GBK -*-
|
| | | #-------------------------------------------------------------------------------
|
| | | #
|
| | | ##@package Skill.PassiveTrigger.PassiveEff_5012
|
| | | #
|
| | | # @todo:概率进行追击
|
| | | # @author hxp
|
| | | # @date 2025-09-18
|
| | | # @version 1.0
|
| | | #
|
| | | # 详细描述: 概率进行追击
|
| | | #
|
| | | #-------------------------------------------------------------------------------
|
| | | #"""Version = 2025-09-18 10:30"""
|
| | | #-------------------------------------------------------------------------------
|
| | |
|
| | | import TurnSkill
|
| | | import IpyGameDataPY
|
| | | import GameWorld
|
| | | import ChConfig
|
| | |
|
| | | def DoSkillEffectLogic(turnFight, batObj, tagObj, effSkill, curEffect, connSkill):
|
| | | rate = curEffect.GetEffectValue(0)
|
| | | if not GameWorld.CanHappen(rate):
|
| | | #GameWorld.DebugLog("概率进行追击不触发!")
|
| | | return
|
| | | skillID = curEffect.GetEffectValue(1) # 技能ID,为0时释放本技能
|
| | | if not skillID:
|
| | | passiveSkill = effSkill
|
| | | else:
|
| | | passiveSkill = IpyGameDataPY.GetIpyGameData("Skill", skillID)
|
| | | if not passiveSkill:
|
| | | return
|
| | | return TurnSkill.OnUseSkill(turnFight, batObj, passiveSkill, batType=ChConfig.TurnBattleType_Pursue, bySkill=connSkill)
|
| | |
|
| | | def DoBuffEffectLogic(turnFight, batObj, tagObj, effBuff, curEffect, connSkill):
|
| | | effSkill = effBuff.GetSkillData().GetIpyData()
|
| | | return DoSkillEffectLogic(turnFight, batObj, tagObj, effSkill, curEffect, connSkill)
|
| | |
| | | # 可扩展其他目标选择,如复活技能没有死亡单位时则使用另外的效果
|
| | | return
|
| | |
|
| | | objID = curBatObj.GetID()
|
| | | oneActionUseCnt = turnFight.GetOneActionUseSkillCnt(objID)
|
| | | if oneActionUseCnt >= 20:
|
| | | GameWorld.ErrLog("单次行动累计使用技能达到上限! objID=%s,oneActionUseCnt=%s" % (objID, oneActionUseCnt), turnFight.playerID)
|
| | | return
|
| | | oneActionUseCnt = turnFight.SetOneActionUseSkillCnt(objID, oneActionUseCnt + 1)
|
| | | |
| | | bySkillID = bySkill.GetSkillID() if bySkill else 0
|
| | | GameWorld.DebugLog("使用技能: curID=%s,skillID=%s,tagCnt=%s,batType=%s,bySkillID=%s,HP:%s/%s" |
| | | % (curBatObj.GetID(), skillID, len(tagObjList), batType, bySkillID, curBatObj.GetHP(), curBatObj.GetMaxHP()))
|
| | | GameWorld.DebugLog("使用技能: curID=%s,skillID=%s,tagCnt=%s,batType=%s,bySkillID=%s,HP:%s/%s,oneActionUseCnt=%s" |
| | | % (objID, skillID, len(tagObjList), batType, bySkillID, curBatObj.GetHP(), curBatObj.GetMaxHP(), oneActionUseCnt))
|
| | | # 以下为技能可以使用的处理,之后的逻辑默认技能使用成功
|
| | |
|
| | | poolMgr = ObjPool.GetPoolMgr()
|
| | |
| | | useSkill.SetBatType(batType)
|
| | | useSkill.SetBySkill(bySkill)
|
| | |
|
| | | isTurnNormalSkill = SkillCommon.isTurnNormalSkill(useSkill)
|
| | | if isTurnNormalSkill:
|
| | | # 普攻追击时强制重新开始算连击
|
| | | useSkill.ComboCheckStart(batType == ChConfig.TurnBattleType_Pursue)
|
| | | |
| | | curBatObj.ClearSkillTempAttr()
|
| | | tagIDList = []
|
| | | for tagObj in tagObjList:
|
| | |
| | | if useSkill.GetFuncType():
|
| | | curBatObj.SetMainTagIDList(tagIDList)
|
| | |
|
| | | objID = curBatObj.GetID()
|
| | | useTag = ""
|
| | |
|
| | | #这个技能是Buff
|
| | |
| | | turnFight.addBatPack(clientPack)
|
| | |
|
| | | # 处理反击 或 连击
|
| | | DoCombo(turnFight, curBatObj, useSkill)
|
| | | if isTurnNormalSkill:
|
| | | if not DoCombo(turnFight, curBatObj, useSkill):
|
| | | useSkill.ComboInterrupt()
|
| | |
|
| | | # 最后重置、回收对象
|
| | | useSkill.ResetUseRec()
|
| | |
| | | 纵排: 优先前面的单位
|
| | | '''
|
| | |
|
| | | if not SkillCommon.isTurnNormalSkill(useSkill):
|
| | | #GameWorld.DebugLog("非普攻不处理反击连击")
|
| | | if not useSkill.ComboEnable():
|
| | | return
|
| | |
|
| | | tagFriendly = useSkill.GetTagFriendly()
|
| | |
| | | if not tagObj:
|
| | | return
|
| | |
|
| | | comboNum = atkObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnComboNum)
|
| | | comboNum = useSkill.GetComboNum()
|
| | | aComboRate = atkObj.GetBatAttrValue(ChConfig.AttrID_ComboRate)
|
| | | aComboRate += TurnPassive.GetTriggerEffectValue(turnFight, atkObj, tagObj, ChConfig.AttrID_ComboRate, useSkill)
|
| | |
|
| | |
| | | return
|
| | | GameWorld.DebugLog("● %s 【连击】 happenRate=%s,aComboRate=%s,dComboRateDef=%s,comboNum=%s"
|
| | | % (TurnAttack.GetObjName(atkObj), happenRate, aComboRate, dComboRateDef, comboNum))
|
| | | atkObj.SetDict(ChConfig.Def_Obj_Dict_TurnComboNum, comboNum + 1)
|
| | | useSkill.SetComboNum(comboNum + 1)
|
| | |
|
| | | # 连击特长
|
| | | DoHeroSpecialty(turnFight, atkObj, ChConfig.HeroSpecialty_Combo, useSkill.GetSkillID())
|
| | |
|
| | | # 连击根据技能目标配置逻辑重新选择目标
|
| | | OnUseSkill(turnFight, atkObj, useSkill, batType=ChConfig.TurnBattleType_Combo)
|
| | | return
|
| | | return True
|
| | |
|
| | | def __getCanAtkBackSkill(useSkill, tagObj):
|
| | | ## 获取是否可反击及反击技能
|
| | |
| | |
|
| | | for tagObj in useSkill.GetTagObjList():
|
| | | tagID = tagObj.GetID()
|
| | | GameWorld.DebugLog(" tagID=%s" % (tagID))
|
| | | if tagID in missObjIDList:
|
| | | # 闪避了不触发
|
| | | continue
|
| | |
| | | if isTurnNormalSkill and not mustHit:
|
| | | aMissRateDef = atkObj.GetBatAttrValue(ChConfig.AttrID_MissRateDef) #atkObj.GetHit() # 抗闪避率 - 命中
|
| | | dMissRate = defObj.GetBatAttrValue(ChConfig.AttrID_MissRate) # 闪避率
|
| | | missNum = defObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnMissNum)
|
| | | missNum = curSkill.GetTagMissNum(defID)
|
| | | missRate = eval(IpyGameDataPY.GetFuncCompileCfg("MissCfg", 1))
|
| | | if GameWorld.CanHappen(missRate):
|
| | | GameWorld.DebugLog("闪避了! missRate=%s,dMissRate=%s,aMissRateDef=%s,missNum=%s" % (missRate, dMissRate, aMissRateDef, missNum))
|
| | | defObj.SetDict(ChConfig.Def_Obj_Dict_TurnMissNum, missRate + 1)
|
| | | curSkill.SetTagMissNum(defID, missRate + 1)
|
| | | return 0, pow(2, ChConfig.HurtType_Miss)
|
| | |
|
| | | hurtTypes = pow(2, ChConfig.HurtType_Normal)
|
| | |
| | | #被控制无法格挡
|
| | | return False
|
| | |
|
| | | defID = defObj.GetID()
|
| | | # 格挡印记
|
| | | buffMgr = defObj.GetBuffManager()
|
| | | parryYJBuff = buffMgr.FindBuffByState(ChConfig.BatObjState_ParryYJ)
|
| | |
| | |
|
| | | aParryRateDef = atkObj.GetBatAttrValue(ChConfig.AttrID_ParryRateDef)
|
| | | dParryRate = defObj.GetBatAttrValue(ChConfig.AttrID_ParryRate)
|
| | | parryNum = defObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnParryNum)
|
| | | parryNum = curSkill.GetTagParryNum(defID)
|
| | | happenRate = eval(IpyGameDataPY.GetFuncCompileCfg("ParryCfg", 1))
|
| | | if GameWorld.CanHappen(happenRate):
|
| | | GameWorld.DebugLog("格挡了: happenRate=%s,aParryRateDef=%s,dParryRate=%s,parryNum=%s" % (happenRate, aParryRateDef, dParryRate, parryNum))
|
| | | defObj.SetDict(ChConfig.Def_Obj_Dict_TurnParryNum, parryNum + 1)
|
| | | curSkill.SetTagParryNum(defID, parryNum + 1)
|
| | | return True
|
| | | return False
|
| | |
|