--逐鹿中原(大乱斗)基类 local EventSystem = require('Event/EventSystem') local BattleEffect = require("Battle/Logic/BattleEffect/BattleEffect") local fight_throne_pb = require('Proto/fight_throne_pb') local FirstPersonEventDispatcher = require"Battle/Logic/Event/FirstPersonEventDispatcher" local Base = require("Battle/Logic/Level/LevelFunction/SyncLevelFunction") local FightThroneBaseLevelFunction = class("FightThroneBaseLevelFunction",Base) local JADE_SHARD_KEY = LuaConst.EFightThroneCollectType.JADE local JADE_SHARD_DROP_RATIO = DataSheetManager.ConstData:GetDataByID("FightThroneSnatchPercentage").IntValue / 100 local MAX_JADE_SHARD_COUNT = DataSheetManager.ConstData:GetDataByID("FightThroneFragmentMax").IntValue local FLAG_MONSTER_ID = DataSheetManager.ConstData:GetDataByID("FightThroneFlagCallId").IntValue local SILVER_AMOUNT_LIMIT = DataSheetManager.RewardPreview:GetDataByID(LuaConst.EFightThroneCollectType.SILVER).RewardLimit local GOLD_AMOUNT_LIMIT = DataSheetManager.RewardPreview:GetDataByID(LuaConst.EFightThroneCollectType.GOLD).RewardLimit local Const_KillerDeBuff = {100094, 100095} -- 给杀人者加上的debuff local GAIN_FLAG_EFFECT_BUFF = 500451 --获得旗子时的特效buff local MONSTER_FLAG_ID = 37000001 function FightThroneBaseLevelFunction:GetExpClass() return require "Battle/Expression/ExpLevel/ExpLevelFunction/ExpFightThroneBaseLevelFunction" end function FightThroneBaseLevelFunction:InitLevel() Base.InitLevel(self) self.dontIgnoreEnemy = true --不使用忽略敌人机制,节省性能 self.LevelReviveType = LuaConst.LevelReviveType.SelectOne -- 复活:一次选一主将活 self.isSwitchOneReviveNeerBy = true self.dontStartAutoFightWhenRetain = true self.RecordPlayerEntitys = {}--记录玩家们开始时的entity顺序 self.playerFlagAmountDic = {} self.playerCollectAmountDic = {} self.guildBornIndexDic = {} --军团出生点index字典 self.curGuildIndexNum = 1 self.isFreeToEnterAndLeave = false self.forceQuitRoomAndNotRetain = true self.hasFirstBlood = false end function FightThroneBaseLevelFunction:GetRobotAI(entity) return nil --大乱斗没有AI,而且必须返回nil,这样才能自由设置AI end function FightThroneBaseLevelFunction:SetSelectOneReviveParam() self.RebornBaseTime = DataSheetManager.ConstData:GetDataByID("FightThroneHeroRebornBaseTime").IntValue -- 基础复活时间 s self.RebornExtraTime = DataSheetManager.ConstData:GetDataByID("FightThroneHeroRebornExtraTime").IntValue -- 死亡次数额外附加时间 s self.RebornMaxTime = DataSheetManager.ConstData:GetDataByID("FightThroneHeroRebornMaxTime").IntValue -- 最大复活时间 end function FightThroneBaseLevelFunction:GetSelectOneRevivePunishTime() return DataSheetManager.ConstData:GetDataByID("FightThroneDeathPunishTime").IntValue -- 死亡惩罚时长 end function FightThroneBaseLevelFunction:AfterLevelLayoutInited() Base.AfterLevelLayoutInited(self) self.bornIndexRandomDiff = LogicRandom.GetIntegerValue(nil, 1, LevelManager.bornPointCount, 45865468) end function FightThroneBaseLevelFunction:GetBornIndex(playerInfo) -- old↓ -- local guildIDNum = playerInfo.guildID -- local guildIDType = type(guildIDNum) -- if guildIDType == "string" then -- guildIDNum = string.sub(guildIDNum, -1):byte() + self.bornIndexRandomDiff -- else -- if guildIDType ~= "number" then -- logging.error(LTAG.ERROR, "HYW : guildID type Error! type : ", guildIDType) -- guildIDNum = 1 -- end -- end -- old↑ -- new↓ 不同军团会根据每个军团第一个进入的玩家的顺序依次分配出生点 local key = string.isNilOrEmpty(playerInfo.guildID) and playerInfo.playerID or playerInfo.guildID local guildIDNum = self.guildBornIndexDic[key] if not guildIDNum then guildIDNum = self.curGuildIndexNum self.curGuildIndexNum = self.curGuildIndexNum + 1 self.guildBornIndexDic[key] = guildIDNum end -- new↑ return ((guildIDNum - 1) % LevelManager.bornPointCount) + 1 end --大乱斗所有玩法都禁止手动切换战斗模式 function FightThroneBaseLevelFunction:CanSwitchFightModeManually() return false end function FightThroneBaseLevelFunction:IsCollectAmountReachLimit(entity, key) --不调用Base local result = false if entity then local playerID = entity:GetPlayerID() if playerID > 0 then local amount = self:GetCollectAmountOfPlayerByCollectKey(playerID, key) if key == LuaConst.EFightThroneCollectType.SILVER then result = amount >= SILVER_AMOUNT_LIMIT elseif key == LuaConst.EFightThroneCollectType.GOLD then result = amount >= GOLD_AMOUNT_LIMIT elseif key == LuaConst.EFightThroneCollectType.JADE then result = amount >= MAX_JADE_SHARD_COUNT else logging.error(LTAG.ERROR, "HYW : key bad value @FightThroneBaseLevelFunction:IsCollectAmountReachLimit value : ", key) end else logging.error(LTAG.ERROR, "HYW : playerID bad value Error @FightThroneBaseLevelFunction:IsCollectAmountReachLimit playerID : ", playerID) end else logging.error(LTAG.ERROR, "HYW : entity nil Error @FightThroneBaseLevelFunction:IsCollectAmountReachLimit") end return result end function FightThroneBaseLevelFunction:CreatePlayers() --不调用Base --LevelPlayerManager.MyPlayerIDInRoom --自己的playerID local heroArmyList = {} local heroArmyDataSet for k,v in pairs(LevelPlayerManager.PlayersArmyTable) do --pairs safe,下面会排序 heroArmyDataSet = {army = v,playerID = k} table.insert(heroArmyList,heroArmyDataSet) end table.sort(heroArmyList,function(a,b) return a.playerID < b.playerID end) self.HeroArmyList = heroArmyList for i,heroArmyDataSet in ipairs(heroArmyList) do self:CreatePlayerEntitys(heroArmyDataSet.playerID,heroArmyDataSet.army, self:GetBornIndex(heroArmyDataSet.army.playerInfo)) local entitys = LevelPlayerManager.GetPlayerEntitysByPlayerIDInRoom(heroArmyDataSet.playerID) self.RecordPlayerEntitys[heroArmyDataSet.playerID] = {} for _ ,entity in ipairs(entitys) do table.insert(self.RecordPlayerEntitys[heroArmyDataSet.playerID] ,entity) end self:OnCreatePlayer(heroArmyDataSet.playerID) end self:InitEntityByClientIntermediateParamsStr() -- self:RefreshAllFightMode() gws:因为有self.dontIgnoreEnemy = true 故把这句代码去掉了 --EventSystem.Dispatch(EventID.Battle_SyncPVE_CreatePlayerFinished) end function FightThroneBaseLevelFunction:InitEntityByClientIntermediateParamsStr() -- 不调用base -- 使用playerInfo里的intermediateStr初始化采集物数量 for i,playerID in ipairs(LevelPlayerManager.SyncPlayerIDList) do local playerInfo = LevelPlayerManager.GetPlayerInfoByPlayerIDInRoom(playerID) if playerInfo.intermediateStr and playerInfo.intermediateStr ~= "" then local splits = string.split(playerInfo.intermediateStr, ',') for j,splitSeg in ipairs(splits) do self:ChangeCollectAmountOfPlayerByCollectKey(nil, playerID, j, tonumber(splitSeg)) end end end end function FightThroneBaseLevelFunction:CreatePlayerEntitys(playerIDInRoom ,playerHeroArmy,index) local heroEntityTable = {} local army = playerHeroArmy.army local playerInfo = playerHeroArmy.playerInfo local isPlayerSelf = playerInfo.playerID == LevelPlayerManager.MyPlayerIDInRoom local gs = 0 for i,v in ipairs(army) do gs = gs + (v.heroGs or 0) end for i,heroArmyData in ipairs(army) do local entity = self:CreatePlayerEntity(playerInfo,heroArmyData,isPlayerSelf,index) entity:SetGs(gs) table.insert(heroEntityTable,entity) end LevelPlayerManager.SetPlayerEntityTable(heroEntityTable ,playerIDInRoom) local firstEntity = heroEntityTable[1] if firstEntity == nil then logging.error(LTAG.ERROR, "HYW : firstEntity为空Error! #army : " .. tostring(#army) .. " 是否是机器人:" .. tostring(self:IsRobotPlayerInfo(playerInfo)) .. " acid : " .. tostring(playerInfo.acid)) end local levelInfo = BattleDataGetter.GetLevelInfoData() if levelInfo.AutoBattle then -- 策划要求根据levelInfo的配置来决定是否开启自动战斗 2021年7月15日 SystemManager.StartAutoFight(firstEntity)-- ×策划要求默认开启自动战斗(已撤销) --2021年1月11日(策划已撤销这个需求 2021年7月15日) end if playerIDInRoom == LevelPlayerManager.MyPlayerIDInRoom then LevelPlayerManager.SetCurEntity(firstEntity ,false , LevelPlayerManager.GetPlayerSetting(playerIDInRoom ,LuaConst.BattleSettingEnum.AutoRide)) --LevelPlayerManager.MainEntityCampID = firstEntity:GetCampID() gws 多余了,在initfuben的时候统计army时就统计了 else SystemManager.Active(firstEntity,LevelPlayerManager.GetPlayerSetting(playerIDInRoom ,LuaConst.BattleSettingEnum.AutoRide))-- 可以不用设置,因为后续在kcp通知battlebegin的时候会把所有玩家的第一个entity都显示出来 end --EventSystem.Dispatch(EventID.Battle_SyncPVE_CreatePlayerFinished) end function FightThroneBaseLevelFunction:OnCreatePlayer(playerID) Base.OnCreatePlayer(self, playerID) self.playerFlagAmountDic[playerID] = 0 self.playerCollectAmountDic[playerID] = {} --玩家采集物数量子弹。key为playerID,value是数量字典,key为采集物索引(就是关卡层数),value是数量 end function FightThroneBaseLevelFunction:OnHeroDead(entity) Base.OnHeroDead(self, entity) self.exp:OnHeroDead(entity) end function FightThroneBaseLevelFunction:OnHeroKillHero(killer, deadEntity, deadComboKill) Base.OnHeroKillHero(self, killer, deadEntity, deadComboKill) for i,v in ipairs(Const_KillerDeBuff) do SystemManager.AddBuff(killer, v) SystemManager.DeleteBuff(deadEntity, v) end end local _tempV1 = FP.newV1(0) function FightThroneBaseLevelFunction:HandleHeroDead(deadEntity, killer) local deadPlayerID = deadEntity:GetPlayerID() local deadKillNums = self:GetPlayerComboKillNum(deadPlayerID) Base.HandleHeroDead(self, deadEntity, killer) if not killer then --好像有些情况关卡会杀Hero,且这种情况下KillerEntity为空,所以这里要判空 return end local directKiller = killer local originKiller = directKiller:GetOriginEntity() if originKiller:IsHero() then if self.shouldSnatchShard then local deadShardCount = self:GetCollectAmountOfPlayerByCollectKey(deadEntity:GetPlayerID(), JADE_SHARD_KEY) if deadShardCount > 0 then local killerShardCount = self:GetCollectAmountOfPlayerByCollectKey(originKiller:GetPlayerID(), JADE_SHARD_KEY) if killerShardCount < MAX_JADE_SHARD_COUNT then local changeAmount = FP.tonumberV1(_tempV1:Reset(deadShardCount):Mul(JADE_SHARD_DROP_RATIO)) if changeAmount < 1 then changeAmount = 1 else changeAmount = math.floor(changeAmount) end if MAX_JADE_SHARD_COUNT - killerShardCount < changeAmount then changeAmount = MAX_JADE_SHARD_COUNT - killerShardCount end --logging.error(LTAG.ERROR, "HYW : 杀人者碎片:", killerShardCount, " 被杀者碎片 : ", deadShardCount, " 夺取数量 : ", changeAmount) self:ChangeCollectAmountOfPlayerByCollectKey(deadEntity, deadEntity:GetPlayerID(), JADE_SHARD_KEY, -changeAmount) self:ChangeCollectAmountOfPlayerByCollectKey(originKiller, originKiller:GetPlayerID(), JADE_SHARD_KEY, changeAmount) end end end --服务器使用的代码:统计击杀信息 local firstBlood = 0 if not self.hasFirstBlood then firstBlood = 1 self.hasFirstBlood = true end local killerPlayerID = originKiller:GetPlayerID() local killerName = LevelPlayerManager.GetPlayerName(killerPlayerID) local guildIdA = originKiller:GetGuildID() local killNums = self:GetPlayerComboKillNum(killerPlayerID) local heroIDA = originKiller:GetCharacterID() local playerNameB = LevelPlayerManager.GetPlayerName(deadPlayerID) local guildIdB = deadEntity:GetGuildID() local heroIDB = deadEntity:GetCharacterID() local info = { killNums = killNums, firstBlood = firstBlood, playerNameA = killerName, guildIdA = guildIdA, playerNameB = playerNameB, guildIdB = guildIdB, playerHeroIdA = heroIDA, playerHeroIdB = heroIDB, killNumsB = deadKillNums, playerIdA = killerPlayerID, playerIdB = deadPlayerID} --A 是杀人者 ,B是被杀者 logging.log(LTAG.LOG,"SyncBattle_KillInfoNotice", info) EventSystem.Dispatch(EventID.SyncBattle_KillInfoNotice, info) end end function FightThroneBaseLevelFunction:ChangeFlagAmountOfPlayer(entity, playerID, delta, eventEntityType) if self.playerFlagAmountDic[playerID] + delta >= 0 then self.playerFlagAmountDic[playerID] = self.playerFlagAmountDic[playerID] + delta if delta > 0 then SystemManager.AddBuff(entity, GAIN_FLAG_EFFECT_BUFF, entity) end --logging.error(LTAG.ERROR, "HYW : ChangeFlagAmountOfPlayer result : ", self.playerFlagAmountDic[playerID], " playerID : ", playerID) if self.playerFlagAmountDic[playerID] > 1 then logging.error(LTAG.ERROR, "HYW : 警告,玩家所持令旗数大于了1,当前数量:", self.playerFlagAmountDic[playerID]) end self.exp:OnPlayerFlagAmountChange(entity, delta, self.playerFlagAmountDic[playerID], eventEntityType) else logging.error(LTAG.ERROR, "HYW : 警告!试图让令旗数变为负数!!!") end end function FightThroneBaseLevelFunction:GetFlagAmountOfPlayer(playerID) return self.playerFlagAmountDic[playerID] or 0 end function FightThroneBaseLevelFunction:TryDropFlagAmountOfEntity(entity) if entity:IsHero() then -- 防止分身也掉落旗子 local playerID = entity:GetPlayerID() if playerID then if self.playerFlagAmountDic[playerID] and self.playerFlagAmountDic[playerID] >= 1 then self:ChangeFlagAmountOfPlayer(entity, playerID, -1) end else logging.error(LTAG.ERROR, "HYW : 警告!试图给没有playerID的单位添加令旗数量。 characterID : ", entity:GetCharacterID()) end end end -- entity可能为空,因为初始化时不会传entity function FightThroneBaseLevelFunction:ChangeCollectAmountOfPlayerByCollectKey(entity, playerID, collectKey, delta, reasonType) self.playerCollectAmountDic[playerID][collectKey] = self.playerCollectAmountDic[playerID][collectKey] or 0 if collectKey == JADE_SHARD_KEY and delta > 0 then local curCount = self.playerCollectAmountDic[playerID][collectKey] if curCount < MAX_JADE_SHARD_COUNT then if curCount + delta > MAX_JADE_SHARD_COUNT then delta = MAX_JADE_SHARD_COUNT - curCount end else delta = 0 end end if delta ~= 0 then self.playerCollectAmountDic[playerID][collectKey] = self.playerCollectAmountDic[playerID][collectKey] + delta self.exp:OnPlayerCollectAmountChange(entity, collectKey, delta, reasonType, self.playerCollectAmountDic[playerID][collectKey]) --logging.error(LTAG.ERROR, "HYW : 添加采集物", collectKey, "级", delta, "个。给玩家:", playerID, " 由Entity ", entity and entity.EntityID or -1, "触发 当前数量为 : ", self.playerCollectAmountDic[playerID][collectKey]) end end function FightThroneBaseLevelFunction:GetCollectAmountOfPlayerByCollectKey(playerID, collectKey) --logging.error(LTAG.ERROR, "HYW : 采集物", collectKey, "数量", self.playerCollectAmountDic[playerID][collectKey] or 0, "。玩家ID :", playerID) return self.playerCollectAmountDic[playerID][collectKey] or 0 end function FightThroneBaseLevelFunction:SendPositionChatLink(pos, speakerEntity) local index = self:AddPositionRecord(pos) FirstPersonEventDispatcher.OnSendPositionChatLink(speakerEntity, index, FP.tonumberV1(pos.x), FP.tonumberV1(pos.z)) --这个会触发TCP的聊天通信,所以只需要主视角发送即可 end function FightThroneBaseLevelFunction:SendResult() local checkStr = self:GetBattleResultCheckStr() local msg = fight_throne_pb.C2GUploadFightThroneResult() msg.surplusFlagNum = self.flagNum for i,playerID in ipairs(LevelPlayerManager.PlayerIDList) do local fighter = fight_throne_pb.FighterFTResult() local playerInfo = LevelPlayerManager.GetPlayerInfoByPlayerIDInRoom(playerID) fighter.playerID = playerID fighter.playerAcid = playerInfo.acid fighter.hasKey = self:GetFlagAmountOfPlayer(playerID) > 0 fighter.silverChest = self:GetCollectAmountOfPlayerByCollectKey(playerID, 1) fighter.goldChest = self:GetCollectAmountOfPlayerByCollectKey(playerID, 2) fighter.jadeFragment = self:GetCollectAmountOfPlayerByCollectKey(playerID, 3) fighter.killNum = self:GetPlayerKillNum(playerID) fighter.deadNum = self:GetPlayerDeadHeroCount(playerID) fighter.intermediateStr = fighter.silverChest .. "," .. fighter.goldChest .. "," .. fighter.jadeFragment table.insert(msg.allFighterRes ,fighter) end msg.checkInfo = checkStr .. "-cmdCount:" .. LogicUpdateManager._handleCmdCount .. "-frameCount:" .. LogicUpdateManager._handleFrameCount if USE_LUA_STANDALONE then -- 服务器校验时 ,需要的字符串要设置好 BattleSimulator.SetCheckResult(msg.checkInfo, msg:SerializeToString()) end EventSystem.Dispatch(EventID.FightThrone_SendResult , msg, self) end function FightThroneBaseLevelFunction:QuitRoom(entity) Base.QuitRoom(self, entity) --退出时尝试掉落令旗 local params = {caster = entity, target = entity, effectData = {intParams = {FLAG_MONSTER_ID}}} BattleEffect.TryDropFlagOfPlayer(params) end function FightThroneBaseLevelFunction:OnLevelSucceed() self:SendResult() Base.OnLevelSucceed(self) end function FightThroneBaseLevelFunction:OnLevelFail() self:SendResult() Base.OnLevelSucceed(self) end function FightThroneBaseLevelFunction:BeforeEndLevel() Base.BeforeEndLevel(self) self.flagNum = 0 -- 剩余旗子数量 for i,entity in ipairs(LogicUpdateManager.EntityList_Normal) do if entity._logicInitData.CharacterID == MONSTER_FLAG_ID then self.flagNum = self.flagNum + 1 end end -- 找出哪些玩家没有旗子 local noFlagPlayerIDList = {} for i,playerID in ipairs(LevelPlayerManager.PlayerIDList) do if self:GetFlagAmountOfPlayer(playerID) <= 0 then table.insert(noFlagPlayerIDList, playerID) end end local randomTimes = math.min(#noFlagPlayerIDList, self.flagNum) local randomResult = {} -- 随机后存在旗子的玩家ID for i = 1, randomTimes do local index = LogicRandom.GetIntegerValue(nil, 1, #noFlagPlayerIDList, 20240103) table.insert(randomResult, noFlagPlayerIDList[index]) table.remove(noFlagPlayerIDList, index) end for i,playerID in ipairs(randomResult) do local entity = LevelPlayerManager.GetPlayerActiveEntity(playerID) self:ChangeFlagAmountOfPlayer(entity, playerID, 1) end self.randomFlagResult = randomResult end function FightThroneBaseLevelFunction:GetFlagIsRandom(playerID) if self.randomFlagResult then for i,v in ipairs(self.randomFlagResult) do if v == playerID then return true end end end return false end return FightThroneBaseLevelFunction