From 4ff284edf33cbbfcb123e2ba01dead78793e9dc8 Mon Sep 17 00:00:00 2001
From: hxp <ale99527@vip.qq.com>
Date: 星期一, 11 十二月 2023 16:47:01 +0800
Subject: [PATCH] 10019 【砍树】回合战斗(每回合攻击顺序改为按攻击速度倒序;每个阵营支持多个战斗实例)

---
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCCommon.py     |   43 ++++++++++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/TurnAttack.py |  171 +++++++++++++++++++++++++-----------------
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameObj.py           |   13 +++
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py          |    1 
 4 files changed, 157 insertions(+), 71 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 375d744..d35b9d4 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/TurnAttack.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/TurnAttack.py
@@ -77,10 +77,29 @@
 
 def DoTrunFight(curPlayer, mapID, funcLineID, tagPlayerID, tick):
     playerID = curPlayer.GetPlayerID()
+    posX, posY = curPlayer.GetPosX(), curPlayer.GetPosY()
+    
+    factionListA, factionListB = [], []
+    factionListA.append(curPlayer)
+    curPet = curPlayer.GetPetMgr().GetFightPet()
+    curPet and factionListA.append(curPet)
+    
+    # 玩家阵营的其他战斗实例,可扩展...
+    assistNPCID = 0 # 协助召唤兽
+    if assistNPCID:
+        assistNPC = NPCCommon.SummonNPC(curPlayer, assistNPCID, posX, posY)
+        assistNPC and factionListA.append(assistNPC)
+        
     tagObj = None
     if tagPlayerID:
         npcID = ChConfig.Def_NPCID_PVP
-        tagObj = NPCCommon.SummonMapNpc(npcID, curPlayer.GetPosX(), curPlayer.GetPosY(), sightLevel=playerID, pvpPlayerID=tagPlayerID)
+        tagObj = NPCCommon.SummonMapNpc(npcID, posX, posY, sightLevel=playerID, pvpPlayerID=tagPlayerID)
+        if not tagObj:
+            return
+        factionListB.append(tagObj)
+        
+        # 对手玩家镜像的其他战斗实例...
+        
     else:
         ipyData = IpyGameDataPY.GetIpyGameData("FBTurn", mapID, funcLineID)
         if not ipyData:
@@ -88,91 +107,83 @@
         npcID = ipyData.GetNPCID()
         if not npcID:
             return
-        tagObj = NPCCommon.SummonMapNpc(npcID, curPlayer.GetPosX(), curPlayer.GetPosY(), sightLevel=playerID)
-        
-    if not tagObj:
+        tagObj = NPCCommon.SummonMapNpc(npcID, posX, posY, sightLevel=playerID)
+        if not tagObj:
+            return
+        factionListB.append(tagObj)
+        summerNPCID = ipyData.GetSummerNPCID()
+        if summerNPCID:
+            summerNPC = NPCCommon.SummonNPC(tagObj, summerNPCID, posX, posY)
+            summerNPC and factionListB.append(summerNPC)
+            
+    if not factionListB:
         return
     
-    turnMax = IpyGameDataPY.GetFuncCfg("TurnFight", 1)
-    curPet = curPlayer.GetPetMgr().GetFightPet()
-    tagPet = None
+    for gameObj in factionListA:
+        GameObj.SetFaction(gameObj, 1)
+    for gameObj in factionListB:
+        GameObj.SetFaction(gameObj, 2)
+        
+    #一个回合攻击顺序,由攻击速度决定,攻速相同下阵营1先攻击,还相同则由ID决定
+    fightObjList = factionListA + factionListB
+    fightObjList.sort(key=lambda o: (GameObj.GetAtkSpeed(o), (10 - GameObj.GetFaction(o)), o.GetID()), reverse=True)
     
+    turnMax = IpyGameDataPY.GetFuncCfg("TurnFight", 1)
     GameWorld.DebugLog("===== 执行回合制战斗: mapID=%s,funcLineID=%s,tagPlayerID=%s,tagObjID=%s" 
                        % (mapID, funcLineID, tagPlayerID, tagObj.GetID()), playerID)
-    GameWorld.DebugLog("curPlayer.GetSightLevel=%s,tagObj.GetSightLevel=%s" 
-                       % (curPlayer.GetSightLevel(), tagObj.GetSightLevel()), playerID)
-        
-    #一个回合攻击顺序
-    #1. 快方宠物攻击,不存在跳过
-    #2. 慢方宠物攻击,不存在跳过
-    #3. 快方主体攻击
-    #4. 慢方主体攻击
-    
     # 战斗前初始化
-    factionObjMax = 0 # 某个阵营的最大战斗实例数
-    factionObjDict = {1:[curPet, curPlayer], 2:[tagPet, tagObj]}
-    for objList in factionObjDict.values():
-        if factionObjMax < len(objList):
-            factionObjMax = len(objList)
-        for gameObj in objList:
-            TurnFightObjStartInit(gameObj)
-            
-    curAtkSpeed = GameObj.GetAtkSpeed(curPlayer)
-    tagAtkSpeed = GameObj.GetAtkSpeed(tagObj)
-    orderList = [1, 2] if curAtkSpeed >= tagAtkSpeed else [2, 1]
-    GameWorld.DebugLog("playerHP=%s,tagHP=%s,curAtkSpeed=%s,tagAtkSpeed=%s" 
-                       % (GameObj.GetHP(curPlayer), GameObj.GetHP(tagObj), curAtkSpeed, tagAtkSpeed), playerID)
-    
+    for gameObj in fightObjList:
+        TurnFightObjStartInit(gameObj)
+        
     isWin = None
     for turnNum in range(1, turnMax + 1):
         GameWorld.DebugLog("----- 回合制战斗轮次: %s -----" % turnNum, playerID)
         SyncTurnFightState(curPlayer, mapID, funcLineID, tagPlayerID, FightState_Fighting, turnNum, turnMax)
         
         # 回合开始: 做一些每回合重置逻辑或者某些根据回合触发的效果等
-        for objList in factionObjDict.values():
-            for gameObj in objList:
-                TurnFightObjTurnStart(gameObj, turnNum)
-                
+        for gameObj in fightObjList:
+            TurnFightObjPerTurnStart(gameObj, turnNum)
+            
         # 回合战斗: 轮流依次攻击
-        for index in range(factionObjMax):
-            for faction in orderList:
-                objList = factionObjDict[faction]
-                if index >= len(objList):
-                    continue
-                gameObj = objList[index]
-                if not gameObj:
-                    continue
-                
-                tagGameObj = tagObj if faction == 1 else curPlayer
-                objType = gameObj.GetGameObjType()
-                objID = gameObj.GetID()
-                tagObjType = tagGameObj.GetGameObjType()
-                tagObjID = tagGameObj.GetID()
-                
-                GameWorld.DebugLog("    行动: turnNum=%s,index=%s,faction=%s,objType=%s,objID=%s,tagObjType=%s,tagObjID=%s" 
-                                   % (turnNum, index, faction, objType, objID, tagObjType, tagObjID), playerID)
-                DoAttack(gameObj, tagGameObj, tick)
-                
-                if tagGameObj and GameObj.GetHP(tagGameObj) > 0:
-                    continue
-                
-                isWin = faction == 1
-                GameWorld.DebugLog("        tagObjType=%s,tagObjID=%s,被击杀,结束战斗: isWin=%s" % (tagObjType, tagObjID, isWin))
-                break
+        for actNum, gameObj in enumerate(fightObjList, 1):
+            if not gameObj:
+                continue
+            faction = GameObj.GetFaction(gameObj)
+            tagGameObj = tagObj if faction == 1 else curPlayer
+            objType = gameObj.GetGameObjType()
+            objID = gameObj.GetID()
+            tagObjType = tagGameObj.GetGameObjType()
+            tagObjID = tagGameObj.GetID()
             
-            if isWin != None:
-                break
+            GameWorld.DebugLog("    行动: turnNum=%s,actNum=%s,faction=%s,objType=%s,objID=%s,tagObjType=%s,tagObjID=%s" 
+                               % (turnNum, actNum, faction, objType, objID, tagObjType, tagObjID), playerID)
+            DoAttack(gameObj, tagGameObj, tick)
             
+            playerDead = GameObj.GetHP(curPlayer) <= 0
+            tagObjDead = (not tagObj or GameObj.GetHP(tagObj) <= 0)
+            if not playerDead and not tagObjDead:
+                continue
+            
+            if playerDead and tagObjDead:
+                isWin = False # 平局算失败
+                GameWorld.DebugLog("        双方被击杀,平局算失败: isWin=%s" % isWin)
+            elif playerDead:
+                isWin = False
+                GameWorld.DebugLog("        玩家被击杀,失败: isWin=%s" % isWin)
+            elif tagObjDead:
+                isWin = True # 胜利
+                GameWorld.DebugLog("        对手被击杀,胜利: isWin=%s" % isWin)
+            break
+        
         if isWin != None:
             break
         
     overState = FightState_Win if isWin else FightState_Fail
     SyncTurnFightState(curPlayer, mapID, funcLineID, tagPlayerID, overState, turnNum, turnMax)
     
-    for objList in factionObjDict.values():
-        for gameObj in objList:
-            TurnFightObjOverReset(gameObj)
-            
+    for gameObj in fightObjList:
+        TurnFightObjOverReset(gameObj)
+        
     GameWorld.DebugLog("===== 回合制战斗结束: mapID=%s,funcLineID=%s,tagPlayerID=%s,isWin=%s,overState=%s" 
                        % (mapID, funcLineID, tagPlayerID, isWin, overState), playerID)
     return
@@ -187,6 +198,10 @@
     gameObj.RefreshView()
     
     objType = gameObj.GetGameObjType()
+    npcID = gameObj.GetNPCID() if objType == IPY_GameWorld.gotNPC else 0
+    GameWorld.DebugLog("    初始化实例: objID=%s,npcID=%s,faction=%s,atkSpeed=%s,HP=%s" 
+                       % (gameObj.GetID(), npcID, GameObj.GetFaction(gameObj), GameObj.GetAtkSpeed(gameObj), GameObj.GetHP(gameObj)))
+    
     # 重置技能CD、战斗buff
     if objType == IPY_GameWorld.gotPlayer:            
         skillManager = gameObj.GetSkillManager()
@@ -198,7 +213,7 @@
         pass
     return
 
-def TurnFightObjTurnStart(gameObj, turnNum):
+def TurnFightObjPerTurnStart(gameObj, turnNum):
     ## 回合制战斗实例 - 每回合开始时处理
     if not gameObj:
         return
@@ -223,18 +238,34 @@
         return
     gameObj.SetDict(ChConfig.Def_Obj_Dict_TurnFightNum, 0)
     gameObj.SetDict(ChConfig.Def_Obj_Dict_TurnBattleType, 0)
+    GameObj.SetFaction(gameObj, 0)
     
     objType = gameObj.GetGameObjType()
     if objType == IPY_GameWorld.gotPlayer:
         pass
     
     elif objType == IPY_GameWorld.gotNPC:
-        npcObjType = gameObj.GetGameNPCObjType()
-        if npcObjType != IPY_GameWorld.gnotPet and GameObj.GetHP(gameObj):
-            NPCCommon.SetDeadEx(gameObj)
-            
+        RecycleObj(gameObj)
     return
 
+def RecycleObj(gameObj):
+    npcObjType = gameObj.GetGameNPCObjType()
+    if npcObjType == IPY_GameWorld.gnotPet:
+        #GameWorld.DebugLog("RecycleObj 灵宠不回收 objID=%s,npcObjType=%s,%s" % (gameObj.GetID(), npcObjType, gameObj.GetNPCID()))
+        return
+    if npcObjType == IPY_GameWorld.gnotSummon:
+        curOwner = NPCCommon.GetSummonOwnerDetel(gameObj)
+        if curOwner and curOwner.GetGameObjType() == IPY_GameWorld.gotNPC:
+            #GameWorld.DebugLog("RecycleObj 召唤兽主人是NPC不回收 objID=%s,npcObjType=%s,%s,ownerID=%s" % (gameObj.GetID(), npcObjType, gameObj.GetNPCID(), curOwner.GetID()))
+            return
+    if GameObj.GetHP(gameObj) <= 0:
+        #GameWorld.DebugLog("RecycleObj 已死亡,不用重复回收 objID=%s,npcObjType=%s,%s" % (gameObj.GetID(), npcObjType, gameObj.GetNPCID()))
+        return
+    #GameWorld.DebugLog("RecycleObj: objID=%s,npcObjType=%s,%s" % (gameObj.GetID(), npcObjType, gameObj.GetNPCID()))
+    NPCCommon.SetDeadEx(gameObj)
+    return
+
+
 def DoAttack(curObj, tagObj, tick):
     curID = curObj.GetID()
     tagID = tagObj.GetID()
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
index be5f30c..ad82af4 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
@@ -3060,6 +3060,7 @@
 ) = range(3)
 
 #---Obj字典-------
+Def_Obj_Dict_Faction = 'Faction' # 所属阵营
 Def_Obj_Dict_TurnFightNum = 'TurnFightNum' # 回合制战斗当前轮次
 Def_Obj_Dict_TurnComboNum = 'TurnComboNum' # 本回合已累计连击次数
 Def_Obj_Dict_TurnAtkBackNum = 'TurnAtkBackNum' # 本回合已累计反击次数
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameObj.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameObj.py
index 78078e5..7866691 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameObj.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameObj.py
@@ -179,6 +179,19 @@
     gameObj.SetDict(ChConfig.Def_PlayerKey_BloodShiledHurtEx, value / ShareDefine.Def_PerPointValue)
     return
 
+def GetFaction(gameObj):
+    faction = gameObj.GetDictByKey(ChConfig.Def_Obj_Dict_Faction)
+    if faction:
+        return faction
+    if gameObj.GetGameObjType() == IPY_GameWorld.gotPlayer:
+        return gameObj.GetFaction()
+    return gameObj.GetCountry()
+def SetFaction(gameObj, value):
+    gameObj.SetDict(ChConfig.Def_Obj_Dict_Faction, value)
+    if gameObj.GetGameObjType() == IPY_GameWorld.gotPlayer:
+        gameObj.SetFaction(value)
+    return
+
 def GetAtkSpeed(gameObj):
     if gameObj.GetGameObjType() == IPY_GameWorld.gotPlayer:
         return gameObj.GetBattleValEx1()
diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCCommon.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCCommon.py
index b517a41..2f74743 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCCommon.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCCommon.py
@@ -148,7 +148,7 @@
 def SetSuppressFightPower(curNPC, value): return curNPC.SetThunderDef(min(value, ShareDefine.Def_UpperLimit_DWord))
 def GetCommendFightPower(curNPC): return curNPC.GetFireDef() # 火防代表推荐战力
 def GetDropOwnerType(curNPC): return curNPC.GetThunderAtk() # 雷攻代表掉落归属类型
-def GetFaction(curNPC): return curNPC.GetCountry()
+def GetFaction(curNPC): return GameObj.GetFaction(curNPC)
 def GetSkillAtkRate(curNPC): return curNPC.GetPoisionAtk() # 毒攻代表NPC技能伤害加成万分率
 def GetFinalHurt(curNPC): return curNPC.GetFireAtk() # 火攻代表NPC最终固定伤害加成, 普攻也有效果
 def SetFinalHurt(curNPC, hurt): return curNPC.SetFireAtk(hurt) # 火攻代表NPC最终固定伤害加成, 普攻也有效果
@@ -2269,6 +2269,10 @@
 # @return 如果召唤失败返回None 否则返回召唤的NPC的实例
 # @remarks 在地图里召唤NPC 根据NPCID 出生点 AI类型 和TICK
 def SummonMapNpc(npcId, rebornX, rebornY, aiType=0, lastTime=0, playerID=0, sightLevel=0, refreshID=0, pvpPlayerID=0):
+    npcData = GameWorld.GetGameData().FindNPCDataByID(npcId)
+    if not npcData:
+        GameWorld.ErrLog("找不到该NPCID: %s" % npcId)
+        return
     curSummon = GameWorld.GetNPCManager().AddPlayerSummonNPC()
     if not curSummon:
         return
@@ -2306,6 +2310,43 @@
     #__NotifyMapPlayerSummonMapNPC(npcId, rebornX, rebornY)
     return curSummon
 
+def SummonNPC(gameObj, npcID, rebornX, rebornY):
+    ''' 某个实例进行召唤,有从属关系
+    '''
+    npcData = GameWorld.GetGameData().FindNPCDataByID(npcID)
+    if not npcData:
+        GameWorld.ErrLog("找不到该NPCID: %s" % npcID)
+        return
+    if gameObj.GetGameObjType() == IPY_GameWorld.gotPlayer:
+        curSummon = gameObj.SummonNewNPC()
+        curSummon.SetLV(gameObj.GetLV())
+        curSummon.SetCountry(gameObj.GetCountry())
+        curSummon.GetNPCAngry().Init(ChConfig.Def_SummonNPC_Angry_Count)
+        curSummon.SetOwner(gameObj)
+    else:
+        sumCount, angryCount = 1, 3
+        if not gameObj.AddSummonCount(sumCount, npcID, angryCount):
+            return
+        #取新增的一只,最后一个
+        index = gameObj.GetSummonCount() - 1
+        if index < 0:
+            return 
+        curSummon = gameObj.GetSummonNPCAt(index)
+        
+    if not curSummon:
+        return
+    
+    tick = GameWorld.GetGameWorld().GetTick()
+    curSummon.SetNPCTypeID(npcID)
+    curSummon.SetBornTime(tick)
+    InitNPC(curSummon)     
+    curSummon.SetSightLevel(gameObj.GetSightLevel())
+    
+    curSummon.Reborn(rebornX, rebornY, False)
+    NPCControl(curSummon).DoNPCRebornCommLogic(tick)
+    #curSummon.RefreshView()
+    return curSummon
+
 ## 通知地图内玩家,地图出现召唤NPC
 # @param npcId: NPCID
 # @param rebornX: 出生点X

--
Gitblit v1.8.0