From c5923a07318557feab24b37bca7d854dc5516fe1 Mon Sep 17 00:00:00 2001 From: yinghua <17803824368@163.com> Date: Sun, 9 Feb 2025 22:45:09 +0800 Subject: [PATCH] =?UTF-8?q?=E5=90=8C=E4=B8=8A?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../Script/Global/Mini/MiniGameConfig.lua | 185 ++ SoloKing/Script/Global/Mini/MiniManager.lua | 821 +++++++ .../Script/Global/Mini/Script/Mini_Solo.lua | 2125 +++++++++++++++++ SoloKing/SoloKing.ugcproj | 14 +- 4 files changed, 3138 insertions(+), 7 deletions(-) create mode 100644 SoloKing/Script/Global/Mini/MiniGameConfig.lua create mode 100644 SoloKing/Script/Global/Mini/MiniManager.lua create mode 100644 SoloKing/Script/Global/Mini/Script/Mini_Solo.lua diff --git a/SoloKing/Script/Global/Mini/MiniGameConfig.lua b/SoloKing/Script/Global/Mini/MiniGameConfig.lua new file mode 100644 index 00000000..c212b7d2 --- /dev/null +++ b/SoloKing/Script/Global/Mini/MiniGameConfig.lua @@ -0,0 +1,185 @@ +require('Script.Global.Table.WeaponTable') +--- 用到的都放在这 +MiniGameMapType = { + SoloKing = 1, -- 和平大乱斗模式 +}; + +--- 是否随机地图 +Mini_RandomMap = false; + +--- 整体进程 +---@type MiniGameState +MiniGameState = { + NON_START = 1, -- 还未开始 + SELECT_GAMES = 2, -- 选择地图截断 + MINI_PREPARE = 3, -- 玩法准备阶段 + --MINI_GAMING = 4, -- 进入玩法游戏阶段 + ROUND_PREPARE = 4, -- 回合准备阶段 + ROUND_GAMING = 5, -- 回合游玩阶段 + ROUND_END = 6, -- 回合结束阶段 + MINI_END = 7, -- 玩法结束阶段 + ENDED = 8, -- 游戏结束阶段 +}; + +--- 小游戏的各种时间 +MiniGameTimes = { + Active = 1, -- 游戏激活时间,游戏激活时间结束后进入游戏阶段 + Prepare = 35, -- 每个玩法准备时间 + RoundPrepare = 2, -- 玩法单个回合开启时间到正式开启时间 + RoundGameTime = -4 * 60, + RoundEnd = 5, -- 玩法单个回合结束到下一个回合开启的时间 + MiniGameEnd = 0, -- 一个玩法结束的时候到下一个小游戏或者游戏结束的时间 + End = 200; -- 结束的时候执行 +}; + +GameStateTimes = { + GangUp = { + SelectMapTime = 12; + } +} + +--- 玩法配置 +--- 可以重写玩法的时间:在单个玩法配置中添加 MiniGameTimes = { Prepare = xxx, } 这种形式即可 +MiniGameConfig = MiniGameConfig or { + [MiniGameMapType.SoloKing] = { + Script = "Solo", -- 会执行的代码文件 + Map = { + -- 按热度排序 + MapName = { + ['Map_SLXLC'] = 1, + ['Map_SMDJ'] = 1, + ['Map_HDDJ'] = 1, + ['Map_JCK'] = 1, + ['Map_DBL'] = 1, + ['Map_SCL'] = 1, + ['Map_NewYear'] = 2, + ['Map_DC'] = 2, + }, + ShowName = "单挑王", -- 显示名称 + }, + --- 小游戏回合次数,如果 <= 1 表示当前游戏只支持单局,且条件为自动设置。 + RoundTimes = 7, + --- 初始给的武器,下面每一条都是要添加的一个初始物品 + InitArmors = { + [1] = EArmorType.Armor3, + [2] = EHelmetType.Helmet3, + [3] = EBagType.Bag1, + }, + InitMedication = { + { "大包", 1, }, -- 10 + { "绷带", 5, }, -- 2 * Num + { "可乐", 3, }, -- 4 * Num + }, + --- 延迟一会后再给的物品 + DelayWeapons = { + { "手榴弹", 1, }, -- 18 + { "烟雾弹", 1, }, -- 14 + { "震爆弹", 1, }, -- 14 + }, + + --- 地图新增物品 + MapAddedItem = { + ['Map_JCK'] = { + { "燃烧瓶", 1 }, + }, + ['Map_DBL'] = { + { "燃烧瓶", 1 }, + }, + ['Map_SCL'] = { + { "燃烧瓶", 1 }, + }, + }, + + --- 游戏参数,会自动展开,如果想要表结构,需要再嵌套一层表 + Params = { + SelectWeaponCount = 7, -- 可以选择武器的个数 + RespawnTime = 2, -- 玩家复活的时间,现在用不到 + KillHealing = 0, -- 击杀可以回复的血量 + KillTimes = 2, -- 击杀多少次当前回合 + ResetTime = 3, -- 重置时间 + SelectMapTime = 8, -- 选择地图时间,正式开始前这么长时间就不允许再选择了 + + EnableInsult = false; -- 是否开启鞭尸 + + DefaultWeapon = 101004, -- 默认初始武器 + + --- 加分方式 + AddFunc = function(Diff, Current, NeedOther) + local Add = 20 - Diff / 100; + Add = math.ceil(Add); + if Add < 5 then Add = 5; end + if Add > 30 then Add = 30; end + + if NeedOther then + if Current < 2200 then + Add = Add + math.random(4, 5); + elseif Current < 3000 then + Add = Add + math.random(1, 2); + --else + -- Add = Add + math.random(0, 1); + end + end + return Add; + end, + + --- 扣分方式 + ReduceFunc = function(Diff, Current) + local Reduce = -20 + Diff / 100; + Reduce = math.floor(Reduce); + if Reduce > -5 then Reduce = -5 end + if Reduce < -30 then Reduce = -30; end + return Reduce; + end, + + SpecialWeapon = { + [EWeaponTypeNew.EWeaponTypeNew_SingleShotSniper] = { + InitArmors = { + [1] = EArmorType.Armor2, + [2] = EHelmetType.Helmet2, + }, + }, + [EWeaponTypeNew.EWeaponTypeNew_Crossbow] = { + InitArmors = { + [1] = EArmorType.Armor2, + [2] = EHelmetType.Helmet2, + }, + }, + [EWeaponTypeNew.EWeaponTypeNew_Melee] = { + InitArmors = { + [1] = EArmorType.Armor1, + [2] = EHelmetType.Helmet1, + }, + }, + } + }; + }, +}; + +GameModeConfig = {} +-- 由于顺序问题 这里不可以跳数字 +GameModeConfig.EGameModeType = { + DefaultMode = 1; + GangUpMode = 2; -- 休闲模式 +}; + +GameModeConfig.GameModeInfo = { + [GameModeConfig.EGameModeType.DefaultMode] = { + Name = "经典模式"; + Feature = "·经典和平,双方武器一致。\n·武器从武器池中随机抽取。"; + }, + [GameModeConfig.EGameModeType.GangUpMode] = { + Name = "休闲模式"; + Feature = "·回合武器可自选!\n·不掉分!"; + -- 时间配置 + MiniGameTimes = { + Active = 2, -- 游戏激活时间,游戏激活时间结束后进入游戏阶段 + Prepare = 15, -- 每个玩法准备时间 + RoundPrepare = 2, -- 玩法单个回合开启时间到正式开启时间 + RoundEnd = 5, -- 玩法单个回合结束到下一个回合开启的时间 + MiniGameEnd = 0, -- 一个玩法结束的时候到下一个小游戏或者游戏结束的时间 + End = 50; -- 结束的时候执行 + }, + }, +} + +return MiniGameConfig; \ No newline at end of file diff --git a/SoloKing/Script/Global/Mini/MiniManager.lua b/SoloKing/Script/Global/Mini/MiniManager.lua new file mode 100644 index 00000000..c25be25a --- /dev/null +++ b/SoloKing/Script/Global/Mini/MiniManager.lua @@ -0,0 +1,821 @@ +MiniManager = {}; + +---@private string 这是玩家选择的地图,按从前往后开始游玩 +MiniManager.ScriptPath = "Script.Global.Mini.Script.Mini_"; +---@type table 当前所有玩家选择的地图 +MiniManager.SelectMaps = {}; +---@type FMiniGameMapIndex 当前选择的地图 +MiniManager.CurrSelectMap = nil; +---@type UGCGameState_C 默认是 GameSate,如果不是可以在具体实例里面实现对应方法 +MiniManager.Owner = nil; +---@type MiniGameMode 当前小玩法的具体实现,统一入口出口管理 +MiniManager.CurrMiniMode = nil; +---@type int32 目标小游戏数量,低于这个数量会自动添加到这个数量 +MiniManager.TargetMiniGameCount = 1; +---@type MiniGameState 模式状态,可以在本实例和 CurrMiniMode 中获取 +MiniManager.State = 0; +---@type table 玩家数据 +MiniManager.PlayerData = {}; +---@type table 小游戏需要同步的数据,会自动执行 OnRep_xxx 函数 +MiniManager.MiniInfo = {}; + +MiniManager.TimerHandlers = nil; + +----------------------------------- 主要函数 ----------------------------------- + +--- 这是游戏启动,做一些初始化的操作即可 +function MiniManager:Init(InOwner) + UGCLogSystem.Log("[MiniManager:ReceiveBeginPlay] 执行成功 self = %s", tostring(self)); + self.Owner = InOwner; + if MiniGameConfig == nil then + require('Script.Global.Mini.MiniGameConfig'); + UGCLogSystem.LogTree(string.format("[MiniManager:Init] MiniGameConfig ="), MiniGameConfig); + end + if DefaultSettings.EnableTest then + for i, v in pairs(MiniGameConfig) do + v.RoundTimes = 1; + end + + MiniGameTimes.RoundGameTime = -500; + end + UGCEventSystem.AddListener(EventTypes.ClientAlready, self.OnClientAlready, self) + + if IsServer then + self:SetState(MiniGameState.SELECT_GAMES); + + GlobalTickTool:AddInternalCount(self, function(o, dt, ServerTime, t) + o:OnMiniGameTimeCount(t); + end, 1, MiniGameTimes.Active, self.OnGameStart); + else + -- 执行客户端逻辑 + self:MakeCachedMiniInfo(); + end + + -- 组装一下具体函数 + self:MakeRepProps(); +end + +function MiniManager:MakeRepProps() + local Func = function(...) return { ... }; end + local Props = Func(self:GetReplicatedProperties()); + if self.Props == nil then self.Props = {}; end + for i, v in pairs(Props) do self.Props[v] = true; end + UGCLogSystem.LogTree(string.format("[MiniManager:MakeRepProps] self.Props ="), self.Props); +end + +function MiniManager:IsRepProp(InName) + if self.Props == nil then self.Props = {}; end + return self.Props[InName] == true; +end + +--- 本身需要同步的数据放进来 +function MiniManager:GetReplicatedProperties() + return "State" + , "SelectMaps" + , "CurrSelectMap" +end + +--- 客户端准备好了,此时开始有 ServerTime +function MiniManager:OnClientAlready() + -- 显示 + if IsClient then + UGCLogSystem.Log("[MiniManager:OnGameBegin] 显示 UI") + end + + table.func(self.CurrMiniMode, "OnClientAlready") +end + +--- UI已经准备好了 +function MiniManager:OnUIAlready() + table.func(self.CurrMiniMode, "OnUIAlready") +end + +--- 准备结束 +function MiniManager:OnPrepareEnd() + if IsServer then + UGCLogSystem.Log("[MiniManager:OnPrepareEnd] 执行") + self:SetMiniInfo(); + UGCGameSystem.SendModeCustomEvent("CheckPlayers"); + end + table.func(self.CurrMiniMode, "OnPrepareEnd") + self:OnMiniRoundPrepare(); +end + +function MiniManager:SendRPC(InRPCName, ...) + UGCLogSystem.Log("[MiniManager:SendRPC] InRPCName = %s", InRPCName); + self.Owner:SendMiniGameRPC(InRPCName, ...); +end + +--- 在游戏进行之前执行 +---@param InTime int32 从游戏开始到游戏正式开始的倒计时 +function MiniManager:OnBeforeGameStart(InTime) + UGCLogSystem.Log("[MiniManager:OnBeforeGameStart] InTime = %s", tostring(InTime)); + if InTime == 1 then + -- 玩家死亡重生 + UE.ResetGame1(0.5, function() + GameState:ResetKill(); + end); + end +end + +--- 游戏正式开始 +function MiniManager:OnGameStart() + UGCLogSystem.Log("[MiniManager:OnGameStart] 执行") + if IsServer then + -- 检查当前选择的地图是否小于对应数量,如果小于,那么就随机选择为选择的 + -- 获取选择了的 + for i, v in pairs(MiniGameConfig) do + table.insert(self.SelectMaps, i); + end + UGCLogSystem.LogTree(string.format("[MiniManager:OnGameStart] SelectMaps ="), self.SelectMaps) + -- 表示如果第一个加载不成,那么就依次完后加载,直到全部加载都不行 + local bSuccess = false; + repeat bSuccess = self:LoadMiniGame() until bSuccess or table.isEmpty(self.SelectMaps); + if not bSuccess then + UGCLogSystem.Log("[MiniManager:OnGameStart] 游戏结束") + self:OnGameEnd(); + end + else + WidgetManager:ShowPanel(WidgetConfig.EUIType.Main, false); + end +end + +function MiniManager:OnGameEnd() + UGCLogSystem.Log("[MiniManager:OnGameEnd] 游戏结束") + if IsServer then + self:SetState(MiniGameState.ENDED); + LuaQuickFireEvent("GameEnd", GameState); + else + -- 显示结算界面 + UGCLogSystem.Log("[MiniManager:OnGameEnd] GameWinner = %s", tostring(self.MiniInfo.GameWinner)); + UGCLogSystem.LogTree(string.format("[MiniManager:OnGameEnd] RoundWinners ="), self.MiniInfo.RoundWinners) + SoloKingGameWinner = self.MiniInfo.GameWinner; + SoloKingRoundWinner = self.MiniInfo.RoundWinners; + UGCLogSystem.Log("[MiniManager:OnGameEnd] 显示 GameEnd 界面"); + if not WidgetManager:IsVisiblePanel(WidgetConfig.EUIType.GameEnd) then + WidgetManager:ShowPanel(WidgetConfig.EUIType.GameEnd, false, self.MiniInfo.GameWinner, self.MiniInfo.RoundWinners); + WidgetManager:ClosePanel(WidgetConfig.EUIType.Main); + end + end +end + +---@param InMiniType MiniGameMapType Mini 游戏类型,只会在客户端存在 +function MiniManager:LoadMiniGame(InMiniType) + if MiniGameConfig == nil then + require('Script.Global.Mini.MiniGameConfig'); + end + if IsServer then + self:SetState(MiniGameState.MINI_PREPARE); + self:AllPlayerDead(); + UGCLogSystem.Log("[MiniManager:LoadMiniGame] 执行") + if table.isEmpty(self.SelectMaps) then return false; end + UGCLogSystem.Log("[MiniManager:LoadMiniGame] 开始执行流程") + self.CurrSelectMap = self.SelectMaps[1]; + if self.CurrSelectMap == nil then return false; end + table.remove(self.SelectMaps, 1); + -- 加载 CurrMiniMode + UGCLogSystem.Log("[MiniManager:LoadMiniGame] 加载 Mini Mode") + self.CurrMiniMode = require(self.ScriptPath .. MiniGameConfig[self.CurrSelectMap].Script); + if self.CurrMiniMode == nil then return false; end + if not table.func(self.CurrMiniMode, "Init", self) then return false; end + -- 发送到客户端表示当前已经同步了 + self.Owner:SelectMiniType(self.CurrSelectMap); + UGCLogSystem.Log("[MiniManager:LoadMiniGame] Mini Mode 加载成功") + self:CurrMiniModeInit(); + if self.CurrMiniMode.RoundTimes == nil then self.CurrMiniMode.RoundTimes = 1; end + self:SetRoundTimes(self.CurrMiniMode.RoundTimes); + -- 这个是玩法的小局准备 + local Times = MiniGameConfig[self.CurrSelectMap].MiniGameTimes + local Time = 0; + if Times ~= nil and Times.Prepare ~= nil then + Time = Times.Prepare; + else + Time = MiniGameTimes.Prepare; + end + UGCLogSystem.Log("[MiniManager:LoadMiniGame] Time = %s", tostring(Time)) + self.TimerHandlers = GlobalTickTool:AddInternalCount(self, function(o, dt, ServerTime, t) + UGCLogSystem.Log("[MiniManager:LoadMiniGame] Time Internal = %s", tostring(t)); + o:OnMiniGameTimeCount(t); + end, 1, Time, self.OnPrepareEnd); + + UGCLogSystem.Log("[MiniManager:LoadMiniGame] 全部加载完成") + return true; + else + UGCLogSystem.Log("[MiniManager:LoadMiniGame] 客户端加载") + self.CurrSelectMap = InMiniType; + self.CurrMiniMode = require(self.ScriptPath .. MiniGameConfig[self.CurrSelectMap].Script); + if self.CurrMiniMode == nil then return ; end + table.func(self.CurrMiniMode, "Init", self); + self:CurrMiniModeInit(); + -- 检查是否有数据啊 + if UGCGameSystem.GameState then + UGCGameSystem.GameState:OnRep_MiniInfo(); + end + end +end + +--- 服务器客户端初始化的共同操作 +function MiniManager:CurrMiniModeInit() + --- 默认设置一些变量供使用或者驱动 + self.CurrMiniMode.Owner = self; + self.CurrMiniMode.MapIndex = self.CurrSelectMap; + self.CurrMiniMode.CreateTime = UE.GetServerTime(); + self.CurrMiniMode.bGameEnd = false; + self.CurrMiniMode.bRoundEnd = false; + self.CurrMiniMode.RoundTimes = MiniGameConfig[self.CurrSelectMap].RoundTimes; -- 当前回合数 + self.CurrMiniMode.TotalRoundTimes = MiniGameConfig[self.CurrSelectMap].RoundTimes; -- 总回合数 + self.CurrMiniMode.bCanRespawn = MiniGameConfig[self.CurrSelectMap].bCanRespawn; -- 是否可以重生 + GlobalMiniType = self.CurrSelectMap; + GlobalMiniMode = self.CurrMiniMode + + for i, v in pairs(self.MiniInfo) do + if type(v) == 'table' then + self.CurrMiniMode[i] = TableHelper.DeepCopyTable(v); + else + self.CurrMiniMode[i] = v; + end + end + + if not table.isEmpty(MiniGameConfig[self.CurrSelectMap].Params) then + for i, v in pairs(MiniGameConfig[self.CurrSelectMap].Params) do self.CurrMiniMode[i] = v; end + end + + UGCLogSystem.Log("[MiniManager:CurrMiniModeInit] 开始加载地图") + -- 加载 Tick + GlobalTickTool:AddTick(self.CurrMiniMode, self.CurrMiniMode.OnTick, nil, function(o) + return not (o.bEnableTick == false); + end); + -- 进入准备 + table.func(self.CurrMiniMode, "OnPrepare"); +end + +function MiniManager:UnLoadMiniGame() + -- 先取消上一个的 + if IsServer then + if self.CurrMiniMode ~= nil then + GlobalTickTool:RemoveTickByOwner(self.CurrMiniMode); + -- 然后赶紧除去地图并且加载 + self:UnLoadMap(); + end + end +end + +function MiniManager:OnMiniGameTimeCount(InVal) + if IsServer then + if InVal == nil then InVal = 0; end + InVal = math.floor(InVal); + --- 执行 + GameState:OnGameProgress_Tick(InVal); + end + if self.CurrMiniMode then + self.CurrMiniMode.CurrTimeCount = InVal; + end + table.func(self.CurrMiniMode, "OnCountTime", InVal) +end + +function MiniManager:OnMiniGameEnd() + UGCLogSystem.Log("[MiniManager:OnMiniGameEnd] ") + local Times = MiniGameConfig[self.CurrSelectMap].MiniGameTimes; + local Time = 0; + if Times and Times.MiniGameEnd then + Time = Times.MiniGameEnd; + else + Time = MiniGameTimes.MiniGameEnd; + end + -- 从小局中取出来 + GlobalTickTool:AddInternalCount(self, function(o, dt, ServerTime, t) + o:OnMiniGameTimeCount(t); + end, 1, Time, self.OnMiniGameSwitch); + self:SetState(MiniGameState.MINI_END); + self.MiniInfo.Scores = table.func(self.CurrMiniMode, "GetScore") + self.MiniInfo.Winner = self.CurrMiniMode.GameWinner; + table.func(self.CurrMiniMode, "OnGameEnd", self.MiniInfo.Scores); + self:SetMiniInfo(); +end + +function MiniManager:ClearMiniMode() + UGCLogSystem.Log("[MiniManager:ClearMiniMode] 执行销毁") + self.PlayerData = nil; + self.SelectMaps = nil; +end + +--- 切换到下一个 MiniGame +function MiniManager:OnMiniGameSwitch() + -- 检查是否还有下一个了 + UGCLogSystem.Log("[MiniManager:OnMiniGameSwitch] 执行") + if table.isEmpty(self.SelectMaps) then + self:OnGameEnd(); + return ; + end + self:UnLoadMiniGame(); + self:LoadMiniGame(); +end + +function MiniManager:SetState(InState) + if IsServer then + UGCLogSystem.Log("[MiniManager:SetState] CurrState = %s", TableHelper.printEnum(MiniGameState, InState)); + self.State = InState; + self.MiniInfo.State = InState; + self:SetMiniInfo(); + table.func(self.CurrMiniMode, 'SetState', InState); + if self.CurrMiniMode ~= nil then + self.CurrMiniMode.State = InState; + end + GameState:SetMiniState(InState); + end + -- 全局的状态 + GlobalMiniState = self.State; +end + +function MiniManager:SetRoundTimes(InTimes) + if IsServer then + self.MiniInfo.RoundTimes = InTimes; + self:SetMiniInfo(); + if self.CurrMiniMode ~= nil then + self.CurrMiniMode.RoundTimes = InTimes; + end + end +end + +function MiniManager:OnRep_RoundTimes(InOld) + if self.CurrMiniMode ~= nil then + self.CurrMiniMode.RoundTimes = self.MiniInfo.RoundTimes; + end +end + +function MiniManager:OnRep_State(InOld) + UGCLogSystem.Log("[MiniManager:OnRep_State] self.State = %s, StateName = %s", tostring(self.MiniInfo.State), TableHelper.printEnum(MiniGameState, self.State)); + self.State = self.MiniInfo.State; + --if self.CurrMiniMode then + -- self.CurrMiniMode.State = self.State; + --end + UGCEventSystem.SendEvent(EventTypes.MiniStateChange, self.State); + if self.State == MiniGameState.MINI_PREPARE then + elseif self.State == MiniGameState.ROUND_PREPARE then + self:OnPrepareEnd(); + elseif self.State == MiniGameState.ROUND_GAMING then + self:OnMiniRoundFormalStart(); + elseif self.State == MiniGameState.ROUND_END then + self:OnMiniRoundEnd(); + elseif self.State == MiniGameState.MINI_END then + self:OnMiniGameEnd(); + elseif self.State == MiniGameState.ENDED then + self:OnGameEnd(); + end + GlobalMiniState = self.State; +end + +--- 设置同步 MiniInfo, +function MiniManager:SetMiniInfo() + self.Owner:SetMiniInfo(self.MiniInfo); +end + +--- 设置游戏数据 +---@vararg +function MiniManager:SetGameInfo(InName, InInfo) + UGCLogSystem.LogTree(string.format("[MiniManager:SetGameInfo] InInfo ="), InInfo) + if type(InInfo) == 'table' then + self.MiniInfo[InName] = TableHelper.DeepCopyTable(InInfo); + else + self.MiniInfo[InName] = InInfo; + end + self:SetMiniInfo(); +end + +-- 给予子模块的数据同步 +function MiniManager:DOREPONCE(Name) + if self.CurrMiniMode then + self:SetGameInfo(Name, self.CurrMiniMode[Name]); + end +end + +----------------------------------- 地图函数 ----------------------------------- + +MiniManager.CurrLoadMapName = nil; + +function MiniManager:RandomSelectMap() + local MapNames = MiniGameConfig[self.CurrSelectMap].Map.MapName; + local MapName = ""; + if type(MapNames) == 'table' then + local Total = 0; + local Maps = {}; + for Name, Rate in pairs(MapNames) do + if type(Name) == 'string' then + Total = Total + Rate; + table.insert(Maps, { + Name = Name, + Rate = Rate, + }); + elseif type(Name) == 'int32' then + Total = Total + 1; + table.insert(Maps, { + Name = Rate, + Rate = 1, + }) + end + end + local MapCount = table.getCount(Maps); + if Total == 0 then + -- 从这两个中随机一个 + MapName = Maps[math.random(MapCount)].Name; + else + local Num = KismetMathLibrary.RandomFloat() + local RandomNum = Num * Total; + for i = 1, table.getCount(Maps) do + RandomNum = RandomNum - Maps[i].Rate; + if RandomNum <= 0 then + MapName = Maps[i].Name; + break ; + end + end + end + elseif type(MapNames) == 'string' then + MapName = MapNames; + end + return MapName; +end + +--- 加载地图 +function MiniManager:LoadMap(InIndex) + UGCLogSystem.Log("[MiniManager:LoadMap] 执行") + if InIndex == nil then InIndex = self.CurrSelectMap end + if self.HadLoadMap == InIndex then return ; end + -- 检查当前是什么东西,如果是随机的话 + local MapName = table.func(self.CurrMiniMode, "SelectMapName", InIndex); + if MapName == nil or string.len(MapName) == 0 then + MapName = self:RandomSelectMap(); + end + + UGCLogSystem.Log("[MiniManager:LoadMap] LoadMap = %s", MapName); + + self.CurrLoadMapName = MapName; + UGCLogSystem.Log("[MiniManager:LoadMap] 执行 END"); + self.Owner:LoadMap(MapName); + self.HadLoadMap = InIndex; +end + +--- 完成加载地图 +function MiniManager:OnMapLoadComplete() + UGCLogSystem.Log("[MiniManager:OnMapLoadComplete] 地图加载完成") + if IsServer then + UE.ResetGame(0.5); + end + self:OnMapLoaded(); +end + +--- 加载地图 +function MiniManager:OnMapLoaded() + UGCLogSystem.Log("[MiniManager:OnMapLoaded] 加载地图成功") + table.func(self.CurrMiniMode, "OnAlready"); +end + +--- 卸载地图 +function MiniManager:UnLoadMap() + -- 然后过一会再重新加载地图 + self.Owner:UnloadMap({ self.CurrLoadMapName }); + self.HadLoadMap = nil; +end + +function MiniManager:OnMapUnLoadedComplete() + UGCLogSystem.Log("[MiniManager:OnMapUnLoadedComplete] 异步卸载地图完成") +end + +--- 玩家选择地图 +function MiniManager:OnPlayerSelectMap(InPlayer, InMapIndex) + if IsServer then + table.insert(self.SelectMaps, InMapIndex); + -- 发送 RPC + self:SendRPC("OnPlayerSelectMap", self.SelectMaps) + else + UGCEventSystem.SendEvent(EventTypes.MiniGame_SelectMap, self.SelectMaps); + end +end + +----------------------------------- 回合函数 ----------------------------------- +--- 开启小局 +function MiniManager:OnMiniRoundPrepare() + -- 小局次数 - 1 + if IsServer then + self:LoadMap(self.CurrSelectMap); + local Times = MiniGameConfig[self.CurrSelectMap].MiniGameTimes; + local Time = (Times == nil or Times.Prepare == nil) and MiniGameTimes.RoundPrepare or Times.Prepare; + GlobalTickTool:AddInternalCount(self, function(o, dt, ServerTime, t) + local InTime = t; + if Time > 0 then InTime = Time - t end + o:OnMiniGameTimeCount(InTime) + self:OnBeforeGameStart(t); + end, 1, Time, self.OnMiniRoundFormalStart); + self.CurrMiniMode.RoundTimes = self.CurrMiniMode.RoundTimes - 1; + self.CurrMiniMode.bRoundEnd = false; + self:SetState(MiniGameState.ROUND_PREPARE); + self:SetRoundTimes(self.CurrMiniMode.RoundTimes); + else + -- 看看是否要执行什么 + end + table.func(self.CurrMiniMode, "OnRoundStart", self:GetCurrRoundTimes()); + if self.CurrMiniMode then + self.CurrMiniMode.RoundEndTime = 0; + end +end + +--- 小局正式开始 +function MiniManager:OnMiniRoundFormalStart() + -- 这是正式开启了 + UGCLogSystem.Log("[MiniManager:OnMiniRoundFormalStart] 正式开始游戏") + if self.CurrMiniMode then + self.CurrMiniMode.RoundStartTime = UE.GetServerTime(); + end + if IsServer then + -- 启动计时,让小游戏有一个时限 + local TotalTime = MiniGameTimes.RoundGameTime; + GlobalTickTool:AddInternalCount(self, function(o, dt, ServerTime, t) + local InTime = t; + if TotalTime > 0 then InTime = TotalTime - t end + o:OnMiniGameTimeCount(InTime); + end, 1., math.abs(TotalTime), self.OnMiniRoundEnd, function(o) + return o.CurrMiniMode.bGameEnd or o.CurrMiniMode.bRoundEnd; + end); + + self:SetState(MiniGameState.ROUND_GAMING); + -- 解除玩家封禁状态 + UE.ClearSceneObjects(); + else + -- 是否显示 “回合正式开始!” + end + table.func(self.CurrMiniMode, "OnRoundFormalStart", self:GetCurrRoundTimes(), self.CurrMiniMode.RoundStartTime); +end + +function MiniManager:OnMiniRoundEnd() + if self.State == MiniGameState.ROUND_GAMING then + if self.CurrMiniMode.bGameEnd == false and self.CurrMiniMode.bRoundEnd == false then + table.func(self.CurrMiniMode, "OnTimeExhausted", self.State) + end + end + -- 通知结束了 + UGCLogSystem.Log("[MiniManager:OnMiniRoundEnd] 结束") + self.CurrMiniMode.RoundEndTime = UE.GetServerTime(); + local Winner = 0; + if IsServer then + local Times = MiniGameConfig[self.CurrSelectMap].MiniGameTimes; + local Time = 0; + if Times and Times.RoundEnd then + Time = Times.RoundEnd; + else + Time = MiniGameTimes.RoundEnd; + end + + UGCLogSystem.Log("[MiniManager:OnMiniRoundEnd] RoundTimes = %d", self.CurrMiniMode.RoundTimes) + UGCLogSystem.Log("[MiniManager:OnMiniRoundEnd] bGameEnd = %s", tostring(self.CurrMiniMode.bGameEnd)) + if self.CurrMiniMode.RoundTimes <= 0 or self.CurrMiniMode.bGameEnd then + UGCLogSystem.Log("[MiniManager:OnMiniRoundEnd] 回合结束") + GlobalTickTool:AddInternalCount(self, function(o, dt, ServerTime, t) + o:OnMiniGameTimeCount(t); + end, 1, Time, self.OnMiniGameEnd); + else + -- 继续 + -- 开始计时 + UGCLogSystem.Log("[MiniManager:OnMiniRoundEnd] 下一小局开始") + GlobalTickTool:AddInternalCount(self, function(o, dt, ServerTime, t) + o:OnMiniGameTimeCount(t); + end, 1, Time, self.OnMiniRoundPrepare); + end + if table.hasFunc(self.CurrMiniMode, 'GetRoundWinner') then + self.MiniInfo.RoundWinner = table.func(self.CurrMiniMode, "GetRoundWinner", self:GetCurrRoundTimes()); + end + Winner = self.MiniInfo.RoundWinner; + table.func(self.CurrMiniMode, "OnRoundEnd", self:GetCurrRoundTimes(), Winner, self.CurrMiniMode.RoundEndTime - self.CurrMiniMode.RoundStartTime); + UGCLogSystem.Log("[MiniManager:OnMiniRoundEnd] Winner = %s", tostring(Winner)) + self:SetState(MiniGameState.ROUND_END); + else + -- 显示回合成功或者失败,执行到此一定可以拿到Winner是谁 + -- 直接获取 Winner + Winner = self.MiniInfo.RoundWinner + UGCLogSystem.Log("[MiniManager:OnMiniRoundEnd] RoundWinner = %s", tostring(Winner)); + table.func(self.CurrMiniMode, "OnRoundEnd", self:GetCurrRoundTimes(), Winner, self.CurrMiniMode.RoundEndTime - self.CurrMiniMode.RoundStartTime); + end +end + +----------------------------------- 玩家函数 ----------------------------------- +--- 当添加玩家的时候执行 +function MiniManager:OnPlayerLogin(InPlayerKey) + UGCLogSystem.Log("[MiniManager:OnPlayerLogin] 玩家:%d 登录", InPlayerKey); + table.func(self.CurrMiniMode, "OnPlayerLogin", InPlayerKey); + -- 获取玩家的排位分 + UGCRankSystem.GetUGCRank(InPlayerKey); +end + +function MiniManager:OnPlayerLeave(InPlayerKey) + UGCLogSystem.Log("[MiniManager:OnPlayerLeave] 玩家:%d 登出", InPlayerKey); + table.func(self.CurrMiniMode, "OnPlayerLeave", InPlayerKey); +end + +---@param PlayerStartList table> +---@param Controller UGCPlayerController_C +function MiniManager:SelectPlayerStart(PlayerStartList, Controller) + return table.func(self.CurrMiniMode, 'SelectPlayerStart', PlayerStartList, Controller); +end + +--- S & C 玩家在加载好之后进行的初始化操作 +function MiniManager:OnPawnInit(Pawn) + if IsServer then + --UGCLogSystem.LogTree(string.format("[MiniManager:OnPawnInit] GameConfig ="), MiniGameConfig); + UGCLogSystem.Log("[MiniManager:OnPawnInit] self.CurrSelectMap = %s", tostring(self.CurrSelectMap)) + if self.CurrSelectMap == nil then return ; end + local InitArmors = MiniGameConfig[self.CurrSelectMap].InitArmors; + local InitMedication = MiniGameConfig[self.CurrSelectMap].InitMedication; + table.func(self.CurrMiniMode, 'OnPawnInit', Pawn, InitArmors, InitMedication); + else + table.func(self.CurrMiniMode, 'OnPawnInit', Pawn); + end +end + +--- 当玩家死亡 +---@param DeadPlayerKey PlayerKey +---@param KillerPlayerKey PlayerKey +function MiniManager:OnPlayerDead(DeadPlayerKey, KillerPlayerKey) + table.func(self.CurrMiniMode, 'OnPlayerDead', DeadPlayerKey, KillerPlayerKey); + if IsServer then + -- 发送 RPC + self:SendRPC("OnPlayerDead", DeadPlayerKey, KillerPlayerKey); + end +end + +function MiniManager:OnPlayerRespawn(InPlayerKey) + table.func(self.CurrMiniMode, "OnPlayerRespawn", InPlayerKey) +end + +function MiniManager:OnPlayerPossessed(Pawn, NewController) + -- 检查是否有初始武器,如果有,那么直接添加 + UGCLogSystem.Log("[MiniManager:OnPlayerPossessed] 执行") + table.func(self.CurrMiniMode, "OnPlayerPossessed", Pawn, NewController); +end + +--- 仅在服务器存在 +function MiniManager:OnPlayerInjury(PlayerKey, CauserKey, DamageInfo) + UGCLogSystem.LogTree(string.format("[MiniManager:OnPlayerInjury] DamageInfo ="), DamageInfo) + table.func(self.CurrMiniMode, "OnPlayerInjury", PlayerKey, CauserKey, DamageInfo); +end + +---@param InPawn UGCPlayerPawn_C +---@param Weapon ASTExtraWeapon +function MiniManager:OnPlayerGetWeapon(InPawn, Weapon) + if self.CurrMiniMode then + table.func(self.CurrMiniMode, "OnPlayerGetWeapon", InPawn, Weapon); + end +end + +--- 射击导致子弹数量发生改变 +---@param PlayerKey PlayerKey 玩家 Key +---@param WeaponID int32 武器 ID +---@param PreCount int32 射击前数量 +---@param CurrCount int32 当前数量 +function MiniManager:OnBulletNumChange(PlayerKey, WeaponID, PreCount, CurrCount) + table.func(self.CurrMiniMode, "OnBulletNumChange", PlayerKey, WeaponID, PreCount, CurrCount); +end + +------------------------------------ 获取函数 ------------------------------------ +--- 获取当前模式 +function MiniManager:GetCurrentMode() return self.CurrMiniMode; end +--- 获取当前地图名 +function MiniManager:GetCurrLevel() return MiniGameConfig[self.CurrSelectMap].Map.MapName; end +--- 获取当前显示地图名称 +function MiniManager:GetShowName() return MiniGameConfig[self.CurrSelectMap].Map.ShowName; end +--- 获取当前是第几回合 +function MiniManager:GetCurrRoundTimes() + if table.isEmpty(MiniGameConfig) or self.CurrSelectMap == nil or table.isEmpty(MiniGameConfig[self.CurrSelectMap]) then + return 1; + end + if MiniGameConfig[self.CurrSelectMap].RoundTimes == nil then + return 1; + else + return MiniGameConfig[self.CurrSelectMap].RoundTimes - self.CurrMiniMode.RoundTimes; + end +end + +--- 获取总的回合数 +function MiniManager:GetTotalRoundTimes() + if table.isEmpty(MiniGameConfig) or self.CurrSelectMap == nil or table.isEmpty(MiniGameConfig[self.CurrSelectMap]) then + return 1; + end + if MiniGameConfig[self.CurrSelectMap].RoundTimes == nil then + return 1; + else + return MiniGameConfig[self.CurrSelectMap].RoundTimes + end +end + +------------------------------------ 给予函数 ------------------------------------ +--- 所有玩家死亡 +function MiniManager:AllPlayerDead() + for i, v in pairs(UGCGameSystem.GetAllPlayerPawn()) do + if v:IsAlive() then v:K2_DestroyActor(); end + end +end + +--- 所有玩家重生 +function MiniManager:AllPlayerRespawn(InTime) + self:AllPlayerDead(); + UGCEventSystem.SetTimer(self.Owner, function() + for i, v in pairs(UGCGameSystem.GetAllPlayerController(false)) do + UGCGameSystem.RespawnPlayer(v.PlayerKey); + end + end, InTime); +end + +---@param InPawn UGCPlayerPawn_C +---@param InState EPawnState +function MiniManager:SetPawnState(InPawn, InState, IsSet) + if IsSet then + UGCPawnSystem.EnterPawnState(InPawn, InState) + else + UGCPawnSystem.LeavePawnState(InPawn, InState) + end +end + +--- 这个需要放在 GameState 中进行更改 +function MiniManager:DOREPONCE(k, v) + self.Owner[k] = v; + DOREPONCE(self.Owner, k); +end + +MiniManager.CachedMiniInfo = {}; + +--- 缓存一份 +function MiniManager:MakeCachedMiniInfo() + if self.CachedMiniInfo.State == nil then + self.CachedMiniInfo.State = MiniGameState.NON_START; + end +end + +--- 属性同步,对比是否不同,只有不同的会进行 OnRep_ 否则就不会进行。 +function MiniManager:OnRep_MiniInfo(InOld) + --UGCLogSystem.LogTree(string.format("[MiniManager:OnRep_MiniInfo] self.MiniInfo ="), self.MiniInfo) + --UGCLogSystem.LogTree(string.format("[MiniManager:OnRep_MiniInfo] self.CachedMiniInfo Begin ="), self.CachedMiniInfo) + for i, v in pairs(self.MiniInfo) do + -- 如果发生改变再执行对应的 OnRep + if type(v) == 'table' then + -- 比较一下这两者有什么不同 + if not table.compare(v, self.CachedMiniInfo[i]) then + -- 更新一下 + UGCLogSystem.Log("[MiniManager:OnRep_MiniInfo] 相同变量 Index = %s", tostring(i)); + if self:IsRepProp(tostring(i)) then + self[i] = v; + table.func(self, "OnRep_" .. tostring(i), self.CachedMiniInfo[i]); + end + if self.CurrMiniMode ~= nil then + self.CurrMiniMode[i] = TableHelper.DeepCopyTable(v); + table.func(self.CurrMiniMode, "OnRep_" .. tostring(i), self.CachedMiniInfo[i]); + end + end + else + if self.CachedMiniInfo[i] ~= v then + if self:IsRepProp(tostring(i)) then + self[i] = v; + table.func(self, "OnRep_" .. tostring(i), self.CachedMiniInfo[i]); + end + if self.CurrMiniMode ~= nil then + self.CurrMiniMode[i] = v; + table.func(self.CurrMiniMode, "OnRep_" .. tostring(i), self.CachedMiniInfo[i]); + end + end + end + UGCLogSystem.Log("[MiniManager:OnRep_MiniInfo] Index = %s", i); + self.CachedMiniInfo[i] = nil; + --UGCLogSystem.LogTree(string.format("[MiniManager:OnRep_MiniInfo] self.CachedMiniInfo ="), self.CachedMiniInfo) + end + --UGCLogSystem.LogTree(string.format("[MiniManager:OnRep_MiniInfo] self.CachedMiniInfo End ="), self.CachedMiniInfo) + -- 检查是否有多余的 + for i, v in pairs(self.CachedMiniInfo) do + if self.MiniInfo[i] == nil then + if self:IsRepProp(tostring(i)) then + self[tostring(i)] = nil; + table.func(self, "OnRep_" .. tostring(i), v); + end + if self.CurrMiniMode ~= nil then + self.CurrMiniMode[tostring(i)] = nil; + table.func(self.CurrMiniMode, "OnRep_" .. tostring(i), v); + end + UGCLogSystem.Log("[MiniManager:OnRep_MiniInfo] 执行冗余的 Index = %s", tostring(i)); + end + UGCLogSystem.Log("[MiniManager:OnRep_MiniInfo] 冗余的 Index = %s", tostring(i)); + end + + -- 设置上去进行缓存 + self.CachedMiniInfo = TableHelper.DeepCopyTable(self.MiniInfo); + --UGCLogSystem.LogTree(string.format("[MiniManager:OnRep_MiniInfo] self.CachedMiniInfo Final ="), self.CachedMiniInfo) +end + +--- 获取内部数据 +function MiniManager:GetMiniInfo(InName) + if self.CurrMiniMode then + local Item = table.func(self.CurrMiniMode, "GetMiniInfo", InName); + if Item ~= nil then return Item; end + return self.CurrMiniMode[InName]; + end + return nil; +end + +function MiniManager:UpdateInternalCount(InCount) + UGCLogSystem.Log("[MiniManager:UpdateInternalCount] self.TimerHandlers = %s", tostring(self.TimerHandlers)); + GlobalTickTool:UpdateInternalCountByHandle(self.TimerHandlers, InCount); +end \ No newline at end of file diff --git a/SoloKing/Script/Global/Mini/Script/Mini_Solo.lua b/SoloKing/Script/Global/Mini/Script/Mini_Solo.lua new file mode 100644 index 00000000..61bb9019 --- /dev/null +++ b/SoloKing/Script/Global/Mini/Script/Mini_Solo.lua @@ -0,0 +1,2125 @@ +local Mini_Solo = {}; + +Mini_Solo.RoundWinner = nil; +--- 游戏获胜者 +Mini_Solo.GameWinner = nil; +Mini_Solo.GameLoser = nil; + +---@class RoundWinnerInfo +---@field Winner PlayerKey +---@field Time float +---@field Weapon ItemId +---@field Score RoundWinnerScore + +---@class RoundWinnerScore +---@field Winner int32 +---@field Loser int32 + +---@class MiniSolo_RankScore +---@field PlayerKey PlayerKey +---@field Current int32 +---@field Add int32 +---@field AddHide int32 +---@field HideScore int32 + +---@type table +Mini_Solo.RoundWinners = {}; +---@type table> 玩家选择的武器 +Mini_Solo.SelectWeapons = {}; +Mini_Solo.Damages = {}; +---@type table +Mini_Solo.RoundDeadTimes = {}; +--- @type table> +Mini_Solo.Disables = {}; +---@type table +Mini_Solo.RankScores = {}; +Mini_Solo.DeadCount = 0; +Mini_Solo.CurrTimeCount = 0; -- 可以直接拿到的倒计时 +Mini_Solo.TotalKDA = {}; +--- 模式 +Mini_Solo.ModeType = nil; +Mini_Solo.IsLobbyTeam = false; + +--- 参数在 MiniGameConfig 中的 Params 中写,此时可以写软资源的异步加载 +function Mini_Solo:Init(Manager, ...) + UGCLogSystem.Log("[Mini_Solo:Init] 执行") + if IsServer then + PoisonManager = require("Script.Blueprint.SceneObj.Poison.PoisonManager"); + end + self.ModeType = GameModeConfig.EGameModeType.DefaultMode; + return true; +end + +--- 在 Init 执行之后调用, +function Mini_Solo:OnPrepare() + -- 显示 UI + if IsServer then + self:LoadArchive(); + else + self:ShowSelectWeaponUI(); + UGCVoiceManagerSystem.SetGlobalVoiceRadius(1000 * 100); + end +end + +function Mini_Solo:LoadArchive() + -- 从存档中加载 Disables + if IsServer then + for i, PC in pairs(UGCGameSystem.GetAllPlayerController(false)) do + local PlayerKey = PC.PlayerKey + self.TotalKDA[PlayerKey] = {}; + if table.isEmpty(self.Disables[PlayerKey]) then + if self.Disables[PlayerKey] == nil then self.Disables[PlayerKey] = {}; end + if ArchiveTable[PlayerKey] and ArchiveTable[PlayerKey].Disables then + for Type, Enable in pairs(ArchiveTable[PlayerKey].Disables) do + self.Disables[PlayerKey][Type] = Enable; + end + UGCLogSystem.LogTree(string.format("[Mini_Solo:LoadArchive] ArchiveData.Disables ="), self.Disables) + end + --- 使用默认 + for Type, Info in pairs(DisableInfo) do + if self.Disables[PlayerKey][Type] == nil and Info.Enable then + self.Disables[PlayerKey][Type] = false; + end + end + end + end + UGCLogSystem.LogTree(string.format("[Mini_Solo:LoadArchive] self.Disables ="), self.Disables) + end +end + +function Mini_Solo:ShowSelectWeaponUI() + if IsClient then + if self.State <= MiniGameState.ROUND_PREPARE then + if LocalIsGlobalSpectator then + if not WidgetManager:IsVisiblePanel(WidgetConfig.EUIType.AllWeapon_Spectator) then + UGCLogSystem.Log("[Mini_Solo:ShowSelectWeaponUI] 显示观战界面"); + WidgetManager:ShowPanel(WidgetConfig.EUIType.AllWeapon_Spectator, false, self.SelectWeaponCount, self.PlayerSelectMaps); + end + -- 隐藏一下 OBUI + else + if not WidgetManager:IsVisiblePanel(WidgetConfig.EUIType.AllWeapon) then + UGCLogSystem.Log("[Mini_Solo:ShowSelectWeaponUI] 显示所有武器界面"); + WidgetManager:ShowPanel(WidgetConfig.EUIType.AllWeapon, false, self.SelectWeaponCount, self.PlayerSelectMaps); + --- 显示段位继承 UI + end + if not WidgetManager:IsVisiblePanel(WidgetConfig.EUIType.ShowRankInheritance) then + self:ShowRankInheritanceUI(); + end + end + end + end +end + +function Mini_Solo:OnClientAlready() + if IsServer then + for _, PS in pairs(UGCGameSystem.GetAllPlayerController(false)) do + self.PlayerSelectMaps[PS.PlayerKey] = ArchiveTable[PS.PlayerKey].LastSelectMap; + end + -- 保存一个随机的 + UGCLogSystem.LogTree(string.format("[Mini_Solo:OnClientAlready] PlayerSelectMaps ="), self.PlayerSelectMaps) + GameState:SetMiniInitData("RandomMapName", self.PlayerSelectMaps); + self:DOREPONCE("PlayerSelectMaps"); + + -- 开启队伍判断 + UGCGameSystem.SendModeCustomEvent("ChangeTeamID"); + + self:LoadArchive(); + self:DOREPONCE("Disables"); + else + self:ShowSelectWeaponUI(); + end +end + +function Mini_Solo:OnUIAlready() + UGCLogSystem.Log("[Mini_Solo:OnUIAlready] 执行"); + if IsClient then + -- 此时和平精英已经准备就绪了 + UGCVoiceManagerSystem.SetGlobalVoiceRadius(1000 * 100); + self:ShowSelectWeaponUI(); + end +end + +Mini_Solo.PrepareEnd_Once = false; + +function Mini_Solo:OnPrepareEnd() + UGCLogSystem.Log("[Mini_Solo:OnPrepareEnd] 执行") + if self.PrepareEnd_Once then return ; end + self.PrepareEnd_Once = true; + if IsClient then + -- 关闭界面 + UGCEventSystem.SetTimer(GameState, function() + WidgetManager:ClosePanel(WidgetConfig.EUIType.AllWeapon); + WidgetManager:ClosePanel(WidgetConfig.EUIType.ShowRankInheritance); + WidgetManager:ClosePanel(WidgetConfig.EUIType.AllWeapon_Spectator); + + if table.isEmpty(self.RoundWinners) then + WidgetManager:ShowPanel(WidgetConfig.EUIType.ShowPK, false) + end + end, 0.5); + UGCEventSystem.SetTimer(GameState, function() + UGCLogSystem.Log("[Mini_Solo:OnPrepareEnd] EnableShovel = %s", tostring(GameState.EnableShovel)); + WidgetManager:ShowPanel(WidgetConfig.EUIType.TipSlidingTackle, false, GameState.EnableShovel) + end, 3); + else + UGCLogSystem.LogTree(string.format("[Mini_Solo:OnPrepareEnd] SelectWeapons First"), self.SelectWeapons) + if self.ModeType == GameModeConfig.EGameModeType.DefaultMode then + -- 记录一下玩家选择的 + for PlayerKey, List in pairs(self.SelectWeapons) do + for i, WeaponId in pairs(List) do self:AddSelectWeaponsArchive(PlayerKey, WeaponId, 1, 1); end + end + + if table.isEmpty(self.SelectWeapons) then + -- 直接匹配所有的枪械,然后选择局数个 + if table.isEmpty(WeaponIdTable) then GetWeaponIdTable() end + for i = 1, self.TotalRoundTimes do table.insert(self.SelectWeapons, WeaponIdTable[i]); end + else + if table.getCount(self.SelectWeapons) == 1 then + -- 选择他选择的所有枪械 + local Table = {}; + local TempWeapons = {}; + for i, v in pairs(self.SelectWeapons) do + for c, d in pairs(v) do + Table[d] = true; + table.insert(TempWeapons, d); + end + end + -- 然后再看够不够,不够差多少 + self.SelectWeapons = TempWeapons; + table.Shuffle(WeaponIdTable); + local Count = self.TotalRoundTimes - table.getCount(Table); + UGCLogSystem.Log("[Mini_Solo:OnPrepareEnd] Count = %d", Count); + if Count > 0 then + for i, v in pairs(WeaponIdTable) do + if Table[v] == nil then + table.insert(self.SelectWeapons, v); + Count = Count - 1; + if Count <= 0 then break ; end + end + end + end + UGCLogSystem.LogTree(string.format("[Mini_Solo:OnPrepareEnd] SelectWeapons ="), self.SelectWeapons) + else + --- 保存一下当前选择的武器 + for PlayerKey, Info in pairs(UE.GetAccountInfo()) do + local Config = self.SelectWeapons[PlayerKey] + -- 保存一下选择的武器 + if Config then + ArchiveTable[PlayerKey].LastSelectWeapons = TableHelper.DeepCopyTable(Config); + end + end + + -- 找到都选择了的,这些进行全部加入,然后再混合两边各选择一些 + local Keys = table.getKeys(self.SelectWeapons); + local SameTables = table.intersection(self.SelectWeapons[Keys[1]], self.SelectWeapons[Keys[2]]); + UGCLogSystem.LogTree(string.format("[Mini_Solo:OnPrepareEnd] SameTables ="), SameTables) + local SameMap = {}; + for i, v in pairs(SameTables) do SameMap[v] = true; end + + -- 去除相同的,遗留不同的 + local Table = {}; + for PlayerKey, v in pairs(self.SelectWeapons) do + for c, d in pairs(v) do + Table[d] = true; + if SameMap[d] then v[c] = nil; end + end + end + + -- 检查剩下的够不够所需的,如果够了,从中选择,不够的话那就全部加入再添加即可 + local WeaponCount = 0; + local PlayerWeapons = {}; + + for i, v in pairs(self.SelectWeapons) do + if PlayerWeapons[i] == nil then PlayerWeapons[i] = {}; end + for c, d in pairs(v) do + WeaponCount = WeaponCount + 1; + table.insert(PlayerWeapons[i], d); + end + end + + local AddWeapons = {}; + local CountNum = #PlayerWeapons[Keys[1]]; + if not table.isEmpty(PlayerWeapons[Keys[1]]) then + for i = 1, CountNum do + for c = 1, #Keys do + if PlayerWeapons[Keys[c]][i] then table.insert(AddWeapons, PlayerWeapons[Keys[c]][i]); end + end + end + end + + if Keys[2] then + if #PlayerWeapons[Keys[2]] > CountNum then + for i = CountNum + 1, #PlayerWeapons[Keys[2]] do + table.insert(AddWeapons, PlayerWeapons[Keys[2]][i]); + end + end + end + + -- 如果刚好够了,就全部加入 + local NeedCount = self.TotalRoundTimes - table.getCount(SameTables) + UGCLogSystem.Log("[Mini_Solo:OnPrepareEnd] NeedCount = %d", NeedCount); + + UGCLogSystem.Log("[Mini_Solo:OnPrepareEnd] WeaponCount = %d", WeaponCount); + if WeaponCount == NeedCount then + for i = 1, #AddWeapons do table.insert(SameTables, AddWeapons[i]); end + elseif WeaponCount < NeedCount then + for i, v in pairs(AddWeapons) do table.insert(SameTables, v); end + table.Shuffle(WeaponIdTable); + UGCLogSystem.LogTree(string.format("[Mini_Solo:OnPrepareEnd] WeaponIdTable ="), WeaponIdTable); + for i, v in pairs(WeaponIdTable) do + if Table[v] == nil then + table.insert(SameTables, v); + if table.getCount(SameTables) == self.TotalRoundTimes then break ; end + end + end + else + -- 从中选择 剩下的 + for i = 1, NeedCount do table.insert(SameTables, AddWeapons[i]); end + end + self.SelectWeapons = SameTables; + end + end + end + + UGCLogSystem.LogTree(string.format("[Mini_Solo:OnPrepareEnd] SelectWeapons"), self.SelectWeapons) + + self:DOREPONCE("SelectWeapons"); -- 再次同步 + + UGCLogSystem.LogTree(string.format("[Mini_Solo:OnPrepareEnd] Disables ="), self.Disables) + -- 先保存一下玩家设置的 + local DisTable = {}; + for PlayerKey, Table in pairs(self.Disables) do + local PC = UGCGameSystem.GetPlayerControllerByPlayerKey(PlayerKey); + ArchiveTable[PC.PlayerKey].Disables = {}; + for Type, Enable in pairs(Table) do ArchiveTable[PC.PlayerKey].Disables[Type] = Enable; end + + for Type, Enable in pairs(Table) do + if Enable then DisTable[Type] = (DisTable[Type] or 0) + 1; end + end + end + UGCLogSystem.LogTree(string.format("[Mini_Solo:OnPrepareEnd] DisTable ="), DisTable) + local PCCount = table.getCount(UGCGameSystem.GetAllPlayerController(false)); + + --- 检查地图 + local DelayWeapons = MiniGameConfig[self.Owner.CurrSelectMap].DelayWeapons + if self.ModeType == GameModeConfig.EGameModeType.DefaultMode then + local MapName = GameState.LoadMapName; + UGCLogSystem.Log("[Mini_Solo:OnPrepareEnd] MapName = " .. tostring(MapName)); + local MapAddedItem = MiniGameConfig[MiniGameMapType.SoloKing].MapAddedItem[MapName]; + UGCLogSystem.LogTree(string.format("[Mini_Solo:OnPrepareEnd] MapAddedItem ="), MapAddedItem) + if MapAddedItem ~= nil then + for i, v in pairs(DelayWeapons) do + if v[2] ~= nil and v[2] > 0 and v[1] == '手榴弹' then + table.insert(DelayWeapons, MapAddedItem[1]); + break ; + end + end + end + else + table.insert(DelayWeapons, { "燃烧瓶", 1 }); + end + UGCLogSystem.LogTree(string.format("[Mini_Solo:OnPrepareEnd] DelayWeapons ="), MiniGameConfig[self.Owner.CurrSelectMap].DelayWeapons); + + for Type, Count in pairs(DisTable) do + if Count == PCCount then + -- 开始执行 + if Type == EDisableType.Grenade then + for i, v in pairs(DelayWeapons) do + if v[1] == '手榴弹' or v[1] == '燃烧瓶' then v[2] = 0; end + end + elseif Type == EDisableType.SmokeBomb then + for i, v in pairs(DelayWeapons) do + if v[1] == '烟雾弹' then + v[2] = 0; + break ; + end + end + elseif Type == EDisableType.FlashBang then + for i, v in pairs(DelayWeapons) do + if v[1] == '震爆弹' then + v[2] = 0; + break ; + end + end + elseif Type == EDisableType.Shovel2 then + -- 设置无法滑铲 + UGCLogSystem.Log("[Mini_Solo:OnPrepareEnd] 禁止滑铲") + GameMode.bIsOpenShovelingAbility = true; + GameState.bIsOpenShovelingAbility = true; + GameState.EnableShovel = true; + end + end + end + end +end + +function Mini_Solo:OnCountTime(InTime) + if self.State < MiniGameState.ROUND_GAMING then + if IsClient then + UGCLogSystem.Log("[Mini_Solo:OnCountTime] SelectMapTime = %s", tostring(self.SelectMapTime)); + if InTime >= self.SelectMapTime then + WidgetManager:GetPanel(WidgetConfig.EUIType.AllWeapon, function(Widget) + Widget:UpdateSelectCountDown(InTime - self.SelectMapTime); + end) + elseif InTime == self.SelectMapTime - 1 then + -- 切换过去 + WidgetManager:GetPanel(WidgetConfig.EUIType.AllWeapon, function(Widget) + table.func(Widget, "SetSelectMapEnable", false); + table.func(Widget, "SwitchSelectMap"); + end) + end + + if LocalIsGlobalSpectator then + UGCLogSystem.Log("[Mini_Solo:OnCountTime] 当前是观战玩家") + if not WidgetManager:IsVisiblePanel(WidgetConfig.EUIType.AllWeapon_Spectator) then + UGCLogSystem.Log("[Mini_Solo:OnCountTime] 显示出来观战 UI") + WidgetManager:ShowPanel(WidgetConfig.EUIType.AllWeapon_Spectator, false, self.SelectWeaponCount, self.PlayerSelectMaps); + end + end + else + -- 开始加载 + if InTime == self.SelectMapTime - 1 then + self:GotoSelectMap(); + end + end + end +end + +function Mini_Solo:GotoSelectMap() + if GameState ~= nil and GameState.LoadMapName ~= nil then return end + self.Owner:LoadMap(); + + local CurrMap = self.Owner.CurrLoadMapName; + UGCLogSystem.Log("[Mini_Solo:GotoSelectMap] 执行 MapName = %s", tostring(CurrMap)); + -- 记录一下玩家选择的地图 + for i, PC in pairs(UGCGameSystem.GetAllPlayerController(false)) do + local PlayerKey = PC.PlayerKey; + if ArchiveTable[PlayerKey].SelectMaps == nil then ArchiveTable[PlayerKey].SelectMaps = {}; end + local Map = self.PlayerSelectMaps[PlayerKey] + if Map ~= nil then + ArchiveTable[PlayerKey].SelectMaps[Map] = (ArchiveTable[PlayerKey].SelectMaps[Map] or 0) + 1 + if ArchiveTable[PlayerKey].NoSelectMaps == nil then ArchiveTable[PlayerKey].NoSelectMaps = {}; end + if CurrMap then + if Map ~= CurrMap then + -- 这是未选择过的Map + ArchiveTable[PlayerKey].NoSelectMaps[Map] = (ArchiveTable[PlayerKey].NoSelectMaps[Map] or 0) + 1; + else + -- 清空该项 + ArchiveTable[PlayerKey].NoSelectMaps[Map] = (ArchiveTable[PlayerKey].NoSelectMaps[Map] or 0) - 3; + if ArchiveTable[PlayerKey].NoSelectMaps[Map] < 0 then ArchiveTable[PlayerKey].NoSelectMaps[Map] = 0; end + end + end + end + ArchiveTable[PlayerKey].LastSelectMap = Map or ArchiveTable[PlayerKey].LastSelectMap; + end +end + +function Mini_Solo:OnTimeExhausted(InState) + if IsServer then + -- 说明是时间耗尽了 + if InState == MiniGameState.ROUND_GAMING then + UGCLogSystem.Log("[Mini_Solo:OnTimeExhausted] 时间耗尽,进行计算谁获胜了"); + -- 计算谁获胜了 + local Count = table.getCount(self.RoundDeadTimes); + UGCLogSystem.Log("[Mini_Solo:OnTimeExhausted] Count = %s", tostring(Count)); + if Count == 2 then + local Table = {}; + for i, v in pairs(self.RoundDeadTimes) do + table.insert(Table, { + PlayerKey = i; + Times = v; -- 死亡次数 + }); + end + table.sort(Table, function(a, b) + return a.Times < b.Times; + end) + -- 判断是否一致 + if Table[1].Times == Table[2].Times then + self.RoundWinner = self:CheckTimeExhausted() + else + self.RoundWinner = Table[1].PlayerKey; + end + elseif Count == 1 then + -- 查看谁死了,另一个人就是获胜方 + local RoundLoser = nil; + for i, v in pairs(self.RoundDeadTimes) do + if v > 0 then RoundLoser = i; end + end + if RoundLoser then + for i, v in pairs(UE.GetAccountInfo()) do + if i ~= RoundLoser then self.RoundWinner = i; end + end + end + else + -- 一次都没死过 + self.RoundWinner = self:CheckTimeExhausted(); + end + + UGCLogSystem.Log("[Mini_Solo:OnTimeExhausted] 执行 RoundWinner = %s", tostring(self.RoundWinner)); + + if self.RoundWinner ~= nil then + local Loser = nil; + for i, v in pairs(UE.GetAccountInfo()) do + if self.RoundWinner ~= i then Loser = i; end + end + local WeaponID = self.CurrWeaponItem[self.RoundWinner] or ItemTool.GetFirstWeaponID(self.RoundWinner); + table.insert(self.RoundWinners, { + Winner = self.RoundWinner, + Time = UE.GetServerTime() - self.RoundStartTime, + -- 拿到对方的枪械 + Weapon = WeaponID, + Score = { + Winner = self.RoundDeadTimes[Loser] or 0, -- 这个是阵亡数,需要反过来 + Loser = self.RoundDeadTimes[self.RoundWinner] or 0, + }, + }); + + if self:IsFormalMode() then + self:AddSelectWeaponsArchive(self.RoundWinner, WeaponID, 3, 1); + end + else + local Weapon = nil; + for i, v in pairs(UGCGameSystem.GetAllPlayerPawn()) do + local CurWeapon = UGCWeaponManagerSystem.GetCurrentWeapon(v); + if CurWeapon then + Weapon = CurWeapon:GetWeaponItemID(); + break ; + end + end + -- 判断此时是什么情况 + local DeadTimes = 0; + if table.getCount(self.RoundDeadTimes) == 2 then DeadTimes = 1; end + table.insert(self.RoundWinners, { + Winner = nil, + Time = UE.GetServerTime() - self.RoundStartTime, + -- 拿到对方的枪械 + Weapon = Weapon, + Score = { + Winner = DeadTimes, -- 这个是阵亡数,需要反过来 + Loser = DeadTimes, + }, + }); + end + local IsOver, WinnerID = self:CheckGameEnd(); + if IsOver then + for i, v in pairs(UE.GetAccountInfo()) do + if WinnerID ~= i then self.GameLoser = i; end + end + self:SetGameOver(WinnerID); + end + self:DOREPONCE("RoundWinners"); + UGCEventSystem.SendEvent(EventTypes.UpdateRoundWinners, self.RoundWinners); + end + end +end + +function Mini_Solo:CheckTimeExhausted() + -- 判断血量 + local Winner = self:CheckTimeExhausted_Health(); + UGCLogSystem.Log("[Mini_Solo:CheckTimeExhausted] Health 胜利方:%s", tostring(Winner)); + if Winner == nil then + Winner = self:CheckTimeExhausted_Damage(); + UGCLogSystem.Log("[Mini_Solo:CheckTimeExhausted] 伤害胜利方:%s", tostring(Winner)); + if Winner == nil then return nil; end + end + return Winner; +end + +--- 通过血量进行判断 +function Mini_Solo:CheckTimeExhausted_Health() + -- 通过其他方式进行计算,计算伤害,计算血量 + UGCLogSystem.Log("[Mini_Solo:CheckTimeExhausted_Health] 开始判断Health") + local Table = {}; + for i, Pawn in pairs(UGCGameSystem.GetAllPlayerPawn()) do + if UE.IsValidPawn(Pawn) then + local Health = UGCPawnAttrSystem.GetHealth(Pawn); + table.insert(Table, { + PlayerKey = Pawn.PlayerKey, + Health = Health, + }); + end + end + local Count = table.getCount(Table); + if Count == 0 then return nil; end + if Count == 1 then return Table[1].PlayerKey; end + table.sort(Table, function(a, b) + return a.Health > b.Health; + end); + UGCLogSystem.LogTree(string.format("[Mini_Solo:CheckTimeExhausted_Health] Table ="), Table) + if Table[1].Health ~= Table[2].Health then + return Table[1].PlayerKey; + end + return nil; +end + +--- 通过伤害进行判断 +function Mini_Solo:CheckTimeExhausted_Damage() + local Table = {}; + for PlayerKey, Damage in pairs(self.RoundDamages) do + table.insert(Table, { + PlayerKey = PlayerKey, + Damage = Damage, + }); + end + UGCLogSystem.LogTree(string.format("[Mini_Solo:CheckTimeExhausted_Damage] Table ="), Table) + local Count = table.getCount(Table); + if Count == 0 then + return nil; + elseif Count == 1 then + return Table[1].PlayerKey; + end + table.sort(Table, function(a, b) return a.Damage > b.Damage; end); + if Table[1].Damage ~= Table[2].Damage then return Table[1].PlayerKey; end + return nil; +end + +function Mini_Solo:SelectMapName(MapIndex) + if DefaultSettings.EnableTest then return "Map_JCK" end + -- 过滤掉没有开放的 + if not table.isEmpty(self.PlayerSelectMaps) then + for PlayerKey, MapName in pairs(self.PlayerSelectMaps) do + if MiniGameConfig[MiniGameMapType.SoloKing].Map.MapName[MapName] == nil then + self.PlayerSelectMaps[PlayerKey] = nil; -- 设置为空 + end + end + end + + UGCLogSystem.LogTree(string.format("[Mini_Solo:SelectMapName] self.PlayerSelectMaps ="), self.PlayerSelectMaps) + -- 查看两位玩家之前选择的 + local SelectCount = table.getCount(self.PlayerSelectMaps); + if SelectCount == 1 then + for i, v in pairs(self.PlayerSelectMaps) do return v; end + elseif SelectCount == 0 then + -- 随机地图 + return self.Owner:RandomSelectMap(); + else + local PlayerNoSelectMap = {}; + for PlayerKey, Archive in pairs(ArchiveTable) do + if Archive.NoSelectMaps then + for MapName, Count in pairs(Archive.NoSelectMaps) do + PlayerNoSelectMap[PlayerKey] = (PlayerNoSelectMap[PlayerKey] or 0) + (Count > 0 and Count or 0) + end + end + end + + UGCLogSystem.LogTree(string.format("[Mini_Solo:SelectMapName] PlayerNoSelectMap ="), PlayerNoSelectMap) + if not table.isEmpty(PlayerNoSelectMap) then + local MapCounts = {}; + for PlayerKey, Count in pairs(PlayerNoSelectMap) do + table.insert(MapCounts, { + PlayerKey = PlayerKey, + Count = Count, + }) + end + table.sort(MapCounts, function(a, b) return a.Count > b.Count end) + return self.PlayerSelectMaps[MapCounts[1].PlayerKey]; + end + + local MapList = {}; + for PlayerKey, MapName in pairs(self.PlayerSelectMaps) do MapList[MapName] = (MapList[MapName] or 0) + 1; end + local Maps = {}; + for i, v in pairs(MapList) do + table.insert(Maps, { + Map = i; + val = math.pop(); + }); + end + table.sort(Maps, function(a, b) return a.val > b.val; end) + return Maps[1].Map; + end +end + +--- 在此时可以进行地图资源的加载,以及软资源的异步加载等 +function Mini_Solo:OnAlready() + UGCLogSystem.Log("[Mini_Solo:OnAlready] 可以加载地图上的东西了") + if IsServer then + PoisonManager:Init(); + end +end + +function Mini_Solo:OnPlayerGetWeapon(InPawn, InWeapon) +end + +---@param PlayerKey PlayerKey 玩家 +---@param WeaponID int32 武器ID +---@param PreCount int32 攻击前子弹数 +---@param CurrCount int32 当前子弹数(攻击后) +function Mini_Solo:OnBulletNumChange(PlayerKey, WeaponID, PreCount, CurrCount) + local Count = PreCount - CurrCount; + UGCLogSystem.Log("[Mini_Solo:OnBulletNumChange] 射击数量 = %d", Count) + self:AddSelectWeaponsArchive(PlayerKey, WeaponID, 4, Count); +end + +--- 正式开始游戏 +function Mini_Solo:Start() + UGCLogSystem.Log("[Mini_Solo:Start] 正式开始游戏,进入小游戏内部准备") +end + +Mini_Solo.HadAddWinTimes = false; +Mini_Solo.LiveInfo = { {}, {} }; + +function Mini_Solo:HandlePlayerRank(GameWinner) + if self.HadAddWinTimes then return ; end + self.HadAddWinTimes = true; + self.GameWinner = GameWinner; + UGCLogSystem.Log("[Mini_Solo:HandlePlayerRank] GameWinner = %s", tostring(GameWinner)); + + local Scores = {}; + for PlayerKey, ArchiveData in pairs(UE.GetArchiveData()) do + Scores[PlayerKey] = ArchiveData == nil and DefaultSettings.RankScore or ArchiveData.Score; + if self.GameWinner then + if self.GameWinner ~= PlayerKey and PlayerKey > 0 then self.GameLoser = PlayerKey; end + end + end + + UGCLogSystem.LogTree(string.format("[Mini_Solo:HandlePlayerRank] Scores ="), Scores) + local Diff = 0; + if self.GameLoser ~= nil and self.GameWinner ~= nil and Scores[self.GameLoser] ~= nil and Scores[self.GameWinner] ~= nil then + Diff = Scores[self.GameWinner] - Scores[self.GameLoser]; + end + + -- 计算两边比分 + local ScoreDiff = 0; + local RoundScores = {}; + for i, v in pairs(self.RoundWinners) do + if v.Winner then RoundScores[v.Winner] = (RoundScores[v.Winner] or 0) + 1; end + end + + UGCLogSystem.Log("[Mini_Solo:HandlePlayerRank] GameLoser = %s", tostring(self.GameLoser)); + + if self.GameWinner then + local Add, AddHide = 0, 0; + -- 计算技术分 + local LobbyTeamPlayerKeys = UGCTeamSystem.GetLobbyTeamKeysByPlayerKey(self.GameWinner); + for i, v in pairs(LobbyTeamPlayerKeys) do + if v ~= self.GameWinner then self.IsLobbyTeam = true; end + end + UGCLogSystem.LogTree(string.format("[Mini_Solo:HandlePlayerRank] IsLobbyTeam = %s, LobbyTeamPlayerKeys", tostring(self.IsLobbyTeam)), LobbyTeamPlayerKeys) + + if self:IsFormalMode() then + if self.GameWinner and self.GameLoser then + ScoreDiff = (RoundScores[self.GameWinner] or 0) - (RoundScores[self.GameLoser] or 0); + ScoreDiff = math.abs(ScoreDiff); + end + + Add = self.AddFunc(Diff, Scores[self.GameWinner], true); + + --- 额外分 + if ScoreDiff > 0 and Add < 10 then + local OtherAddTable = { + [2] = math.random(2), + [3] = 3, + [4] = 5, + }; + local OtherAdd = OtherAddTable[ScoreDiff] or 0; + if not self.IsLobbyTeam then OtherAdd = 5; end + Add = Add + OtherAdd; + end + + --- 扣除隐藏分 + local HideScore = ArchiveTable[self.GameWinner].HideScore or 0; + if Add > 0 and (HideScore ~= 0) then + if HideScore > 0 then + if HideScore > Add then + AddHide = Add; + Add = Add + Add; + ArchiveTable[self.GameWinner].HideScore = HideScore - Add; + else + AddHide = ArchiveTable[self.GameWinner].HideScore; + Add = Add + HideScore; + ArchiveTable[self.GameWinner].HideScore = 0; + end + end + end + UGCLogSystem.Log("[Mini_Solo:HandlePlayerRank] PlayerKey %s 加分为 %d", tostring(self.GameWinner), Add); + + ArchiveTable[self.GameWinner].TotalGameTimes = (ArchiveTable[self.GameWinner].TotalGameTimes or 0) + 1; + ArchiveTable[self.GameWinner].GameWinTimes = (ArchiveTable[self.GameWinner].GameWinTimes or 0) + 1; + ArchiveTable[self.GameWinner].Score = (ArchiveTable[self.GameWinner].Score or DefaultSettings.RankScore) + Add; + + self:OnPostPlayerRank(self.GameWinner, true); + end + + -- 发送 RPC + self.RankScores[1] = { + PlayerKey = self.GameWinner, + Current = ArchiveTable[self.GameWinner].Score, -- 当前分数,之前分数 = Current - Add + Add = Add, -- 最终分数,要获取应该减去的分 = Add - AddHide + AddHide = AddHide, -- 添加的隐藏分 + HideScore = ArchiveTable[self.GameWinner].HideScore, + }; + + if self.GameLoser then + local Reduce, ReduceHide = 0, 0; + -- 判断当前是什么状态,如果是初始直接进入的那么就不加分 + if self:IsFormalMode() then + Reduce = self.ReduceFunc(Diff, Scores[self.GameLoser]); + + UGCLogSystem.Log("[Mini_Solo:HandlePlayerRank] ScoreDiff = %d, Reduce = %d", ScoreDiff, Reduce); + if ScoreDiff > 0 and Reduce ~= 0 and (RoundScores[self.GameWinner] ~= nil and RoundScores[self.GameWinner] >= 4) then + -- 那么扣分上少扣一部分 + local AddVal = math.floor(math.abs(Reduce) / 10 * (4 - ScoreDiff)); + UGCLogSystem.Log("[Mini_Solo:HandlePlayerRank] 额外多加分:%d", AddVal); + Reduce = AddVal + Reduce; + if Reduce > -5 then Reduce = -5; end + end + + UGCLogSystem.Log("[Mini_Solo:HandlePlayerRank] Reduce = %d", Reduce); + + -- 计算隐藏分 + local HideScore = ArchiveTable[self.GameLoser].HideScore; + if Reduce < 0 and (HideScore ~= nil and HideScore ~= 0) then + if HideScore > 0 then + local Base = math.abs(Reduce); + if HideScore > Base then + Reduce = 0; + ReduceHide = Base; + ArchiveTable[self.GameLoser].HideScore = HideScore - Base; + else + Reduce = Reduce + HideScore; + ReduceHide = HideScore; + ArchiveTable[self.GameLoser].HideScore = 0; + end + else + ArchiveTable[self.GameLoser].HideScore = 0; + end + end + + ArchiveTable[self.GameLoser].TotalGameTimes = (ArchiveTable[self.GameLoser].TotalGameTimes or 0) + 1; + if Reduce ~= 0 then + ArchiveTable[self.GameLoser].Score = (ArchiveTable[self.GameLoser].Score or DefaultSettings.RankScore) + Reduce; + end + self:OnPostPlayerRank(self.GameLoser, false); + end + + self.RankScores[2] = { + PlayerKey = self.GameLoser, + Current = ArchiveTable[self.GameLoser].Score, + Add = Reduce, + AddHide = ReduceHide, + HideScore = ArchiveTable[self.GameLoser].HideScore, + }; + end + + if self:IsFormalMode() then + if not self.IsLobbyTeam then + UGCLogSystem.LogTree(string.format("[Mini_Solo:HandlePlayerRank] LiveInfo ="), self.LiveInfo); + for i, Info in pairs(self.LiveInfo) do + UGCGameSystem.SendLiveStreamingTLog(i, 411, Info); + end + end + local PlayerKeys = {}; + for i, v in pairs(UE.GetAccountInfo()) do table.insert(PlayerKeys, i); end + UGCLogSystem.LogTree(string.format("[Mini_Solo:HandlePlayerRank] PlayerKeys ="), PlayerKeys) + self:InsertLastGame(PlayerKeys[1], PlayerKeys[2]); + self:InsertLastGame(PlayerKeys[2], PlayerKeys[1]); + UGCLogSystem.Log("[Mini_Solo:HandlePlayerRank] 开始插入新的战绩"); + else + for PlayerKey, v in pairs(UE.GetAccountInfo()) do + UGCPlayerStateSystem.SavePlayerArchiveData(UE.GetPlayerUID(PlayerKey), ArchiveTable[PlayerKey]); + end + end + else + for i, v in pairs(UE.GetAccountInfo()) do + table.insert(self.RankScores, { + PlayerKey = nil, -- 用于判断是否是平局 + PK = i, + Current = ArchiveTable[i].Score, + Add = 0, + AddHide = 0, + HideScore = ArchiveTable[i].HideScore, + }); + UGCPlayerStateSystem.SavePlayerArchiveData(UE.GetPlayerUID(i), ArchiveTable[i]); + end + end + --- 无论如何都要同步一下 + UGCLogSystem.Log("[Mini_Solo:HandlePlayerRank] 同步") + + -- 这个就很小了,可以正常走 + GameState:HandleArchiveData(nil, { + "GameTimes", + "Weapons", + "WinTimes", + "CurSeason", + "IsNewSeason", + "SelectMaps", + "LastSelectMap", + "Disables", + "LastSelectWeapons", + "sw_version", + "PlayerEnableShovel", + "SeasonInfo", + "TechScore", + "Friends", + "SelectWeapons", + "Last10Games", + "NoSelectMaps", + "EnterWeapons", + "EnterWeaponIndex", + }); + + UGCLogSystem.Log("[Mini_Solo:HandlePlayerRank] 发送"); + UGCLogSystem.LogTree(string.format("[Mini_Solo:HandlePlayerRank] PlayerSelectedWeapons ="), self.PlayerSelectedWeapons); + for i, PC in pairs(UGCGameSystem.GetAllPlayerController(false)) do + -- 再次发送数据 + if not table.isEmpty(self.PlayerSelectedWeapons[PC.PlayerKey]) then + local List = {}; + for WeaponID, v in pairs(self.PlayerSelectedWeapons[PC.PlayerKey]) do + List[WeaponID] = TableHelper.DeepCopyTable(ArchiveTable[PC.PlayerKey].SelectWeapons[WeaponID]); + end + PC:SendWeapons(-1, List); + end + end +end + +function Mini_Solo:OnPostPlayerRank(PlayerKey, IsWin) + local Rank = UGCRankSystem.GetUGCRank(PlayerKey); + UGCLogSystem.Log("[Mini_Solo:OnPostPlayerRank] UGCRank Begin = %s", tostring(Rank)); + UGCRankSystem.AddRanktProgress(PlayerKey, ArchiveTable[PlayerKey].Score - Rank); -- rank 是对的 + UGCLogSystem.Log("[Mini_Solo:OnPostPlayerRank] UGCRank End = %s", tostring(UGCRankSystem.GetUGCRank(PlayerKey))); + + local PS = UGCGameSystem.GetPlayerStateByPlayerKey(PlayerKey); + if PS and UE.IsValid(PS) then PS:OnBestRank(ArchiveTable[PlayerKey].Score); end + + -- 设置分数 + local PC = UGCGameSystem.GetPlayerControllerByPlayerKey(PlayerKey) + + --- 1:积分;2:技术分 + --local UID = UE.GetPlayerUID(PlayerKey); + --PC.RankingListComponent:Server_UpdateRankListScore(PC, UID, 1, ArchiveTable[PlayerKey].Score); + + if not self.IsLobbyTeam then + for i = 1, 2 do + table.insert(self.LiveInfo[i], { + UID = AccountTable[PlayerKey].UID, + TeamRank = IsWin and 1 or 2, + rankScore = ArchiveTable[PlayerKey].Score, + }); + end + end + UGCLogSystem.Log("[Mini_Solo:OnPostPlayerRank] Player:%s 积分:%s 技术分:%s", UE.GetPlayerName(PlayerKey), tostring(ArchiveTable[PlayerKey].Score), tostring(ArchiveTable[PlayerKey].Score)); +end + +function Mini_Solo:IsFormalMode() + return self.ModeType == GameModeConfig.EGameModeType.DefaultMode and table.getCount(UE.GetAccountInfo()) > 1; +end + +--- 小游戏结束 +function Mini_Solo:OnGameEnd(InResultList) + UGCLogSystem.LogTree(string.format("[Mini_Solo:OnGameEnd] 游戏结束 InResultList ="), InResultList) + UGCLogSystem.Log("[Mini_Solo:OnGameEnd] GameWinner = %s", tostring(self.GameWinner)); + if IsServer then + if self.GameWinner == nil then + local Winners = {}; + for i, v in pairs(InResultList) do + table.insert(Winners, { + PlayerKey = i, + Score = v, + }); + end + if table.getCount(Winners) == 1 then + self.GameWinner = Winners[1].PlayerKey; + else + UGCLogSystem.LogTree(string.format("[Mini_Solo:OnGameEnd] Winners ="), Winners) + table.sort(Winners, function(a, b) return a.Score > b.Score; end) + if Winners[1].Score == Winners[2].Score then + self.GameWinner = nil; + else + self.GameWinner = Winners[1].PlayerKey + end + end + end + if table.isEmpty(self.RankScores) then + self:HandlePlayerRank(self.GameWinner); + end + self.Owner:SendRPC("UpdatePlayerRank", self.RankScores); + end +end + +function Mini_Solo:UpdatePlayerRank(RankScores) + UGCLogSystem.LogTree(string.format("[Mini_Solo:UpdatePlayerRank] InRanks ="), RankScores); + WidgetManager:GetPanel(WidgetConfig.EUIType.GameEnd, function(Widget, ...) + Widget:OnUpdatePlayerRank(RankScores); + end, RankScores); +end + +---@param Pawn UGCPlayerPawn_C +function Mini_Solo:OnPawnInit(Pawn, InitArmor, InitMedication) + if IsServer then + if self.State < MiniGameState.ROUND_PREPARE then return ; end + if self.State >= MiniGameState.MINI_END then return ; end + -- 仅在正式模式下 + local AddArmors = TableHelper.DeepCopyTable(InitArmor); + UGCLogSystem.LogTree(string.format("[Mini_Solo:OnPawnInit] InitArmor ="), InitArmor) + UGCLogSystem.LogTree(string.format("[Mini_Solo:OnPawnInit] AddArmors ="), AddArmors) + local Medications = TableHelper.DeepCopyTable(InitMedication); + if self:IsFormalMode() then + local CurrWeaponId = 0; + if self.State == MiniGameState.ROUND_PREPARE then + -- 说明此时拿取第一把枪即可 + CurrWeaponId = self.SelectWeapons[1]; + else + CurrWeaponId = self.CurrWeaponItem[Pawn.PlayerKey] or ItemTool.GetFirstWeaponID(Pawn.PlayerKey); + end + + UGCLogSystem.Log("[Mini_Solo:OnPawnInit] CurrWeaponId = %d", CurrWeaponId); + if WeaponTable[CurrWeaponId] and WeaponTable[CurrWeaponId].TypeNew then + local SpecialConfig = self.SpecialWeapon[WeaponTable[CurrWeaponId].TypeNew]; + if SpecialConfig and SpecialConfig.InitArmors then + for i, v in pairs(SpecialConfig.InitArmors) do + AddArmors[i] = SpecialConfig.InitArmors[i]; + end + end + end + end + + UGCLogSystem.LogTree(string.format("[Mini_Solo:OnPawnInit] AddArmors ="), AddArmors) + + local AddItems = {}; + for i, v in pairs(AddArmors) do + table.insert(AddItems, { v, 1 }); + end + + for i, v in pairs(Medications) do + table.insert(AddItems, v); + end + + Pawn:AddInitItems(AddItems); + UGCEventSystem.SetTimer(GameState, function() + -- 判断当前有哪些东西 + local DelayWeapons = MiniGameConfig[MiniGameMapType.SoloKing].DelayWeapons; + Pawn:AddInitItems(DelayWeapons); + end, 1); + end +end + +Mini_Solo.RoundDamages = {}; + +--- 玩家受到伤害回调 +---@param DamagedActor UGCPlayerPawn_C +---@param Damage float +---@param DamageType EDamageType +---@param EventInstigator UGCPlayerController_C +function Mini_Solo:OnPlayerTakeDamage(DamagedActor, Damage, DamageType, EventInstigator) + UGCLogSystem.Log("[Mini_Solo:OnPlayerTakeDamage] 收到的伤害为 %f, DamagedActor = %s", Damage, UE.GetName(DamagedActor)); + -- 选择武器期间不受伤害 + if EventInstigator ~= nil and UE.IsValid(EventInstigator) and EventInstigator.PlayerKey ~= DamagedActor.PlayerKey then + local PlayerKey = EventInstigator.PlayerKey; + self.Damages[PlayerKey] = (self.Damages[PlayerKey] or 0) + Damage; + self.RoundDamages[PlayerKey] = (self.RoundDamages[PlayerKey] or 0) + Damage; + end + return Damage; +end + +--- 因为在短短的时间内,只可能有一个玩家死亡,因此只需要一个变量即可 +Mini_Solo.IsPlayerDying = false; + +--- 玩家死亡回调 +function Mini_Solo:OnPlayerDead(InPlayerKey, InCauserKey) + UGCLogSystem.Log("[Mini_Solo:OnPlayerDead] PlayerKey = %s, CauserKey = %s", tostring(InPlayerKey), tostring(InCauserKey)); + -- 检查是否 + if IsServer then + if self.State == MiniGameState.ROUND_GAMING then + -- 检查一下是否已经击杀三局了 + local WinnerPlayerKey = 0; + for i, v in pairs(UGCGameSystem.GetAllPlayerController(false)) do + if v.PlayerKey == InPlayerKey then + --- 计算死亡者的 KD + self.RoundDeadTimes[InPlayerKey] = (self.RoundDeadTimes[InPlayerKey] or 0) + 1; + self.TotalKDA[InPlayerKey].Dead = (self.TotalKDA[InPlayerKey].Dead or 0) + 1; + ArchiveTable[InPlayerKey].Dead = (ArchiveTable[InPlayerKey].Dead or 0) + 1; + else + self.RoundDeadTimes[v.PlayerKey] = self.RoundDeadTimes[v.PlayerKey] or 0; + local Pawn = UGCGameSystem.GetPlayerPawnByPlayerKey(v.PlayerKey); + if UE.IsValidPawn(Pawn) then + UGCPawnAttrSystem.SetHealth(Pawn, UGCPawnAttrSystem.GetHealth(Pawn) + self.KillHealing); + if not self.EnableInsult then + UGCPawnSystem.DisabledPawnState(Pawn, EPawnState.GunFire, true); + UGCPawnSystem.DisabledPawnState(Pawn, EPawnState.MeleeAttack, true); + end + end + WinnerPlayerKey = v.PlayerKey; + end + end + + --- 计算击杀者的分数 + if InCauserKey ~= nil and InCauserKey ~= InPlayerKey and InCauserKey > 0 then + self.TotalKDA[InCauserKey].Kill = (self.TotalKDA[InCauserKey].Kill or 0) + 1; + if ArchiveTable[InCauserKey] then + ArchiveTable[InCauserKey].Kill = (ArchiveTable[InCauserKey].Kill or 0) + 1; + end + end + + self:DOREPONCE("RoundDeadTimes"); + self.IsPlayerDying = true; + if self.RoundDeadTimes[InPlayerKey] == nil or self.RoundDeadTimes[InPlayerKey] >= self.KillTimes then + -- 结束 + if self.RoundWinner == nil then + self.RoundWinner = WinnerPlayerKey; + UGCLogSystem.Log("[Mini_Solo:OnPlayerDead] InCauserKey = %d, State = %s", InCauserKey, TableHelper.printEnum(MiniGameState, self.State)); + self.bRoundEnd = true; + local WeaponId = self.CurrWeaponItem[WinnerPlayerKey] or ItemTool.GetFirstWeaponID(WinnerPlayerKey); + -- 检查一下是否超过一半 + table.insert(self.RoundWinners, { + Winner = self.RoundWinner, + Time = UE.GetServerTime() - self.RoundStartTime, + -- 拿到对方的枪械 + Weapon = WeaponId, + Score = { + Winner = self.RoundDeadTimes[InPlayerKey] or 0, -- 这个是阵亡数,需要反过来 + Loser = self.RoundDeadTimes[self.RoundWinner] or 0, + }, + }); + if self:IsFormalMode() then + self:AddSelectWeaponsArchive(self.RoundWinner, WeaponId, 3, 1); + end + + UGCLogSystem.LogTree(string.format("[Mini_Solo:OnPlayerDead] self.RoundWinners ="), self.RoundWinners) + -- 同步一下 + self:DOREPONCE("RoundWinners"); + local IsOver, WinnerID = self:CheckGameEnd(); + if IsOver then + self.GameLoser = InPlayerKey; + self:SetGameOver(WinnerID); + end + UGCEventSystem.SendEvent(EventTypes.UpdateRoundWinners, self.RoundWinners); + end + else + -- 玩家重生 + UGCEventSystem.SetTimer(GameState, function() + UE.ResetGame1(0.1); + end, self.ResetTime); + end + local PlayerDamageTable = {}; + for i, PC in pairs(UGCGameSystem.GetAllPlayerController(false)) do + local PlayerKey = PC.PlayerKey; + local Pawn = UGCGameSystem.GetPlayerPawnByPlayerKey(PlayerKey); + PlayerDamageTable[PlayerKey] = { + Damage = self.Damages[PlayerKey] or 0, + Health = UE.IsValidPawn(Pawn) and UGCPawnAttrSystem.GetHealth(Pawn) or 0, + }; + end + self.Owner:SendRPC("AfterPlayerDead", PlayerDamageTable); + end + self.DeadCount = self.DeadCount + 1; + end +end + +function Mini_Solo:AfterPlayerDead(InTable) + UGCLogSystem.LogTree(string.format("[Mini_Solo:AfterPlayerDead] InTable ="), InTable) + +end + +Mini_Solo.CurrWeaponItem = {}; + +function Mini_Solo:OnPlayerRespawn(InPlayerKey) + -- 设置该玩家不能动 + if IsServer then + self.IsPlayerDying = false; + self.Damages[InPlayerKey] = 0; + else + if InPlayerKey == LocalPlayerKey then + if self.ModeType ~= GameModeConfig.EGameModeType.DefaultMode then + --WidgetManager:ShowPanel(WidgetConfig.EUIType.ShowCustomSelectWeaponBtn, false); + WidgetManager:GetPanel(WidgetConfig.EUIType.Main, function(Widget) + table.func(Widget, "ShowCustomSelectWeaponBtn", true); + end); + end + end + end +end + +function Mini_Solo:OnRep_RoundWinners() + UGCLogSystem.LogTree(string.format("[Mini_Solo:OnRep_RoundWinners] RoundWinners"), self.RoundWinners) + UGCEventSystem.SendEvent(EventTypes.UpdateRoundWinners, self.RoundWinners); +end + +function Mini_Solo:OnPlayerLeave(InPlayerKey) + UGCLogSystem.Log("[Mini_Solo:OnPlayerLeave] 玩家 %d 退出", InPlayerKey) + -- 直接结束 + if self.State >= MiniGameState.MINI_END then return ; end + if IsServer then + local PlayerKeys = {}; + for i, v in pairs(UGCGameSystem.GetAllPlayerController(false)) do + if UE.IsValid(v) and v.PlayerKey ~= InPlayerKey then + PlayerKeys[v.PlayerKey] = 1; + if v.PlayerKey ~= InPlayerKey then + self.GameWinner = v.PlayerKey; + self.RoundWinner = self.GameWinner; + end + end + end + UGCLogSystem.Log("[Mini_Solo:OnPlayerLeave] GameWinner = %s", tostring(self.GameWinner)) + table.printTable(PlayerKeys); + UGCLogSystem.LogTree(string.format("[Mini_Solo:OnPlayerLeave] PlayerKeys ="), PlayerKeys) + if table.getCount(PlayerKeys) == 1 then + for i, v in pairs(PlayerKeys) do self.GameWinner = i; end + -- 查看哪个玩家已经够局数了 + if self.State == MiniGameState.ROUND_GAMING then + local WeaponID = self.CurrWeaponItem[self.GameWinner] or ItemTool.GetFirstWeaponID(self.GameWinner) + table.insert(self.RoundWinners, { + Winner = self.GameWinner, + Time = UE.GetServerTime() - self.RoundStartTime, + -- 拿到对方的枪械 + Weapon = WeaponID, + Score = { + Winner = self.RoundDeadTimes[InPlayerKey] or 0, -- 这个是阵亡数,需要反过来 + Loser = self.RoundDeadTimes[self.GameWinner] or 0, + }, + }); + if self:IsFormalMode() then + self:AddSelectWeaponsArchive(self.RoundWinner, WeaponID, 3, 1) + end + self:DOREPONCE("RoundWinners"); + end + + self:HandlePlayerRank(self.GameWinner); + self:SetGameOver(self.GameWinner); + end + end + + UGCLogSystem.Log("[Mini_Solo:OnPlayerLeave] 结束执行"); +end + +---@param WinnerId int32 +function Mini_Solo:SetGameOver(WinnerId) + UGCLogSystem.Log("[Mini_Solo:SetGameOver] 设置游戏结束, Winner = %s", UE.GetPlayerName(WinnerId)); + self.GameWinner = WinnerId; + + local WinTable = {}; + for _, Info in pairs(self.RoundWinners) do + if Info.Winner then + WinTable[Info.Winner] = (WinTable[Info.Winner] or 0) + 1; + end + end + + if self.GameWinner == nil then + -- 获取胜利的 + if table.getCount(UE.GetAccountInfo()) == 1 then + for i, PC in pairs(UGCGameSystem.GetAllPlayerController(false)) do + self.GameWinner = PC.PlayerKey; + end + else + local Wins = {}; + for PlayerKey, WinTimes in pairs(WinTable) do + table.insert(Wins, { + PlayerKey = PlayerKey, + WinTimes = WinTimes, + }); + end + table.sort(Wins, function(a, b) + return a.WinTimes > b.WinTimes; + end); + UGCLogSystem.LogTree(string.format("[Mini_Solo:SetGameOver] Wins ="), Wins) + self.GameWinner = Wins[1].PlayerKey; + if Wins[2] then + self.GameLoser = Wins[2].PlayerKey; + end + end + end + + UGCLogSystem.Log("[Mini_Solo:SetGameOver] GameWinner = %s, WinnerId = %s", tostring(self.GameWinner), tostring(WinnerId)); + + if self.GameLoser == nil then + for PlayerKey, Info in pairs(UE.GetAccountInfo()) do + if PlayerKey ~= self.GameWinner then self.GameLoser = PlayerKey; end + end + end + + self:DOREPONCE("GameWinner"); + + self.bGameEnd = true; + self.bRoundEnd = true; +end + +function Mini_Solo:InsertLastGame(PlayerKey, OtherKey) + UGCLogSystem.Log("[Mini_Solo:InsertLastGame] 开始执行"); + local WinTable = {}; + for _, Info in pairs(self.RoundWinners) do + if Info.Winner then + WinTable[Info.Winner] = (WinTable[Info.Winner] or 0) + 1; + end + end + + UGCLogSystem.LogTree(string.format("[Mini_Solo:InsertLastGame] RoundWinners ="), self.RoundWinners); + + local WinRoundTable = {}; + for i, v in pairs(self.RoundWinners) do + local IsWin = PlayerKey == v.Winner; + table.insert(WinRoundTable, { + PlayerKey == v.Winner, -- IsWin 1 + v.Weapon, -- WeaponID 2 + IsWin and v.Score.Winner or v.Score.Loser, -- 3 + IsWin and v.Score.Loser or v.Score.Winner, -- 4 + }); + end + UGCLogSystem.LogTree(string.format("[Mini_Solo:SetGameOver] WinRoundTable "), WinRoundTable); + -- 直接添加 + local Last10Games = ArchiveTable[PlayerKey].Last10Games + if Last10Games == nil then + ArchiveTable[PlayerKey].Last10Games = {}; + end + local CurrCount = #(ArchiveTable[PlayerKey].Last10Games); + if CurrCount >= 10 then + table.remove(ArchiveTable[PlayerKey].Last10Games, 1); -- 移除第一个即可,以为不可能超过 10 个,最多 10 个 + end + + local IsWin = PlayerKey == self.GameWinner; + UGCLogSystem.LogTree(string.format("[Mini_Solo:InsertLastGame] RankScores ="), self.RankScores) + + local LastGame = { + IsWin, -- IsWin 1 + UE.GetPlayerUID(OtherKey), -- UID 2 + WinTable[PlayerKey] or 0, -- MyScore 3 + WinTable[OtherKey] or 0, -- EnemyScore 4 + self.RankScores[IsWin and 1 or 2].Current or 0, -- Score 5 + self.RankScores[IsWin and 1 or 2].Add or 0, -- Add Score 6 + self.TotalKDA[PlayerKey].Kill or 0, -- Kill 7 + self.TotalKDA[PlayerKey].Dead or 0, -- Dead 8 + WinRoundTable, -- GameInfo 9 + } + table.insert(ArchiveTable[PlayerKey].Last10Games, LastGame); + + -- 检查是否存在 Player + if ArchiveTable[PlayerKey].Friends == nil then ArchiveTable[PlayerKey].Friends = {}; end + if ArchiveTable[PlayerKey].Friends[UE.GetPlayerUID(OtherKey)] == nil then + ArchiveTable[PlayerKey].Friends[UE.GetPlayerUID(OtherKey)] = { + UE.GetPlayerName(OtherKey), + UE.GetPlayerIconURL(OtherKey), + }; + end + + local PC = UGCGameSystem.GetPlayerControllerByPlayerKey(PlayerKey); + if PC and UE.IsValid(PC) then + PC:SendNewArchive(CurrCount + 1, LastGame, ArchiveTable[PlayerKey].Friends[UE.GetPlayerUID(OtherKey)]); + end + + -- 清空其他的 + local ExistFriends = {}; + for i, v in pairs(ArchiveTable[PlayerKey].Last10Games) do + -- 获取玩家的 UID + local UID = nil; + if type(v[2]) == 'table' then + UID = v[2][1]; + elseif type(v[2]) == 'number' then + UID = v[2] + end + if UID then ExistFriends[UID] = 1; end + end + + local Removes = {}; + for UID, v in pairs(ArchiveTable[PlayerKey].Friends) do + if ExistFriends[UID] == nil then table.insert(Removes, UID); end + end + + for i, UID in pairs(Removes) do + ArchiveTable[PlayerKey].Friends[UID] = nil; + end + + UGCLogSystem.LogTree(string.format("[Mini_Solo:InsertLastGame] ArchiveTable[PlayerKey].Last10Games ="), ArchiveTable[PlayerKey].Last10Games) + UGCPlayerStateSystem.SavePlayerArchiveData(UE.GetPlayerUID(PlayerKey), ArchiveTable[PlayerKey]); +end + +function Mini_Solo:OnRep_GameWinner() + -- 因为无法保证顺序,所以需要这样传输 + UGCEventSystem.SetTimer(GameState, function() + UGCEventSystem.SendEvent(EventTypes.UpdateGameWinner, self.GameWinner, self.RoundWinners); + end, 0.3); +end + +--- 检查是否游戏结束了 +function Mini_Solo:CheckGameEnd() + local Winners = {}; + for i, v in pairs(self.RoundWinners) do + if v.Winner then Winners[v.Winner] = 1 + (Winners[v.Winner] or 0); end + end + UGCLogSystem.LogTree(string.format("[Mini_Solo:CheckGameEnd] Winners ="), Winners) + for i, v in pairs(Winners) do + if v > self.TotalRoundTimes // 2 then + self.GameWinner = i; + UGCLogSystem.Log("[Mini_Solo:CheckGameEnd] GameWinner = %s", tostring(i)); + return true, i; + end + end + return false; +end + +--- 存在一个内部参数可以控制 Tick,bEnableTick 设置为 false 就会停止 Tick +function Mini_Solo:OnTick(InDeltaTime, InServerTime) +end + +--- 小局初始化(每一次小局开始前都会调用) +function Mini_Solo:OnRoundStart(InTimes) + UGCLogSystem.Log("[Mini_Solo:OnRoundStart] 执行, InTimes = %d", InTimes) + if IsServer then + -- 显示选择武器界面 + self.RoundWinner = nil; + self.RoundDeadTimes = {}; + self:DOREPONCE("RoundDeadTimes") + else + UGCLogSystem.Log("[Mini_Solo:OnRoundStart] 执行") + UGCEventSystem.SendEvent(EventTypes.ShowRoundWin, false); + end + + UE.ClearSceneObjects(); + return true; +end + +function Mini_Solo:OnRep_RoundDeadTimes() + WidgetManager:GetPanel(WidgetConfig.EUIType.Main, function(Widget) + Widget:SetRoundKill(self.RoundDeadTimes); + end) +end + +--- 小局结束当前回合,每小局都会执行 +function Mini_Solo:OnRoundEnd(InRoundTimes, Winner) + UGCLogSystem.Log("[Mini_Solo:OnRoundEnd] RoundTimes = %d, Winner = %s", InRoundTimes, tostring(Winner)); + if IsServer then + -- 计算当前数据 + if self.CheckPlayerExistHandler ~= nil then + UGCEventSystem.StopTimer(self.CheckPlayerExistHandler); + self.CheckPlayerExistHandler = nil; + end + else + UGCEventSystem.SendEvent(EventTypes.ShowRoundWin, true, Winner); + -- 显示回合胜利 + --WidgetManager:GetPanel(WidgetConfig.EUIType.Main, function(Widget) + -- Widget:ShowRoundWin(true, Winner); + --end); + end +end + +Mini_Solo.CheckPlayerExistHandler = nil; + +--- 小局正式开始游戏(每一次都会调用) +function Mini_Solo:OnRoundFormalStart() + UGCLogSystem.Log("[Mini_Solo:OnRoundFormalStart] 小局正式开始"); + if IsServer then + local HadChanged = false; + -- 玩家装备对应武器 + if self.ModeType == GameModeConfig.EGameModeType.DefaultMode then + UGCLogSystem.LogTree(string.format("[Mini_Solo:OnRoundFormalStart] CurrWeapon Begin"), self.CurrWeapon) + UGCLogSystem.LogTree(string.format("[Mini_Solo:OnRoundFormalStart] SelectWeapons Begin"), self.SelectWeapons) + -- 从列表中随机给一把枪 + local WeaponId = self.SelectWeapons[1]; + if WeaponId then + table.remove(self.SelectWeapons, 1); + for i, v in pairs(UGCGameSystem.GetAllPlayerController(false)) do + local PlayerKey = v.PlayerKey; + self.CurrWeaponItem[PlayerKey] = WeaponId; + HadChanged = true; + if self.PlayerSelectedWeapons[PlayerKey] == nil then self.PlayerSelectedWeapons[PlayerKey] = {}; end + self.PlayerSelectedWeapons[PlayerKey][WeaponId] = 1; + self:AddSelectWeaponsArchive(PlayerKey, WeaponId, 2, 1); + -- 玩家直接添加武器 + self:PlayerAddWeapon(PlayerKey, self.CurrWeaponItem[PlayerKey]); + end + end + + -- 移除对应的东西 + self:DOREPONCE("SelectWeapons"); + GameState:SetSelectGameMode(self.ModeType); + UGCLogSystem.LogTree(string.format("[Mini_Solo:OnRoundFormalStart] SelectWeapons End"), self.SelectWeapons) + else + UGCLogSystem.Log("[Mini_Solo:OnRoundFormalStart] 娱乐模式") + UGCLogSystem.LogTree(string.format("[Mini_Solo:OnRoundFormalStart] self.EnterWeaponItem ="), self.EnterWeaponItem) + -- 去读取一下,否则就用默认的枪械 + for i, PC in pairs(UGCGameSystem.GetAllPlayerController(false)) do + local PlayerKey = PC.PlayerKey; + if table.isEmpty(self.EnterWeaponItem[PlayerKey]) then + local EnterWeapons = ArchiveTable[PlayerKey].EnterWeapons or WeaponSelectionCombinationConfig.WeaponCombinationList.Weapon; + local EnterWeaponIndex = ArchiveTable[PlayerKey].EnterWeaponIndex or 1; + self.EnterWeaponItem[PlayerKey] = EnterWeapons[EnterWeaponIndex]; + HadChanged = true; + end + UGCLogSystem.LogTree(string.format("[Mini_Solo:OnRoundFormalStart] EnterWeaponItem ="), self.EnterWeaponItem[PlayerKey]) + local Pawn = UGCGameSystem.GetPlayerPawnByPlayerKey(PlayerKey); + if Pawn and UE.IsValid(Pawn) then + Pawn:UpdateSlotWeapons(self.EnterWeaponItem[PlayerKey]); + end + end + end + + if HadChanged then + self:DOREPONCE("CurrWeaponItem") + end + + self.RoundDamages = {}; + PoisonManager:Toggle(true); + if self.CheckPlayerExistHandler ~= nil then + UGCEventSystem.StopTimer(self.CheckPlayerExistHandler); + self.CheckPlayerExistHandler = nil; + end + self.CheckPlayerExistHandler = UGCEventSystem.SetTimerLoop(GameState, function() + self:CheckPlayerExist(); + end, 5); + else + --self:AllPawnsAddOutline(); + if GlobalModeType == nil then + GlobalModeType = GameModeConfig.EGameModeType.DefaultMode; + UGCEventSystem.SendEvent(EventTypes.UpdateModeType, GlobalModeType); + end + end + UE.ClearSceneObjects(); +end + +--- 娱乐模式下玩家获取武器 +---@param PlayerKey PlayerKey +---@param Index int32|nil +function Mini_Solo:GetPlayerEnterWeapons(PlayerKey, Index) + local Weapons = ItemTool.GetPlayerEnterWeapons(PlayerKey, Index); + self.EnterWeaponItem[PlayerKey] = TableHelper.DeepCopyTable(Weapons); + return Weapons; +end + +--- 检测玩家是否存在 +function Mini_Solo:CheckPlayerExist(dt, st) + -- 说明此时走了正常逻辑 + if self.IsPlayerDying == true then return ; end + + local Pawns = UGCGameSystem.GetAllPlayerPawn(); + local AlivePawns = {}; + local WinnerPlayerKey = 0; + local Count = 0; + for i, v in pairs(Pawns) do + if UE.IsValidPawn(v) then + AlivePawns[v.PlayerKey] = v; + WinnerPlayerKey = v.PlayerKey; + Count = Count + 1; + end + end + if Count > 1 then return ; end + if Count == 1 then + local DeadPlayerKey = 0; + -- 说明当前结束了,此时判断玩家是否计算了 + for PlayerKey, Info in pairs(UE.GetAccountInfo()) do + if WinnerPlayerKey ~= PlayerKey then DeadPlayerKey = PlayerKey; end + end + self:OnPlayerDead(DeadPlayerKey, WinnerPlayerKey); + end +end + +function Mini_Solo:AllPawnsAddOutline() + UGCLogSystem.Log("[Mini_Solo:AllPawnsAddOutline] 执行") + for i, Pawn in pairs(UGCGameSystem.GetAllPlayerPawn()) do + if UE.IsValidPawn(Pawn) then + UGCLogSystem.Log("[Mini_Solo:AllPawnsAddOutline] 添加描边") + Pawn:AddOutline(); + end + end +end + +---@param Pawn UGCPlayerPawn_C +---@param Controller UGCPlayerController_C +function Mini_Solo:OnPlayerPossessed(Pawn, Controller) + -- 清空玩家身上的武器 + if self.ModeType == GameModeConfig.EGameModeType.DefaultMode then + UGCLogSystem.LogTree(string.format("[Mini_Solo:OnPlayerPossessed] CurrWeaponItem"), self.CurrWeaponItem) + if table.isEmpty(self.CurrWeaponItem) then return ; end + UGCLogSystem.Log("[Mini_Solo:OnPlayerPossessed] 开始准备添加武器") + if self.CurrWeaponItem[Pawn.PlayerKey] ~= nil then + UGCEventSystem.SetTimer(Pawn, function() + UGCLogSystem.Log("[Mini_Solo:OnPlayerPossessed] 开始添加武器") + local Weapon = ItemTool.GetPlayerFirstWeapon(Pawn); + if Weapon == nil or not UE.IsValid(Weapon) or Weapon:GetWeaponItemID() ~= self.CurrWeaponItem[Pawn.PlayerKey] then + self:PlayerAddWeapon(Pawn.PlayerKey, self.CurrWeaponItem[Pawn.PlayerKey]); + end + end, 1); + end + else + UGCLogSystem.LogTree(string.format("[Mini_Solo:OnPlayerPossessed] EnterWeaponItem ="), self.EnterWeaponItem); + if table.isEmpty(self.EnterWeaponItem) then return ; end + UGCEventSystem.SetTimer(Pawn, function() + Pawn:UpdateSlotWeapons(self.EnterWeaponItem[Pawn.PlayerKey]); + end, 1); + end +end + +Mini_Solo.CheckWeaponTimer = nil; + +function Mini_Solo:CloseCheckWeaponTimer() + -- 关闭 + if self.CheckWeaponTimer ~= nil then + UGCEventSystem.StopTimer(self.CheckWeaponTimer); + self.CheckWeaponTimer = nil; + end +end + +function Mini_Solo:CheckWeapon() + if table.isEmpty(self.CurrWeaponItem) then + return self:CloseCheckWeaponTimer(); + end + local HasWeaponCount = 0; + for i, Pawn in pairs(UGCGameSystem.GetAllPlayerPawn()) do + if UE.IsValidPawn(Pawn) then + -- 判断当前是什么武器 + if self.CurrWeaponItem[Pawn.PlayerKey] then + local HasWeapon = false; + local RemoveTypes = {}; + -- 检查当前是什么玩意 + local WeaponInfo = WeaponTable[self.CurrWeaponItem[Pawn.PlayerKey]] + if WeaponInfo then + if WeaponInfo.TypeNew == EWeaponTypeNew.EWeaponTypeNew_Melee then + -- 获取所有武器 + local AllItemData = UGCBackPackSystem.GetAllItemData(Pawn); + for _, Info in pairs(AllItemData) do + if Info.ItemID == self.CurrWeaponItem[Pawn.PlayerKey] then + UGCLogSystem.Log("[Mini_Solo:CheckWeapon] 找到武器了,近战武器") + HasWeapon = true; + HasWeaponCount = HasWeaponCount + 1; + + if Info.Count >= 2 then + UGCBackPackSystem.DropItem(Pawn, Info.ItemID, Info.Count - 1, true); + end + end + end + + for _, Type in pairs(AllWeaponEnums) do + local Weapon = UGCWeaponManagerSystem.GetWeaponBySlot(Pawn, Type); + if Weapon ~= nil and UE.IsValid(Weapon) then + if Weapon:GetWeaponItemID() ~= self.CurrWeaponItem[Pawn.PlayerKey] then + -- 检查是否有其他武器 + table.insert(RemoveTypes, { + DefineID = Weapon:GetItemDefineID(), + Count = 1; + }); + end + end + end + else + for _, Type in pairs(AllWeaponEnums) do + local Weapon = UGCWeaponManagerSystem.GetWeaponBySlot(Pawn, Type); + if Weapon ~= nil and UE.IsValid(Weapon) then + if Weapon:GetWeaponItemID() == self.CurrWeaponItem[Pawn.PlayerKey] then + UGCLogSystem.Log("[Mini_Solo:CheckWeapon] 找到武器了") + HasWeapon = true; + HasWeaponCount = HasWeaponCount + 1; + else + -- 检查是否有其他武器 + table.insert(RemoveTypes, { + DefineID = Weapon:GetItemDefineID(), + Count = 1; + }); + end + end + end + end + end + -- 有的话就移除 + if not table.isEmpty(RemoveTypes) then + local BackpackComp = UGCBackPackSystem.GetBackpackComponent(Pawn); + for j = 1, #RemoveTypes do + local Item = RemoveTypes[j]; + UGCLogSystem.Log("[Mini_Solo:CheckWeapon] 移除别的武器:%d", Item.DefineID.TypeSpecificID); + BackpackComp:DropItem(Item.DefineID, Item.Count, EBattleItemDropReason.Force); + end + end + + if not HasWeapon then + UGCLogSystem.Log("[Mini_Solo:CheckWeapon] 没有武器,给他加上") + -- 给玩家添加上去 + self:PlayerAddWeapon(self.CurrWeaponItem[Pawn.PlayerKey]) + -- 然后过一段时间补满子弹 + ItemTool.FillAllWeaponBullets(Pawn); + end + end + end + end + if HasWeaponCount == 2 then + self:CloseCheckWeaponTimer(); + end +end + +--- 玩家添加武器到备选列表 +function Mini_Solo:PlayerAddWeapon(PlayerKey, Weapon) + local Pawn = UGCGameSystem.GetPlayerPawnByPlayerKey(PlayerKey); + if Pawn and UE.IsValid(Pawn) and Pawn:IsAlive() then + ItemTool.ClearAllWeapon(Pawn); + if Weapon then + UGCLogSystem.Log("[Mini_Solo:PlayerAddWeapon] 开始添加") + Pawn:AddItem(Weapon, 1, true, EFillBulletType.ClipInfinite); + + -- 添加其他倍镜 + local NeedAddTelescope = ItemTool.GetOtherTelescopes(Pawn); + -- 检查当前武器上是否有倍镜 + + for i, v in pairs(NeedAddTelescope) do + Pawn:AddItem(i, 1, false); + end + + -- 判断武器上原本是否有该配件 + if ArchiveTable[PlayerKey] and ArchiveTable[PlayerKey].Weapons[Weapon] then + if WeaponSuits[Weapon] then + if WeaponSuits[Weapon][EWeaponPartType.Telescope] then + local HaveParts = {}; + for i, PartID in pairs(WeaponSuits[Weapon][EWeaponPartType.Telescope]) do + HaveParts[PartID] = 1; + end + local Parts = ArchiveTable[PlayerKey].Weapons[Weapon]; + -- 判断是否有倍镜 + local HavePart = false; + for i, PartID in pairs(Parts) do + if HaveParts[PartID] then HavePart = true; end + end + + -- 移除 + if not HavePart then + local Weapons = ItemTool.GetWeaponsById(Pawn, Weapon) + for i, v in pairs(Weapons) do + UGCGunSystem.RemoveGunAttachmentBySocketType(v, ItemTool.GetWeaponAttachmentSocketType(EWeaponPartType.Telescope)); + end + end + end + end + end + + Pawn:ResetAllParts(); + -- 启动检测 + self:CloseCheckWeaponTimer(); + self.CheckWeaponTimer = UGCEventSystem.SetTimerLoop(GameState, function() + UGCLogSystem.Log("[Mini_Solo:OnPlayerPossessed] 检查是否有武器") + self:CheckWeapon(); + end, 1); + end + end +end + +---@param PlayerStartList table> +---@param Controller UGCPlayerController_C +function Mini_Solo:SelectPlayerStart(PlayerStartList, Controller) + local TeamId = UGCPlayerControllerSystem.GetTeamID(Controller); + if self.DeadCount % 2 == 0 then + return PlayerStartList[TeamId]; + else + local Reverse = ((TeamId + 1) % 2 == 0) and 2 or 1; + return PlayerStartList[Reverse]; + end + return nil; -- 否则使用默认的方式 +end + +function Mini_Solo:GetRoundWinner(InTimes) + -- 获取当前回合赢了的玩家 / TeamId + if self.RoundWinner == nil then + -- 检查一下是否是玩家退出 + local LastPCs = UGCGameSystem.GetAllPlayerController(false); + if table.getCount(LastPCs) == 1 then + for i, v in pairs(LastPCs) do + self:SetRoundWinner(v.PlayerKey) + return self.RoundWinner; + end + end + -- 设置一下 + local DeadTimesTable = {}; + for PlayerKey, DeadTimes in pairs(self.RoundDeadTimes) do + table.insert(DeadTimesTable, { + PlayerKey = PlayerKey, + DeadTimes = DeadTimes, + }); + end + if #DeadTimesTable > 0 then + table.sort(DeadTimesTable, function(a, b) + return a.DeadTimes < b.DeadTimes; + end); + if #DeadTimesTable == 1 then + UE.ForeachAllPCs(function(PC) + if PC.PlayerKey ~= DeadTimesTable[1].PlayerKey then + self:SetRoundWinner(PC.PlayerKey); + end + end) + return self.RoundWinner; + else + if DeadTimesTable[1].DeadTimes < DeadTimesTable[2].DeadTimes then + self:SetRoundWinner(DeadTimesTable[1].PlayerKey); + return self.RoundWinner; + end + end + end + UGCLogSystem.LogTree(string.format("[Mini_Solo:GetRoundWinner] DeadTimesTable ="), DeadTimesTable) + -- 判断一下生命值,到这步肯定是两个玩家都存活 + local HealthTable = {}; + UE.ForeachAllPCs(function(PC) + local Pawn = UGCGameSystem.GetPlayerPawnByPlayerKey(PC.PlayerKey); + if UE.IsValidPawn(Pawn) then + table.insert(HealthTable, { + PlayerKey = PC.PlayerKey, + Health = UGCPawnAttrSystem.GetHealth(Pawn), + }); + else + table.insert(HealthTable, { + PlayerKey = PC.PlayerKey, + Health = 0, + }); + end + end) + UGCLogSystem.LogTree(string.format("[Mini_Solo:GetRoundWinner] HealthTable ="), HealthTable) + if table.getCount(HealthTable) > 1 then + table.sort(HealthTable, function(a, b) + return a.Health > b.Health; + end) + if HealthTable[1].Health ~= HealthTable[2].Health then + self:SetRoundWinner(HealthTable[1].PlayerKey); + return self.RoundWinner; + end + end + -- 判断伤害 + local Damages = {}; + for PlayerKey, Damage in pairs(self.RoundDamages) do + table.insert(Damages, { + PlayerKey = PlayerKey, + Damage = Damage, + }); + end + if #Damages == 2 then + table.sort(Damages, function(a, b) + return a.Damage > b.Damage; + end); + if Damages[1].Damage > Damages[2].Damage then + self:SetRoundWinner(Damages[1].PlayerKey); + return self.RoundWinner; + end + elseif #Damages == 1 then + self:SetRoundWinner(Damages[1].PlayerKey); + return self.RoundWinner; + end + UGCLogSystem.LogTree(string.format("[Mini_Solo:GetRoundWinner] Damages ="), Damages) + end + return self.RoundWinner; +end + +function Mini_Solo:SetRoundWinner(InWinner) + self.RoundWinner = InWinner; + self:DOREPONCE("RoundWinners"); +end + +function Mini_Solo:GetScore() + -- 获取几方的一个数组,然后进行排好序 + local Rounds = {}; + for i, v in pairs(self.RoundWinners) do + if v.Winner then + Rounds[v.Winner] = (Rounds[v.Winner] or 0) + 1; + end + end + return Rounds; +end + +------------------------------------------- 武器 ------------------------------------------- +function Mini_Solo:OnSelectWeapons(InPlayerKey, ItemId, IsSelect) + if self.State ~= MiniGameState.MINI_PREPARE then return ; end + UGCLogSystem.Log("[Mini_Solo:OnSelectWeapons] 开始选择 InPlayerKey = %d, ItemId = %d, IsSelect = %s", InPlayerKey, ItemId, tostring(IsSelect)); + if self.SelectWeapons[InPlayerKey] == nil then + self.SelectWeapons[InPlayerKey] = {}; + end + if IsSelect then + -- 检查是否超过约定个数 + if table.getCount(self.SelectWeapons[InPlayerKey]) < self.SelectWeaponCount then + local Find = false; + for i, v in pairs(self.SelectWeapons[InPlayerKey]) do + if v == ItemId then + Find = true; + end + end + if not Find then + table.insert(self.SelectWeapons[InPlayerKey], ItemId); + end + end + else + local Find, FindIndex = false, 0; + for i, v in pairs(self.SelectWeapons[InPlayerKey]) do + if v == ItemId then + Find = true; + FindIndex = i; + end + end + if FindIndex ~= 0 then + table.remove(self.SelectWeapons[InPlayerKey], FindIndex); + end + -- 检查是否为空 + if table.isEmpty(self.SelectWeapons[InPlayerKey]) then + self.SelectWeapons[InPlayerKey] = nil; + end + end + -- 同步 + self:DOREPONCE("SelectWeapons"); -- 这种方式同步数据 + UGCLogSystem.LogTree(string.format("[Mini_Solo:OnSelectWeapons] SelectWeapons ="), self.SelectWeapons) +end + +--- 执行属性同步 +function Mini_Solo:DOREPONCE(Name) + self.Owner:SetGameInfo(Name, self[Name]); +end + +function Mini_Solo:OnRep_SelectWeapons(InOld) + UGCLogSystem.Log("[Mini_Solo:OnRep_SelectWeapons] 执行") + -- 显示自己已经选择了的 + UGCLogSystem.LogTree(string.format("[Mini_Solo:OnRep_SelectWeapons] self.SelectWeapons ="), self.SelectWeapons) + UGCEventSystem.SendEvent(EventTypes.UpdateSelectWeapons, self.SelectWeapons); +end + +Mini_Solo.CurrWeapon = {}; + +function Mini_Solo:SelectCurrWeapon(InPlayerKey, InWeaponId) + -- 移除对应的 + --if self.State ~= MiniGameState.ROUND_GAMING then return; end + UGCLogSystem.LogTree(string.format("[Mini_Solo:SelectCurrWeapon] self.SelectWeapons ="), self.SelectWeapons) + local Index = nil; + if InWeaponId == nil then + Index = self:RandSelectCurrWeapon(InPlayerKey) + else + Index = table.find(self.SelectWeapons[InPlayerKey], InWeaponId) + if Index == nil then + Index = self:RandSelectCurrWeapon(InPlayerKey); + end + end + + if Index ~= nil then + self.CurrWeapon[InPlayerKey] = self.SelectWeapons[InPlayerKey][Index]; + self:DOREPONCE("CurrWeapon"); + else + UGCLogSystem.Log("[Mini_Solo:SelectCurrWeapon] Index 为空,很奇怪,查一下"); + end + UGCLogSystem.Log("[Mini_Solo:SelectCurrWeapon] Index = %d", Index); +end + +--- 随机当前武器 +function Mini_Solo:RandSelectCurrWeapon(InPlayerKey) + UGCLogSystem.Log("[Mini_Solo:RandSelectCurrWeapon] 随机选择索引") + return math.random(table.getCount(self.SelectWeapons[InPlayerKey])) +end + +function Mini_Solo:OnRep_CurrWeapon() + UGCLogSystem.LogTree(string.format("[Mini_Solo:OnRep_CurrWeapon] CurrWeapon ="), self.CurrWeapon); + -- 通知选择了 + UGCEventSystem.SendEvent(EventTypes.UpdateCurrWeapon, self.CurrWeapon); +end + +Mini_Solo.PlayerSelectMaps = {}; + +function Mini_Solo:OnPlayerSelectMaps(PlayerKey, MapName) + if self.State > MiniGameState.MINI_PREPARE then return ; end + self.PlayerSelectMaps[PlayerKey] = MapName; + self:DOREPONCE("PlayerSelectMaps"); +end + +--- 这是被击中之后的表现 +function Mini_Solo:OnPlayerInjury(PlayerKey, CauserKey, DamageData) + if not self:IsFormalMode() then return ; end + local WeaponID = DamageData.WeaponID; -- 需要去除不是的环境 + -- 说明存在 + if CauserKey ~= nil and UE.GetAccountInfo(CauserKey) ~= nil then + self:AddSelectWeaponsArchive(CauserKey, WeaponID, 5, 1); + -- 计算暴击数 + if DamageData.IsHeadShotDamage then + self:AddSelectWeaponsArchive(CauserKey, WeaponID, 6, 1); + end + --- 总伤害 + self:AddSelectWeaponsArchive(CauserKey, WeaponID, 7, DamageData.Damage); + end +end + +--- 对应的是 UE.MakeSelectWeapon +---@param PlayerKey PlayerKey 玩家Key +---@param WeaponID int32 武器ID +---@param MajorIndex int32 主要索引 +---@param AddCount int32 添加数量 +function Mini_Solo:AddSelectWeaponsArchive(PlayerKey, WeaponID, MajorIndex, AddCount) + if ArchiveTable[PlayerKey].SelectWeapons == nil then ArchiveTable[PlayerKey].SelectWeapons = {}; end + if ArchiveTable[PlayerKey].SelectWeapons[WeaponID] == nil then + ArchiveTable[PlayerKey].SelectWeapons[WeaponID] = { + 0, -- 选择的次数 + 0, -- 使用次数 + 0, -- 获胜次数 + 0, -- 射击数 + 0, -- 击中数 + 0, -- 暴击数 + 0, -- 总伤害 + }; + end + -- 二次验证 + ArchiveTable[PlayerKey].SelectWeapons[WeaponID][MajorIndex] = (ArchiveTable[PlayerKey].SelectWeapons[WeaponID][MajorIndex] or 0) + AddCount; +end + +function Mini_Solo:OnRep_PlayerSelectMaps() + if not table.isEmpty(self.PlayerSelectMaps) then + UGCLogSystem.LogTree(string.format("[Mini_Solo:OnRep_PlayerSelectMaps] PlayerSelectMaps ="), self.PlayerSelectMaps); + WidgetManager:GetPanel(WidgetConfig.EUIType.AllWeapon, function(Widget) + Widget:OnPlayerSelectMap(self.PlayerSelectMaps); + end); + end +end + +function Mini_Solo:OnRep_RoundTimes() + UGCLogSystem.Log("[Mini_Solo:OnRep_RoundTimes] 当前是 %s 关卡", tostring(self.RoundTimes)) + UGCEventSystem.SendEvent(EventTypes.UpdateRoundTimes, self.RoundTimes, self.TotalRoundTimes); +end + +--- 设置是否开启禁用功能 +function Mini_Solo:SetEnableDisableType(InPlayerKey, DisableType, IsEnable) + if self.State > MiniGameState.ROUND_PREPARE then return ; end + if self.Disables[InPlayerKey] == nil then self.Disables[InPlayerKey] = {}; end + self.Disables[InPlayerKey][DisableType] = IsEnable; + -- 先不管 + self:DOREPONCE("Disables"); +end + +function Mini_Solo:OnRep_Disables() + UGCLogSystem.LogTree(string.format("[Mini_Solo:OnRep_Disables] self.Disables ="), self.Disables) + UGCEventSystem.SendEvent(EventTypes.PlayerDisable, self.Disables) +end + +Mini_Solo.PlayerSelectModes = {}; + +function Mini_Solo:OnRep_PlayerSelectModes() + UGCLogSystem.LogTree(string.format("[Mini_Solo:OnRep_PlayerSelectModes] self.PlayerSelectModes ="), self.PlayerSelectModes) + UGCEventSystem.SendEvent(EventTypes.UpdateSelectModes, self.PlayerSelectModes); + if table.getCount(self.PlayerSelectModes) == 2 then + if self.PlayerSelectModes[1] == self.PlayerSelectModes[2] then + GlobalModeType = self.PlayerSelectModes[1]; + else + GlobalModeType = GameModeConfig.EGameModeType.DefaultMode; + end + -- 更新一下 + UGCEventSystem.SendEvent(EventTypes.UpdateModeType, GlobalModeType); + end +end + +--- 娱乐模式武器数据 +Mini_Solo.EnterWeaponItem = {}; + +--- 选择模式,一个玩家只能选一次 +function Mini_Solo:SelectMode(InPlayerKey, InModeType) + UGCLogSystem.Log("[Mini_Solo:SelectMode] 执行,PlayerKey = %s,ModeType = %s", tostring(InPlayerKey), tostring(InModeType)); + table.insert(self.PlayerSelectModes, InModeType); + ArchiveTable[InPlayerKey].ModeType = InModeType; + self:DOREPONCE("PlayerSelectModes"); + + -- 检查是否跟玩家数量不一样 + if #self.PlayerSelectModes == table.getCount(UGCGameSystem.GetAllPlayerController(false)) then + if self.PlayerSelectModes[1] == self.PlayerSelectModes[2] and self.PlayerSelectModes[1] ~= GameModeConfig.EGameModeType.DefaultMode then + self.ModeType = self.PlayerSelectModes[1]; + self:DOREPONCE("ModeType"); + self:ResetMiniGameTimes(); + + UGCLogSystem.Log("[Mini_Solo:SelectMode] 执行") + -- 拿到之前的武器,并赋值 + for i, PC in pairs(UGCGameSystem.GetAllPlayerController(false)) do + local PlayerKey = PC.PlayerKey; + self:GetPlayerEnterWeapons(PlayerKey, ArchiveTable[PlayerKey].EnterWeaponIndex); + end + + UGCLogSystem.LogTree(string.format("[Mini_Solo:SelectMode] EnterWeaponItem ="), self.EnterWeaponItem) + + UGCLogSystem.Log("[Mini_Solo:SelectMode] self.SelectMapTime = %s", tostring(self.SelectMapTime)); + if self.CurrTimeCount ~= nil and self.CurrTimeCount > GameStateTimes.GangUp.SelectMapTime then + UGCLogSystem.Log("[Mini_Solo:SelectMode] self.CurrTimeCount = %s", tostring(self.CurrTimeCount), tostring(self.SelectMapTime)); + MiniManager:UpdateInternalCount(GameStateTimes.GangUp.SelectMapTime); + end + end + end +end + +function Mini_Solo:OnRep_ModeType() + self:ResetMiniGameTimes(); + -- 同步一下 + if GlobalModeType == nil then GlobalModeType = self.ModeType; end + UGCEventSystem.SendEvent(EventTypes.UpdateModeType, self.ModeType); +end + +--- 重置时间 +function Mini_Solo:ResetMiniGameTimes() + -- 把时间传递过去 + local Times = GameModeConfig.GameModeInfo[self.ModeType].MiniGameTimes; + if Times then + for Name, Time in pairs(Times) do MiniGameTimes[Name] = Time; end + end +end + +Mini_Solo.PlayerSelectedWeapons = {}; + +---@deprecated +function Mini_Solo:PlayerSelectWeapon(PlayerKey, WeaponID) + -- 给玩家添加上去 + self.CurrWeaponItem[PlayerKey] = WeaponID; + if self.PlayerSelectedWeapons[PlayerKey] == nil then self.PlayerSelectedWeapons[PlayerKey] = {}; end + self.PlayerSelectedWeapons[PlayerKey][WeaponID] = 1; + -- 开始添加这个武器 + self:PlayerAddWeapon(PlayerKey, WeaponID); + self:DOREPONCE("CurrWeaponItem"); + UGCLogSystem.Log("[Mini_Solo:PlayerSelectWeapon] WeaponID = %d", WeaponID); + ArchiveTable[PlayerKey].LastWeapon = WeaponID; +end + +--- 玩家选择多个武器,此处是配置,并不是设置 +function Mini_Solo:PlayerSelectWeapons(PlayerKey, SaveIndex, Weapons) + -- 保存EnterWeapons + if table.isEmpty(ArchiveTable[PlayerKey].EnterWeapons) then ArchiveTable[PlayerKey].EnterWeapons = {}; end + ArchiveTable[PlayerKey].EnterWeapons[SaveIndex] = Weapons; + UGCLogSystem.LogTree(string.format("[Mini_Solo:PlayerSelectWeapons] Weapons ="), Weapons) + self.EnterWeaponItem[PlayerKey] = TableHelper.DeepCopyTable(Weapons); + local Pawn = UGCGameSystem.GetPlayerPawnByPlayerKey(PlayerKey); + if Pawn and UE.IsValid(Pawn) then + Pawn:UpdateSlotWeapons(Weapons); + local PC = UGCGameSystem.GetPlayerControllerByPlayerKey(PlayerKey); + UnrealNetwork.CallUnrealRPC(PC, Pawn, "UpdateEnterWeapons", SaveIndex, Weapons); + end +end + +--- 选择武器索引 +function Mini_Solo:SelectWeaponIndex(PlayerKey, WeaponIndex) + if self.ModeType == GameModeConfig.EGameModeType.DefaultMode then return ; end + ArchiveTable[PlayerKey].EnterWeaponIndex = WeaponIndex; + local Pawn = UGCGameSystem.GetPlayerPawnByPlayerKey(PlayerKey); + -- 玩家拾取该武器 + if Pawn then + Pawn:UpdateSlotWeapons(self:GetPlayerEnterWeapons(PlayerKey, WeaponIndex)); + end +end + +Mini_Solo.AlreadyPlayers = {}; + +function Mini_Solo:OnPlayerAlready(PlayerKey) + self.AlreadyPlayers[PlayerKey] = 1; + ArchiveTable[PlayerKey].ModeType = GameModeConfig.EGameModeType.GangUpMode; + self:DOREPONCE("AlreadyPlayers"); + if self.ModeType == GameModeConfig.EGameModeType.DefaultMode then return ; end + local SelectMapTime = GameModeConfig.GameModeInfo[self.ModeType].SelectMapTime; + if SelectMapTime == nil then return ; end + if self.CurrTimeCount <= SelectMapTime then return ; end + if table.getCount(self.AlreadyPlayers) < 2 then return ; end + + MiniManager:UpdateInternalCount(SelectMapTime); +end + +function Mini_Solo:OnRep_AlreadyPlayers() + UGCEventSystem.SendEvent(EventTypes.UpdatePlayerReady, self.AlreadyPlayers); +end + +function Mini_Solo:ShowRankInheritanceUI() + -- 看一下是否可以显示段位页面 + if table.isEmpty(ArchiveTable[LocalPlayerKey]) then return ; end + if ArchiveTable[LocalPlayerKey].IsNewSeason then + -- 读取之前数据 + local Seasons = ArchiveTable[LocalPlayerKey].Seasons + if table.isEmpty(Seasons) then return ; end + UGCLogSystem.LogTree(string.format("[Mini_Solo:ShowRankInheritanceUI] Seasons ="), Seasons) + -- 获取上一赛季 + local LastSeason, LastRankScore = -1, 0; + for i, v in pairs(Seasons) do + if i > LastSeason then + LastSeason = i; + LastRankScore = v[2][1]; + end + end + if LastSeason > -1 then + local HideScore = ArchiveTable[LocalPlayerKey].HideScore; + UGCLogSystem.Log("[Mini_Solo:ShowRankInheritanceUI] LastRankScore = %d, HideScore = %d", LastRankScore, HideScore) + WidgetManager:ShowPanel(WidgetConfig.EUIType.ShowRankInheritance, false, LastSeason, DefaultSettings.CurrentSeason, LastRankScore, DefaultSettings.RankScore, HideScore); + end + end +end + +function Mini_Solo:OpenOldParts(PlayerKey, bOldParts) + if ArchiveTable[PlayerKey] then + ArchiveTable[PlayerKey].bOldParts = bOldParts; + end +end + +return Mini_Solo; diff --git a/SoloKing/SoloKing.ugcproj b/SoloKing/SoloKing.ugcproj index 2aee0fab..09f28466 100644 --- a/SoloKing/SoloKing.ugcproj +++ b/SoloKing/SoloKing.ugcproj @@ -53,13 +53,13 @@ SwitchesInMaps=((Key="r.Mobile.EnableIBL",Value=0),(Key="s.StreamableDelegateLim PlayBindingArray=[] [JobOption] -LastJobId=-1 -LastWindowsJobId=-1 -LastAndroidJobId=-1 -LastIOSJobId=-1 -PakOnly=0 -LastSkipBake=False -LastTargetPlatform=LinuxServer +LastJobId=600045182 +LastWindowsJobId=600026723 +LastAndroidJobId=600026723 +LastIOSJobId=600026723 +PakOnly=1 +LastSkipBake=True +LastTargetPlatform=LinuxServer+WindowsNoEditor+Android_ETC2+IOS+OpenHarmony_ETC2 [UGCUploadOption] PlatformIndex=0