local world_boss_pb = require('Proto/world_boss_pb') local EventSystem = require('Event/EventSystem') local Base = require("Battle/Logic/Level/LevelFunction/SyncWorldBossLevelFunction") --战区世界boss 大部分的功能都跟世界boss一样 local SyncWarZoneWorldBossLevelFunction = class("SyncWarZoneWorldBossLevelFunction",Base) local KillConditionInFrame = DataSheetManager.ConstData:GetDataByID("WarZoneWorldBossKillCondition") and DataSheetManager.ConstData:GetDataByID("WarZoneWorldBossKillCondition").IntValue * LuaConst.LogicFrameRate or nil function SyncWarZoneWorldBossLevelFunction:GetExpClass() return require "Battle/Expression/ExpLevel/ExpLevelFunction/ExpSyncWarZoneWorldBossLevelFunction" end function SyncWarZoneWorldBossLevelFunction:InitLevel() Base.InitLevel(self) self.curOccupierPlayerID = nil --当前占领的玩家ID ,为空表示无人占领 self.curOccupierStartFrame = nil --当前玩家开始占领的帧数 ,为空表示无人占领 self.occupyRecordList = {} --玩家占领信息列表 元素是table = {playerID, occupyFrameCount, teamId} --occupyFrameCount是占领时长(单位:帧数) self.occupyRankList = {} --队伍占领排名列表,按名次排序,元素是table = {teamId, occupyFrameCount, teamRecordList, teamLeaderName, hasTeam, guildName, guildEmblemContent, guildEmblemFrame} self.dieOccupyFrameFactor = 1 - (DataSheetManager.ConstData:GetDataByID("WarZoneBossDeathPunish").IntValue / 100) end function SyncWarZoneWorldBossLevelFunction:GetHeroKillInvolvedTimeLimitFrame() return KillConditionInFrame or -1 --战区boss默认没有助攻,所以填负数。填负数的效果就是任何情况都不可能被判定为助攻 end function SyncWarZoneWorldBossLevelFunction:OnPlayerActived(playerID) Base.OnPlayerActived(self, playerID) self.exp:RefreshNo1Icon() end function SyncWarZoneWorldBossLevelFunction:GetAssistAimPlayerInfo(playerInfo) if not string.isNilOrEmpty(playerInfo.assisAimAcid) then return LevelPlayerManager.GetPlayerInfoByAcid(playerInfo.assisAimAcid) end end function SyncWarZoneWorldBossLevelFunction:SetCurOccupierPlayerID(playerID) if self.curOccupierPlayerID ~= playerID then local oldOccupierPlayerID = self.curOccupierPlayerID self.curOccupierPlayerID = playerID if self.curOccupierPlayerID then self:TryInitPlayerRecordHpDic(self.curOccupierPlayerID) end self:OnOccupierChanged(oldOccupierPlayerID, playerID) EventSystem.Dispatch(EventID.UI_CountryWorldBoss_UpdateOccupierInfo) end end function SyncWarZoneWorldBossLevelFunction:GetCurOccupierPlayerID() return self.curOccupierPlayerID end function SyncWarZoneWorldBossLevelFunction:CreateRecord(playerID) local record = {playerID = playerID, occupyFrameCount = 0, occupyFrameCountBefore = 0} local playerInfo = LevelPlayerManager.GetPlayerInfoByPlayerIDInRoom(playerID) if playerInfo then record.playerInfo = playerInfo record.teamId = playerInfo.teamId else logging.error(LTAG.ERROR, "HYW : 致命错误! 找不到playerInfo!") end table.insert(self.occupyRecordList, record) return record end function SyncWarZoneWorldBossLevelFunction:GetOccupyRecordByPlayerID(playerID) for i,record in ipairs(self.occupyRecordList) do if record.playerID == playerID then return record end end end function SyncWarZoneWorldBossLevelFunction:GetOccupyFrameCountOfTeam(teamId) local frameCount = 0 for i,record in ipairs(self.occupyRecordList) do if record.teamId == teamId then frameCount = frameCount + record.occupyFrameCount end end if self.curOccupierTeamId == teamId then frameCount = frameCount + LogicUpdateManager._clientHandleFrame - self.curOccupierStartFrame end return frameCount end local occupyRankListSorter = function(a, b) if a.occupyFrameCount ~= b.occupyFrameCount then return a.occupyFrameCount > b.occupyFrameCount else local minPlayerIDOfA for i,record in ipairs(a.teamRecordList) do if minPlayerIDOfA == nil or minPlayerIDOfA > record.playerID then minPlayerIDOfA = record.playerID end end local minPlayerIDOfB for i,record in ipairs(b.teamRecordList) do if minPlayerIDOfB == nil or minPlayerIDOfB > record.playerID then minPlayerIDOfB = record.playerID end end return minPlayerIDOfA < minPlayerIDOfB end end function SyncWarZoneWorldBossLevelFunction:GetOccupyRankList() return self.occupyRankList end function SyncWarZoneWorldBossLevelFunction:GetTeamRank(teamId) for i,_rank in ipairs(self.occupyRankList) do if _rank.teamId == teamId then return _rank, i end end end function SyncWarZoneWorldBossLevelFunction:RefreshCurOccupierRankList() if self.curOccupierTeamId then local rank, index = self:GetTeamRank(self.curOccupierTeamId) if rank then local curRecord = self:GetOccupyRecordByPlayerID(self.curOccupierPlayerID) curRecord.occupyFrameCount = curRecord.occupyFrameCountBefore + LogicUpdateManager._clientHandleFrame - self.curOccupierStartFrame rank.occupyFrameCount = 0 for i,record in ipairs(rank.teamRecordList) do rank.occupyFrameCount = rank.occupyFrameCount + record.occupyFrameCount end if index > 1 then --如果不是第一名 for i=1,index-1 do local _rank = self.occupyRankList[i] local needInsert = false if rank.occupyFrameCount > _rank.occupyFrameCount then needInsert = true elseif rank.occupyFrameCount == _rank.occupyFrameCount then local minPlayerIDOfA for i,record in ipairs(rank.teamRecordList) do if minPlayerIDOfA == nil or minPlayerIDOfA > record.playerID then minPlayerIDOfA = record.playerID end end local minPlayerIDOfB for i,record in ipairs(_rank.teamRecordList) do if minPlayerIDOfB == nil or minPlayerIDOfB > record.playerID then minPlayerIDOfB = record.playerID end end needInsert = minPlayerIDOfA < minPlayerIDOfB end if needInsert then table.remove(self.occupyRankList, index) table.insert(self.occupyRankList, i, rank) self.exp:RefreshNo1Icon() break end end end else logging.error(LTAG.ERROR, "HYW : rank of self.curOccupierTeamId nil Error! @RefreshCurOccupierRankList") end end end function SyncWarZoneWorldBossLevelFunction:RefreshOccupyRankByOccupyRecord(occupyRecord) local rank = self:GetTeamRank(occupyRecord.teamId) if not rank then rank = { teamId = occupyRecord.teamId, teamRecordList = {occupyRecord}, } local playerInfo = LevelPlayerManager.GetPlayerInfoByPlayerIDInRoom(occupyRecord.playerID) rank.teamLeaderName = playerInfo.teamLeaderName rank.hasTeam = playerInfo.teamId ~= playerInfo.playerID self:TryFillTeamLeaderInfoOfRank(rank, playerInfo) table.insert(self.occupyRankList, rank) end local exist = false rank.occupyFrameCount = 0 for j,_record in ipairs(rank.teamRecordList) do rank.occupyFrameCount = rank.occupyFrameCount + _record.occupyFrameCount if _record == occupyRecord then exist = true end end if not exist then table.insert(rank.teamRecordList, occupyRecord) rank.occupyFrameCount = rank.occupyFrameCount + occupyRecord.occupyFrameCount end table.sort(self.occupyRankList, occupyRankListSorter) self.exp:RefreshNo1Icon() end function SyncWarZoneWorldBossLevelFunction:TryFillTeamLeaderInfoOfRankList() --尝试刷新RankList里面的队长信息,包括军团名、军团徽记等等 for i,rank in ipairs(self.occupyRankList) do if #rank.teamRecordList > 0 then self:TryFillTeamLeaderInfoOfRank(rank, rank.teamRecordList[1].playerInfo) end end end function SyncWarZoneWorldBossLevelFunction:TryFillTeamLeaderInfoOfRank(rank, anyPlayerInfo) if not rank.guildName then --如果没有填充过信息才尝试填充 local teamLeaderPlayerID if rank.hasTeam then local teamLeader = LevelPlayerManager.GetTeamLeaderByTeamId(anyPlayerInfo.teamId) if teamLeader then teamLeaderPlayerID = teamLeader:GetPlayerID() end else teamLeaderPlayerID = anyPlayerInfo.playerID end if teamLeaderPlayerID then local teamLeaderPlayerInfo = LevelPlayerManager.GetPlayerInfoByPlayerIDInRoom(teamLeaderPlayerID) rank.guildName = teamLeaderPlayerInfo.guildName rank.guildEmblemContent = teamLeaderPlayerInfo.guildEmblemContent rank.guildEmblemFrame = teamLeaderPlayerInfo.guildEmblemFrame end end end function SyncWarZoneWorldBossLevelFunction:RemoveOccupyRankOfTeam(teamId) for i,rank in ipairs(self.occupyRankList) do if rank.teamId == teamId then table.remove(self.occupyRankList, i) break end end end --old 老版战区boss不用记录伤害,但在2022年11月2日后,新版战区boss加了国战规则,需要记录伤害了 -- function SyncWarZoneWorldBossLevelFunction:RefreshDamageList() -- --不调用Base,覆盖Base -- --do nothing -- end --old↑ function SyncWarZoneWorldBossLevelFunction:OnUpdate() Base.OnUpdate(self) if self.curOccupierPlayerID then self:RefreshCurOccupierRankList() end end function SyncWarZoneWorldBossLevelFunction:OnHpChange(entity, caster, delta, op) Base.OnHpChange(self, entity, caster, delta, op) if self.isResultSent then --如果发送过结果了,则不再统计HpChange return end if not entity or not caster then return end --如果是自己给自己造成伤害,直接return if entity == caster then return end if entity:IsBoss() then if delta < FP.Const.Zero then if caster and caster:IsActive() and caster:IsAlive() then local originEntity = caster:GetOriginEntity() if originEntity:IsHero() and originEntity:IsActive() and originEntity:IsAlive() then local playerID = originEntity:GetPlayerID() if self.canHurtBossDic[playerID] then if self.curOccupierPlayerID == nil then --无占领状态下对boss造成了伤害,需要进行占领者变更判定 self:SetCurOccupierPlayerID(originEntity:GetPlayerID()) else if not self:GetOccupyRecordByPlayerID(originEntity:GetPlayerID()) then local record = self:CreateRecord(originEntity:GetPlayerID()) self:RefreshOccupyRankByOccupyRecord(record) end end end end end end end end function SyncWarZoneWorldBossLevelFunction:SendBIWorldBossBeKilled(killerName, decOccupyTime, occupyTime) --不调用base if decOccupyTime and occupyTime then EventSystem.Dispatch(EventID.BI_LevelHigh,BIManager.BIType.WorldBossBeKilled, killerName, decOccupyTime, occupyTime) --else --do nothing 正常情况 end end function SyncWarZoneWorldBossLevelFunction:HandleHeroDead(deadEntity, killer) Base.HandleHeroDead(self, deadEntity, killer) if deadEntity:GetPlayerID() == self.curOccupierPlayerID and self.curOccupierPlayerID then --如果占领者被杀死 if deadEntity == killer then --如果是自杀,则直接置为无占领状态(存在自杀的情况,比如毒王鼎) self:SetCurOccupierPlayerID(nil) else if killer then --好像有些情况关卡会杀Hero,且这种情况下KillerEntity为空,所以这里要判空 local originKiller = killer:GetOriginEntity() if originKiller:IsHero() and originKiller:IsActive() and originKiller:IsAlive() then local playerInfo = LevelPlayerManager.GetPlayerInfoByPlayerIDInRoom(originKiller:GetPlayerID()) if self:IsAssitant(playerInfo) then local assistTargetPlayerInfo = self:GetAssistAimPlayerInfo(playerInfo) local assistTargetEntity = nil if assistTargetPlayerInfo and self:CanHurtBoss(assistTargetPlayerInfo) then assistTargetEntity = LevelPlayerManager.GetPlayerActiveEntity(assistTargetPlayerInfo.playerID) end if assistTargetEntity and assistTargetEntity:IsActive() and assistTargetEntity:IsAlive() then self:SetCurOccupierPlayerID(assistTargetPlayerInfo.playerID) else self:SetCurOccupierPlayerID(nil) end else if self:CanHurtBoss(playerInfo) then self:SetCurOccupierPlayerID(playerInfo.playerID) else self:SetCurOccupierPlayerID(nil) end end else self:SetCurOccupierPlayerID(nil) end else self:SetCurOccupierPlayerID(nil) end end end local record = self:GetOccupyRecordByPlayerID(deadEntity:GetPlayerID()) if killer then local originKiller = killer:GetOriginEntity() local killerPlayerInfo = LevelPlayerManager.GetPlayerInfoByPlayerIDInRoom(originKiller:GetPlayerID()) local killerName if killerPlayerInfo then killerName = killerPlayerInfo.name elseif originKiller:IsBoss() then killerName = "boss-" .. tostring(originKiller.components.base.CurCharacterData.ID) else killerName = tostring(originKiller.components.base.CurCharacterData.ID) end if record then local oldFrameCount = record.occupyFrameCount record.occupyFrameCount = math.floor(record.occupyFrameCount * self.dieOccupyFrameFactor) if deadEntity:IsPlayerSelf() then --主视角safe 纯dispatch给UI self:SendBIWorldBossBeKilled(killerName, oldFrameCount - record.occupyFrameCount, record.occupyFrameCount) end self:RefreshOccupyRankByOccupyRecord(record) else if deadEntity:IsPlayerSelf() then --主视角safe 纯dispatch给UI self:SendBIWorldBossBeKilled(killerName, 0, 0) end end end end function SyncWarZoneWorldBossLevelFunction:QuitRoom(entity) --↓ 这段要先调 if entity:GetPlayerID() == self.curOccupierPlayerID then self:SetCurOccupierPlayerID(nil) end local playerID = entity:GetPlayerID() for i,record in ipairs(self.occupyRecordList) do if record.playerID == playerID then table.remove(self.occupyRecordList, i) break end end local rank, index = self:GetTeamRank(entity:GetTeamID()) if rank then for i,record in ipairs(rank.teamRecordList) do if record.playerID == playerID then rank.occupyFrameCount = rank.occupyFrameCount - record.occupyFrameCount table.remove(rank.teamRecordList, i) if #rank.teamRecordList == 0 then table.remove(self.occupyRankList, index) end break end end if #self.occupyRankList > 0 then if #rank.teamRecordList <= 0 then self.exp:HideNo1IconOfTeam(entity:GetTeamID()) end self.exp:RefreshNo1Icon() else self.exp:HideNo1IconOfTeam(entity:GetTeamID()) end end --↑ 这段要先调 Base.QuitRoom(self, entity) end function SyncWarZoneWorldBossLevelFunction:GetCheckStr() --不调用base local checkStr = "-"-- 服务器认为""有特殊含义, 所以不能为"" for i,rank in ipairs(self.occupyRankList) do for j,record in ipairs(rank.teamRecordList) do local entities = LevelPlayerManager.GetPlayerEntitysByPlayerIDInRoom(record.playerID) for m,entity in ipairs(entities) do checkStr = checkStr .. self:GetBattleResultCheckStrOfEntity(entity) end checkStr = checkStr .. ",ocpf:" .. record.occupyFrameCount .. " " end end return checkStr end --设置结算协议 function SyncWarZoneWorldBossLevelFunction:SendBattleResult(isSuccess) --不调用Base 下面的代码 self.isResultSent = true local playerHerosHPDic = self:GetAllPlayerHerosHP() local checkStr = self:GetCheckStr() local occupierPlayerInfo = self.finalOccupierPlayerID and LevelPlayerManager.GetPlayerInfoByPlayerIDInRoom(self.finalOccupierPlayerID) local isOccupier = false local playerInfo local msg = world_boss_pb.C2GUploadWorldBossResult() for _, playerID in ipairs(LevelPlayerManager.SyncPlayerIDList) do local fighter = world_boss_pb.FighterWBResult() fighter.playerID = playerID fighter.heroLeftHp = playerHerosHPDic[playerID] or "" fighter.killNum = self:GetKillNum(playerID) local record = self:GetOccupyRecordByPlayerID(playerID) fighter.damageTime = record and record.occupyFrameCount or 0 local playerStatistic = self.PlayerStatisticDic[playerID] if playerStatistic then fighter.beKilledTimesByBoss = playerStatistic[LuaConst.EStatisticType.PlayerBeKilledByBossCount] end --new↓新的战区boss需要统计伤害 local damage = self:GetDamageOfPlayer(playerID) if damage then fighter.damage = FP.tonumberV1(damage) else fighter.damage = 0 end --new↑ if occupierPlayerInfo then playerInfo = LevelPlayerManager.GetPlayerInfoByPlayerIDInRoom(playerID) isOccupier = occupierPlayerInfo.teamLeaderName == playerInfo.teamLeaderName end fighter.isOccupier = isOccupier --old↓ 老的战区boss不统计伤害 -- if record then -- fighter.damage = 1 --战区世界boss, 对boss造成过伤害的(有record等价于造成过伤害),damage传随便的正值 -- else -- fighter.damage = 0 --战区世界boss, 对boss没造成过伤害的(无record),damage传0 -- end --old↑ self:FillBeKilledInfo(fighter, playerID) self:ClearKillNum(playerID) table.insert(msg.allFighterRes ,fighter) end msg.whoKilledBoss = 0 --杀死boss的人,暂时不传,服务器也么有用 ,等策划订好怎么用时再想办法加 msg.checkInfo = checkStr msg.success = isSuccess if LogicUpdateManager.IsReplayOrServerCheck then -- 客户端重播或服务器校验的话,不要发送TCP logging.log(LTAG.LOG,"[GWS]SyncWorldBoss BattleCheckStr = ",checkStr) else EventSystem.Dispatch(EventID.WorldBoss_SendResult,msg) end if USE_LUA_STANDALONE then BattleSimulator.SetCheckResult(checkStr, msg:SerializeToString()) end end function SyncWarZoneWorldBossLevelFunction:OnTeamQuitRoom(teamId) Base.OnTeamQuitRoom(self, teamId) for i=#self.occupyRecordList,1,-1 do if self.occupyRecordList[i].teamId == teamId then table.remove(self.occupyRecordList, i) end end end function SyncWarZoneWorldBossLevelFunction:OnOccupierChanged(oldPlayerID, newPlayerID) if oldPlayerID then --刷新 oldPlayerID的占领时长 local record = self:GetOccupyRecordByPlayerID(oldPlayerID) if not record then record = self:CreateRecord(oldPlayerID) end record.occupyFrameCount = record.occupyFrameCountBefore + LogicUpdateManager._clientHandleFrame - self.curOccupierStartFrame self:RefreshOccupyRankByOccupyRecord(record) if self:GetDamageOfPlayer(oldPlayerID) == FP.Const.Zero then self:RemoveRecordHpIfZero(oldPlayerID) end end if newPlayerID then self.curOccupierStartFrame = LogicUpdateManager._clientHandleFrame local playerInfo = LevelPlayerManager.GetPlayerInfoByPlayerIDInRoom(newPlayerID) if playerInfo then self.curOccupierTeamId = playerInfo.teamId else logging.error(LTAG.ERROR, "HYW : 致命错误! 找不到playerInfo! 222") end local record = self:GetOccupyRecordByPlayerID(newPlayerID) if not record then record = self:CreateRecord(newPlayerID) self:RefreshOccupyRankByOccupyRecord(record) end record.occupyFrameCountBefore = record.occupyFrameCount else self.curOccupierStartFrame = nil self.curOccupierTeamId = nil end self.exp:OnOccupierChanged(oldPlayerID, newPlayerID) end function SyncWarZoneWorldBossLevelFunction:OnLevelSucceed(withShow) self.finalOccupierPlayerID = self.curOccupierPlayerID self:SetCurOccupierPlayerID(nil) --通过set占领者为nil来触发一次统计刷新 Base.OnLevelSucceed(self, withShow) end function SyncWarZoneWorldBossLevelFunction:OnLevelFail() self.finalOccupierPlayerID = self.curOccupierPlayerID self:SetCurOccupierPlayerID(nil) --通过set占领者为nil来触发一次统计刷新 Base.OnLevelSucceed(self, false) --策划要求战区世界boss失败也算成功 end return SyncWarZoneWorldBossLevelFunction