mirror of
https://github.com/YimMenu/YimMenuV2.git
synced 2026-10-10 03:43:15 +08:00
Merge branch 'enhanced' of https://github.com/YimMenu/YimMenuV2 into enhanced
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
@@ -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>;
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
|
||||
@@ -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.";
|
||||
}
|
||||
}
|
||||
@@ -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."};
|
||||
}
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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"};
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
};
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -42,5 +42,4 @@ namespace YimMenu
|
||||
void* Get() const;
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
@@ -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 };
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
};
|
||||
}
|
||||
@@ -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
|
||||
};
|
||||
}
|
||||
@@ -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.";
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,5 +1,5 @@
|
||||
#include "VehicleRewardData.hpp"
|
||||
#include "FMRandomEvents.hpp"
|
||||
#include "VehicleRewardData.hpp"
|
||||
#include "game/gta/ScriptLocal.hpp"
|
||||
|
||||
#define DEFINE_LOCAL_ACCESSOR(str, local) \
|
||||
|
||||
Reference in New Issue
Block a user