From ea5a80feef14b35ce8e423c9cbd74d25261e4b27 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 May 2023 18:01:30 +0000 Subject: [PATCH 01/33] build(deps): bump deps/rapidjson from `949c771` to `0e88d5e` Bumps [deps/rapidjson](https://github.com/Tencent/rapidjson) from `949c771` to `0e88d5e`. - [Release notes](https://github.com/Tencent/rapidjson/releases) - [Commits](https://github.com/Tencent/rapidjson/compare/949c771b03de448bdedea80c44a4a5f65284bfeb...0e88d5e40448616ede258be29e6e337eb99aa104) --- updated-dependencies: - dependency-name: deps/rapidjson dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- deps/rapidjson | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/rapidjson b/deps/rapidjson index 949c771b..0e88d5e4 160000 --- a/deps/rapidjson +++ b/deps/rapidjson @@ -1 +1 @@ -Subproject commit 949c771b03de448bdedea80c44a4a5f65284bfeb +Subproject commit 0e88d5e40448616ede258be29e6e337eb99aa104 From e548c5f2210fa9436111236fc577fd5dc1fc96c0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 9 May 2023 18:01:37 +0000 Subject: [PATCH 02/33] build(deps): bump deps/curl from `8e21b1a` to `8e6abec` Bumps [deps/curl](https://github.com/curl/curl) from `8e21b1a` to `8e6abec`. - [Release notes](https://github.com/curl/curl/releases) - [Commits](https://github.com/curl/curl/compare/8e21b1a05f3c0ee098dbcb6c3d84cb61f102a122...8e6abece403f162946d360c1871e2251f124a637) --- updated-dependencies: - dependency-name: deps/curl dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- deps/curl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/curl b/deps/curl index 8e21b1a0..8e6abece 160000 --- a/deps/curl +++ b/deps/curl @@ -1 +1 @@ -Subproject commit 8e21b1a05f3c0ee098dbcb6c3d84cb61f102a122 +Subproject commit 8e6abece403f162946d360c1871e2251f124a637 From bd1bb6f2a146e34003bffb1e62360ca02184aa49 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 10 May 2023 18:05:44 +0000 Subject: [PATCH 03/33] build(deps): bump deps/rapidjson from `0e88d5e` to `2a1f586` Bumps [deps/rapidjson](https://github.com/Tencent/rapidjson) from `0e88d5e` to `2a1f586`. - [Release notes](https://github.com/Tencent/rapidjson/releases) - [Commits](https://github.com/Tencent/rapidjson/compare/0e88d5e40448616ede258be29e6e337eb99aa104...2a1f586ba692ecbbf6d63c8ffbd4d837b1d4a9a4) --- updated-dependencies: - dependency-name: deps/rapidjson dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- deps/rapidjson | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/rapidjson b/deps/rapidjson index 0e88d5e4..2a1f586b 160000 --- a/deps/rapidjson +++ b/deps/rapidjson @@ -1 +1 @@ -Subproject commit 0e88d5e40448616ede258be29e6e337eb99aa104 +Subproject commit 2a1f586ba692ecbbf6d63c8ffbd4d837b1d4a9a4 From ab640ba4708225dc342ba150a6ace62289bd4fe4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 10 May 2023 18:05:49 +0000 Subject: [PATCH 04/33] build(deps): bump deps/curl from `8e6abec` to `2cc1c93` Bumps [deps/curl](https://github.com/curl/curl) from `8e6abec` to `2cc1c93`. - [Release notes](https://github.com/curl/curl/releases) - [Commits](https://github.com/curl/curl/compare/8e6abece403f162946d360c1871e2251f124a637...2cc1c93f45ce948c2e1122e53d8360740a853ce2) --- updated-dependencies: - dependency-name: deps/curl dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- deps/curl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/curl b/deps/curl index 8e6abece..2cc1c93f 160000 --- a/deps/curl +++ b/deps/curl @@ -1 +1 @@ -Subproject commit 8e6abece403f162946d360c1871e2251f124a637 +Subproject commit 2cc1c93f45ce948c2e1122e53d8360740a853ce2 From 6245762862897004b03cffda456d3851f716f51d Mon Sep 17 00:00:00 2001 From: WantedDV <122710241+WantedDV@users.noreply.github.com> Date: Fri, 12 May 2023 15:02:12 -0230 Subject: [PATCH 05/33] Add unlock all easter eggs option --- data/ui_scripts/stats/__init__.lua | 60 +++++++++++++++++++++++------- 1 file changed, 46 insertions(+), 14 deletions(-) diff --git a/data/ui_scripts/stats/__init__.lua b/data/ui_scripts/stats/__init__.lua index 70a1eeac..cad82697 100644 --- a/data/ui_scripts/stats/__init__.lua +++ b/data/ui_scripts/stats/__init__.lua @@ -16,6 +16,20 @@ DataSources.MPStatsSettings = DataSourceHelpers.ListSetup("MPStatsSettings", fun if dvarName == "cg_unlockall_loot" then Engine.SetDvar("ui_enableAllHeroes", f1_arg1.value) end + if dvarName == "all_ee_completed" then + Engine.ExecNow(f1_arg0, "statsetbyname darkops_zod_ee " .. f1_arg1.value) + Engine.ExecNow(f1_arg0, "statsetbyname darkops_zod_super_ee " .. f1_arg1.value) + Engine.ExecNow(f1_arg0, "statsetbyname darkops_factory_ee " .. f1_arg1.value) + Engine.ExecNow(f1_arg0, "statsetbyname darkops_factory_super_ee " .. f1_arg1.value) + Engine.ExecNow(f1_arg0, "statsetbyname darkops_castle_ee " .. f1_arg1.value) + Engine.ExecNow(f1_arg0, "statsetbyname darkops_castle_super_ee " .. f1_arg1.value) + Engine.ExecNow(f1_arg0, "statsetbyname darkops_island_ee " .. f1_arg1.value) + Engine.ExecNow(f1_arg0, "statsetbyname darkops_island_super_ee " .. f1_arg1.value) + Engine.ExecNow(f1_arg0, "statsetbyname darkops_stalingrad_ee " .. f1_arg1.value) + Engine.ExecNow(f1_arg0, "statsetbyname darkops_stalingrad_super_ee " .. f1_arg1.value) + Engine.ExecNow(f1_arg0, "statsetbyname darkops_genesis_ee " .. f1_arg1.value) + Engine.ExecNow(f1_arg0, "statsetbyname DARKOPS_GENESIS_SUPER_EE " .. f1_arg1.value) + end end table.insert(optionsTable, @@ -103,20 +117,38 @@ DataSources.MPStatsSettings = DataSourceHelpers.ListSetup("MPStatsSettings", fun value = 1 }, }, nil, updateDvar)) - table.insert(optionsTable, - CoD.OptionsUtility.CreateDvarSettings(controller, "Unlock all Specialists Outfits", - "All specialists outfits are unlocked.", "MPStatsSettings_unlockall_specialists_outfits", - "cg_unlockall_specialists_outfits", { - { - option = "MENU_DISABLED", - value = 0, - default = true - }, - { - option = "MENU_ENABLED", - value = 1 - }, - }, nil, updateDvar)) + if Engine.CurrentSessionMode() == Enum.eModes.MODE_MULTIPLAYER then + table.insert(optionsTable, + CoD.OptionsUtility.CreateDvarSettings(controller, "Unlock all Specialists Outfits", + "All specialists outfits are unlocked.", "MPStatsSettings_unlockall_specialists_outfits", + "cg_unlockall_specialists_outfits", { + { + option = "MENU_DISABLED", + value = 0, + default = true + }, + { + option = "MENU_ENABLED", + value = 1 + }, + }, nil, updateDvar)) + end + if Engine.CurrentSessionMode() == Enum.eModes.MODE_ZOMBIES then + table.insert(optionsTable, + CoD.OptionsUtility.CreateDvarSettings(controller, "Unlock Easter Eggs", + "Complete all Easter Egg Achievements.", "MPStatsSettings_complete_ee", + "all_ee_completed", { + { + option = "MENU_DISABLED", + value = 0, + default = true + }, + { + option = "MENU_ENABLED", + value = 1 + }, + }, nil, updateDvar)) + end local rankLevels = {} if Engine.CurrentSessionMode() == Enum.eModes.MODE_MULTIPLAYER then From 5a6b14faa98af74a46af4707aca6b2952d102504 Mon Sep 17 00:00:00 2001 From: WantedDV <122710241+WantedDV@users.noreply.github.com> Date: Fri, 12 May 2023 15:04:26 -0230 Subject: [PATCH 06/33] Allow setting master rank --- data/ui_scripts/stats/__init__.lua | 152 ++++++++++++++++++++--------- 1 file changed, 106 insertions(+), 46 deletions(-) diff --git a/data/ui_scripts/stats/__init__.lua b/data/ui_scripts/stats/__init__.lua index cad82697..963ca382 100644 --- a/data/ui_scripts/stats/__init__.lua +++ b/data/ui_scripts/stats/__init__.lua @@ -151,43 +151,57 @@ DataSources.MPStatsSettings = DataSourceHelpers.ListSetup("MPStatsSettings", fun end local rankLevels = {} - if Engine.CurrentSessionMode() == Enum.eModes.MODE_MULTIPLAYER then - rankLevels = { 1, 10, 20, 30, 40, 50, 55 } - elseif Engine.CurrentSessionMode() == Enum.eModes.MODE_ZOMBIES then - rankLevels = { 1, 10, 20, 30, 35 } - end local rankObjs = {} - local hasDefault = false + local hasDefault = true + local currentPrestige = CoD.PrestigeUtility.GetCurrentPLevel(controller, Engine.CurrentSessionMode()) local currentRank = CoD.BlackMarketUtility.GetCurrentRank(controller) + 1 - for index, value in ipairs(rankLevels) do - table.insert(rankObjs, { - name = value, - value = value - 1, - default = value == currentRank, - title = "Rank Level", - desc = "" - }) - if not hasDefault then - hasDefault = value == currentRank + + local isMasterPrestige = currentPrestige == 11 + + if Engine.CurrentSessionMode() == Enum.eModes.MODE_MULTIPLAYER then + if not isMasterPrestige then + rankLevels = { 1, 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55 } + else + rankLevels = { 56, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000 } + end + + elseif Engine.CurrentSessionMode() == Enum.eModes.MODE_ZOMBIES then + if not isMasterPrestige then + rankLevels = { 1, 5, 10, 15, 20, 25, 30, 35 } + else + rankLevels = { 36, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000 } end end - if not hasDefault then + local maxlevel = math.max(table.unpack(rankLevels)) + local minlevel = math.min(table.unpack(rankLevels)) + + for index, value in ipairs(rankLevels) do table.insert(rankObjs, { - name = currentRank, + name = value <= minlevel and "Min" or value >= maxlevel and "Max" or value, + value = value - 1, + default = value == currentRank, + title = "Rank Level", + desc = value~=currentRank and "" or "Current Rank" + }) + end + + if hasDefault and currentRank ~= minlevel and currentRank < maxlevel and not isMasterPrestige then + table.insert(rankObjs, { + name = "Current: " .. tostring(currentRank <= minlevel and "Min" or currentRank >= maxlevel and "Max" or currentRank), value = currentRank - 1, default = true, title = "Rank Level", - desc = "" + desc = "Do not adjust rank" }) end local prestigeTable = {} - for i = 0, 10 do + for i = 0, 11 do table.insert(prestigeTable, { - name = i == 0 and "None" or i, + name = i == 0 and "None" or i==11 and "Master" or i, value = i, - default = i == CoD.PrestigeUtility.GetCurrentPLevel(controller), + default = i == currentPrestige, title = "Prestige", desc = "" }) @@ -228,25 +242,18 @@ DataSources.MPStatsSettings = DataSourceHelpers.ListSetup("MPStatsSettings", fun table.insert(optionsTable, { models = { - name = "Rank Level", + name = "Prestige", desc = "", image = nil, - optionsDatasource = createSettingsDatasource(controller, "MPStatsSettings_rank_level", rankObjs, - CoD.BlackMarketUtility.GetCurrentRank(controller), false, function(f1_arg0, f1_arg1, f1_arg2, dvarName, f1_arg4) + optionsDatasource = createSettingsDatasource(controller, "MPStatsSettings_rank_prestige", prestigeTable, + CoD.PrestigeUtility.GetCurrentPLevel(controller, Engine.CurrentSessionMode()), false, function(f1_arg0, f1_arg1, f1_arg2, dvarName, f1_arg4) UpdateInfoModels(f1_arg1) - local rankTable = nil - if Engine.CurrentSessionMode() == Enum.eModes.MODE_MULTIPLAYER then - rankTable = "gamedata/tables/mp/mp_ranktable.csv" - elseif Engine.CurrentSessionMode() == Enum.eModes.MODE_ZOMBIES then - rankTable = "gamedata/tables/zm/zm_ranktable.csv" + local newPrestige = f1_arg1.value + if newPrestige == 11 then + Engine.Exec( f1_arg0, "PrestigeStatsMaster " .. tostring( Engine.CurrentSessionMode() ) ) end - local skipLines = Engine.CurrentSessionMode() == Enum.eModes.MODE_MULTIPLAYER and 3 or 2 - local maxXp = tonumber(Engine.TableLookupGetColumnValueForRow(rankTable, f1_arg1.value + skipLines, 7)) - if maxXp == nil then - maxXp = 9999999999 - end - Engine.ExecNow(f1_arg0, "statsetbyname rankxp " .. maxXp - 1) - Engine.ExecNow(f1_arg0, "statsetbyname rank " .. f1_arg1.value) + Engine.ExecNow(f1_arg0, "statsetbyname plevel " .. newPrestige) + Engine.ExecNow(f1_arg0, "statsetbyname hasprestiged " .. (newPrestige > 0 and 1 or 0)) Engine.Exec(f1_arg0, "uploadstats " .. tostring(Engine.CurrentSessionMode())) end) }, @@ -258,16 +265,70 @@ DataSources.MPStatsSettings = DataSourceHelpers.ListSetup("MPStatsSettings", fun table.insert(optionsTable, { models = { - name = "Prestige", + name = "Rank Level", desc = "", image = nil, - optionsDatasource = createSettingsDatasource(controller, "MPStatsSettings_rank_prestige", prestigeTable, - CoD.PrestigeUtility.GetCurrentPLevel(controller), false, function(f1_arg0, f1_arg1, f1_arg2, dvarName, f1_arg4) + optionsDatasource = createSettingsDatasource(controller, "MPStatsSettings_rank_level", rankObjs, + CoD.BlackMarketUtility.GetCurrentRank(controller), false, function(f1_arg0, f1_arg1, f1_arg2, dvarName, f1_arg4) UpdateInfoModels(f1_arg1) - local newPrestige = f1_arg1.value - Engine.ExecNow(f1_arg0, "statsetbyname plevel " .. newPrestige) - Engine.ExecNow(f1_arg0, "statsetbyname hasprestiged " .. (newPrestige > 0 and 1 or 0)) - Engine.Exec(f1_arg0, "uploadstats " .. tostring(Engine.CurrentSessionMode())) + local rankTable = nil + local rank = f1_arg1.value + 1 + if currentPrestige <= 10 then + if Engine.CurrentSessionMode() == Enum.eModes.MODE_MULTIPLAYER then + rankTable = "gamedata/tables/mp/mp_ranktable.csv" + elseif Engine.CurrentSessionMode() == Enum.eModes.MODE_ZOMBIES then + rankTable = "gamedata/tables/zm/zm_ranktable.csv" + end + local skipLines = Engine.CurrentSessionMode() == Enum.eModes.MODE_MULTIPLAYER and 3 or 2 + local maxXp = tonumber(Engine.TableLookupGetColumnValueForRow(rankTable, rank - 2 + skipLines, 7)) + if Engine.CurrentSessionMode() == Enum.eModes.MODE_MULTIPLAYER then + if maxXp ~= nil and rank == maxlevel then + maxXp = maxXp + 55600 + end + end + if Engine.CurrentSessionMode() == Enum.eModes.MODE_ZOMBIES then + if maxXp ~= nil and rank == maxlevel then + maxXp = maxXp + 54244 + end + end + if maxXp == nil then + maxXp = 0 + end + Engine.ExecNow(f1_arg0, "statsetbyname rank " .. rank - 1 ) + Engine.ExecNow(f1_arg0, "statsetbyname rankxp " .. maxXp ) + Engine.ExecNow(f1_arg0, "statsetbyname paragon_rankxp " .. 0 ) + else + if Engine.CurrentSessionMode() == Enum.eModes.MODE_MULTIPLAYER then + rankTable = "gamedata/tables/mp/mp_paragonranktable.csv" + elseif Engine.CurrentSessionMode() == Enum.eModes.MODE_ZOMBIES then + rankTable = "gamedata/tables/zm/zm_paragonranktable.csv" + end + local skipLines = 2 + local maxXp = 0 + if Engine.CurrentSessionMode() == Enum.eModes.MODE_MULTIPLAYER then + maxXp = tonumber(Engine.TableLookupGetColumnValueForRow(rankTable, rank - 57 + skipLines, 7)) + if maxXp ~= nil and rank == maxlevel then + maxXp = maxXp + 55600 + end + rank = rank - 55 + end + if Engine.CurrentSessionMode() == Enum.eModes.MODE_ZOMBIES then + maxXp = tonumber(Engine.TableLookupGetColumnValueForRow(rankTable, rank - 37 + skipLines, 7)) + if maxXp ~= nil and rank == maxlevel then + maxXp = maxXp + 54244 + end + rank = rank - 35 + end + if maxXp == nil then + maxXp = 0 + end + Engine.ExecNow(f1_arg0, "statsetbyname paragon_rank " .. rank - 1 ) + Engine.ExecNow(f1_arg0, "statsetbyname paragon_rankxp " .. maxXp ) + end + Engine.Exec(f1_arg0, "uploadstats " .. tostring(Engine.CurrentSessionMode())) + Engine.Exec(f1_arg0, "savegamerprofilestats") + + currentRank = rank end) }, properties = { @@ -300,8 +361,7 @@ LUI.createMenu.BoiiiStatsMenu = function(controller) GameSettingsBackground:setLeftRight(true, true, 0, 0) GameSettingsBackground:setTopBottom(true, true, 0, 0) GameSettingsBackground.MenuFrame.titleLabel:setText(Engine.Localize("STATS SETTINGS")) - GameSettingsBackground.MenuFrame.cac3dTitleIntermediary0.FE3dTitleContainer0.MenuTitle.TextBox1.Label0:setText(Engine - .Localize("STATS SETTINGS")) + GameSettingsBackground.MenuFrame.cac3dTitleIntermediary0.FE3dTitleContainer0.MenuTitle.TextBox1.Label0:setText(Engine.Localize("STATS SETTINGS")) GameSettingsBackground.GameSettingsSelectedItemInfo.GameModeInfo:setAlpha(0) GameSettingsBackground.GameSettingsSelectedItemInfo.GameModeName:setAlpha(0) self:addElement(GameSettingsBackground) From 93b4240dcacd276f8a260cee26a37808ef41ba8d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 12 May 2023 18:00:57 +0000 Subject: [PATCH 07/33] build(deps): bump deps/curl from `2cc1c93` to `ac5ad52` Bumps [deps/curl](https://github.com/curl/curl) from `2cc1c93` to `ac5ad52`. - [Release notes](https://github.com/curl/curl/releases) - [Commits](https://github.com/curl/curl/compare/2cc1c93f45ce948c2e1122e53d8360740a853ce2...ac5ad5214261a2237bdbe344708f9d32c9393fd6) --- updated-dependencies: - dependency-name: deps/curl dependency-type: direct:production ... Signed-off-by: dependabot[bot] --- deps/curl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/deps/curl b/deps/curl index 2cc1c93f..ac5ad521 160000 --- a/deps/curl +++ b/deps/curl @@ -1 +1 @@ -Subproject commit 2cc1c93f45ce948c2e1122e53d8360740a853ce2 +Subproject commit ac5ad5214261a2237bdbe344708f9d32c9393fd6 From 0f47cacb9c0ce61940dcea24251dc93991915d2d Mon Sep 17 00:00:00 2001 From: WantedDV <122710241+WantedDV@users.noreply.github.com> Date: Fri, 12 May 2023 23:34:21 -0230 Subject: [PATCH 08/33] formatting --- data/ui_scripts/stats/__init__.lua | 42 ++++++++++++++++-------------- 1 file changed, 22 insertions(+), 20 deletions(-) diff --git a/data/ui_scripts/stats/__init__.lua b/data/ui_scripts/stats/__init__.lua index 963ca382..ce1f99fb 100644 --- a/data/ui_scripts/stats/__init__.lua +++ b/data/ui_scripts/stats/__init__.lua @@ -132,7 +132,7 @@ DataSources.MPStatsSettings = DataSourceHelpers.ListSetup("MPStatsSettings", fun value = 1 }, }, nil, updateDvar)) - end + end if Engine.CurrentSessionMode() == Enum.eModes.MODE_ZOMBIES then table.insert(optionsTable, CoD.OptionsUtility.CreateDvarSettings(controller, "Unlock Easter Eggs", @@ -155,7 +155,7 @@ DataSources.MPStatsSettings = DataSourceHelpers.ListSetup("MPStatsSettings", fun local hasDefault = true local currentPrestige = CoD.PrestigeUtility.GetCurrentPLevel(controller, Engine.CurrentSessionMode()) local currentRank = CoD.BlackMarketUtility.GetCurrentRank(controller) + 1 - + local isMasterPrestige = currentPrestige == 11 if Engine.CurrentSessionMode() == Enum.eModes.MODE_MULTIPLAYER then @@ -164,7 +164,6 @@ DataSources.MPStatsSettings = DataSourceHelpers.ListSetup("MPStatsSettings", fun else rankLevels = { 56, 100, 200, 300, 400, 500, 600, 700, 800, 900, 1000 } end - elseif Engine.CurrentSessionMode() == Enum.eModes.MODE_ZOMBIES then if not isMasterPrestige then rankLevels = { 1, 5, 10, 15, 20, 25, 30, 35 } @@ -182,13 +181,14 @@ DataSources.MPStatsSettings = DataSourceHelpers.ListSetup("MPStatsSettings", fun value = value - 1, default = value == currentRank, title = "Rank Level", - desc = value~=currentRank and "" or "Current Rank" + desc = value ~= currentRank and "" or "Current Rank" }) end if hasDefault and currentRank ~= minlevel and currentRank < maxlevel and not isMasterPrestige then table.insert(rankObjs, { - name = "Current: " .. tostring(currentRank <= minlevel and "Min" or currentRank >= maxlevel and "Max" or currentRank), + name = "Current: " .. + tostring(currentRank <= minlevel and "Min" or currentRank >= maxlevel and "Max" or currentRank), value = currentRank - 1, default = true, title = "Rank Level", @@ -199,7 +199,7 @@ DataSources.MPStatsSettings = DataSourceHelpers.ListSetup("MPStatsSettings", fun local prestigeTable = {} for i = 0, 11 do table.insert(prestigeTable, { - name = i == 0 and "None" or i==11 and "Master" or i, + name = i == 0 and "None" or i == 11 and "Master" or i, value = i, default = i == currentPrestige, title = "Prestige", @@ -246,11 +246,12 @@ DataSources.MPStatsSettings = DataSourceHelpers.ListSetup("MPStatsSettings", fun desc = "", image = nil, optionsDatasource = createSettingsDatasource(controller, "MPStatsSettings_rank_prestige", prestigeTable, - CoD.PrestigeUtility.GetCurrentPLevel(controller, Engine.CurrentSessionMode()), false, function(f1_arg0, f1_arg1, f1_arg2, dvarName, f1_arg4) + CoD.PrestigeUtility.GetCurrentPLevel(controller, Engine.CurrentSessionMode()), false, + function(f1_arg0, f1_arg1, f1_arg2, dvarName, f1_arg4) UpdateInfoModels(f1_arg1) local newPrestige = f1_arg1.value - if newPrestige == 11 then - Engine.Exec( f1_arg0, "PrestigeStatsMaster " .. tostring( Engine.CurrentSessionMode() ) ) + if newPrestige == 11 then + Engine.Exec(f1_arg0, "PrestigeStatsMaster " .. tostring(Engine.CurrentSessionMode())) end Engine.ExecNow(f1_arg0, "statsetbyname plevel " .. newPrestige) Engine.ExecNow(f1_arg0, "statsetbyname hasprestiged " .. (newPrestige > 0 and 1 or 0)) @@ -269,7 +270,8 @@ DataSources.MPStatsSettings = DataSourceHelpers.ListSetup("MPStatsSettings", fun desc = "", image = nil, optionsDatasource = createSettingsDatasource(controller, "MPStatsSettings_rank_level", rankObjs, - CoD.BlackMarketUtility.GetCurrentRank(controller), false, function(f1_arg0, f1_arg1, f1_arg2, dvarName, f1_arg4) + CoD.BlackMarketUtility.GetCurrentRank(controller), false, + function(f1_arg0, f1_arg1, f1_arg2, dvarName, f1_arg4) UpdateInfoModels(f1_arg1) local rankTable = nil local rank = f1_arg1.value + 1 @@ -294,9 +296,9 @@ DataSources.MPStatsSettings = DataSourceHelpers.ListSetup("MPStatsSettings", fun if maxXp == nil then maxXp = 0 end - Engine.ExecNow(f1_arg0, "statsetbyname rank " .. rank - 1 ) - Engine.ExecNow(f1_arg0, "statsetbyname rankxp " .. maxXp ) - Engine.ExecNow(f1_arg0, "statsetbyname paragon_rankxp " .. 0 ) + Engine.ExecNow(f1_arg0, "statsetbyname rank " .. rank - 1) + Engine.ExecNow(f1_arg0, "statsetbyname rankxp " .. maxXp) + Engine.ExecNow(f1_arg0, "statsetbyname paragon_rankxp " .. 0) else if Engine.CurrentSessionMode() == Enum.eModes.MODE_MULTIPLAYER then rankTable = "gamedata/tables/mp/mp_paragonranktable.csv" @@ -322,13 +324,12 @@ DataSources.MPStatsSettings = DataSourceHelpers.ListSetup("MPStatsSettings", fun if maxXp == nil then maxXp = 0 end - Engine.ExecNow(f1_arg0, "statsetbyname paragon_rank " .. rank - 1 ) - Engine.ExecNow(f1_arg0, "statsetbyname paragon_rankxp " .. maxXp ) + Engine.ExecNow(f1_arg0, "statsetbyname paragon_rank " .. rank - 1) + Engine.ExecNow(f1_arg0, "statsetbyname paragon_rankxp " .. maxXp) end - Engine.Exec(f1_arg0, "uploadstats " .. tostring(Engine.CurrentSessionMode())) - Engine.Exec(f1_arg0, "savegamerprofilestats") - - currentRank = rank + Engine.Exec(f1_arg0, "uploadstats " .. tostring(Engine.CurrentSessionMode())) + + currentRank = rank end) }, properties = { @@ -361,7 +362,8 @@ LUI.createMenu.BoiiiStatsMenu = function(controller) GameSettingsBackground:setLeftRight(true, true, 0, 0) GameSettingsBackground:setTopBottom(true, true, 0, 0) GameSettingsBackground.MenuFrame.titleLabel:setText(Engine.Localize("STATS SETTINGS")) - GameSettingsBackground.MenuFrame.cac3dTitleIntermediary0.FE3dTitleContainer0.MenuTitle.TextBox1.Label0:setText(Engine.Localize("STATS SETTINGS")) + GameSettingsBackground.MenuFrame.cac3dTitleIntermediary0.FE3dTitleContainer0.MenuTitle.TextBox1.Label0:setText( + Engine.Localize("STATS SETTINGS")) GameSettingsBackground.GameSettingsSelectedItemInfo.GameModeInfo:setAlpha(0) GameSettingsBackground.GameSettingsSelectedItemInfo.GameModeName:setAlpha(0) self:addElement(GameSettingsBackground) From 5f95b1279242114e940f998ec03dd3e42d0d3635 Mon Sep 17 00:00:00 2001 From: WantedDV <122710241+WantedDV@users.noreply.github.com> Date: Thu, 20 Apr 2023 22:18:03 -0230 Subject: [PATCH 09/33] Revert to original script dev blocks --- data/scripts/mp/bots/_bot.gsc_raw | 378 +++++++++++++++++------------- 1 file changed, 211 insertions(+), 167 deletions(-) diff --git a/data/scripts/mp/bots/_bot.gsc_raw b/data/scripts/mp/bots/_bot.gsc_raw index 609e7a22..1ffddbf4 100644 --- a/data/scripts/mp/bots/_bot.gsc_raw +++ b/data/scripts/mp/bots/_bot.gsc_raw @@ -7,7 +7,7 @@ #using scripts\shared\system_shared; #using scripts\shared\util_shared; #using scripts\shared\weapons_shared; -#using scripts\shared\weapons\_weapons; +#using scripts\shared\weapons\_weapons; #using scripts\shared\bots\_bot; #using scripts\shared\bots\_bot_combat; @@ -25,37 +25,12 @@ #using scripts\mp\bots\_bot_koth; #using scripts\mp\bots\_bot_loadout; #using scripts\mp\bots\_bot_sd; -#using scripts\mp\killstreaks\_killstreakrules; -#using scripts\mp\killstreaks\_killstreaks; -#using scripts\mp\killstreaks\_ai_tank; -#using scripts\mp\killstreaks\_airsupport; -#using scripts\mp\killstreaks\_combat_robot; -#using scripts\mp\killstreaks\_counteruav; -#using scripts\mp\killstreaks\_dart; -#using scripts\mp\killstreaks\_dogs; -#using scripts\mp\killstreaks\_drone_strike; -#using scripts\mp\killstreaks\_emp; -#using scripts\mp\killstreaks\_flak_drone; -#using scripts\mp\killstreaks\_helicopter; -#using scripts\mp\killstreaks\_helicopter_gunner; -#using scripts\mp\killstreaks\_killstreak_bundles; -#using scripts\mp\killstreaks\_killstreak_detect; -#using scripts\mp\killstreaks\_killstreak_hacking; -#using scripts\mp\killstreaks\_killstreakrules; -#using scripts\mp\killstreaks\_killstreaks; -#using scripts\mp\killstreaks\_microwave_turret; -#using scripts\mp\killstreaks\_planemortar; -#using scripts\mp\killstreaks\_qrdrone; -#using scripts\mp\killstreaks\_raps; -#using scripts\mp\killstreaks\_rcbomb; -#using scripts\mp\killstreaks\_remote_weapons; -#using scripts\mp\killstreaks\_remotemissile; -#using scripts\mp\killstreaks\_satellite; -#using scripts\mp\killstreaks\_sentinel; -#using scripts\mp\killstreaks\_supplydrop; -#using scripts\mp\killstreaks\_turret; -#using scripts\mp\killstreaks\_uav; +#using scripts\mp\killstreaks\_killstreakrules; +#using scripts\mp\killstreaks\_killstreaks; +#using scripts\mp\killstreaks\_uav; +#using scripts\mp\killstreaks\_satellite; +#using scripts\mp\killstreaks\_emp; #using scripts\mp\teams\_teams; #using scripts\mp\_util; @@ -66,13 +41,13 @@ #define MAX_ONLINE_PLAYERS 18 #define MAX_ONLINE_PLAYERS_PER_TEAM 6 -#define RESPAWN_DELAY 0 -#define RESPAWN_INTERVAL 0.2 - +#define RESPAWN_DELAY 0.1 +#define RESPAWN_INTERVAL 0.1 + #namespace bot; REGISTER_SYSTEM( "bot_mp", &__init__, undefined ) - + function __init__() { callback::on_start_gametype( &init ); @@ -94,6 +69,11 @@ function __init__() level.botIgnoreThreat = &bot_combat::bot_ignore_threat; level.enemyEmpActive = &emp::EnemyEmpActive; + +/# + level.botDevguiCmd = &bot_devgui_cmd; + level thread system_devgui_gadget_think(); +#/ } function init() @@ -101,12 +81,12 @@ function init() level endon( "game_ended" ); level.botSoak = is_bot_soak(); - - if( level.rankedmatch && level.botsoak || !init_bot_gametype() ) + + if ( ( level.rankedMatch && !level.botSoak ) || !init_bot_gametype() ) { return; } - + wait_for_host(); level thread populate_bots(); @@ -117,6 +97,9 @@ function init() function is_bot_soak() { +/* + return GetDvarInt( "sv_botsoak", 0 ); +*/ return IsDedicated() && GetDvarInt( "sv_botsoak", 0 ); } @@ -194,6 +177,31 @@ function on_bot_connect() function on_bot_spawned() { self.bot.goalTag = undefined; +/# + weapon = undefined; + + if ( GetDvarInt( "scr_botsHasPlayerWeapon" ) != 0 ) + { + player = util::getHostPlayer(); + weapon = player GetCurrentWeapon(); + } + + if ( GetDvarString( "devgui_bot_weapon", "" ) != "" ) + { + weapon = GetWeapon( GetDvarString( "devgui_bot_weapon" ) ); + } + + if ( isdefined( weapon ) && level.weaponNone != weapon ) + { + self weapons::detach_all_weapons(); + self TakeAllWeapons(); + self GiveWeapon( weapon ); + self SwitchToWeapon( weapon ); + self SetSpawnWeapon( weapon ); + + self teams::set_player_model( self.team, weapon ); + } +#/ } function on_bot_killed() @@ -233,7 +241,7 @@ function bot_idle() { return; } - + // TODO: Look for an enemy radar blip // TODO: Get points on navmesh and feed into the spawn system to see if an enemy is likely to spawn there self bot::navmesh_wander(); @@ -565,112 +573,15 @@ function use_killstreak() { case "killstreak_uav": case "killstreak_counteruav": - case "killstreak_remote_missile": - { - self switchtoweapon( weapon ); - self waittill( "weapon_change_complete" ); - wait 1.5; - self bot::press_attack_button(); - } - return; case "killstreak_satellite": case "killstreak_helicopter_player_gunner": - case "killstreak_ai_tank_drop": - self use_supply_drop( weapon ); - break; case "killstreak_raps": case "killstreak_sentinel": - { - self switchtoweapon(useweapon); - break; - } + self SwitchToWeapon( useWeapon ); + break; } } -function get_closest_enemy( origin, on_radar ) -{ - enemies = self get_enemies( on_radar ); - enemies = arraysort( enemies, origin ); - - if ( enemies.size ) - return enemies[0]; - - return undefined; -} - -function use_supply_drop( weapon ) -{ - if ( weapon == "inventory_supplydrop_mp" || weapon == "supplydrop_mp" ) - { - if ( gettime() - self.spawntime > 5000 ) - return; - } - - yaw = ( 0, self.angles[1], 0 ); - dir = anglestoforward( yaw ); - dir = vectornormalize( dir ); - drop_point = self.origin + vectorscale( dir, 384 ); - end = drop_point + vectorscale( ( 0, 0, 1 ), 2048.0 ); - - if ( !sighttracepassed( drop_point, end, 0, undefined ) ) - return; - - if ( !sighttracepassed( self.origin, end, 0, undefined ) ) - return; - - end = drop_point - vectorscale( ( 0, 0, 1 ), 32.0 ); - - if ( bullettracepassed( drop_point, end, 0, undefined ) ) - return; - - self addgoal( self.origin, 24, 4, "killstreak" ); - - if ( weapon == "missile_drone_mp" || weapon == "inventory_missile_drone_mp" ) - self lookat( drop_point + vectorscale( ( 0, 0, 1 ), 384.0 ) ); - else - self lookat( drop_point ); - - wait 0.5; - - if ( self getcurrentweapon() != weapon ) - { - self thread weapon_switch_failsafe(); - self switchtoweapon( weapon ); - - self waittill( "weapon_change_complete" ); - } - - use_item( weapon ); - self switchtoweapon( self.lastnonkillstreakweapon ); - self clearlookat(); - self cancelgoal( "killstreak" ); -} - -function use_item( weapon ) -{ - self bot::press_attack_button(); - wait 0.5; - - for ( i = 0; i < 10; i++ ) - { - if ( self getcurrentweapon() == weapon || self getcurrentweapon() == "none" ) - self bot::press_attack_button(); - else - return; - - wait 0.5; - } -} - -function weapon_switch_failsafe() -{ - self endon( "death" ); - self endon( "disconnect" ); - self endon( "weapon_change_complete" ); - wait 10; - self notify( "weapon_change_complete" ); -} - function has_radar() { @@ -706,6 +617,17 @@ function get_enemies( on_radar ) enemies = self GetEnemies(); +/# + for ( i = 0; i < enemies.size; i++ ) + { + if ( isplayer( enemies[i] ) && enemies[i] IsInMoveMode( "ufo", "noclip" ) ) + { + ArrayRemoveIndex( enemies, i ); + i--; + } + } +#/ + if ( on_radar && !self has_radar() ) { for ( i = 0; i < enemies.size; i++ ) @@ -786,69 +708,43 @@ function set_rank() function init_bot_gametype() { - switch(level.gametype) + switch( level.gameType ) { case "ball": - { bot_ball::init(); return true; - } case "conf": - { bot_conf::init(); return true; - } case "ctf": - { bot_ctf::init(); return true; - } case "dem": - { bot_dem::init(); return true; - } case "dm": - { return true; - } case "dom": - { bot_dom::init(); return true; - } case "escort": - { bot_escort::init(); return true; - } -/* case "infect": - { + case "infect": return true; - } -*/ case "gun": - { + case "gun": return true; - } case "koth": - { bot_koth::init(); return true; - } case "sd": - { bot_sd::init(); return true; - } case "clean": - { bot_clean::init(); return true; - } case "tdm": - { return true; - } } return false; @@ -892,6 +788,11 @@ function get_friends() return []; } +function get_closest_enemy( origin, someFlag ) +{ + return undefined; +} + function bot_vehicle_weapon_ammo( weaponName ) { return false; @@ -907,3 +808,146 @@ function dive_to_prone( exit_stance ) } +/# + +// Devgui +//======================================== + +function bot_devgui_cmd( cmd ) +{ + cmdTokens = strtok( cmd," "); + + if ( cmdTokens.size == 0 ) + { + return false; + } + + host = util::getHostPlayerForBots(); + team = get_host_team(); + + switch( cmdTokens[0] ) + { + case "spawn_enemy": + team = util::getotherteam(team); + case "spawn_friendly": + count = 1; + if ( cmdTokens.size > 1 ) + { + count = int( cmdTokens[1] ); + } + for( i = 0; i < count; i++ ) + { + add_bot( team ); + } + return true; + case "remove_enemy": + team = util::getotherteam(team); + case "remove_friendly": + remove_bots( undefined, team ); + return true; + case "fixed_spawn_enemy": + team = util::getotherteam(team); + case "fixed_spawn_friendly": + bot = add_bot_at_eye_trace( team ); + if ( isdefined( bot ) ) + { + bot thread fixed_spawn_override(); + } + return true; + + case "player_weapon": + players = GetPlayers(); + foreach( player in players ) + { + if ( !player util::is_bot() ) + { + continue; + } + + weapon = host GetCurrentWeapon(); + + player weapons::detach_all_weapons(); + player TakeAllWeapons(); + player GiveWeapon( weapon ); + player SwitchToWeapon( weapon ); + player SetSpawnWeapon( weapon ); + + player teams::set_player_model( player.team, weapon ); + } + return true; + } + + return false; +} + +function system_devgui_gadget_think() +{ + SetDvar( "devgui_bot_gadget", "" ); + + for ( ;; ) + { + wait( 1 ); + + gadget = GetDvarString( "devgui_bot_gadget" ); + + if ( gadget != "" ) + { + bot_turn_on_gadget( GetWeapon(gadget) ); + SetDvar( "devgui_bot_gadget", "" ); + } + } +} + +function bot_turn_on_gadget( gadget ) +{ + players = GetPlayers(); + + foreach( player in players ) + { + if ( !player util::is_bot() ) + { + continue; + } + + host = util::getHostPlayer(); + weapon = host GetCurrentWeapon(); + + if ( !isdefined( weapon ) || weapon == level.weaponNone || weapon == level.weaponNull ) + { + weapon = GetWeapon( "smg_standard" ); + } + + player weapons::detach_all_weapons(); + player TakeAllWeapons(); + player GiveWeapon( weapon ); + player SwitchToWeapon( weapon ); + player SetSpawnWeapon( weapon ); + + player teams::set_player_model( player.team, weapon ); + + player GiveWeapon( gadget ); + slot = player GadgetGetSlot( gadget ); + player GadgetPowerSet( slot, 100.0 ); + player BotPressButtonForGadget( gadget ); + } +} + + + +function fixed_spawn_override() +{ + self endon( "disconnect" ); + + spawnOrigin = self.origin; + spawnAngles = self.angles; + + while( 1 ) + { + self waittill( "spawned_player" ); + + self SetOrigin( spawnOrigin ); + self SetPlayerAngles( spawnAngles ); + } +} + +#/ From 5d2f5634cf2da9e3c04978c137f10879e5c2e09c Mon Sep 17 00:00:00 2001 From: WantedDV <122710241+WantedDV@users.noreply.github.com> Date: Thu, 20 Apr 2023 22:21:05 -0230 Subject: [PATCH 10/33] Using additional scripts --- data/scripts/mp/bots/_bot.gsc_raw | 35 +++++++++++++++++++++++++++---- 1 file changed, 31 insertions(+), 4 deletions(-) diff --git a/data/scripts/mp/bots/_bot.gsc_raw b/data/scripts/mp/bots/_bot.gsc_raw index 1ffddbf4..1b72b588 100644 --- a/data/scripts/mp/bots/_bot.gsc_raw +++ b/data/scripts/mp/bots/_bot.gsc_raw @@ -1,4 +1,5 @@ #using scripts\codescripts\struct; + #using scripts\shared\array_shared; #using scripts\shared\callbacks_shared; #using scripts\shared\killstreaks_shared; @@ -7,12 +8,14 @@ #using scripts\shared\system_shared; #using scripts\shared\util_shared; #using scripts\shared\weapons_shared; -#using scripts\shared\weapons\_weapons; + +#using scripts\shared\weapons\_weapons; #using scripts\shared\bots\_bot; #using scripts\shared\bots\_bot_combat; -#using scripts\shared\bots\bot_traversals; #using scripts\shared\bots\bot_buttons; +#using scripts\shared\bots\bot_traversals; + #using scripts\mp\bots\_bot_ball; #using scripts\mp\bots\_bot_clean; #using scripts\mp\bots\_bot_combat; @@ -26,11 +29,35 @@ #using scripts\mp\bots\_bot_loadout; #using scripts\mp\bots\_bot_sd; +#using scripts\mp\killstreaks\_ai_tank; +#using scripts\mp\killstreaks\_airsupport; +#using scripts\mp\killstreaks\_combat_robot; +#using scripts\mp\killstreaks\_counteruav; +#using scripts\mp\killstreaks\_dart; +#using scripts\mp\killstreaks\_dogs; +#using scripts\mp\killstreaks\_drone_strike; +#using scripts\mp\killstreaks\_emp; +#using scripts\mp\killstreaks\_flak_drone; +#using scripts\mp\killstreaks\_helicopter; +#using scripts\mp\killstreaks\_helicopter_gunner; +#using scripts\mp\killstreaks\_killstreak_bundles; +#using scripts\mp\killstreaks\_killstreak_detect; +#using scripts\mp\killstreaks\_killstreak_hacking; #using scripts\mp\killstreaks\_killstreakrules; #using scripts\mp\killstreaks\_killstreaks; -#using scripts\mp\killstreaks\_uav; +#using scripts\mp\killstreaks\_microwave_turret; +#using scripts\mp\killstreaks\_planemortar; +#using scripts\mp\killstreaks\_qrdrone; +#using scripts\mp\killstreaks\_raps; +#using scripts\mp\killstreaks\_rcbomb; +#using scripts\mp\killstreaks\_remote_weapons; +#using scripts\mp\killstreaks\_remotemissile; #using scripts\mp\killstreaks\_satellite; -#using scripts\mp\killstreaks\_emp; +#using scripts\mp\killstreaks\_sentinel; +#using scripts\mp\killstreaks\_supplydrop; +#using scripts\mp\killstreaks\_turret; +#using scripts\mp\killstreaks\_uav; + #using scripts\mp\teams\_teams; #using scripts\mp\_util; From 8d595ab150d263b453d97a10fc17647f5f205b01 Mon Sep 17 00:00:00 2001 From: WantedDV <122710241+WantedDV@users.noreply.github.com> Date: Thu, 20 Apr 2023 22:28:03 -0230 Subject: [PATCH 11/33] bot functions: use killstreak, items, drops --- data/scripts/mp/bots/_bot.gsc_raw | 134 ++++++++++++++++++++++++++++-- 1 file changed, 129 insertions(+), 5 deletions(-) diff --git a/data/scripts/mp/bots/_bot.gsc_raw b/data/scripts/mp/bots/_bot.gsc_raw index 1b72b588..68a07246 100644 --- a/data/scripts/mp/bots/_bot.gsc_raw +++ b/data/scripts/mp/bots/_bot.gsc_raw @@ -609,6 +609,135 @@ function use_killstreak() } } +function get_closest_enemy( origin, on_radar ) +{ + enemies = self get_enemies( on_radar ); + enemies = arraysort( enemies, origin ); + + if ( enemies.size ) + return enemies[0]; + + return undefined; +} + +function use_supply_drop( weapon ) +{ + if ( weapon == "inventory_supplydrop_mp" || weapon == "supplydrop_mp" ) + { + if ( gettime() - self.spawntime > 5000 ) + return; + } + + yaw = ( 0, self.angles[1], 0 ); + dir = anglestoforward( yaw ); + dir = vectornormalize( dir ); + drop_point = self.origin + vectorscale( dir, 384 ); + end = drop_point + vectorscale( ( 0, 0, 1 ), 2048.0 ); + + if ( !sighttracepassed( drop_point, end, 0, undefined ) ) + return; + + if ( !sighttracepassed( self.origin, end, 0, undefined ) ) + return; + + end = drop_point - vectorscale( ( 0, 0, 1 ), 32.0 ); + + if ( bullettracepassed( drop_point, end, 0, undefined ) ) + return; + + self addgoal( self.origin, 24, 4, "killstreak" ); + + if ( weapon == "missile_drone_mp" || weapon == "inventory_missile_drone_mp" ) + self lookat( drop_point + vectorscale( ( 0, 0, 1 ), 384.0 ) ); + else + self lookat( drop_point ); + + wait 0.5; + + if ( self getcurrentweapon() != weapon ) + { + self thread weapon_switch_failsafe(); + self switchtoweapon( weapon ); + + self waittill( "weapon_change_complete" ); + } + + use_item( weapon ); + self switchtoweapon( self.lastnonkillstreakweapon ); + self clearlookat(); + self cancelgoal( "killstreak" ); +} + +function use_item( weapon ) +{ + self bot::press_attack_button(); + wait 0.5; + + for ( i = 0; i < 10; i++ ) + { + if ( self getcurrentweapon() == weapon || self getcurrentweapon() == "none" ) + self bot::press_attack_button(); + else + return; + + wait 0.5; + } +} + +function killstreak_location( num, weapon ) +{ + enemies = get_enemies(); + + if ( !enemies.size ) + return; + + if ( !self switchtoweapon( weapon ) ) + return; + + self waittill( "weapon_change" ); + + self util::freeze_player_controls( true ); + wait_time = 1; + + while ( !isdefined( self.selectinglocation ) || self.selectinglocation == 0 ) + { + wait 0.05; + wait_time -= 0.05; + + if ( wait_time <= 0 ) + { + self util::freeze_player_controls( false ); + self switchtoweapon( self.lastnonkillstreakweapon ); + return; + } + } + + wait 2; + + for ( i = 0; i < num; i++ ) + { + enemies = get_enemies(); + + if ( enemies.size ) + { + enemy = randomInt( enemies ); + self notify( "confirm_location", enemy.origin, 0 ); + } + + wait 0.25; + } + + self util::freeze_player_controls( false ); +} + +function weapon_switch_failsafe() +{ + self endon( "death" ); + self endon( "disconnect" ); + self endon( "weapon_change_complete" ); + wait 10; + self notify( "weapon_change_complete" ); +} function has_radar() { @@ -815,11 +944,6 @@ function get_friends() return []; } -function get_closest_enemy( origin, someFlag ) -{ - return undefined; -} - function bot_vehicle_weapon_ammo( weaponName ) { return false; From ebd3998d756d05d0e03b1693dec152cdf39a6616 Mon Sep 17 00:00:00 2001 From: WantedDV <122710241+WantedDV@users.noreply.github.com> Date: Thu, 20 Apr 2023 23:57:23 -0230 Subject: [PATCH 12/33] Bot autoconnect - wait on host before spawning bots --- data/scripts/mp/bots/_bot.gsc_raw | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/data/scripts/mp/bots/_bot.gsc_raw b/data/scripts/mp/bots/_bot.gsc_raw index 68a07246..8ffc052c 100644 --- a/data/scripts/mp/bots/_bot.gsc_raw +++ b/data/scripts/mp/bots/_bot.gsc_raw @@ -108,8 +108,8 @@ function init() level endon( "game_ended" ); level.botSoak = is_bot_soak(); - - if ( ( level.rankedMatch && !level.botSoak ) || !init_bot_gametype() ) + + if( !init_bot_gametype() ) { return; } @@ -124,21 +124,13 @@ function init() function is_bot_soak() { -/* - return GetDvarInt( "sv_botsoak", 0 ); -*/ - return IsDedicated() && GetDvarInt( "sv_botsoak", 0 ); + return GetDvarInt( "sv_botsoak", 0 ); } function wait_for_host() { level endon( "game_ended" ); - if ( level.botSoak ) - { - return; - } - host = util::getHostPlayerForBots(); while ( !isdefined( host ) ) From d9d58875611aabd2271f868d70b135cabe8e9f7e Mon Sep 17 00:00:00 2001 From: WantedDV <122710241+WantedDV@users.noreply.github.com> Date: Thu, 20 Apr 2023 23:58:15 -0230 Subject: [PATCH 13/33] Fix Infected + support other modes --- data/scripts/mp/bots/_bot.gsc_raw | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/data/scripts/mp/bots/_bot.gsc_raw b/data/scripts/mp/bots/_bot.gsc_raw index 8ffc052c..3cd05509 100644 --- a/data/scripts/mp/bots/_bot.gsc_raw +++ b/data/scripts/mp/bots/_bot.gsc_raw @@ -108,7 +108,6 @@ function init() level endon( "game_ended" ); level.botSoak = is_bot_soak(); - if( !init_bot_gametype() ) { return; @@ -878,8 +877,8 @@ function init_bot_gametype() case "escort": bot_escort::init(); return true; - case "infect": - return true; + // case "infect": + // return true; case "gun": return true; case "koth": @@ -893,6 +892,12 @@ function init_bot_gametype() return true; case "tdm": return true; + case "sas": + return true; + case "prop": + return true; + case "sniperonly": + return true; } return false; From 26e6d0652391a8b2f1b9c5b39c3917934a149c47 Mon Sep 17 00:00:00 2001 From: WantedDV <122710241+WantedDV@users.noreply.github.com> Date: Thu, 20 Apr 2023 22:31:29 -0230 Subject: [PATCH 14/33] Allow bots to use remote missile + ai_tank - precache eventstring --- data/scripts/mp/bots/_bot.gsc_raw | 20 +++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/data/scripts/mp/bots/_bot.gsc_raw b/data/scripts/mp/bots/_bot.gsc_raw index 3cd05509..87170670 100644 --- a/data/scripts/mp/bots/_bot.gsc_raw +++ b/data/scripts/mp/bots/_bot.gsc_raw @@ -73,6 +73,9 @@ #namespace bot; +#precache( "eventstring", "mpl_killstreak_cruisemissile" ); +#precache( "eventstring", "mpl_killstreak_raps" ); + REGISTER_SYSTEM( "bot_mp", &__init__, undefined ) function __init__() @@ -595,8 +598,23 @@ function use_killstreak() case "killstreak_helicopter_player_gunner": case "killstreak_raps": case "killstreak_sentinel": + { self SwitchToWeapon( useWeapon ); - break; + break; + } + case "killstreak_ai_tank_drop": + { + self use_supply_drop( weapon ); + break; + } + case "killstreak_remote_missile": + { + self SwitchToWeapon( weapon ); + self waittill( "weapon_change_complete" ); + wait 1.5; + self bot::press_attack_button(); + return; + } } } From 79aec8ac5e596e4940981b6f08647b3236b57793 Mon Sep 17 00:00:00 2001 From: WantedDV <122710241+WantedDV@users.noreply.github.com> Date: Sat, 22 Apr 2023 19:03:35 -0230 Subject: [PATCH 15/33] bot_enableWallrun --- data/scripts/mp/bots/_bot.gsc_raw | 1 + 1 file changed, 1 insertion(+) diff --git a/data/scripts/mp/bots/_bot.gsc_raw b/data/scripts/mp/bots/_bot.gsc_raw index 87170670..0d1bb593 100644 --- a/data/scripts/mp/bots/_bot.gsc_raw +++ b/data/scripts/mp/bots/_bot.gsc_raw @@ -104,6 +104,7 @@ function __init__() level.botDevguiCmd = &bot_devgui_cmd; level thread system_devgui_gadget_think(); #/ + SetDvar( "bot_enableWallrun", 1 ); } function init() From d971fcff47f5b6ab89be78cad346459dcad42ba5 Mon Sep 17 00:00:00 2001 From: WantedDV <122710241+WantedDV@users.noreply.github.com> Date: Mon, 24 Apr 2023 16:33:23 -0230 Subject: [PATCH 16/33] update compiled script --- data/scripts/mp/bots/_bot.gsc | Bin 14624 -> 19044 bytes 1 file changed, 0 insertions(+), 0 deletions(-) diff --git a/data/scripts/mp/bots/_bot.gsc b/data/scripts/mp/bots/_bot.gsc index ae8a168e147f46df0acd22ee701ded9d4cc78e0b..ca508a4ff04db204cfbcf29bf04d1a046cc49a73 100644 GIT binary patch literal 19044 zcma)j30#!b`u}-{0RfRn?dmPlm)ZB78JJa#+(AV}L<9zgO$V6R1VN%qQ?oKNv$8Cg z$}B6>EK}ReTWV^yS+}xlW_7b}x4LSZ{=d&V^Tz1!`uqRp-wd#A!8Qaw&2ke#!io7Y*A|TyK*dJypyr69L7T9qTzl$W49xngX!4^jDAYjf=2itGjSZJ;ZH#L!i$yN&ZABvn ztPKBOmQhyOSYHwR?|kGdt7vU$LH++VKk-|df^Ahz&B1VQlKP1G&w9%$Fy4P=zKBy9 zt_n6>hIMh9F3#52P<@$PEtg@0s_OrHj!@%e7+7G9O}&G1Q3Gmk`0s_yX>6(e@0@UB zFx1$3nc|v5@tNY5pSdhpSJr|R^}q0&np-20OImtS5z*N#Yif*N1L)2riCP<4s+wAZ zZI`Vo6ufviF3KNjths3RFJ?A1HdK{iOV!P(x@_@P^^wc+s>8uKWg#l%vPo*I!gZC6 z5%l5zkff}pwV~mEN!idh=@oy*icoEl@z@E5Z=)Azt2KbFmm~pG*wn$ zQ(v~zO{l!3>VJr_ONTLgtq<3>;5KKluZtFf_^76; zDi$O{s45s@*VQ&QHdkF24mLNJjcphmtgm9d!&63Gi-VPoe~OPdYVRb(5qmc(t+BXNP$HMAjfV-u8tKj)Li`C`;tE{kQ1iW^GV zTf+ZfHIPK26Q4mNi8R(Vv@{E_9rH+sUL_q=l{k~=_zB@34x8Ay0tv*T$3=)mkHHos zXbv{Bh_K=s>LOJTc;V>8h3cxS>ndBrEwOowlvM?r|BN>@Hq{5k6;uWVC=^>wWo-~i zXdl7msuryGi={M?1>L|@(_G00^kM9`B*u;-yn^r`LKi|Yf&-x+!uN@cy@T*9!tDql zgy9H-5x$c$_Bz69ga(B12pWVmgs&19+mG-R!cv4Pgpmj`gj9s@B#ga_@DjpWghdGT z2vZT<2tyGP5We9U+lTNd!XkuvgggW@!a#(x&=o&HcoktS!i@-(2xAa(3h&K__ z@4Nov{moS~f3~Wk``cr;E+a;*JyNc~D4h4QqWo%2eRc5PlZc)p&)^HkmS<6%ew4p5 zN1wNOcIoScU)HcGa@UM;dllF0BfK%^ERAu7t2W~l{=%;rYyJmfL?P`n#WA~dqj;wncmc69;LLPFfn{($Zj1YZJ zPKoLHXU6n2TE}VJg(GUJMtz%3bg#)(uyb6WLw98kQ?+%s7Uk}c$%*a@L<&nEU3m3^ ztg$(rlSkVR9QfsFqIc!ASAT0wzp^;{H`hG1cS7Wk8IKb^U+d3uByFl5=DAvJ4mc&Mw|uOZ2Uo)Ab*(8hWNUJDtBGJK|%Sa*wP#xAC@$k#`gSDtkIF^K;rS zj9Qx>^MG-Uj48I)ys)x=nD`5P8GLnqq>AG7>&MTwd^UOWn>$?Z`O>8D) zUAgg;gZN!J72Y$)55L@FNavGetn$Z~_JxT4nNq?sFo!u>7OI>qn|g1>%hwTI<4@=7 zWY3#fN4wfQuf37qwe>NgZ_LTyD_o;g6sI4}{}9JNGks{|hXyvwJn+bPqMKEtyHn^;y)U{fY5)4SiZ z%a~SXK>K_AT^Nr$J#2=U?pGztZ1vw_d+$O9KQXUv4&|kvQ^R?MdRo(YLk=^D>9;!A zlo{rC4a{|qrof-69L%;jnP;-mtul4a=2!YNoO5f&pbyfl9p+@#=r2ILz@t?%uT3rS zmd&R$`@9oz8;kz>@gML;YoMeTpLIVy-yQlSr%L~yz$`1x#gCplczsT&=JrGD7C8Oy ztCHA%{1i7ha#=dRMLtf=EVZZKSV3i6jnO!$c~i^$dDS|jC#UCyeoqm-1LLdpzhY+N z-NRc7%=(*Otji>NUuy>ctuDW42HLqY&{02a$#1z<@0&TVY5KG6+W7{er|70xh;DbB zHngF}PjdQZvr)A-Oq*DpFV;I)f%V`VX<~)y;CQ_?_~W)=L#h0SlIo2lHT z=5+oI>+g0pv97qKEufI!;uH3{)sw+DyJq6%8~qK?OA7wr4jyL^OQ|Q`n8j4d*(Gk} zxjco@K56Jr5BKp`b03@51-Odqv4a+vG{~lMvTkwxRchYQJ>)Q<*IE~glozey=9W^) z1xl7b3~i`TvFauR)2v&+j|3vy?&s<^o6`A}zQVC29CxY9vxeiVRx*7aB-->nLmL6v zUf+yy#P80TC$pgRbUxEO9QdS{k(iq-rW>hZPLglKPQSkwY*we^Qj4`qy__=7`W&Cm zN_|daLXAJ%rsTTb(xe(zQ%n70HEfp0L2|B8x(OBl#;#ST^Y^GQ|0O08bFP)Y+;yJl zv@QxWxq>vyIVFRjOO>WBBD&j_&Uab4qSe_YJc|@|4&5;20MT#4yt%Tu$>%dM*Q4$2 zD?4}YCVB(XZ_4DVkND=PX^oe9H&~f>g8z!tKU~CLZ_D7bAOI;&zkYnXmezTiWtXom z%W9)_Zc$a~)70(uM;;os`3-BMdLAEEfAH+@k7@n)WvB7mRc{|W=v#vIeNkJt@2~LXBZ*R^OjZ-HsILIJ8>(9@rWU5)CPfMSCo&W)qwt8|J(~O(9 zUOweGgH&9%pwh%Dtyw+Xq9v@%;BeYMdyLJA?fp*Iulh*#VsE<6ph!0!l1Vga9;M}0t@MgjroK7XXFs8z zYE2zK%se1)M3&;N=T8~>4bLGO!zCn>x z^eO*9Ai1NS@AUMk-(yUg|BX9KmuR3JhDsDPTXPTNE67%G#p75d>^I^U{G z&d*bPYA#g&v{2J@ojy38z7Y+B)KX1&M;5YD`mH%q=UtgvrL<_HJk9%*`wHZrX=Pl3 zGP!kbV3JMChYy4_&+#^Pj8DGaXTQ(e*(K2IjV2mLr%tc>3){sfJIfunxT>cT?;Q)L zBpzo^kZm^Ymr3o@e0`NJeTREE+bB<{oviAQHTJ9wE5oMvcWFOrN0I3Pvy_d?UIflR zJ=k;MsKEPU$@)8q-(bV)RLp~v0!srdFI(rh0}NQrSkQw7W-{66vqLN{<@`1++SSUcy~k;cS1% zw<>2{Kr*EhYb9SLk&ksSXmx?c#BaKGQ9A~Cxsbxwqf8BMQfi!&oirDZS-H{U%<2iR zd8hk1JB#!L()k%W)_&gbsg0#7Nv-p|@!Z4PD1Wh>db!7y>UdUGWnrPu&fGte=o1zUJP-iI6frT+aFAjxHs zLh8pSTAY)lB(_)26Whyqv7aFqsV($N({u9Nkd1%2t17~*w)Pu)Zkx#L@=R*S zM*DDesV}TH@96*86|z#aWVowPt|_|(d+h=AS3IYV`z0==C7nNK%y6y%?`tQ6bj%wm z@}J7#rW60LpVRBL5>2z}1q*|!cze+|zfwEgwp(mol)lqp@jit7(0QOmYPDkigDz&P z=hOLJI1SbsFw&$%LJ+=wRDFT+Z#HM}RnQeFPQQ^ZX_wG1=#E0aAnPU$EH5MZW_s|O zy-emaQU8t@Pb*Ft5~lv|&g#3Y3G-wMgPwNZDFfH=A1xc<*u7>hl`}*xWhWd*KADn=* zkhGZ_rcqnI)G}y^g=(?BRVFS-+T1_v`Or35&)Rwdxk_n3saxtzP-OFU-l0rmmo~p` zI*fgCRCTS&gkHLgl9@A9tvW8pZchsgMK70YsLfb!1>W=}O;m4@kJXG&Ec6)Iewk!` znd-cUo4p^}07;$gT2%%00h(dAnEpE*i(KyNmQ`#|F#Z(bI+ zez$r0xP^X0`CR++TSu6ype<#SLq#%Gm^bK{BbL4XD1*54Jnmn^AT!rJ{`JcYdh0ZO zk{4@wf*%Ux>Soo=G@dF;Vy(l{qfE5EZL*rA%q&}>a_h&-rM4~JX}-kvOz3PqhBZ1a zd{fR=heTa(J@1id?$J18E0|X!DZ@O5u6L>|39eG(DTAaEIy@+~()k)oV&1qc$Sy5JZAi@5=}Cl+ zh+T*~IbFfUd>Vg>otyW9fyR=4f7d3o-`U5oilpe5PyhXCHcB?xAv)XG(na)=rG|UiWIx@5+&An>s5r4tjxb zK^NQgFP}Aw&d&F|KF9ih|J|QweahdT9kvr~o8^F>XfmsWZOqK^ZPU3?%68jZw|4#Q ztR9jcB3CSDi-Mb>@Rh5$%(iUeFV`CQHJ*uix&2OzpK4`wgWLmbY)+E(K1GE!mDa8I zD!HV!RC$$J%9hEe;{0fZ44!Y>hB-Xvn&SFy?i)wXXO3}g*KnRa7So^dXO}-^?yili zej$DM!_;S!8RV~UuY~;VlQi#RW)0Omd)v7647x8f8rCt~zF#u=M={9S6Zd|8JHxg6 zkyD@TVg;?<&f%l4eqX-VN#{+e7k4$YK3}x+1Orhy@RNFsoE3G{7tg#;xTkMXB+sY& zrq&NV1akKup^tx~@!sm_GwQVOlp(oxU#9d1sTu2J+F|PnZ{oy8tHGRDeKv5TaVs+@ z67xGf(!!&LUzJJf9>Xp^F*r>x9j~`PYD&;2s?zy#Rgx8Uk>K%jyJb{vl1`#3)Q6D|-2>)y*6B%7_GEFjt^SuY(^+9=f=y>j3>Rx}vE^QX ztebc?pz=jW1DazUPH^1x=gz(QVag9V8`x}`=3|PNG8Y5W3B@&kqFa>7aQiQ)5$~%@ z%{%m4!2KyRY5pf#j2#&#agU$y({SM)eyuvmbO-nYY)Sb)sr!2vY?Ne|6!TxJ-mES> znzTadJ?co~--5mJmB1m$*fdM3lWz1!?i=(jwa1P7ZMH-1N+y8c(hC;^y(kp>mc+hO zV_%V<8^hk%*MV;aKSS8tRL-}mgaGN13`T+LQXjg4O?HlM9@JUICXmeKB7zMBa(rF; z&%(U@?qklKa>z`d#JJeYy1s~60=_<``i07?(=qjJInZ627n_Uaa3FB(F+y_77V!^c zmm5uPN<+VGp2R|7eZyAJUDn`X1#R8B3v4%QEs8ABUt7cqJ14hX^?L#vy~ilEk8pIN z<3mhGlxgggLE0X$+zoueI7B{}E%EoYSI@ihvr*^uyw$jPz-fKHiDva(XJ0R;{v^vg z;g6r6pZ%@p1AYs?L7w2JRSumf>!h4?V)33(r;}K#aTdJjm)O8*SFZ0kL+w21lGuy2 zxx&5StLz>Q8d~_f%t8FCK2F{0-(%!7|Dt>U^)Gew>FPy0<=`^Qi**j0>7i zC8Vlve95A(sJx`u{d}6@tYK{y3-8Fx8%g62O;4~Si0Qm)>ca&OCp&3Dwvl$3q`SZW ztPUqg?rqSszgM0!wkcU7^hxaj9n*SWZNGuaAInEqw9jXYJc2Qr<(H0G%?~c#r?uBm zJ&Rp8`5E-;wXgnkh|&*Mtj&^EZB#yqw8i{kSsI(6lg?b}+YLO8-{?1B?cS;8=G>+- zc42K^r;|%Ym1^5fYT5~T+KK_&A6-x7xNS)}q_aTd^>T_KDpo0&X*)#zBaR62CdZfNZ@Z4x+A##`&@KBkY(1e@Xm!)zS^74Cn%*I|MXywW&1SZ z{;_(_TB7^s%|IGYGbJ`iBWL2ll_JPGF1ob8UZKp4G$!;0JV zcyU~yJ-Uw>UN!OHoHsyz2-em7B9XsR)=_^9Z9Hb!DkGVBkLnR6Y$?;k`mUC_gcWzj zZW%@OcG*ADvfA0Mnbt*+12;^gw$tyhDQV*LK^+WhBf2kPW)VWwbtLx!T`a zdF7|79xKh+7g|pFGTHN>Yv1#IIFZ`Z*Sg%nP5f0UsavYLR$knqip(t9>;8wvmX*em zWo-e%c{#@nGH-}|}?q`dPYW(c8ir*_|rR^AG^$hmc z-}FThqPhKg9bV4_%R;miD(6ux*$9qW$X0#3h0a}^=he#h1|Oj`iX75TbA|I5@^0Sq z)5iZm^hG?4uiCqJFjGTEn;@p2ZKw2Sv_yye@{8#QxX6lYC0QZ-$j%wILT0toD^^+P zxhX$vB*r$Kls%;N$n`m{%JVlCOqyU!&cXfOO!4)2TY&DU!%p!1`qo+@y+fT~=E5%F z45R#C+7t4G^KRsHy|B(<#TC}K40?R`N#${CGW0izMv{93meVbA>^xX2Y>}selLh?( zdc~Nfs(^Jh>$aWnvf?8OywljXIJug8WsgIS^`HefAFDNXF5m9JjVY#AKf2=IRaAeO zl_cvJ*>uD|^5q=JMY4`RoVulz+QE%X*}bR{eJ+^<$!))uE?zV9kYHm_(~s z&N{%Utwo+|7!WlAG(m@;cCnp8Uy<6Q>S``dmd!(A@46onLbc5=BFpGW3#NG z#h;AUcxBNDpSh*(>_biL2I&MK~|C{JJ4rZqROH?=t{Dj_MLRX3OuUQov%u)z2Hf?;ce67 zfqm9pn7PDh8hgsbhOAQWSDAlTO4)Ab8oX~+=YI;>jQe6?n>R(h$^5E!x;8kT-keIb zX9Mdr?HG%V&O|+LNU`3R2}v338!Z2f`gz!6VY6~n6Da={XQH#yoKiH{I?uDr;%%k; zKbl*0eXeJo{iZ&hTLTNSI$%Ng!r0}c^cAYaYNVfPlxZB*B zc5>Ec(=lD5ZHML&zvIGUZ&J9#F~{AX-DOLic*>AeH%*qLODeuwHv%hvqcf=m`?JlE zc3hZ)EedJi>6|WWA4R8gp(UwVsT*gn%uaNTfFvwsClu0|Soe;^oQJa$3$zASGw;6p z=y9KY;2bYcn15F$>}jUs54`yEPTNnJ3A5Eo7FCz?D+b>!*u@7ZB-IYfM(jMaw|+{N zM3YpQs^2M}>Rk$%H{69?Ja(GCPx-rsq%25X{kw-fB$#kzHyTxgC|1LAcG8*_{0^dffaB3=&qPzlBqQE3-h0LC^6LCer_-1l`wx5rf7G`>#m9%8qx{ z=_xsj9h{zS?vVAuyO_woT88sH_XWJ_V>LmNiuAD-cn{cCsK%MO$OLd95d_Px$mhKG zD!6=VAI(SAOp(6c_Gy5da{%*(*L>J3MEXsNZ;f2u0Uo)uXLQ$@xr#;nT{h0!tcj?& z$};6^*`dlSqC>-eI3K-3y%4(_or~e*7#=0olPrukfX6Ux9ykJ~c!=^ey#sH6T66sO;6yff_l zm#>{{C&GOa`m}4#_2*dLPDg>K*Y9Cbc7j((2eB`tgX|a5b#BbuZk-#axBRNRR^}~> zmJWTK=jP|m-0%gPcv7ti=mR4Cj9XG7lmq!Myd%~Oacs9*{(S#vbaHt;Dbs?iI)f*} zw3x5k-*3En%JNsqZj#yPKEmL$AoyeC7j=+sL)K@R?w%Gl%`!?jPvDLq*b!lEj@lX3 zLE*h0&IrFNrrg6|WOf(-Je0u;VRGQf0c5if?zde5-_;4}{0N7$x)hb)rcIlQxs~z5 zj(B;JA-)!3B>Z`2weX4lgKM(JKuPKH=BZPJhefUqmket+srAA@b2@VO+b_Bg( zT_8nK&o>!)L*M3V^KNe#6G^fq#f8~|p`tzO9pU{YNtaU7>WB24zb=qGdxrV2p|5I6 z7T)$M9?IV6C)+gkVfTJn-$+9i?9=6TWbjIM`dO@p?2bT{g%oRd2OybS8MomgP6X zUg)2J*=zGkvvAYUi|2VkmXvwaJJFs!#?%O2V4>rZN-N&uuwONFPIXzOWw+T`Nc5{9 zKMAi!>RRrNzPE{f729w>g_ULcrc9|G+MP!9s~|rKSlP=D`=uV-BW2<}<}JupSoyng z+t0=AyixS4cm(gNpli`y?cBgrEv@~lVC9DAi{Qs4`d3_K*DAT{I$c8k7H^03=kw>S zTx1b{j{#;);WsrVJ7>qf8)Dz{e?(Q zO3qvsp`6DZ>opTlE?ElLD0q`a%?ur){|j^qSQp04yYj<6f}Xz=EATr-!w70ap zbs&vZtbb$94t-bLJA_k{k|nesa!`;Hkb{DpfN^2eiz)4-@1B0~gC%57sOf(AL-K=M2()eQS8-YZ3VWxEW;Ouw22`!|BeV+;M2NN@k z>yuYV*{eA>!+!xMFmz+l4+%H$j-{~Q;$^WOUJvud_3E{7h9im^3pdT_AL9NrGYvX0 zXE`qT3jLy=2sdhuqPnnb&~#b8iEKlUxodAYj`73G!!&WcSJ=6U#dyzy&qXzE z-}&OY4@1MKP$d<@+9No8iR=C*>@B?C2iNG5RMxqz_vFU~ z8%nD|n{+*_Je}gYCwr31$aST7lAN2AlWer^H)SSOW6!`^p{y0x{d(-D?=zEadt6Cj zygpA9>vN-AjXk-}WlSoD7S^(3=D;>|4et}Ijrvoq3Md$Rb0k(?GurBUS{3z>n6zf= z!<3Hpqd}28`gW`$jAi^t$!7a#cdNNuL{+7xUGI-CcM&Vqz zinL`vPuh77H1g{dX{QFh|IhM%jL}&q(o$-!S@b4oA6egjMWnG;G_qr$k&muOEBW+n zss@T4`R9tXkM3}IUddpLd~-$G=QaP_Fy>15#ln9}r2VUH@s@`{BVS#Swzuohg>#^h zpB2$aZ+hh3DNkqPRf2p%MB1}iX&G;VMt-Pb-sA^fz476{!224$5JV$g>%giTs(u)R z_Z9dZh_r3B;}88Xm@#_uCK@@~oc&>4-7|lMmp1$$h(`5>EY;sXb2W4@_z;M+&M&OV zlZG%x{%S-+GS>b1m(N5X#RAhxPl>dIY5g<59tL}@d)We_QCn^tH*7#T<T~h~>@R zZ9QXwCkok7MVfl%gyJ7SyYA*+)`@u)l4R~pCEm1QrzINIyJ?v^k^%1=vNedb{Kvn_ zUJM%f4~eud*RLx195k|-5smuxO3hK(YTPu*?^8_oN$QZ!H*upOUtp1D)U1E5*2oz7 zYm2lO-_aOho??=N4Nnk_bXnaCNf(MhbN2V`7HKUDm%DpFOWgSF$6{VH>wj=LXt&?} z>s>^nwpjlX?06isF14|eXf#%9Uc6WKCTI6e-0Y?OpCPKE3f;p9hwaJ zNfQlO8J{B!X4@H~vqemIq4@Z7t6@{60US4O*7LyPn1P@57sv!U zYop^Ok!8op4e({vz~Z_fd`p}RA-oz`+>5}fA63hDpm~`yPSHE~O_>y$Uk$CLA z1c!mewTbkKv~=k3@PSVJXt@GdIuw|EjYaGPj!)kWOuow^f7K=Vw_K8cA29hOi|Ky` z7WX*Sp9C4#+aJzW0!(LjtUvvmfa%PRtvAOqVA73Z{kJ`H5$0^ifaz=|zJzhMuYpV8 z*-qy&y-%agfkPof={y$8bOO`47{#2U0GQ5S5znUd@Z%Nn&A@cNDtp#{#WBgib-?j` zIu9($W7MZqLGF@2Y^*+M`^9ot@hC9)xr+SPfXTmA#2)~Yzi1RoWUKo#Mt++yzGCPA z{DlnsGDZF*VDgU?`JVujKV%F`&j5>ZjOJkAK*q@LG0Nu@CSbDf6UG?IRs%l+*-USZ zu{5$5KqH?$G0z#`-gAUg4#XKkJ|3}sBW(hXPyZ-z@4QQ7Qk*aGn2$SeFviM}m+;Gh zd(RY3*$ph7MMy6@4NN+x*xn4BRU)Q7S%9-~R`s4ioU8=2c)SQ$Jj)=vWJlx5fUJ@Y zLH>At53pDV@gKhgzX?qDOtDQRI2YsbGT`3)Om^%dK9ez=nIa#uTs8!FBtmZ)Ojdi* zxys2_0+UaWSmzJG@$<6gn%=plHlF|{9~d$HnM?SCu@2(-P>dP*wut+CF|fFHsJvf+ zCHJ-o&v6r7hykeoIF&N z0*kr}ho*D`$M^4k;9ebwlkK{M{{b+)8At15itmBxjaaNd9r{xI_>2OMufOXOyy}wl zJBi<`AITKBRm8V%95B88MddvwZMp=1d`bERyTOnFc z3g~O}R=4K2dYlEE#0wnHpLz*D3`}o!;`rPFEb4_AZ^d3eB>8&V+Z4Uv*mv`u5zKn-18JAvG4J^t4)Gs>?On2bec`0qtVm;ukW5Ei~ zht$6`9p2vXh7qezmJ3X86;XbIq#BssAfkM!Yy)t7{$0TI)(}lEk-!g<(VIdPOC=IL z^dr0}MDug93}AW-ptmZjzZ#fq{xQB{B{13gqkJZP6qxkEA6DPF1pSeG9K(}uW^Tei z#&EgP*ho0l5KaGWWYp_~Wifo!E!UP29v;KD^*#12;bM`0ChR2K9>XivUVA&?6)}8h z!GyaBKLH$n4)s7sC!6t7{Wkour$jQ)1bqy)&)9g{O3WAOTm5ea7Vmo~&$b$vY<{uz z-TyVN`d2bCD`IF(v_A2$LmT@0>|xV$6iVwrz?E|9Iq=e+$rMpVcTlpUVV|rR-4_k(a zVJl+v_rsWL_GBu~=2#r=+l>BJl<3D0Cm&r2;$fWUYj6i3Kkh`}H0U&gp_gnxD1yH6 zIC%88g$dx*LRbGBVG=@9tgL1IaleYiS0YY-XF+u^=vymd@ga!Q-$)R>1aa~Kmm=;! z9q^Z6i&2jO^^#vOrCEkHZHvVx;rt()9Hp4Uwb z{2bz3EDeJkN{q#m5l@cAGZ0UU#RnrkAQtBl9~6sg5I4r+7R0r&csAlgV)5aK+hXxC zh%009Nr=;Xp3r{8>Fti7*MUPtkRh|{|p#WNr`HTZHE;G!$A z{t!<@d@th5u&3Wc$iUv*06ZK#33%@z{v^WmSiV{{?me-11o6^Xe5x5bZY*v zrkPq=W?E+YdX>G@+_IjPsn1L^d$wq1W%)m6m|r0Oc>n)=xcu(-oVzdQo^$SPPoFrd zPcj*@>2%4;_9Q}Huo6<5-0`Iyganm@6ln;-I0ha~NF}7x6De6rI(~M-Ar0mA)zQWV zU3nxJV&e^s^-blCf3g~?0`;MwE>K?|X!Uo1?!59qI9wJeuW9IkUsD|pL#d%ak11*c zja5Blt`F4J^uTIpZDj3BXvEsHqO=gKg*#hQBNVlaw_zHbN8s#?O+6IX5bT<% z%ktCtJ3)O@ICRSZcd}r9yMP|c3RL?WVRil&etknzG}^7#T}sx)SBk$r(sez-&~!`G zRM!})ZwfT`SXD4^>(JhkKNzX(xue1QNL|Pe+q1eR)MN3X+Gvlwig2LDA1kHDBvqks zb$KKTefWPQ@mDt0)%};0on3=nQWyOHO`<;-Y7BLeYTbvpOQBUD$*Surdu(ZKb$NYc zD(ql?V^e*7=$0keSqvi_%5)d!+IPhEX^8Eonv8(I&QH-`R~ z80+5kj%2mf4Gq=do>xFapfMBblS^lIfQ5z`YP|h5q)umi~_s?Y09N zLxEZt=h&y~DELwK6BMJkY@1P5H$(!kPouB|0*#S+0s^!eHa{j|1xYy^bN(pIeV~%< zqrVQuZz@b+Rcl9SftC@S8EXNxRCg2t@wEC-hy;)j35E>N@G&K0f)};q( zL!@&s{MeB$usrhT2Jb?R&mTK8T{xYS(S_K#$#CVhhU(dk)Fn+^V&Qg;c5OgxnRQ9m zz|LiLT{A=@^>Fn6IeW2Dy#;mVB=OdE2n0;oS;GHf)q&(8c)kATC z5f?j_%HagU!zKuSaJ0lv5s(q2<8TO)jzg~z65xCWt1Bw1%bUWD@i~k7LxF}r<8_hx z+5o#Y{Gi$dI!W|HP1~u>` zgtsBAhHyWGatLD}u)jXEfIg|WJ5IU{7QfnDaOuRu3z7G-SU6q+V{lkZvZ`y`O%;J3 z?m>Dh-IrERw7D>jKg_?=qHWterQ{vNUt7u4O1FQ;yOP2C5YHE@B;!@Sq6W=@eu$4- ziw(ukJpH#L_Q&X8rQW;uu5p)QMWK+ z_|7=Iae^+jW=<68PwQ0KJ6;~senc|amET%BBb0VYfb`W`^`u=Hy$)@050dNCs_skO zDH0?7N9UyRCC|?pG+(;KT#=n8J84oxyk=KuKSz96O#x?iF>q%X`y zy_95E$e%3RI|}Jz^#b~cdy|ON=8Y}2sIutY+cqG5JJXk*D7F<~9Dg{E3N^`C&ME&C zaiU`g)Uiqt@%kbvSO-vQFpy(S*WGbs9P<54X0#=l0js3rx7kif|{zlRilrMKJWCoIt)Fl6a z?lVs`ZwkHCyVTQ`V}<^-DOYO}$zu6%h+k7SyGgoH^*v*1!8ErEE2gpa^r1hY@3zU@ zomgqwI>Q+}CizNq%AV=PzG|GWYYv+%sz(m3o&BOlCQTqxH^x^eQeh0garqS_TJ`OF zOR$W!Y5~nNE-;ZQgR#XFmbJg$=Ov`i_6TU1vPMJX{-CYg6Mo>0Y9Z1MuD{g!&k)u^JS{m8o>c`4EdGA$geKQ$rl)0fZO;?ZF=C=9bC(CpbJ+IG_G~jz zqI5mh+eeeziuKwgj|l~Iir(WTEfJ$-GnVVr322q?At90JrnN-MY~lw!vHd(t(w9z? z7N=tx{Pm$1xr?04^^MGM(>-@zS<{zxhn1~%PX`zI)jAyS3+{B~TZ}vd$Gcjz+53}k zTHUj&hHc*KKH$7=8^L_?%8d;cx6GPCuNM|-1@sK{E-NWFSlD`Vq=}@_=U2Z~H1ovH z_H5+r7cq{% zWro{Sx#MRaB-tPp|EMV^wKLS;@?P9QCh5~2>=(F9s_vV#V0lgo8DEk8oOt4Ck|ztS zon5Xa<5Ymgkz0cqyw4ZelMn(sa?x$q5X8r?Q+4 zBqryWVf0hj-V#}#DO%kYt3Ybg2+Dr2Y>}kQY*!C;@NUcZ^o|bG9aS!tC70IHm7ZnV zr2NN(1Y>%W@~p~Z`bViUX|J)VOhV~L-j^JS7DnIS z*h^)zCuF^(`&GoBI6@+zEA@$D*dMln3|}M|n7CHaj_pX$^T-?G;go>3*%Nb&vSAWy z`jt8I`XipqD1PBwLvg1$Dhe7feX@`@y+qT_@QNpSQd|cW17tih#!09oW1@M#@+psk z4j))4pDHyHwIVT?qe(YAWk|cI^J{S&pO80t?j-BQi48{8GHa0*c}CSjJ@S-BuJbM@ zl%2O<)O&4WXa*RD|T$YjGqz_GZW(UJ+xGn?|G zdB4wlZV~dgGq5__4$uPnnB-#_$@%&I0?~+ z$lvR&)AC5rsU>st$=;RnrzC@zWHLa^vmEv$shk>(@(w_W(He7d)mF!0HP4XmNis6} z{UUzL25T?VBFT7j)gPCI$>EKfv>%|(ZG>&%6T9! z@`N0Z!bZYbBkxu5FHYZ${0R&t-=;5>CYR=DEKZjQ=i<7WnmN}jOMPB>hw-AAL>9mq zH_1a3S7fl~LFS=|d+*gX+cE!08TJy|QSpRyppRsqy7u%)q>t5$yj0ZB^mk2gq3A;z z{vNVZ(_{M~ZL@6N!;AX8XLyt@wq+^a(mWfwYJJ8f7L~bi-xK>v*;xrG&z1FO?tmJe zkdBoTkdxzL(jE|M? zEinnnwio4NnJq0gHrSr8Ox)tiopS;t-5tL3u~3wNaJ;{L!Fb~NT#xPex9tVPJwADc zZfCz!t2HIil8E~o;k3GX*lP|28Nr^{%d{M(&@P}4ss1Br2VPW;($TMG`TK;FxeYWC zn}#abW8(-%X&>|w5R8xHU;Gu@F<-ph>W0$S3;W9!cH{@GP(6{&f7DHEW|)U;DRG^2 z-KQqnwwNCH&N10d%-`G4mqtAhbSZ` zVO6bX@QjCbr$UjqI<>D4(;X2}GqArxoqE!8;D4ncs4h-o`P&?1{AfFup(^TJsSG#! zb7jbjyKjSm$^%&-GrzTRDwY#8^2lD{{F@6DBv3C&a&g9OmAoez2q|qEq5`c6bjnPS zrEL1=%+TW#Tvp2a+-Pa*I5NZT?!UA&wclg-Xa z|4>_QaWW}D;h6No{UWO68%>?|Zs?^@hi!(nQsEZNtH*jTYsj<`&0AJA*{J8pzE*&2 zaxd2|iOJS?J(*tY1I(O-P5-NisE&FHlq7nNDb-ZP&JrxAQpqvK_BAMlqc1)oCbAt8 zT>mFs7Im|mk`L2%ta(^_F$Iwwj}2B59;SoxvUX|CN~n=f+4dRC&{9ZuuS#C(V(Sg- zGlV$y9#{u^HtIFK>`Ofa9q&^21u)0tH_=S4T^DWQcj7W`pok1+R6C;tem~{wqUy z3Kbjml-!_R?&D+}v45oIOv}`46D=W4N>1G*6*c0RdYP8X)Y7od%d@4FVW^xk5zAx3 zMKZ2GUq4uVdB>hJLaW-0_QWhXY5-hs8d2-G1@*qC+`{q5FIHw%KLh+X9-hBizK$U?P|6k?RO{Pfa^k4!Sud^!0o~5^xLaddZM+WQuM2>pKm2#bDw(s;(4Mj z@u00EHNQ$Hkndvg)fyg2_4z?#J*k*%M$NP8zN-g+-h<_Q>EKK{B3Y^AjOQvU#Rm^hfB$b58G|}3Th3w`WgTr#a#8sW8ssZIS(48@?xxf}XUFxGkfb|CgHvVKo-cMwTwCqhS zEEkZqXP-Rt2+7Z`c=r6M-9-L{r)_xppgG1(ay)OoaT%p(yR-g;RdM@(k~G)|81#jc zpNiRu`JTkAS_9gU`<(>j?!SYd{f6yY?(0=x*8ky3%-H7O`L;T;rM$=oo()!ha6ZUy ze!y)=R&OJ7-Ta*C2A;KDYxgCjOFZxS_?b34FZz;hgO%HYdc%BoLNdr==JfTqL|E== zFUMM-Q|mYyu2bs4Gq40CV8ZlfrdM&5nwFw$xFSq&9g}Pl6Ohxrdp$h>^9^yP_;}=P zhaULzz~)DL`wcIrXt{lsmuQ`Nul!@~P)xUv7Qk#IjM!$TD%;g>8wI4D;o2-p{sg{s zp(FL?VGq^3Ss{p9a(gtKnMNxC#dqq|L2EF7jhW<)kd#SD+d_FeU;({fl#sJUJWor~ zQPsVB-NXZ!&h8bP^NuAfIVL%8Oreua;O+CxiH+kv4FP@l$WwQHgz3=E6410d!MoQz zL`p1~SB6KBzMYxls({kl8A`=7g7p{eFzng#<*-WA$OdI1CWhbZH*d!Dp>X{BLj1cc z{>_bl7stPA<6k#?`_eLbM=3BqAcIhcB;YL=mAvXU;t6Lp+|?E$BLy@_wR_()$aDk_ zfVC}GWAnAdL|n5iF|9&0NkwLYW)gD{e0@Ut3ziA|C{K6OMaJxxA9f{^XGQG{Dg03< zH#{S~Q)Q}T>-}88uZXSd>}Y7Fzs^NKcUImc;P*+(nx`6?kN$$j0XMj$e7}en>}#!t zj^8U(8W&!?&Uga7{+?Jp>eN@{xC`WD2uR%#~Hh1hm}5)xo(0vY)jNN@Sd}BVb$X7jbL{lq8LLuJszWb(@(Z zEwl?`_QFD4J9S>oDL$`jG@o-(>02Gm4CP*cI`(Lfm=kW$6-Zw55+#n$i_9toNP*S| z#FYJCYT_AJ^w0$?@8$TulUSb>H8Vs$SDi5p#~*ahx)Dsdflb%3BFCF3O9uKdMwaL~ z{%i87TF|4^sApN7=VXUH#C%>&6@acKbidtlAC}Mh$QH}TXDxy;`ohPno@*Xh^NP>i zg!NpJJtt38rEbgL$#T; zQ(^A@KI)L1<6b5;yB>9c?+N@9{a<_jIV@+W%oOwVfrhDiSiIIqI@}TZPQDoX;hP73 zqHkOoG6H7@dLY(5w{HyQSL=A=Oqyf`+6J$Pz@OqoZ-gpaJ!jDzN9ertV+rmEY z_zf0unAmy-r|phw_kKXeqdyFGcr^%cklpP5m$`3KLk=H@`B}}86B|zl`(tvkH`(#N zc%LB*z273XYRCk3Tvmc!U8yM2(7?GOyI~?TK;VO{XZapae)c|S<4w&?H_FO~#n9FY zc`aL?)41J=yP?gVHx}#NYPsPdr9Ss{!$TkkEUI|(!9P}SL_778DWv*bpEa?=H~Fn( z8ZEZr_^N#KnSeRDpao9j_f;7_q-~I>lznM%et_QHSE$CCX*c?J}9; z1CL-DVa&=cu_7IGi0F<<idvH29Y|!LeK2hLd%*e?&~w#Dhk3QK>4%Cm z(~CiI$GrGMzw=c|geFcIXztFuS0{eI9_c%EJhIC?RCJGTMCBj%Pq;^FE(ZJWHwDHQ z(H$ovSnal7KUf`0zsXkYr6#E4m=}MCwcO^ITm)}OOfE+A+G6vY1A1P%Rr#$tkqpqm zDQ3b`^NI{+Jmvs-DUcI8e@=U;%w6K?299@?8hdiV4VsKa6=m!DLB2wcD@m0Z z{1e0=H&MpHiq-TA-9prVTlyO*Q=%(Na%q6B;}`#QMBp!(#yi6;zjaVOu)Ar z&IW$^Mq!eBqv(+Hf>3SdktM2?WVSY}JOFzn$;fZLB22P-j7Rkzvqz3T=h4;#!%cS! zj75`@pE2K^H0@LQC@-n&9Vk78<5?)ylUC~p2J>?nez{7KWLTnj+x@=8;>Y~^VZM5) zGb~DDFY{i@XuC_MCNC%ogqXg+kw5+;by5~(&)5I1t**iJ1HtM^a9^~XP$o2OaLl%x zb@SCO<5{!$<|I|Z#M|_4SwE7YOSaiG39cV(QhkCpS;YtcC+I|NuwSOCQ%=X$<^+aU zY1VHr^m0Gv1f9y?=FauXEc_WinUW19q(I37`Lmqns|;4Y5AqdFd+I5?!Xv#D`5tcZ zw{U{|Lw9<`8&_YKmPxq=xHrN}G!V&U10RpgF`S2*1^O*kj;m6i;8^0RRwj%qloZ+@ zmCgsx(P~3MXLs+suhN^w)l+NmTu$AlYntElMiCL?fV2 z&{V5hmsksPJwpu|{oN(kWB$2c8B&G5I{|HXV!Ku|SA^uguQb#o(8oYv_f}ts`LCf& zRPR-5T5Eb^eeD*Gp+qxFeFVn)XHP(iV{CAz85=|ba!#LV{qW#H&#RWfs*^CjocvEU zI4@Tf?j}sP!EqOOZmz32qhW+Vwxc|seN{aS%iRDv`Dc)p?=*%n?NB3Xub`)nZ}EXf zRQ*Kh(pdf5K^`7*eqlsC9mKqC$HzBf`kWK=JakZFS@`QiuQyLUzpuGUGGht~yx46M zNOJbR)8P8TM@9F5#{#5fX?`|KpQQu)sX`921@@@CHjkyRRYUr*Ltw-}0|Wh?rMJ>> zuac!P>~&ESm%u!LbqBX|89tW(6SLS%Mg9f(pgfS=EZrf_a8cGx&gC?f{s3r5z>QtZ zvHaN{@N-(v!g#^Vf#_xFgG6J!lq(Z%qaX+9=PZ4eZj_FanZeql8aCM+#+2A7!280u z9(pkTO^JVp#J}qJ7xh%k;*5VY|R48+R}T-C1cJS}Js#PoEy?X%U4zD~k76dT>0 zdi+c;*B?sa!w#G#1& zmKivaSUKRkiQUUYXBusyF@-E2?rBZ!Ns|JkvM+t0k7IvTG9iH{-qyr?EYRsW3pZVQ z0ciLRAV!0XD^|4`&cLq0HNw&^nvzCDVR7JnHA`zgb$#K>K*PIdmUdcwU;_;|6^V|7 z9V{(nL;n?Xf%d84v7J#L_H|b1P;%$WBI{=n; z@$;JExj@4^JeIa)ap=?;py9g!mUiLx88hvD3BkKIq~Tm2efPy*TKW@$_W~^KA;Xtz z6Yqd`wQyI?=2duKdE*Sw&>xO8Tpy#0o)GBo1lb9`XO{L@?Wtkws#c&W?v=9 z^!1lMWAjcks55DxJ@WXkk0A}m^z@;hKeYpGx=d4!G#r;X+%tpnfmXNSWhI-AUE7dH z7)>Sw-?q$mJ->${JkDIe>^evOi-7Shi~Qejent_B^EzO*56IsSm|e4o&jM!GE8<@P zvuhP`KiEg?nnbJwjBiv{r+iWbm>LNf-=?s*5HP+;VR1cRe2c>3`GD~a3X9hQMqkm} zI~PBUxNCYZ$N+q=!1D6| zcgHwp^Gmb?k0Hc2dF^5p1>wpJ=c7%6~Y#!?^GLK?%0i#bkzK(d?0C!D)9&p!r zPX$@XVh-VmN&&CwA|ENjVIBb7Df1|14`5bS0$-#Ck09C&Y`gF2hNFNxWjQ-wm z*2mw$df@#C82z_wdLvlk=5^mlgT zhcycr{e|)JMP}F|=*R28Jkf*Q@C$&^U&r##0Y-mZ983DqU^{|eEnc3aup4d$jQ*bv zK9MW~%$~z2cXj~o+TUYrVsRb-ZQ*?ppu$Zun5Q z^gjYde~wu2K@jKfLC^=#kF)Z(+FuZ_1l*Osy&L}^VD#s(?Yj(^)iEfLV-nCM(BH!H zqky~emjFh;MhBlGI@1kHLGS3gzg`54_CKCQP(IJh!1#jQJ$s4kU)bJ*fYF|2%j1Cu z813c`K9?f}jP`H`pC<|e?wWr(V6=NX(sMY=0i%7}fq9&N07m<^BR?fN0vPR5^qXM) zQqYOe{*3b_xq#8`?BEk#1z^-YzF)p*9<-nHbR6eAK%9uT#c?U4i6Gt|$CsjM?;t)K z#{(W5>PJjK-@@`1^geM3@t`;!a4l>_Y>(q5tA{>nw|ML;wgYx8ISV1FX&}x z@61mZ(;@%V9wp~8?eTaK#PLlE(pN$p@7z)E zZiG5`P{%(ZgrQ!%hs87pp-p(7hw;TA)8HX!EPfp1#k+C(Nr)%K>E|FmIv)QP;-AIS zT!r}6c>D&$C&kn7K(4$Nr>8(1??AAwe?lDZKQMj*;^?EsF&Zu;{E; s;%Lib+fo$p)+8PWZz(~WJ=SK3$Lw`TlL>LO)sbEVakRNHz6Rp|1GQ>g&Hw-a From 2d6a51a23a1aeafe5c18c2eb9da7ee266add8507 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 13 May 2023 09:36:02 +0200 Subject: [PATCH 17/33] Stabilize spawnbot command --- src/client/component/bots.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/src/client/component/bots.cpp b/src/client/component/bots.cpp index 56d39d01..1677ee50 100644 --- a/src/client/component/bots.cpp +++ b/src/client/component/bots.cpp @@ -2,6 +2,7 @@ #include "loader/component_loader.hpp" #include "command.hpp" +#include "scheduler.hpp" #include #include @@ -147,13 +148,16 @@ namespace bots } } - for (size_t i = 0; i < count; ++i) + scheduler::once([count] { - if (!game::SV_AddTestClient()) + for (size_t i = 0; i < count; ++i) { - break; + if (!game::SV_AddTestClient()) + { + break; + } } - } + }, scheduler::server); }); } }; From 9b0e14115d5da1ee7f406f5b3b5a943e77176b25 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 13 May 2023 10:15:31 +0200 Subject: [PATCH 18/33] Small hooking adjustments --- src/common/utils/hook.cpp | 21 ++++++++++++++++----- src/common/utils/hook.hpp | 2 ++ 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/src/common/utils/hook.cpp b/src/common/utils/hook.cpp index f79874b4..1b4fe55c 100644 --- a/src/common/utils/hook.cpp +++ b/src/common/utils/hook.cpp @@ -29,7 +29,7 @@ namespace utils::hook uint8_t* allocate_somewhere_near(const void* base_address, const size_t granularity, const size_t size) { - size_t target_address = reinterpret_cast(base_address) - (1ull << 31); + size_t target_address = reinterpret_cast(base_address) - (1ull << 31); target_address &= ~(granularity - 1); while (true) @@ -415,7 +415,12 @@ namespace utils::hook bool is_relatively_far(const void* pointer, const void* data, const int offset) { - const int64_t diff = reinterpret_cast(data) - (reinterpret_cast(pointer) + offset); + return is_relatively_far(reinterpret_cast(pointer), reinterpret_cast(data), offset); + } + + bool is_relatively_far(const size_t pointer, const size_t data, const int offset) + { + const auto diff = static_cast(data - (pointer + offset)); const auto small_diff = static_cast(diff); return diff != static_cast(small_diff); } @@ -534,19 +539,25 @@ namespace utils::hook return result; } - void inject(void* pointer, const void* data) + void inject(size_t pointer, size_t data) { if (is_relatively_far(pointer, data, 4)) { throw std::runtime_error("Too far away to create 32bit relative branch"); } - set(pointer, int32_t(size_t(data) - (size_t(pointer) + 4))); + set( + pointer, static_cast(data - (pointer + 4))); + } + + void inject(void* pointer, const void* data) + { + return inject(reinterpret_cast(pointer), reinterpret_cast(data)); } void inject(const size_t pointer, const void* data) { - return inject(reinterpret_cast(pointer), data); + return inject(pointer, reinterpret_cast(data)); } std::vector move_hook(void* pointer) diff --git a/src/common/utils/hook.hpp b/src/common/utils/hook.hpp index b924e17b..9eed6f5a 100644 --- a/src/common/utils/hook.hpp +++ b/src/common/utils/hook.hpp @@ -162,6 +162,7 @@ namespace utils::hook void copy_string(size_t place, const char* str); bool is_relatively_far(const void* pointer, const void* data, int offset = 5); + bool is_relatively_far(size_t pointer, size_t data, int offset = 5); void call(void* pointer, void* data); void call(size_t pointer, void* data); @@ -175,6 +176,7 @@ namespace utils::hook void inject(void* pointer, const void* data); void inject(size_t pointer, const void* data); + void inject(size_t pointer, size_t data); std::vector move_hook(void* pointer); std::vector move_hook(size_t pointer); From a88e1c6192e2673e046a0daaf61ffb3a77ee85b4 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 13 May 2023 10:16:15 +0200 Subject: [PATCH 19/33] Add initial cg_fovScale support #141 --- src/client/component/fov.cpp | 42 ++++++++++++++++++++++++++++++++++++ src/client/game/symbols.hpp | 8 ++++++- 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 src/client/component/fov.cpp diff --git a/src/client/component/fov.cpp b/src/client/component/fov.cpp new file mode 100644 index 00000000..e1541c80 --- /dev/null +++ b/src/client/component/fov.cpp @@ -0,0 +1,42 @@ +#include +#include "loader/component_loader.hpp" + +#include "game/game.hpp" + +#include + +namespace fov +{ + namespace + { + void cg_calc_fov_stub(const int local_client_num, float* fov_x, float* dx_dz_at_default_aspect_ratio, + float* dx_dz, float* dy_dz) + { + game::CG_CalcFOVfromLens.call_safe(local_client_num, fov_x, dx_dz_at_default_aspect_ratio, dx_dz, dy_dz); + + const game::dvar_t* cg_fovScale = *reinterpret_cast(0x144A31A88_g); + if (cg_fovScale && !game::Com_IsRunningUILevel()) + { + const auto scale = cg_fovScale->current.value.value; + + *fov_x *= scale; + *dx_dz *= scale; + *dy_dz *= scale; + } + } + } + + struct component final : client_component + { + void post_unpack() override + { + // Hook CG_CalcFOVfromLens within CG_CalcFov + utils::hook::call(0x1404DADA7_g, cg_calc_fov_stub); + + // Patch cg_fovScale flags + utils::hook::set(0x14090E735_g, game::DVAR_ARCHIVE); + } + }; +} + +REGISTER_COMPONENT(fov::component) diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index 470af2aa..2995a46f 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -8,6 +8,10 @@ namespace game { #define Com_Error(code, fmt, ...) Com_Error_(__FILE__, __LINE__, code, fmt, ##__VA_ARGS__) + // CG + WEAK symbol + CG_CalcFOVfromLens{0x1404D6230}; + // CL WEAK symbol UI_OpenErrorPopupWithMessage{0x14228DEE0}; + WEAK symbol UI_OpenErrorPopupWithMessage{ + 0x14228DEE0 + }; WEAK symbol UI_CoD_Init{0x141F29010, 0x1404A0A50}; WEAK symbol UI_CoD_LobbyUI_Init{0x141F2BD80, 0x1404A1F50}; WEAK symbol UI_CoD_Shutdown{0x141F32E10, 0x0}; From d711d5f6c56806d619773bceedfe34ac25d74255 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sat, 13 May 2023 10:39:14 +0200 Subject: [PATCH 20/33] Fix cg_fovScale resetting --- src/client/component/fov.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/client/component/fov.cpp b/src/client/component/fov.cpp index e1541c80..48c3e682 100644 --- a/src/client/component/fov.cpp +++ b/src/client/component/fov.cpp @@ -35,6 +35,9 @@ namespace fov // Patch cg_fovScale flags utils::hook::set(0x14090E735_g, game::DVAR_ARCHIVE); + + // Don't reset cg_fovScale + utils::hook::set(0x140926D2A_g, 0xC3); } }; } From 7de1ffbe9d04c6f5090bb42002aa924116ddad44 Mon Sep 17 00:00:00 2001 From: FutureRave Date: Sat, 13 May 2023 10:25:14 +0100 Subject: [PATCH 21/33] fix: hot join join issue for dedis & dangling pointer in script --- src/client/component/bots.cpp | 7 +-- src/client/component/colors.cpp | 2 - src/client/component/dedicated_patches.cpp | 3 +- src/client/component/getinfo.cpp | 10 +--- src/client/component/party.cpp | 2 +- src/client/component/patches.cpp | 53 ++++++++++++++-------- src/client/component/scheduler.cpp | 8 ++-- src/client/component/scheduler.hpp | 8 ++-- src/client/component/script.cpp | 21 ++++----- src/client/game/structs.hpp | 24 ++++++++-- src/client/game/symbols.cpp | 5 -- src/client/game/symbols.hpp | 16 +++++-- src/client/game/utils.cpp | 6 +-- 13 files changed, 94 insertions(+), 71 deletions(-) diff --git a/src/client/component/bots.cpp b/src/client/component/bots.cpp index 56d39d01..43f124ae 100644 --- a/src/client/component/bots.cpp +++ b/src/client/component/bots.cpp @@ -94,9 +94,9 @@ namespace bots } int format_bot_string(char* buffer, [[maybe_unused]] const char* format, const char* name, const char* xuid, - const char* xnaddr, int protocol, int net_field_chk, const char* session_mode, int qport) + const char* xnaddr, int protocol, int net_field_chk, const char* session_mode, int qport) { - const auto find_name = [](const std::string& needle) -> const char* + const auto find_clan_name = [](const std::string& needle) -> const char* { for (const auto& entry : get_bot_names()) { @@ -109,7 +109,8 @@ namespace bots return "3arc"; }; - return sprintf_s(buffer, 1024, bot_format_string, name, find_name(name), xuid, xnaddr, protocol, net_field_chk, session_mode, qport); + return sprintf_s(buffer, 1024, bot_format_string, name, find_clan_name(name), + xuid, xnaddr, protocol, net_field_chk, session_mode, qport); } } diff --git a/src/client/component/colors.cpp b/src/client/component/colors.cpp index 5c7f7b4e..3ffe2c41 100644 --- a/src/client/component/colors.cpp +++ b/src/client/component/colors.cpp @@ -5,8 +5,6 @@ #include "auth.hpp" -#include "steam/steam.hpp" - #include #include diff --git a/src/client/component/dedicated_patches.cpp b/src/client/component/dedicated_patches.cpp index 80a0245c..11f3862d 100644 --- a/src/client/component/dedicated_patches.cpp +++ b/src/client/component/dedicated_patches.cpp @@ -2,7 +2,6 @@ #include "loader/component_loader.hpp" #include "game/game.hpp" -#include "scheduler.hpp" #include @@ -12,7 +11,7 @@ namespace dedicated_patches { utils::hook::detour spawn_server_hook; - void scr_are_textures_loaded_stub([[maybe_unused]] game::scriptInstance_t inst) + void scr_are_textures_loaded_stub() { game::Scr_AddInt(game::SCRIPTINSTANCE_SERVER, 1); } diff --git a/src/client/component/getinfo.cpp b/src/client/component/getinfo.cpp index b40c902a..5efcf49b 100644 --- a/src/client/component/getinfo.cpp +++ b/src/client/component/getinfo.cpp @@ -68,14 +68,6 @@ namespace getinfo return count; } - namespace - { - int Com_SessionMode_GetGameMode() - { - return *reinterpret_cast(game::select(0x1568ED7F4, 0x14948DB04)) << 14 >> 28; - } - } - int get_assigned_team() { return (rand() % 2) + 1; @@ -112,7 +104,7 @@ namespace getinfo info.set("protocol", std::to_string(PROTOCOL)); info.set("sub_protocol", std::to_string(SUB_PROTOCOL)); info.set("playmode", std::to_string(game::Com_SessionMode_GetMode())); - info.set("gamemode", std::to_string(Com_SessionMode_GetGameMode())); + info.set("gamemode", std::to_string(game::Com_SessionMode_GetGameMode())); info.set("sv_running", std::to_string(game::is_server_running())); info.set("dedicated", game::is_server() ? "1" : "0"); info.set("hc", std::to_string(game::Com_GametypeSettings_GetUInt("hardcoremode", false))); diff --git a/src/client/component/party.cpp b/src/client/component/party.cpp index 0ee400d5..07a15f11 100644 --- a/src/client/component/party.cpp +++ b/src/client/component/party.cpp @@ -54,7 +54,7 @@ namespace party { const auto local_client = *reinterpret_cast(0x14342155C_g); const auto current_mode = game::Com_SessionMode_GetMode(); - game::Com_SwitchMode(local_client, current_mode, mode, 6); + game::Com_SwitchMode(local_client, static_cast(current_mode), mode, 6); }, scheduler::main); } diff --git a/src/client/component/patches.cpp b/src/client/component/patches.cpp index 662ccf97..e1794351 100644 --- a/src/client/component/patches.cpp +++ b/src/client/component/patches.cpp @@ -2,8 +2,7 @@ #include "loader/component_loader.hpp" #include - -#include "network.hpp" +#include #include @@ -11,21 +10,10 @@ namespace patches { namespace { - utils::hook::detour sv_execute_client_messages_hook; + const game::dvar_t* lobby_min_players; - void sv_execute_client_messages_stub(game::client_s* client, game::msg_t* msg) - { - if ((client->reliableSequence - client->reliableAcknowledge) < 0) - { - client->reliableAcknowledge = client->reliableSequence; - network::send(client->address, "error", "EXE_LOSTRELIABLECOMMANDS"); - return; - } - - sv_execute_client_messages_hook.invoke(client, msg); - } - - void script_errors_stub(const char* file, int line, unsigned int code, const char* fmt, ...) + void script_errors_stub([[maybe_unused]] const char* file, [[maybe_unused]] int line, + [[maybe_unused]] unsigned int code, const char* fmt, ...) { char buffer[0x1000]; @@ -38,6 +26,30 @@ namespace patches game::Com_Error(game::ERROR_SCRIPT_DROP, "%s", buffer); } + + void scr_get_num_expected_players() + { + const auto mode = game::Com_SessionMode_GetMode(); + if (mode == game::MODE_ZOMBIES || mode == game::MODE_CAMPAIGN) + { + game::Scr_AddInt(game::SCRIPTINSTANCE_SERVER, lobby_min_players->current.value.integer); + } + + const auto num_expected_players = std::max(1, game::LobbyHost_GetClientCount(game::LOBBY_TYPE_GAME, game::LOBBY_CLIENT_TYPE_ALL)); + game::Scr_AddInt(game::SCRIPTINSTANCE_SERVER, num_expected_players); + } + + void sv_execute_client_messages_stub(game::client_s* client, game::msg_t* msg) + { + if ((client->reliableSequence - client->reliableAcknowledge) < 0) + { + client->reliableAcknowledge = client->reliableSequence; + game::SV_DropClient(client, "EXE_LOSTRELIABLECOMMANDS", true, true); + return; + } + + game::SV_ExecuteClientMessage(client, msg); + } } struct component final : generic_component @@ -53,13 +65,16 @@ namespace patches // don't make script errors fatal error utils::hook::call(game::select(0x1412CAC4D, 0x140158EB2), script_errors_stub); - // Change 4 character name limit to 3 characters + // change 4 character name limit to 3 characters utils::hook::set(game::select(0x14224DA53, 0x140531143), 3); utils::hook::set(game::select(0x14224DBB4, 0x1405312A8), 3); utils::hook::set(game::select(0x14224DF8C, 0x1405316DC), 3); - // make sure client's reliableAck are not negative - sv_execute_client_messages_hook.create(game::select(0x14224A460, 0x14052F840), sv_execute_client_messages_stub); + // make sure reliableAck is not negative or too big + utils::hook::call(game::select(0x14225489C, 0x140537C4C), sv_execute_client_messages_stub); + + lobby_min_players = game::register_dvar_int("lobby_min_players", 1, 1, 8, game::DVAR_NONE, ""); + utils::hook::jump(game::select(0x141A7BCF0, 0x1402CB900), scr_get_num_expected_players, true); } }; } diff --git a/src/client/component/scheduler.cpp b/src/client/component/scheduler.cpp index a115b1d9..7cbeb0b9 100644 --- a/src/client/component/scheduler.cpp +++ b/src/client/component/scheduler.cpp @@ -84,7 +84,7 @@ namespace scheduler }; volatile bool kill = false; - std::thread thread; + std::thread async_thread; task_pipeline pipelines[pipeline::count]; utils::hook::detour r_end_frame_hook; @@ -153,7 +153,7 @@ namespace scheduler { void post_load() override { - thread = utils::thread::create_named_thread("Async Scheduler", []() + async_thread = utils::thread::create_named_thread("Async Scheduler", []() { while (!kill) { @@ -180,9 +180,9 @@ namespace scheduler void pre_destroy() override { kill = true; - if (thread.joinable()) + if (async_thread.joinable()) { - thread.join(); + async_thread.join(); } } }; diff --git a/src/client/component/scheduler.hpp b/src/client/component/scheduler.hpp index 8949b6e4..56aaf8a0 100644 --- a/src/client/component/scheduler.hpp +++ b/src/client/component/scheduler.hpp @@ -30,12 +30,12 @@ namespace scheduler void execute(const pipeline type); - void schedule(const std::function& callback, pipeline type = pipeline::async, + void schedule(const std::function& callback, pipeline type, std::chrono::milliseconds delay = 0ms); - void loop(const std::function& callback, pipeline type = pipeline::async, + void loop(const std::function& callback, pipeline type, std::chrono::milliseconds delay = 0ms); - void once(const std::function& callback, pipeline type = pipeline::async, + void once(const std::function& callback, pipeline type, std::chrono::milliseconds delay = 0ms); - void on_game_initialized(const std::function& callback, pipeline type = pipeline::async, + void on_game_initialized(const std::function& callback, pipeline type, std::chrono::milliseconds delay = 0ms); } diff --git a/src/client/component/script.cpp b/src/client/component/script.cpp index 2958dae6..0016d087 100644 --- a/src/client/component/script.cpp +++ b/src/client/component/script.cpp @@ -14,7 +14,7 @@ namespace script { constexpr size_t GSC_MAGIC = 0x1C000A0D43534780; - utils::hook::detour db_findxassetheader_hook; + utils::hook::detour db_find_x_asset_header_hook; utils::hook::detour gscr_get_bgb_remaining_hook; std::unordered_map loaded_scripts; @@ -33,7 +33,6 @@ namespace script void load_script(std::string& name, const std::string& data) { auto& allocator = *utils::memory::get_allocator(); - const auto* file_string = allocator.duplicate_string(data); const auto appdata_path = (game::get_appdata_path() / "data/").generic_string(); const auto host_path = (utils::nt::library{}.get_folder() / "boiii/").generic_string(); @@ -50,12 +49,12 @@ namespace script name.erase(i, host_path.length()); } - auto* rawfile = allocator.allocate(); - rawfile->name = name.c_str(); - rawfile->buffer = file_string; - rawfile->len = static_cast(data.length()); + auto* raw_file = allocator.allocate(); + raw_file->name = allocator.duplicate_string(name); + raw_file->buffer = allocator.duplicate_string(data); + raw_file->len = static_cast(data.length()); - loaded_scripts[name] = rawfile; + loaded_scripts[name] = raw_file; } void load_scripts_folder(const std::string& script_dir) @@ -94,11 +93,11 @@ namespace script load_scripts_folder((host.get_folder() / "boiii/scripts").string()); } - game::RawFile* db_findxassetheader_stub(const game::XAssetType type, const char* name, + game::RawFile* db_find_x_asset_header_stub(const game::XAssetType type, const char* name, const bool error_if_missing, const int wait_time) { - auto* asset_header = db_findxassetheader_hook.invoke( + auto* asset_header = db_find_x_asset_header_hook.invoke( type, name, error_if_missing, wait_time); if (type != game::ASSET_TYPE_SCRIPTPARSETREE) @@ -134,10 +133,10 @@ namespace script } else { - scheduler::once(load_scripts, scheduler::pipeline::renderer); + scheduler::once(load_scripts, scheduler::pipeline::main); } - db_findxassetheader_hook.create(game::select(0x141420ED0, 0x1401D5FB0), db_findxassetheader_stub); + db_find_x_asset_header_hook.create(game::select(0x141420ED0, 0x1401D5FB0), db_find_x_asset_header_stub); gscr_get_bgb_remaining_hook.create(game::select(0x141A8CAB0, 0x1402D2310), gscr_get_bgb_remaining_stub); } }; diff --git a/src/client/game/structs.hpp b/src/client/game/structs.hpp index bc861685..1ceca9a2 100644 --- a/src/client/game/structs.hpp +++ b/src/client/game/structs.hpp @@ -890,7 +890,7 @@ namespace game enum LobbyType { - LOBBY_TYPE_INVALID = 0xFFFFFFFF, + LOBBY_TYPE_INVALID = -1, LOBBY_TYPE_PRIVATE = 0x0, LOBBY_TYPE_GAME = 0x1, LOBBY_TYPE_TRANSITION = 0x2, @@ -900,6 +900,14 @@ namespace game LOBBY_TYPE_AUTO = 0x3, }; + enum LobbyClientType + { + LOBBY_CLIENT_TYPE_INVALID = -1, + LOBBY_CLIENT_TYPE_ALL = 0x0, + LOBBY_CLIENT_TYPE_LOCAL = 0x1, + LOBBY_CLIENT_TYPE_REMOTE = 0x2, + }; + enum LobbyNetworkMode { LOBBY_NETWORKMODE_INVALID = 0xFFFFFFFF, @@ -1600,7 +1608,6 @@ namespace game char __pad6[171432]; }; - #ifdef __cplusplus static_assert(sizeof(client_s) == 0xE5110); @@ -1637,14 +1644,23 @@ namespace game struct EntityState { int number; - }; + }; // Incomplete struct gentity_s { EntityState s; unsigned char __pad0[0x24C]; gclient_s* client; - unsigned char __pad1[0x2A0]; + unsigned char __pad1[0x17C]; + struct + { + unsigned int notifyString; + unsigned int index; + unsigned char stoppable; + int basetime; + int duration; + } snd_wait; + unsigned char __pad2[0x110]; }; #ifdef __cplusplus diff --git a/src/client/game/symbols.cpp b/src/client/game/symbols.cpp index fb36ce71..789acbb7 100644 --- a/src/client/game/symbols.cpp +++ b/src/client/game/symbols.cpp @@ -4,11 +4,6 @@ namespace game { - eModes Com_SessionMode_GetMode() - { - return eModes(*reinterpret_cast(game::select(0x1568ED7F4, 0x14948DB04)) << 28 >> 28); - } - bool I_islower(int c) { return c >= 'a' && c <= 'z'; diff --git a/src/client/game/symbols.hpp b/src/client/game/symbols.hpp index 470af2aa..9df36d84 100644 --- a/src/client/game/symbols.hpp +++ b/src/client/game/symbols.hpp @@ -25,6 +25,8 @@ namespace game WEAK symbol Com_Printf{0x142148F60, 0x140505630}; WEAK symbol Com_Error_{0x1420F8170, 0x140501470}; WEAK symbol Com_SessionMode_IsMode{0x1420F7370}; + WEAK symbol Com_SessionMode_GetMode{0x1420F6D30 , 0x1405002D0}; + WEAK symbol Com_SessionMode_GetGameMode{0x1420F68B0, 0x1404FFE50}; WEAK symbol Com_SessionMode_SetNetworkMode{0x1420F75B0, 0x140500B80}; WEAK symbol Com_SessionMode_SetGameMode{0x1420F7570, 0x140500B40}; WEAK symbol Com_SessionMode_SetMode{0x1420F7570}; @@ -131,7 +133,7 @@ namespace game }; WEAK symbol Dvar_RegisterInt{ - 0x0, 0x14057B7B0 + 0x1422D0AE0, 0x14057B7B0 }; WEAK symbol Dvar_RegisterFloat{ @@ -204,10 +206,20 @@ namespace game }; WEAK symbol SV_Cmd_TokenizeString{0x1420EF130, 0x1404FA6C0}; WEAK symbol SV_Cmd_EndTokenizedString{0x1420EF0E0, 0x1404FA670}; + WEAK symbol SV_ExecuteClientMessage{0x14224A460, 0x14052F840}; + + WEAK symbol SV_DropClient{ + 0x14224A050, 0x14052F430 + }; // FS WEAK symbol FS_AllocMem{0x1422AC9F0, 0x14056C340}; + // Lobby + WEAK symbol LobbyHost_GetClientCount{ + 0x141ED8AC0, 0x14048A360 + }; + // Utils WEAK symbol I_CleanStr{0x1422E9050, 0x140580E80}; WEAK symbol I_strcpy{ @@ -261,8 +273,6 @@ namespace game constexpr auto CMD_MAX_NESTING = 8; // Re-implementations - eModes Com_SessionMode_GetMode(); - bool I_islower(int c); bool I_isupper(int c); diff --git a/src/client/game/utils.cpp b/src/client/game/utils.cpp index 4f6fb99a..cc083632 100644 --- a/src/client/game/utils.cpp +++ b/src/client/game/utils.cpp @@ -136,11 +136,10 @@ namespace game } auto* dvar_to_change = dvar; - if (dvar_to_change->type == DVAR_TYPE_SESSIONMODE_BASE_DVAR) { const auto mode = Com_SessionMode_GetMode(); - dvar_to_change = Dvar_GetSessionModeSpecificDvar(dvar_to_change, mode); + dvar_to_change = Dvar_GetSessionModeSpecificDvar(dvar_to_change, static_cast(mode)); } dvar_to_change->flags |= flags; @@ -156,11 +155,10 @@ namespace game } auto* dvar_to_change = dvar; - if (dvar_to_change->type == DVAR_TYPE_SESSIONMODE_BASE_DVAR) { const auto mode = Com_SessionMode_GetMode(); - dvar_to_change = Dvar_GetSessionModeSpecificDvar(dvar_to_change, mode); + dvar_to_change = Dvar_GetSessionModeSpecificDvar(dvar_to_change, static_cast(mode)); } dvar_to_change->flags = flags; From f6d45ca3b7485b11e2fd2fd7081eb77701a93a48 Mon Sep 17 00:00:00 2001 From: FutureRave Date: Sat, 13 May 2023 10:34:51 +0100 Subject: [PATCH 22/33] fix(server_status): format it properly --- src/client/component/patches.cpp | 3 -- src/client/component/status.cpp | 47 ++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 src/client/component/status.cpp diff --git a/src/client/component/patches.cpp b/src/client/component/patches.cpp index 662ccf97..11254632 100644 --- a/src/client/component/patches.cpp +++ b/src/client/component/patches.cpp @@ -44,9 +44,6 @@ namespace patches { void post_unpack() override { - // print hexadecimal xuids in status command - utils::hook::copy_string(game::select(0x143050560, 0x140E85B00), "%12llx "); - // print hexadecimal xuids in chat game log command utils::hook::set(game::select(0x142FD9362, 0x140E16FA2), 'x'); diff --git a/src/client/component/status.cpp b/src/client/component/status.cpp new file mode 100644 index 00000000..620260a3 --- /dev/null +++ b/src/client/component/status.cpp @@ -0,0 +1,47 @@ +#include +#include "loader/component_loader.hpp" +#include + +#include + +namespace status +{ + namespace + { + int client_num_; + + void print_client_num(int channel, int label, const char* fmt, const int client_num) + { + client_num_ = client_num; + game::Com_Printf(channel, label, fmt, client_num); + } + + void print_client_xuid(int channel, int label, [[maybe_unused]] const char* fmt, const uint64_t xuid) + { + if (game::SV_IsTestClient(client_num_)) + { + game::Com_Printf(channel, label, "%16s ", "bot0"); + return; + } + + game::Com_Printf(channel, label, "%12llx ", xuid); + } + } + + struct component final : generic_component + { + void post_unpack() override + { + // Patch the status command for test clients + utils::hook::call(game::select(0x142246E37, 0x14052C527), print_client_num); + utils::hook::call(game::select(0x142246EDE, 0x14052C5CE), print_client_xuid); + + utils::hook::copy_string(game::select(0x143050480, 0x140E85A20), + "num score ping xuid name address qport \n"); + utils::hook::copy_string(game::select(0x1430504E0, 0x140E85A80), + "--- ----- ---- ---------------- ---------------- ------------------------ ------ \n"); + } + }; +} + +REGISTER_COMPONENT(status::component) From cf6bf6bd89a5a871d5a5e10aca9926a3cc6edf3a Mon Sep 17 00:00:00 2001 From: WantedDV <122710241+WantedDV@users.noreply.github.com> Date: Sat, 13 May 2023 13:00:34 -0230 Subject: [PATCH 23/33] camel case --- data/scripts/mp/bots/_bot.gsc_raw | 154 +++++++++++++++--------------- 1 file changed, 77 insertions(+), 77 deletions(-) diff --git a/data/scripts/mp/bots/_bot.gsc_raw b/data/scripts/mp/bots/_bot.gsc_raw index 0d1bb593..a8cac035 100644 --- a/data/scripts/mp/bots/_bot.gsc_raw +++ b/data/scripts/mp/bots/_bot.gsc_raw @@ -98,13 +98,13 @@ function __init__() level.botIgnoreThreat = &bot_combat::bot_ignore_threat; - level.enemyEmpActive = &emp::EnemyEmpActive; + level.enemyEmpActive = &emp::enemyEmpActive; /# level.botDevguiCmd = &bot_devgui_cmd; level thread system_devgui_gadget_think(); #/ - SetDvar( "bot_enableWallrun", 1 ); + setDvar( "bot_enableWallrun", 1 ); } function init() @@ -127,7 +127,7 @@ function init() function is_bot_soak() { - return GetDvarInt( "sv_botsoak", 0 ); + return getDvarInt( "sv_botsoak", 0 ); } function wait_for_host() @@ -202,24 +202,24 @@ function on_bot_spawned() /# weapon = undefined; - if ( GetDvarInt( "scr_botsHasPlayerWeapon" ) != 0 ) + if ( getDvarInt( "scr_botsHasPlayerWeapon" ) != 0 ) { player = util::getHostPlayer(); - weapon = player GetCurrentWeapon(); + weapon = player getCurrentWeapon(); } - if ( GetDvarString( "devgui_bot_weapon", "" ) != "" ) + if ( getDvarString( "devgui_bot_weapon", "" ) != "" ) { - weapon = GetWeapon( GetDvarString( "devgui_bot_weapon" ) ); + weapon = getWeapon( getDvarString( "devgui_bot_weapon" ) ); } if ( isdefined( weapon ) && level.weaponNone != weapon ) { self weapons::detach_all_weapons(); - self TakeAllWeapons(); - self GiveWeapon( weapon ); - self SwitchToWeapon( weapon ); - self SetSpawnWeapon( weapon ); + self takeAllWeapons(); + self giveWeapon( weapon ); + self switchToWeapon( weapon ); + self setSpawnWeapon( weapon ); self teams::set_player_model( self.team, weapon ); } @@ -276,7 +276,7 @@ function bot_idle() function do_supplydrop( maxRange = 1400 ) // A little under minimap width { - crates = GetEntArray( "care_package", "script_noteworthy" ); + crates = getEntArray( "care_package", "script_noteworthy" ); maxRangeSq = maxRange * maxRange; @@ -287,12 +287,12 @@ function do_supplydrop( maxRange = 1400 ) // A little under minimap width foreach( crate in crates ) { - if ( !crate IsOnGround() ) + if ( !crate isOnGround() ) { continue; } - crateDistSq = Distance2DSquared( self.origin, crate.origin ); + crateDistSq = distance2DSquared( self.origin, crate.origin ); if ( crateDistSq > maxRangeSq ) { @@ -312,7 +312,7 @@ function do_supplydrop( maxRange = 1400 ) // A little under minimap width return true; } - if ( !self has_minimap() && !self BotSightTracePassed( crate ) ) + if ( !self has_minimap() && !self botSightTracePassed( crate ) ) { continue; } @@ -326,12 +326,12 @@ function do_supplydrop( maxRange = 1400 ) // A little under minimap width if ( isdefined( closestCrate ) ) { - randomAngle = ( 0, RandomInt( 360 ), 0 ); + randomAngle = ( 0, randomInt( 360 ), 0 ); randomVec = AnglesToForward( randomAngle ); point = closestCrate.origin + randomVec * CRATE_GOAL_RADIUS; - if ( self BotSetGoal( point ) ) + if ( self botSetGoal( point ) ) { self thread watch_crate( closestCrate ); return true; @@ -352,7 +352,7 @@ function watch_crate( crate ) wait level.botSettings.thinkInterval; } - self BotSetGoal( self.origin ); + self botSetGoal( self.origin ); } // Bot Team Population @@ -364,14 +364,14 @@ function populate_bots() if ( level.teambased ) { - maxAllies = GetDvarInt( "bot_maxAllies", 0 ); - maxAxis = GetDvarInt( "bot_maxAxis", 0 ); + maxAllies = getDvarInt( "bot_maxAllies", 0 ); + maxAxis = getDvarInt( "bot_maxAxis", 0 ); level thread monitor_bot_team_population( maxAllies, maxAxis ); } else { - maxFree = GetDvarInt( "bot_maxFree", 0 ); + maxFree = getDvarInt( "bot_maxFree", 0 ); level thread monitor_bot_population( maxFree ); } @@ -393,8 +393,8 @@ function monitor_bot_team_population( maxAllies, maxAxis ) wait 3; // TODO: Get a player count that includes 'CON_CONNECTING' players - allies = GetPlayers( "allies" ); - axis = GetPlayers( "axis" ); + allies = getPlayers( "allies" ); + axis = getPlayers( "axis" ); if ( allies.size > maxAllies && remove_best_bot( allies ) ) @@ -417,16 +417,16 @@ function monitor_bot_team_population( maxAllies, maxAxis ) function fill_balanced_teams( maxAllies, maxAxis ) { - allies = GetPlayers( "allies" ); - axis = GetPlayers( "axis" ); + allies = getPlayers( "allies" ); + axis = getPlayers( "axis" ); while ( ( allies.size < maxAllies || axis.size < maxAxis ) && add_balanced_bot( allies, maxAllies, axis, maxAxis ) ) { WAIT_SERVER_FRAME; - allies = GetPlayers( "allies" ); - axis = GetPlayers( "axis" ); + allies = getPlayers( "allies" ); + axis = getPlayers( "axis" ); } } @@ -457,12 +457,12 @@ function monitor_bot_population( maxFree ) } // Initial Fill - players = GetPlayers( ); + players = getPlayers( ); while ( players.size < maxFree ) { add_bot(); WAIT_SERVER_FRAME; - players = GetPlayers( ); + players = getPlayers( ); } while ( 1 ) @@ -470,7 +470,7 @@ function monitor_bot_population( maxFree ) wait 3; // TODO: Get a player count that includes 'CON_CONNECTING' players - players = GetPlayers( ); + players = getPlayers( ); if ( players.size < maxFree ) { @@ -511,11 +511,11 @@ function remove_best_bot( players ) if ( bestBots.size ) { - remove_bot( bestBots[RandomInt( bestBots.size )] ); + remove_bot( bestBots[randomInt( bestBots.size )] ); } else { - remove_bot( bots[RandomInt( bots.size )] ); + remove_bot( bots[randomInt( bots.size )] ); } return true; @@ -533,9 +533,9 @@ function choose_class() currClass = self bot_loadout::get_current_class(); - if ( !isdefined( currClass ) || RandomInt( 100 ) < VAL( level.botSettings.changeClassWeight, 0 ) ) + if ( !isdefined( currClass ) || randomInt( 100 ) < VAL( level.botSettings.changeClassWeight, 0 ) ) { - classIndex = RandomInt( self.loadoutClasses.size ); + classIndex = randomInt( self.loadoutClasses.size ); className = self.loadoutClasses[classIndex].name; } @@ -555,13 +555,13 @@ function choose_class() function use_killstreak() { if ( !level.loadoutKillstreaksEnabled || - self emp::EnemyEMPActive() ) + self emp::enemyEmpActive() ) { return; } - weapons = self GetWeaponsList(); - inventoryWeapon = self GetInventoryWeapon(); + weapons = self getWeaponsList(); + inventoryWeapon = self getInventoryWeapon(); foreach( weapon in weapons ) { @@ -572,7 +572,7 @@ function use_killstreak() continue; } - if ( weapon != inventoryWeapon && !self GetWeaponAmmoClip( weapon ) ) + if ( weapon != inventoryWeapon && !self getWeaponAmmoClip( weapon ) ) { continue; } @@ -600,7 +600,7 @@ function use_killstreak() case "killstreak_raps": case "killstreak_sentinel": { - self SwitchToWeapon( useWeapon ); + self switchToWeapon( useWeapon ); break; } case "killstreak_ai_tank_drop": @@ -610,7 +610,7 @@ function use_killstreak() } case "killstreak_remote_missile": { - self SwitchToWeapon( weapon ); + self switchToWeapon( weapon ); self waittill( "weapon_change_complete" ); wait 1.5; self bot::press_attack_button(); @@ -664,16 +664,16 @@ function use_supply_drop( weapon ) wait 0.5; - if ( self getcurrentweapon() != weapon ) + if ( self getCurrentWeapon() != weapon ) { self thread weapon_switch_failsafe(); - self switchtoweapon( weapon ); + self switchToWeapon( weapon ); self waittill( "weapon_change_complete" ); } use_item( weapon ); - self switchtoweapon( self.lastnonkillstreakweapon ); + self switchToWeapon( self.lastnonkillstreakweapon ); self clearlookat(); self cancelgoal( "killstreak" ); } @@ -685,7 +685,7 @@ function use_item( weapon ) for ( i = 0; i < 10; i++ ) { - if ( self getcurrentweapon() == weapon || self getcurrentweapon() == "none" ) + if ( self getCurrentWeapon() == weapon || self getCurrentWeapon() == "none" ) self bot::press_attack_button(); else return; @@ -701,7 +701,7 @@ function killstreak_location( num, weapon ) if ( !enemies.size ) return; - if ( !self switchtoweapon( weapon ) ) + if ( !self switchToWeapon( weapon ) ) return; self waittill( "weapon_change" ); @@ -717,7 +717,7 @@ function killstreak_location( num, weapon ) if ( wait_time <= 0 ) { self util::freeze_player_controls( false ); - self switchtoweapon( self.lastnonkillstreakweapon ); + self switchToWeapon( self.lastnonkillstreakweapon ); return; } } @@ -786,9 +786,9 @@ function get_enemies( on_radar ) /# for ( i = 0; i < enemies.size; i++ ) { - if ( isplayer( enemies[i] ) && enemies[i] IsInMoveMode( "ufo", "noclip" ) ) + if ( isplayer( enemies[i] ) && enemies[i] isInMoveMode( "ufo", "noclip" ) ) { - ArrayRemoveIndex( enemies, i ); + arrayRemoveIndex( enemies, i ); i--; } } @@ -800,12 +800,12 @@ function get_enemies( on_radar ) { if ( !isdefined( enemies[i].lastFireTime ) ) { - ArrayRemoveIndex( enemies, i ); + arrayRemoveIndex( enemies, i ); i--; } else if ( GetTime() - enemies[i].lastFireTime > 2000 ) { - ArrayRemoveIndex( enemies, i ); + arrayRemoveIndex( enemies, i ); i--; } } @@ -816,7 +816,7 @@ function get_enemies( on_radar ) function set_rank() { - players = GetPlayers(); + players = getPlayers(); ranks = []; bot_ranks = []; @@ -848,12 +848,12 @@ function set_rank() while ( bot_ranks.size + human_ranks.size < 5 ) { // add some random ranks for better random number distribution - r = human_avg + RandomIntRange( -5, 5 ); + r = human_avg + randomIntRange( -5, 5 ); rank = math::clamp( r, 0, level.maxRank ); human_ranks[ human_ranks.size ] = rank; } - ranks = ArrayCombine( human_ranks, bot_ranks, true, false ); + ranks = arrayCombine( human_ranks, bot_ranks, true, false ); avg = math::array_average( ranks ); s = math::array_std_deviation( ranks, avg ); @@ -924,7 +924,7 @@ function init_bot_gametype() function get_bot_settings() { - switch ( GetDvarInt( "bot_difficulty", 1 ) ) + switch ( getDvarInt( "bot_difficulty", 1 ) ) { case 0: bundleName = "bot_mp_easy"; @@ -1023,7 +1023,7 @@ function bot_devgui_cmd( cmd ) return true; case "player_weapon": - players = GetPlayers(); + players = getPlayers(); foreach( player in players ) { if ( !player util::is_bot() ) @@ -1031,13 +1031,13 @@ function bot_devgui_cmd( cmd ) continue; } - weapon = host GetCurrentWeapon(); + weapon = host getCurrentWeapon(); player weapons::detach_all_weapons(); - player TakeAllWeapons(); - player GiveWeapon( weapon ); - player SwitchToWeapon( weapon ); - player SetSpawnWeapon( weapon ); + player takeAllWeapons(); + player giveWeapon( weapon ); + player switchToWeapon( weapon ); + player setSpawnWeapon( weapon ); player teams::set_player_model( player.team, weapon ); } @@ -1049,25 +1049,25 @@ function bot_devgui_cmd( cmd ) function system_devgui_gadget_think() { - SetDvar( "devgui_bot_gadget", "" ); + setDvar( "devgui_bot_gadget", "" ); for ( ;; ) { wait( 1 ); - gadget = GetDvarString( "devgui_bot_gadget" ); + gadget = getDvarString( "devgui_bot_gadget" ); if ( gadget != "" ) { - bot_turn_on_gadget( GetWeapon(gadget) ); - SetDvar( "devgui_bot_gadget", "" ); + bot_turn_on_gadget( getWeapon(gadget) ); + setDvar( "devgui_bot_gadget", "" ); } } } function bot_turn_on_gadget( gadget ) { - players = GetPlayers(); + players = getPlayers(); foreach( player in players ) { @@ -1077,25 +1077,25 @@ function bot_turn_on_gadget( gadget ) } host = util::getHostPlayer(); - weapon = host GetCurrentWeapon(); + weapon = host getCurrentWeapon(); if ( !isdefined( weapon ) || weapon == level.weaponNone || weapon == level.weaponNull ) { - weapon = GetWeapon( "smg_standard" ); + weapon = getWeapon( "smg_standard" ); } player weapons::detach_all_weapons(); - player TakeAllWeapons(); - player GiveWeapon( weapon ); - player SwitchToWeapon( weapon ); - player SetSpawnWeapon( weapon ); + player takeAllWeapons(); + player giveWeapon( weapon ); + player switchToWeapon( weapon ); + player setSpawnWeapon( weapon ); player teams::set_player_model( player.team, weapon ); - player GiveWeapon( gadget ); - slot = player GadgetGetSlot( gadget ); - player GadgetPowerSet( slot, 100.0 ); - player BotPressButtonForGadget( gadget ); + player giveWeapon( gadget ); + slot = player gadgetGetSlot( gadget ); + player gadgetPowerSet( slot, 100.0 ); + player botPressButtonForGadget( gadget ); } } @@ -1112,8 +1112,8 @@ function fixed_spawn_override() { self waittill( "spawned_player" ); - self SetOrigin( spawnOrigin ); - self SetPlayerAngles( spawnAngles ); + self setOrigin( spawnOrigin ); + self setPlayerAngles( spawnAngles ); } } From 523dec3b615fada3eb3b469b18315cca5418a05e Mon Sep 17 00:00:00 2001 From: WantedDV <122710241+WantedDV@users.noreply.github.com> Date: Sat, 13 May 2023 13:05:53 -0230 Subject: [PATCH 24/33] formatting whitespace --- data/scripts/mp/bots/_bot.gsc_raw | 977 +++++++++++++++--------------- 1 file changed, 487 insertions(+), 490 deletions(-) diff --git a/data/scripts/mp/bots/_bot.gsc_raw b/data/scripts/mp/bots/_bot.gsc_raw index a8cac035..cd6b335d 100644 --- a/data/scripts/mp/bots/_bot.gsc_raw +++ b/data/scripts/mp/bots/_bot.gsc_raw @@ -73,52 +73,52 @@ #namespace bot; -#precache( "eventstring", "mpl_killstreak_cruisemissile" ); -#precache( "eventstring", "mpl_killstreak_raps" ); +#precache("eventstring", "mpl_killstreak_cruisemissile"); +#precache("eventstring", "mpl_killstreak_raps"); -REGISTER_SYSTEM( "bot_mp", &__init__, undefined ) +REGISTER_SYSTEM("bot_mp", &__init__, undefined) function __init__() { - callback::on_start_gametype( &init ); - + callback::on_start_gametype(&init); + level.getBotSettings = &get_bot_settings; - + level.onBotConnect = &on_bot_connect; level.onBotSpawned = &on_bot_spawned; level.onBotKilled = &on_bot_killed; - + level.botIdle = &bot_idle; - + level.botThreatLost = &bot_combat::chase_threat; level.botPreCombat = &bot_combat::mp_pre_combat; level.botCombat = &bot_combat::combat_think; level.botPostCombat = &bot_combat::mp_post_combat; - + level.botIgnoreThreat = &bot_combat::bot_ignore_threat; - + level.enemyEmpActive = &emp::enemyEmpActive; - + /# level.botDevguiCmd = &bot_devgui_cmd; level thread system_devgui_gadget_think(); #/ - setDvar( "bot_enableWallrun", 1 ); + setDvar("bot_enableWallrun", 1); } function init() -{ - level endon( "game_ended" ); - +{ + level endon("game_ended"); + level.botSoak = is_bot_soak(); - if( !init_bot_gametype() ) + if (!init_bot_gametype()) { return; } wait_for_host(); - + level thread populate_bots(); } @@ -127,18 +127,18 @@ function init() function is_bot_soak() { - return getDvarInt( "sv_botsoak", 0 ); + return getDvarInt("sv_botsoak", 0); } function wait_for_host() { - level endon( "game_ended" ); - + level endon("game_ended"); + host = util::getHostPlayerForBots(); - - while ( !isdefined( host ) ) + + while (!isdefined(host)) { - wait( 0.25 ); + wait(0.25); host = util::getHostPlayerForBots(); } } @@ -146,12 +146,12 @@ function wait_for_host() function get_host_team() { host = util::getHostPlayerForBots(); - - if ( !isdefined( host ) || host.team == "spectator" ) + + if (!isdefined(host) || host.team == "spectator") { return "allies"; } - + return host.team; } @@ -160,35 +160,34 @@ function is_bot_comp_stomp() return false; } - // Bot Events //======================================== function on_bot_connect() { - self endon( "disconnect" ); - level endon( "game_ended" ); - - if ( IS_TRUE( level.disableClassSelection ) ) + self endon("disconnect"); + level endon("game_ended"); + + if (IS_TRUE(level.disableClassSelection)) { self set_rank(); - + // Doesn't work if we don't do it in this order self bot_loadout::pick_hero_gadget(); self bot_loadout::pick_killstreaks(); - + return; } - - if ( !IS_TRUE( self.pers["bot_loadout"] ) ) + + if (!IS_TRUE(self.pers["bot_loadout"])) { self set_rank(); - + // Doesn't work if we don't do it in this order self bot_loadout::build_classes(); self bot_loadout::pick_hero_gadget(); self bot_loadout::pick_killstreaks(); - + self.pers["bot_loadout"] = true; } @@ -202,26 +201,26 @@ function on_bot_spawned() /# weapon = undefined; - if ( getDvarInt( "scr_botsHasPlayerWeapon" ) != 0 ) + if (getDvarInt("scr_botsHasPlayerWeapon") != 0) { player = util::getHostPlayer(); weapon = player getCurrentWeapon(); } - if ( getDvarString( "devgui_bot_weapon", "" ) != "" ) + if (getDvarString("devgui_bot_weapon", "") != "") { - weapon = getWeapon( getDvarString( "devgui_bot_weapon" ) ); + weapon = getWeapon(getDvarString("devgui_bot_weapon")); } - if ( isdefined( weapon ) && level.weaponNone != weapon ) + if (isdefined(weapon) && level.weaponNone != weapon) { self weapons::detach_all_weapons(); self takeAllWeapons(); - self giveWeapon( weapon ); - self switchToWeapon( weapon ); - self setSpawnWeapon( weapon ); + self giveWeapon(weapon); + self switchToWeapon(weapon); + self setSpawnWeapon(weapon); - self teams::set_player_model( self.team, weapon ); + self teams::set_player_model(self.team, weapon); } #/ } @@ -229,37 +228,37 @@ function on_bot_spawned() function on_bot_killed() { self endon("disconnect"); - level endon( "game_ended" ); - self endon( "spawned" ); - self waittill ( "death_delay_finished" ); + level endon("game_ended"); + self endon("spawned"); + self waittill("death_delay_finished"); wait RESPAWN_DELAY; - - if ( self choose_class() && level.playerForceRespawn ) + + if (self choose_class() && level.playerForceRespawn) { return; } - + self thread respawn(); } function respawn() { - self endon( "spawned" ); - self endon( "disconnect" ); - level endon( "game_ended" ); + self endon("spawned"); + self endon("disconnect"); + level endon("game_ended"); - while( 1 ) + while (1) { self bot::tap_use_button(); - + wait RESPAWN_INTERVAL; } } function bot_idle() -{ - if ( self do_supplydrop() ) +{ + if (self do_supplydrop()) { return; } @@ -274,85 +273,85 @@ function bot_idle() #define CRATE_GOAL_RADIUS 39 #define CRATE_USE_RADIUS 62 // Wild guess on usable radius -function do_supplydrop( maxRange = 1400 ) // A little under minimap width +function do_supplydrop(maxRange = 1400) // A little under minimap width { - crates = getEntArray( "care_package", "script_noteworthy" ); - + crates = getEntArray("care_package", "script_noteworthy"); + maxRangeSq = maxRange * maxRange; - + useRadiusSq = CRATE_USE_RADIUS * CRATE_USE_RADIUS; - + closestCrate = undefined; closestCrateDistSq = undefined; - foreach( crate in crates ) + foreach(crate in crates) { - if ( !crate isOnGround() ) + if (!crate isOnGround()) { continue; } - - crateDistSq = distance2DSquared( self.origin, crate.origin ); - - if ( crateDistSq > maxRangeSq ) + + crateDistSq = distance2DSquared(self.origin, crate.origin); + + if (crateDistSq > maxRangeSq) { continue; } - - inUse = isdefined( crate.useEnt ) && IS_TRUE( crate.useEnt.inUse ); - - if ( crateDistSq <= useRadiusSq ) + + inUse = isdefined(crate.useEnt) && IS_TRUE(crate.useEnt.inUse); + + if (crateDistSq <= useRadiusSq) { - if ( inUse && !self useButtonPressed() ) + if (inUse && !self useButtonPressed()) { continue; } - + self bot::press_use_button(); return true; } - if ( !self has_minimap() && !self botSightTracePassed( crate ) ) + if (!self has_minimap() && !self botSightTracePassed(crate)) { continue; } - if ( !isdefined( closestCrate ) || crateDistSq < closestCrateDistSq ) + if (!isdefined(closestCrate) || crateDistSq < closestCrateDistSq) { closestCrate = crate; closestCrateDistSq = crateDistSq; } } - - if ( isdefined( closestCrate ) ) - { - randomAngle = ( 0, randomInt( 360 ), 0 ); - randomVec = AnglesToForward( randomAngle ); - + + if (isdefined(closestCrate)) + { + randomAngle = (0, randomInt(360), 0); + randomVec = AnglesToForward(randomAngle); + point = closestCrate.origin + randomVec * CRATE_GOAL_RADIUS; - - if ( self botSetGoal( point ) ) + + if (self botSetGoal(point)) { - self thread watch_crate( closestCrate ); + self thread watch_crate(closestCrate); return true; } } - + return false; } -function watch_crate( crate ) +function watch_crate(crate) { - self endon( "death" ); - self endon( "bot_goal_reached" ); - level endon( "game_ended" ); - - while ( isdefined( crate ) && !self bot_combat::has_threat() ) + self endon("death"); + self endon("bot_goal_reached"); + level endon("game_ended"); + + while (isdefined(crate) && !self bot_combat::has_threat()) { wait level.botSettings.thinkInterval; } - - self botSetGoal( self.origin ); + + self botSetGoal(self.origin); } // Bot Team Population @@ -360,164 +359,164 @@ function watch_crate( crate ) function populate_bots() { - level endon( "game_ended" ); - - if ( level.teambased ) + level endon("game_ended"); + + if (level.teambased) { - maxAllies = getDvarInt( "bot_maxAllies", 0 ); - maxAxis = getDvarInt( "bot_maxAxis", 0 ); - - level thread monitor_bot_team_population( maxAllies, maxAxis ); + maxAllies = getDvarInt("bot_maxAllies", 0); + maxAxis = getDvarInt("bot_maxAxis", 0); + + level thread monitor_bot_team_population(maxAllies, maxAxis); } else { - maxFree = getDvarInt( "bot_maxFree", 0 ); - - level thread monitor_bot_population( maxFree ); + maxFree = getDvarInt("bot_maxFree", 0); + + level thread monitor_bot_population(maxFree); } } -function monitor_bot_team_population( maxAllies, maxAxis ) +function monitor_bot_team_population(maxAllies, maxAxis) { - level endon( "game_ended" ); - - if ( !maxAllies && !maxAxis ) + level endon("game_ended"); + + if (!maxAllies && !maxAxis) { return; } - - fill_balanced_teams( maxAllies, maxAxis ); - - while ( 1 ) + + fill_balanced_teams(maxAllies, maxAxis); + + while (1) { wait 3; - + // TODO: Get a player count that includes 'CON_CONNECTING' players - allies = getPlayers( "allies" ); - axis = getPlayers( "axis" ); - - if ( allies.size > maxAllies && - remove_best_bot( allies ) ) + allies = getPlayers("allies"); + axis = getPlayers("axis"); + + if (allies.size > maxAllies && + remove_best_bot(allies)) { continue; } - - if ( axis.size > maxAxis && - remove_best_bot( axis ) ) + + if (axis.size > maxAxis && + remove_best_bot(axis)) { continue; } - - if ( allies.size < maxAllies || axis.size < maxAxis ) + + if (allies.size < maxAllies || axis.size < maxAxis) { - add_balanced_bot( allies, maxAllies, axis, maxAxis ); + add_balanced_bot(allies, maxAllies, axis, maxAxis); } } } -function fill_balanced_teams( maxAllies, maxAxis ) +function fill_balanced_teams(maxAllies, maxAxis) { - allies = getPlayers( "allies" ); - axis = getPlayers( "axis" ); - - while ( ( allies.size < maxAllies || axis.size < maxAxis ) && - add_balanced_bot( allies, maxAllies, axis, maxAxis ) ) - { - WAIT_SERVER_FRAME; - - allies = getPlayers( "allies" ); - axis = getPlayers( "axis" ); - } -} + allies = getPlayers("allies"); + axis = getPlayers("axis"); -function add_balanced_bot( allies, maxAllies, axis, maxAxis ) -{ - bot = undefined; - - if ( allies.size < maxAllies && - ( allies.size <= axis.size || axis.size >= maxAxis ) ) - { - bot = add_bot( "allies" ); - } - else if ( axis.size < maxAxis ) + while ((allies.size < maxAllies || axis.size < maxAxis) && + add_balanced_bot(allies, maxAllies, axis, maxAxis)) { - bot = add_bot( "axis" ); - } + WAIT_SERVER_FRAME; - return isdefined( bot ); + allies = getPlayers("allies"); + axis = getPlayers("axis"); + } } -function monitor_bot_population( maxFree ) +function add_balanced_bot(allies, maxAllies, axis, maxAxis) { - level endon( "game_ended" ); - - if ( !maxFree ) + bot = undefined; + + if (allies.size < maxAllies && + (allies.size <= axis.size || axis.size >= maxAxis)) + { + bot = add_bot("allies"); + } + else if (axis.size < maxAxis) + { + bot = add_bot("axis"); + } + + return isdefined(bot); +} + +function monitor_bot_population(maxFree) +{ + level endon("game_ended"); + + if (!maxFree) { return; } - + // Initial Fill - players = getPlayers( ); - while ( players.size < maxFree ) + players = getPlayers(); + while (players.size < maxFree) { add_bot(); WAIT_SERVER_FRAME; - players = getPlayers( ); + players = getPlayers(); } - - while ( 1 ) + + while (1) { wait 3; - + // TODO: Get a player count that includes 'CON_CONNECTING' players - players = getPlayers( ); - - if ( players.size < maxFree ) + players = getPlayers(); + + if (players.size < maxFree) { add_bot(); } - else if ( players.size > maxFree ) + else if (players.size > maxFree) { - remove_best_bot( players ); + remove_best_bot(players); } } } -function remove_best_bot( players ) +function remove_best_bot(players) { - bots = filter_bots( players ); - - if ( !bots.size ) + bots = filter_bots(players); + + if (!bots.size) { return false; } - + // Prefer non-combat bots bestBots = []; - - foreach( bot in bots ) + + foreach(bot in bots) { // Don't kick bots in the process of connecting - if ( bot.sessionstate == "spectator" ) + if (bot.sessionstate == "spectator") { continue; } - - if ( bot.sessionstate == "dead" || !bot bot_combat::has_threat() ) + + if (bot.sessionstate == "dead" || !bot bot_combat::has_threat()) { bestBots[bestBots.size] = bot; } } - - if ( bestBots.size ) + + if (bestBots.size) { - remove_bot( bestBots[randomInt( bestBots.size )] ); + remove_bot(bestBots[randomInt(bestBots.size)]); } else { - remove_bot( bots[randomInt( bots.size )] ); + remove_bot(bots[randomInt(bots.size)]); } - + return true; } @@ -526,26 +525,26 @@ function remove_best_bot( players ) function choose_class() { - if ( IS_TRUE( level.disableClassSelection ) ) + if (IS_TRUE(level.disableClassSelection)) { return false; } - + currClass = self bot_loadout::get_current_class(); - if ( !isdefined( currClass ) || randomInt( 100 ) < VAL( level.botSettings.changeClassWeight, 0 ) ) + if (!isdefined(currClass) || randomInt(100) < VAL(level.botSettings.changeClassWeight, 0)) { - classIndex = randomInt( self.loadoutClasses.size ); + classIndex = randomInt(self.loadoutClasses.size); className = self.loadoutClasses[classIndex].name; } - - if ( !isdefined(className) || className === currClass ) + + if (!isdefined(className) || className == = currClass) { return false; } - - self notify( "menuresponse", MENU_CHANGE_CLASS, className ); - + + self notify("menuresponse", MENU_CHANGE_CLASS, className); + return true; } @@ -554,229 +553,229 @@ function choose_class() function use_killstreak() { - if ( !level.loadoutKillstreaksEnabled || - self emp::enemyEmpActive() ) + if (!level.loadoutKillstreaksEnabled || + self emp::enemyEmpActive()) { return; } - + weapons = self getWeaponsList(); inventoryWeapon = self getInventoryWeapon(); - - foreach( weapon in weapons ) - { - killstreak = killstreaks::get_killstreak_for_weapon( weapon ); - - if ( !isdefined( killstreak ) ) + + foreach(weapon in weapons) + { + killstreak = killstreaks::get_killstreak_for_weapon(weapon); + + if (!isdefined(killstreak)) { continue; } - - if ( weapon != inventoryWeapon && !self getWeaponAmmoClip( weapon ) ) + + if (weapon != inventoryWeapon && !self getWeaponAmmoClip(weapon)) { continue; } - - if ( self killstreakrules::isKillstreakAllowed( killstreak, self.team ) ) + + if (self killstreakrules::isKillstreakAllowed(killstreak, self.team)) { useWeapon = weapon; break; } } - - if ( !isdefined( useWeapon ) ) + + if (!isdefined(useWeapon)) { return; } - - killstreak_ref = killstreaks::get_menu_name( killstreak ); - - switch( killstreak_ref ) + + killstreak_ref = killstreaks::get_menu_name(killstreak); + + switch (killstreak_ref) { - case "killstreak_uav": - case "killstreak_counteruav": - case "killstreak_satellite": - case "killstreak_helicopter_player_gunner": - case "killstreak_raps": - case "killstreak_sentinel": - { - self switchToWeapon( useWeapon ); - break; - } - case "killstreak_ai_tank_drop": - { - self use_supply_drop( weapon ); - break; - } - case "killstreak_remote_missile": - { - self switchToWeapon( weapon ); - self waittill( "weapon_change_complete" ); - wait 1.5; - self bot::press_attack_button(); - return; - } + case "killstreak_uav": + case "killstreak_counteruav": + case "killstreak_satellite": + case "killstreak_helicopter_player_gunner": + case "killstreak_raps": + case "killstreak_sentinel": + { + self switchToWeapon(useWeapon); + break; + } + case "killstreak_ai_tank_drop": + { + self use_supply_drop(weapon); + break; + } + case "killstreak_remote_missile": + { + self switchToWeapon(weapon); + self waittill("weapon_change_complete"); + wait 1.5; + self bot::press_attack_button(); + return; + } } } -function get_closest_enemy( origin, on_radar ) +function get_closest_enemy(origin, on_radar) { - enemies = self get_enemies( on_radar ); - enemies = arraysort( enemies, origin ); + enemies = self get_enemies(on_radar); + enemies = arraysort(enemies, origin); - if ( enemies.size ) - return enemies[0]; + if (enemies.size) + return enemies[0]; - return undefined; + return undefined; } -function use_supply_drop( weapon ) +function use_supply_drop(weapon) { - if ( weapon == "inventory_supplydrop_mp" || weapon == "supplydrop_mp" ) - { - if ( gettime() - self.spawntime > 5000 ) - return; - } + if (weapon == "inventory_supplydrop_mp" || weapon == "supplydrop_mp") + { + if (gettime() - self.spawntime > 5000) + return; + } - yaw = ( 0, self.angles[1], 0 ); - dir = anglestoforward( yaw ); - dir = vectornormalize( dir ); - drop_point = self.origin + vectorscale( dir, 384 ); - end = drop_point + vectorscale( ( 0, 0, 1 ), 2048.0 ); + yaw = (0, self.angles[1], 0); + dir = anglestoforward(yaw); + dir = vectornormalize(dir); + drop_point = self.origin + vectorscale(dir, 384); + end = drop_point + vectorscale((0, 0, 1), 2048.0); - if ( !sighttracepassed( drop_point, end, 0, undefined ) ) - return; + if (!sighttracepassed(drop_point, end, 0, undefined)) + return; - if ( !sighttracepassed( self.origin, end, 0, undefined ) ) - return; + if (!sighttracepassed(self.origin, end, 0, undefined)) + return; - end = drop_point - vectorscale( ( 0, 0, 1 ), 32.0 ); + end = drop_point - vectorscale((0, 0, 1), 32.0); - if ( bullettracepassed( drop_point, end, 0, undefined ) ) - return; + if (bullettracepassed(drop_point, end, 0, undefined)) + return; - self addgoal( self.origin, 24, 4, "killstreak" ); + self addgoal(self.origin, 24, 4, "killstreak"); - if ( weapon == "missile_drone_mp" || weapon == "inventory_missile_drone_mp" ) - self lookat( drop_point + vectorscale( ( 0, 0, 1 ), 384.0 ) ); - else - self lookat( drop_point ); + if (weapon == "missile_drone_mp" || weapon == "inventory_missile_drone_mp") + self lookat(drop_point + vectorscale((0, 0, 1), 384.0)); + else + self lookat(drop_point); - wait 0.5; + wait 0.5; - if ( self getCurrentWeapon() != weapon ) - { - self thread weapon_switch_failsafe(); - self switchToWeapon( weapon ); + if (self getCurrentWeapon() != weapon) + { + self thread weapon_switch_failsafe(); + self switchToWeapon(weapon); - self waittill( "weapon_change_complete" ); - } + self waittill("weapon_change_complete"); + } - use_item( weapon ); - self switchToWeapon( self.lastnonkillstreakweapon ); - self clearlookat(); - self cancelgoal( "killstreak" ); + use_item(weapon); + self switchToWeapon(self.lastnonkillstreakweapon); + self clearlookat(); + self cancelgoal("killstreak"); } -function use_item( weapon ) +function use_item(weapon) { - self bot::press_attack_button(); - wait 0.5; + self bot::press_attack_button(); + wait 0.5; - for ( i = 0; i < 10; i++ ) - { - if ( self getCurrentWeapon() == weapon || self getCurrentWeapon() == "none" ) - self bot::press_attack_button(); - else - return; + for (i = 0; i < 10; i++) + { + if (self getCurrentWeapon() == weapon || self getCurrentWeapon() == "none") + self bot::press_attack_button(); + else + return; - wait 0.5; - } + wait 0.5; + } } -function killstreak_location( num, weapon ) +function killstreak_location(num, weapon) { - enemies = get_enemies(); + enemies = get_enemies(); - if ( !enemies.size ) - return; + if (!enemies.size) + return; - if ( !self switchToWeapon( weapon ) ) - return; + if (!self switchToWeapon(weapon)) + return; - self waittill( "weapon_change" ); + self waittill("weapon_change"); - self util::freeze_player_controls( true ); - wait_time = 1; + self util::freeze_player_controls(true); + wait_time = 1; - while ( !isdefined( self.selectinglocation ) || self.selectinglocation == 0 ) - { - wait 0.05; - wait_time -= 0.05; + while (!isdefined(self.selectinglocation) || self.selectinglocation == 0) + { + wait 0.05; + wait_time -= 0.05; - if ( wait_time <= 0 ) - { - self util::freeze_player_controls( false ); - self switchToWeapon( self.lastnonkillstreakweapon ); - return; - } - } + if (wait_time <= 0) + { + self util::freeze_player_controls(false); + self switchToWeapon(self.lastnonkillstreakweapon); + return; + } + } - wait 2; + wait 2; - for ( i = 0; i < num; i++ ) - { - enemies = get_enemies(); + for (i = 0; i < num; i++) + { + enemies = get_enemies(); - if ( enemies.size ) - { - enemy = randomInt( enemies ); - self notify( "confirm_location", enemy.origin, 0 ); - } + if (enemies.size) + { + enemy = randomInt(enemies); + self notify("confirm_location", enemy.origin, 0); + } - wait 0.25; - } + wait 0.25; + } - self util::freeze_player_controls( false ); + self util::freeze_player_controls(false); } function weapon_switch_failsafe() { - self endon( "death" ); - self endon( "disconnect" ); - self endon( "weapon_change_complete" ); - wait 10; - self notify( "weapon_change_complete" ); + self endon("death"); + self endon("disconnect"); + self endon("weapon_change_complete"); + wait 10; + self notify("weapon_change_complete"); } function has_radar() { - if ( level.teambased ) + if (level.teambased) { - return ( uav::HasUAV( self.team ) || satellite::HasSatellite( self.team ) ); + return (uav::HasUAV(self.team) || satellite::HasSatellite(self.team)); } - - return ( uav::HasUAV( self.entnum ) || satellite::HasSatellite( self.entnum ) ); + + return (uav::HasUAV(self.entnum) || satellite::HasSatellite(self.entnum)); } function has_minimap() { - if ( self IsEmpJammed() ) + if (self IsEmpJammed()) { return false; } - - if ( IS_TRUE( level.hardcoreMode ) ) + + if (IS_TRUE(level.hardcoreMode)) { return self has_radar(); } - + return true; } -function get_enemies( on_radar ) +function get_enemies(on_radar) { - if ( !isdefined( on_radar ) ) + if (!isdefined(on_radar)) { on_radar = false; } @@ -784,28 +783,28 @@ function get_enemies( on_radar ) enemies = self GetEnemies(); /# - for ( i = 0; i < enemies.size; i++ ) + for (i = 0; i < enemies.size; i++) { - if ( isplayer( enemies[i] ) && enemies[i] isInMoveMode( "ufo", "noclip" ) ) + if (isplayer(enemies[i]) && enemies[i] isInMoveMode("ufo", "noclip")) { - arrayRemoveIndex( enemies, i ); + arrayRemoveIndex(enemies, i); i--; } } #/ - if ( on_radar && !self has_radar() ) + if (on_radar && !self has_radar()) { - for ( i = 0; i < enemies.size; i++ ) + for (i = 0; i < enemies.size; i++) { - if ( !isdefined( enemies[i].lastFireTime ) ) + if (!isdefined(enemies[i].lastFireTime)) { - arrayRemoveIndex( enemies, i ); + arrayRemoveIndex(enemies, i); i--; } - else if ( GetTime() - enemies[i].lastFireTime > 2000 ) + else if (GetTime() - enemies[i].lastFireTime > 2000) { - arrayRemoveIndex( enemies, i ); + arrayRemoveIndex(enemies, i); i--; } } @@ -822,101 +821,101 @@ function set_rank() bot_ranks = []; human_ranks = []; - for ( i = 0; i < players.size; i++ ) + for (i = 0; i < players.size; i++) { - if ( players[i] == self ) + if (players[i] == self) continue; - if ( isdefined( players[i].pers[ "rank" ] ) ) + if (isdefined(players[i].pers["rank"])) { - if ( players[i] util::is_bot() ) + if (players[i] util::is_bot()) { - bot_ranks[ bot_ranks.size ] = players[i].pers[ "rank" ]; + bot_ranks[bot_ranks.size] = players[i].pers["rank"]; } else { - human_ranks[ human_ranks.size ] = players[i].pers[ "rank" ]; + human_ranks[human_ranks.size] = players[i].pers["rank"]; } } } - if( !human_ranks.size ) - human_ranks[ human_ranks.size ] = 10; + if (!human_ranks.size) + human_ranks[human_ranks.size] = 10; - human_avg = math::array_average( human_ranks ); + human_avg = math::array_average(human_ranks); - while ( bot_ranks.size + human_ranks.size < 5 ) + while (bot_ranks.size + human_ranks.size < 5) { // add some random ranks for better random number distribution - r = human_avg + randomIntRange( -5, 5 ); - rank = math::clamp( r, 0, level.maxRank ); - human_ranks[ human_ranks.size ] = rank; + r = human_avg + randomIntRange(-5, 5); + rank = math::clamp(r, 0, level.maxRank); + human_ranks[human_ranks.size] = rank; } - ranks = arrayCombine( human_ranks, bot_ranks, true, false ); + ranks = arrayCombine(human_ranks, bot_ranks, true, false); - avg = math::array_average( ranks ); - s = math::array_std_deviation( ranks, avg ); - - rank = Int( math::random_normal_distribution( avg, s, 0, level.maxRank ) ); - - while ( !isdefined( self.pers["codpoints"] ) ) + avg = math::array_average(ranks); + s = math::array_std_deviation(ranks, avg); + + rank = Int(math::random_normal_distribution(avg, s, 0, level.maxRank)); + + while (!isdefined(self.pers["codpoints"])) { wait 0.1; } - - self.pers[ "rank" ] = rank; - self.pers[ "rankxp" ] = rank::getRankInfoMinXP( rank ); - self setRank( rank ); + self.pers["rank"] = rank; + self.pers["rankxp"] = rank::getRankInfoMinXP(rank); + + self setRank(rank); self rank::syncXPStat(); } function init_bot_gametype() { - switch( level.gameType ) + switch (level.gameType) { - case "ball": - bot_ball::init(); - return true; - case "conf": - bot_conf::init(); - return true; - case "ctf": - bot_ctf::init(); - return true; - case "dem": - bot_dem::init(); - return true; - case "dm": - return true; - case "dom": - bot_dom::init(); - return true; - case "escort": - bot_escort::init(); - return true; + case "ball": + bot_ball::init(); + return true; + case "conf": + bot_conf::init(); + return true; + case "ctf": + bot_ctf::init(); + return true; + case "dem": + bot_dem::init(); + return true; + case "dm": + return true; + case "dom": + bot_dom::init(); + return true; + case "escort": + bot_escort::init(); + return true; // case "infect": // return true; - case "gun": - return true; - case "koth": - bot_koth::init(); - return true; - case "sd": - bot_sd::init(); - return true; - case "clean": - bot_clean::init(); - return true; - case "tdm": - return true; - case "sas": - return true; - case "prop": - return true; - case "sniperonly": - return true; + case "gun": + return true; + case "koth": + bot_koth::init(); + return true; + case "sd": + bot_sd::init(); + return true; + case "clean": + bot_clean::init(); + return true; + case "tdm": + return true; + case "sas": + return true; + case "prop": + return true; + case "sniperonly": + return true; } return false; @@ -924,99 +923,99 @@ function init_bot_gametype() function get_bot_settings() { - switch ( getDvarInt( "bot_difficulty", 1 ) ) + switch (getDvarInt("bot_difficulty", 1)) { - case 0: - bundleName = "bot_mp_easy"; - break; - - case 1: - bundleName = "bot_mp_normal"; - break; - case 2: - bundleName = "bot_mp_hard"; - break; - case 3: - default: - bundleName = "bot_mp_veteran"; - break; + case 0: + bundleName = "bot_mp_easy"; + break; + + case 1: + bundleName = "bot_mp_normal"; + break; + case 2: + bundleName = "bot_mp_hard"; + break; + case 3: + default: + bundleName = "bot_mp_veteran"; + break; } - - return struct::get_script_bundle( "botsettings", bundleName ); + + return struct::get_script_bundle("botsettings", bundleName); } -function friend_goal_in_radius( goal_name, origin, radius ) +function friend_goal_in_radius(goal_name, origin, radius) { return 0; } -function friend_in_radius( goal_name, origin, radius ) +function friend_in_radius(goal_name, origin, radius) { return false; } function get_friends() { - return []; + return[]; } -function bot_vehicle_weapon_ammo( weaponName ) +function bot_vehicle_weapon_ammo(weaponName) { return false; } -function navmesh_points_visible( origin, point ) +function navmesh_points_visible(origin, point) { return false; } -function dive_to_prone( exit_stance ) +function dive_to_prone(exit_stance) { - + } -/# +/ # // Devgui //======================================== -function bot_devgui_cmd( cmd ) +function bot_devgui_cmd(cmd) { - cmdTokens = strtok( cmd," "); - - if ( cmdTokens.size == 0 ) + cmdTokens = strtok(cmd, " "); + + if (cmdTokens.size == 0) { return false; } - + host = util::getHostPlayerForBots(); team = get_host_team(); - - switch( cmdTokens[0] ) + + switch (cmdTokens[0]) { case "spawn_enemy": - team = util::getotherteam(team); - case "spawn_friendly": + team = util::getotherteam(team); + case "spawn_friendly": count = 1; - if ( cmdTokens.size > 1 ) + if (cmdTokens.size > 1) { - count = int( cmdTokens[1] ); + count = int(cmdTokens[1]); } - for( i = 0; i < count; i++ ) + for (i = 0; i < count; i++) { - add_bot( team ); + add_bot(team); } return true; case "remove_enemy": team = util::getotherteam(team); case "remove_friendly": - remove_bots( undefined, team ); + remove_bots(undefined, team); return true; case "fixed_spawn_enemy": - team = util::getotherteam(team); - case "fixed_spawn_friendly": - bot = add_bot_at_eye_trace( team ); - if ( isdefined( bot ) ) + team = util::getotherteam(team); + case "fixed_spawn_friendly": + bot = add_bot_at_eye_trace(team); + if (isdefined(bot)) { bot thread fixed_spawn_override(); } @@ -1024,9 +1023,9 @@ function bot_devgui_cmd( cmd ) case "player_weapon": players = getPlayers(); - foreach( player in players ) + foreach(player in players) { - if ( !player util::is_bot() ) + if (!player util::is_bot()) { continue; } @@ -1035,11 +1034,11 @@ function bot_devgui_cmd( cmd ) player weapons::detach_all_weapons(); player takeAllWeapons(); - player giveWeapon( weapon ); - player switchToWeapon( weapon ); - player setSpawnWeapon( weapon ); + player giveWeapon(weapon); + player switchToWeapon(weapon); + player setSpawnWeapon(weapon); - player teams::set_player_model( player.team, weapon ); + player teams::set_player_model(player.team, weapon); } return true; } @@ -1049,71 +1048,69 @@ function bot_devgui_cmd( cmd ) function system_devgui_gadget_think() { - setDvar( "devgui_bot_gadget", "" ); + setDvar("devgui_bot_gadget", ""); - for ( ;; ) + for (;; ) { - wait( 1 ); + wait(1); - gadget = getDvarString( "devgui_bot_gadget" ); - - if ( gadget != "" ) + gadget = getDvarString("devgui_bot_gadget"); + + if (gadget != "") { - bot_turn_on_gadget( getWeapon(gadget) ); - setDvar( "devgui_bot_gadget", "" ); - } + bot_turn_on_gadget(getWeapon(gadget)); + setDvar("devgui_bot_gadget", ""); + } } } -function bot_turn_on_gadget( gadget ) +function bot_turn_on_gadget(gadget) { players = getPlayers(); - - foreach( player in players ) + + foreach(player in players) { - if ( !player util::is_bot() ) + if (!player util::is_bot()) { continue; } - + host = util::getHostPlayer(); weapon = host getCurrentWeapon(); - - if ( !isdefined( weapon ) || weapon == level.weaponNone || weapon == level.weaponNull ) + + if (!isdefined(weapon) || weapon == level.weaponNone || weapon == level.weaponNull) { - weapon = getWeapon( "smg_standard" ); + weapon = getWeapon("smg_standard"); } player weapons::detach_all_weapons(); player takeAllWeapons(); - player giveWeapon( weapon ); - player switchToWeapon( weapon ); - player setSpawnWeapon( weapon ); + player giveWeapon(weapon); + player switchToWeapon(weapon); + player setSpawnWeapon(weapon); - player teams::set_player_model( player.team, weapon ); - - player giveWeapon( gadget ); - slot = player gadgetGetSlot( gadget ); - player gadgetPowerSet( slot, 100.0 ); - player botPressButtonForGadget( gadget ); - } + player teams::set_player_model(player.team, weapon); + + player giveWeapon(gadget); + slot = player gadgetGetSlot(gadget); + player gadgetPowerSet(slot, 100.0); + player botPressButtonForGadget(gadget); + } } - - function fixed_spawn_override() { - self endon( "disconnect" ); - + self endon("disconnect"); + spawnOrigin = self.origin; spawnAngles = self.angles; - - while( 1 ) + + while (1) { - self waittill( "spawned_player" ); - - self setOrigin( spawnOrigin ); - self setPlayerAngles( spawnAngles ); + self waittill("spawned_player"); + + self setOrigin(spawnOrigin); + self setPlayerAngles(spawnAngles); } } From b4b5ce5ae953bea928acde512d561137a68673e9 Mon Sep 17 00:00:00 2001 From: WantedDV <122710241+WantedDV@users.noreply.github.com> Date: Sat, 13 May 2023 13:08:13 -0230 Subject: [PATCH 25/33] non-empty string check --- data/scripts/mp/bots/_bot.gsc_raw | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/data/scripts/mp/bots/_bot.gsc_raw b/data/scripts/mp/bots/_bot.gsc_raw index cd6b335d..03e00351 100644 --- a/data/scripts/mp/bots/_bot.gsc_raw +++ b/data/scripts/mp/bots/_bot.gsc_raw @@ -1056,7 +1056,7 @@ function system_devgui_gadget_think() gadget = getDvarString("devgui_bot_gadget"); - if (gadget != "") + if (gadget.size == 0) { bot_turn_on_gadget(getWeapon(gadget)); setDvar("devgui_bot_gadget", ""); From f14ea87e44977326cedb9bf22cd13d93d7591003 Mon Sep 17 00:00:00 2001 From: FutureRave Date: Sat, 13 May 2023 17:26:17 +0100 Subject: [PATCH 26/33] maint: clean client_t struct --- src/client/component/auth.cpp | 8 ++++---- src/client/game/structs.hpp | 12 +++++++++++- src/client/game/utils.cpp | 4 ++-- 3 files changed, 17 insertions(+), 7 deletions(-) diff --git a/src/client/component/auth.cpp b/src/client/component/auth.cpp index 26c31a33..b52b9eb0 100644 --- a/src/client/component/auth.cpp +++ b/src/client/component/auth.cpp @@ -98,7 +98,7 @@ namespace auth { static const auto is_first = [] { - static utils::nt::handle<> mutex = CreateMutexA(nullptr, FALSE, "boiii_mutex"); + static utils::nt::handle mutex = CreateMutexA(nullptr, FALSE, "boiii_mutex"); return mutex && GetLastError() != ERROR_ALREADY_EXISTS; }(); @@ -134,9 +134,9 @@ namespace auth const auto& fragment_packet = packet_buffer.get_buffer(); - game::NET_OutOfBandData( - sock, adr, fragment_packet.data(), - static_cast(fragment_packet.size())); + game::NET_OutOfBandData(sock, adr, + fragment_packet.data(), + static_cast(fragment_packet.size())); }); } diff --git a/src/client/game/structs.hpp b/src/client/game/structs.hpp index bc861685..56aac009 100644 --- a/src/client/game/structs.hpp +++ b/src/client/game/structs.hpp @@ -1579,9 +1579,19 @@ namespace game SV_CMD_RELIABLE_0 = 0x1, }; + enum + { + CS_FREE = 0x0, + CS_ZOMBIE = 0x1, + CS_RECONNECTING = 0x2, + CS_CONNECTED = 0x3, + CS_CLIENTLOADING = 0x4, + CS_ACTIVE = 0x5, + }; + struct client_s { - int client_state; + int state; char __pad0[0x28]; netadr_t address; char __pad1[20468]; diff --git a/src/client/game/utils.cpp b/src/client/game/utils.cpp index 4f6fb99a..5ebe4131 100644 --- a/src/client/game/utils.cpp +++ b/src/client/game/utils.cpp @@ -205,7 +205,7 @@ namespace game } auto& client = client_states[index]; - if (client.client_state <= 0) + if (client.state == CS_FREE) { return false; } @@ -238,7 +238,7 @@ namespace game { foreach_client([&](client_s& client, const size_t index) { - if (client.client_state > 0) + if (client.state != CS_FREE) { callback(client, index); } From b42ba37f8ceaf07796163e0069ec61bfe35ebfb8 Mon Sep 17 00:00:00 2001 From: WantedDV <122710241+WantedDV@users.noreply.github.com> Date: Sat, 13 May 2023 13:43:40 -0230 Subject: [PATCH 27/33] update compiled script --- data/scripts/mp/bots/_bot.gsc | Bin 19044 -> 19044 bytes data/scripts/mp/bots/_bot.gsc_raw | 8 ++++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/data/scripts/mp/bots/_bot.gsc b/data/scripts/mp/bots/_bot.gsc index ca508a4ff04db204cfbcf29bf04d1a046cc49a73..4c562fbe05f66c90e974c24f99ae0344f3e75845 100644 GIT binary patch delta 1528 zcmZ8gdrVVT9R8i#a)An$!n&yhwp&WyEp2a0Yunq_2O=UB1Z;4E0;>fTH+2XiV`aw2 z;xN-u-PHOB=nOI09Cf+@>K{JhoNh7BIF|v&ImHY!qqyldaOVV?B|FK@J>Pe}?|08R z_xs%qp}QgEYMoOuD^Ub#V`uv+K8*)>lnby$H2(f%F2EEkK)oHnpFjS5qy^ZHbr#UV z%`aSkCQFX$kDY_1I?I}lU#G$%X<=X4?Y|; zp;RA5{bX;So?alivU_bUnEW-VwD%h@y1mY@SrR#v-j*y`c5q=YR4EENfA}K@tY!Sr z`L2hN>4qEuI@G?I^9IW;2h@|5B2z9fEW>Kmkjq&?@!If>^MJ=bBUH@c>omzXW77$) zGcv4C)-lJ!tC z;G!soJuC-)X-lE@V2;>BKA_=ZJppBxG`9Q~yRafg;gbqYyYT`CyfbIDukLT(}LZ0fj&>ouw7Ex`5_1PNmZ2tq;PSz5bnD- zB8FASV4h?8Zq&Gh@H?bbeUFS`c@=Y(~$o8Pe}iAHTi=gnZ)Gq$+EQ4?L-!9hm!gQ=Le>Eq1tPFj9W0kx+VOB#q? ztOSnSShcpU5a80xum+a@$kMNitWe(&^klwW6z)Dmgeo_~KGVh7@CFvI)Pw!vjJ8RH zZ({pcL2;Hgrl#AtU#%Mxvn?wW)$gt*Yh>t^RAuH%30t9TejtBTdIMA*(`q=G`FV@O zf0n0|ZtW`Hlg+BN-4--=iGHtUbmZiUK{r$myE5E)DEpKl2d26rEzR5e6_-2-xC_Rd zNV|lenFZbwnQc+N$NQcUH!{F6e05Kx@YV%WKL`G*1x05%9uj_=;f}67%{n4n^G{7; zyTtasE-+LeIG&1|`*gUm+#!F4uu9cXf2$}BK(@&xARKWHdsI6kmu!ACqcFVx>Fq3l zKGskhbzHYh{(e0N@Im#=_Ne1(`n;`1GXUwxsBYGx@AmG9tg?Sh(FhPXloVn3p7`Kh zZ2eD$xJMY1Mjf|NoCKF4eKb*qYsHwve?jWk8}WuEKVwW{KY>#oV@%>cp|>Ph07z=b zG2%)wCTZr!bM2wFf!iY30!mCAiC;tL<>!;NK delta 1528 zcmZ8hdrVVT9R8h4xj2Q451B99`ogZcnm*P^1b4HYf5sDmkD zHb-^KV3`3?NS3MVHs^CQQ?|KBwnTJUGBF$5SXBPlNCsxW&Pi#O>?Swu_nq(i-TOP| z``xh+8VjMEwxX&PPw*kFxc$h%(+L0%3jsR#k>AiN0EPo-H3N7`BKKP=fTLJv1Qpyl zpYwN$unlz_hFZ0eGu%4^HKK~d#9ODr#i?EK!o04}PD5pp!8&N~g%ox7}57)S5@5i&i#^G8bhL2oYujk+&f3@E=Llaj2J-THKS%fvdJvI^JCv z&eavfpuz5Twk)W(tpR{RW51#l1dM=DOQ6uK1lfinTVuwaryq{oz{|jLke#C_*_(1V zZW+OyVgd6=vOSM@U1I5T-$XQ-ABR#K$@+l#f~s{cnIZql#VHc9-gaCLlJ-{qaa>H= zW3Ha9EK{B)wl2DUC{b>_l$gS6@0eZ8T9oi1S(XECsQ=w zP_PswV9sh`{RZ6dI|a!O@_=M{oW4fan-OR4aq!BDl?hg!_cD7uCpM!-XVS!K8dTf0 zx6rIL);hrP%nz(R4tlj)dD9V$wYWsQ+(p^n+hUrJi3H4qh+cD83%bPmx_hKBBjLey z^8qAaW^JGNd29}r$=i!dz$4ZQ4$P^ zkbYDX5k`5xx`acV-09PPLL=IU)yt$bac7S&-WVj7fu96Rb2hBz3Y|n2>!) zM0?j6;hA)Uv|#~%#zb`eEZMDi_L_-q+^T_!=mRadu)+|(*`%S}I~Zubuuiy(=wB1T zF4B-!=8yn8H z89bu0s=wM5FScbNF;6$FoSFP+ixU~ZSw6o!9yv5x!H`ZtWIwle`nGUHv zdhf)!C3wiM_U>M9kxn73^8b<wfFvub zS7S^96v33yi7^RI1dEZe5fkJ9qlO7$zy}w_{P3f~%T!7%1#kmzTo>M;+xSlI{%}=~ Sa1m}dgb^81gca5JZT Date: Sat, 13 May 2023 17:52:15 +0100 Subject: [PATCH 28/33] status: rename xuid to guid --- src/client/component/status.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/component/status.cpp b/src/client/component/status.cpp index 620260a3..83c6b686 100644 --- a/src/client/component/status.cpp +++ b/src/client/component/status.cpp @@ -37,7 +37,7 @@ namespace status utils::hook::call(game::select(0x142246EDE, 0x14052C5CE), print_client_xuid); utils::hook::copy_string(game::select(0x143050480, 0x140E85A20), - "num score ping xuid name address qport \n"); + "num score ping guid name address qport \n"); utils::hook::copy_string(game::select(0x1430504E0, 0x140E85A80), "--- ----- ---- ---------------- ---------------- ------------------------ ------ \n"); } From ebbb3fe1958a96575a47deac4300e3b587ccc05c Mon Sep 17 00:00:00 2001 From: Edo Date: Sat, 13 May 2023 18:11:19 +0100 Subject: [PATCH 29/33] Update status.cpp --- src/client/component/status.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/component/status.cpp b/src/client/component/status.cpp index 83c6b686..620260a3 100644 --- a/src/client/component/status.cpp +++ b/src/client/component/status.cpp @@ -37,7 +37,7 @@ namespace status utils::hook::call(game::select(0x142246EDE, 0x14052C5CE), print_client_xuid); utils::hook::copy_string(game::select(0x143050480, 0x140E85A20), - "num score ping guid name address qport \n"); + "num score ping xuid name address qport \n"); utils::hook::copy_string(game::select(0x1430504E0, 0x140E85A80), "--- ----- ---- ---------------- ---------------- ------------------------ ------ \n"); } From c573ba893f4b3ddef745b119cefa1eacae2470dd Mon Sep 17 00:00:00 2001 From: Edo Date: Sat, 13 May 2023 19:30:42 +0100 Subject: [PATCH 30/33] hot-fix: apply lobby_min_players only on server (#697) --- src/client/component/patches.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/component/patches.cpp b/src/client/component/patches.cpp index e1794351..f4302627 100644 --- a/src/client/component/patches.cpp +++ b/src/client/component/patches.cpp @@ -30,7 +30,7 @@ namespace patches void scr_get_num_expected_players() { const auto mode = game::Com_SessionMode_GetMode(); - if (mode == game::MODE_ZOMBIES || mode == game::MODE_CAMPAIGN) + if (game::is_server() && (mode == game::MODE_ZOMBIES || mode == game::MODE_CAMPAIGN)) { game::Scr_AddInt(game::SCRIPTINSTANCE_SERVER, lobby_min_players->current.value.integer); } From 644e01d1d4f10d0d6e38dff20ace22e65d4da620 Mon Sep 17 00:00:00 2001 From: FutureRave Date: Sat, 13 May 2023 19:56:36 +0100 Subject: [PATCH 31/33] fix: better scr_get_num_expected_players patch --- src/client/component/patches.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/src/client/component/patches.cpp b/src/client/component/patches.cpp index f4302627..6f364ccf 100644 --- a/src/client/component/patches.cpp +++ b/src/client/component/patches.cpp @@ -29,13 +29,19 @@ namespace patches void scr_get_num_expected_players() { + auto expected_players = game::LobbyHost_GetClientCount(game::LOBBY_TYPE_GAME, + game::LOBBY_CLIENT_TYPE_ALL); + const auto mode = game::Com_SessionMode_GetMode(); - if (game::is_server() && (mode == game::MODE_ZOMBIES || mode == game::MODE_CAMPAIGN)) + if ((mode == game::MODE_ZOMBIES || mode == game::MODE_CAMPAIGN)) { - game::Scr_AddInt(game::SCRIPTINSTANCE_SERVER, lobby_min_players->current.value.integer); + if (const auto min_players = lobby_min_players->current.value.integer) + { + expected_players = min_players; + } } - const auto num_expected_players = std::max(1, game::LobbyHost_GetClientCount(game::LOBBY_TYPE_GAME, game::LOBBY_CLIENT_TYPE_ALL)); + const auto num_expected_players = std::max(1, expected_players); game::Scr_AddInt(game::SCRIPTINSTANCE_SERVER, num_expected_players); } @@ -73,7 +79,7 @@ namespace patches // make sure reliableAck is not negative or too big utils::hook::call(game::select(0x14225489C, 0x140537C4C), sv_execute_client_messages_stub); - lobby_min_players = game::register_dvar_int("lobby_min_players", 1, 1, 8, game::DVAR_NONE, ""); + lobby_min_players = game::register_dvar_int("lobby_min_players", 0, 0, 8, game::DVAR_NONE, ""); utils::hook::jump(game::select(0x141A7BCF0, 0x1402CB900), scr_get_num_expected_players, true); } }; From 48f21ee71daf90d7184ca11e40cc275848b927b5 Mon Sep 17 00:00:00 2001 From: Edo Date: Sat, 13 May 2023 20:45:55 +0100 Subject: [PATCH 32/33] status: thread local --- src/client/component/status.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/client/component/status.cpp b/src/client/component/status.cpp index 620260a3..a9e3380f 100644 --- a/src/client/component/status.cpp +++ b/src/client/component/status.cpp @@ -8,7 +8,7 @@ namespace status { namespace { - int client_num_; + thread_local int client_num_; void print_client_num(int channel, int label, const char* fmt, const int client_num) { From c9586f964997fbd059882ada731cc34ab7fda412 Mon Sep 17 00:00:00 2001 From: momo5502 Date: Sun, 14 May 2023 09:13:44 +0200 Subject: [PATCH 33/33] Small cleanup --- src/client/component/status.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/client/component/status.cpp b/src/client/component/status.cpp index a9e3380f..2fd8bfab 100644 --- a/src/client/component/status.cpp +++ b/src/client/component/status.cpp @@ -8,17 +8,17 @@ namespace status { namespace { - thread_local int client_num_; + thread_local int g_client_num{0}; - void print_client_num(int channel, int label, const char* fmt, const int client_num) + void print_client_num(const int channel, const int label, const char* fmt, const int client_num) { - client_num_ = client_num; + g_client_num = client_num; game::Com_Printf(channel, label, fmt, client_num); } - void print_client_xuid(int channel, int label, [[maybe_unused]] const char* fmt, const uint64_t xuid) + void print_client_xuid(const int channel, const int label, [[maybe_unused]] const char* fmt, const uint64_t xuid) { - if (game::SV_IsTestClient(client_num_)) + if (game::SV_IsTestClient(g_client_num)) { game::Com_Printf(channel, label, "%16s ", "bot0"); return;