From f2aeecf0a02b97418b762bd6ee518c33d3ae2685 Mon Sep 17 00:00:00 2001
From: hxp <ale99527@vip.qq.com>
Date: 星期五, 12 九月 2025 10:22:35 +0800
Subject: [PATCH] 129 【战斗】战斗系统-服务端(新增演武场;支持机器人;支持PVP战斗;每场战斗结束后支持查看战斗回放;榜单优化存储玩家形象Value5;主线关卡榜支持;支持查看玩家;)

---
 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerArena.py |  566 +++++++++++++++++++++++++++-----------------------------
 1 files changed, 273 insertions(+), 293 deletions(-)

diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerArena.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerArena.py
index 93d59c1..5db30f2 100644
--- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerArena.py
+++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerArena.py
@@ -4,366 +4,346 @@
 #
 ##@package Player.PlayerArena
 #
-# @todo:竞技场 - 本服
+# @todo:演武场
 # @author hxp
-# @date 2020-12-07
+# @date 2025-09-12
 # @version 1.0
 #
-# 详细描述: 竞技场 - 本服
+# 详细描述: 演武场
 #
 #-------------------------------------------------------------------------------
-#"""Version = 2020-12-07 19:30"""
+#"""Version = 2025-09-12 10:30"""
 #-------------------------------------------------------------------------------
 
+import DBDataMgr
+import PlayerMail
 import ShareDefine
 import GameFuncComm
 import PlayerControl
 import IpyGameDataPY
 import ChPyNetSendPack
+import PlayerViewCache
 import NetPackCommon
+import PyGameData
 import GameWorld
 import ChConfig
-import FBCommon
-import IPY_GameWorld
-import ItemControler
-import PlayerActTask
-import PlayerWeekParty
-import PlayerFeastTravel
-import PlayerActivity
-import PlayerSuccess
-import PlayerGubao
+import random
 
-def DoArenaOpen(curPlayer):
-    ## 竞技场功能开启
-    __DoArenaSeasonReset(curPlayer)
+# 记录攻击类型
+RecAtkType_Atk = 1 # 发起攻击
+RecAtkType_Def = 2 # 被攻击的
+
+def GetRecUpdScore(recData): return recData.GetValue1() # 更新积分
+def SetRecUpdScore(recData, score): return recData.SetValue1(score)
+def GetRecAtkType(recData): return recData.GetValue2() # 攻击类型 1-发起攻击的,2-被攻击的
+def SetRecAtkType(recData, atkType): return recData.SetValue2(atkType)
+def GetRecTagPlayerID(recData): return recData.GetValue3() # 相对攻击类型的目标玩家ID
+def SetRecTagPlayerID(recData, tagPlayerID): return recData.SetValue3(tagPlayerID)
+def GetRecIsWin(recData): return recData.GetValue4() # 是否获胜 1-获胜;2-失败
+def SetRecIsWin(recData, isWin): return recData.SetValue4(1 if isWin else 0)
+def GetRecFace(recData): return recData.GetValue5() # 目标头像
+def SetRecFace(recData, face): return recData.SetValue5(face)
+def GetRecFacePic(recData): return recData.GetValue6()
+def SetRecFacePic(recData, facePic): return recData.SetValue6(facePic)
+def GetRecRealmLV(recData): return recData.GetValue7()
+def SetRecRealmLV(recData, realmLV): return recData.SetValue7(realmLV)
+def GetRecLV(recData): return recData.GetValue8()
+def SetRecLV(recData, tagLV): return recData.SetValue8(tagLV)
+#SetUserData 名字、变更积分 +-、战力
+
+def OnWeek():
+    DoArenaReset()
+    return
+
+def OnDay():
+    __DoGiveBillboardAward("Day")
+    return
+
+def DoArenaReset():
+    ''' 赛季重置
+    '''
+    GameWorld.Log("=============== 重置竞技场 ===============")
+    
+    PyGameData.g_arenaPlayerMatchDict = {}
+    
+    # 结算上赛季排行奖励
+    __DoGiveBillboardAward("Week")
+    
+    # 重置排行榜
+    DBDataMgr.GetBillboardMgr().RemoveBillboard(ShareDefine.Def_BT_Arena)
+    # 重置记录
+    #DBDataMgr.GetGameRecMgr().DelDataByType(ShareDefine.Def_GameRecType_ArenaRecord) # 挑战记录不重置
+    
+    GameWorld.Log("==========================================")
+    return True
+
+def __DoGiveBillboardAward(awardType):
+    ## 竞技场结算排行奖励, 每日、赛季通用
+    
+    GameWorld.Log("=== 竞技场结算排行奖励! === %s" % awardType)
+    
+    billboardMgr = DBDataMgr.GetBillboardMgr()
+    billBoard = billboardMgr.GetBillboard(ShareDefine.Def_BT_Arena)
+    if not billBoard:
+        return
+    
+    if awardType == "Day":
+        billboradAwardDict = IpyGameDataPY.GetFuncEvalCfg("ArenaBillboradAward", 1, {})
+    elif awardType == "Week":
+        billboradAwardDict = IpyGameDataPY.GetFuncEvalCfg("ArenaBillboradAward", 2, {})
+    else:
+        return
+    
+    orderList = [int(orderStr) for orderStr in billboradAwardDict.keys()]
+    orderList.sort()
+    GameWorld.Log("    奖励名次列表: %s" % orderList)
+    
+    awardOrder = orderList[0]
+    orderPlayerIDDict = {}
+    billboardCount, billboardMaxCount = billBoard.GetCount(), billBoard.GetMaxCount()
+    GameWorld.Log("    榜单数据数! billboardCount=%s,billboardMaxCount=%s" % (billboardCount, billboardMaxCount))
+    for index in xrange(billboardCount):
+        billBoardData = billBoard.At(index)
+        if not billBoardData:
+            continue
+        order = index + 1
+        
+        if order > awardOrder:
+            nextOrderIndex = orderList.index(awardOrder) + 1
+            if nextOrderIndex >= len(orderList):
+                break
+            awardOrder = orderList[nextOrderIndex]
+            
+        playerID = billBoardData.GetID()
+        if playerID < ShareDefine.RealPlayerIDStart:
+            # 非真人不处理
+            continue
+        
+        orderPlayerIDDict[playerID] = [order, awardOrder]
+        
+        paramList = [order]
+        awardList = billboradAwardDict[str(awardOrder)]
+        PlayerMail.SendMailByKey("ArenaBillboardAward%s" % awardType, playerID, awardList, paramList)
+        
+    GameWorld.Log("    奖励玩家名次信息: %s" % orderPlayerIDDict)
     return
 
 def OnLogin(curPlayer):
     if not GameFuncComm.GetFuncCanUse(curPlayer, ShareDefine.GameFuncID_Arena):
         return
-    OSSeasonState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaOSSeasonState)
-    if not OSSeasonState:
-        __DoArenaSeasonReset(curPlayer)
-    else:
-        Sync_ArenaInfo(curPlayer)
+    __loginUpdPlayerScore(curPlayer)
+    Sync_ArenaInfo(curPlayer)
+    return
+
+def __loginUpdPlayerScore(curPlayer):
+    playerID = curPlayer.GetPlayerID()
+    recMgr = DBDataMgr.GetGameRecMgr()
+    recIDMgr = recMgr.GetRecTypeIDMgr(ShareDefine.Def_GameRecType_ArenaRecord, playerID)
+    if not recIDMgr.GetCount():
+        return
+    finalRecData = recIDMgr.At(recIDMgr.GetCount() - 1)
+    recTime = finalRecData.GetTime()
+    if not GameWorld.CheckTimeIsSameWeek(recTime):
+        GameWorld.Log("玩家上线演武场记录积分非本周不更新! recTime=%s" % GameWorld.ChangeTimeNumToStr(recTime), playerID)
+        return
+    updScore = GetRecUpdScore(finalRecData)
+    befScore = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaScore)
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ArenaScore, updScore)
+    GameWorld.Log("玩家上线更新演武场积分: befScore=%s,updScore=%s,recTime=%s" % (befScore, updScore, GameWorld.ChangeTimeNumToStr(recTime)), playerID)
     return
 
 def OnDayEx(curPlayer):
     if not GameFuncComm.GetFuncCanUse(curPlayer, ShareDefine.GameFuncID_Arena):
         return
-    
-    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ArenaItemAddCount, 0)
-    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ArenaBattleCountDay, 0)
-    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ArenaMatchRefreshCount, 0)
     Sync_ArenaInfo(curPlayer)
-    
-    openServerDay = GameWorld.GetGameWorld().GetGameWorldDictByKey(ShareDefine.Def_Notify_WorldKey_ServerDay) + 1
-    customMaxServerDay = IpyGameDataPY.GetFuncCfg("OperationAction", 1)
-    if openServerDay <= customMaxServerDay:
-        GameWorld.DebugLog("OnDayEx时竞技场开服定制赛季进行中,不处理! openServerDay=%s <= %s" % (openServerDay, customMaxServerDay))
-        return
-    
-    OSSeasonState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaOSSeasonState)
-    if OSSeasonState > 1:
-        GameWorld.DebugLog("OnDayEx时竞技场开服定制赛季已结算过,不处理! OSSeasonState=%s" % (OSSeasonState))
-        return
-    
-    __DoArenaSeasonReset(curPlayer)
     return
 
 def OnWeekEx(curPlayer):
     if not GameFuncComm.GetFuncCanUse(curPlayer, ShareDefine.GameFuncID_Arena):
         return
-    
-    openServerDay = GameWorld.GetGameWorld().GetGameWorldDictByKey(ShareDefine.Def_Notify_WorldKey_ServerDay) + 1
-    customMaxServerDay = IpyGameDataPY.GetFuncCfg("OperationAction", 1)
-    if openServerDay <= customMaxServerDay:
-        GameWorld.DebugLog("OnWeekEx时在开服定制天内,不处理竞技场赛季重置! openServerDay=%s <= %s" % (openServerDay, customMaxServerDay))
-        return
-    
-    OSSeasonState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaOSSeasonState)
-    if not OSSeasonState or OSSeasonState == 1 or OSSeasonState == openServerDay:
-        GameWorld.DebugLog("OnWeekEx时竞技场开服定制赛季进行中或同一天结算,不处理重置! openServerDay=%s,OSSeasonState=%s" % (openServerDay, OSSeasonState))     
-        return
-    
+    __DoArenaSeasonReset(curPlayer)
+    return
+
+def DoArenaOpen(curPlayer):
     __DoArenaSeasonReset(curPlayer)
     return
 
 def __DoArenaSeasonReset(curPlayer):
     ## 玩家重置竞技场
-    
-    OSSeasonState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaOSSeasonState)
-    openServerDay = GameWorld.GetGameWorld().GetGameWorldDictByKey(ShareDefine.Def_Notify_WorldKey_ServerDay) + 1
-    
-    customMaxServerDay = IpyGameDataPY.GetFuncCfg("OperationAction", 1)
-    if openServerDay <= customMaxServerDay and OSSeasonState != 0:
-        GameWorld.DebugLog("开服定制天内不能重置!")
-        return
-    
-    setScoreMin, setScoreMax, refScoreMax = IpyGameDataPY.GetFuncEvalCfg("ArenaSet", 2)
-    setScore = setScoreMin
-    if openServerDay <= customMaxServerDay and OSSeasonState == 0:
-        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ArenaOSSeasonState, 1)
-        GameWorld.DebugLog("竞技场开服定制赛季! setScore=%s" % setScore)
-    else:
-        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ArenaOSSeasonState, customMaxServerDay + 1)
-        
-        preSeasonscore = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaScore)
-        if preSeasonscore <= setScoreMin:
-            setScore = setScoreMin
-        elif preSeasonscore >= refScoreMax:
-            setScore = setScoreMax
-        else:
-            # 按比例降低积分,都减去最低分的差值算比例
-            calcScore = preSeasonscore - setScoreMin
-            setScore = setScoreMin + int(calcScore * (setScoreMax - setScoreMin) / float(refScoreMax - setScoreMin))
-            
-        GameWorld.DebugLog("竞技场赛季重置! preSeasonscore=%s,setScore=%s" % (preSeasonscore, setScore))
-        
-    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ArenaScore, setScore)
-    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ArenaItemAddCount, 0)
-    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ArenaBattleCountDay, 0)
-    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ArenaMatchRefreshCount, 0)
-    Sync_ArenaInfo(curPlayer, True)
+    initScore = IpyGameDataPY.GetFuncCfg("ArenaSet", 1)
+    GameWorld.DebugLog("竞技场赛季重置!initScore=%s" % (initScore))
+    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ArenaScore, initScore)
+    Sync_ArenaInfo(curPlayer)
     return
 
-def CheckArenaBattleCount(curPlayer):
-    ## 验证是否还有对战次数
-    todayBattleCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaBattleCountDay)
-    itemAddCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaItemAddCount)
-    dayFreeCount = IpyGameDataPY.GetFuncCfg("ArenaSet", 3)
-    return todayBattleCount < (dayFreeCount + itemAddCount)
+def GetArenaTicketStoreMax(curPlayer):
+    ## 获取挑战券存储上限
+    baseCnt = IpyGameDataPY.GetFuncCfg("ArenaSet", 3)
+    
+    # 其他特权提升上限
+    
+    storeMax = baseCnt
+    return storeMax
 
-#// B2 09 竞技场匹配玩家 #tagCMArenaMatch
+#// B2 09 演武场匹配玩家 #tagCSArenaMatch
 #
-#struct    tagCMArenaMatch
+#struct    tagCSArenaMatch
 #{
 #    tagHead         Head;
-#    BYTE        IsRefresh;    // 0-打开界面无匹配数据时时查询,1-强制刷新匹配列表
+#    BYTE        IsRefresh;    // 0-打开界面无匹配数据时查询,1-强制刷新匹配列表
 #};
 def OnArenaMatch(index, clientData, tick):
     curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
     isRefresh = clientData.IsRefresh
-    
-    playerID = curPlayer.GetPlayerID()
-    refreshCountLimit = IpyGameDataPY.GetFuncCfg("ArenaSet", 5)
-    if isRefresh and refreshCountLimit:
-        refreshCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaMatchRefreshCount)
-        if refreshCount >= refreshCountLimit:
-            GameWorld.DebugLog("竞技场刷新匹配玩家次数已满!refreshCount=%s >= %s" % (refreshCount, refreshCountLimit), playerID)
-            return
-        
-    if not GameWorld.SetPlayerTickTime(curPlayer, ChConfig.TYPE_Player_Tick_Arena, tick):
-        GameWorld.DebugLog("竞技场匹配操作CD中...", playerID)
-        PlayerControl.NotifyCode(curPlayer, "RequestLater")
-        return
-    
-    playerLV = curPlayer.GetLV()
-    playerScore = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaScore)
-    msgInfo = str(["MatchRefresh", {"isRefresh":isRefresh, "playerLV":playerLV, "playerScore":playerScore}])
-    GameWorld.DebugLog("竞技场发送GameServer匹配: %s" % msgInfo, playerID)
-    GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(curPlayer.GetID(), 0, 0, "Arena", msgInfo, len(msgInfo))
+    DoArenaMatchRefresh(curPlayer, isRefresh)
     return
 
 def GMArenaMatch(curPlayer, gmMatchIDList):
-    playerID = curPlayer.GetPlayerID()
-    playerLV = curPlayer.GetLV()
-    playerScore = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaScore)
-    msgInfo = str(["MatchRefresh", {"isRefresh":1, "playerLV":playerLV, "playerScore":playerScore, "gmMatchIDList":gmMatchIDList}])
-    GameWorld.DebugLog("竞技场发送GameServer匹配: %s" % msgInfo, playerID)
-    GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(curPlayer.GetID(), 0, 0, "Arena", msgInfo, len(msgInfo))
+    ## GM直接匹配
+    isRefresh = True
+    DoArenaMatchRefresh(curPlayer, isRefresh, gmMatchIDList)
     return
 
-#// B2 10 竞技场挑战玩家 #tagCMArenaBattle
-#
-#struct    tagCMArenaBattle
-#{
-#    tagHead         Head;
-#    DWORD        TagPlayerID;    // 目标玩家ID或机器人ID
-#    BYTE        Result;    // 0-进入自定义场景发送通知后端;1-胜利(后端处理,暂时不需要发送此状态);2-失败(前端被对手击杀需要发送此状态)
-#};
-def OnArenaBattle(index, clientData, tick):
-    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
+def DoArenaMatchRefresh(curPlayer, isRefresh, gmMatchIDList=None, isSys=False):
+    ## 玩家刷新匹配对手
+    
     playerID = curPlayer.GetPlayerID()
-    tagPlayerID = clientData.TagPlayerID
-    result = clientData.Result
+    playerScore = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaScore)
+    matchScoreList = IpyGameDataPY.GetFuncEvalCfg("ArenaMatch", 1)
     
-    GameWorld.DebugLog("竞技场挑战玩家! tagPlayerID=%s,result=%s" % (tagPlayerID, result), playerID)
-    if not tagPlayerID:
+    GameWorld.DebugLog("竞技场玩家刷新匹配列表: isRefresh=%s,playerScore=%s,gmMatchIDList=%s,isSys=%s" % (isRefresh, playerScore, gmMatchIDList, isSys), playerID)
+    GameWorld.DebugLog("    matchScoreList=%s" % (matchScoreList), playerID)
+    
+    # 匹配对象缓存
+    needMatchCount = len(matchScoreList)
+    if playerID not in PyGameData.g_arenaPlayerMatchDict:
+        PyGameData.g_arenaPlayerMatchDict[playerID] = []
+    matchIDList = PyGameData.g_arenaPlayerMatchDict[playerID]
+    if len(matchIDList) > needMatchCount:
+        matchIDList = matchIDList[:needMatchCount] # 删除多余的个数,一般都是相同的,除非修改匹配数重读配置
+    if not isRefresh and len(matchIDList) == needMatchCount:
+        # 非刷新的并且已经有记录的直接同步
+        GameWorld.DebugLog("    非刷新且有数据,直接同步!", playerID)
+        __SyncMatchList(curPlayer, matchIDList)
         return
-    
-    if not result:
-        GameWorld.DebugLog("更新竞技场对战对手ID! tagPlayerID=%s" % tagPlayerID, playerID)
-        # 记录对手ID
-        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ArenaBattleTagID, tagPlayerID)
-        return
-    
-    if tagPlayerID >= 10000:
-        if result:
-            GameWorld.DebugLog("真人由后端镜像PK决定胜负! tagPlayerID=%s" % tagPlayerID, playerID)
+    if isRefresh and not gmMatchIDList and not isSys:
+        costMoney, moneyValue = IpyGameDataPY.GetFuncEvalCfg("ArenaMatch", 4)
+        if not costMoney or not moneyValue or not PlayerControl.PayMoney(curPlayer, costMoney, moneyValue, "Arena"):
             return
         
-    isWin = 1 if result == 1 else 0
-#    # 木桩被击杀,后端判断,其他前端同步
-#    if isWin:
-#        GameWorld.ErrLog("前端不能同步竞技场胜利状态!", playerID)
-#        return
-    
-    recTagPlayerID = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaBattleTagID)
-    if tagPlayerID != recTagPlayerID:
-        GameWorld.ErrLog("竞技场结算时对手ID不一致! tagPlayerID(%s) != recTagPlayerID(%s)" % (tagPlayerID, recTagPlayerID), playerID)
-        __DoArenaBattleOver(curPlayer)
+    billboardMgr = DBDataMgr.GetBillboardMgr()
+    billBoard = billboardMgr.GetBillboard(ShareDefine.Def_BT_Arena)
+    if not billBoard:
         return
+    maxOrder = billBoard.GetCount()
+    playerOrder = billBoard.IndexOfByID(playerID) + 1  # 玩家在排行榜中的名次,没有名次为-1
     
-    # 失败结算入口: 前端同步
-    SendGameServer_ArenaBattleOver(curPlayer, isWin)
-    return
-
-def OnKillBattleNPC(curPlayer, curNPC):
-#    ## 击杀对手,前端本,使用木桩NPC作为对手
-#    
-#    if curNPC.GetGameObjType() != IPY_GameWorld.gotNPC or curNPC.GetType() not in [ChConfig.ntPriWoodPilePVE, ChConfig.ntPriWoodPilePVP]:
-#        GameWorld.DebugLog("击杀非木桩NPC,不结算!")
-#        return
-#    
-#    # 胜利结算入口:后端验证击杀对手
-#    tagPlayerID = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaBattleTagID)
-#    GameWorld.DebugLog("竞技场击杀对手! tagPlayerID=%s" % tagPlayerID, curPlayer.GetPlayerID())
-#    isWin = 1
-#    SendGameServer_ArenaBattleOver(curPlayer, isWin)
-    return
-
-def SendGameServer_ArenaBattleOver(curPlayer, isWin):
-    ## 发送GameServer通知战斗结算
+    matchRobotCntDict = IpyGameDataPY.GetFuncEvalCfg("ArenaMatch", 3)
+    if playerOrder > 0:
+        matchRobotRange = GameWorld.GetOrderValueByDict(matchRobotCntDict, playerOrder)
+        matchRobotCnt = random.randint(matchRobotRange[0], matchRobotRange[1])
+    else:
+        matchRobotCnt = needMatchCount
+    matchPlayerCnt = needMatchCount - matchRobotCnt
+    GameWorld.DebugLog("    maxOrder=%s,playerOrder=%s,matchRobotCnt=%s,matchPlayerCnt=%s" % (maxOrder, playerOrder, matchRobotCnt, matchPlayerCnt), playerID)
     
-    playerID = curPlayer.GetPlayerID()
-    tagPlayerID = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaBattleTagID)
-    if not tagPlayerID:
-        GameWorld.ErrLog("竞技场结算时没有对手ID!", playerID)
-        __DoArenaBattleOver(curPlayer)
-        return
-    
-    if not CheckArenaBattleCount(curPlayer):
-        GameWorld.ErrLog("竞技场已经没有对战次数!", playerID)
-        __DoArenaBattleOver(curPlayer)
-        return
-    
-    tick = GameWorld.GetGameWorld().GetTick()
-    if not GameWorld.SetPlayerTickTime(curPlayer, ChConfig.TYPE_Player_Tick_Arena, tick):
-        GameWorld.ErrLog("结算竞技场CD中!tagPlayerID=%s" % tagPlayerID, playerID)
-        return
-    
-    playerLV = curPlayer.GetLV()
-    playerScore = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaScore)
-    msgInfo = str(["BattleResult", {"tagPlayerID":tagPlayerID, "isWin":isWin, "playerLV":playerLV, "playerScore":playerScore, 
-                                    "realmLV":curPlayer.GetOfficialRank(), "fightPower":PlayerControl.GetFightPower(curPlayer)}])
-    GameWorld.DebugLog("竞技场发送GameServer结算: %s" % msgInfo, playerID)
-    GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(curPlayer.GetID(), 0, 0, "Arena", msgInfo, len(msgInfo))
-    return
-
-def __DoArenaBattleOver(curPlayer, retDict={}):
-    ## 主动战斗结算奖励
-    # @param isOK: True时才结算奖励,防止某些异常情况无法结算通知前端FBOver,导致卡副本
-    
-    GameWorld.DebugLog("结算竞技场对战奖励! retDict=%s" % retDict)
-    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ArenaBattleTagID, 0)
-    
-    isOK = retDict.get("isOK", False)
-    isWin = retDict.get("isWin", 0)
-    if not isOK:
-        # 一直异常的情况直接同步结束包,防止不结算卡副本
-        FBCommon.NotifyFBOver(curPlayer, ChConfig.Def_FBMapID_ArenaBattle, 0, isWin)
-        return
-    
-    #GameServer MapServer 同步有一定时间差,本功能存在被动挑战引发积分变动的情况,
-    #curScore = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaScore)
-    addScore = retDict["addScore"]
-    updScore = retDict["updScore"]
-    curOrder = retDict["curOrder"]
-    updOrder = retDict["updOrder"]
-    offlineRecTime = retDict.get("offlineRecTime", 0)
-    
-    # 扣次数
-    if not offlineRecTime or GameWorld.CheckTimeIsSameServerDayEx(offlineRecTime):
-        todayBattleCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaBattleCountDay) + 1
-        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ArenaBattleCountDay, todayBattleCount)
-    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ArenaMatchRefreshCount, 0)
+    fromLowerCnt, matchPerRank = IpyGameDataPY.GetFuncEvalCfg("ArenaMatch", 2)
+    toOrder = playerOrder + fromLowerCnt * matchPerRank # 从低名次往高名次匹配
+    GameWorld.DebugLog("    fromLowerCnt=%s,matchPerRank=%s,toOrder=%s" % (fromLowerCnt, matchPerRank, toOrder), playerID)
+    matchOrderList = [] # 匹配到的名次
+    for _ in range(matchPlayerCnt):
+        fromOrder = max(1, toOrder - matchPerRank)
+        if toOrder <= fromOrder:
+            break
+        orderList = range(fromOrder, toOrder)
+        random.shuffle(orderList)
+        if playerOrder in orderList:
+            orderList.remove(playerOrder) # 不包含自己
+        if not orderList:
+            break
         
-    # 更新积分
-    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ArenaScore, updScore)
-    highestScore = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaHighestScore)
-    if updScore > highestScore:
-        highestScore = updScore
-        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ArenaHighestScore, highestScore)
-        GameWorld.DebugLog("    更新竞技场历史最高分! %s" % highestScore)
+        if fromOrder == 1:
+            for order in orderList:
+                if order > maxOrder:
+                    continue
+                matchOrderList.append(order)
+                if len(matchOrderList) >= matchPlayerCnt:
+                    break
+        else:
+            order = orderList[0]
+            if order <= maxOrder:
+                matchOrderList.append(order)
+                
+        GameWorld.DebugLog("    匹配玩家: fromOrder=%s,toOrder=%s,matchOrderList=%s" % (fromOrder, toOrder, matchOrderList), playerID)
+        toOrder = fromOrder - 1
         
-    # 胜利给额外奖励
-    itemList = retDict.get("awardItemList", [])
-    ItemControler.GivePlayerItemOrMail(curPlayer, itemList)
-    jsonItemList = FBCommon.GetJsonItemList(itemList)
-    
-    overDict = {FBCommon.Over_itemInfo:jsonItemList, "addScore":addScore, "updScore":updScore, "curOrder":curOrder, "updOrder":updOrder}
-    FBCommon.NotifyFBOver(curPlayer, ChConfig.Def_FBMapID_ArenaBattle, 0, isWin, overDict)
-    Sync_ArenaInfo(curPlayer)
-    
-    PlayerWeekParty.AddWeekPartyActionCnt(curPlayer, ChConfig.Def_WPAct_Arena, 1)
-    PlayerFeastTravel.AddFeastTravelTaskValue(curPlayer, ChConfig.Def_FeastTravel_Arena, 1)
-    PlayerActivity.AddDailyActionFinishCnt(curPlayer, ShareDefine.DailyActionID_Arena, 1)
-    PlayerSuccess.DoAddSuccessProgress(curPlayer, ShareDefine.SuccType_Arena, 1)
-    PlayerGubao.AddGubaoItemEffValue(curPlayer, PlayerGubao.GubaoEffType_Arena, 1)
-    PlayerActTask.AddActTaskValue(curPlayer, ChConfig.ActTaskType_Arena)
-    return
-
-def __DoUpdateArenaScore(curPlayer, cmdDict={}):
-    ''' 玩家直接更新积分,有以下几种情况,都是被挑战的,只更新积分
-    1. 被动挑战在线时直接更新积分
-    2. 离线/脱机时被挑战,上线后同步最新积分
-    '''
-    
-    playerScore = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaScore)
-    updScore = cmdDict.get("updScore", playerScore)
-    if updScore == playerScore:
-        return
-    
-    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ArenaScore, updScore)
-    Sync_ArenaInfo(curPlayer)
-    return
-
-def GameServer_ArenaResult(curPlayer, msgList, tick):
-    if not msgList:
-        return
-    
-    cmd = msgList[0]
-    cmdDict = msgList[1] if len(msgList) > 1 else {}
-    retDict = msgList[2] if len(msgList) > 2 else {}
-    
-    # 刷新匹配
-    if cmd == "MatchRefresh":
-        isRefresh = cmdDict.get("isRefresh", False)
-        refreshCountLimit = IpyGameDataPY.GetFuncCfg("ArenaSet", 5)
-        if isRefresh and refreshCountLimit:
-            updRefreshCount = min(250, curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaMatchRefreshCount) + 1)
-            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ArenaMatchRefreshCount, updRefreshCount)
-            GameWorld.DebugLog("更新竞技场刷新匹配次数! updRefreshCount=%s" % updRefreshCount)
-            Sync_ArenaInfo(curPlayer)
+    # GM指定匹配测试
+    if gmMatchIDList != None and curPlayer.GetGMLevel():
+        for gmMatchID in gmMatchIDList:
+            if gmMatchID == playerID:
+                GameWorld.DebugAnswer(curPlayer, "目标ID不能是自己!无法匹配!%s" % gmMatchID)
+                continue
             
-    # 主动对战结果
-    elif cmd == "BattleResult":
-        __DoArenaBattleOver(curPlayer, retDict)
+            gmMatchOrder = billBoard.IndexOfByID(gmMatchID) + 1
+            if gmMatchOrder <= 0:
+                GameWorld.DebugAnswer(curPlayer, "目标ID不在榜单上!无法匹配!%s" % gmMatchID)
+                continue
+            GameWorld.DebugAnswer(curPlayer, "指定匹配ID(%s),order(%s)" % (gmMatchID, gmMatchOrder))
+            if gmMatchID not in matchOrderList:
+                matchOrderList.insert(0, gmMatchOrder)
+        matchOrderList = matchOrderList[:needMatchCount]
         
-    # 被动挑战更新积分
-    elif cmd == "UpdScore":
-        __DoUpdateArenaScore(curPlayer, cmdDict)
+    matchOrderList.sort()
+    matchIDList = [] # 最终匹配的玩家ID列表
+    for matchOrder in matchOrderList:
+        if matchOrder > maxOrder or matchOrder <= 0:
+            break
+        billData = billBoard.At(matchOrder - 1)
+        matchIDList.append(billData.GetID())
         
+    needRobotCnt = needMatchCount - len(matchIDList)
+    GameWorld.DebugLog("    匹配榜单结果: matchIDList=%s,matchOrderList=%s,needRobotCnt=%s" % (matchIDList, matchOrderList, needRobotCnt), playerID)
+    ipyDataMgr = IpyGameDataPY.IPY_Data()
+    robotMax = ipyDataMgr.GetRobotCount()
+    doCnt = 100
+    while doCnt > 0 and needRobotCnt > 0 and robotMax:
+        doCnt -= 1
+        robotIndex = random.randint(0, robotMax - 1)
+        robotIpyData = ipyDataMgr.GetRobotByIndex(robotIndex)
+        robotID = robotIpyData.GetID()
+        if robotID not in matchIDList:
+            matchIDList.append(robotID)
+            needRobotCnt -= 1
+    GameWorld.DebugLog("    最终匹配结果: matchIDList=%s" % matchIDList, playerID)
+    
+    PyGameData.g_arenaPlayerMatchDict[playerID] = matchIDList
+    __SyncMatchList(curPlayer, matchIDList)
     return
 
-def Sync_ArenaInfo(curPlayer, isReset=False):
-    clientPack = ChPyNetSendPack.tagMCArenaPlayerInfo()
-    clientPack.IsReset = 1 if isReset else 0
-    clientPack.Score = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaScore)
-    clientPack.BattleCountToday = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaBattleCountDay)
-    clientPack.MatchRefreshCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaMatchRefreshCount)
-    clientPack.ItemAddBattleCountToday = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaItemAddCount)
+def __SyncMatchList(curPlayer, matchIDList):
+    ## 同步匹配列表
+    clientPack = ChPyNetSendPack.tagSCArenaMatchList()
+    clientPack.MatchList = []
+    for matchID in matchIDList:
+        viewCache = PlayerViewCache.FindViewCache(matchID)
+        matchInfo = ChPyNetSendPack.tagSCArenaMatchInfo()
+        matchInfo.PlayerID = matchID
+        if viewCache:
+            matchInfo.PlayerName = viewCache.GetPlayerName()
+            matchInfo.RealmLV = viewCache.GetRealmLV()
+            matchInfo.Face = viewCache.GetFace()
+            matchInfo.FacePic = viewCache.GetFacePic()
+            matchInfo.FightPower = viewCache.GetFightPower()
+            matchInfo.FightPowerEx = viewCache.GetFightPowerEx()
+        else:
+            matchInfo.PlayerName = "p%s" % matchID
+        clientPack.MatchList.append(matchInfo)
+    clientPack.MatchCount = len(clientPack.MatchList)
     NetPackCommon.SendFakePack(curPlayer, clientPack)
     return
 
+def Sync_ArenaInfo(curPlayer):
+    clientPack = ChPyNetSendPack.tagSCArenaPlayerInfo()
+    clientPack.Score = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ArenaScore)
+    NetPackCommon.SendFakePack(curPlayer, clientPack)
+    return

--
Gitblit v1.8.0