| | |
| | | import OperControlManager
|
| | | import PlayerViewCacheTube
|
| | | import PassiveBuffEffMng
|
| | | import GameWorldProcess
|
| | | import ChNetSendPack
|
| | | import IpyGameDataPY
|
| | | import AttackCommon
|
| | |
| | |
|
| | | import time
|
| | |
|
| | | Def_StateTimeList = [3, 60, 10] # 默认阶段时长,秒
|
| | |
|
| | | class MirrorBattle():
|
| | | ## 某场战斗
|
| | |
|
| | |
| | | return
|
| | |
|
| | | def Clear(self):
|
| | | self.isChangeMap = 0 # 是否切图战斗的
|
| | | self.isSysbg = False # 是否系统后台进行战斗的,玩家无感知,仅知道结果
|
| | | self.requestID = 0 # 请求ID,一般是玩家ID或者系统自定的ID,如某一场PK的标识信息
|
| | | self.playerID = 0 # 所属玩家ID,可能为0
|
| | |
| | | self.mapID = 0 # 功能mapID,代表某一个功能
|
| | | self.funcLineID = 0
|
| | | self.batState = 0 # 状态:0-无;1-准备中;2-战斗中;3-快速结束中,4-结束
|
| | | self.startTick = 0 # 开始战斗tick
|
| | | self.fightTickMax = 0 # 战斗最大时长,tick
|
| | | self.fightTickRemain = 0 # 剩余战斗时长,tick
|
| | | self.stateTick = 0 # 阶段状态变更时tick
|
| | | self.stateTickRemain = 0 # 阶段剩余时长,tick
|
| | | self.mirrorIDDict = {} # 该场所有玩家镜像实例ID对应真实ID {playerID:realPlayerID, ...}
|
| | | self.realIDDict = {} # 该场所有真实玩家对应初始信息 {playerID:{k:v, ...}, ...}
|
| | | self.playerFactionDict = {} # 该场所有玩家阵营信息,真实玩家+镜像玩家 {playerID:faction, ...}
|
| | |
| | | self.isQuick = False # 是否快速战斗结束的
|
| | | self.isWin = False # 是否获胜
|
| | | self.winFaction = 0 # 获胜阵营
|
| | | # 结算时血量明细
|
| | | self.curHP = 0
|
| | | self.curHPMax = 0
|
| | | self.tagHP = 0
|
| | | self.tagHPMax = 0
|
| | | return
|
| | |
|
| | | def GetTagPlayerID(self): return self.tagPlayerIDList[0] if self.tagPlayerIDList else 0
|
| | |
|
| | | def CaclFightTick(self, tick):
|
| | | ## 计算战斗时长,返回剩余时长tick
|
| | | fightTickCost = tick - self.startTick # 已过战斗时长
|
| | | self.fightTickRemain = max(0, self.fightTickMax - fightTickCost) # 剩余战斗时长
|
| | | return self.fightTickRemain
|
| | | def SyncFBStepTime(self, tick):
|
| | | #curPlayer.Sync_TimeTick(IPY_GameWorld.tttWaitStart, 0, max(notify_tick, 0), True)
|
| | | if self.isSysbg:
|
| | | return
|
| | | self.CaclStateTick(tick)
|
| | | state = self.batState
|
| | | if state == ChConfig.Def_MirrorBatState_Prepare:
|
| | | self.__SyncRealPlayerTick(ChConfig.tttWaitStart, self.stateTickRemain)
|
| | | elif state == ChConfig.Def_MirrorBatState_Fight:
|
| | | self.__SyncRealPlayerTick(ChConfig.tttTowerTake, self.stateTickRemain)
|
| | | elif state == ChConfig.Def_MirrorBatState_Over:
|
| | | self.__SyncRealPlayerTick(ChConfig.tttLeaveMap, self.stateTickRemain)
|
| | | return
|
| | | |
| | | def __SyncRealPlayerTick(self, msgType, msgTick):
|
| | | playerMgr = GameWorld.GetMapCopyPlayerManager()
|
| | | for playerID in self.realIDDict.keys():
|
| | | curPlayer = playerMgr.FindPlayerByID(playerID)
|
| | | if not curPlayer:
|
| | | continue
|
| | | curPlayer.Sync_TimeTick(msgType, 0, msgTick, True)
|
| | | return
|
| | | |
| | | def ChangeBattleState(self, state, tick):
|
| | | GameWorld.DebugLog("镜像战斗阶段变更: mapID=%s,state=%s" % (self.mapID, state), self.battleID)
|
| | | self.batState = state
|
| | | self.stateTick = tick |
| | | self.stateTickRemain = self.GetStateTickMax()
|
| | | self.SyncFBStepTime(tick)
|
| | | return
|
| | | |
| | | def CaclStateTick(self, tick):
|
| | | ## 计算状态时长,返回剩余时长tick
|
| | | stateTickMax = self.GetStateTickMax()
|
| | | passTick = tick - self.stateTick # 已过时长
|
| | | self.stateTickRemain = max(0, stateTickMax - passTick) # 剩余时长
|
| | | return self.stateTickRemain
|
| | | |
| | | def GetStateTickRemain(self): return self.stateTickRemain
|
| | | def GetStateTickMax(self):
|
| | | fightTimeLimitDict = IpyGameDataPY.GetFuncEvalCfg("MirrorAttack", 1, {})
|
| | | stateTimeList = fightTimeLimitDict.get(self.mapID, []) # 阶段时长列表
|
| | | if not stateTimeList or len(stateTimeList) != 3:
|
| | | stateTimeList = Def_StateTimeList
|
| | | |
| | | state = self.batState
|
| | | stateTime = 0
|
| | | if state == ChConfig.Def_MirrorBatState_Prepare:
|
| | | stateTime = stateTimeList[0]
|
| | | elif state == ChConfig.Def_MirrorBatState_Fight:
|
| | | stateTime = stateTimeList[1]
|
| | | elif state == ChConfig.Def_MirrorBatState_Over:
|
| | | stateTime = stateTimeList[2]
|
| | | return stateTime * 1000
|
| | | |
| | | def CalcHPPer(self):
|
| | | ## 结算当前阶段双方阵营剩余血量占比,一般用于结算计算
|
| | | curHPPer = round(self.curHP / float(self.curHPMax) * 100, 2)
|
| | | tagHPPer = round(self.tagHP / float(self.tagHPMax) * 100, 2)
|
| | | return curHPPer, tagHPPer
|
| | | def CalcRemainTimePer(self):
|
| | | ## 结算当前阶段剩余时间占比,一般用于结算计算
|
| | | remainTimePer = round(self.stateTickRemain / float(self.GetStateTickMax()) * 100)
|
| | | return remainTimePer
|
| | |
|
| | | def AddBattlePlayer(self, curPlayer, faction, posX=0, posY=0):
|
| | | playerID = curPlayer.GetPlayerID()
|
| | |
| | | if realPlayerID:
|
| | | self.mirrorIDDict[playerID] = realPlayerID
|
| | | else:
|
| | | self.realIDDict[playerID] = {"SightLevel":curPlayer.GetSightLevel(), "Faction":curPlayer.GetFaction(), "PosX":curPlayer.GetPosX(), "PosY":curPlayer.GetPosY()}
|
| | | self.realIDDict[playerID] = {"SightLevel":curPlayer.GetSightLevel(), "Faction":curPlayer.GetFaction()}
|
| | | self.playerFactionDict[playerID] = faction
|
| | |
|
| | | curPlayer.SetDict(ChConfig.Def_PlayerKey_MirrorBattleID, self.battleID)
|
| | |
| | | curPlayer.SetCanAttack(True)
|
| | | curPlayer.SetFaction(faction)
|
| | | PlayerControl.SetPlayerSightLevel(curPlayer, self.battleID) # 视野层级默认为战场ID,每场战斗的玩家独立视野
|
| | | PlayerControl.SetSight(curPlayer, ChConfig.Def_PlayerSight_Default * 3)
|
| | | GameObj.SetHPFull(curPlayer) # 回满血
|
| | | SkillCommon.ResetAllSkillCD(curPlayer) # 重置技能CD
|
| | | return
|
| | |
| | |
|
| | | def GetMirrorBattle(curPlayer):
|
| | | ## 获取玩家实例所属的战场
|
| | | return GetMirrorBattleByID(curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_MirrorBattleID))
|
| | | if curPlayer.GetRealPlayerID():
|
| | | return GetMirrorBattleByID(curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_MirrorBattleID))
|
| | | return GetMirrorBattleByID(curPlayer.GetPlayerID())
|
| | |
|
| | | def GetMirrorBattleByID(battleID):
|
| | | battle = None
|
| | |
| | | battle = MirrorBattle()
|
| | | return battle
|
| | |
|
| | | def ClearMirrorBattleByPlayer(curPlayer):
|
| | | ## 清除玩家创建的镜像战斗
|
| | | ClearMirrorBattleByID(curPlayer.GetPlayerID())
|
| | | return
|
| | |
|
| | | def ClearMirrorBattleByID(battleID):
|
| | | ## 清除镜像战斗
|
| | | battle = PyGameData.g_mirrorBattleDict.pop(battleID, None)
|
| | | if not battle:
|
| | | return
|
| | | ownerPlayerID = battle.playerID
|
| | | isSysbg = battle.isSysbg
|
| | | GameWorld.DebugLog("清除镜像战斗: battleID=%s,ownerPlayerID=%s,isSysbg=%s" % (isSysbg, ownerPlayerID, isSysbg), battleID)
|
| | | playerMgr = GameWorld.GetPlayerManager()
|
| | | tick = GameWorld.GetGameWorld().GetTick()
|
| | |
|
| | |
| | | PlayerControl.DeleteMirror(mirrorPlayer, isSysbg) # 系统场延迟回收
|
| | |
|
| | | # 重置真实玩家
|
| | | for playerID, info in battle.realIDDict.items():
|
| | | curPlayer = playerMgr.FindPlayerByID(playerID)
|
| | | for realPlayerID, info in battle.realIDDict.items():
|
| | | curPlayer = playerMgr.FindPlayerByID(realPlayerID)
|
| | | if not curPlayer:
|
| | | continue
|
| | | curPlayer.SetDict(ChConfig.Def_PlayerKey_MirrorBattleID, 0)
|
| | | curPlayer.SetDict(ChConfig.Def_PlayerKey_MirrorBattleTime, 0)
|
| | | if curPlayer.GetPlayerAction() == IPY_GameWorld.paDie or GameObj.GetHP(curPlayer) <= 0:
|
| | | ChPlayer.PlayerRebornByType(curPlayer, ChConfig.rebornType_System, tick, isAddSuperBuff=False)
|
| | | if "PosX" in info:
|
| | | curPlayer.ResetPos(info["PosX"], info["PosY"]) # 回到进去前的坐标
|
| | | curPlayer.SetFaction(0)
|
| | | PlayerControl.SetPlayerSightLevel(curPlayer, 0)
|
| | | curPlayer.SetFaction(info.get("Faction", 0))
|
| | | PlayerControl.SetPlayerSightLevel(curPlayer, info.get("SightLevel", 0))
|
| | | PlayerControl.SetSight(curPlayer, ChConfig.Def_PlayerSight_Default)
|
| | | GameObj.SetHPFull(curPlayer) # 回满血
|
| | | SkillCommon.ResetAllSkillCD(curPlayer) # 重置技能CD
|
| | | curPlayer.SetAttackTick(tick)
|
| | | ChPlayer.__Sync_ClientBuff(curPlayer)
|
| | |
|
| | | # 所属玩家
|
| | | playerID = battle.playerID
|
| | | curPlayer = playerMgr.FindPlayerByID(playerID)
|
| | | if curPlayer:
|
| | | curPlayer.SetDict(ChConfig.Def_PlayerKey_MirrorBattleID, 0)
|
| | | curPlayer.SetDict(ChConfig.Def_PlayerKey_MirrorBattleTime, 0)
|
| | | |
| | | # 如果是真实地图战斗的,关闭副本
|
| | | if battle.isChangeMap:
|
| | | GameWorldProcess.CloseFB(GameWorld.GetGameWorld().GetTick())
|
| | | return
|
| | |
|
| | | def CreateMirrorPlayer(battleID, mirrorPlayerID, mirrorPlayerData, posX=0, posY=0, faction=0, curPlayer=None):
|
| | |
| | | GameWorld.ErrLog("CreateMirrorPlayer mirrorPlayerID=%s,posX=%s,posY=%s,faction=%s"
|
| | | % (mirrorPlayerID, posX, posY, faction), playerID)
|
| | | return
|
| | | PlayerControl.SetCustomMap(mirrorPlayer, mapID, funcLineID)
|
| | | if not battle.isChangeMap:
|
| | | PlayerControl.SetCustomMap(mirrorPlayer, mapID, funcLineID)
|
| | | else:
|
| | | PlayerControl.SetCustomMap(mirrorPlayer, 0, 0) |
| | | mirrorID = mirrorPlayer.GetID()
|
| | | realPlayerID = mirrorPlayer.GetRealPlayerID()
|
| | | dataFightPower = PlayerControl.GetFightPower(mirrorPlayer)
|
| | |
| | | realPlayerID = curPlayer.GetRealPlayerID()
|
| | | posX = curPlayer.GetPosX()
|
| | | posY = curPlayer.GetPosY()
|
| | | faction = curPlayer.GetFaction()
|
| | | sightLevel = curPlayer.GetSightLevel()
|
| | | GameWorld.DebugLog("realPlayerID=%s,posX=%s,posY=%s,sightLevel=%s" % (realPlayerID, posX, posY, sightLevel), playerID)
|
| | | sight = curPlayer.GetSight()
|
| | | GameWorld.DebugLog("realPlayerID=%s,posX=%s,posY=%s,faction=%s,sightLevel=%s,sight=%s" |
| | | % (realPlayerID, posX, posY, faction, sightLevel, sight), playerID)
|
| | | GameWorld.DebugLog("生命=%s/%s, 护盾=%s/%s"
|
| | | % (GameObj.GetHP(curPlayer), GameObj.GetMaxHP(curPlayer),
|
| | | PlayerControl.GetProDef(curPlayer), PlayerControl.GetMaxProDef(curPlayer)), playerID)
|
| | |
| | |
|
| | | # 创建战斗,玩家自身参与
|
| | | if cmdType == 0:
|
| | | isSysbg = False
|
| | | requestID = playerID
|
| | | posX, posY = curPlayer.GetPosX(), curPlayer.GetPosY()
|
| | | battlePlayerList = []
|
| | | battlePlayerList.append({"playerID":playerID, "faction":1, "posX":posX, "posY":posY})
|
| | | battlePlayerList.append({"playerID":tagPlayeID, "faction":2, "posX":posX + 5, "posY":posY})
|
| | | OnRequestCreateMirrorBattle(mapID, funcLineID, requestID, battlePlayerList, isSysbg, curPlayer)
|
| | | OnRequestCreateMirrorBattle(mapID, funcLineID, playerID, [[playerID], [tagPlayeID]], False, curPlayer, True)
|
| | | return
|
| | |
|
| | | # 开始战斗
|
| | | if cmdType == 1:
|
| | | battle = GetMirrorBattle(curPlayer)
|
| | | if battle:
|
| | | OnMirrorBattleStart(battle.battleID)
|
| | | return
|
| | | # 开始战斗,该流程改为后端控制
|
| | | #if cmdType == 1:
|
| | | # battle = GetMirrorBattle(curPlayer)
|
| | | # if battle:
|
| | | # OnMirrorBattleStart(battle.battleID)
|
| | | # return
|
| | |
|
| | | # 战斗中跳过
|
| | | if cmdType == 2:
|
| | |
| | |
|
| | | # 不战斗直接跳过,即玩家没有参与,创建系统战斗场,之后扩展
|
| | | if cmdType == 3:
|
| | | isSysbg = True
|
| | | requestID = playerID
|
| | | posX, posY = curPlayer.GetPosX(), curPlayer.GetPosY()
|
| | | battlePlayerList = []
|
| | | battlePlayerList.append({"playerID":playerID, "faction":1, "posX":posX, "posY":posY})
|
| | | battlePlayerList.append({"playerID":tagPlayeID, "faction":2, "posX":posX + 5, "posY":posY})
|
| | | OnRequestCreateMirrorBattle(mapID, funcLineID, requestID, battlePlayerList, isSysbg, curPlayer)
|
| | | OnRequestCreateMirrorBattle(mapID, funcLineID, playerID, [[playerID], [tagPlayeID]], True, curPlayer)
|
| | | return
|
| | |
|
| | | # 可不做验证,PK结束后由各个功能自行做结算验证
|
| | | return
|
| | |
|
| | | def OnPlayerLeaveMap(curPlayer):
|
| | | ## 玩家离开地图
|
| | | if curPlayer.GetRealPlayerID():
|
| | | return
|
| | | battle = GetMirrorBattle(curPlayer)
|
| | | if not battle:
|
| | | return
|
| | | |
| | | # 如果还在战斗中,直接快速执行战斗结果
|
| | | if battle.batState == ChConfig.Def_MirrorBatState_Fight:
|
| | | DoMirrorBattleQuick(battle.battleID, isLogout=True)
|
| | | |
| | | # 统一退出
|
| | | if PlayerControl.GetCustomMapID(curPlayer):
|
| | | PlayerFB.DoExitCustomScene(curPlayer)
|
| | | return
|
| | |
|
| | | def OnRequestCreateMirrorBattle(mapID, funcLineID, requestID, battlePlayerList, isSysbg=False, curPlayer=None):
|
| | | def OnRequestCreateMirrorBattle(mapID, funcLineID, requestID, factionPlayerList, isSysbg=False, curPlayer=None, isChangeMap=False):
|
| | | ''' 请求创建镜像战斗,支持多对多,支持跨服,本服跨服地图中均可直接请求
|
| | | @param mapID: 功能地图ID
|
| | | @param funcLineID: 功能地图线路ID
|
| | | @param requestID: 请求ID,如果是玩家发起的,一般传入玩家ID;如果是系统发起的,由系统自行决定,比如roomID之类
|
| | | @param battlePlayerList: 战斗的玩家信息列表 [{"playerID":玩家ID, "posX":坐标x, "posY":坐标y, "faction":阵营}, ...]
|
| | | @param factionPlayerList: 战斗的阵营玩家列表 [[阵营1玩家ID, ...], [阵营2玩家ID, ...]]
|
| | | @param isSysbg: 是否后台战斗,默认否,但是系统发起的默认是
|
| | | @param curPlayer: 发起的玩家,为空时代表系统发起创建的
|
| | | @param isChangeMap: 是否切战斗场景地图
|
| | | '''
|
| | |
|
| | | playerID = 0
|
| | | if curPlayer:
|
| | | if not FBLogic.OnMirrorBattleRequest(curPlayer, mapID, funcLineID):
|
| | | if GameWorld.IsCrossServer():
|
| | | GameWorld.DebugLog("跨服服务器中不允许玩家镜像战斗请求!", playerID)
|
| | | return
|
| | | if not FBLogic.OnMirrorBattleRequest(curPlayer, mapID, funcLineID, factionPlayerList):
|
| | | GameWorld.DebugLog("当前不允许该镜像战斗请求! mapID=%s,funcLineID=%s" % (mapID, funcLineID), playerID)
|
| | | return
|
| | | playerID = curPlayer.GetPlayerID()
|
| | |
| | | else:
|
| | | isSysbg = True # 系统发起的默认后台战斗
|
| | |
|
| | | mirrorIDList = []
|
| | | for battleInfo in battlePlayerList:
|
| | | batPlayerID = battleInfo["playerID"]
|
| | | faction = battleInfo["faction"]
|
| | | if batPlayerID == playerID and faction == 1 and not isSysbg:
|
| | | # 自己不用,使用自身进行战斗即可
|
| | | continue
|
| | | if batPlayerID not in mirrorIDList:
|
| | | mirrorIDList.append(batPlayerID)
|
| | | |
| | | mirrorIDList = [] # 需要使用镜像的玩家ID列表
|
| | | for faction, batPlayerIDList in enumerate(factionPlayerList, 1):
|
| | | for batPlayerID in batPlayerIDList:
|
| | | if batPlayerID == playerID and faction == 1 and not isSysbg:
|
| | | # 自己不用,使用自身进行战斗即可
|
| | | continue
|
| | | if batPlayerID not in mirrorIDList:
|
| | | mirrorIDList.append(batPlayerID)
|
| | | |
| | | # 战斗相关的数据
|
| | | msgData = {"mapID":mapID, "funcLineID":funcLineID, "battlePlayerList":battlePlayerList, "isSysbg":isSysbg}
|
| | | msgData = {"mapID":mapID, "funcLineID":funcLineID, "factionPlayerList":factionPlayerList, "isSysbg":isSysbg}
|
| | |
|
| | | # 发送GameServer请求玩家打包数据
|
| | | requestTime = curTime # 请求的时间戳,每个玩家最多允许同时存在一场战斗,每次重新请求后覆盖数据
|
| | | requestMapID = GameWorld.GetGameWorld().GetRealMapID()
|
| | | sendMsg = str({"msgType":"MirrorBattle", "msgData":msgData, "mirrorIDList":mirrorIDList, |
| | | "requestTime":requestTime, "requestID":requestID, "requestMapID":requestMapID, "playerID":playerID})
|
| | | sceneMapID = GameWorld.GetGameWorld().GetRealMapID()
|
| | | sendMsg = {"msgType":"MirrorBattle", "msgData":msgData, "mirrorIDList":mirrorIDList, |
| | | "requestTime":requestTime, "requestID":requestID, "sceneMapID":sceneMapID, "playerID":playerID}
|
| | | |
| | | if isChangeMap:
|
| | | # 默认切到PK地图
|
| | | sendMsg["isChangeMap"] = 1
|
| | | PlayerControl.PlayerEnterFB(curPlayer, mapID, funcLineID, reqInfoEx=sendMsg)
|
| | | return True
|
| | | sendMsg = str(sendMsg)
|
| | | GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(0, 0, 0, "ReuestPlayerPackData", sendMsg, len(sendMsg))
|
| | | GameWorld.DebugLog("请求创建镜像战斗: %s" % sendMsg, playerID)
|
| | | return True
|
| | |
|
| | | def OnMirrorBattleEnterMapInit(curPlayer, tick):
|
| | | ''' 镜像战斗初始化 - 需要切图的,玩家切图成功或地图收到打包数据同步时会触发,即这两个条件都准备好后才开始初始化
|
| | | '''
|
| | | if not curPlayer or curPlayer.IsEmpty() or not curPlayer.GetMapLoadOK():
|
| | | return
|
| | | |
| | | battle = GetMirrorBattle(curPlayer)
|
| | | if battle:
|
| | | GameWorld.DebugLog("镜像战斗玩家断线重连成功!", curPlayer.GetPlayerID())
|
| | | curPlayer.SetDict(ChConfig.Def_PlayerKey_MirrorBattleID, battle.battleID)
|
| | | curPlayer.SetFaction(1)
|
| | | PlayerControl.SetPlayerSightLevel(curPlayer, battle.battleID)
|
| | | PlayerControl.SetSight(curPlayer, ChConfig.Def_PlayerSight_Default * 3)
|
| | | battle.SyncFBStepTime(tick)
|
| | | return
|
| | | |
| | | playerID = curPlayer.GetPlayerID()
|
| | | if playerID not in PyGameData.g_playerReqEnterFBEx:
|
| | | return
|
| | | msgInfo, packDataDict = PyGameData.g_playerReqEnterFBEx[playerID]
|
| | | OnMirrorBattleInit(msgInfo, packDataDict, curPlayer)
|
| | | return
|
| | |
|
| | | def OnMirrorBattleInit(msgInfo, packDataDict, curPlayer=None):
|
| | | ''' 镜像战斗初始化
|
| | |
| | |
|
| | | mapID = msgData.get("mapID", 0)
|
| | | funcLineID = msgData.get("funcLineID", 0)
|
| | | battlePlayerList = msgData.get("battlePlayerList", [])
|
| | | factionPlayerList = msgData.get("factionPlayerList", [])
|
| | | isSysbg = msgData.get("isSysbg", 0) # 系统后台战斗
|
| | |
|
| | | battleID = 0
|
| | |
| | | if not battle:
|
| | | GameWorld.ErrLog("镜像战场ID已存在! battleID=%s,msgInfo=%s" % (battleID, msgInfo), requestID)
|
| | | return
|
| | | battle.isChangeMap = msgInfo.get("isChangeMap", 0)
|
| | | GameWorld.DebugLog("镜像战斗初始化: msgData=%s,packIDList=%s" % (msgData, packDataDict.keys()), battleID)
|
| | |
|
| | | for battleInfo in battlePlayerList:
|
| | | batPlayerID = battleInfo["playerID"]
|
| | | posX = battleInfo.get("posX", 0)
|
| | | posY = battleInfo.get("posY", 0)
|
| | | faction = battleInfo.get("faction", 0)
|
| | | |
| | | if curPlayer and batPlayerID == playerID and faction == 1 and not isSysbg:
|
| | | battle.AddBattlePlayer(curPlayer, faction, posX, posY)
|
| | | continue
|
| | | |
| | | packData = packDataDict.get(batPlayerID)
|
| | | if not packData:
|
| | | GameWorld.ErrLog("初始化镜像战斗时没有玩家镜像数据! batPlayerID=%s" % batPlayerID, playerID)
|
| | | continue
|
| | | |
| | | CreateMirrorPlayer(battleID, batPlayerID, packData, posX, posY, faction, curPlayer)
|
| | | |
| | | battle.batState = ChConfig.Def_MirrorBatState_Prepare
|
| | | fightTimeLimitDict = IpyGameDataPY.GetFuncEvalCfg("MirrorAttack", 1, {})
|
| | | battle.fightTickMax = fightTimeLimitDict.get(str(mapID), 60) * 1000 # 最大战斗时长,默认60秒
|
| | | factionPosList = OnGetMirrorBattlePos(mapID, funcLineID, isSysbg)
|
| | | for faction, batPlayerIDList in enumerate(factionPlayerList, 1):
|
| | | posInfo = factionPosList[faction - 1]
|
| | | factionPosX, factionPosY = posInfo
|
| | | for index, batPlayerID in enumerate(batPlayerIDList):
|
| | | posX, posY = factionPosX, factionPosY + index * 5
|
| | | if curPlayer and batPlayerID == playerID and faction == 1 and not isSysbg:
|
| | | battle.AddBattlePlayer(curPlayer, faction, posX, posY)
|
| | | continue
|
| | | |
| | | packData = packDataDict.get(batPlayerID)
|
| | | if not packData:
|
| | | GameWorld.ErrLog("初始化镜像战斗时没有玩家镜像数据! batPlayerID=%s" % batPlayerID, playerID)
|
| | | continue
|
| | | |
| | | CreateMirrorPlayer(battleID, batPlayerID, packData, posX, posY, faction, curPlayer)
|
| | | |
| | | tick = GameWorld.GetGameWorld().GetTick()
|
| | | battle.ChangeBattleState(ChConfig.Def_MirrorBatState_Prepare, tick)
|
| | |
|
| | | if not isSysbg:
|
| | | return
|
| | |
| | | # 系统场默认直接开始、快速战斗结束
|
| | | OnMirrorBattleStart(battleID)
|
| | | DoMirrorBattleQuick(battleID)
|
| | | ClearMirrorBattleByID(battleID)
|
| | | return
|
| | |
|
| | | def OnGetMirrorBattlePos(mapID, lineID, isSysbg=False):
|
| | | if isSysbg:
|
| | | gameMap = GameWorld.GetMap()
|
| | | posX, posY = gameMap.GetRebornMapX(), gameMap.GetRebornMapY() # 系统战斗默认取当前地图的复活点
|
| | | factionPosList = [[posX, posY], [posX + 5, posY]]
|
| | | else:
|
| | | factionPosDict = IpyGameDataPY.GetFuncEvalCfg("MirrorAttack", 4, {})
|
| | | factionPosList = factionPosDict.get(mapID, [[10, 7], [40,37]])
|
| | | return factionPosList
|
| | |
|
| | | def OnMirrorBattleStart(battleID):
|
| | | ## 镜像战斗开始
|
| | |
| | | return
|
| | | if battle.batState >= ChConfig.Def_MirrorBatState_Fight:
|
| | | return
|
| | | battle.batState = ChConfig.Def_MirrorBatState_Fight
|
| | | battle.startTick = GameWorld.GetGameWorld().GetTick()
|
| | | tick = GameWorld.GetGameWorld().GetTick()
|
| | | battle.ChangeBattleState(ChConfig.Def_MirrorBatState_Fight, tick)
|
| | | return
|
| | |
|
| | | def ProcessPlayerMirrorAI(curPlayer, tick):
|
| | |
| | | battle = GetMirrorBattle(curPlayer)
|
| | | if not battle:
|
| | | return
|
| | | |
| | | playerID = curPlayer.GetPlayerID()
|
| | | realPlayerID = curPlayer.GetRealPlayerID()
|
| | | if realPlayerID:
|
| | | # 用第一个对手镜像玩家来定时判断战斗阶段,因为玩家自身可能会掉线,所以不用自己,而用镜像玩家
|
| | | if realPlayerID == battle.GetTagPlayerID():
|
| | | if battle.stateTick and battle.CaclStateTick(tick) <= 0:
|
| | | if battle.batState == ChConfig.Def_MirrorBatState_Prepare:
|
| | | OnMirrorBattleStart(battle.battleID)
|
| | | elif battle.batState == ChConfig.Def_MirrorBatState_Fight:
|
| | | OnMirrorAttackOver(battle.battleID)
|
| | | elif battle.batState == ChConfig.Def_MirrorBatState_Over:
|
| | | ClearMirrorBattleByID(battle.battleID)
|
| | | else:
|
| | | # 常规战斗下,真实玩家不处理,由玩家自行控制
|
| | | if not battle.isQuick:
|
| | | return
|
| | | |
| | | if battle.batState != ChConfig.Def_MirrorBatState_Fight:
|
| | | #GameWorld.DebugLog("镜像玩家仅自由战斗状态下需要处理! battleID=%s,batState=%s" % (battle.battleID, battle.batState), playerID)
|
| | | return
|
| | |
|
| | | if not battle.isQuick:
|
| | | realPlayerID = curPlayer.GetRealPlayerID()
|
| | | if not realPlayerID:
|
| | | # 常规战斗下,真实玩家不处理,由玩家自行控制
|
| | | # 真实玩家附加判断是否PK超时
|
| | | if battle.startTick and battle.CaclFightTick(tick) <= 0:
|
| | | OnMirrorAttackOver(battle.battleID)
|
| | | return
|
| | | |
| | | if GameObj.GetHP(curPlayer) <= 0:
|
| | | #GameWorld.DebugLog("镜像玩家已被击杀", playerID)
|
| | | return
|
| | |
|
| | | # 攻击间隔
|
| | | if tick - curPlayer.GetPlayerAttackTick() < curPlayer.GetAtkInterval():
|
| | | GameWorld.DebugLog("攻击间隔: %s < %s" % (tick - curPlayer.GetPlayerAttackTick(), curPlayer.GetAtkInterval()), playerID)
|
| | | #GameWorld.DebugLog("攻击间隔: %s < %s" % (tick - curPlayer.GetPlayerAttackTick(), curPlayer.GetAtkInterval()), playerID)
|
| | | return
|
| | |
|
| | | autoUseSkillList = battle.GetPlayerAutoUseSkillList(curPlayer)
|
| | | GameWorld.DebugLog("镜像AI攻击: autoUseSkillList=%s" % (autoUseSkillList), playerID)
|
| | | #GameWorld.DebugLog("镜像AI攻击: autoUseSkillList=%s" % (autoUseSkillList), playerID)
|
| | |
|
| | | if curPlayer.GetPlayerVehicle() == IPY_GameWorld.pvHorse:
|
| | | PlayerHorse.PlayerRideHorseDown(curPlayer)
|
| | |
| | | curPlayer.SetUseSkill(curSkill.GetSkillData())
|
| | | useSkillData = curPlayer.GetUseSkill()
|
| | | if not PlayerState.__DoClientUseSkillEx(curPlayer, useSkillData, tick):
|
| | | GameWorld.DebugLog(" 技能攻击失败: playerID=%s,tagID=%s,skillID=%s" % (playerID, tagObjID, skillID))
|
| | | #GameWorld.DebugLog(" 技能攻击失败: playerID=%s,tagID=%s,skillID=%s" % (playerID, tagObjID, skillID))
|
| | | continue
|
| | | useSkillResult = True
|
| | | GameWorld.DebugLog(" 技能攻击成功: playerID=%s,tagID=%s,skillID=%s" % (playerID, tagObjID, skillID))
|
| | | #GameWorld.DebugLog(" 技能攻击成功: playerID=%s,tagID=%s,skillID=%s" % (playerID, tagObjID, skillID))
|
| | |
|
| | | if useSkillData and useSkillData.GetSkillID() != ChConfig.Def_SkillID_Somersault:
|
| | | # 跟随玩家同频率攻击
|
| | |
| | | battle = GetMirrorBattleByID(battleID)
|
| | | if not battle:
|
| | | return
|
| | | if battle.batState > ChConfig.Def_MirrorBatState_Fight:
|
| | | if battle.batState != ChConfig.Def_MirrorBatState_Fight:
|
| | | return
|
| | | if battle.isQuick:
|
| | | #不重复触发处理
|
| | |
| | | if mapID in quickLimitMapIDList:
|
| | | GameWorld.DebugLog("战斗中不允许点击快速战斗! mapID=%s" % mapID, battle.playerID)
|
| | | return
|
| | | if isLogout:
|
| | | logoutQuickLimitMapIDList = IpyGameDataPY.GetFuncEvalCfg("MirrorAttack", 3)
|
| | | if mapID in logoutQuickLimitMapIDList:
|
| | | GameWorld.DebugLog("掉线不允许快速战斗! mapID=%s" % mapID, battle.playerID)
|
| | | return
|
| | | tick = GameWorld.GetGameWorld().GetTick()
|
| | | battle.batState = ChConfig.Def_MirrorBatState_Fight
|
| | | battle.isQuick = True
|
| | | battle.isLogout = isLogout
|
| | | battle.CaclFightTick(tick)
|
| | | battle.CaclStateTick(tick)
|
| | |
|
| | | playerMgr = GameWorld.GetMapCopyPlayerManager()
|
| | | perLoopTick = 100 # 每次循环视为已过毫秒
|
| | | maxLoopCount = battle.fightTickRemain / perLoopTick # 循环次数上限
|
| | | GameWorld.DebugLog("DoMirrorBattleQuick isLogout=%s,maxLoopCount=%s,tick=%s,fightTickRemain=%s" |
| | | % (isLogout, maxLoopCount, tick, battle.fightTickRemain), battleID)
|
| | | maxLoopCount = battle.stateTickRemain / perLoopTick # 循环次数上限
|
| | | GameWorld.DebugLog("镜像PK快速结算: isLogout=%s,maxLoopCount=%s,tick=%s,stateTickRemain=%s" |
| | | % (isLogout, maxLoopCount, tick, battle.stateTickRemain), battleID)
|
| | |
|
| | | # 屏蔽发包
|
| | | for batPlayerID in battle.realIDDict.keys():
|
| | |
| | | # 可能还没循环完毕就结束了
|
| | | break
|
| | | tick += perLoopTick # 修改每次循环的tick
|
| | | battle.CaclFightTick(tick)
|
| | | GameWorld.DebugLog(" loopCount=%s,tick=%s,fightTickRemain=%s" % (loopCount, tick, battle.fightTickRemain), battleID)
|
| | | #GameWorld.DebugLog(" loopCount=%s,tick=%s,stateTickRemain=%s" % (loopCount, tick, battle.stateTickRemain), battleID)
|
| | | for batPlayerID in battle.playerFactionDict.keys():
|
| | | if batPlayerID in battle.deadPlayerIDList:
|
| | | continue
|
| | |
| | | if battle.batState >= ChConfig.Def_MirrorBatState_Over:
|
| | | # 已经结算过
|
| | | return
|
| | | battle.batState = ChConfig.Def_MirrorBatState_Over
|
| | | tick = GameWorld.GetGameWorld().GetTick()
|
| | | if not battle.fightTickRemain:
|
| | | battle.CaclFightTick(tick)
|
| | | if not battle.stateTickRemain:
|
| | | battle.CaclStateTick(tick)
|
| | | # 暂定没击杀算输,发起方为1
|
| | | if not battle.winFaction:
|
| | | battle.winFaction = 2
|
| | |
| | | curPlayer.SetDead(curPlayer.GetDictByKey(ChConfig.Def_NPCDead_KillerID),
|
| | | curPlayer.GetDictByKey(ChConfig.Def_NPCDead_KillerType))
|
| | |
|
| | | #统计明细
|
| | | for playerID, faction in battle.playerFactionDict.items():
|
| | | player = playerMgr.FindPlayerByID(playerID)
|
| | | if not player:
|
| | | continue
|
| | | realPlayerID = player.GetRealPlayerID()
|
| | | hp = GameObj.GetHP(player)
|
| | | hpMax = GameObj.GetMaxHP(player)
|
| | | |
| | | GameWorld.DebugLog("剩余血量: %s/%s, 护盾:%s/%s,playerID=%s,realPlayerID=%s,faction=%s" |
| | | % (hp, hpMax, PlayerControl.GetProDef(player), PlayerControl.GetMaxProDef(player), playerID, realPlayerID, faction), battleID)
|
| | | if faction == 1:
|
| | | battle.curHP += hp
|
| | | battle.curHPMax += hpMax
|
| | | else:
|
| | | battle.tagHP += hp
|
| | | battle.tagHPMax += hpMax
|
| | | |
| | | FBLogic.OnMirrorBattleOver(battleID, mapID)
|
| | |
|
| | | if battle.isSysbg:
|
| | | ClearMirrorBattleByID(battleID)
|
| | | # 改变状态需放在最后
|
| | | battle.ChangeBattleState(ChConfig.Def_MirrorBatState_Over, tick)
|
| | | return
|
| | |
|
| | | def DoPlayerLeaveFB(curPlayer, tick):
|
| | | ##玩家主动离开副本
|
| | | if curPlayer.GetRealPlayerID():
|
| | | return
|
| | | battle = GetMirrorBattle(curPlayer)
|
| | | if not battle:
|
| | | return
|
| | | GameWorld.DebugLog("玩家主动退出镜像战斗强制快速结算战斗!", curPlayer.GetPlayerID())
|
| | | DoQuickOverByExit(curPlayer)
|
| | | return
|
| | |
|
| | | def DoExitFB(curPlayer, tick):
|
| | | ##玩家退出副本
|
| | | if curPlayer.GetRealPlayerID():
|
| | | return
|
| | | battle = GetMirrorBattle(curPlayer)
|
| | | if not battle:
|
| | | return
|
| | | # 退出时还有战场数据一般是掉线的,因为主动退出默认强制结算
|
| | | mapID = battle.mapID
|
| | | logoutQuickLimitMapIDList = IpyGameDataPY.GetFuncEvalCfg("MirrorAttack", 3)
|
| | | if mapID in logoutQuickLimitMapIDList:
|
| | | GameWorld.DebugLog("掉线不允许快速战斗! mapID=%s" % mapID, battle.playerID)
|
| | | return
|
| | | GameWorld.DebugLog("玩家掉线退出镜像战斗快速结算战斗!", curPlayer.GetPlayerID())
|
| | | DoQuickOverByExit(curPlayer)
|
| | | return
|
| | |
|
| | | def DoQuickOverByExit(curPlayer):
|
| | | ## 执行退出快速结算
|
| | | |
| | | battle = GetMirrorBattle(curPlayer)
|
| | | if not battle:
|
| | | return
|
| | | |
| | | battleID = battle.battleID
|
| | | if battle.batState < ChConfig.Def_MirrorBatState_Fight:
|
| | | OnMirrorBattleStart(battleID) # 还未开始则强制开始
|
| | | |
| | | # 如果还在战斗中,直接快速执行战斗结果
|
| | | if battle.batState == ChConfig.Def_MirrorBatState_Fight:
|
| | | DoMirrorBattleQuick(battle.battleID, isLogout=True)
|
| | | |
| | | ClearMirrorBattleByID(battleID) |
| | | return
|