local EventSystem = require('Event/EventSystem') local Base = require("Battle/Logic/Level/LevelFunction/SyncLevelFunction") local SyncSoloLevelFunction = class("SyncSoloLevelFunction",Base) local battle_match_pb = require 'Proto/battle_match_pb' function SyncSoloLevelFunction:BeginLevel() self.dontStartAutoFightWhenPlayerOffline = true Base.BeginLevel(self) --如果是在重新进入的时,需要让玩家重新active if not MultiplayManager.IsFromStartEnter then MultiplayManager.SetAllRolesActive() -- 这个代码只有在 重登游戏时直接进入1v1时会出现 end local playerInfo = nil local entities = nil for i,playerID in ipairs(LevelPlayerManager.SyncPlayerIDList) do playerInfo = LevelPlayerManager.GetPlayerInfoByPlayerIDInRoom(playerID) if playerInfo.fighterType == LuaConst.BattleMemberType.Robot_Hero then entities = LevelPlayerManager.GetPlayerEntitysByPlayerIDInRoom(playerID) self:StartAutoFight(entities[1]) --机器人默认开启AI if playerInfo.isGuideRobot then -- 训练机器人要改下名字 self.exp:SetPracticeRobotName(playerID) end end end self.damageDic = {} end function SyncSoloLevelFunction:CreatePlayers() Base.CreatePlayers(self) --主视角视图代码↓ 应该搞个exp,移动到exp里去 local enemyPlayerID = LevelPlayerManager.MyPlayerIDInRoom == 1 and 2 or 1 local enemyEntities = LevelPlayerManager.GetPlayerEntitysByPlayerIDInRoom(enemyPlayerID) SystemManager.SetCameraTarget(enemyEntities[1]) -- ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ end function SyncSoloLevelFunction:GetRobotAI(entity) -- old↓ 玩家自动战斗AI设置成了idle -- local playerInfo = LevelPlayerManager.GetPlayerInfoByPlayerIDInRoom(entity:GetPlayerID()) -- if playerInfo.fighterType == LuaConst.BattleMemberType.Robot_Hero then -- return LuaConst.SoloFightAIID -- else -- return LuaConst.IdleAIID -- end -- old↑ -- new↓ 玩家/机器人的自动战斗AI都设为 LuaConst.SoloFightAIID return LuaConst.SoloFightAIID end function SyncSoloLevelFunction:OnUpdate() Base.OnUpdate(self) if self.sendResultFrame and self.sendResultFrame <= LogicUpdateManager._clientHandleFrame then self:SendResultImmediately() end end function SyncSoloLevelFunction:OnHpChange(entity, caster, delta, op) --不调用Base if op == "sub" and delta < FP.Const.Zero then caster = caster:GetMasterEntity() or caster if caster:IsHero() then self.damageDic[caster.EntityID] = self.damageDic[caster.EntityID] or FP.newV1(0) self.damageDic[caster.EntityID] = self.damageDic[caster.EntityID]:Add(-delta) end end end function SyncSoloLevelFunction:OnSwitchHero(fromEntity, toEntity) Base.OnSwitchHero(self, fromEntity, toEntity) --主视角视图代码↓ 应该搞个exp,移动到exp里去 if not toEntity:IsPlayerSelf() then SystemManager.SetCameraTarget(toEntity, fromEntity) end -- ↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ end function SyncSoloLevelFunction:DelaySendResult() self.sendResultFrame = LogicUpdateManager._clientHandleFrame + 60 --hard code 延迟60帧发送结果 end function SyncSoloLevelFunction:SendResultImmediately(quitRoomEntity, dontStopLevel) self.sendResultFrame = nil self:SendBattleResult(quitRoomEntity) if not dontStopLevel then self:StopLevel() end end function SyncSoloLevelFunction:OnPlayerAllHeroDead(entity) -- old↓ -- --不调用Base -- self:SendBattleResult() -- self:StopLevel() --old↑ --new 新增机制:当某一队死亡后,给另一队添加无敌buff,避免平局↓ local winnerPlayerId = entity:GetPlayerID() == 1 and 2 or 1 local entities = LevelPlayerManager.GetPlayerEntitysByPlayerIDInRoom(winnerPlayerId) for i,_entity in ipairs(entities) do SystemManager.AddBuff(_entity, 500001, _entity) end --↑ self:DelaySendResult() end function SyncSoloLevelFunction:OnLevelSucceed() --这里由关卡事件触发,直接发送结果就行 self:SendResultImmediately(nil, true) Base.OnLevelSucceed(self) end function SyncSoloLevelFunction:OnLevelFail() --这里由关卡事件触发,直接发送结果就行 self:SendResultImmediately(nil, true) Base.OnLevelSucceed(self) end function SyncSoloLevelFunction:GetHeroKillNumByEntity(entity) local statistic = self.PlayerStatisticDic[entity:GetPlayerID()] if statistic then local heroKillNumKey = LuaConst.EStatisticType.Hero1KillNum + LevelPlayerManager.GetHeroArmyPos(entity:GetPlayerID(), entity:GetCharacterID()) return statistic[heroKillNumKey] or 0 else return 0 end end function SyncSoloLevelFunction:GetHeroDamage(entity) return self.damageDic[entity.EntityID] and FP.tonumberV1(self.damageDic[entity.EntityID]) or 0 end --↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑↑ function SyncSoloLevelFunction:QuitRoom(entity) --不调用base if entity ~= LogicUpdateManager._curEntity then --主视角safe 纯视图代码 --如果退出房间的是对面的,就弹个tips说对面认输 EventSystem.Dispatch(EventID.UI_MainShowTips, UIUtils.GetLocalizedTxt(Const_IDS.IDS_1v1Sync_PlayerQuit)) end self:SendResultImmediately(entity) end function SyncSoloLevelFunction:FillFighterRecords(fighterRecords, playerID) local playerInfo = LevelPlayerManager.GetPlayerInfoByPlayerIDInRoom(playerID) local entities = LevelPlayerManager.GetPlayerEntitysByPlayerIDInRoom(playerID) local sortedEntities = {} --运营要求排序 for i,entity in ipairs(entities) do sortedEntities[i] = entity end table.sort(sortedEntities, function(a, b) return a.EntityID < b.EntityID end) self.playerID2DeadHeroDic[playerID] = {} fighterRecords.playerId = playerID fighterRecords.serId = playerInfo.serId local hplmtTotal = FP.newV1(0) local hpTotal = FP.newV1(0) fighterRecords.aliveHero = 0 fighterRecords.leftTotalHp = 0 for i,entity in ipairs(sortedEntities) do table.insert(fighterRecords.killNum, self:GetHeroKillNumByEntity(entity)) table.insert(fighterRecords.damage, math.ceil(self:GetHeroDamage(entity))) local leftHp = FP.tonumberV1(entity.components.attr:HitPointPercents()) if leftHp <= 0.001 then if entity:IsAlive() then leftHp = 0.001 end end table.insert(fighterRecords.leftHp, leftHp) fighterRecords.leftTotalHp = fighterRecords.leftTotalHp + fighterRecords.leftHp[i] hplmtTotal:Add(entity.components.attr:GetAttrValue(LuaConst.AttrType.hplmt)) hpTotal:Add(entity.components.attr:GetAttrValue(LuaConst.RealtimeAttrType.hp)) if entity:IsAlive() then fighterRecords.aliveHero = fighterRecords.aliveHero + 1 else table.insert(self.playerID2DeadHeroDic[playerID], entity:GetCharacterID()) end end fighterRecords.fighterName = playerInfo.name end function SyncSoloLevelFunction:OnIllusionDead(entity) self.exp:OnIllusionDead(entity) end function SyncSoloLevelFunction:OnVisiblityChanged(entity, oldLv, oldGroup) if entity.isHero then ExpSystemManager.TryRecoverMyCameraLock(entity, true) end end function SyncSoloLevelFunction:SendBattleResult(quitRoomEntity) local msg = battle_match_pb.C2GUploadSyncSoloBattleResult() local enemyPlayerID = LevelPlayerManager.MyPlayerIDInRoom == 1 and 2 or 1 self.playerID2DeadHeroDic = {} --key是playerID, value是一个list,记录了这个玩家死过的英雄id, 用来给外部查询 self:FillFighterRecords(msg.ourFighterRecords, LevelPlayerManager.MyPlayerIDInRoom) self:FillFighterRecords(msg.enemyFighterRecords, enemyPlayerID) msg.checkInfo = self:GetBattleResultCheckStr() msg.passTime = math.floor(LogicUpdateManager._clientHandleFrame * LuaConst.TimeSpan) -- 时间:秒(和结算界面显示的要一致) local myPlayerInfo = LevelPlayerManager.GetPlayerInfoByPlayerIDInRoom(LevelPlayerManager.MyPlayerIDInRoom) local myCampID = myPlayerInfo.campID local enemyPlayerInfo = LevelPlayerManager.GetPlayerInfoByPlayerIDInRoom(enemyPlayerID) local enemyCampID = enemyPlayerInfo.campID if quitRoomEntity then --如果有人中途就退出了,视为投降,直接判负 msg.winnerCampId = quitRoomEntity:IsPlayerSelf() and enemyCampID or myCampID else if msg.enemyFighterRecords.leftTotalHp >= 3 and msg.ourFighterRecords.leftTotalHp >= 3 then msg.winnerCampId = 0 --双方都满血,算作双方都失败 else if msg.ourFighterRecords.aliveHero == msg.enemyFighterRecords.aliveHero then --如果存活武将数量相等,判断血量 if msg.ourFighterRecords.leftTotalHp == msg.enemyFighterRecords.leftTotalHp then if enemyPlayerInfo.fighterType ~= LuaConst.BattleMemberType.Account_Hero then --如果敌方是机器人,则算玩家胜利 msg.winnerCampId = myCampID else --如果两个玩家最后血量相等,比较伤害量 local dmgDelta = 0 for i,dmg in ipairs(msg.ourFighterRecords.damage) do dmgDelta = dmgDelta + dmg end for i,dmg in ipairs(msg.enemyFighterRecords.damage) do dmgDelta = dmgDelta - dmg end if dmgDelta ~= 0 then if dmgDelta > 0 then msg.winnerCampId = myCampID elseif dmgDelta then msg.winnerCampId = enemyCampID end else --如果两个玩家最后血量相等、伤害量相等,算camp1胜利(实际就是随机) msg.winnerCampId = 1 end end else msg.winnerCampId = msg.ourFighterRecords.leftTotalHp > msg.enemyFighterRecords.leftTotalHp and myCampID or enemyCampID end else --如果存活武将数量不相等,直接判断存活武将数量 msg.winnerCampId = msg.ourFighterRecords.aliveHero > msg.enemyFighterRecords.aliveHero and myCampID or enemyCampID end end end self.winnerCampId = msg.winnerCampId --存起来方便其他地方查询 if USE_LUA_STANDALONE then -- 服务器校验时 ,需要的字符串要设置好 BattleSimulator.SetCheckResult(msg.checkInfo, msg:SerializeToString()) end if LogicUpdateManager.IsReplayOrServerCheck then -- 客户端重播或服务器校验的话,不要发送TCP logging.log(LTAG.LOG, "[GWS]SyncSolo BattleCheckStr = :",msg.checkInfo) BattleSimulator.EndPlay() if LevelManager.IsReplayBattle() then return end end EventSystem.Dispatch(EventID.SyncSolo_BattleResult,msg) end return SyncSoloLevelFunction