diff --git a/src/game/backend/NativeHooks.cpp b/src/game/backend/NativeHooks.cpp index d1c6b7a..720c482 100644 --- a/src/game/backend/NativeHooks.cpp +++ b/src/game/backend/NativeHooks.cpp @@ -69,7 +69,10 @@ namespace YimMenu else { std::vector hooks = {Hook(index, hook)}; - m_RegisteredHooks.emplace(script, hooks); + if (!m_RegisteredHooks.emplace(script, hooks).second) + { + LOGF(WARNING, "NativeHooks::AddHookImpl: {:X} already registered for script {:X}", static_cast(index), script); + } } for (auto& [scp, program] : m_RegisteredPrograms) diff --git a/src/game/features/network/BypassCasinoRestrictions.cpp b/src/game/features/network/BypassCasinoRestrictions.cpp index afc37b1..17e50e0 100644 --- a/src/game/features/network/BypassCasinoRestrictions.cpp +++ b/src/game/features/network/BypassCasinoRestrictions.cpp @@ -13,8 +13,11 @@ namespace YimMenu::Features virtual void OnEnable() override { - NativeHooks::AddHook(NativeHooks::ALL_SCRIPTS, NativeIndex::NETWORK_CASINO_CAN_BET, &NetworkCasinoCanBetHook); - NativeHooks::AddHook(NativeHooks::ALL_SCRIPTS, NativeIndex::NETWORK_CASINO_CAN_BUY_CHIPS_PVC, &NetworkCasinoCanBuyChipsPVCHook); + static auto hooked = []() { + NativeHooks::AddHook(NativeHooks::ALL_SCRIPTS, NativeIndex::NETWORK_CASINO_CAN_BET, &NetworkCasinoCanBetHook); + NativeHooks::AddHook(NativeHooks::ALL_SCRIPTS, NativeIndex::NETWORK_CASINO_CAN_BUY_CHIPS_PVC, &NetworkCasinoCanBuyChipsPVCHook); + return true; + }(); } }; diff --git a/src/game/features/network/FastJoin.cpp b/src/game/features/network/FastJoin.cpp index bf2d729..42f4456 100644 --- a/src/game/features/network/FastJoin.cpp +++ b/src/game/features/network/FastJoin.cpp @@ -13,9 +13,13 @@ namespace YimMenu::Features virtual void OnEnable() override { - NativeHooks::AddHook("freemode"_J, NativeIndex::NETWORK_HAS_RECEIVED_HOST_BROADCAST_DATA, &BroadcastHook); - NativeHooks::AddHook("fmmc_launcher"_J, NativeIndex::NETWORK_HAS_RECEIVED_HOST_BROADCAST_DATA, &BroadcastHook); - NativeHooks::AddHook("am_launcher"_J, NativeIndex::NETWORK_HAS_RECEIVED_HOST_BROADCAST_DATA, &BroadcastHook); + static auto hooked = []() + { + NativeHooks::AddHook("freemode"_J, NativeIndex::NETWORK_HAS_RECEIVED_HOST_BROADCAST_DATA, &BroadcastHook); + NativeHooks::AddHook("fmmc_launcher"_J, NativeIndex::NETWORK_HAS_RECEIVED_HOST_BROADCAST_DATA, &BroadcastHook); + NativeHooks::AddHook("am_launcher"_J, NativeIndex::NETWORK_HAS_RECEIVED_HOST_BROADCAST_DATA, &BroadcastHook); + return true; + }(); } }; diff --git a/src/game/features/self/FormatMoney.cpp b/src/game/features/self/FormatMoney.cpp index 95d989c..d03f6f6 100644 --- a/src/game/features/self/FormatMoney.cpp +++ b/src/game/features/self/FormatMoney.cpp @@ -27,7 +27,11 @@ namespace YimMenu::Features formatIntCaller2Hook = CallSiteHook::AddHook(Pointers.FormatIntCaller2, reinterpret_cast(FormatIntHook)); } formatIntCaller2Hook->Enable(); - NativeHooks::AddHook("shop_controller"_J, NativeIndex::SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT, &ScaleformAddIntHook); + static auto hooked = []() + { + NativeHooks::AddHook("shop_controller"_J, NativeIndex::SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT, &ScaleformAddIntHook); + return true; + }(); } virtual void OnDisable() override diff --git a/src/game/features/self/InfiniteSpecialAbility.cpp b/src/game/features/self/InfiniteSpecialAbility.cpp new file mode 100644 index 0000000..9f11462 --- /dev/null +++ b/src/game/features/self/InfiniteSpecialAbility.cpp @@ -0,0 +1,24 @@ +#include "core/commands/LoopedCommand.hpp" +#include "game/backend/Self.hpp" +#include "game/gta/Natives.hpp" + +namespace YimMenu::Features +{ + class InfiniteSpecialAbility : public LoopedCommand + { + using LoopedCommand::LoopedCommand; + + virtual void OnTick() override + { + if (!Self::GetPed()) + return; + + auto id = Self::GetPlayer().GetId(); + + if (PLAYER::IS_SPECIAL_ABILITY_UNLOCKED(Self::GetPed().GetModel()) && !PLAYER::IS_SPECIAL_ABILITY_METER_FULL(id, 0)) + PLAYER::SPECIAL_ABILITY_CHARGE_ABSOLUTE(id, 200, true, 0); + } + }; + + static InfiniteSpecialAbility _InfiniteSpecialAbility{"infspecialability", "Infinite Special Ability", "Ensures that the special ability bar never runs out"}; +} \ No newline at end of file diff --git a/src/game/features/self/MpSpecialAbility.cpp b/src/game/features/self/MpSpecialAbility.cpp new file mode 100644 index 0000000..9863a52 --- /dev/null +++ b/src/game/features/self/MpSpecialAbility.cpp @@ -0,0 +1,79 @@ +#include "core/commands/LoopedCommand.hpp" +#include "core/commands/ListCommand.hpp" +#include "game/backend/NativeHooks.hpp" +#include "game/backend/Self.hpp" +#include "game/gta/Natives.hpp" +#include "game/pointers/Pointers.hpp" +#include "types/pad/ControllerInputs.hpp" + +namespace YimMenu::Features +{ + static void IsControlPressedHook(rage::scrNativeCallContext* ctx); + + const std::vector> g_SpecialAbilityTypes = { + {0, "Slipstream"}, + {2, "Deadeye"}, + {1, "Trevor Rage"}, + {3, "Snapshot (Aim at head)"}, + {4, "Insult"}, + }; + static ListCommand _SelectedSpecialAbility{"selspecialability", "Special Ability in MP", "The special ability to enable for the MP character", g_SpecialAbilityTypes, 0}; + + class MpSpecialAbility : public LoopedCommand + { + using LoopedCommand::LoopedCommand; + + virtual void OnEnable() override + { + static auto hooked = []() { + NativeHooks::AddHook("freemode"_J, NativeIndex::IS_CONTROL_PRESSED, &IsControlPressedHook); + return true; + }(); + + Pointers.AbilityBarPatch->Apply(); + if (*Pointers.IsSessionStarted) + { + HUD::SET_ALLOW_ABILITY_BAR(true); + HUD::SET_ABILITY_BAR_VISIBILITY(true); + HUD::FLASH_ABILITY_BAR(2000); + } + } + + virtual void OnTick() override + { + if (!Self::GetPed() || !*Pointers.IsSessionStarted) + return; + + auto id = Self::GetPlayer().GetId(); + if (!PLAYER::IS_SPECIAL_ABILITY_UNLOCKED(0)) + PLAYER::SPECIAL_ABILITY_UNLOCK(0, true); // the second parameter enables the cut C&C ability mode + + if (!PLAYER::IS_SPECIAL_ABILITY_ACTIVE(id, 0)) + PLAYER::SET_SPECIAL_ABILITY_MP(id, _SelectedSpecialAbility.GetState(), 0); + HUD::SET_ALLOW_ABILITY_BAR(true); + HUD::SET_ABILITY_BAR_VISIBILITY(true); + } + + virtual void OnDisable() override + { + Pointers.AbilityBarPatch->Restore(); + PLAYER::SPECIAL_ABILITY_LOCK(0, true); + HUD::SET_ALLOW_ABILITY_BAR(false); + } + }; + + static MpSpecialAbility _MpSpecialAbility{"mpspecialability", "Enable Special Abilities in MP", "Enables special abilities in multiplayer. This repurposes cut content and may be unstable"}; + + void IsControlPressedHook(rage::scrNativeCallContext* ctx) + { + if (_MpSpecialAbility.GetState()) + { + auto input = static_cast(ctx->GetArg(1)); + + if (input == ControllerInputs::INPUT_SPECIAL_ABILITY_PC || input == ControllerInputs::INPUT_SPECIAL_ABILITY || input == ControllerInputs::INPUT_SPECIAL_ABILITY_SECONDARY) + ctx->SetReturnValue(FALSE); + } + + return ctx->SetReturnValue(PAD::IS_CONTROL_PRESSED(ctx->GetArg(0), ctx->GetArg(1))); + } +} \ No newline at end of file diff --git a/src/game/frontend/submenus/Self.cpp b/src/game/frontend/submenus/Self.cpp index 833e87d..982459b 100644 --- a/src/game/frontend/submenus/Self.cpp +++ b/src/game/frontend/submenus/Self.cpp @@ -15,6 +15,7 @@ namespace YimMenu::Submenus auto globalsGroup = std::make_shared("Globals"); auto movementGroup = std::make_shared("Movement"); auto toolsGroup = std::make_shared("Tools", 2); + auto specialAbilityGroup = std::make_shared("Special Ability"); auto wantedGroup = std::make_shared("Wanted"); globalsGroup->AddItem(std::make_shared("godmode"_J)); @@ -57,8 +58,15 @@ namespace YimMenu::Submenus movementGroup->AddItem(std::make_shared("freecam"_J)); movementGroup->AddItem(std::make_shared("freecam"_J, std::make_shared("freecamspeed"_J))); + specialAbilityGroup->AddItem(std::make_shared("infspecialability"_J)); + auto specialInMp = std::make_shared("", 1); + specialInMp->AddItem(std::make_shared("mpspecialability"_J, "Enable in MP")); + specialInMp->AddItem(std::make_shared("mpspecialability"_J, std::make_shared("selspecialability"_J, "##specialselect"))); + specialAbilityGroup->AddItem(std::move(specialInMp)); + main->AddItem(globalsGroup); main->AddItem(toolsGroup); + main->AddItem(specialAbilityGroup); main->AddItem(wantedGroup); main->AddItem(movementGroup); AddCategory(std::move(main)); diff --git a/src/game/pointers/Pointers.cpp b/src/game/pointers/Pointers.cpp index f2a7732..bdf871b 100644 --- a/src/game/pointers/Pointers.cpp +++ b/src/game/pointers/Pointers.cpp @@ -411,6 +411,11 @@ namespace YimMenu GetAnticheatInitializedHash2 = ptr.Add(0x9).Rip().As(); }); + constexpr auto abilityBarPatchPtrn = Pattern<"75 39 48 85 F6 74 1A 48 89 F1 E8">("AbilityBarPatch"); + scanner.Add(abilityBarPatchPtrn, [this](PointerCalculator ptr) { + AbilityBarPatch = BytePatches::Add(ptr.As(), 0x9090); + }); + if (!scanner.Scan()) { LOG(FATAL) << "Some patterns could not be found, unloading."; diff --git a/src/game/pointers/Pointers.hpp b/src/game/pointers/Pointers.hpp index c760203..a0a676c 100644 --- a/src/game/pointers/Pointers.hpp +++ b/src/game/pointers/Pointers.hpp @@ -162,6 +162,7 @@ namespace YimMenu PVOID GetAnticheatInitializedHash; PVOID GetAnticheatInitializedHash2; CAnticheatContext** AnticheatContext; + BytePatch AbilityBarPatch; }; struct Pointers : PointerData