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