Merge branch 'enhanced' of https://github.com/YimMenu/YimMenuV2 into enhanced

This commit is contained in:
maybegreat48
2025-04-21 18:00:37 -04:00
66 changed files with 2455 additions and 414 deletions
+6
View File
@@ -38,6 +38,12 @@ namespace YimMenu
MarkDirty();
}
void ListCommand::SetList(std::vector<std::pair<int, const char*>> list)
{
m_List = std::move(list);
MarkDirty();
}
std::vector<std::pair<int, const char*>>& ListCommand::GetList()
{
return m_List;
+1
View File
@@ -18,6 +18,7 @@ namespace YimMenu
ListCommand(std::string name, std::string label, std::string description, std::vector<std::pair<int, const char*>> list, int def_val = 0);
int GetState();
void SetState(int state);
void SetList(std::vector<std::pair<int, const char*>> list);
std::vector<std::pair<int, const char*>>& GetList();
};
}
+78
View File
@@ -0,0 +1,78 @@
#include "CallHook.hpp"
namespace YimMenu
{
CallHookMemory::CallHookMemory()
{
m_Memory = VirtualAlloc((void*)((uintptr_t)GetModuleHandle(0) + 0x20000000), 1024, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
m_Offset = 0;
}
void* CallHookMemory::AllocateJumpSequenceImpl(void* func)
{
m_Offset = m_Offset + ((16 - (m_Offset % 16)) % 16);
*m_Memory.Add(m_Offset).As<int16_t*>() = 0xB848;
*m_Memory.Add(m_Offset).Add(2).As<void**>() = func;
*m_Memory.Add(m_Offset).Add(10).As<int16_t*>() = 0xE0FF;
m_Offset += 12;
return m_Memory.Add(m_Offset).Sub(12).As<void*>();
}
void CallHookMemory::DestroyImpl()
{
VirtualFree(m_Memory.As<void*>(), 0, MEM_RELEASE);
}
CallSiteHook::Hook::Hook(void* location, void* hook) :
m_Location(location),
m_Hook(hook),
m_Enabled(false)
{
auto seq = CallHookMemory::AllocateJumpSequence(hook);
m_PatchedBytes[0] = 0xE8;
*(int32_t*)&m_PatchedBytes[1] = (int32_t)((uint64_t)seq - (uint64_t)location - 5);
memcpy(m_OriginalBytes, location, 5);
m_OriginalFunction = PointerCalculator(location).Add(1).Rip().As<void*>();
}
void CallSiteHook::Hook::Enable()
{
if (!m_Enabled)
{
memcpy(m_Location, m_PatchedBytes, 5);
m_Enabled = true;
}
}
void CallSiteHook::Hook::Disable()
{
if (m_Enabled)
{
memcpy(m_Location, m_OriginalBytes, 5);
m_Enabled = false;
}
}
std::shared_ptr<CallSiteHook::Hook> CallSiteHook::AddHookImpl(void* location, void* hook)
{
auto hookPtr = std::make_shared<Hook>(location, hook);
m_Hooks.push_back(hookPtr);
return hookPtr;
}
void CallSiteHook::DestroyImpl()
{
for (auto& hook : m_Hooks)
{
if (hook)
hook->Disable();
}
m_Hooks.clear();
CallHookMemory::Destroy();
}
}
+88
View File
@@ -0,0 +1,88 @@
#pragma once
#include "core/memory/PointerCalculator.hpp"
namespace YimMenu
{
class CallHookMemory
{
static CallHookMemory& GetInstance()
{
static CallHookMemory instance;
return instance;
}
void* AllocateJumpSequenceImpl(void* func);
void DestroyImpl();
PointerCalculator m_Memory;
int m_Offset;
public:
CallHookMemory();
static void* AllocateJumpSequence(void* func)
{
return GetInstance().AllocateJumpSequenceImpl(func);
}
static void Destroy()
{
GetInstance().DestroyImpl();
}
};
class CallSiteHook
{
public:
class Hook
{
Hook(Hook&& that) = delete;
Hook& operator=(Hook&& that) = delete;
Hook(Hook const&) = delete;
Hook& operator=(Hook const&) = delete;
void* m_Location;
void* m_Hook;
uint8_t m_PatchedBytes[5];
uint8_t m_OriginalBytes[5];
void* m_OriginalFunction;
bool m_Enabled;
public:
Hook(void* location, void* hook);
void Enable();
void Disable();
template<typename T>
T GetOriginal()
{
return static_cast<T>(m_OriginalFunction);
}
};
static std::shared_ptr<Hook> AddHook(void* location, void* hook)
{
return GetInstance().AddHookImpl(location, hook);
}
static void Destroy()
{
GetInstance().DestroyImpl();
}
private:
static CallSiteHook& GetInstance()
{
static CallSiteHook Instance;
return Instance;
}
std::shared_ptr<Hook> AddHookImpl(void* location, void* hook);
void DestroyImpl();
static inline std::vector<std::shared_ptr<Hook>> m_Hooks;
};
using CallHook = std::shared_ptr<CallSiteHook::Hook>;
}
+15 -71
View File
@@ -1,67 +1,13 @@
#include "ScriptPatches.hpp"
#include "game/backend/ScriptPointers.hpp"
#include "game/pointers/Pointers.hpp"
#include "types/script/scrProgram.hpp"
namespace YimMenu
{
static uint8_t* GetCodeLocation(ScriptPatches::Data* data, int idx)
{
return &data->GetData()[idx >> 14][idx & 0x3FFF];
}
// TODO: refactor this and cache results
static std::optional<int32_t> GetCodeLocationByPattern(ScriptPatches::Data* data, const SimplePattern& pattern)
{
uint32_t code_size = data->GetSize();
for (uint32_t i = 0; i < (code_size - pattern.m_Bytes.size()); i++)
{
for (uint32_t j = 0; j < pattern.m_Bytes.size(); j++)
{
if (pattern.m_Bytes[j].has_value())
{
int loc = i + j;
if (pattern.m_Bytes[j] != *GetCodeLocation(data, loc))
goto incorrect;
}
}
return i;
incorrect:
continue;
}
return std::nullopt;
}
ScriptPatches::Data::Data(rage::scrProgram* program)
{
auto pages = new uint8_t*[program->GetNumCodePages()];
for (auto i = 0u; i < program->GetNumCodePages(); i++)
{
pages[i] = new uint8_t[program->GetCodePageSize(i)];
std::memcpy(pages[i], program->GetCodePage(i), program->GetCodePageSize(i));
}
m_Data = pages;
m_Pages = program->GetNumCodePages();
m_Size = program->GetFullCodeSize();
}
ScriptPatches::Data::~Data()
{
for (auto i = 0u; i < m_Pages; i++)
{
delete[] m_Data[i];
}
delete[] m_Data;
m_Data = nullptr;
}
std::optional<int32_t> ScriptPatches::Patch::GetPC()
std::optional<uint32_t> ScriptPatches::Patch::GetPC()
{
if (m_Pc.has_value())
return m_Pc;
@@ -71,15 +17,14 @@ namespace YimMenu
if (!data)
return std::nullopt;
auto location = GetCodeLocationByPattern(data, m_Pattern);
if (!location.has_value())
if (auto address = ScriptPointers::GetPointer(Joaat(m_Pointer.GetName())))
{
LOG(FATAL) << "Failed to find pattern for script " << HEX(m_Hash);
m_Pc = address;
}
else
{
m_Pc = location.value() + m_Offset;
m_Pc = m_Pointer.Scan(data).As<std::uint32_t>();
ScriptPointers::CachePointer(Joaat(m_Pointer.GetName()), m_Pc.value());
}
return m_Pc;
@@ -96,10 +41,10 @@ namespace YimMenu
if (m_OriginalBytes.size() == 0)
{
m_OriginalBytes.resize(m_PatchedBytes.size());
memcpy(m_OriginalBytes.data(), GetCodeLocation(data, pc.value()), m_PatchedBytes.size());
memcpy(m_OriginalBytes.data(), ScriptData::GetCodeLocation(data, pc.value()), m_PatchedBytes.size());
}
memcpy(GetCodeLocation(data, pc.value()), m_PatchedBytes.data(), m_PatchedBytes.size());
memcpy(ScriptData::GetCodeLocation(data, pc.value()), m_PatchedBytes.data(), m_PatchedBytes.size());
}
void ScriptPatches::Patch::Restore()
@@ -113,13 +58,12 @@ namespace YimMenu
if (!pc || !data)
return;
memcpy(GetCodeLocation(data, pc.value()), m_OriginalBytes.data(), m_OriginalBytes.size());
memcpy(ScriptData::GetCodeLocation(data, pc.value()), m_OriginalBytes.data(), m_OriginalBytes.size());
}
ScriptPatches::Patch::Patch(joaat_t script, SimplePattern pattern, int32_t offset, std::vector<uint8_t> patch) :
m_Pattern(pattern),
m_Offset(offset),
ScriptPatches::Patch::Patch(joaat_t script, ScriptPointer pointer, std::vector<uint8_t> patch) :
m_PatchedBytes(patch),
m_Pointer(pointer),
m_Enabled(false),
m_Pc(std::nullopt),
m_OriginalBytes({}),
@@ -162,9 +106,9 @@ namespace YimMenu
return m_Hash == hash;
}
std::shared_ptr<ScriptPatches::Patch> ScriptPatches::AddPatchImpl(joaat_t script, const std::string& pattern, int32_t offset, std::vector<uint8_t> patch)
std::shared_ptr<ScriptPatches::Patch> ScriptPatches::AddPatchImpl(joaat_t script, ScriptPointer pointer, std::vector<uint8_t> patch)
{
auto scr_patch = std::make_shared<Patch>(script, SimplePattern(pattern), offset, patch);
auto scr_patch = std::make_shared<Patch>(script, pointer, patch);
// add patch to map
m_Patches.push_back(scr_patch);
@@ -202,7 +146,7 @@ namespace YimMenu
if (!in_scope)
return; // avoid polluting memory with unused program bytecode
m_Datas.emplace(program->m_NameHash, std::move(std::make_unique<Data>(program)));
m_Datas.emplace(program->m_NameHash, std::move(std::make_unique<ScriptData>(program)));
// refresh patches so they can enable themselves
for (auto& patch : m_Patches)
@@ -248,7 +192,7 @@ namespace YimMenu
}
}
ScriptPatches::Data* ScriptPatches::GetDataImpl(joaat_t script)
ScriptData* ScriptPatches::GetDataImpl(joaat_t script)
{
if (auto it = m_Datas.find(script); it != m_Datas.end())
return it->second.get();
+11 -33
View File
@@ -1,6 +1,7 @@
#pragma once
#include "core/memory/Pattern.hpp"
#include "core/util/Joaat.hpp"
#include "game/gta/ScriptData.hpp"
#include "game/gta/ScriptPointer.hpp"
namespace rage
{
@@ -12,52 +13,29 @@ namespace YimMenu
class ScriptPatches
{
public:
class Data
{
std::uint8_t** m_Data;
std::uint32_t m_Pages;
std::uint32_t m_Size;
public:
inline std::uint8_t** GetData() const
{
return m_Data;
}
inline std::uint32_t GetSize() const
{
return m_Size;
}
Data(rage::scrProgram* program);
~Data();
};
class Patch
{
std::vector<uint8_t> m_OriginalBytes;
std::vector<uint8_t> m_PatchedBytes;
std::optional<int32_t> m_Pc;
SimplePattern m_Pattern;
int32_t m_Offset;
std::optional<uint32_t> m_Pc;
ScriptPointer m_Pointer;
bool m_Enabled;
std::uint32_t m_Hash;
std::optional<int32_t> GetPC();
std::optional<uint32_t> GetPC();
void Apply();
void Restore();
public:
Patch(joaat_t script, SimplePattern pattern, int32_t offset, std::vector<uint8_t> patch);
Patch(joaat_t script, ScriptPointer pointer, std::vector<uint8_t> patch);
void Enable();
void Disable();
void Update();
bool InScope(std::uint32_t hash);
};
static std::shared_ptr<Patch> AddPatch(joaat_t script, const std::string& pattern, int32_t offset, std::vector<uint8_t> patch)
static std::shared_ptr<Patch> AddPatch(joaat_t script, ScriptPointer pointer, std::vector<uint8_t> patch)
{
return GetInstance().AddPatchImpl(script, pattern, offset, patch);
return GetInstance().AddPatchImpl(script, pointer, patch);
}
static void RegisterProgram(rage::scrProgram* program)
@@ -90,15 +68,15 @@ namespace YimMenu
return Instance;
}
std::shared_ptr<Patch> AddPatchImpl(joaat_t script, const std::string& pattern, int32_t offset, std::vector<uint8_t> patch);
std::shared_ptr<Patch> AddPatchImpl(joaat_t script, ScriptPointer pointer, std::vector<uint8_t> patch);
void RegisterProgramImpl(rage::scrProgram* program);
void UnregisterProgramImpl(rage::scrProgram* program);
void OnScriptVMEnterImpl(rage::scrProgram* program);
void OnScriptVMLeaveImpl(rage::scrProgram* program);
Data* GetDataImpl(joaat_t script);
ScriptData* GetDataImpl(joaat_t script);
std::vector<std::shared_ptr<Patch>> m_Patches;
std::unordered_map<joaat_t, std::unique_ptr<Data>> m_Datas;
std::unordered_map<joaat_t, std::unique_ptr<ScriptData>> m_Datas;
std::uint8_t** m_CurrentlyReplacedBytecode;
};
+75
View File
@@ -0,0 +1,75 @@
#include "ScriptPointers.hpp"
#include "core/filemgr/FileMgr.hpp"
#include "core/memory/ModuleMgr.hpp"
namespace YimMenu
{
ScriptPointers::ScriptPointers() :
m_CacheFile(FileMgr::GetProjectFile("./scr_pointers.bin"))
{
}
void ScriptPointers::InitImpl()
{
m_CacheFile.Load();
if (m_CacheFile.UpToDate(ModuleMgr.Get("GTA5_Enhanced.exe"_J)->GetNtHeader()->FileHeader.TimeDateStamp))
{
Load();
}
}
void ScriptPointers::CachePointerImpl(joaat_t nameHash, std::uint32_t address)
{
m_ScriptPointers.emplace(nameHash, address);
Save();
}
std::uint32_t ScriptPointers::GetPointerImpl(joaat_t nameHash)
{
if (auto it = m_ScriptPointers.find(nameHash); it != m_ScriptPointers.end())
{
return it->second;
}
return 0;
}
void ScriptPointers::Save()
{
auto dataSize = sizeof(std::uint32_t) + sizeof(scrPointerSaveStruct) * m_ScriptPointers.size();
auto data = std::make_unique<uint8_t[]>(dataSize);
auto dataPtr = data.get();
*(std::uint32_t*)dataPtr = m_ScriptPointers.size();
dataPtr += sizeof(std::uint32_t);
for (auto& [hash, val] : m_ScriptPointers)
{
auto saveStruct = (scrPointerSaveStruct*)dataPtr;
saveStruct->m_NameHash = hash;
saveStruct->m_Address = val;
dataPtr += sizeof(scrPointerSaveStruct);
}
m_CacheFile.SetHeaderVersion(ModuleMgr.Get("GTA5_Enhanced.exe"_J)->GetNtHeader()->FileHeader.TimeDateStamp);
m_CacheFile.SetData(std::move(data), dataSize);
m_CacheFile.Write();
}
void ScriptPointers::Load()
{
auto data = m_CacheFile.Data();
auto numPointers = *(std::uint32_t*)data;
data += sizeof(std::uint32_t);
for (int i = 0; i < numPointers; i++)
{
auto saveStruct = (scrPointerSaveStruct*)data;
m_ScriptPointers.emplace(saveStruct->m_NameHash, saveStruct->m_Address);
data += sizeof(scrPointerSaveStruct);
}
LOG(INFO) << "Loaded " << m_ScriptPointers.size() << " script pointers from cache.";
}
}
+50
View File
@@ -0,0 +1,50 @@
#pragma once
#include "core/util/Joaat.hpp"
#include "core/filemgr/CacheFile.hpp"
namespace YimMenu
{
#pragma pack(push, 1)
struct scrPointerSaveStruct
{
joaat_t m_NameHash;
std::uint32_t m_Address;
};
#pragma pack(pop)
class ScriptPointers
{
static ScriptPointers& GetInstance()
{
static ScriptPointers instance;
return instance;
}
void InitImpl();
void CachePointerImpl(joaat_t nameHash, std::uint32_t address);
std::uint32_t GetPointerImpl(joaat_t nameHash);
void Save();
void Load();
CacheFile m_CacheFile;
std::unordered_map<joaat_t, std::uint32_t> m_ScriptPointers{};
public:
ScriptPointers();
static void Init()
{
GetInstance().InitImpl();
}
static void CachePointer(joaat_t nameHash, std::uint32_t address)
{
GetInstance().CachePointerImpl(nameHash, address);
}
static std::uint32_t GetPointer(joaat_t nameHash)
{
return GetInstance().GetPointerImpl(nameHash);
}
};
}
@@ -13,7 +13,7 @@ namespace YimMenu::Features
{
if (!m_DeathBarriersPatch)
{
m_DeathBarriersPatch = ScriptPatches::AddPatch("freemode"_J, "2D 01 09 00 00 5D ? ? ? 56 ? ? 3A", 5, {0x2E, 0x01, 0x00});
m_DeathBarriersPatch = ScriptPatches::AddPatch("freemode"_J, ScriptPointer("DeathBarriersPatch", "2D 01 09 00 00 5D ? ? ? 56 ? ? 3A").Add(5), {0x2E, 0x01, 0x00});
}
m_DeathBarriersPatch->Enable();
}
@@ -0,0 +1,25 @@
#include "core/commands/LoopedCommand.hpp"
#include "game/gta/Natives.hpp"
#include "game/gta/Scripts.hpp"
#include "game/pointers/Pointers.hpp"
namespace YimMenu::Features
{
class ForceScriptHost : public LoopedCommand
{
using LoopedCommand::LoopedCommand;
virtual void OnTick() override
{
if (!*Pointers.IsSessionStarted || SCRIPT::GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH("maintransition"_J) > 0)
return;
if (auto freemode = Scripts::FindScriptThread("freemode"_J))
{
Scripts::ForceScriptHost(freemode);
}
}
};
static ForceScriptHost _ForceScriptHost{"forcescripthost", "Force Script Host", "Forces you to become freemode script host. Note that this might break some missions."};
}
@@ -1,19 +0,0 @@
#include "core/commands/Command.hpp"
#include "game/gta/Stats.hpp"
namespace YimMenu::Features
{
class CayoPericoCooldown : public Command
{
using Command::Command;
virtual void OnCall() override
{
Stats::SetInt("MPX_H4_TARGET_POSIX", 1);
Stats::SetInt("MPX_H4_COOLDOWN", 1);
Stats::SetInt("MPX_H4_COOLDOWN_HARD", 1);
}
};
static CayoPericoCooldown _CayoPericoCooldown{"skipcayocooldown", "Cooldown skip for Cayo Perico Heist", "Skips the cooldown between each Cayo Perico heist"};
}
@@ -1,47 +0,0 @@
#include "core/commands/Command.hpp"
#include "game/gta/Stats.hpp"
namespace YimMenu::Features
{
class CayoPericoSetup : public Command
{
using Command::Command;
virtual void OnCall() override
{
Stats::SetInt("MPX_H4CNF_BS_GEN", 131071);
Stats::SetInt("MPX_H4CNF_BS_ENTR", 63);
Stats::SetInt("MPX_H4CNF_BS_ABIL", 63);
Stats::SetInt("MPX_H4CNF_WEAPONS", 2);
Stats::SetInt("MPX_H4CNF_WEP_DISRP", 3);
Stats::SetInt("MPX_H4CNF_ARM_DISRP", 3);
Stats::SetInt("MPX_H4CNF_HEL_DISRP", 3);
Stats::SetInt("MPX_H4CNF_TARGET", 5);
Stats::SetInt("MPX_H4CNF_TROJAN", 4);
Stats::SetInt("MPX_H4CNF_APPROACH", -1);
Stats::SetInt("MPX_H4LOOT_CASH_I", 0);
Stats::SetInt("MPX_H4LOOT_CASH_C", 0);
Stats::SetInt("MPX_H4LOOT_WEED_I", 0);
Stats::SetInt("MPX_H4LOOT_WEED_C", 0);
Stats::SetInt("MPX_H4LOOT_COKE_I", 0);
Stats::SetInt("MPX_H4LOOT_COKE_C", 0);
Stats::SetInt("MPX_H4LOOT_GOLD_I", -1);
Stats::SetInt("MPX_H4LOOT_GOLD_C", -1);
Stats::SetInt("MPX_H4LOOT_PAINT", -1);
Stats::SetInt("MPX_H4_PROGRESS", 131055);
Stats::SetInt("MPX_H4LOOT_CASH_I_SCOPED", 0);
Stats::SetInt("MPX_H4LOOT_CASH_C_SCOPED", 0);
Stats::SetInt("MPX_H4LOOT_WEED_I_SCOPED", 0);
Stats::SetInt("MPX_H4LOOT_WEED_C_SCOPED", 0);
Stats::SetInt("MPX_H4LOOT_COKE_I_SCOPED", 0);
Stats::SetInt("MPX_H4LOOT_COKE_C_SCOPED", 0);
Stats::SetInt("MPX_H4LOOT_GOLD_I_SCOPED", -1);
Stats::SetInt("MPX_H4LOOT_GOLD_C_SCOPED", -1);
Stats::SetInt("MPX_H4LOOT_PAINT_SCOPED", -1);
Stats::SetInt("MPX_H4_MISSIONS", 65535);
Stats::SetInt("MPX_H4_PLAYTHROUGH_STATUS", 40000);
}
};
static CayoPericoSetup _CayoPericoSetup{"skipcayosetup", "Setup Cayo Perico Heist", "Gives the best cayo perico loadout."};
}
+3 -3
View File
@@ -15,19 +15,19 @@ namespace YimMenu::Features
{
if (!m_VehiclePOSIXPatch)
{
m_VehiclePOSIXPatch = ScriptPatches::AddPatch("appinternet"_J, "59 ? ? 72 2E 02 01", 0, {0x2B, 0x00, 0x00});
m_VehiclePOSIXPatch = ScriptPatches::AddPatch("appinternet"_J, ScriptPointer("VehiclePOSIXPatch", "59 ? ? 72 2E 02 01"), {0x2B, 0x00, 0x00});
}
m_VehiclePOSIXPatch->Enable();
if (!m_GetVehiclePricePatch)
{
m_GetVehiclePricePatch = ScriptPatches::AddPatch("appinternet"_J, "56 ? ? 70 2E 04 01 38 01", 0, {0x55});
m_GetVehiclePricePatch = ScriptPatches::AddPatch("appinternet"_J, ScriptPointer("GetVehiclePricePatch", "56 ? ? 70 2E 04 01 38 01"), {0x55});
}
m_GetVehiclePricePatch->Enable();
if (!m_BuyVehiclePatch)
{
m_BuyVehiclePatch = ScriptPatches::AddPatch("appinternet"_J, "5D ? ? ? 06 56 ? ? 38 00 25 ? 50", 5, {0x55});
m_BuyVehiclePatch = ScriptPatches::AddPatch("appinternet"_J, ScriptPointer("BuyVehiclePatch", "5D ? ? ? 06 56 ? ? 38 00 25 ? 50").Add(5), {0x55});
}
m_BuyVehiclePatch->Enable();
}
@@ -2,14 +2,13 @@
#include "core/backend/ScriptMgr.hpp"
#include "game/backend/Self.hpp"
#include "game/gta/Natives.hpp"
#include "game/gta/Scripts.hpp"
#include "game/gta/ScriptFunction.hpp"
#include "game/gta/ScriptLocal.hpp"
#include "types/script/locals/VehicleRewardData.hpp"
namespace YimMenu
{
static ScriptFunction giveVehicleReward("GVR", "AM_MP_VEHICLE_REWARD"_J, "2D 0C 1E 00 00");
bool GiveVehicleReward::IsSafeToRunScript()
{
return Self::GetVehicle().IsValid() && *Pointers.IsSessionStarted;
@@ -67,6 +66,7 @@ namespace YimMenu
if (auto VehicleRewardData = VEHICLE_REWARD_DATA::Get(m_Thread))
{
auto VehicleMenuData = ScriptLocal(m_Thread, 176).As<int*>(); // TO-DO: add struct for this?
static ScriptFunction giveVehicleReward("AM_MP_VEHICLE_REWARD"_J, ScriptPointer("GiveVehicleReward", "2D 0C 1E 00 00"));
if (giveVehicleReward.Call<bool>(Self::GetVehicle().GetHandle(), VehicleMenuData, &VehicleRewardData->TransactionStatus, &VehicleRewardData->Garage, &VehicleRewardData->GarageOffset, &VehicleRewardData->ControlStatus, false, true, true, false, 0, -1))
{
if (VehicleRewardData->ControlStatus != 3)
@@ -0,0 +1,132 @@
#include "core/commands/IntCommand.hpp"
#include "core/commands/Command.hpp"
#include "game/gta/Stats.hpp"
#include "game/backend/Players.hpp"
#include "game/gta/ScriptGlobal.hpp"
#include "game/gta/ScriptLocal.hpp"
#include "core/backend/ScriptMgr.hpp"
#include "types/script/globals/GlobalPlayerBD.hpp"
namespace YimMenu::Features
{
namespace ApartmentHeist
{
static IntCommand _ApartmentHeistCut1{"apartmentheistcut1", "Player 1", "Player 1 cut", std::nullopt, std::nullopt, 0};
static IntCommand _ApartmentHeistCut2{"apartmentheistcut2", "Player 2", "Player 2 cut", std::nullopt, std::nullopt, 0};
static IntCommand _ApartmentHeistCut3{"apartmentheistcut3", "Player 3", "Player 3 cut", std::nullopt, std::nullopt, 0};
static IntCommand _ApartmentHeistCut4{"apartmentheistcut4", "Player 4", "Player 4 cut", std::nullopt, std::nullopt, 0};
class SetCuts : public Command
{
using Command::Command;
virtual void OnCall() override
{
auto base1 = ScriptGlobal(1929794).At(1);
auto base2 = ScriptGlobal(1931762).At(3008);
*base1.At(1).As<int*>() = 100 - (_ApartmentHeistCut1.GetState() + _ApartmentHeistCut2.GetState() + _ApartmentHeistCut3.GetState() + _ApartmentHeistCut4.GetState());
*base1.At(2).As<int*>() = _ApartmentHeistCut2.GetState();
*base1.At(3).As<int*>() = _ApartmentHeistCut3.GetState();
*base1.At(4).As<int*>() = _ApartmentHeistCut4.GetState();
ScriptMgr::Yield(500ms);
*base2.At(1).As<int*>() = -1 * (*base1.At(1).As<int*>() + *base1.At(2).As<int*>() + *base1.At(3).As<int*>() + *base1.At(4).As<int*>() - 100);
*base2.At(2).As<int*>() = *base1.At(2).As<int*>();
*base2.At(3).As<int*>() = *base1.At(3).As<int*>();
*base2.At(4).As<int*>() = *base1.At(4).As<int*>();
}
};
class ForceReady : public Command
{
using Command::Command;
virtual void OnCall() override
{
if (auto gpbd = GlobalPlayerBD::Get(); gpbd && Scripts::SafeToModifyFreemodeBroadcastGlobals())
{
for (auto& player : Players::GetPlayers())
{
gpbd->Entries[player.second.GetId()].HeistCutSelectionStage = 6;
}
}
}
};
class Setup : public Command
{
using Command::Command;
virtual void OnCall() override
{
Stats::SetInt("MPX_HEIST_PLANNING_STAGE", -1);
}
};
class SkipHacking : public Command
{
using Command::Command;
virtual void OnCall() override
{
*ScriptLocal("fm_mission_controller"_J, 12216).At(24).As<int*>() = 7;
*ScriptLocal("fm_mission_controller"_J, 10213).As<int*>() = *ScriptLocal("fm_mission_controller"_J, 10213).As<int*>() | (1 << 9);
}
};
class SkipDrilling : public Command
{
using Command::Command;
virtual void OnCall() override
{
*ScriptLocal("fm_mission_controller"_J, 10507).At(11).As<float*>() = 100.0f;
}
};
class InstantFinish : public Command
{
using Command::Command;
virtual void OnCall() override
{
Scripts::ForceScriptHost(Scripts::FindScriptThread("fm_mission_controller"_J));
ScriptMgr::Yield(500ms);
*ScriptLocal("fm_mission_controller"_J, 20387).At(1725).At(1).As<int*>() = 80;
*ScriptLocal("fm_mission_controller"_J, 20387).As<int*>() = 12;
*ScriptLocal("fm_mission_controller"_J, 29006).At(1).As<int*>() = 99999;
*ScriptLocal("fm_mission_controller"_J, 32462).At(1).At(68).As<int*>() = 99999;
// TODO: find a way of getting current heist info so that InstantFinishPacific can be implemented here conditionally.
}
};
class InstantFinishPacific : public Command
{
using Command::Command;
virtual void OnCall() override
{
Scripts::ForceScriptHost(Scripts::FindScriptThread("fm_mission_controller"_J));
ScriptMgr::Yield(500ms);
*ScriptLocal("fm_mission_controller"_J, 20387).At(2686).As<int*>() = 1875000;
*ScriptLocal("fm_mission_controller"_J, 20387).At(1062).As<int*>() = 5;
*ScriptLocal("fm_mission_controller"_J, 20387).As<int*>() = 12;
*ScriptLocal("fm_mission_controller"_J, 29006).At(1).As<int*>() = 99999;
*ScriptLocal("fm_mission_controller"_J, 32462).At(1).At(68).As<int*>() = 99999;
}
};
static SetCuts _ApartmentHeistSetCuts{"apartmentheistsetcuts", "Set Cuts", "Sets heist cut"};
static ForceReady _ApartmentHeistForceReady{"apartmentheistforceready", "Force Ready", "Forces all players to be ready"};
static Setup _ApartmentHeistSetup{"apartmentheistsetup", "Setup", "Sets up current apartment heist"};
static SkipHacking _ApartmentHeistSkipHacking{"apartmentheistskiphacking", "Skip Hacking", "Skips hacking process"};
static SkipDrilling _ApartmentHeistSkipDrilling{"apartmentheistskipdrilling", "Skip Drilling", "Skips drilling process"};
static InstantFinish _ApartmentHeistInstantFinish{"apartmentheistinstantfinish", "Instant Finish", "Instantly passes the heist"};
static InstantFinishPacific _ApartmentHeistInstantFinishPacific{"apartmentheistinstantfinishpacific", "Instant Finish (Pacific)", "Instantly passes Pacific Standard Job"};
}
}
@@ -0,0 +1,257 @@
#include "core/commands/Command.hpp"
#include "core/commands/IntCommand.hpp"
#include "core/commands/ListCommand.hpp"
#include "game/backend/Self.hpp"
#include "game/gta/Natives.hpp"
#include "game/gta/Stats.hpp"
#include "game/gta/ScriptGlobal.hpp"
#include "game/gta/ScriptLocal.hpp"
#include "core/backend/ScriptMgr.hpp"
#include "game/backend/Tunables.hpp"
namespace YimMenu::Features
{
namespace CayoPericoHeist
{
static IntCommand _CayoPericoHeistCut1{"cayopericoheistcut1", "Player 1", "Player 1 cut", std::nullopt, std::nullopt, 0};
static IntCommand _CayoPericoHeistCut2{"cayopericoheistcut2", "Player 2", "Player 2 cut", std::nullopt, std::nullopt, 0};
static IntCommand _CayoPericoHeistCut3{"cayopericoheistcut3", "Player 3", "Player 3 cut", std::nullopt, std::nullopt, 0};
static IntCommand _CayoPericoHeistCut4{"cayopericoheistcut4", "Player 4", "Player 4 cut", std::nullopt, std::nullopt, 0};
class SetCuts : public Command
{
using Command::Command;
virtual void OnCall() override
{
auto base = ScriptGlobal(1973698).At(831).At(56);
*base.At(1).As<int*>() = _CayoPericoHeistCut1.GetState();
*base.At(2).As<int*>() = _CayoPericoHeistCut2.GetState();
*base.At(3).As<int*>() = _CayoPericoHeistCut3.GetState();
*base.At(4).As<int*>() = _CayoPericoHeistCut4.GetState();
}
};
class ForceReady : public Command
{
using Command::Command;
virtual void OnCall() override
{
auto base = ScriptGlobal(1974810);
*base.At(0, 27).At(8).At(0).As<int*>() = 1;
*base.At(1, 27).At(8).At(1).As<int*>() = 1;
*base.At(2, 27).At(8).At(2).As<int*>() = 1;
*base.At(3, 27).At(8).At(3).As<int*>() = 1;
}
};
static std::vector<std::pair<int, const char*>> cayoPericoHeistDifficulty = {
{126823, "Normal"},
{131055, "Hard"}
};
static ListCommand _CayoPericoHeistDifficulty{"cayopericoheistdifficulty", "Difficulty", "Heist difficulty", cayoPericoHeistDifficulty, 126823};
static std::vector<std::pair<int, const char*>> cayoPericoHeistPrimaryTarget = {
{5, "Panther Statue"},
{3, "Pink Diamond"},
{4, "Madrazo Files"},
{2, "Bearer Bonds"},
{1, "Ruby Necklace"},
{0, "Sinsimito Tequila"}
};
static ListCommand _CayoPericoHeistPrimaryTarget{"cayopericoheistprimarytarget", "Primary Target", "Primary target", cayoPericoHeistPrimaryTarget, 5};
static std::vector<std::pair<int, const char*>> cayoPericoHeistWeapon = {
{1, "Aggressor"},
{2, "Conspirator"},
{3, "Crack Shot"},
{4, "Saboteur"},
{5, "Marksman"}
};
static ListCommand _CayoPericoHeistWeapon{"cayopericoheistweapon", "Weapon", "Weapon category", cayoPericoHeistWeapon, 1};
class Setup : public Command
{
using Command::Command;
virtual void OnCall() override
{
Stats::SetInt("MPX_H4CNF_TARGET", _CayoPericoHeistPrimaryTarget.GetState()); // Primary target
Stats::SetInt("MPX_H4LOOT_CASH_I", 2359448);
Stats::SetInt("MPX_H4LOOT_CASH_I_SCOPED", 2359448);
Stats::SetInt("MPX_H4LOOT_CASH_C", 0);
Stats::SetInt("MPX_H4LOOT_CASH_C_SCOPED", 0);
Stats::SetInt("MPX_H4LOOT_COKE_I", 4901222);
Stats::SetInt("MPX_H4LOOT_COKE_I_SCOPED", 4901222);
Stats::SetInt("MPX_H4LOOT_COKE_C", 0);
Stats::SetInt("MPX_H4LOOT_COKE_C_SCOPED", 0);
Stats::SetInt("MPX_H4LOOT_GOLD_I", 0);
Stats::SetInt("MPX_H4LOOT_GOLD_I_SCOPED", 0);
Stats::SetInt("MPX_H4LOOT_GOLD_C", 255);
Stats::SetInt("MPX_H4LOOT_GOLD_C_SCOPED", 255);
Stats::SetInt("MPX_H4LOOT_WEED_I", 0);
Stats::SetInt("MPX_H4LOOT_WEED_I_SCOPED", 0);
Stats::SetInt("MPX_H4LOOT_WEED_C", 0);
Stats::SetInt("MPX_H4LOOT_WEED_C_SCOPED", 0);
Stats::SetInt("MPX_H4LOOT_PAINT", 127);
Stats::SetInt("MPX_H4LOOT_PAINT_SCOPED", 127);
Stats::SetInt("MPX_H4LOOT_CASH_V", 599431);
Stats::SetInt("MPX_H4LOOT_COKE_V", 1198863);
Stats::SetInt("MPX_H4LOOT_GOLD_V", 1598484);
Stats::SetInt("MPX_H4LOOT_PAINT_V", 1198863);
Stats::SetInt("MPX_H4LOOT_WEED_V", 0);
Stats::SetInt("MPX_H4_PROGRESS", _CayoPericoHeistDifficulty.GetState()); // Difficulty
Stats::SetInt("MPX_H4CNF_BS_GEN", 262143);
Stats::SetInt("MPX_H4CNF_BS_ENTR", 63);
Stats::SetInt("MPX_H4CNF_BS_ABIL", 63);
Stats::SetInt("MPX_H4CNF_WEP_DISRP", 3);
Stats::SetInt("MPX_H4CNF_ARM_DISRP", 3);
Stats::SetInt("MPX_H4CNF_HEL_DISRP", 3);
Stats::SetInt("MPX_H4CNF_APPROACH", -1);
Stats::SetInt("MPX_H4CNF_BOLTCUT", 4424);
Stats::SetInt("MPX_H4CNF_UNIFORM", 5256);
Stats::SetInt("MPX_H4CNF_GRAPPEL", 5156);
Stats::SetInt("MPX_H4_MISSIONS", -1);
Stats::SetInt("MPX_H4CNF_WEAPONS", _CayoPericoHeistWeapon.GetState()); // Weapon
Stats::SetInt("MPX_H4CNF_TROJAN", 5);
Stats::SetInt("MPX_H4_PLAYTHROUGH_STATUS", 100);
ScriptMgr::Yield(500ms);
*ScriptLocal("heist_island_planning"_J, 1566).As<int*>() = 2;
}
};
static IntCommand _CayoPericoHeistPrimaryTargetValue{"cayopericoheistprimarytargetvalue", "Primary Target Value", "Updates primary target value", std::nullopt, std::nullopt, 0};
class SetPrimaryTargetValue : public Command
{
using Command::Command;
virtual void OnCall() override
{
auto primary_target = Stats::GetInt("MPX_H4CNF_TARGET");
switch (primary_target)
{
case 0: *Tunables::GetTunable("IH_PRIMARY_TARGET_VALUE_TEQUILA"_J).As<int*>() = _CayoPericoHeistPrimaryTargetValue.GetState(); break;
case 1: *Tunables::GetTunable("IH_PRIMARY_TARGET_VALUE_PEARL_NECKLACE"_J).As<int*>() = _CayoPericoHeistPrimaryTargetValue.GetState(); break;
case 2: *Tunables::GetTunable("IH_PRIMARY_TARGET_VALUE_BEARER_BONDS"_J).As<int*>() = _CayoPericoHeistPrimaryTargetValue.GetState(); break;
case 3: *Tunables::GetTunable("IH_PRIMARY_TARGET_VALUE_PINK_DIAMOND"_J).As<int*>() = _CayoPericoHeistPrimaryTargetValue.GetState(); break;
case 4: *Tunables::GetTunable("IH_PRIMARY_TARGET_VALUE_MADRAZO_FILES"_J).As<int*>() = _CayoPericoHeistPrimaryTargetValue.GetState(); break;
case 5: *Tunables::GetTunable("IH_PRIMARY_TARGET_VALUE_SAPPHIRE_PANTHER_STATUE"_J).As<int*>() = _CayoPericoHeistPrimaryTargetValue.GetState(); break;
default: break;
}
}
};
static IntCommand _CayoPericoHeistSecondaryTakeValue{"cayopericoheistsecondarytakevalue", "Secondary Take Value", "Updates secondary take value", std::nullopt, std::nullopt, 0};
class SetSecondaryTakeValue : public Command
{
using Command::Command;
virtual void OnCall() override
{
*ScriptLocal("fm_mission_controller_2020"_J, 56033).At(1518).At(53).As<int*>() = _CayoPericoHeistSecondaryTakeValue.GetState();
}
};
class SkipHacking : public Command
{
using Command::Command;
virtual void OnCall() override
{
*ScriptLocal("fm_mission_controller_2020"_J, 25388).As<int*>() = 5;
}
};
class CutSewer : public Command
{
using Command::Command;
virtual void OnCall() override
{
*ScriptLocal("fm_mission_controller_2020"_J, 30212).As<int*>() = 6;
}
};
class CutGlass : public Command
{
using Command::Command;
virtual void OnCall() override
{
*ScriptLocal("fm_mission_controller_2020"_J, 31451).At(3).As<float*>() = 100.0f;
}
};
class TakePrimaryTarget : public Command
{
using Command::Command;
virtual void OnCall() override
{
auto ped = Self::GetPed();
if (!ped)
return;
auto pos = ped.GetPosition();
auto heading = ped.GetHeading();
auto primary_target = Stats::GetInt("MPX_H4CNF_TARGET");
TASK::TASK_GO_STRAIGHT_TO_COORD(ped.GetHandle(), 5006.917, -5755.931, 15.484, 1.0, 3, 15, 5);
switch (primary_target)
{
case 0:
case 1:
case 3:
case 5:
*ScriptLocal("fm_mission_controller_2020"_J, 31450).As<int*>() = 5;
*ScriptLocal("fm_mission_controller_2020"_J, 31451).As<int*>() = 3;
break;
case 2:
case 4:
*ScriptLocal("fm_mission_controller_2020"_J, 31426).As<int*>() = 7;
break;
default: break;
}
ScriptMgr::Yield(4000ms);
TASK::TASK_GO_STRAIGHT_TO_COORD(ped.GetHandle(), pos.x, pos.y, pos.z, 1.0, 3, heading, 5);
}
};
class InstantFinish : public Command
{
using Command::Command;
virtual void OnCall() override
{
Scripts::ForceScriptHost(Scripts::FindScriptThread("fm_mission_controller_2020"_J));
ScriptMgr::Yield(500ms);
*ScriptLocal("fm_mission_controller_2020"_J, 52581).As<int*>() = 9;
*ScriptLocal("fm_mission_controller_2020"_J, 52581).At(1776).At(1).As<int*>() = 50;
}
};
static SetCuts _CayoPericoHeistSetCuts{"cayopericoheistsetcuts", "Set Cuts", "Sets heist cut"};
static ForceReady _CayoPericoHeistForceReady{"cayopericoheistforceready", "Force Ready", "Forces all players to be ready"};
static Setup _CayoPericoHeistSetup{"cayopericoheistsetup", "Setup", "Sets up cayo perico heist"};
static SetPrimaryTargetValue _CayoPericoHeistSetPrimaryTargetValue{"cayopericoheistsetprimarytargetvalue", "Set Primary Target Value", "Updates primary target value"};
static SetSecondaryTakeValue _CayoPericoHeistSetSecondaryTakeValue{"cayopericoheistsetsecondarytakevalue", "Set Secondary Take Value", "Updates secondary take value"};
static SkipHacking _CayoPericoHeistSkipHacking{"cayopericoheistskiphacking", "Skip Hacking", "Skips hacking process"};
static CutSewer _CayoPericoHeistCutSewer{"cayopericoheistcutsewer", "Cut Sewer", "Cuts the sewer"};
static CutGlass _CayoPericoHeistCutGlass{"cayopericoheistcutglass", "Cut Glass", "Cuts the glass"};
static TakePrimaryTarget _CayoPericoHeistTakePrimaryTarget{"cayopericoheisttakeprimarytarget", "Take Primary Target", "Takes primary target"};
static InstantFinish _CayoPericoHeistInstantFinish{"cayopericoheistinstantfinish", "Instant Finish", "Instantly passes the heist"};
}
}
@@ -0,0 +1,333 @@
#include "core/commands/Command.hpp"
#include "core/commands/IntCommand.hpp"
#include "core/commands/ListCommand.hpp"
#include "game/gta/Stats.hpp"
#include "core/backend/FiberPool.hpp"
#include "game/gta/ScriptGlobal.hpp"
#include "game/gta/ScriptLocal.hpp"
#include "core/backend/ScriptMgr.hpp"
#include "game/backend/Tunables.hpp"
namespace YimMenu::Features
{
namespace DiamondCasinoHeist
{
static IntCommand _DiamondCasinoHeistCut1{"diamondcasinoheistcut1", "Player 1", "Player 1 cut", std::nullopt, std::nullopt, 0};
static IntCommand _DiamondCasinoHeistCut2{"diamondcasinoheistcut2", "Player 2", "Player 2 cut", std::nullopt, std::nullopt, 0};
static IntCommand _DiamondCasinoHeistCut3{"diamondcasinoheistcut3", "Player 3", "Player 3 cut", std::nullopt, std::nullopt, 0};
static IntCommand _DiamondCasinoHeistCut4{"diamondcasinoheistcut4", "Player 4", "Player 4 cut", std::nullopt, std::nullopt, 0};
class SetCuts : public Command
{
using Command::Command;
virtual void OnCall() override
{
auto base = ScriptGlobal(1966898).At(1497).At(736).At(92);
*base.At(1).As<int*>() = _DiamondCasinoHeistCut1.GetState();
*base.At(2).As<int*>() = _DiamondCasinoHeistCut2.GetState();
*base.At(3).As<int*>() = _DiamondCasinoHeistCut3.GetState();
*base.At(4).As<int*>() = _DiamondCasinoHeistCut4.GetState();
}
};
class ForceReady : public Command
{
using Command::Command;
virtual void OnCall() override
{
auto base = ScriptGlobal(1971261);
*base.At(0, 68).At(8).At(0).As<int*>() = 1;
*base.At(1, 68).At(8).At(1).As<int*>() = 1;
*base.At(2, 68).At(8).At(2).As<int*>() = 1;
*base.At(3, 68).At(8).At(3).As<int*>() = 1;
}
};
static std::vector<std::pair<int, const char*>> diamondCasinoHeistDifficulty = {
{0, "Normal"},
{1, "Hard"}
};
static ListCommand _DiamondCasinoHeistDifficulty{"diamondcasinoheistdifficulty", "Difficulty", "Heist difficulty", diamondCasinoHeistDifficulty, 0};
static std::vector<std::pair<int, const char*>> diamondCasinoHeistPrimaryTarget = {
{3, "Diamonds"},
{1, "Gold"},
{2, "Artwork"},
{0, "Cash"}
};
static ListCommand _DiamondCasinoHeistPrimaryTarget{"diamondcasinoheistprimarytarget", "Primary Target", "Primary target", diamondCasinoHeistPrimaryTarget, 3};
static ListCommand* _DiamondCasinoHeistGunmanPtr = nullptr;
static ListCommand* _DiamondCasinoHeistApproachPtr = nullptr;
static std::vector<std::vector<std::vector<std::pair<int, const char*>>>> diamondCasinoHeistWeapon = {
{
{{0, "MK II Shotgun Loadout"}, {1, "MK II Rifle Loadout"}},
{{0, "MK II SMG Loadout"}, {1, "MK II Rifle Loadout"}},
{{0, "MK II Shotgun Loadout"}, {1, "MK II Rifle Loadout"}}
},
{
{{0, "Rifle Loadout"}, {1, "Shotgun Loadout"}},
{{0, "Rifle Loadout"}, {1, "Shotgun Loadout"}},
{{0, "Rifle Loadout"}, {1, "Shotgun Loadout"}}
},
{
{{0, "Combat PDW Loadout"}, {1, "Rifle Loadout"}},
{{0, "Shotgun Loadout"}, {1, "Rifle Loadout"}},
{{0, "Shotgun Loadout"}, {1, "Combat MG Loadout"}}
},
{
{{0, "SMG Loadout"}, {1, "Shotgun Loadout"}},
{{0, "Machine Pistol Loadout"}, {1, "Shotgun Loadout"}},
{{0, "SMG Loadout"}, {1, "Shotgun Loadout"}}
},
{
{{0, "Micro SMG Loadout"}, {1, "Machine Pistol Loadout"}},
{{0, "Micro SMG Loadout"}, {1, "Shotgun Loadout"}},
{{0, "Shotgun Loadout"}, {1, "Revolver Loadout"}}
},
{
{{0, " "}, {1, ""}},
{{0, ""}, {1, ""}},
{{0, ""}, {1, ""}}
}
};
static ListCommand _DiamondCasinoHeistWeapon{"diamondcasinoheistweapon", "Weapon", "Weapon", diamondCasinoHeistWeapon[5][0], 0};
static std::vector<std::pair<int, const char*>> diamondCasinoHeistGunman = {
{0, "Chester McCoy"},
{1, "Gustavo Mota"},
{2, "Patrick McReary"},
{3, "Charlie Reed"},
{4, "Karl Abolaji"},
{5, "Remove Gunman"}
};
class Gunman : public ListCommand
{
using ListCommand::ListCommand;
virtual void OnChange() override
{
_DiamondCasinoHeistWeapon.SetList(diamondCasinoHeistWeapon[this->GetState()][_DiamondCasinoHeistApproachPtr->GetState()]);
_DiamondCasinoHeistWeapon.SetState(0);
}
};
static Gunman _DiamondCasinoHeistGunman{"diamondcasinoheistgunman", "Gunman", "Gunman", diamondCasinoHeistGunman, 5};
static std::vector<std::pair<int, const char*>> diamondCasinoHeistApproach = {
{0, "Silent & Sneaky"},
{1, "The Big Con"},
{2, "Aggressive"}
};
class Approach : public ListCommand
{
using ListCommand::ListCommand;
virtual void OnChange() override
{
_DiamondCasinoHeistWeapon.SetList(diamondCasinoHeistWeapon[_DiamondCasinoHeistGunmanPtr->GetState()][this->GetState()]);
_DiamondCasinoHeistWeapon.SetState(0);
}
};
static Approach _DiamondCasinoHeistApproach{"diamondcasinoheistapproach", "Approach", "Heist approach", diamondCasinoHeistApproach, 0};
static struct InitPtrs
{
InitPtrs()
{
_DiamondCasinoHeistGunmanPtr = &_DiamondCasinoHeistGunman;
_DiamondCasinoHeistApproachPtr = &_DiamondCasinoHeistApproach;
}
} _initPtrs;
static std::vector<std::vector<std::pair<int, const char*>>> diamondCasinoHeistVehicle = {
{{0, "Zhaba"}, {1, "Vagrant"}, {2, "Outlaw"}, {3, "Everon"}},
{{0, "Sultan Classic"}, {1, "Gauntlet Classic"}, {2, "Ellie"}, {3, "Komoda"}},
{{0, "Retinue MK II"}, {1, "Drifty Yosemite"}, {2, "Sugoi"}, {3, "Jugular"}},
{{0, "Manchez"}, {1, "Stryder"}, {2, "Defiler"}, {3, "Lectro"}},
{{0, "Issi Classic"}, {1, "Asbo"}, {2, "Kanjo"}, {3, "Sentinel Classic"}},
{{0, " "}, {1, ""}, {2, ""}, {3, ""}}
};
static ListCommand _DiamondCasinoHeistVehicle{"diamondcasinoheistvehicle", "Vehicle", "Vehicle", diamondCasinoHeistVehicle[5], 0};
static std::vector<std::pair<int, const char*>> diamondCasinoHeistDriver = {
{0, "Chester McCoy"},
{1, "Eddie Toh"},
{2, "Taliana Martinez"},
{3, "Zach Nelson"},
{4, "Karim Denz"},
{5, "Remove Driver"}
};
class Driver : public ListCommand
{
using ListCommand::ListCommand;
virtual void OnChange() override
{
_DiamondCasinoHeistVehicle.SetList(diamondCasinoHeistVehicle[this->GetState()]);
_DiamondCasinoHeistVehicle.SetState(0);
}
};
static Driver _DiamondCasinoHeistDriver{"diamondcasinoheistdriver", "Driver", "Driver", diamondCasinoHeistDriver, 5};
static std::vector<std::pair<int, const char*>> diamondCasinoHeistHacker = {
{4, "Avi Schwartzman"},
{5, "Paige Harris"},
{2, "Christian Feltz"},
{3, "Yohan Blair"},
{1, "Rickie Lukens"},
{6, "Remove Hacker"}
};
static ListCommand _DiamondCasinoHeistHacker{"diamondcasinoheisthacker", "Hacker", "Hacker", diamondCasinoHeistHacker, 6};
class Setup : public Command
{
using Command::Command;
virtual void OnCall() override
{
Stats::SetInt("MPX_H3_COMPLETEDPOSIX", -1);
Stats::SetInt("MPX_H3OPT_MASKS", 4);
Stats::SetInt("MPX_H3OPT_WEAPS", _DiamondCasinoHeistWeapon.GetState());
Stats::SetInt("MPX_H3OPT_VEHS", _DiamondCasinoHeistVehicle.GetState());
Stats::SetInt("MPX_CAS_HEIST_FLOW", -1);
Stats::SetInt("MPX_H3_LAST_APPROACH", 0);
Stats::SetInt("MPX_H3OPT_APPROACH", _DiamondCasinoHeistApproach.GetState() + 1); // 1 = Silent & Sneaky, 2 = The Big Con, 3 = Aggressive
switch (_DiamondCasinoHeistDifficulty.GetState())
{
case 0: Stats::SetInt("MPX_H3_HARD_APPROACH", 0); break;
case 1: Stats::SetInt("MPX_H3_HARD_APPROACH", _DiamondCasinoHeistApproach.GetState() + 1); break;
default: break;
}
Stats::SetInt("MPX_H3OPT_TARGET", _DiamondCasinoHeistPrimaryTarget.GetState());
Stats::SetInt("MPX_H3OPT_POI", 1023);
Stats::SetInt("MPX_H3OPT_ACCESSPOINTS", 2047);
switch (_DiamondCasinoHeistGunman.GetState())
{
case 0: Stats::SetInt("MPX_H3OPT_CREWWEAP", 4); break;
case 1: Stats::SetInt("MPX_H3OPT_CREWWEAP", 2); break;
case 2: Stats::SetInt("MPX_H3OPT_CREWWEAP", 5); break;
case 3: Stats::SetInt("MPX_H3OPT_CREWWEAP", 3); break;
case 4: Stats::SetInt("MPX_H3OPT_CREWWEAP", 1); break;
case 5: Stats::SetInt("MPX_H3OPT_CREWWEAP", 6); break;
default: break;
}
switch (_DiamondCasinoHeistDriver.GetState())
{
case 0: Stats::SetInt("MPX_H3OPT_CREWDRIVER", 5); break;
case 1: Stats::SetInt("MPX_H3OPT_CREWDRIVER", 3); break;
case 2: Stats::SetInt("MPX_H3OPT_CREWDRIVER", 2); break;
case 3: Stats::SetInt("MPX_H3OPT_CREWDRIVER", 4); break;
case 4: Stats::SetInt("MPX_H3OPT_CREWDRIVER", 1); break;
case 5: Stats::SetInt("MPX_H3OPT_CREWDRIVER", 6); break;
default: break;
}
Stats::SetInt("MPX_H3OPT_CREWHACKER", _DiamondCasinoHeistHacker.GetState());
Stats::SetInt("MPX_H3OPT_DISRUPTSHIP", 3); // Security Strength: 1 = Strong, 2 = Medium, 3 = Weak
Stats::SetInt("MPX_H3OPT_BODYARMORLVL", -1);
Stats::SetInt("MPX_H3OPT_KEYLEVELS", 2); // 1 = Level1 Security Pass, 2 = Level2 Security Pass
Stats::SetInt("MPX_H3OPT_BITSET0", rand() % (INT_MAX)); // Refresh board
Stats::SetInt("MPX_H3OPT_BITSET1", rand() % (INT_MAX)); // Refresh board
ScriptMgr::Yield(500ms);
Stats::SetInt("MPX_H3OPT_BITSET0", -1); // Refresh board
Stats::SetInt("MPX_H3OPT_BITSET1", -1); // Refresh board
}
};
static IntCommand _DiamondCasinoHeistPotentialTake{"diamondcasinoheistpotentialtake", "Potential Take", "Updates potential take", std::nullopt, std::nullopt, 0};
class SetPotentialTake : public Command
{
using Command::Command;
virtual void OnCall() override
{
int primary_target = Stats::GetInt("MPX_H3OPT_TARGET");
switch (primary_target)
{
case 0: *Tunables::GetTunable(static_cast<joaat_t>(-1638885821)).As<int*>() = _DiamondCasinoHeistPotentialTake.GetState(); break; // "Cash"
case 1: *Tunables::GetTunable(static_cast<joaat_t>(-582734553)).As<int*>() = _DiamondCasinoHeistPotentialTake.GetState(); break; // "Gold"
case 2: *Tunables::GetTunable(static_cast<joaat_t>(1934398910)).As<int*>() = _DiamondCasinoHeistPotentialTake.GetState(); break; // "Artwork"
case 3: *Tunables::GetTunable(static_cast<joaat_t>(1277889925)).As<int*>() = _DiamondCasinoHeistPotentialTake.GetState(); break; // "Diamond"
default: break;
}
}
};
static IntCommand _DiamondCasinoHeistActualTake{"diamondcasinoheistactualtake", "Actual Take", "Updates actual take", std::nullopt, std::nullopt, 0};
class SetActualTake : public Command
{
using Command::Command;
virtual void OnCall() override
{
*ScriptLocal("fm_mission_controller"_J, 20387).At(2686).As<int*>() = _DiamondCasinoHeistActualTake.GetState();
}
};
class SkipHacking : public Command
{
using Command::Command;
virtual void OnCall() override
{
*ScriptLocal("fm_mission_controller"_J, 53999).As<int*>() = 5;
*ScriptLocal("fm_mission_controller"_J, 55065).As<int*>() = 5;
}
};
class SkipDrilling : public Command
{
using Command::Command;
virtual void OnCall() override
{
*ScriptLocal("fm_mission_controller"_J, 10547).At(7).As<int*>() = *ScriptLocal("fm_mission_controller"_J, 10547).At(37).As<int*>();
}
};
class InstantFinish : public Command
{
using Command::Command;
virtual void OnCall() override
{
Scripts::ForceScriptHost(Scripts::FindScriptThread("fm_mission_controller"_J));
ScriptMgr::Yield(500ms);
*ScriptLocal("fm_mission_controller"_J, 20387).At(1740).At(1).As<int*>() = 80;
*ScriptLocal("fm_mission_controller"_J, 20387).At(2686).As<int*>() = 4443220;
*ScriptLocal("fm_mission_controller"_J, 20387).At(1062).As<int*>() = 5;
*ScriptLocal("fm_mission_controller"_J, 20387).As<int*>() = 12;
*ScriptLocal("fm_mission_controller"_J, 29006).At(1).As<int*>() = 99999;
*ScriptLocal("fm_mission_controller"_J, 32462).At(1).At(68).As<int*>() = 99999;
}
};
static SetCuts _DiamondCasinoHeistSetCuts{"diamondcasinoheistsetcuts", "Set Cuts", "Sets heist cut"};
static ForceReady _DiamondCasinoHeistForceReady{"diamondcasinoheistforceready", "Force Ready", "Forces all players to be ready"};
static Setup _DiamondCasinoHeistSetup{"diamondcasinoheistsetup", "Setup", "Sets up diamond casino heist"};
static SetPotentialTake _DiamondCasinoHeistSetPotentialTake{"diamondcasinoheistsetpotentialtake", "Set Potential Take", "Updates potential take"};
static SetActualTake _DiamondCasinoHeistSetActualTake{"diamondcasinoheistsetactualtake", "Set Actual Take", "Updates actual take"};
static SkipHacking _DiamondCasinoHeistSkipHacking{"diamondcasinoheistskiphacking", "Skip Hacking", "Skips hacking process"};
static SkipDrilling _DiamondCasinoHeistSkipDrilling{"diamondcasinoheistskipdrilling", "Skip Drilling", "Skips drilling process"};
static InstantFinish _DiamondCasinoHeistInstantFinish{"diamondcasinoheistinstantfinish", "Instant Finish", "Instantly passes the heist"};
}
}
@@ -0,0 +1,141 @@
#include "core/commands/Command.hpp"
#include "core/commands/IntCommand.hpp"
#include "core/commands/ListCommand.hpp"
#include "game/gta/Stats.hpp"
#include "game/gta/ScriptGlobal.hpp"
#include "game/gta/ScriptLocal.hpp"
#include "core/backend/ScriptMgr.hpp"
namespace YimMenu::Features
{
namespace DoomsdayHeist
{
static IntCommand _DoomsdayHeistCut1{"doomsdayheistcut1", "Player 1", "Player 1 cut", std::nullopt, std::nullopt, 0};
static IntCommand _DoomsdayHeistCut2{"doomsdayheistcut2", "Player 2", "Player 2 cut", std::nullopt, std::nullopt, 0};
static IntCommand _DoomsdayHeistCut3{"doomsdayheistcut3", "Player 3", "Player 3 cut", std::nullopt, std::nullopt, 0};
static IntCommand _DoomsdayHeistCut4{"doomsdayheistcut4", "Player 4", "Player 4 cut", std::nullopt, std::nullopt, 0};
class SetCuts : public Command
{
using Command::Command;
virtual void OnCall() override
{
auto base = ScriptGlobal(1962078).At(812).At(50);
*base.At(1).As<int*>() = _DoomsdayHeistCut1.GetState();
*base.At(2).As<int*>() = _DoomsdayHeistCut2.GetState();
*base.At(3).As<int*>() = _DoomsdayHeistCut3.GetState();
*base.At(4).As<int*>() = _DoomsdayHeistCut4.GetState();
}
};
class ForceReady : public Command
{
using Command::Command;
virtual void OnCall() override
{
auto base = ScriptGlobal(1882925);
*base.At(0, 149).At(43).At(0).At(4).At(8).As<int*>() = 1;
*base.At(1, 149).At(43).At(1).At(4).At(8).As<int*>() = 1;
*base.At(2, 149).At(43).At(2).At(4).At(8).As<int*>() = 1;
*base.At(3, 149).At(43).At(3).At(4).At(8).As<int*>() = 1;
}
};
static std::vector<std::pair<int, const char*>> doomsdayHeistCategory = {
{0, "The Data Breaches"},
{1, "The Bogdan Problem"},
{2, "The Doomsday Senario"}
};
static ListCommand _DoomsdayHeistCategory{"doomsdayheistcategory", "Select Heist", "Heist categories", doomsdayHeistCategory, 0};
class Setup : public Command
{
using Command::Command;
virtual void OnCall() override
{
switch (_DoomsdayHeistCategory.GetState())
{
case 0:
Stats::SetInt("MPX_GANGOPS_FLOW_MISSION_PROG", 503);
Stats::SetInt("MPX_GANGOPS_HEIST_STATUS", -229383);
Stats::SetInt("MPX_GANGOPS_FLOW_NOTIFICATIONS", 1557);
break;
case 1:
Stats::SetInt("MPX_GANGOPS_FLOW_MISSION_PROG", 240);
Stats::SetInt("MPX_GANGOPS_HEIST_STATUS", -229378);
Stats::SetInt("MPX_GANGOPS_FLOW_NOTIFICATIONS", 1557);
break;
case 2:
Stats::SetInt("MPX_GANGOPS_FLOW_MISSION_PROG", 16368);
Stats::SetInt("MPX_GANGOPS_HEIST_STATUS", -229380);
Stats::SetInt("MPX_GANGOPS_FLOW_NOTIFICATIONS", 1557);
break;
default: break;
}
ScriptMgr::Yield(500ms);
*ScriptLocal("gb_gang_ops_planning"_J, 207).As<int*>() = 6; // Reload planning screen
}
};
class SkipHacking : public Command
{
using Command::Command;
virtual void OnCall() override
{
*ScriptLocal("fm_mission_controller"_J, 1538).As<int*>() = 3;
*ScriptLocal("fm_mission_controller"_J, 1569).As<int*>() = 2;
*ScriptLocal("fm_mission_controller"_J, 1294).At(135).As<int*>() = 3;
}
};
class InstantFinish : public Command
{
using Command::Command;
virtual void OnCall() override
{
Scripts::ForceScriptHost(Scripts::FindScriptThread("fm_mission_controller"_J));
ScriptMgr::Yield(500ms);
*ScriptLocal("fm_mission_controller"_J, 20387).At(1725).At(1).As<int*>() = 80;
*ScriptLocal("fm_mission_controller"_J, 20387).As<int*>() = 12;
*ScriptLocal("fm_mission_controller"_J, 29006).At(1).As<int*>() = 99999;
*ScriptLocal("fm_mission_controller"_J, 32462).At(1).At(68).As<int*>() = 99999;
// TODO: find a way of getting current heist info so that InstantFinishAct3 can be implemented here conditionally.
}
};
class InstantFinishAct3 : public Command
{
using Command::Command;
virtual void OnCall() override
{
Scripts::ForceScriptHost(Scripts::FindScriptThread("fm_mission_controller"_J));
ScriptMgr::Yield(500ms);
*ScriptLocal("fm_mission_controller"_J, 20387).As<int*>() = 12;
*ScriptLocal("fm_mission_controller"_J, 20387).At(1740).At(1).As<int*>() = 150;
*ScriptLocal("fm_mission_controller"_J, 20387).At(1062).As<int*>() = 5;
*ScriptLocal("fm_mission_controller"_J, 29006).At(1).As<int*>() = 99999;
*ScriptLocal("fm_mission_controller"_J, 32462).At(1).At(68).As<int*>() = 99999;
}
};
static SetCuts _DoomsdayHeistSetCuts{"doomsdayheistsetcuts", "Set Cuts", "Sets heist cut"};
static ForceReady _DoomsdayHeistForceReady{"doomsdayheistforceready", "Force Ready", "Forces all players to be ready"};
static Setup _DoomsdayHeistSetup{"doomsdayheistsetup", "Setup", "Sets up doomsday heist"};
static SkipHacking _DoomsdayHeistSkipHacking{"doomsdayheistskiphacking", "Skip Hacking", "Skips hacking process"};
static InstantFinish _DoomsdayHeistInstantFinish{"doomsdayheistinstantfinish", "Instant Finish", "Instantly passes the heist"};
static InstantFinishAct3 _DoomsdayHeistInstantFinishAct3{"doomsdayheistinstantfinishact3", "Instant Finish (Act: III)", "Instantly passes Doomsday Scenario Act: III"};
}
}
@@ -32,62 +32,62 @@ namespace YimMenu::Features
{
if (!m_CanLaunchJobPatch)
{
m_CanLaunchJobPatch = ScriptPatches::AddPatch("fmmc_launcher"_J, "2D 05 0C 00 00 71", 5, {0x72, 0x2E, 0x05, 0x01}); // the main patch that bypasses the not enough players alert
m_CanLaunchJobPatch = ScriptPatches::AddPatch("fmmc_launcher"_J, ScriptPointer("CanLaunchJobPatch", "2D 05 0C 00 00 71").Add(5), {0x72, 0x2E, 0x05, 0x01}); // the main patch that bypasses the not enough players alert
}
m_CanLaunchJobPatch->Enable();
// these patches allow the mission request system to launch fm_mission_controller with insufficent players
if (!m_MissionRequestPatch1)
{
m_MissionRequestPatch1 = ScriptPatches::AddPatch("freemode"_J, "38 00 72 5D ? ? ? 38 00 5D ? ? ? 2E 02 00 38 00 38 01", 0, std::vector<std::uint8_t>(14, 0x0));
m_MissionRequestPatch1 = ScriptPatches::AddPatch("freemode"_J, ScriptPointer("MissionRequestPatch1", "38 00 72 5D ? ? ? 38 00 5D ? ? ? 2E 02 00 38 00 38 01"), std::vector<std::uint8_t>(14, 0x0));
}
m_MissionRequestPatch1->Enable();
if (!m_MissionRequestPatch2)
{
m_MissionRequestPatch2 = ScriptPatches::AddPatch("freemode"_J, "25 ? 37 07 33 37 07 5D ? ? ? 39 11", 20, {0x72});
m_MissionRequestPatch2 = ScriptPatches::AddPatch("freemode"_J, ScriptPointer("MissionRequestPatch2", "25 ? 37 07 33 37 07 5D ? ? ? 39 11").Add(20), {0x72});
}
m_MissionRequestPatch2->Enable();
if (!m_MissionRequestPatch3)
{
m_MissionRequestPatch3 = ScriptPatches::AddPatch("freemode"_J, "2D 03 1A 00 00 38 00 5D ? ? ? 39 05", 5, {0x72, 0x2E, 0x03, 0x01});
m_MissionRequestPatch3 = ScriptPatches::AddPatch("freemode"_J, ScriptPointer("MissionRequestPatch3", "2D 03 1A 00 00 38 00 5D ? ? ? 39 05").Add(5), {0x72, 0x2E, 0x03, 0x01});
}
m_MissionRequestPatch3->Enable();
if (!m_MissionRequestPatch4)
{
m_MissionRequestPatch4 = ScriptPatches::AddPatch("freemode"_J, "5D ? ? ? 39 06 38 01 5D ? ? ? 25", 0, {0x72, 0x2E, 0x04, 0x01});
m_MissionRequestPatch4 = ScriptPatches::AddPatch("freemode"_J, ScriptPointer("MissionRequestPatch4", "5D ? ? ? 39 06 38 01 5D ? ? ? 25"), {0x72, 0x2E, 0x04, 0x01});
}
m_MissionRequestPatch4->Enable();
if (!m_PlayerCountWatchdogPatch1)
{
m_PlayerCountWatchdogPatch1 = ScriptPatches::AddPatch("fmmc_launcher"_J, "2D 02 09 00 00 25 A4", 5, {0x71, 0x2E, 0x02, 0x01}); // instant kick if this check fails
m_PlayerCountWatchdogPatch1 = ScriptPatches::AddPatch("fmmc_launcher"_J, ScriptPointer("PlayerCountWatchdogPatch1", "2D 02 09 00 00 25 A4").Add(5), {0x71, 0x2E, 0x02, 0x01}); // instant kick if this check fails
}
m_PlayerCountWatchdogPatch1->Enable();
if (!m_PlayerCountWatchdogPatch2)
{
m_PlayerCountWatchdogPatch2 = ScriptPatches::AddPatch("fmmc_launcher"_J, "2D 04 0B 00 00 2C ? ? ? 71 5D", 5, {0x71, 0x2E, 0x04, 0x01});
m_PlayerCountWatchdogPatch2 = ScriptPatches::AddPatch("fmmc_launcher"_J, ScriptPointer("PlayerCountWatchdogPatch2", "2D 04 0B 00 00 2C ? ? ? 71 5D").Add(5), {0x71, 0x2E, 0x04, 0x01});
}
m_PlayerCountWatchdogPatch2->Enable();
if (!m_HeistTeamsPatch1)
{
m_HeistTeamsPatch1 = ScriptPatches::AddPatch("fmmc_launcher"_J, "47 ? ? 5B 7B 00 38 04", 0, {0x2B, 0x2B, 0x00, 0x55}); // TODO: doesn't work for doomsday heist
m_HeistTeamsPatch1 = ScriptPatches::AddPatch("fmmc_launcher"_J, ScriptPointer("HeistTeamsPatch1", "47 ? ? 5B 7B 00 38 04"), {0x2B, 0x2B, 0x00, 0x55}); // TODO: doesn't work for doomsday heist
}
m_HeistTeamsPatch1->Enable();
if (!m_HeistTeamsPatch2)
{
m_HeistTeamsPatch2 = ScriptPatches::AddPatch("fmmc_launcher"_J, "2D 01 05 00 00 25 5D", 5, {0x72, 0x2E, 0x01, 0x01});
m_HeistTeamsPatch2 = ScriptPatches::AddPatch("fmmc_launcher"_J, ScriptPointer("HeistTeamsPatch2", "2D 01 05 00 00 25 5D").Add(5), {0x72, 0x2E, 0x01, 0x01});
}
m_HeistTeamsPatch2->Enable();
if (!m_ShouldFailMissionPatch1)
{
m_ShouldFailMissionPatch1 = ScriptPatches::AddPatch("fm_mission_controller"_J, "50 ? ? 78 82 06 1F 56 ? ? 38 02", 0, {0x00, 0x00, 0x00, 0x72, 0x00});
m_ShouldFailMissionPatch1 = ScriptPatches::AddPatch("fm_mission_controller"_J, ScriptPointer("ShouldFailMissionPatch1", "50 ? ? 78 82 06 1F 56 ? ? 38 02"), {0x00, 0x00, 0x00, 0x72, 0x00});
}
m_ShouldFailMissionPatch1->Enable();
@@ -96,7 +96,10 @@ namespace YimMenu::Features
// TODO: this is a very bad idea that can break anytime
// for some reason, Rockstar thought it's a good idea to copy-paste the same failure check in four different branches, "just in case"
for (int i = 0; i < 4; i++)
m_ShouldFailMissionPatches.push_back(ScriptPatches::AddPatch("fm_mission_controller"_J, "38 02 5D ? ? ? 71 09 2A 56 07 00 71 5D ? ? ? 06 1F 56", 0, {0x71, 0x00, 0x00, 0x00, 0x00, 0x00}));
{
std::string ptrName = "ShouldFailMissionPatches" + std::to_string(i);
m_ShouldFailMissionPatches.push_back(ScriptPatches::AddPatch("fm_mission_controller"_J, ScriptPointer(ptrName, "38 02 5D ? ? ? 71 09 2A 56 07 00 71 5D ? ? ? 06 1F 56"), {0x71, 0x00, 0x00, 0x00, 0x00, 0x00}));
}
}
for (auto& patch : m_ShouldFailMissionPatches)
@@ -104,37 +107,37 @@ namespace YimMenu::Features
if (!m_ShouldFailMissionPatch2)
{
m_ShouldFailMissionPatch2 = ScriptPatches::AddPatch("fm_mission_controller"_J, "56 07 00 38 02 5D ? ? ? 20 56 BC 01", 0, {0x2B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2B, 0x71}); // some heist check, more or less same as above
m_ShouldFailMissionPatch2 = ScriptPatches::AddPatch("fm_mission_controller"_J, ScriptPointer("ShouldFailMissionPatch2", "56 07 00 38 02 5D ? ? ? 20 56 BC 01"), {0x2B, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2B, 0x71}); // some heist check, more or less same as above
}
m_ShouldFailMissionPatch2->Enable();
if (!m_ShouldFailMissionPatch3)
{
m_ShouldFailMissionPatch3 = ScriptPatches::AddPatch("fm_mission_controller"_J, "50 ? ? 78 82 06 1F 56 2E 01", 0, {0x00, 0x00, 0x00, 0x00, 0x72});
m_ShouldFailMissionPatch3 = ScriptPatches::AddPatch("fm_mission_controller"_J, ScriptPointer("ShouldFailMissionPatch3", "50 ? ? 78 82 06 1F 56 2E 01"), {0x00, 0x00, 0x00, 0x00, 0x72});
}
m_ShouldFailMissionPatch3->Enable();
if (!m_NotEnoughTeamsPatch)
{
m_NotEnoughTeamsPatch = ScriptPatches::AddPatch("fm_mission_controller"_J, "2D 00 02 00 00 61 ? ? ? 47 ? ? 72 57 04 00 72 2E 00 01 4F", 5, {0x71, 0x2E, 0x00, 0x01});
m_NotEnoughTeamsPatch = ScriptPatches::AddPatch("fm_mission_controller"_J, ScriptPointer("NotEnoughTeamsPatch", "2D 00 02 00 00 61 ? ? ? 47 ? ? 72 57 04 00 72 2E 00 01 4F").Add(5), {0x71, 0x2E, 0x00, 0x01});
}
m_NotEnoughTeamsPatch->Enable();
if (!m_IsTeamValidPatch)
{
m_IsTeamValidPatch = ScriptPatches::AddPatch("fm_mission_controller"_J, "2D 01 03 00 00 38 00 71 57 1D 00", 5, {0x72, 0x2E, 0x01, 0x01});
m_IsTeamValidPatch = ScriptPatches::AddPatch("fm_mission_controller"_J, ScriptPointer("IsTeamValidPatch", "2D 01 03 00 00 38 00 71 57 1D 00").Add(5), {0x72, 0x2E, 0x01, 0x01});
}
m_IsTeamValidPatch->Enable();
if (!m_EnsureMissionPassedPatch)
{
m_EnsureMissionPassedPatch = ScriptPatches::AddPatch("fm_mission_controller"_J, "55 C8 FF 61", 3, {0x2E, 0x00, 0x00}); // the game does one final check to ensure all players exist before the mission is passed
m_EnsureMissionPassedPatch = ScriptPatches::AddPatch("fm_mission_controller"_J, ScriptPointer("EnsureMissionPassedPatch", "55 C8 FF 61").Add(3), {0x2E, 0x00, 0x00}); // the game does one final check to ensure all players exist before the mission is passed
}
m_EnsureMissionPassedPatch->Enable();
if (!m_ProcessPhoneHackingPatch)
{
m_ProcessPhoneHackingPatch = ScriptPatches::AddPatch("fm_mission_controller"_J, "58 13 00 38 00 4F ? ? 48", 0, {0x2B, 0x00, 0x00});
m_ProcessPhoneHackingPatch = ScriptPatches::AddPatch("fm_mission_controller"_J, ScriptPointer("ProcessPhoneHackingPatch", "58 13 00 38 00 4F ? ? 48"), {0x2B, 0x00, 0x00});
}
if (!m_QuickRestartPatch1)
+75
View File
@@ -0,0 +1,75 @@
#include "core/commands/BoolCommand.hpp"
#include "core/hooking/CallHook.hpp"
#include "game/backend/NativeHooks.hpp"
#include "game/gta/Natives.hpp"
#include "game/gta/Stats.hpp"
namespace YimMenu::Features
{
static CallHook formatIntCaller1Hook{};
static CallHook formatIntCaller2Hook{};
static void FormatIntHook(int64_t integer, char* str, size_t strSize, bool insertCommas);
static void ScaleformAddIntHook(rage::scrNativeCallContext* ctx);
class FormatMoney : public BoolCommand
{
using BoolCommand::BoolCommand;
virtual void OnEnable() override
{
if (!formatIntCaller1Hook)
{
formatIntCaller1Hook = CallSiteHook::AddHook(Pointers.FormatIntCaller1, FormatIntHook);
}
formatIntCaller1Hook->Enable();
if (!formatIntCaller2Hook)
{
formatIntCaller2Hook = CallSiteHook::AddHook(Pointers.FormatIntCaller2, FormatIntHook);
}
formatIntCaller2Hook->Enable();
NativeHooks::AddHook("shop_controller"_J, NativeIndex::SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT, &ScaleformAddIntHook);
}
virtual void OnDisable() override
{
if (formatIntCaller1Hook)
{
formatIntCaller1Hook->Disable();
}
if (formatIntCaller2Hook)
{
formatIntCaller2Hook->Disable();
}
}
};
static FormatMoney _FormatMoney{"formatmoney", "Format Money", "Formats HUD money with commas."};
static void FormatIntHook(int64_t integer, char* str, size_t strSize, bool insertCommas)
{
insertCommas = true;
auto original = formatIntCaller1Hook->GetOriginal<void (*)(int64_t, char*, size_t, bool)>();
original(integer, str, strSize, insertCommas);
}
static void ScaleformAddIntHook(rage::scrNativeCallContext* ctx)
{
int value = ctx->GetArg<int>(0);
if (_FormatMoney.GetState())
{
int chips = Stats::GetInt("MPX_CASINO_CHIPS");
if (value == chips && chips >= 1000)
{
auto formatted = std::to_string(value);
for (int i = formatted.size() - 3; i > 0; i -= 3)
{
formatted.insert(i, ",");
}
return GRAPHICS::SCALEFORM_MOVIE_METHOD_ADD_PARAM_PLAYER_NAME_STRING(formatted.c_str());
}
}
GRAPHICS::SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(value);
}
}
+26
View File
@@ -0,0 +1,26 @@
#include "core/commands/LoopedCommand.hpp"
#include "game/backend/Self.hpp"
#include "game/gta/Natives.hpp"
namespace YimMenu::Features
{
class MobileRadio : public LoopedCommand
{
using LoopedCommand::LoopedCommand;
virtual void OnTick() override
{
AUDIO::SET_MOBILE_PHONE_RADIO_STATE(true);
AUDIO::SET_MOBILE_RADIO_ENABLED_DURING_GAMEPLAY(true);
}
virtual void OnDisable() override
{
AUDIO::SET_MOBILE_PHONE_RADIO_STATE(false);
AUDIO::SET_MOBILE_RADIO_ENABLED_DURING_GAMEPLAY(false);
}
};
static MobileRadio _MobileRadio{"mobileradio", "listen any radio station on foot", "Allows you to listen to any radio station on foot with Hotkey Q"};
}
+1 -1
View File
@@ -13,7 +13,7 @@ namespace YimMenu::Features
{
if (!m_ShopPatch)
{
m_ShopPatch = ScriptPatches::AddPatch("shop_controller"_J, "2D 01 04 00 00 2C ? ? ? 56 ? ? 71", 5, {0x71, 0x2E, 0x01, 0x01}); // disable the kick out subroutine
m_ShopPatch = ScriptPatches::AddPatch("shop_controller"_J, ScriptPointer("ShopPatch", "2D 01 04 00 00 2C ? ? ? 56 ? ? 71").Add(5), {0x71, 0x2E, 0x01, 0x01}); // disable the kick out subroutine
}
m_ShopPatch->Enable();
}
@@ -15,13 +15,13 @@ namespace YimMenu::Features
{
if (!m_CanUseVehiclePatch)
{
m_CanUseVehiclePatch = ScriptPatches::AddPatch("carmod_shop"_J, "2D ? ? ? ? 38 ? 5D ? ? ? 56 ? ? 71 2E ? ? 5D", 5, {0x72, 0x2E, 0x03, 0x01});
m_CanUseVehiclePatch = ScriptPatches::AddPatch("carmod_shop"_J, ScriptPointer("CanUseVehiclePatch", "2D ? ? ? ? 38 ? 5D ? ? ? 56 ? ? 71 2E ? ? 5D").Add(5), {0x72, 0x2E, 0x03, 0x01});
}
m_CanUseVehiclePatch->Enable();
if (!m_BlockMenuOptionPatch)
{
m_BlockMenuOptionPatch = ScriptPatches::AddPatch("carmod_shop"_J, "2D ? ? ? ? 38 ? 5D ? ? ? 5D ? ? ? 56", 5, {0x71, 0x2E, 0x01, 0x01});
m_BlockMenuOptionPatch = ScriptPatches::AddPatch("carmod_shop"_J, ScriptPointer("BlockMenuOptionPatch", "2D ? ? ? ? 38 ? 5D ? ? ? 5D ? ? ? 56").Add(5), {0x71, 0x2E, 0x01, 0x01});
}
m_BlockMenuOptionPatch->Enable();
}
@@ -75,7 +75,6 @@ namespace YimMenu::Features
auto new_coords{coords};
ResolveZCoordinate(new_coords);
Self::GetPed().TeleportTo(new_coords);
ScriptMgr::Yield();
});
HUD::SET_WAYPOINT_OFF();
}
+1 -1
View File
@@ -105,7 +105,7 @@ namespace YimMenu::Features
// ensure shop controller can't control the weather
if (!m_ShopControllerWeatherPatch)
{
m_ShopControllerWeatherPatch = ScriptPatches::AddPatch("shop_controller"_J, "2D 00 07 00 00 71 39 02 71", 5, {0x2E, 0x00, 0x00});
m_ShopControllerWeatherPatch = ScriptPatches::AddPatch("shop_controller"_J, ScriptPointer("ShopControllerWeatherPatch", "2D 00 07 00 00 71 39 02 71").Add(5), {0x2E, 0x00, 0x00});
}
m_ShopControllerWeatherPatch->Enable();
}
+61 -20
View File
@@ -10,8 +10,12 @@
#include "game/gta/Pools.hpp"
#include "game/gta/Scripts.hpp"
//#include "game/gta/data/PedModels.hpp"
#include "game/gta/data/RandomEvents.hpp"
#include "game/gta/invoker/Invoker.hpp"
#include "game/gta/Natives.hpp"
#include "types/script/globals/GPBD_FM_2.hpp"
#include "types/script/globals/GSBD_RandomEvents.hpp"
#include "types/script/locals/FMRandomEvents.hpp"
namespace
{
@@ -58,6 +62,9 @@ namespace YimMenu::Features
ColorCommand _HashColorPeds("hashcolorpeds", "Ped Hash Color", "Changes the color of the hash ESP for peds", ImVec4{1.0f, 1.0f, 1.0f, 1.0f});
ColorCommand _DistanceColorPeds("distancecolorpeds", "Ped Distance Color", "Changes the color of the distance ESP for peds", ImVec4{1.0f, 1.0f, 1.0f, 1.0f});
ColorCommand _SkeletonColorPeds("skeletoncolorpeds", "Ped Skeleton Color", "Changes the color of the skeleton ESP for peds", ImVec4{1.0f, 1.0f, 1.0f, 1.0f});
// Random Events
BoolCommand _ESPDrawRandomEvents("esprandomevents", "Random Events ESP", "Should the ESP draw Random Events?");
}
namespace YimMenu
@@ -75,42 +82,43 @@ namespace YimMenu
static ImVec4 Orange = ImVec4(0.69f, 0.49f, 0.29f, 1.f);
static ImVec4 Red = ImVec4(0.69f, 0.29f, 0.29f, 1.f);
static ImVec4 Blue = ImVec4(0.36f, 0.71f, 0.89f, 1.f);
static ImVec4 White = ImVec4(1.0f, 1.0f, 1.0f, 1.0f);
static auto boneToScreen = [](rage::fvector3 bone)
static auto worldToScreen = [](rage::fvector3 coords)
{
float screen_x{}, screen_y{};
GRAPHICS::GET_SCREEN_COORD_FROM_WORLD_COORD(bone.x, bone.y, bone.z, &screen_x, &screen_y);
GRAPHICS::GET_SCREEN_COORD_FROM_WORLD_COORD(coords.x, coords.y, coords.z, &screen_x, &screen_y);
return ImVec2{screen_x * (*Pointers.ScreenResX), screen_y * (*Pointers.ScreenResY)};
};
void DrawSkeleton(Ped ped, ImDrawList* drawList, ImColor color)
{
drawList->AddLine(boneToScreen(ped.GetBonePosition(headBone)), boneToScreen(ped.GetBonePosition(neckBone)), color, 1.5f);
drawList->AddLine(worldToScreen(ped.GetBonePosition(headBone)), worldToScreen(ped.GetBonePosition(neckBone)), color, 1.5f);
drawList->AddLine(boneToScreen(ped.GetBonePosition(neckBone)), boneToScreen(ped.GetBonePosition(leftShoulderBone)), color, 1.5f);
drawList->AddLine(boneToScreen(ped.GetBonePosition(leftShoulderBone)), boneToScreen(ped.GetBonePosition(leftElbowBone)), color, 1.5f);
drawList->AddLine(boneToScreen(ped.GetBonePosition(leftElbowBone)), boneToScreen(ped.GetBonePosition(leftHandBone)), color, 1.5f);
drawList->AddLine(worldToScreen(ped.GetBonePosition(neckBone)), worldToScreen(ped.GetBonePosition(leftShoulderBone)), color, 1.5f);
drawList->AddLine(worldToScreen(ped.GetBonePosition(leftShoulderBone)), worldToScreen(ped.GetBonePosition(leftElbowBone)), color, 1.5f);
drawList->AddLine(worldToScreen(ped.GetBonePosition(leftElbowBone)), worldToScreen(ped.GetBonePosition(leftHandBone)), color, 1.5f);
drawList->AddLine(boneToScreen(ped.GetBonePosition(neckBone)), boneToScreen(ped.GetBonePosition(rightShoulderBone)), color, 1.5f);
drawList->AddLine(boneToScreen(ped.GetBonePosition(rightShoulderBone)), boneToScreen(ped.GetBonePosition(rightElbowBone)), color, 1.5f);
drawList->AddLine(boneToScreen(ped.GetBonePosition(rightElbowBone)), boneToScreen(ped.GetBonePosition(rightHandBone)), color, 1.5f);
drawList->AddLine(worldToScreen(ped.GetBonePosition(neckBone)), worldToScreen(ped.GetBonePosition(rightShoulderBone)), color, 1.5f);
drawList->AddLine(worldToScreen(ped.GetBonePosition(rightShoulderBone)), worldToScreen(ped.GetBonePosition(rightElbowBone)), color, 1.5f);
drawList->AddLine(worldToScreen(ped.GetBonePosition(rightElbowBone)), worldToScreen(ped.GetBonePosition(rightHandBone)), color, 1.5f);
drawList->AddLine(boneToScreen(ped.GetBonePosition(neckBone)), boneToScreen(ped.GetBonePosition(torsoBone)), color, 1.5f);
drawList->AddLine(worldToScreen(ped.GetBonePosition(neckBone)), worldToScreen(ped.GetBonePosition(torsoBone)), color, 1.5f);
drawList->AddLine(boneToScreen(ped.GetBonePosition(torsoBone)), boneToScreen(ped.GetBonePosition(leftKneeBone)), color, 1.5f);
drawList->AddLine(boneToScreen(ped.GetBonePosition(leftKneeBone)), boneToScreen(ped.GetBonePosition(leftFootBone)), color, 1.5f);
drawList->AddLine(worldToScreen(ped.GetBonePosition(torsoBone)), worldToScreen(ped.GetBonePosition(leftKneeBone)), color, 1.5f);
drawList->AddLine(worldToScreen(ped.GetBonePosition(leftKneeBone)), worldToScreen(ped.GetBonePosition(leftFootBone)), color, 1.5f);
drawList->AddLine(boneToScreen(ped.GetBonePosition(torsoBone)), boneToScreen(ped.GetBonePosition(rightKneeBone)), color, 1.5f);
drawList->AddLine(boneToScreen(ped.GetBonePosition(rightKneeBone)), boneToScreen(ped.GetBonePosition(rightFootBone)), color, 1.5f);
drawList->AddLine(worldToScreen(ped.GetBonePosition(torsoBone)), worldToScreen(ped.GetBonePosition(rightKneeBone)), color, 1.5f);
drawList->AddLine(worldToScreen(ped.GetBonePosition(rightKneeBone)), worldToScreen(ped.GetBonePosition(rightFootBone)), color, 1.5f);
}
//TODO : Very bare bones currently, expand and possibly refactor
void ESP::DrawPlayer(Player plyr, ImDrawList* drawList)
{
if (!plyr.IsValid() || !plyr.GetPed().IsValid() || plyr == Self::GetPlayer()
|| boneToScreen(plyr.GetPed().GetBonePosition(torsoBone)).x == 0
|| worldToScreen(plyr.GetPed().GetBonePosition(torsoBone)).x == 0
|| (plyr.GetPed().IsDead() && !Features::_ESPDrawDeadPlayers.GetState()))
return;
@@ -132,7 +140,7 @@ namespace YimMenu
if (Features::_ESPName.GetState())
{
drawList->AddText(boneToScreen(plyr.GetPed().GetBonePosition(headBone)),
drawList->AddText(worldToScreen(plyr.GetPed().GetBonePosition(headBone)),
plyr == Players::GetSelected() ? ImGui::ColorConvertFloat4ToU32(Blue) :
ImGui::ColorConvertFloat4ToU32(Features::_NameColorPlayers.GetState()),
plyr.GetName());
@@ -141,7 +149,7 @@ namespace YimMenu
if (Features::_ESPDistance.GetState())
{
std::string distanceStr = std::to_string((int)Self::GetPed().GetPosition().GetDistance(plyr.GetPed().GetBonePosition(torsoBone))) + "m";
drawList->AddText({boneToScreen(plyr.GetPed().GetBonePosition(headBone)).x, boneToScreen(plyr.GetPed().GetBonePosition(headBone)).y + 20}, colorBasedOnDistance, distanceStr.c_str());
drawList->AddText({worldToScreen(plyr.GetPed().GetBonePosition(headBone)).x, worldToScreen(plyr.GetPed().GetBonePosition(headBone)).y + 20}, colorBasedOnDistance, distanceStr.c_str());
}
currentFont->Scale = originalFontSize;
@@ -160,7 +168,7 @@ namespace YimMenu
void ESP::DrawPed(Ped ped, ImDrawList* drawList)
{
if (!ped.IsValid() || ped.IsPlayer() || ped == Self::GetPlayer().GetPed() || boneToScreen(ped.GetBonePosition(torsoBone)).x == 0 || (ped.IsDead() && !Features::_ESPDrawDeadPeds.GetState()))
if (!ped.IsValid() || ped.IsPlayer() || ped == Self::GetPlayer().GetPed() || worldToScreen(ped.GetBonePosition(torsoBone)).x == 0 || (ped.IsDead() && !Features::_ESPDrawDeadPeds.GetState()))
return;
float distanceToPed = 0.0f;
@@ -210,13 +218,13 @@ namespace YimMenu
}
if (!info.empty())
drawList->AddText(boneToScreen(ped.GetBonePosition(headBone)), ImGui::ColorConvertFloat4ToU32(Features::_HashColorPeds.GetState()), info.c_str());
drawList->AddText(worldToScreen(ped.GetBonePosition(headBone)), ImGui::ColorConvertFloat4ToU32(Features::_HashColorPeds.GetState()), info.c_str());
if (Features::_ESPDistancePeds.GetState())
{
std::string distanceStr = std::to_string((int)distanceToPed) + "m";
drawList->AddText(
{boneToScreen(ped.GetBonePosition(headBone)).x, boneToScreen(ped.GetBonePosition(headBone)).y + 20},
{worldToScreen(ped.GetBonePosition(headBone)).x, worldToScreen(ped.GetBonePosition(headBone)).y + 20},
colorBasedOnDistance,
distanceStr.c_str());
}
@@ -235,6 +243,32 @@ namespace YimMenu
}
}
void ESP::DrawRandomEvent(int event, ImDrawList* drawList)
{
if (SCRIPT::GET_NUMBER_OF_THREADS_RUNNING_THE_SCRIPT_WITH_THIS_HASH("freemode"_J) == 0 || HUD::IS_PAUSE_MENU_ACTIVE() || NETWORK::NETWORK_IS_IN_MP_CUTSCENE())
return;
if (GPBD_FM_2::Get()->Entries[Self::GetPlayer().GetId()].RandomEventsClientData.InitState != eRandomEventClientInitState::INITIALIZED)
return;
auto state = GSBD_RandomEvents::Get()->EventData[event].State;
auto coords = GSBD_RandomEvents::Get()->EventData[event].TriggerPosition;
auto range = GSBD_RandomEvents::Get()->EventData[event].TriggerRange;
auto timer = GSBD_RandomEvents::Get()->EventData[event].TimerState;
auto availability = RANDOM_EVENTS_FREEMODE_DATA::Get(Scripts::FindScriptThread("freemode"_J))->EventData[event].AvailableTime;
auto timeLeft = GSBD_RandomEvents::Get()->EventData[event].TimerState.GetRemainingTimeStr(availability);
if (state != eRandomEventState::INACTIVE && coords != Vector3(0.0f, 0.0f, 0.0f))
{
float distance = Self::GetPed().GetPosition().GetDistance(coords);
float formattedDistance = (distance < 1000.0f) ? distance : (distance / 1000.0f);
std::string unit = (distance < 1000.0f) ? "m" : "km";
std::string text = std::format("{}\n{:.2f}{} {}", randomEventNames[event], formattedDistance, unit, (state == eRandomEventState::AVAILABLE ? timeLeft : ""));
ImColor color = (state == eRandomEventState::ACTIVE) ? Green : White;
drawList->AddText({worldToScreen(coords).x, worldToScreen(coords).y}, color, text.c_str());
}
}
void ESP::Draw()
{
if (!NativeInvoker::AreHandlersCached() || CAM::IS_SCREEN_FADED_OUT() || HUD::IS_WARNING_MESSAGE_ACTIVE())
@@ -257,6 +291,13 @@ namespace YimMenu
DrawPed(ped, drawList);
}
}
if (Features::_ESPDrawRandomEvents.GetState())
{
for (int event = 0; event < 21; event++)
{
DrawRandomEvent(event, drawList);
}
}
}
}
+1
View File
@@ -9,5 +9,6 @@ namespace YimMenu
static void Draw();
static void DrawPlayer(Player plyr, ImDrawList* draw_list);
static void DrawPed(Ped plyr, ImDrawList* drawList);
static void DrawRandomEvent(int event, ImDrawList* drawList);
};
}
+8 -3
View File
@@ -1,5 +1,6 @@
#include "Menu.hpp"
#include "imgui.h"
#include "imgui_internal.h"
#include "core/commands/Commands.hpp"
#include "core/frontend/manager/UIManager.hpp"
#include "core/renderer/Renderer.hpp"
@@ -15,7 +16,7 @@
#include "submenus/Settings.hpp"
#include "submenus/Debug.hpp"
#include "submenus/World.hpp"
#include "core/filemgr/FileMgr.hpp"
namespace YimMenu
{
void Menu::Init()
@@ -110,7 +111,11 @@ namespace YimMenu
void Menu::SetupFonts()
{
auto& IO = ImGui::GetIO();
auto& IO = ImGui::GetIO();
auto file_path = std::filesystem::path(std::getenv("appdata")) / "YimMenuV2" / "imgui.ini";
static auto path = file_path.string();
IO.IniFilename = path.c_str();
IO.LogFilename = NULL;
ImFontConfig FontCfg{};
FontCfg.FontDataOwnedByAtlas = false;
+16
View File
@@ -197,4 +197,20 @@ namespace YimMenu
std::optional<std::string> m_LabelOverride;
std::optional<std::string> m_CurrentInput = std::nullopt;
};
class TabItem : public UIItem
{
public:
explicit TabItem(const std::string& name);
void Draw() override;
void AddItem(std::shared_ptr<UIItem>&& item)
{
m_Items.push_back(std::move(item));
}
private:
std::string m_Name;
std::vector<std::shared_ptr<UIItem>> m_Items;
};
}
+22
View File
@@ -0,0 +1,22 @@
#include "Items.hpp"
namespace YimMenu
{
TabItem::TabItem(const std::string& name) :
m_Name(name)
{
}
void TabItem::Draw()
{
if (ImGui::BeginTabItem(m_Name.c_str()))
{
for (auto& item : m_Items)
{
if (item->CanDraw())
item->Draw();
}
ImGui::EndTabItem();
}
}
}
+1 -1
View File
@@ -18,7 +18,7 @@ namespace YimMenu::Submenus
if (ImGui::Button("fm_mission_controller DoTeamSwap"))
{
FiberPool::Push([] {
static ScriptFunction DoTeamSwap("DoTeamSwap", "fm_mission_controller"_J, "2D 02 04 00 00 38 00 50");
static ScriptFunction DoTeamSwap("fm_mission_controller"_J, ScriptPointer("DoTeamSwap", "2D 02 04 00 00 38 00 50"));
DoTeamSwap.Call<void>(team, true);
});
}
+2 -1
View File
@@ -4,7 +4,7 @@
#include "game/frontend/items/Items.hpp"
#include "game/frontend/submenus/Network/SavedPlayers.hpp"
#include "game/gta/Network.hpp"
#include "game/frontend/submenus/network/RandomEvents.hpp"
#include "game/frontend/submenus/Network/RandomEvents.hpp"
namespace YimMenu::Submenus
{
@@ -78,6 +78,7 @@ namespace YimMenu::Submenus
enhancements->AddItem(std::make_shared<BoolCommandItem>("disabledeathbarriers"_J));
enhancements->AddItem(std::make_shared<BoolCommandItem>("despawnbypass"_J)); // move this somewhere else?
enhancements->AddItem(std::make_shared<BoolCommandItem>("bypasscasinogeoblock"_J));
enhancements->AddItem(std::make_shared<BoolCommandItem>("forcescripthost"_J));
session->AddItem(joinGroup);
session->AddItem(bountyGroup);
+2 -5
View File
@@ -3,6 +3,7 @@
#include "game/features/recovery/GiveVehicleReward.hpp"
#include "Recovery/StatEditor.hpp"
#include "Recovery/Transactions.hpp"
#include "Recovery/HeistModifier.hpp"
namespace YimMenu::Submenus
{
@@ -13,7 +14,6 @@ namespace YimMenu::Submenus
auto missions = std::make_shared<Category>("Missions");
auto vehiclesGroup = std::make_shared<Group>("Vehicles");
auto generalGroup = std::make_shared<Group>("General");
auto cayoPericoGroup = std::make_shared<Group>("Cayo Perico");
vehiclesGroup->AddItem(std::make_shared<BoolCommandItem>("dlcvehicles"_J));
@@ -30,15 +30,12 @@ namespace YimMenu::Submenus
generalGroup->AddItem(std::make_shared<BoolCommandItem>("playallmissionssolo"_J));
generalGroup->AddItem(std::make_shared<CommandItem>("forcelaunchheist"_J));
cayoPericoGroup->AddItem(std::make_shared<CommandItem>("skipcayosetup"_J));
cayoPericoGroup->AddItem(std::make_shared<CommandItem>("skipcayocooldown"_J));
shopping->AddItem(vehiclesGroup);
missions->AddItem(generalGroup);
missions->AddItem(cayoPericoGroup);
AddCategory(std::move(shopping));
AddCategory(std::move(missions));
AddCategory(BuildStatEditorMenu());
AddCategory(BuildTransactionsMenu());
AddCategory(BuildHeistModifierMenu());
}
}
@@ -0,0 +1,33 @@
#include "ApartmentHeist.hpp"
namespace YimMenu::Submenus
{
std::shared_ptr<TabItem> RenderApartmentHeistMenu()
{
auto tab = std::make_shared<TabItem>("Apartment Heist");
auto cuts = std::make_shared<Group>("Heist Cuts", 2);
auto setups = std::make_shared<Group>("Heist Setups");
auto misc = std::make_shared<Group>("Misc", 1);
cuts->AddItem(std::make_shared<IntCommandItem>("apartmentheistcut1"_J));
cuts->AddItem(std::make_shared<IntCommandItem>("apartmentheistcut3"_J));
cuts->AddItem(std::make_shared<IntCommandItem>("apartmentheistcut2"_J));
cuts->AddItem(std::make_shared<IntCommandItem>("apartmentheistcut4"_J));
cuts->AddItem(std::make_shared<CommandItem>("apartmentheistforceready"_J));
cuts->AddItem(std::make_shared<CommandItem>("apartmentheistsetcuts"_J));
setups->AddItem(std::make_shared<CommandItem>("apartmentheistsetup"_J));
misc->AddItem(std::make_shared<CommandItem>("apartmentheistskiphacking"_J));
misc->AddItem(std::make_shared<CommandItem>("apartmentheistskipdrilling"_J));
misc->AddItem(std::make_shared<CommandItem>("apartmentheistinstantfinish"_J));
misc->AddItem(std::make_shared<CommandItem>("apartmentheistinstantfinishpacific"_J));
tab->AddItem(cuts);
tab->AddItem(setups);
tab->AddItem(misc);
return tab;
}
}
@@ -0,0 +1,6 @@
#include "game/frontend/submenus/Recovery/HeistModifier.hpp"
namespace YimMenu::Submenus
{
std::shared_ptr<TabItem> RenderApartmentHeistMenu();
}
@@ -0,0 +1,50 @@
#include "CayoPericoHeist.hpp"
namespace YimMenu::Submenus
{
std::shared_ptr<TabItem> RenderCayoPericoHeistMenu()
{
auto tab = std::make_shared<TabItem>("Cayo Perico Heist");
auto cuts = std::make_shared<Group>("Heist Cuts", 2);
auto setups = std::make_shared<Group>("Heist Setups");
auto loots = std::make_shared<Group>("Loots");
auto misc = std::make_shared<Group>("Misc", 1);
cuts->AddItem(std::make_shared<IntCommandItem>("cayopericoheistcut1"_J));
cuts->AddItem(std::make_shared<IntCommandItem>("cayopericoheistcut3"_J));
cuts->AddItem(std::make_shared<IntCommandItem>("cayopericoheistcut2"_J));
cuts->AddItem(std::make_shared<IntCommandItem>("cayopericoheistcut4"_J));
cuts->AddItem(std::make_shared<CommandItem>("cayopericoheistforceready"_J));
cuts->AddItem(std::make_shared<CommandItem>("cayopericoheistsetcuts"_J));
setups->AddItem(std::make_shared<ListCommandItem>("cayopericoheistdifficulty"_J));
setups->AddItem(std::make_shared<ListCommandItem>("cayopericoheistprimarytarget"_J));
setups->AddItem(std::make_shared<ListCommandItem>("cayopericoheistweapon"_J));
setups->AddItem(std::make_shared<CommandItem>("cayopericoheistsetup"_J));
loots->AddItem(std::make_shared<IntCommandItem>("cayopericoheistprimarytargetvalue"_J));
loots->AddItem(std::make_shared<ImGuiItem>([] {
ImGui::SameLine();
}));
loots->AddItem(std::make_shared<CommandItem>("cayopericoheistsetprimarytargetvalue"_J));
loots->AddItem(std::make_shared<IntCommandItem>("cayopericoheistsecondarytakevalue"_J));
loots->AddItem(std::make_shared<ImGuiItem>([] {
ImGui::SameLine();
}));
loots->AddItem(std::make_shared<CommandItem>("cayopericoheistsetsecondarytakevalue"_J));
misc->AddItem(std::make_shared<CommandItem>("cayopericoheistskiphacking"_J));
misc->AddItem(std::make_shared<CommandItem>("cayopericoheistcutsewer"_J));
misc->AddItem(std::make_shared<CommandItem>("cayopericoheistcutglass"_J));
misc->AddItem(std::make_shared<CommandItem>("cayopericoheisttakeprimarytarget"_J));
misc->AddItem(std::make_shared<CommandItem>("cayopericoheistinstantfinish"_J));
tab->AddItem(cuts);
tab->AddItem(setups);
tab->AddItem(loots);
tab->AddItem(misc);
return tab;
}
}
@@ -0,0 +1,6 @@
#include "game/frontend/submenus/Recovery/HeistModifier.hpp"
namespace YimMenu::Submenus
{
std::shared_ptr<TabItem> RenderCayoPericoHeistMenu();
}
@@ -0,0 +1,61 @@
#include "DiamondCasinoHeist.hpp"
namespace YimMenu::Submenus
{
std::shared_ptr<TabItem> RenderDiamondCasinoHeistMenu()
{
auto tab = std::make_shared<TabItem>("Diamond Casino Heist");
auto cuts = std::make_shared<Group>("Heist Cuts", 2);
auto setups1 = std::make_shared<Group>("Heist Setups");
auto setups2 = std::make_shared<Group>("");
auto loots = std::make_shared<Group>("Loots");
auto misc = std::make_shared<Group>("Misc", 1);
cuts->AddItem(std::make_shared<IntCommandItem>("diamondcasinoheistcut1"_J));
cuts->AddItem(std::make_shared<IntCommandItem>("diamondcasinoheistcut3"_J));
cuts->AddItem(std::make_shared<IntCommandItem>("diamondcasinoheistcut2"_J));
cuts->AddItem(std::make_shared<IntCommandItem>("diamondcasinoheistcut4"_J));
cuts->AddItem(std::make_shared<CommandItem>("diamondcasinoheistforceready"_J));
cuts->AddItem(std::make_shared<CommandItem>("diamondcasinoheistsetcuts"_J));
setups1->AddItem(std::make_shared<ListCommandItem>("diamondcasinoheistdifficulty"_J));
setups1->AddItem(std::make_shared<ListCommandItem>("diamondcasinoheistprimarytarget"_J));
setups1->AddItem(std::make_shared<ListCommandItem>("diamondcasinoheistapproach"_J));
setups1->AddItem(std::make_shared<ListCommandItem>("diamondcasinoheistgunman"_J));
setups1->AddItem(std::make_shared<ImGuiItem>([] {
ImGui::SameLine();
}));
setups1->AddItem(std::make_shared<ListCommandItem>("diamondcasinoheistweapon"_J));
setups2->AddItem(std::make_shared<ListCommandItem>("diamondcasinoheistdriver"_J));
setups2->AddItem(std::make_shared<ImGuiItem>([] {
ImGui::SameLine();
}));
setups2->AddItem(std::make_shared<ListCommandItem>("diamondcasinoheistvehicle"_J));
setups2->AddItem(std::make_shared<ListCommandItem>("diamondcasinoheisthacker"_J));
setups2->AddItem(std::make_shared<CommandItem>("diamondcasinoheistsetup"_J));
loots->AddItem(std::make_shared<IntCommandItem>("diamondcasinoheistpotentialtake"_J));
loots->AddItem(std::make_shared<ImGuiItem>([] {
ImGui::SameLine();
}));
loots->AddItem(std::make_shared<CommandItem>("diamondcasinoheistsetpotentialtake"_J));
loots->AddItem(std::make_shared<IntCommandItem>("diamondcasinoheistactualtake"_J));
loots->AddItem(std::make_shared<ImGuiItem>([] {
ImGui::SameLine();
}));
loots->AddItem(std::make_shared<CommandItem>("diamondcasinoheistsetactualtake"_J));
misc->AddItem(std::make_shared<CommandItem>("diamondcasinoheistskiphacking"_J));
misc->AddItem(std::make_shared<CommandItem>("diamondcasinoheistskipdrilling"_J));
misc->AddItem(std::make_shared<CommandItem>("diamondcasinoheistinstantfinish"_J));
tab->AddItem(cuts);
tab->AddItem(setups1);
tab->AddItem(setups2);
tab->AddItem(loots);
tab->AddItem(misc);
return tab;
}
}
@@ -0,0 +1,6 @@
#include "game/frontend/submenus/Recovery/HeistModifier.hpp"
namespace YimMenu::Submenus
{
std::shared_ptr<TabItem> RenderDiamondCasinoHeistMenu();
}
@@ -0,0 +1,33 @@
#include "DoomsdayHeist.hpp"
namespace YimMenu::Submenus
{
std::shared_ptr<TabItem> RenderDoomsdayHeistMenu()
{
auto tab = std::make_shared<TabItem>("Doomsday Heist");
auto cuts = std::make_shared<Group>("Heist Cuts", 2);
auto setups = std::make_shared<Group>("Heist Setups");
auto misc = std::make_shared<Group>("Misc", 1);
cuts->AddItem(std::make_shared<IntCommandItem>("doomsdayheistcut1"_J));
cuts->AddItem(std::make_shared<IntCommandItem>("doomsdayheistcut3"_J));
cuts->AddItem(std::make_shared<IntCommandItem>("doomsdayheistcut2"_J));
cuts->AddItem(std::make_shared<IntCommandItem>("doomsdayheistcut4"_J));
cuts->AddItem(std::make_shared<CommandItem>("doomsdayheistforceready"_J));
cuts->AddItem(std::make_shared<CommandItem>("doomsdayheistsetcuts"_J));
setups->AddItem(std::make_shared<ListCommandItem>("doomsdayheistcategory"_J));
setups->AddItem(std::make_shared<CommandItem>("doomsdayheistsetup"_J));
misc->AddItem(std::make_shared<CommandItem>("doomsdayheistskiphacking"_J));
misc->AddItem(std::make_shared<CommandItem>("doomsdayheistinstantfinish"_J));
misc->AddItem(std::make_shared<CommandItem>("doomsdayheistinstantfinishact3"_J));
tab->AddItem(cuts);
tab->AddItem(setups);
tab->AddItem(misc);
return tab;
}
}
@@ -0,0 +1,6 @@
#include "game/frontend/submenus/Recovery/HeistModifier.hpp"
namespace YimMenu::Submenus
{
std::shared_ptr<TabItem> RenderDoomsdayHeistMenu();
}
@@ -0,0 +1,26 @@
#include "HeistModifier.hpp"
#include "Heist/ApartmentHeist.hpp"
#include "Heist/DiamondCasinoHeist.hpp"
#include "Heist/CayoPericoHeist.hpp"
#include "Heist/DoomsdayHeist.hpp"
namespace YimMenu::Submenus
{
std::shared_ptr<Category> BuildHeistModifierMenu()
{
auto menu = std::make_shared<Category>("Heists");
menu->AddItem(std::make_shared<ImGuiItem>([] {
ImGui::BeginTabBar("Heist Modifier");
}));
menu->AddItem(RenderApartmentHeistMenu());
menu->AddItem(RenderDiamondCasinoHeistMenu());
menu->AddItem(RenderCayoPericoHeistMenu());
menu->AddItem(RenderDoomsdayHeistMenu());
menu->AddItem(std::make_shared<ImGuiItem>([] {
ImGui::EndTabBar();
}));
return menu;
}
}
@@ -0,0 +1,8 @@
#pragma once
#include "core/frontend/manager/Category.hpp"
#include "game/frontend/items/Items.hpp"
namespace YimMenu::Submenus
{
std::shared_ptr<Category> BuildHeistModifierMenu();
}
@@ -203,7 +203,7 @@ namespace YimMenu::Submenus
if (info.m_IsBoolStat)
value.m_AsBool = STATS::GET_PACKED_STAT_BOOL_CODE(info.m_Index, -1);
else
value.m_AsInt = STATS::GET_PACKED_STAT_BOOL_CODE(info.m_Index, -1);
value.m_AsInt = STATS::GET_PACKED_STAT_INT_CODE(info.m_Index, -1);
}
static void WritePackedStat(const StatValue& value, const PackedStatInfo& info)
@@ -224,8 +224,6 @@ namespace YimMenu::Submenus
if (info.m_IsBoolStat)
STATS::SET_PACKED_STAT_BOOL_CODE(info.m_Index, static_cast<bool>(value), -1);
else
STATS::SET_PACKED_STAT_INT_CODE(info.m_Index, value, -1);
}
}
+3 -1
View File
@@ -12,7 +12,7 @@ namespace YimMenu::Submenus
auto globalsGroup = std::make_shared<Group>("Globals");
auto movementGroup = std::make_shared<Group>("Movement");
auto wantedGroup = std::make_shared<Group>("Wanted");
auto toolsGroup = std::make_shared<Group>("Tools");
auto toolsGroup = std::make_shared<Group>("Tools", 1);
globalsGroup->AddItem(std::make_shared<BoolCommandItem>("godmode"_J));
globalsGroup->AddItem(std::make_shared<BoolCommandItem>("invis"_J));
@@ -21,6 +21,7 @@ namespace YimMenu::Submenus
globalsGroup->AddItem(std::make_shared<BoolCommandItem>("noragdoll"_J));
globalsGroup->AddItem(std::make_shared<BoolCommandItem>("noidlekick"_J));
globalsGroup->AddItem(std::make_shared<BoolCommandItem>("unlimitedoxygen"_J));
globalsGroup->AddItem(std::make_shared<BoolCommandItem>("formatmoney"_J));
auto clearWanted = std::make_shared<Group>("", 1);
clearWanted->AddItem(std::make_shared<ConditionalItem>("neverwanted"_J, std::make_shared<CommandItem>("clearwanted"_J), true));
@@ -37,6 +38,7 @@ namespace YimMenu::Submenus
toolsGroup->AddItem(std::make_shared<CommandItem>("heal"_J));
toolsGroup->AddItem(std::make_shared<CommandItem>("cleardamage"_J));
toolsGroup->AddItem(std::make_shared<CommandItem>("fillinventory"_J));
toolsGroup->AddItem(std::make_shared<CommandItem>("MobileRadio"_J));
movementGroup->AddItem(std::make_shared<BoolCommandItem>("standonvehicles"_J));
movementGroup->AddItem(std::make_shared<BoolCommandItem>("disableactionmode"_J));
@@ -3,9 +3,12 @@
#include "core/backend/ScriptMgr.hpp"
#include "core/frontend/Notifications.hpp"
#include "game/backend/Self.hpp"
#include "game/backend/Tunables.hpp"
#include "game/backend/ScriptPatches.hpp"
#include "game/gta/data/RandomEvents.hpp"
#include "game/gta/Scripts.hpp"
#include "game/gta/ScriptFunction.hpp"
#include "game/pointers/Pointers.hpp"
#include "types/script/globals/GPBD_FM_2.hpp"
#include "types/script/globals/GSBD_RandomEvents.hpp"
#include "types/script/locals/FMRandomEvents.hpp"
#include "types/script/ScriptEvent.hpp"
@@ -42,84 +45,25 @@ namespace YimMenu::Submenus
MAX_EVENTS
};
static constexpr std::array randomEventNames = {
"Drug Vehicle",
"Movie Props",
"Sleeping Guard",
"Exotic Exports",
"The Slashers",
"Phantom Car",
"Sightseeing",
"Smuggler Trail",
"Cerberus Surprise",
"Smuggler Plane",
"Crime Scene",
"Metal Detector",
"Finders Keepers",
"Shop Robbery",
"The Gooch",
"Weazel Plaza Shootout",
"Armored Truck",
"Possessed Animals",
"Ghosts Exposed",
"Happy Holidays Hauler",
"Community Outreach"
};
static constexpr std::array RandomEventScripts = {
"fm_content_drug_vehicle"_J,
"fm_content_movie_props"_J,
"fm_content_golden_gun"_J,
"fm_content_vehicle_list"_J,
"fm_content_slasher"_J,
"fm_content_phantom_car"_J,
"fm_content_sightseeing"_J,
"fm_content_smuggler_trail"_J,
"fm_content_cerberus"_J,
"fm_content_smuggler_plane"_J,
"fm_content_crime_scene"_J,
"fm_content_metal_detector"_J,
"fm_content_convoy"_J,
"fm_content_robbery"_J,
"fm_content_xmas_mugger"_J,
"fm_content_bank_shootout"_J,
"fm_content_armoured_truck"_J,
"fm_content_possessed_animals"_J,
"fm_content_ghosthunt"_J,
"fm_content_xmas_truck"_J,
"fm_content_community_outreach"_J
};
static YimMenu::ScriptFunction getNumFMMCVariations("GMFV", "freemode"_J, "5D ? ? ? 01 72 02 39 04", 1, true);
static std::vector<ScriptPatch> sendUpdateRECoordsTSECooldownPatches{};
static GPBD_FM_2* GPBDFM2 = nullptr;
static GSBD_RandomEvents* GSBDRandomEvents = nullptr;
static RANDOM_EVENTS_FREEMODE_DATA* FMRandomEvents = nullptr;
static eRandomEvent selectedEvent = DRUG_VEHICLE;
static int selectedSubvariation = 0;
static int numSubVariations = 30;
std::string GetEventTimeLeftStr(int eventTime, int timer)
{
int timePassed = (*Pointers.NetworkTime - timer) < 0 ? -(*Pointers.NetworkTime - timer) : (*Pointers.NetworkTime - timer);
int diff = (eventTime - timePassed);
int totalSeconds = diff / 1000;
int hours = totalSeconds / 3600;
int minutes = (totalSeconds % 3600) / 60;
int seconds = totalSeconds % 60;
if (hours < 1)
return std::format("{:02}:{:02}", minutes, seconds);
else
return std::format("{:02}:{:02}:{:02}", hours, minutes, seconds);
}
static int numSubvariations = 29;
static int setCooldown = 1800000;
static int setAvailability = 900000;
static bool applyInMinutes = false;
static std::string GetEventStateString()
{
switch (GSBDRandomEvents->EventData[selectedEvent].State)
{
case eRandomEventState::INACTIVE:
return "Inactive - launching in " + GetEventTimeLeftStr(FMRandomEvents->EventData[selectedEvent].InactiveTime, GSBDRandomEvents->EventData[selectedEvent].TimerState.Time);
return "Inactive - launching in " + GSBDRandomEvents->EventData[selectedEvent].TimerState.GetRemainingTimeStr(FMRandomEvents->EventData[selectedEvent].InactiveTime);
case eRandomEventState::AVAILABLE:
return "Available - deactivating in " + GetEventTimeLeftStr(FMRandomEvents->EventData[selectedEvent].AvailableTime, GSBDRandomEvents->EventData[selectedEvent].TimerState.Time);
return "Available - deactivating in " + GSBDRandomEvents->EventData[selectedEvent].TimerState.GetRemainingTimeStr(FMRandomEvents->EventData[selectedEvent].AvailableTime);
case eRandomEventState::ACTIVE:
return "Active";
case eRandomEventState::CLEANUP:
@@ -129,20 +73,97 @@ namespace YimMenu::Submenus
return "N/A";
}
static int GetNumLocallyActiveEvents()
{
int numEvents{};
for (int event = DRUG_VEHICLE; event < MAX_EVENTS; event++)
{
if (GPBDFM2->Entries[Self::GetPlayer().GetId()].RandomEventsClientData.EventData[event].State != eRandomEventClientState::INACTIVE)
numEvents++;
}
return numEvents;
}
static void ResetEventTunables(eRandomEvent event)
{
if (event == ARMOURED_TRUCK) // It doesn't have tunables
{
setCooldown = *ScriptGlobal(262145).At(33719).As<int*>();
setAvailability = *ScriptGlobal(262145).At(33720).As<int*>();
}
else
{
// Phantom Car's cooldown is actually 2147483647ms if STANDARDTARGETTINGTIME is not enabled
setCooldown = *Tunables::GetTunable(randomEventCooldowns[event]).As<int*>();
setAvailability = *Tunables::GetTunable(randomEventAvailabilities[event]).As<int*>();
}
}
static void OnComboChange()
{
static ScriptFunction getNumFMMCVariations("freemode"_J, ScriptPointer("GetNumFMMCVariations", "5D ? ? ? 01 72 02 39 04").Add(1).Rip());
numSubvariations = getNumFMMCVariations.Call<int>(FMRandomEvents->MissionData.FMMCData[selectedEvent].FMMCType, 0) - 1;
selectedSubvariation = 0;
ResetEventTunables(selectedEvent);
}
static void KillActiveEvent()
{
if (auto eventThread = Scripts::FindScriptThread(randomEventScripts[(int)selectedEvent]))
{
if (auto NetComponent = reinterpret_cast<GtaThread*>(eventThread)->m_NetComponent)
{
if (auto eventProgram = Scripts::FindScriptProgram(randomEventScripts[(int)selectedEvent]))
{
// TO-DO: Cache these too?
if (NetComponent->IsLocalPlayerHost())
{
std::string ptrName = "SetFMContentScriptServerState" + std::to_string(selectedEvent);
ScriptFunction setFMContentScriptServerState(randomEventScripts[(int)selectedEvent], ScriptPointer(ptrName, "5D ? ? ? 55 2E 00 5D").Add(1).Rip());
setFMContentScriptServerState.Call<void>(3);
}
else
{
std::string ptrName = "SetFMContentScriptClientState" + std::to_string(selectedEvent);
ScriptFunction setFMContentScriptClientState(randomEventScripts[(int)selectedEvent], ScriptPointer(ptrName, "5D ? ? ? 55 08 00 74").Add(1).Rip());
setFMContentScriptClientState.Call<void>(3);
}
}
}
}
else
{
Notifications::Show("Random Events", "Event script is not active. Are you a participant?", NotificationType::Error);
}
}
std::shared_ptr<Category> BuildRandomEventsMenu()
{
auto menu = std::make_shared<Category>("Random Events");
if (sendUpdateRECoordsTSECooldownPatches.empty())
{
for (int event = DRUG_VEHICLE; event < MAX_EVENTS; event++)
{
std::string ptrName = "SendUpdateRECoordsTSECooldownPatch" + std::to_string(event);
sendUpdateRECoordsTSECooldownPatches.push_back(ScriptPatches::AddPatch(randomEventScripts[event], ScriptPointer(ptrName, "43 88 13 2E 00 01"), {0x71, 0x00, 0x00}));
}
}
for (auto& patch : sendUpdateRECoordsTSECooldownPatches)
patch->Enable();
auto menu = std::make_shared<Category>("Random Events");
auto settings = std::make_shared<Group>("Settings");
menu->AddItem(std::make_unique<ImGuiItem>([] {
GSBDRandomEvents = nullptr;
FMRandomEvents = nullptr;
GPBDFM2 = GPBD_FM_2::Get();
GSBDRandomEvents = GSBD_RandomEvents::Get();
if (!GSBDRandomEvents)
return ImGui::Text("Freemode global block is not loaded yet.");
if (!GPBDFM2 || !GSBDRandomEvents)
return ImGui::Text("Freemode global block is not loaded.");
if (GSBDRandomEvents->InitState != eRandomEventInitState::INITIALIZED)
return ImGui::Text("Random Events are not initialized yet.");
if (GPBDFM2->Entries[Self::GetPlayer().GetId()].RandomEventsClientData.InitState != eRandomEventClientInitState::INITIALIZED)
return ImGui::Text("Random Events are not initialized.");
if (auto freemode = Scripts::FindScriptThread("freemode"_J))
{
@@ -176,8 +197,8 @@ namespace YimMenu::Submenus
if (ImGui::Selectable(randomEventNames[event], event == selectedEvent))
{
FiberPool::Push([event] {
selectedEvent = (eRandomEvent)event;
numSubVariations = getNumFMMCVariations.Call<int>(FMRandomEvents->MissionData.FMMCData[selectedEvent].FMMCType, 0) - 1;
selectedEvent = (eRandomEvent)event;
OnComboChange();
});
}
@@ -187,11 +208,18 @@ namespace YimMenu::Submenus
ImGui::EndCombo();
}
if (ImGui::InputInt(std::format("Select Location (0-{})", numSubVariations).c_str(), &selectedSubvariation))
if (ImGui::InputInt(std::format("Select Location (0-{})", numSubvariations).c_str(), &selectedSubvariation))
{
selectedSubvariation = std::clamp(selectedSubvariation, 0, numSubVariations);
selectedSubvariation = std::clamp(selectedSubvariation, 0, numSubvariations);
}
int numActiveEvents = GetNumLocallyActiveEvents();
int maxActiveEvents = *Tunables::GetTunable("FMREMAXACTIVATEDEVENTS"_J).As<int*>();
if (numActiveEvents >= maxActiveEvents)
ImGui::TextColored(ImVec4(1.0f, 0.0f, 0.0f, 1.0f), "Active Events: %d/%d", numActiveEvents, maxActiveEvents);
else
ImGui::Text("Active Events: %d/%d", numActiveEvents, maxActiveEvents);
if (ImGui::Button("Launch Event"))
{
FiberPool::Push([] {
@@ -215,9 +243,7 @@ namespace YimMenu::Submenus
});
}
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip("Force launches the event.");
}
ImGui::SetTooltip("Requires freemode script host.");
ImGui::SameLine();
@@ -230,8 +256,7 @@ namespace YimMenu::Submenus
}
else if (GSBDRandomEvents->EventData[selectedEvent].State == eRandomEventState::ACTIVE)
{
ScriptFunction terminateFMContentScript("TFMCS", RandomEventScripts[(int)selectedEvent], "2D 01 05 00 00 5D ? ? ?");
terminateFMContentScript.Call<void>(false); // Is it ok to do this when we're not host?
KillActiveEvent();
}
else
{
@@ -239,10 +264,6 @@ namespace YimMenu::Submenus
}
});
}
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip("Terminates the event.");
}
ImGui::SameLine();
@@ -267,14 +288,10 @@ namespace YimMenu::Submenus
}
});
}
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip("Teleports to the event.");
}
if (GSBDRandomEvents->EventData[selectedEvent].State == eRandomEventState::ACTIVE)
{
if (auto eventThread = Scripts::FindScriptThread(RandomEventScripts[(int)selectedEvent]))
if (auto eventThread = Scripts::FindScriptThread(randomEventScripts[(int)selectedEvent]))
{
if (auto netComponent = reinterpret_cast<GtaThread*>(eventThread)->m_NetComponent)
{
@@ -296,10 +313,46 @@ namespace YimMenu::Submenus
}
ImGui::Text("State: %s", GetEventStateString().c_str());
ImGui::Text("Location: %d", GSBDRandomEvents->EventData[selectedEvent].Subvariation);
ImGui::Text("Trigger Range: %.2f", GSBDRandomEvents->EventData[selectedEvent].TriggerRange); // Default value is 400, it will be updated once the event switches to the available state
if (GSBDRandomEvents->EventData[selectedEvent].State == eRandomEventState::INACTIVE)
{
ImGui::Text("Location: N/A");
ImGui::Text("Trigger Range: N/A");
}
else
{
ImGui::Text("Location: %d", GSBDRandomEvents->EventData[selectedEvent].Subvariation);
ImGui::Text("Trigger Range: %.2f", GSBDRandomEvents->EventData[selectedEvent].TriggerRange); // Default value is 400, it will be updated once the event switches to the available state
}
// We should probably put this into a separate group, but I just don't want to do the same safety checks before rendering it
ImGui::SeparatorText("Cooldown & Availability");
ImGui::InputInt("##cooldown", &setCooldown);
ImGui::SameLine();
if (ImGui::Button("Set Cooldown"))
{
int value = applyInMinutes ? (setCooldown * 60000) : setCooldown;
FMRandomEvents->EventData[selectedEvent].InactiveTime = value;
}
if (ImGui::IsItemHovered())
ImGui::SetTooltip("Requires freemode script host.");
ImGui::InputInt("##availability", &setAvailability);
ImGui::SameLine();
if (ImGui::Button("Set Availability"))
{
int value = applyInMinutes ? (setAvailability * 60000) : setAvailability;
FMRandomEvents->EventData[selectedEvent].AvailableTime = value;
}
if (ImGui::IsItemHovered())
ImGui::SetTooltip("Requires freemode script host.");
ImGui::Checkbox("Apply in Minutes", &applyInMinutes);
}));
settings->AddItem(std::make_shared<BoolCommandItem>("esprandomevents"_J));
menu->AddItem(std::move(settings));
return menu;
}
}
+2 -2
View File
@@ -18,10 +18,10 @@ namespace YimMenu::Network
{
void LaunchJoinType(JoinType to_launch)
{
static ScriptFunction send_to_clouds("SendToClouds", "shop_controller"_J, "2D 00 02 00 00 72 5D ? ? ? 72");
static ScriptFunction sendToClouds("shop_controller"_J, ScriptPointer("SendToClouds", "2D 00 02 00 00 72 5D ? ? ? 72"));
static ScriptGlobal join_type_global(1575038);
send_to_clouds.Call<void>();
sendToClouds.Call<void>();
*join_type_global.As<JoinType*>() = to_launch;
}
+61
View File
@@ -0,0 +1,61 @@
#include "ScriptData.hpp"
#include "types/script/scrProgram.hpp"
namespace YimMenu
{
ScriptData::ScriptData(rage::scrProgram* program)
{
auto pages = new uint8_t*[program->GetNumCodePages()];
for (auto i = 0u; i < program->GetNumCodePages(); i++)
{
pages[i] = new uint8_t[program->GetCodePageSize(i)];
std::memcpy(pages[i], program->GetCodePage(i), program->GetCodePageSize(i));
}
m_Data = pages;
m_Pages = program->GetNumCodePages();
m_Size = program->GetFullCodeSize();
m_Name = program->m_Name;
}
ScriptData::~ScriptData()
{
for (auto i = 0u; i < m_Pages; i++)
{
delete[] m_Data[i];
}
delete[] m_Data;
m_Data = nullptr;
m_Name = nullptr;
}
std::uint8_t* ScriptData::GetCodeLocation(ScriptData* data, int idx)
{
return &data->GetData()[idx >> 14][idx & 0x3FFF];
}
std::optional<std::uint32_t> ScriptData::GetCodeLocationByPattern(ScriptData* data, const SimplePattern& pattern)
{
std::uint32_t codeSize = data->GetSize();
for (uint32_t i = 0; i < (codeSize - pattern.m_Bytes.size()); i++)
{
for (uint32_t j = 0; j < pattern.m_Bytes.size(); j++)
{
if (pattern.m_Bytes[j].has_value())
{
int loc = i + j;
if (pattern.m_Bytes[j] != *GetCodeLocation(data, loc))
goto incorrect;
}
}
return i;
incorrect:
continue;
}
return std::nullopt;
}
}
+40
View File
@@ -0,0 +1,40 @@
#pragma once
#include "core/memory/Pattern.hpp"
namespace rage
{
class scrProgram;
}
namespace YimMenu
{
class ScriptData
{
std::uint8_t** m_Data;
std::uint32_t m_Pages;
std::uint32_t m_Size;
const char* m_Name;
public:
inline std::uint8_t** GetData() const
{
return m_Data;
}
inline std::uint32_t GetSize() const
{
return m_Size;
}
inline const char* GetName() const
{
return m_Name;
}
ScriptData(rage::scrProgram* program);
~ScriptData();
static uint8_t* GetCodeLocation(ScriptData* data, int idx);
static std::optional<uint32_t> GetCodeLocationByPattern(ScriptData* data, const SimplePattern& pattern);
};
}
+52 -20
View File
@@ -1,34 +1,66 @@
#include "ScriptFunction.hpp"
#include "game/backend/ScriptPointers.hpp"
#include "game/pointers/Pointers.hpp"
#include "game/gta/Scripts.hpp"
#include "game/gta/ScriptPointer.hpp"
#include "types/script/scrThread.hpp"
#include "types/script/scrProgram.hpp"
#include "types/rage/tlsContext.hpp"
namespace YimMenu
{
ScriptFunction::ScriptFunction(const std::string& name, const joaat_t script, const SimplePattern& pattern, std::int32_t offset, bool rip) :
m_Name(name),
m_Script(script),
m_Pattern(pattern),
m_Offset(offset),
m_Rip(rip),
m_PC(0)
ScriptFunction::ScriptFunction(const joaat_t script, ScriptPointer ptr) :
m_Script(script),
m_Pointer(ptr),
m_Pc(0)
{
}
std::uint32_t ScriptFunction::GetPC(rage::scrProgram* program)
void ScriptFunction::CallImpl(const std::vector<uint64_t>& args, void* returnValue, std::uint32_t returnSize)
{
if (m_PC != 0)
return m_PC;
auto thread = Scripts::FindScriptThread(m_Script);
auto program = Scripts::FindScriptProgram(m_Script);
if (auto location = Scripts::GetCodeLocationByPattern(program, m_Pattern))
if (!thread || !program)
return;
if (!m_Pc)
{
m_PC = location.value() + m_Offset;
if (m_Rip)
m_PC = ReadThreeByte(program->GetCodeAddress(m_PC));
LOG(INFO) << "Found pattern for " << m_Name << " at " << HEX(m_PC) << " in script " << program->m_Name;
}
else
{
LOG(FATAL) << "Failed to find pattern for " << m_Name << " in script " << program->m_Name;
if (auto address = ScriptPointers::GetPointer(Joaat(m_Pointer.GetName())))
{
m_Pc = address;
}
else
{
m_Pc = m_Pointer.Scan(program).As<std::uint32_t>();
ScriptPointers::CachePointer(Joaat(m_Pointer.GetName()), m_Pc);
}
if (!m_Pc) // if still not valid
return;
}
return m_PC;
auto tlsCtx = rage::tlsContext::Get();
auto stack = (std::uint64_t*)thread->m_Stack;
auto ogThread = tlsCtx->m_CurrentScriptThread;
tlsCtx->m_CurrentScriptThread = thread;
tlsCtx->m_ScriptThreadActive = true;
rage::scrThread::Context ctx = thread->m_Context;
auto topStack = ctx.m_StackPointer;
for (auto& arg : args)
stack[ctx.m_StackPointer++] = arg;
stack[ctx.m_StackPointer++] = 0;
ctx.m_ProgramCounter = m_Pc;
ctx.m_State = rage::scrThread::State::IDLE;
Pointers.ScriptVM(stack, Pointers.ScriptGlobals, program, &ctx);
tlsCtx->m_CurrentScriptThread = ogThread;
tlsCtx->m_ScriptThreadActive = ogThread != nullptr;
if (returnValue)
std::memcpy(returnValue, stack + topStack, returnSize);
}
}
+16 -49
View File
@@ -1,74 +1,41 @@
#pragma once
#include "core/util/Joaat.hpp"
#include "core/memory/Pattern.hpp"
#include "game/pointers/Pointers.hpp"
#include "game/gta/Scripts.hpp"
#include "types/script/scrThread.hpp"
#include "types/script/scrProgram.hpp"
#include "types/rage/tlsContext.hpp"
#include "game/gta/ScriptPointer.hpp"
namespace YimMenu
{
class ScriptFunction
{
joaat_t m_Script;
const SimplePattern m_Pattern;
std::int32_t m_Offset;
bool m_Rip;
std::uint32_t m_PC;
std::string m_Name;
std::uint32_t GetPC(rage::scrProgram* program);
ScriptPointer m_Pointer;
std::uint32_t m_Pc;
template<typename Arg>
void PushArg(std::uint64_t* stack, std::uint32_t& stackPtr, Arg&& value)
static void PushArg(std::uint64_t* stack, std::uint32_t& stackPtr, Arg&& value)
{
*reinterpret_cast<std::remove_cv_t<std::remove_reference_t<Arg>>*>(reinterpret_cast<std::uint64_t*>(stack) + (stackPtr++)) = std::forward<Arg>(value);
}
std::uint32_t ReadThreeByte(std::uint8_t* arr)
{
return arr[0] + (arr[1] << 8) + (arr[2] << 16);
}
void CallImpl(const std::vector<uint64_t>& args, void* returnValue = 0, std::uint32_t returnSize = 0);
public:
ScriptFunction(const std::string& name, const joaat_t script, const SimplePattern& pattern, std::int32_t offset = 0, bool rip = false);
ScriptFunction(const joaat_t script, ScriptPointer ptr);
template<typename Ret, typename... Args>
Ret Call(Args... args)
{
auto thread = Scripts::FindScriptThread(m_Script);
auto program = Scripts::FindScriptProgram(m_Script);
if (!thread || !program)
return Ret();
auto pc = GetPC(program);
if (!pc)
return Ret();
auto tlsCtx = rage::tlsContext::Get();
auto stack = (std::uint64_t*)thread->m_Stack;
auto ogThread = tlsCtx->m_CurrentScriptThread;
tlsCtx->m_CurrentScriptThread = thread;
tlsCtx->m_ScriptThreadActive = true;
rage::scrThread::Context ctx = thread->m_Context;
auto topStack = ctx.m_StackPointer;
(PushArg(stack, ctx.m_StackPointer, std::forward<Args>(args)), ...);
stack[ctx.m_StackPointer++] = 0;
ctx.m_ProgramCounter = pc;
ctx.m_State = rage::scrThread::State::IDLE;
Pointers.ScriptVM(stack, Pointers.ScriptGlobals, program, &ctx);
tlsCtx->m_CurrentScriptThread = ogThread;
tlsCtx->m_ScriptThreadActive = ogThread != nullptr;
std::uint32_t index{};
std::vector<std::uint64_t> params(sizeof...(Args));
(PushArg(params.data(), index, std::forward<Args>(args)), ...);
if constexpr (!std::is_same_v<Ret, void>)
{
return *reinterpret_cast<Ret*>(stack + topStack);
Ret returnValue;
CallImpl(params, &returnValue, sizeof(returnValue));
return returnValue;
}
else
{
CallImpl(params);
}
}
};
-1
View File
@@ -42,5 +42,4 @@ namespace YimMenu
void* Get() const;
};
}
+8
View File
@@ -2,6 +2,8 @@
#include <cstddef>
#include <type_traits>
#include <types/script/scrThread.hpp>
#include <core/util/Joaat.hpp>
#include <src/game/gta/Scripts.hpp>
namespace YimMenu
{
@@ -32,6 +34,12 @@ namespace YimMenu
}
constexpr ScriptLocal(joaat_t script, std::size_t index) :
ScriptLocal(Scripts::FindScriptThread(script)->m_Stack, index)
{
}
constexpr ScriptLocal At(std::ptrdiff_t offset) const
{
return { m_StackPtr, m_Index + offset };
+67
View File
@@ -0,0 +1,67 @@
#include "ScriptPointer.hpp"
#include "game/gta/Scripts.hpp"
#include "types/script/scrProgram.hpp"
namespace YimMenu
{
static std::uint32_t ReadThreeByte(std::uint8_t* arr)
{
return arr[0] + (arr[1] << 8) + (arr[2] << 16);
}
ScriptPointer::ScriptPointer(const std::string& name, const SimplePattern& pattern, std::int32_t offset, bool rip, std::uint32_t address) :
m_Name(name),
m_Pattern(pattern),
m_Offset(offset),
m_Rip(rip),
m_Address(address)
{
}
ScriptPointer ScriptPointer::Add(std::uint32_t offset)
{
return ScriptPointer(m_Name, m_Pattern, m_Offset + offset, m_Rip, m_Address);
}
ScriptPointer ScriptPointer::Sub(std::uint32_t offset)
{
return ScriptPointer(m_Name, m_Pattern, m_Offset - offset, m_Rip, m_Address);
}
ScriptPointer ScriptPointer::Rip()
{
return ScriptPointer(m_Name, m_Pattern, m_Offset, true, m_Address);
}
ScriptPointer ScriptPointer::Scan(rage::scrProgram* program)
{
if (auto location = Scripts::GetCodeLocationByPattern(program, m_Pattern))
{
m_Address = location.value() + m_Offset;
if (m_Rip)
m_Address = ReadThreeByte(program->GetCodeAddress(m_Address));
LOG(INFO) << "Found pattern for " << m_Name << " at " << HEX(m_Address) << " in script " << program->m_Name;
return ScriptPointer(m_Name, m_Pattern, m_Offset, m_Rip, m_Address);
}
LOG(FATAL) << "Failed to find pattern for " << m_Name;
return ScriptPointer(m_Name, m_Pattern, m_Offset, m_Rip, 0);
}
ScriptPointer ScriptPointer::Scan(ScriptData* data)
{
if (auto location = ScriptData::GetCodeLocationByPattern(data, m_Pattern))
{
m_Address = location.value() + m_Offset;
if (m_Rip)
m_Address = ReadThreeByte(ScriptData::GetCodeLocation(data, m_Address));
LOG(INFO) << "Found pattern for " << m_Name << " at " << HEX(m_Address) << " in script " << data->GetName();
return ScriptPointer(m_Name, m_Pattern, m_Offset, m_Rip, m_Address);
}
LOG(FATAL) << "Failed to find pattern for " << m_Name;
return ScriptPointer(m_Name, m_Pattern, m_Offset, m_Rip, 0);
}
}
+34
View File
@@ -0,0 +1,34 @@
#pragma once
#include "game/gta/ScriptData.hpp"
namespace YimMenu
{
class ScriptPointer
{
const std::string m_Name;
SimplePattern m_Pattern;
std::int32_t m_Offset;
bool m_Rip;
std::uint32_t m_Address;
public:
ScriptPointer(const std::string& name, const SimplePattern& pattern, std::int32_t offset = 0, bool rip = false, std::uint32_t address = 0);
ScriptPointer Add(std::uint32_t offset);
ScriptPointer Sub(std::uint32_t offset);
ScriptPointer Rip();
ScriptPointer Scan(rage::scrProgram* program);
ScriptPointer Scan(ScriptData* data); // For script patches
template<typename T>
T As()
{
return (T)m_Address;
}
std::string GetName() const
{
return m_Name;
}
};
}
+101
View File
@@ -0,0 +1,101 @@
#pragma once
#include "core/util/Joaat.hpp"
namespace YimMenu
{
static constexpr std::array randomEventNames = {
"Drug Vehicle",
"Movie Props",
"Sleeping Guard",
"Exotic Exports",
"The Slashers",
"Phantom Car",
"Sightseeing",
"Smuggler Trail",
"Cerberus Surprise",
"Smuggler Plane",
"Crime Scene",
"Metal Detector",
"Finders Keepers",
"Shop Robbery",
"The Gooch",
"Weazel Plaza Shootout",
"Armored Truck",
"Possessed Animals",
"Ghosts Exposed",
"Happy Holidays Hauler",
"Community Outreach"
};
static constexpr std::array randomEventScripts = {
"fm_content_drug_vehicle"_J,
"fm_content_movie_props"_J,
"fm_content_golden_gun"_J,
"fm_content_vehicle_list"_J,
"fm_content_slasher"_J,
"fm_content_phantom_car"_J,
"fm_content_sightseeing"_J,
"fm_content_smuggler_trail"_J,
"fm_content_cerberus"_J,
"fm_content_smuggler_plane"_J,
"fm_content_crime_scene"_J,
"fm_content_metal_detector"_J,
"fm_content_convoy"_J,
"fm_content_robbery"_J,
"fm_content_xmas_mugger"_J,
"fm_content_bank_shootout"_J,
"fm_content_armoured_truck"_J,
"fm_content_possessed_animals"_J,
"fm_content_ghosthunt"_J,
"fm_content_xmas_truck"_J,
"fm_content_community_outreach"_J
};
static constexpr std::array randomEventCooldowns = {
"SUM22_RE_DRUG_VEHICLE_INACTIVE_TIME"_J,
"SUM22_RE_MOVIE_PROPS_INACTIVE_TIME"_J,
"SUM22_RE_GOLDEN_GUN_INACTIVE_TIME"_J,
"SUM22_RE_VEHICLE_LIST_INACTIVE_TIME"_J,
"STANDARDCONTROLLERVOLUME_COOLDOWN"_J,
"STANDARDTARGETTINGTIME_COOLDOWN"_J,
"SSP2_COOLDOWN"_J
"SUM22_RE_SMUGGLER_TRAIL_INACTIVE_TIME"_J,
"NC_SOURCE_TRUCK_COOLDOWN"_J,
"SUM22_RE_SMUGGLER_PLANE_INACTIVE_TIME"_J,
"SUM22_RE_CRIME_SCENE_INACTIVE_TIME"_J,
"SUM22_RE_METAL_DETECTOR_INACTIVE_TIME"_J,
"XM22_RE_GANG_CONVOY_INACTIVE_TIME"_J,
"XM22_RE_ROBBERY_INACTIVE_TIME"_J,
"STANDARD_KEYBIND_COOLDOWN"_J,
"XM22_RE_BANK_SHOOTOUT_INACTIVE_TIME"_J,
(joaat_t)NULL,
"STANDARDCONTROLLERVOLUME_COOLDOWN"_J,
"SUM23_RE_GHOSTHUNT_INACTIVE_TIME"_J,
"XMAS_TRUCK_INACTIVE_TIME"_J,
"RE_COMMUNITY_OUTREACH_INACTIVE_TIME"_J
};
static constexpr std::array randomEventAvailabilities = {
"SUM22_RE_DRUG_VEHICLE_AVAILABLE_TIME"_J,
"SUM22_RE_MOVIE_PROPS_AVAILABLE_TIME"_J,
"SUM22_RE_GOLDEN_GUN_AVAILABLE_TIME"_J,
"SUM22_RE_VEHICLE_LIST_AVAILABLE_TIME"_J,
"STANDARDCONTROLLERVOLUME_AVAILABILITY"_J,
"STANDARDTARGETTINGTIME_AVAILABILITY"_J,
"SSP2_AVAILABILITY"_J,
"SUM22_RE_SMUGGLER_TRAIL_AVAILABLE_TIME"_J,
"NC_SOURCE_TRUCK_AVAILABILITY"_J,
"SUM22_RE_SMUGGLER_PLANE_AVAILABLE_TIME"_J,
"SUM22_RE_CRIME_SCENE_AVAILABLE_TIME"_J,
"SUM22_RE_METAL_DETECTOR_AVAILABLE_TIME"_J,
"XM22_RE_GANG_CONVOY_AVAILABLE_TIME"_J,
"XM22_RE_ROBBERY_AVAILABLE_TIME"_J,
"STANDARD_KEYBIND_AVAILABILITY"_J,
"XM22_RE_BANK_SHOOTOUT_AVAILABLE_TIME"_J,
(joaat_t)NULL,
"STANDARDCONTROLLERVOLUME_AVAILABILITY"_J,
"SUM23_RE_GHOSTHUNT_AVAILABLE_TIME"_J,
"XMAS_TRUCK_AVAILABLE_TIME"_J,
"RE_COMMUNITY_OUTREACH_AVAILABLE_TIME"_J
};
}
+15
View File
@@ -308,6 +308,21 @@ namespace YimMenu
NetworkTime = ptr.Add(2).Rip().As<std::uint32_t*>();
});
constexpr auto gameTimerPtrn = Pattern<"3B 2D ? ? ? ? 76">("GameTimer");
scanner.Add(gameTimerPtrn, [this](PointerCalculator ptr) {
GameTimer = ptr.Add(2).Rip().As<std::uint32_t*>();
});
constexpr auto formatIntCaller1Ptrn = Pattern<"48 89 35 ? ? ? ? 48 8B 74 24">("FormatIntCaller1");
scanner.Add(formatIntCaller1Ptrn, [this](PointerCalculator ptr) {
FormatIntCaller1 = ptr.Add(0x5D).As<PVOID>();
});
constexpr auto formatIntCaller2Ptrn = Pattern<"48 B8 20 73 69 7A 65 3D 27 32 48 89 84 24">("FormatIntCaller2");
scanner.Add(formatIntCaller2Ptrn, [this](PointerCalculator ptr) {
FormatIntCaller2 = ptr.Sub(0x11).As<PVOID>();
});
if (!scanner.Scan())
{
LOG(FATAL) << "Some patterns could not be found, unloading.";
+3
View File
@@ -135,6 +135,9 @@ namespace YimMenu
Functions::GetPresenceAttributes GetPresenceAttributes;
Functions::GetAvatars GetAvatars;
std::uint32_t* NetworkTime;
std::uint32_t* GameTimer;
PVOID FormatIntCaller1;
PVOID FormatIntCaller2;
};
struct Pointers : PointerData
+5
View File
@@ -7,6 +7,7 @@
#include "core/filemgr/FileMgr.hpp"
#include "core/frontend/Notifications.hpp"
#include "core/hooking/Hooking.hpp"
#include "core/hooking/CallHook.hpp"
#include "core/memory/ModuleMgr.hpp"
#include "core/renderer/Renderer.hpp"
#include "game/backend/AnticheatBypass.hpp"
@@ -16,6 +17,7 @@
#include "game/backend/Self.hpp"
#include "game/backend/NativeHooks.hpp"
#include "game/backend/Tunables.hpp"
#include "game/backend/ScriptPointers.hpp"
#include "game/frontend/GUI.hpp"
#include "game/pointers/Pointers.hpp"
#include "game/features/recovery/GiveVehicleReward.hpp"
@@ -49,6 +51,8 @@ namespace YimMenu
ScriptMgr::Init();
LOG(INFO) << "ScriptMgr initialized";
ScriptPointers::Init();
GUI::Init();
ScriptMgr::AddScript(std::make_unique<Script>(&NativeHooks::RunScript)); // runs once
@@ -78,6 +82,7 @@ namespace YimMenu
FiberPool::Destroy();
ScriptMgr::Destroy();
Hooking::Destroy();
CallSiteHook::Destroy();
EARLY_UNLOAD:
g_Running = false;
+62
View File
@@ -0,0 +1,62 @@
#include "Timer.hpp"
#include "game/pointers/Pointers.hpp"
void TIMER::Initialize(bool localTimer)
{
if (!IsInitialized)
{
Time = (*YimMenu::Pointers.IsSessionStarted && !localTimer) ? *YimMenu::Pointers.NetworkTime : *YimMenu::Pointers.GameTimer;
IsInitialized = true;
}
}
void TIMER::Reset(bool localTimer)
{
Time = (*YimMenu::Pointers.IsSessionStarted && !localTimer) ? *YimMenu::Pointers.NetworkTime : *YimMenu::Pointers.GameTimer;
IsInitialized = true;
}
void TIMER::Destroy()
{
IsInitialized = false;
}
bool TIMER::_IsInitialized()
{
return IsInitialized;
}
bool TIMER::HasTimePassed(int ms, bool localTimer)
{
if (ms < 0)
return true;
Initialize(localTimer);
int timePassed = (*YimMenu::Pointers.IsSessionStarted && !localTimer) ? (*YimMenu::Pointers.NetworkTime - Time) : (*YimMenu::Pointers.GameTimer - Time);
if (timePassed >= ms)
return true;
return false;
}
int TIMER::GetRemainingTime(int ms, bool localTimer)
{
int timePassed = (*YimMenu::Pointers.IsSessionStarted && !localTimer) ? (*YimMenu::Pointers.NetworkTime - Time) : (*YimMenu::Pointers.GameTimer - Time);
return (ms - timePassed);
}
std::string TIMER::GetRemainingTimeStr(int ms, bool localTimer)
{
int timePassed = (*YimMenu::Pointers.IsSessionStarted && !localTimer) ? (*YimMenu::Pointers.NetworkTime - Time) : (*YimMenu::Pointers.GameTimer - Time);
int difference = (ms - timePassed);
int totalSeconds = difference / 1000;
int hours = totalSeconds / 3600;
int minutes = (totalSeconds % 3600) / 60;
int seconds = totalSeconds % 60;
if (hours < 1)
return std::format("{:02}:{:02}", minutes, seconds);
else
return std::format("{:02}:{:02}:{:02}", hours, minutes, seconds);
}
+8
View File
@@ -5,5 +5,13 @@ struct TIMER
{
SCR_INT Time;
SCR_BOOL IsInitialized;
void Initialize(bool localTimer = false);
void Reset(bool localTimer = false);
void Destroy();
bool _IsInitialized();
bool HasTimePassed(int ms, bool localTimer = false);
int GetRemainingTime(int ms, bool localTimer = false);
std::string GetRemainingTimeStr(int ms, bool localTimer = false);
};
static_assert(sizeof(TIMER) == 2 * 8);
+120
View File
@@ -0,0 +1,120 @@
#pragma once
#include "../Timer.hpp"
#include "../types.hpp"
enum class eRaceRoundType
{
NOT_SELECTED = -1,
FINISH_FIRST,
MOST_POINTS,
FASTEST_TIME
};
enum class eRaceFinalRoundType
{
NOT_SELECTED,
HEAD_TO_HEAD
};
enum class eRandomEventClientState
{
INACTIVE,
TRIGGERING, // This is different than the server available state
ACTIVE,
CLEANUP
};
enum class eRandomEventClientFlags
{
FORCE_LAUNCH
};
enum class eRandomEventClientInitState
{
INITIALIZING,
INITIALIZED
};
struct GANGOPS_DATA
{
SCR_INT UNK_0000; // 0
SCR_ARRAY<uint64_t, 4> PlayerIndexes; // 1
SCR_ARRAY<uint64_t, 4> PlayerRoles; // 6
SCR_ARRAY<uint64_t, 4> ArePlayersReady; // 11
SCR_ARRAY<uint64_t, 5> PlayerCuts; // 16
SCR_INT HighlightedPlayer; // 22
SCR_INT GangopsFlowMissionProgFlags; // 23
SCR_INT GangopsFMMissionProgFlags; // 24
SCR_INT GangopsFMMissionSkipFlags; // 25
SCR_INT GangopsHeistStatusFlags; // 26
SCR_INT Flags; // 27
SCR_BOOL IsPlanningScreenReady; // 28
SCR_BOOL QuittedPlanningScreen; // 29
SCR_BOOL IsTutorialActive; // 30
SCR_ARRAY<uint64_t, 4> IsTutorialActiveForPlayer; // 31
TIMER FinaleForceLaunchTimer; // 36 (H2_FINALE_FORCE_LAUNCH_TIME)
SCR_BOOL IsFinaleForceLaunched; // 38 (if players don't click ready in 3 minutes)
};
static_assert(sizeof(GANGOPS_DATA) == 39 * 8);
struct RANDOM_EVENTS_CLIENT_EVENT_DATA
{
alignas(8) eRandomEventClientState State; // 0
SCR_ARRAY<SCR_BITSET<eRandomEventClientFlags>, 1> Flags; // 1
};
static_assert(sizeof(RANDOM_EVENTS_CLIENT_EVENT_DATA) == 3 * 8);
struct RANDOM_EVENTS_CLIENT_DATA
{
alignas(8) eRandomEventClientInitState InitState; // 0
SCR_ARRAY<RANDOM_EVENTS_CLIENT_EVENT_DATA, 21> EventData; // 1
SCR_BITSET<uint64_t> IsParticipantInEventFlags; // 65
SCR_INT UNK_0066; // 66 (unused)
};
static_assert(sizeof(RANDOM_EVENTS_CLIENT_DATA) == 67 * 8);
struct GPBD_FM_2_Entry
{
SCR_INT NumTeams; // 0
SCR_INT NumRounds; // 1
SCR_INT RoundsPlayed; // 2
SCR_INT RoundScore; // 3
SCR_INT CurrentTeam; // 4
SCR_INT Flags; // 5
SCR_INT TotalScore; // 6
SCR_INT TotalKills; // 7
SCR_INT TotalDeaths; // 8
SCR_INT RPEarned; // 9
SCR_INT CashEarned; // 10
uint64_t PAD_0011[2]; // 11
SCR_INT APEarned; // 13
SCR_INT Duration; // 14
alignas(8) eRaceRoundType RaceRoundType; // 15
alignas(8) eRaceFinalRoundType RaceFinalRoundType; // 16
SCR_INT Flags2; // 17
SCR_INT Vote; // 18
SCR_INT NumVotes; // 19
SCR_INT MaxVotes; // 20
SCR_INT PlayerTeam; // 21
uint64_t PAD_0022[8]; // 22 (mission stuff)
SCR_INT TunableCloudCRC; // 30
SCR_INT CatalogCloudCRC; // 31
SCR_INT UNK_0032; // 32
SCR_INT Flags3; // 33
SCR_INT UNK_0034; // 34
SCR_BOOL HasVoted; // 35
TIMER UNK_0036; // 36
TIMER UNK_0038; // 38
SCR_VEC3 CoronaPosition; // 40
GANGOPS_DATA GangopsData; // 43
RANDOM_EVENTS_CLIENT_DATA RandomEventsClientData; // 82
};
static_assert(sizeof(GPBD_FM_2_Entry) == 149 * 8);
struct GPBD_FM_2
{
SCR_ARRAY<GPBD_FM_2_Entry, 32> Entries;
static GPBD_FM_2* Get();
};
static_assert(sizeof(GPBD_FM_2) == 4769 * 8);
@@ -16,7 +16,7 @@ enum class eRandomEventState
CLEANUP
};
enum class eRandomEventBitset
enum class eRandomEventFlags
{
TRIGGERED_BY_CLIENT,
FORCE_LAUNCH,
@@ -36,7 +36,7 @@ struct RANDOM_EVENTS_DATA
{
alignas(8) eRandomEventState State; // 0
TIMER TimerState; // 1
SCR_ARRAY<SCR_BITSET<eRandomEventBitset>, 1> Bitset; // 3
SCR_ARRAY<SCR_BITSET<eRandomEventFlags>, 1> Flags; // 3
SCR_INT Variation; // 5
SCR_INT Subvariation; // 6
RANDOM_EVENTS_RESERVATION_DATA ReservationData; // 7
+12 -9
View File
@@ -1,5 +1,5 @@
#include "GlobalPlayerBD.hpp"
#include "GPBD_FM.hpp"
#include "GPBD_FM_2.hpp"
#include "GPBD_FM_3.hpp"
#include "GPBD_Kicking.hpp"
#include "GPBD_MissionName.hpp"
@@ -9,20 +9,23 @@
#include "GSBD_FM_Events.hpp"
#include "GSBD_Kicking.hpp"
#include "GSBD_PropertyInstances.hpp"
#include "g_AMC_playerBD.hpp"
#include "GSBD_RandomEvents.hpp"
#include "GlobalPlayerBD.hpp"
#include "g_AMC_playerBD.hpp"
#include "game/gta/ScriptGlobal.hpp"
#define DEFINE_GLOBAL_ACCESSOR(str, global) str* str::Get()\
{ \
auto glb = YimMenu::ScriptGlobal(global); \
if (!glb.CanAccess()) \
return nullptr; \
return glb.As<str*>(); \
}
#define DEFINE_GLOBAL_ACCESSOR(str, global) \
str* str::Get() \
{ \
auto glb = YimMenu::ScriptGlobal(global); \
if (!glb.CanAccess()) \
return nullptr; \
return glb.As<str*>(); \
}
DEFINE_GLOBAL_ACCESSOR(GlobalPlayerBD, 2657994);
DEFINE_GLOBAL_ACCESSOR(GPBD_FM, 1845270);
DEFINE_GLOBAL_ACCESSOR(GPBD_FM_2, 1882925);
DEFINE_GLOBAL_ACCESSOR(GPBD_FM_3, 1887694);
DEFINE_GLOBAL_ACCESSOR(GPBD_Kicking, 1874328);
DEFINE_GLOBAL_ACCESSOR(GPBD_MissionName, 1873815);
+2 -2
View File
@@ -7,7 +7,7 @@ namespace rage
class scrThread;
}
enum class eRandomEventFlags
enum class eRandomEventFMFlags
{
RESTART = 2,
DISABLE_DISTANCE_CHECK = 4
@@ -22,7 +22,7 @@ struct RANDOM_EVENTS_LOCAL_DATA
SCR_INT AvailablePtr; // 5
SCR_INT InactiveTime; // 6
SCR_INT AvailableTime; // 7
SCR_BITSET<eRandomEventFlags> Flags; // 8
SCR_BITSET<eRandomEventFMFlags> Flags; // 8
TIMER LastTriggerAttempt; // 9
SCR_INT UNK_0011; // 11 (unused, ranges from 0 to 4)
};
+1 -1
View File
@@ -1,5 +1,5 @@
#include "VehicleRewardData.hpp"
#include "FMRandomEvents.hpp"
#include "VehicleRewardData.hpp"
#include "game/gta/ScriptLocal.hpp"
#define DEFINE_LOCAL_ACCESSOR(str, local) \