diff --git a/data/ui_scripts/stats/__init__.lua b/data/ui_scripts/stats/__init__.lua index ec928c95..8fa3bc88 100644 --- a/data/ui_scripts/stats/__init__.lua +++ b/data/ui_scripts/stats/__init__.lua @@ -5,7 +5,20 @@ end DataSources.MPStatsSettings = DataSourceHelpers.ListSetup( "MPStatsSettings", function ( controller ) local optionsTable = {} - table.insert( optionsTable, CoD.OptionsUtility.CreateDvarSettings( controller, "Unlock all loot", "Whether loot should be locked based on the player's stats or always unlocked.", "MPStatsSettings_unlock_loot", "cg_unlockall_loot", { + local updateDvar = function(f1_arg0, f1_arg1, f1_arg2, dvarName, f1_arg4) + local oldValue = Engine.DvarInt( nil, dvarName ) + local newValue = f1_arg1.value + UpdateInfoModels( f1_arg1 ) + if oldValue == newValue then + return + end + Engine.SetDvar( dvarName, f1_arg1.value ) + if dvarName == "cg_unlockall_loot" then + Engine.SetDvar( "ui_enableAllHeroes", f1_arg1.value ) + end + end + + table.insert( optionsTable, CoD.OptionsUtility.CreateDvarSettings( controller, "Unlock All Loot", "Whether loot should be locked based on the player's stats or always unlocked.", "MPStatsSettings_unlock_loot", "cg_unlockall_loot", { { option = "MENU_DISABLED", value = 0, @@ -15,16 +28,165 @@ DataSources.MPStatsSettings = DataSourceHelpers.ListSetup( "MPStatsSettings", fu option = "MENU_ENABLED", value = 1 }, - }, nil, function(f1_arg0, f1_arg1, f1_arg2, dvarName, f1_arg4) - local oldValue = Engine.DvarInt( nil, dvarName ) - local newValue = f1_arg1.value - UpdateInfoModels( f1_arg1 ) - if oldValue == newValue then - return - end - Engine.SetDvar( dvarName, f1_arg1.value ) - Engine.SetDvar( "ui_enableAllHeroes", f1_arg1.value ) - end) ) + }, nil, updateDvar )) + if Engine.CurrentSessionMode() == Enum.eModes.MODE_MULTIPLAYER then + table.insert( optionsTable, CoD.OptionsUtility.CreateDvarSettings( controller, "Unlock All Purchases", "All items that need to be purchased with unlock tokens are unlocked.", "MPStatsSettings_purchase_all", "cg_unlockall_purchases", { + { + option = "MENU_DISABLED", + value = 0, + default = true + }, + { + option = "MENU_ENABLED", + value = 1 + }, + }, nil, updateDvar )) + end + table.insert( optionsTable, CoD.OptionsUtility.CreateDvarSettings( controller, "Unlock All Attachments", "All attachments on weapons are unlocked.", "MPStatsSettings_unlockall_attachments", "cg_unlockall_attachments", { + { + option = "MENU_DISABLED", + value = 0, + default = true + }, + { + option = "MENU_ENABLED", + value = 1 + }, + }, nil, updateDvar )) + -- Placeholder for later + --[[table.insert( optionsTable, CoD.OptionsUtility.CreateDvarSettings( controller, "Unlock all camos", "All camos on weapons are unlocked.", "MPStatsSettings_unlockall_camos", "cg_unlockall_camos", { + { + option = "MENU_DISABLED", + value = 0, + default = true + }, + { + option = "MENU_ENABLED", + value = 1 + }, + }, nil, updateDvar ))]] + + 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 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 + end + end + + if not hasDefault then + table.insert( rankObjs, { + name = currentRank, + value = currentRank - 1, + default = true, + title = "Rank Level", + desc = "" + }) + end + + local prestigeTable = {} + for i = 0, 10 do + table.insert( prestigeTable, { + name = i == 0 and "None" or i, + value = i, + default = i == CoD.PrestigeUtility.GetCurrentPLevel( controller ), + title = "Prestige", + desc = "" + }) + end + + local createSettingsDatasource = function ( controller, datasourceName, optionsTable, currentValue, loopEdges, action ) + if currentValue == nil then + currentValue = 0 + end + DataSources[datasourceName] = DataSourceHelpers.ListSetup( datasourceName, function ( f47_arg0 ) + local f47_local0 = {} + for f47_local4, f47_local5 in ipairs( optionsTable ) do + table.insert( f47_local0, { + models = { + text = optionsTable[f47_local4].name + }, + properties = { + title = optionsTable[f47_local4].title, + desc = optionsTable[f47_local4].desc, + image = optionsTable[f47_local4].image, + value = optionsTable[f47_local4].value, + default = optionsTable[f47_local4].default, + action = action, + selectIndex = optionsTable[f47_local4].value == currentValue, + loopEdges = loopEdges, + showChangeIndicator = function ( f48_arg0, f48_arg1, f48_arg2 ) + return f48_arg0.default ~= true + end + } + } ) + end + f47_local0[1].properties.first = true + f47_local0[#optionsTable].properties.last = true + return f47_local0 + end, nil, nil, nil ) + return datasourceName + end + + table.insert( optionsTable, { + models = { + name = "Rank Level", + 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) + 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" + 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.Exec( f1_arg0, "uploadstats " .. tostring( Engine.CurrentSessionMode() ) ) + end ) + }, + properties = { + revert = function ( f50_arg0 ) end + } + }) + + table.insert( optionsTable, { + models = { + name = "Prestige", + 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) + 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() ) ) + end ) + }, + properties = { + revert = function ( f50_arg0 ) end + } + }) return optionsTable end) @@ -33,8 +195,8 @@ if Dvar.cg_unlockall_loot:get() == true then Engine.SetDvar( "ui_enableAllHeroes", 1 ) end -LUI.createMenu.MPStatsMenu = function ( controller ) - local self = CoD.Menu.NewForUIEditor( "MPStatsMenu" ) +LUI.createMenu.BoiiiStatsMenu = function ( controller ) + local self = CoD.Menu.NewForUIEditor( "BoiiiStatsMenu" ) if PreLoadFunc then PreLoadFunc( self, controller ) end @@ -43,13 +205,13 @@ LUI.createMenu.MPStatsMenu = function ( controller ) self:setLeftRight( true, true, 0, 0 ) self:setTopBottom( true, true, 0, 0 ) self:playSound( "menu_open", controller ) - self.buttonModel = Engine.CreateModel( Engine.GetModelForController( controller ), "MPStatsMenu.buttonPrompts" ) + self.buttonModel = Engine.CreateModel( Engine.GetModelForController( controller ), "BoiiiStatsMenu.buttonPrompts" ) self.anyChildUsesUpdateState = true local GameSettingsBackground = CoD.GameSettings_Background.new( self, controller ) GameSettingsBackground:setLeftRight( true, true, 0, 0 ) GameSettingsBackground:setTopBottom( true, true, 0, 0 ) - GameSettingsBackground.MenuFrame.titleLabel:setText( Engine.Localize( "STATS SETTINGS" ) ) + GameSettingsBackground.MenuFrame.titleLabel: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 ) @@ -95,7 +257,7 @@ LUI.createMenu.MPStatsMenu = function ( controller ) LUI.OverrideFunction_CallOriginalSecond( self, "close", function ( element ) element.GameSettingsBackground:close() element.Options:close() - Engine.UnsubscribeAndFreeModel( Engine.GetModel( Engine.GetModelForController( controller ), "MPStatsMenu.buttonPrompts" ) ) + Engine.UnsubscribeAndFreeModel( Engine.GetModel( Engine.GetModelForController( controller ), "BoiiiStatsMenu.buttonPrompts" ) ) end ) if PostLoadFunc then @@ -109,7 +271,7 @@ CoD.LobbyButtons.MP_STATS = { stringRef = "STATS", action = function ( self, element, controller, param, menu ) SetPerControllerTableProperty( controller, "disableGameSettingsOptions", true ) - OpenPopup( menu, "MPStatsMenu", controller ) + OpenPopup( menu, "BoiiiStatsMenu", controller ) end, customId = "btnMPStats" } @@ -240,6 +402,26 @@ CoD.LobbyMenus.MPButtonsOnline = function ( f26_arg0, f26_arg1, f26_arg2 ) AddSmallButton( f26_arg0, f26_arg1, CoD.LobbyButtons.MP_STATS ) end +CoD.LobbyMenus.ZMButtonsOnline = function ( f33_arg0, f33_arg1, f33_arg2 ) + if IsStarterPack() then + AddSmallButton( f33_arg0, f33_arg1, CoD.LobbyButtons.QUIT ) + return + elseif f33_arg2 == 1 then + AddLargeButton( f33_arg0, f33_arg1, CoD.LobbyButtons.ZM_SOLO_GAME ) + AddLargeButton( f33_arg0, f33_arg1, CoD.LobbyButtons.ZM_FIND_MATCH ) + AddLargeButton( f33_arg0, f33_arg1, CoD.LobbyButtons.ZM_CUSTOM_GAMES ) + AddLargeButton( f33_arg0, f33_arg1, CoD.LobbyButtons.THEATER_ZM ) + AddSpacer( f33_arg1 ) + end + AddLargeButton( f33_arg0, f33_arg1, CoD.LobbyButtons.ZM_BUBBLEGUM_BUFFS ) + -- Disable these for now, demonware emulation still needs to be implemented + --AddLargeButton( f33_arg0, f33_arg1, CoD.LobbyButtons.ZM_MEGACHEW_FACTORY ) + --AddLargeButton( f33_arg0, f33_arg1, CoD.LobbyButtons.ZM_GOBBLEGUM_RECIPES ) + AddLargeButton( f33_arg0, f33_arg1, CoD.LobbyButtons.ZM_BUILD_KITS ) + AddSpacer( f33_arg1 ) + AddSmallButton( f33_arg0, f33_arg1, CoD.LobbyButtons.MP_STATS ) +end + local targetButtons = { [LobbyData.UITargets.UI_MAIN.id] = CoD.LobbyMenus.ModeSelect, [LobbyData.UITargets.UI_MODESELECT.id] = CoD.LobbyMenus.ModeSelect, diff --git a/src/client/component/dvars.cpp b/src/client/component/dvars.cpp index 8bf1b58c..1e74871d 100644 --- a/src/client/component/dvars.cpp +++ b/src/client/component/dvars.cpp @@ -116,7 +116,7 @@ namespace dvars } //TODO: Fix archive dvars not stripping names from registered dvars - if (dvar->debugName == "cg_unlockall_loot"s) + if (dvar->debugName == "cg_unlockall_loot"s || dvar->debugName == "cg_unlockall_purchases"s || dvar->debugName == "cg_unlockall_attachments"s || dvar->debugName == "cg_unlockall_camos"s) { return true; } diff --git a/src/client/component/loot.cpp b/src/client/component/loot.cpp index b60de531..6d58a5c0 100644 --- a/src/client/component/loot.cpp +++ b/src/client/component/loot.cpp @@ -11,10 +11,16 @@ namespace loot namespace { game::dvar_t* dvar_cg_unlockall_loot; + game::dvar_t* dvar_cg_unlockall_purchases; + game::dvar_t* dvar_cg_unlockall_attachments; + game::dvar_t* dvar_cg_cg_unlockall_camos; utils::hook::detour loot_getitemquantity_hook; utils::hook::detour liveinventory_getitemquantity_hook; utils::hook::detour liveinventory_areextraslotspurchased_hook; + utils::hook::detour bg_unlockablesisitempurchased_hook; + utils::hook::detour bg_unlockablesisitemattachmentlocked_hook; + utils::hook::detour bg_unlockablesisattachmentslotlocked_hook; int loot_getitemquantity_stub(const game::ControllerIndex_t controller_index, const game::eModes mode, const int item_id) @@ -53,6 +59,36 @@ namespace loot return liveinventory_areextraslotspurchased_hook.invoke(controller_index); } + + bool bg_unlockablesisitempurchased_stub(game::eModes mode, const game::ControllerIndex_t controller_index, int item_index) + { + if (dvar_cg_unlockall_purchases->current.enabled) + { + return true; + } + + return bg_unlockablesisitempurchased_hook.invoke(mode, controller_index, item_index); + } + + bool bg_unlockablesisitemattachmentlocked_stub(game::eModes mode, const game::ControllerIndex_t controller_index, int item_index, int attachment_num) + { + if (dvar_cg_unlockall_attachments->current.enabled) + { + return false; + } + + return bg_unlockablesisitemattachmentlocked_hook.invoke(mode, controller_index, item_index, attachment_num); + } + + bool bg_unlockablesisattachmentslotlocked_stub(game::eModes mode, const game::ControllerIndex_t controller_index, int item_index, int attachment_slot_index) + { + if (dvar_cg_unlockall_attachments->current.enabled) + { + return false; + } + + return bg_unlockablesisattachmentslotlocked_hook.invoke(mode, controller_index, item_index, attachment_slot_index); + } }; struct component final : client_component @@ -61,10 +97,19 @@ namespace loot { dvar_cg_unlockall_loot = game::Dvar_RegisterBool(game::Dvar_GenerateHash("cg_unlockall_loot"), "cg_unlockall_loot", false, (game::dvarFlags_e)0x0, "Unlocks blackmarket loot"); dvar_cg_unlockall_loot->debugName = "cg_unlockall_loot"; + dvar_cg_unlockall_purchases = game::Dvar_RegisterBool(game::Dvar_GenerateHash("cg_unlockall_purchases"), "cg_unlockall_purchases", false, (game::dvarFlags_e)0x0, "Unlock all purchases with tokens"); + dvar_cg_unlockall_purchases->debugName = "cg_unlockall_purchases"; + dvar_cg_unlockall_attachments = game::Dvar_RegisterBool(game::Dvar_GenerateHash("cg_unlockall_attachments"), "cg_unlockall_attachments", false, (game::dvarFlags_e)0x0, "Unlocks all attachments"); + dvar_cg_unlockall_attachments->debugName = "cg_unlockall_attachments"; + dvar_cg_cg_unlockall_camos = game::Dvar_RegisterBool(game::Dvar_GenerateHash("cg_unlockall_camos"), "cg_unlockall_camos", false, (game::dvarFlags_e)0x0, "Unlocks all camos"); + dvar_cg_cg_unlockall_camos->debugName = "cg_unlockall_camos"; loot_getitemquantity_hook.create(0x141E82C00_g, loot_getitemquantity_stub); liveinventory_getitemquantity_hook.create(0x141E09030_g, liveinventory_getitemquantity_stub); liveinventory_areextraslotspurchased_hook.create(0x141E08950_g, liveinventory_areextraslotspurchased_stub); + bg_unlockablesisitempurchased_hook.create(0x1426A9620_g, bg_unlockablesisitempurchased_stub); + bg_unlockablesisitemattachmentlocked_hook.create(0x1426A88D0_g, bg_unlockablesisitemattachmentlocked_stub); + bg_unlockablesisattachmentslotlocked_hook.create(0x1426A86D0_g, bg_unlockablesisattachmentslotlocked_stub); scheduler::once([]() { if (dvar_cg_unlockall_loot->current.enabled)