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/Attack/TurnAttack.py | 289 +++++++++++++++++++++++++++++++++++++-------------------- 1 files changed, 189 insertions(+), 100 deletions(-) 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() -- Gitblit v1.8.0