diff --git a/src/core/commands/HotkeySystem.cpp b/src/core/commands/HotkeySystem.cpp index 61dbf24..082ed8c 100644 --- a/src/core/commands/HotkeySystem.cpp +++ b/src/core/commands/HotkeySystem.cpp @@ -9,6 +9,7 @@ #include "game/pointers/Pointers.hpp" // game import in core! #include "game/gta/Natives.hpp" // game import in core! +#include "game/frontend/GUI.hpp" namespace YimMenu { @@ -94,7 +95,7 @@ namespace YimMenu { while (g_Running) { - if (GetForegroundWindow() == *Pointers.Hwnd && !HUD::IS_PAUSE_MENU_ACTIVE() && !HUD::IS_SOCIAL_CLUB_ACTIVE() && !m_BeingModified) + if (GetForegroundWindow() == *Pointers.Hwnd && !HUD::IS_PAUSE_MENU_ACTIVE() && !HUD::IS_SOCIAL_CLUB_ACTIVE() && !m_BeingModified && !GUI::IsUsingKeyboard()) { for (auto& [hash, link] : m_CommandHotkeys) { diff --git a/src/game/backend/Self.cpp b/src/game/backend/Self.cpp index fe1a421..71f7cdc 100644 --- a/src/game/backend/Self.cpp +++ b/src/game/backend/Self.cpp @@ -18,17 +18,21 @@ namespace YimMenu { while (g_Running) { - CPed* ped_ptr = nullptr; - if (auto factory = *Pointers.PedFactory) - ped_ptr = factory->m_LocalPed; - m_SelfPed = Ped(ped_ptr, PLAYER::PLAYER_PED_ID()); - m_SelfPlayer = Player(PLAYER::PLAYER_ID()); - if (m_SelfPed.IsValid()) - { - m_Vehicle = m_SelfPed.GetVehicle(); - } - + UpdateImpl(); ScriptMgr::Yield(); } } + + void Self::UpdateImpl() + { + CPed* ped_ptr = nullptr; + if (auto factory = *Pointers.PedFactory) + ped_ptr = factory->m_LocalPed; + m_SelfPed = Ped(ped_ptr, PLAYER::PLAYER_PED_ID()); + m_SelfPlayer = Player(PLAYER::PLAYER_ID()); + if (m_SelfPed.IsValid()) + { + m_Vehicle = m_SelfPed.GetVehicle(); + } + } } \ No newline at end of file diff --git a/src/game/backend/Self.hpp b/src/game/backend/Self.hpp index 7197abe..ecba694 100644 --- a/src/game/backend/Self.hpp +++ b/src/game/backend/Self.hpp @@ -33,9 +33,15 @@ namespace YimMenu GetInstance().RunScriptImpl(); } + static void Update() + { + GetInstance().UpdateImpl(); + } + private: Self(); void RunScriptImpl(); + void UpdateImpl(); static Self& GetInstance() { diff --git a/src/game/features/network/ForceThunder.cpp b/src/game/features/network/ForceThunder.cpp new file mode 100644 index 0000000..c0e9865 --- /dev/null +++ b/src/game/features/network/ForceThunder.cpp @@ -0,0 +1,34 @@ +#include "core/commands/LoopedCommand.hpp" +#include "game/backend/Self.hpp" +#include "game/gta/Scripts.hpp" +#include "types/script/globals/GPBD_FM_3.hpp" + +namespace YimMenu::Features +{ + class ForceThunder : public LoopedCommand + { + using LoopedCommand::LoopedCommand; + + virtual void OnTick() override + { + if (auto global = GPBD_FM_3::Get(); global && Scripts::SafeToModifyFreemodeBroadcastGlobals()) + { + global->Entries[Self::GetPlayer().GetId()].BossGoon.ActiveFreemodeEvents[0] |= (1 << 9); + global->Entries[Self::GetPlayer().GetId()].BossGoon.ActiveFreemodeEvents[0] |= (1 << 10); + global->Entries[Self::GetPlayer().GetId()].BossGoon.ActiveFreemodeEvents[0] |= (1 << 11); + } + } + + virtual void OnDisable() override + { + if (auto global = GPBD_FM_3::Get(); global && Scripts::SafeToModifyFreemodeBroadcastGlobals()) + { + global->Entries[Self::GetPlayer().GetId()].BossGoon.ActiveFreemodeEvents[0] &= ~(1 << 9); + global->Entries[Self::GetPlayer().GetId()].BossGoon.ActiveFreemodeEvents[0] &= ~(1 << 10); + global->Entries[Self::GetPlayer().GetId()].BossGoon.ActiveFreemodeEvents[0] &= ~(1 << 11); + } + } + }; + + static ForceThunder _ForceThunder{"forcethunder", "Force Thunder", "Forces the weather to thunder for all players in the session"}; +} \ No newline at end of file diff --git a/src/game/features/players/toxic/Blackscreen.cpp b/src/game/features/players/toxic/Blackscreen.cpp new file mode 100644 index 0000000..bb615c8 --- /dev/null +++ b/src/game/features/players/toxic/Blackscreen.cpp @@ -0,0 +1,35 @@ +#include "game/backend/Self.hpp" +#include "game/commands/PlayerCommand.hpp" +#include "types/script/globals/GlobalPlayerBD.hpp" +#include "types/script/ScriptEvent.hpp" + +namespace YimMenu::Features +{ + class Blackscreen : public PlayerCommand + { + using PlayerCommand::PlayerCommand; + + virtual void OnCall(Player player) override + { + OnCall(std::vector{player}); + } + + virtual void OnCall(const std::vector& players) override + { + SCRIPT_EVENT_SEND_TO_PROPERTY message; + message.Owner = Self::GetPlayer().GetId(); + message.PropertyIndex = 114; + message.SubProperyIndex = 999; + message.MissionPassNotify1 = true; + message.MissionPassNotify2 = true; + message.PAD_0004 = 999; + message.Variation = 999; + message.Flags = 3; + for (auto& player : players) + message.SetPlayer(player.GetId()); + message.Send(); + } + }; + + static Blackscreen _Blackscreen{"blackscreen", "Blackscreen", "Forces the player into an infinite loading screen that can only be fixed by restarting the game"}; +} \ No newline at end of file diff --git a/src/game/features/recovery/ForceLaunchHeist.cpp b/src/game/features/recovery/ForceLaunchHeist.cpp deleted file mode 100644 index b0a82bf..0000000 --- a/src/game/features/recovery/ForceLaunchHeist.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#include "core/commands/Command.hpp" -#include "types/script/ScriptEvent.hpp" - -namespace YimMenu::Features -{ - class ForceLaunchHeist : public Command - { - using Command::Command; - - virtual void OnCall() override - { - SCRIPT_EVENT_COMMAND event; - event.Command = SCRIPT_EVENT_COMMAND::eCommand::LaunchHeist; - event.SetAllPlayers(); - event.Send(); - } - }; - - static ForceLaunchHeist _ForceLaunchHeist{"forcelaunchheist", "Force Launch Heist", "Forces the heist to launch from the setup screen"}; -} \ No newline at end of file diff --git a/src/game/frontend/GUI.cpp b/src/game/frontend/GUI.cpp index 6d5fce3..558c3f7 100644 --- a/src/game/frontend/GUI.cpp +++ b/src/game/frontend/GUI.cpp @@ -95,7 +95,7 @@ namespace YimMenu { if (UIManager::ShowingContentWindow()) { - if (GUI::IsUsingKeyboard()) + if (GUI::IsUsingKeyboard() && PAD::IS_USING_KEYBOARD_AND_MOUSE(0)) { PAD::DISABLE_ALL_CONTROL_ACTIONS(0); } diff --git a/src/game/frontend/GUI.hpp b/src/game/frontend/GUI.hpp index 81438c6..768a99f 100644 --- a/src/game/frontend/GUI.hpp +++ b/src/game/frontend/GUI.hpp @@ -33,7 +33,7 @@ namespace YimMenu static bool IsUsingKeyboard() { - return ImGui::GetIO().WantTextInput; + return ImGui::GetIO().WantCaptureKeyboard; } static void RunScript() diff --git a/src/game/frontend/submenus/Network.cpp b/src/game/frontend/submenus/Network.cpp index 7d6a002..cabc44f 100644 --- a/src/game/frontend/submenus/Network.cpp +++ b/src/game/frontend/submenus/Network.cpp @@ -19,6 +19,7 @@ namespace YimMenu::Submenus auto toxicGroup = std::make_shared("Toxic"); auto teleportGroup = std::make_shared("Teleport"); auto trollGroup = std::make_shared("Troll"); + auto miscGroup = std::make_shared("Misc"); auto enhancements = std::make_shared("Enhancements"); auto joinSession = std::make_shared("", 1); @@ -83,6 +84,8 @@ namespace YimMenu::Submenus toxicGroup->AddItem(std::make_shared("explodeall"_J, "Explode All")); toxicGroup->AddItem(std::make_shared("ceokickall"_J, "CEO Kick All")); + miscGroup->AddItem(std::make_shared("forcethunder"_J)); + enhancements->AddItem(std::make_shared("notifyonplayerjoin"_J)); enhancements->AddItem(std::make_shared("fastjoin"_J)); enhancements->AddItem(std::make_shared("disabledeathbarriers"_J)); @@ -97,6 +100,7 @@ namespace YimMenu::Submenus session->AddItem(trollGroup); session->AddItem(teleportGroup); session->AddItem(toxicGroup); + session->AddItem(miscGroup); session->AddItem(enhancements); auto spoofing = std::make_shared("Spoofing"); diff --git a/src/game/frontend/submenus/Player/Kick.cpp b/src/game/frontend/submenus/Player/Kick.cpp index abe0301..a6dc341 100644 --- a/src/game/frontend/submenus/Player/Kick.cpp +++ b/src/game/frontend/submenus/Player/Kick.cpp @@ -12,7 +12,11 @@ namespace YimMenu::Submenus kicks->AddItem(std::make_shared("endkick"_J)); kicks->AddItem(std::make_shared("nfkick"_J)); + auto other = std::make_shared("Other"); + other->AddItem(std::make_shared("blackscreen"_J)); + menu->AddItem(kicks); + menu->AddItem(other); return menu; } diff --git a/src/game/frontend/submenus/Recovery.cpp b/src/game/frontend/submenus/Recovery.cpp index 3417ecd..a7c5344 100644 --- a/src/game/frontend/submenus/Recovery.cpp +++ b/src/game/frontend/submenus/Recovery.cpp @@ -23,16 +23,13 @@ namespace YimMenu::Submenus //auto casinoRoulette = std::make_shared("Roulette"); generalGroup->AddItem(std::make_shared("playallmissionssolo"_J)); - generalGroup->AddItem(std::make_shared("forcelaunchheist"_J)); generalGroup->AddItem(std::make_shared("unlockgtaplus"_J)); generalGroup->AddItem(std::make_shared("overriderpmultiplier"_J)); generalGroup->AddItem(std::make_shared("overriderpmultiplier"_J, std::make_shared("rpmultiplierinput"_J))); - generalGroup->AddItem(std::make_shared("freechangeappearance"_J)); generalGroup->AddItem(std::make_shared("nochangeappearancecooldown"_J)); generalGroup->AddItem(std::make_shared("allowgenderchange"_J)); - businessGroup->AddItem(std::make_shared("businesssafe"_J)); businessGroup->AddItem(std::make_shared("claimsafeearnings"_J)); diff --git a/src/game/frontend/submenus/Recovery/StatEditor.cpp b/src/game/frontend/submenus/Recovery/StatEditor.cpp index 0beb301..530ce54 100644 --- a/src/game/frontend/submenus/Recovery/StatEditor.cpp +++ b/src/game/frontend/submenus/Recovery/StatEditor.cpp @@ -64,7 +64,9 @@ namespace YimMenu::Submenus // not sure why people do this if (len > 1 && name_str[0] == '$') { - name_str = std::string_view{name_str.begin()++, name_str.end()}; + auto it = name_str.begin(); + std::advance(it, 1); + name_str = std::string_view{it, name_str.end()}; len--; name.m_Normalized = true; } @@ -340,7 +342,7 @@ namespace YimMenu::Submenus ImGui::Text("Normalized name to: %s", current_info.m_Name.data()); } - bool can_edit = !current_info.m_Data->IsServerAuthoritative() || AnticheatBypass::IsFSLProvidingLocalSaves(); // TODO: a lot of false positives and negatives with this one + bool can_edit = !current_info.m_Data->IsControlledByNetshop(); RenderStatEditor(value, current_info.m_Data); diff --git a/src/game/frontend/submenus/World/SpawnPed.cpp b/src/game/frontend/submenus/World/SpawnPed.cpp index d9ef8e7..b1e0d56 100644 --- a/src/game/frontend/submenus/World/SpawnPed.cpp +++ b/src/game/frontend/submenus/World/SpawnPed.cpp @@ -8,6 +8,7 @@ #include "types/ped/PedCombatAttribute.hpp" #include "game/gta/data/Weapons.hpp" #include "game/gta/Scripts.hpp" +#include "game/backend/NativeHooks.hpp" namespace YimMenu::Submenus { @@ -48,10 +49,14 @@ namespace YimMenu::Submenus ImGui::PushID(name); if (ImGui::Selectable(name)) { - FiberPool::Push([name] { + auto set_player = ImGui::GetIO().KeyCtrl; + FiberPool::Push([name, set_player] { auto hash = Joaat(name); auto handle = Ped::Create(hash, Self::GetPed().GetPosition(), Self::GetPed().GetHeading()); + if (!handle) + return; + handle.SetCombatAttribute(PedCombatAttribute::AlwaysFight, true); handle.SetCombatAttribute(PedCombatAttribute::DisableAllRandomsFlee, true); handle.SetCombatAttribute(PedCombatAttribute::DisableFleeFromCombat, true); @@ -66,7 +71,7 @@ namespace YimMenu::Submenus if (spawnDead) handle.Kill(); - if (spawnAsBodyguard) + if (spawnAsBodyguard && !set_player) { handle.SetCombatAttribute(PedCombatAttribute::CanCharge, true); handle.SetCombatAttribute(PedCombatAttribute::CanCommandeerVehicles, true); @@ -116,7 +121,41 @@ namespace YimMenu::Submenus } } - spawnedPeds.push_back(handle); + if (set_player) + { + static auto hooked = []() + { + NativeHooks::AddHook("freemode"_J, NativeIndex::GET_ENTITY_MODEL, [](rage::scrNativeCallContext* ctx) { + auto model = ENTITY::GET_ENTITY_MODEL(ctx->GetArg(0)); + + if (ctx->GetArg(0) == Self::GetPed().GetHandle() && (model != "mp_m_freemode_01"_J && model != "mp_f_freemode_01"_J)) + { + return ctx->SetReturnValue("mp_m_freemode_01"_J); + } + + return ctx->SetReturnValue(model); + }); + for (auto script : {"main"_J, "respawn_controller"_J, "pi_menu"_J}) + { + NativeHooks::AddHook(script, NativeIndex::GET_ENTITY_MODEL, [](rage::scrNativeCallContext* ctx) { + auto model = ENTITY::GET_ENTITY_MODEL(ctx->GetArg(0)); + + if (ctx->GetArg(0) == Self::GetPed().GetHandle() && (model != "player_zero"_J && model != "player_one"_J && model != "player_two"_J)) + { + return ctx->SetReturnValue("player_zero"_J); + } + + return ctx->SetReturnValue(model); + }); + } + return true; + }(); + Self::GetPlayer().SetPed(handle); + } + else + { + spawnedPeds.push_back(handle); + } }); } ImGui::PopID(); @@ -128,6 +167,7 @@ namespace YimMenu::Submenus ImGui::SameLine(); ImGui::BeginGroup(); + ImGui::BulletText("Ctrl+Click to set player model"); ImGui::Checkbox("Invincible", &invincible); ImGui::Checkbox("Spawn Dead", &spawnDead); ImGui::Checkbox("Spawn As Bodyguard", &spawnAsBodyguard); diff --git a/src/game/gta/Player.cpp b/src/game/gta/Player.cpp index 520d745..986daed 100644 --- a/src/game/gta/Player.cpp +++ b/src/game/gta/Player.cpp @@ -12,6 +12,7 @@ #include "game/backend/Players.hpp" #include "game/gta/Vehicle.hpp" #include "types/network/sync/nodes/vehicle/CVehicleProximityMigrationDataNode.hpp" +#include "game/backend/Self.hpp" namespace YimMenu { @@ -357,6 +358,15 @@ namespace YimMenu return PLAYER::GET_PLAYER_GROUP(GetId()); } + void Player::SetPed(Ped ped, bool delete_old) + { + auto old_ped = Self::GetPed(); + PLAYER::CHANGE_PLAYER_PED(GetId(), ped.GetHandle(), true, true); + Self::Update(); + if (delete_old) + old_ped.Delete(); + } + bool Player::operator==(Player other) { return m_Handle == other.m_Handle; diff --git a/src/game/gta/Player.hpp b/src/game/gta/Player.hpp index fb7260c..286b93c 100644 --- a/src/game/gta/Player.hpp +++ b/src/game/gta/Player.hpp @@ -85,6 +85,8 @@ namespace YimMenu int GetGroup(); + void SetPed(Ped ped, bool delete_old = true); + bool operator==(Player other); inline operator bool() diff --git a/src/types/stats/sStatData.hpp b/src/types/stats/sStatData.hpp index e0ee011..7e4a617 100644 --- a/src/types/stats/sStatData.hpp +++ b/src/types/stats/sStatData.hpp @@ -57,6 +57,11 @@ public: { return (m_Flags & 0x80) != 0; } + + inline bool IsControlledByNetshop() const + { + return (m_Flags & 0x8000000) != 0; + } }; static_assert(sizeof(sStatData) == 0x10);