From 206203b4ccec9426178e12b8d67c815c4743df54 Mon Sep 17 00:00:00 2001
From: hxp <ale99527@vip.qq.com>
Date: 星期一, 01 九月 2025 15:45:06 +0800
Subject: [PATCH] 129 【战斗】战斗系统-服务端(优化主线战斗片段断点逻辑;)

---
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/TurnAttack.py |  233 ++++++++++++++++++++++++++--------------------------------
 1 files changed, 105 insertions(+), 128 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 dab5601..0b40ce3 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/TurnAttack.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/TurnAttack.py
@@ -148,8 +148,6 @@
         self.turnNum = 1 # 当前第x回合,默认第1回合开始
         self.turnMax = 15 # 最大回合数
         self.enterLogic = False # 是否已执行进场逻辑
-        self.turnStart = 0 # 已执行回合开始值,如第1回合开始已执行则为1,第2回合为2
-        self.turnEnd = 0 # 已执行回合结束值,如第1回合结束已执行则为1,第2回合为2
         self.winFaction = 0 # 本场战斗结束标记,获胜阵营,为0时代表未结束,所有小队打完或失败才有结果,0-未结束,>0-获胜的阵营
         self.batBuffer = "" # 战报buffer,战报暂时只保留最后一个小队的
         self.isNeedReport = isNeedReport # 是否需要战报
@@ -157,9 +155,8 @@
         
         self.factionDict = {} # 战斗阵营 {faction:BatFaction, ...},一般是只有两个阵营,faction为1或2,每个阵营支持多个阵容
         self.actionSortList = [] # 阵容行动顺序 [[faction, num], ...]
-        self.actionIndex = 0 # 行动顺序索引
+        self.actionIndex = 0 # 行动顺序索引        
         self.timeline = 0 # 时间轴节点  turnNum*1000+actionIndex*100++actionNum
-        
         self.startTime = 0 # 开始时间戳,支持毫秒小数
         self.costTime = 0 # 单场战斗总耗时,支持毫秒小数
         return
@@ -178,11 +175,10 @@
         ## 一般用于玩家发起的战斗,在需要保留玩家阵容属性及状态的情况下,重置回合进入下一场战斗
         self.turnNum = 1
         self.enterLogic = False
-        self.turnStart = 0
-        self.turnEnd = 0
         self.winFaction = 0
         self.batBuffer = "" # 战报buffer
         self.msgDict.update(msgDict)
+        self.timeline = 0
         self.startTime = time.time()
         self.costTime = 0
         return
@@ -220,21 +216,20 @@
         GameWorld.DebugLog("阵容行动顺序[f, n]: %s" % self.actionSortList)
         return
     
+    def getTurnNumStartTimelin(self, turnNum): return turnNum * TimelineSet + 0 # 每回合的时间节点起点
     def getTimeline(self): return self.timeline
-    def setTimeline(self, turnNum):
+    def setTimeline(self, timeline, isEmpty=False):
         '''回合战斗的时间轴节点 ,即第几回合开始,每个回合支持9999个行动节点
         @param turnNum: 第x回合
         '''
-        self.timeline = turnNum * TimelineSet + 0
+        self.timeline = timeline
         GameWorld.DebugLog("时间节点更新: %s" % self.timeline)
+        if isEmpty:
+            # 空位置的节点可直接跳过
+            return timeline
+        
         OnTimelineChange(self)
-        return
-    def addTimeline(self):
-        ## 每切换一个行动单位可视为一个行动节点,即代表单回合战斗中的某一个时间节点
-        self.timeline += 1
-        GameWorld.DebugLog("时间节点更新: %s" % self.timeline)
-        OnTimelineChange(self)
-        return
+        return timeline
     
     def getBatFaction(self, faction=ChConfig.Def_FactionA):
         ## 默认阵营1
@@ -288,7 +283,8 @@
     def startFight(self):
         ## 准备就绪,开始战斗
         self.state = FightState_Start
-        self.setTimeline(1)
+        self.turnNum = 1
+        self.timeline = self.getTurnNumStartTimelin(self.turnNum)
         self.syncInit()
         return
     
@@ -742,6 +738,7 @@
         __doSetFightPoint(curPlayer, reqValue)
         return
     
+    GameWorld.DebugLog("主线战斗请求: reqType=%s" % reqType, curPlayer.GetPlayerID())
     clientPack = ChPyNetSendPack.tagSCTurnFightReportSign()
     clientPack.Sign = 0
     NetPackCommon.SendFakePack(curPlayer, clientPack) # 标记开始
@@ -856,6 +853,8 @@
     turnFight.setFactionLineup(ChConfig.Def_FactionB, {1:GetNPCLineupInfo(lineupID, strongerLV, difficulty)})
     turnFight.sortActionQueue()
     turnFight.startFight()
+    
+    __doMainFight(curPlayer)
     return
 
 def __doMainBossStart(curPlayer):
@@ -939,18 +938,20 @@
     __processTurnFight(turnFight.guid)
     return
 
-def __doMainFight(curPlayer, tick):
-    ## 主线执行战斗
+def __doMainFight(curPlayer, tick=0):
+    '''执行主线战斗,单场战斗断电式战斗,以前端玩家手动点击节点做为断点处
+    每场战斗的初始化、结束默认断点,由前端决定自动继续或者点击继续
+    '''
     
     # 限制请求CD
-    #if not GameWorld.GetGameWorld().GetDebugLevel():
-    key = "MainFightReqTick"
-    lastTick = curPlayer.GetDictByKey(key)
-    if lastTick and tick - lastTick <= 1000:
-        GameWorld.DebugLog("主线战斗请求CD中")
-        return
-    curPlayer.SetDict(key, tick)
-    
+    if tick:
+        key = "MainFightReqTick"
+        lastTick = curPlayer.GetDictByKey(key)
+        if lastTick and tick - lastTick <= 1000:
+            GameWorld.DebugLog("主线战斗请求CD中")
+            return
+        curPlayer.SetDict(key, tick)
+        
     mainFightMgr = GetMainFightMgr(curPlayer)
     turnFight = mainFightMgr.turnFight
     
@@ -977,6 +978,8 @@
                 # 每次处理一小队的完整战斗,相当于一次完整战报
                 __processTurnFight(turnFight.guid)
                 return
+            else:
+                __doMainFight(curPlayer)
         else:
             __doMainLevelWave(curPlayer, False)
         return
@@ -987,128 +990,109 @@
     
     # 小怪战斗,每次消耗1个战锤
     fightPoint = max(curPlayer.GetFightPoint(), 1) # 主线战斗消耗倍值,默认1
-    
     if not PlayerControl.HaveMoney(curPlayer, ShareDefine.TYPE_Price_Xiantao, fightPoint):
         GameWorld.DebugLog("回合开始时战锤不足!")
         return
     
     # 以下均是处理关卡小怪分段实时战斗
-    EntryLogic(turnFight)
+    isEntry = EntryLogic(turnFight)
     
-    # 按阵营阵容执行顺序,逐个遍历
-    doCnt = 0
-    doMax = (PosNumMax + 2) * len(turnFight.actionSortList) # 防止死循环,做最大循环次数限制 = (最大位置数 + 主公、红颜位置)*行动阵容数
-    overLineupList = [] # 本回合已经结束行动的阵容列表 [(faction, num), ...], 所有阵容全部结束代表本回合结束
+    # 是否开始检查断点,预判可断的点,方便前端点击体验,点下去就是玩家放的某个行动
+    # 初始开始进场后,默认开始断点
+    checkBreakpoint = True if isEntry else False
     
     batObjMgr = BattleObj.GetBatObjMgr()
     turnNum = turnFight.turnNum
-    GameWorld.DebugLog("turnNum=%s,doMax=%s,actionIndex=%s,%s" % (turnNum, doMax, turnFight.actionIndex, turnFight.actionSortList))
-    while doCnt < doMax and len(overLineupList) < len(turnFight.actionSortList):
-        doCnt += 1
-        turnNum = turnFight.turnNum
-        # 执行回合开始逻辑
-        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
-            turnFight.turnStart = turnNum
-            turnFight.actionIndex = 0
-            turnFight.addTimeline() # 每回合开始算一个时间节点
+    turnMax = turnFight.turnMax
+    for turnNum in range(turnNum, turnMax + 1):
+        turnTimeline = turnFight.getTurnNumStartTimelin(turnNum) # 本回合起始时间节点
+        curTimeline = turnFight.getTimeline()
+        
+        # 回合开始
+        turnTimeline += 1 # 每回合开始算一个时间节点
+        if curTimeline < turnTimeline:
+            curTimeline = turnFight.setTimeline(turnTimeline)
+            GameWorld.DebugLog("【----- 回合制战斗轮次: %s -----】 curTimeline=%s" % (turnNum, curTimeline))
+            turnFight.turnNum = turnNum
+            if curPlayer:
+                turnFight.syncState(FightState_Fighting)
+                
             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)
-                batLineup.actionNum = ActionNumStart
+                batLineup.actionNum = 1
                 for objID in batLineup.posObjIDDict.values():
                     batObj = batObjMgr.getBatObj(objID)
                     TurnFightPerTurnBigStart(turnFight, batObj, turnNum)
                     
-        if turnFight.actionIndex >= len(turnFight.actionSortList):
-            turnFight.actionIndex = 0
-            
-        playerHeroAtk = False # 玩家阵容行动标记
-        faction, num = turnFight.actionSortList[turnFight.actionIndex]
-        batFaction = turnFight.getBatFaction(faction)
-        batLineup = batFaction.getBatlineup(num)
-        if batLineup.actionNum > max(batLineup.posObjIDDict):
-            if (faction, num) not in overLineupList:
-                overLineupList.append((faction, num))
-                
-            turnFight.actionIndex += 1
-            continue
-        
-        GameWorld.DebugLog("执行行动: turnNum=%s,faction=%s,num=%s,actionNum=%s" % (turnFight.turnNum, faction, num, batLineup.actionNum))
-        
-        # 主公
-        if batLineup.actionNum == -1:
-            pass
-        
         # 红颜
-        elif batLineup.actionNum == 0:
-            pass
+        # 灵兽
+        
+        if turnFight.checkOverByKilled():
+            break
         
         # 武将
-        elif batLineup.actionNum > 0:
+        doMax = PosNumMax * len(turnFight.actionSortList)
+        doCnt = 0
+        while doCnt < doMax and turnFight.actionIndex < len(turnFight.actionSortList):
+            doCnt += 1
+            faction, num = turnFight.actionSortList[turnFight.actionIndex]
+            batFaction = turnFight.getBatFaction(faction)
+            batLineup = batFaction.getBatlineup(num)
             for posNum in range(batLineup.actionNum, PosNumMax + 1):
-                turnFight.addTimeline() # 每个武将位算一个时间节点
-                batLineup.actionNum = posNum
-                if posNum not in batLineup.posObjIDDict:
+                turnTimeline += 1 # 每个武将位算一个时间节点
+                if turnTimeline <= curTimeline:
+                    # 该时间节点已经处理过了
+                    GameWorld.DebugLog("该时间节点已经处理过了! turnTimeline=%s <= %s" % (turnTimeline, curTimeline))
                     continue
+                
+                if posNum not in batLineup.posObjIDDict:
+                    batLineup.actionNum = posNum + 1
+                    curTimeline = turnFight.setTimeline(turnTimeline, True)
+                    continue
+                
                 objID = batLineup.posObjIDDict[posNum]
                 batObj = batObjMgr.getBatObj(objID)
+                
+                # 玩家自己阵营,预判可否行动
+                if checkBreakpoint and faction == ChConfig.Def_FactionA and batObj:
+                    if batObj.CanAction():
+                        GameWorld.DebugLog("玩家武将已经行动过了,且有下一个可行动的武将,断点: curTimeline=%s,nextPosNum=%s" % (curTimeline, posNum))
+                        return
+                    
+                batLineup.actionNum = posNum + 1
+                curTimeline = turnFight.setTimeline(turnTimeline)
                 TurnFightHeroTurnStart(turnFight, batObj, turnNum)
                 if not OnObjAction(turnFight, batObj):
                     continue
                 
-                if faction == ChConfig.Def_FactionA:
-                    playerHeroAtk = True
+                if not checkBreakpoint and faction == ChConfig.Def_FactionA:
+                    checkBreakpoint = True
                     
-                break
-            
-        turnFight.actionIndex += 1
-        batLineup.actionNum += 1
-        if batLineup.actionNum > max(batLineup.posObjIDDict):
-            GameWorld.DebugLog("该阵容本回合已经全部行动完了: turnNum=%s,faction=%s,num=%s,actionNum=%s" % (turnFight.turnNum, faction, num, batLineup.actionNum))
-            if (faction, num) not in overLineupList:
-                overLineupList.append((faction, num))
+            if turnFight.actionIndex >= len(turnFight.actionSortList) - 1:
+                turnFight.actionIndex = 0
+            else:
+                turnFight.actionIndex += 1
                 
-        if turnFight.checkOverByKilled():
-            break
-        
-        if playerHeroAtk:
-            # 玩家武将有行动则停止,一段段执行
-            GameWorld.DebugLog("玩家武将有行动则停止!")
-            break
-        
-    if turnFight.winFaction:
-        return
-    
-    GameWorld.DebugLog("turnNum=%s,doCnt=%s,overLineupList=%s" % (turnNum, doCnt, overLineupList))
-    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
-            turnFight.turnEnd = turnNum
-            turnFight.addTimeline() # 每回合结束算一个时间节点
+        # 回合结束
+        turnTimeline += 1 # 每回合结束算一个时间节点
+        if curTimeline < turnTimeline:
+            curTimeline = turnFight.setTimeline(turnTimeline)
             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():
                     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)
-            
+        if turnFight.checkOverByKilled():
+            break
+        
+    if not turnFight.winFaction:
+        OnTurnAllOver(turnFight.guid)
+        
     return
 
 def __processTurnFight(guid):
@@ -1121,12 +1105,12 @@
     for turnNum in range(1, turnMax + 1):
         turnFight.turnNum = turnNum
         GameWorld.DebugLog("【----- 回合制战斗轮次: %s -----】" % turnNum)
-        turnFight.setTimeline(turnNum)
+        curTimeline = turnFight.getTurnNumStartTimelin(turnNum) # 本回合起始时间节点
+        curTimeline = turnFight.setTimeline(curTimeline + 1)
         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)
@@ -1136,17 +1120,9 @@
                 batObj = batObjMgr.getBatObj(objID)
                 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)
+        # 灵兽
             
         if turnFight.checkOverByKilled():
             break
@@ -1160,10 +1136,11 @@
             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:
+                    curTimeline = turnFight.setTimeline(curTimeline + 1, True)
                     continue
+                curTimeline = turnFight.setTimeline(curTimeline + 1) # 每个武将位算一个时间节点
                 objID = batLineup.posObjIDDict[posNum]
                 batObj = batObjMgr.getBatObj(objID)
                 TurnFightHeroTurnStart(turnFight, batObj, turnNum)
@@ -1178,7 +1155,7 @@
                 turnFight.actionIndex += 1
                 
         # 回合结束
-        turnFight.addTimeline() # 每回合结束算一个时间节点
+        curTimeline = turnFight.setTimeline(curTimeline + 1) # 每回合结束算一个时间节点
         for faction, num in turnFight.actionSortList:
             GameWorld.DebugLog("回合结束逻辑: turnNum=%s,faction=%s, num=%s" % (turnNum, faction, num))
             batFaction = turnFight.getBatFaction(faction)
@@ -1223,7 +1200,7 @@
             TurnPassive.OnTriggerPassiveEffect(turnFight, batObj, ChConfig.TriggerWay_FightStart)
             
     turnFight.enterLogic = True
-    return
+    return True
 
 def OnTimelineChange(turnFight):
     ## 每个时间节点变化时处理
@@ -1335,7 +1312,7 @@
     return
 
 def TurnFightHeroTurnStart(turnFight, batObj, turnNum):
-    ## 武将回合开始时
+    ## 武将回合开始时,不能行动也要触发
     if not batObj:
         return
     

--
Gitblit v1.8.0