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:
@@ -4,6 +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"
|
||||
|
||||
namespace YimMenu::Submenus
|
||||
{
|
||||
@@ -96,5 +97,6 @@ namespace YimMenu::Submenus
|
||||
AddCategory(std::move(session));
|
||||
AddCategory(std::move(spoofing));
|
||||
AddCategory(std::move(BuildSavedPlayersMenu()));
|
||||
AddCategory(BuildRandomEventsMenu());
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,304 @@
|
||||
#include "RandomEvents.hpp"
|
||||
#include "core/backend/FiberPool.hpp"
|
||||
#include "core/backend/ScriptMgr.hpp"
|
||||
#include "core/frontend/Notifications.hpp"
|
||||
#include "game/backend/Self.hpp"
|
||||
#include "game/gta/Scripts.hpp"
|
||||
#include "game/gta/ScriptFunction.hpp"
|
||||
#include "game/pointers/Pointers.hpp"
|
||||
#include "types/script/globals/GSBD_RandomEvents.hpp"
|
||||
#include "types/script/locals/FMRandomEvents.hpp"
|
||||
#include "types/script/ScriptEvent.hpp"
|
||||
#include "types/script/GtaThread.hpp"
|
||||
#include "types/script/CGameScriptHandlerNetComponent.hpp"
|
||||
#include "types/network/CNetGamePlayer.hpp"
|
||||
|
||||
namespace YimMenu::Submenus
|
||||
{
|
||||
enum eRandomEvent
|
||||
{
|
||||
DRUG_VEHICLE,
|
||||
MOVIE_PROPS,
|
||||
GOLDEN_GUN,
|
||||
VEHICLE_LIST,
|
||||
SLASHER,
|
||||
PHANTOM_CAR,
|
||||
SIGHTSEEING,
|
||||
SMUGGLER_TRAIL,
|
||||
CERBERUS,
|
||||
SMUGGLER_PLANE,
|
||||
CRIME_SCENE,
|
||||
METAL_DETECTOR,
|
||||
CONVOY,
|
||||
ROBBERY,
|
||||
XMAS_MUGGER,
|
||||
BANK_SHOOTOUT,
|
||||
ARMOURED_TRUCK,
|
||||
POSSESSED_ANIMALS,
|
||||
GHOSTHUNT,
|
||||
XMAS_TRUCK,
|
||||
COMMUNITY_OUTREACH,
|
||||
|
||||
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 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 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);
|
||||
case eRandomEventState::AVAILABLE:
|
||||
return "Available - deactivating in " + GetEventTimeLeftStr(FMRandomEvents->EventData[selectedEvent].AvailableTime, GSBDRandomEvents->EventData[selectedEvent].TimerState.Time);
|
||||
case eRandomEventState::ACTIVE:
|
||||
return "Active";
|
||||
case eRandomEventState::CLEANUP:
|
||||
return "Cleanup";
|
||||
}
|
||||
|
||||
return "N/A";
|
||||
}
|
||||
|
||||
std::shared_ptr<Category> BuildRandomEventsMenu()
|
||||
{
|
||||
auto menu = std::make_shared<Category>("Random Events");
|
||||
|
||||
menu->AddItem(std::make_unique<ImGuiItem>([] {
|
||||
GSBDRandomEvents = nullptr;
|
||||
FMRandomEvents = nullptr;
|
||||
|
||||
GSBDRandomEvents = GSBD_RandomEvents::Get();
|
||||
if (!GSBDRandomEvents)
|
||||
return ImGui::Text("Freemode global block is not loaded yet.");
|
||||
|
||||
if (GSBDRandomEvents->InitState != eRandomEventInitState::INITIALIZED)
|
||||
return ImGui::Text("Random Events are not initialized yet.");
|
||||
|
||||
if (auto freemode = Scripts::FindScriptThread("freemode"_J))
|
||||
{
|
||||
FMRandomEvents = RANDOM_EVENTS_FREEMODE_DATA::Get(freemode);
|
||||
if (!FMRandomEvents)
|
||||
return ImGui::Text("Freemode stack is not valid.");
|
||||
}
|
||||
else
|
||||
{
|
||||
return ImGui::Text("Freemode is not running.");
|
||||
}
|
||||
|
||||
if (ImGui::BeginCombo("Select Event", randomEventNames[selectedEvent]))
|
||||
{
|
||||
for (int event = DRUG_VEHICLE; event < MAX_EVENTS; event++)
|
||||
{
|
||||
switch (GSBDRandomEvents->EventData[event].State)
|
||||
{
|
||||
case eRandomEventState::INACTIVE:
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 0.0f, 0.0f, 1.0f));
|
||||
break;
|
||||
case eRandomEventState::AVAILABLE:
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(1.0f, 1.0f, 1.0f, 1.0f));
|
||||
break;
|
||||
case eRandomEventState::ACTIVE:
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImVec4(0.0f, 1.0f, 0.0f, 1.0f));
|
||||
break;
|
||||
}
|
||||
|
||||
if (ImGui::Selectable(randomEventNames[event], event == selectedEvent))
|
||||
{
|
||||
FiberPool::Push([event] {
|
||||
selectedEvent = (eRandomEvent)event;
|
||||
numSubVariations = getNumFMMCVariations.Call<int>(FMRandomEvents->MissionData.FMMCData[selectedEvent].FMMCType, 0) - 1;
|
||||
});
|
||||
}
|
||||
|
||||
ImGui::PopStyleColor();
|
||||
}
|
||||
|
||||
ImGui::EndCombo();
|
||||
}
|
||||
|
||||
if (ImGui::InputInt(std::format("Select Location (0-{})", numSubVariations).c_str(), &selectedSubvariation))
|
||||
{
|
||||
selectedSubvariation = std::clamp(selectedSubvariation, 0, numSubVariations);
|
||||
}
|
||||
|
||||
if (ImGui::Button("Launch Event"))
|
||||
{
|
||||
FiberPool::Push([] {
|
||||
if (GSBDRandomEvents->EventData[selectedEvent].State != eRandomEventState::ACTIVE)
|
||||
{
|
||||
SCRIPT_EVENT_REQUEST_RANDOM_EVENT eventData;
|
||||
eventData.FMMCType = FMRandomEvents->MissionData.FMMCData[selectedEvent].FMMCType;
|
||||
eventData.Subvariation = selectedSubvariation;
|
||||
eventData.PlayersToSend = 1; // Set FORCE_LAUNCH bit of all players
|
||||
eventData.Send();
|
||||
ScriptMgr::Yield(100ms);
|
||||
if (GSBDRandomEvents->EventData[selectedEvent].State == eRandomEventState::INACTIVE)
|
||||
{
|
||||
Notifications::Show("Random Events", "Failed to launch event. Are you freemode host?", NotificationType::Error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Notifications::Show("Random Events", "Event is already active.", NotificationType::Error);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
ImGui::SetTooltip("Force launches the event.");
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button("Kill Event"))
|
||||
{
|
||||
FiberPool::Push([] {
|
||||
if (GSBDRandomEvents->EventData[selectedEvent].State == eRandomEventState::AVAILABLE)
|
||||
{
|
||||
GSBDRandomEvents->EventData[selectedEvent].State = eRandomEventState::CLEANUP;
|
||||
}
|
||||
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?
|
||||
}
|
||||
else
|
||||
{
|
||||
Notifications::Show("Random Events", "Event is not active.", NotificationType::Error);
|
||||
}
|
||||
});
|
||||
}
|
||||
if (ImGui::IsItemHovered())
|
||||
{
|
||||
ImGui::SetTooltip("Terminates the event.");
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button("Teleport to Event"))
|
||||
{
|
||||
FiberPool::Push([] {
|
||||
if (GSBDRandomEvents->EventData[selectedEvent].State >= eRandomEventState::AVAILABLE)
|
||||
{
|
||||
auto coords = GSBDRandomEvents->EventData[selectedEvent].TriggerPosition;
|
||||
if (coords != Vector3(0.f, 0.f, 0.f))
|
||||
{
|
||||
Self::GetPed().TeleportTo(coords);
|
||||
}
|
||||
else // Either update event coords TSE not sent yet or event doesn't register a trigger point
|
||||
{
|
||||
Notifications::Show("Random Events", "Failed to teleport to event. Coordinates are not valid.", NotificationType::Error);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
Notifications::Show("Random Events", "Event is not active.", NotificationType::Error);
|
||||
}
|
||||
});
|
||||
}
|
||||
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 netComponent = reinterpret_cast<GtaThread*>(eventThread)->m_NetComponent)
|
||||
{
|
||||
if (auto host = netComponent->GetHost())
|
||||
{
|
||||
ImGui::Text("Host: %s", host->GetName());
|
||||
}
|
||||
ImGui::SameLine();
|
||||
ImGui::BeginDisabled(netComponent->IsLocalPlayerHost());
|
||||
if (ImGui::SmallButton("Take Control"))
|
||||
{
|
||||
FiberPool::Push([eventThread] {
|
||||
Scripts::ForceScriptHost(eventThread);
|
||||
});
|
||||
}
|
||||
ImGui::EndDisabled();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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
|
||||
}));
|
||||
|
||||
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> BuildRandomEventsMenu();
|
||||
}
|
||||
@@ -2,10 +2,12 @@
|
||||
|
||||
namespace YimMenu
|
||||
{
|
||||
ScriptFunction::ScriptFunction(const std::string& name, const joaat_t script, const SimplePattern& pattern) :
|
||||
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)
|
||||
{
|
||||
}
|
||||
@@ -17,7 +19,9 @@ namespace YimMenu
|
||||
|
||||
if (auto location = Scripts::GetCodeLocationByPattern(program, m_Pattern))
|
||||
{
|
||||
m_PC = location.value();
|
||||
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
|
||||
|
||||
@@ -13,6 +13,8 @@ namespace YimMenu
|
||||
{
|
||||
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;
|
||||
|
||||
@@ -24,8 +26,13 @@ namespace YimMenu
|
||||
*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);
|
||||
}
|
||||
|
||||
public:
|
||||
ScriptFunction(const std::string& name, const joaat_t script, const SimplePattern& pattern);
|
||||
ScriptFunction(const std::string& name, const joaat_t script, const SimplePattern& pattern, std::int32_t offset = 0, bool rip = false);
|
||||
|
||||
template<typename Ret, typename... Args>
|
||||
Ret Call(Args... args)
|
||||
|
||||
@@ -303,6 +303,11 @@ namespace YimMenu
|
||||
GetSessionByGamerHandle = ptr.Sub(0x4A).Add(1).Rip().As<Functions::GetSessionByGamerHandle>();
|
||||
});
|
||||
|
||||
constexpr auto networkTimePtrn = Pattern<"89 05 ? ? ? ? 80 3D ? ? ? ? ? 0F 84 ? ? ? ? E9">("NetworkTime");
|
||||
scanner.Add(networkTimePtrn, [this](PointerCalculator ptr) {
|
||||
NetworkTime = ptr.Add(2).Rip().As<std::uint32_t*>();
|
||||
});
|
||||
|
||||
if (!scanner.Scan())
|
||||
{
|
||||
LOG(FATAL) << "Some patterns could not be found, unloading.";
|
||||
|
||||
@@ -134,6 +134,7 @@ namespace YimMenu
|
||||
Functions::GetSessionByGamerHandle GetSessionByGamerHandle;
|
||||
Functions::GetPresenceAttributes GetPresenceAttributes;
|
||||
Functions::GetAvatars GetAvatars;
|
||||
std::uint32_t* NetworkTime;
|
||||
};
|
||||
|
||||
struct Pointers : PointerData
|
||||
|
||||
@@ -76,7 +76,9 @@ enum class ScriptEventIndex
|
||||
TriggerCEORaid = -1906536929,
|
||||
|
||||
StartScriptBegin = -366707054,
|
||||
StartScriptProceed = 1757622014
|
||||
StartScriptProceed = 1757622014,
|
||||
|
||||
RequestRandomEvent = -126218586
|
||||
};
|
||||
|
||||
struct SCRIPT_EVENT
|
||||
@@ -169,4 +171,15 @@ struct SCRIPT_EVENT_SEND_TO_INTERIOR : public SCRIPT_EVENT
|
||||
};
|
||||
static_assert(sizeof(SCRIPT_EVENT_SEND_TO_INTERIOR) == 16 * 8);
|
||||
|
||||
struct SCRIPT_EVENT_REQUEST_RANDOM_EVENT : public SCRIPT_EVENT
|
||||
{
|
||||
REGISTER_SCRIPT_EVENT(SCRIPT_EVENT_REQUEST_RANDOM_EVENT, RequestRandomEvent);
|
||||
|
||||
SCR_INT FMMCType;
|
||||
SCR_INT Variation;
|
||||
SCR_INT Subvariation;
|
||||
SCR_INT PlayersToSend;
|
||||
};
|
||||
static_assert(sizeof(SCRIPT_EVENT_REQUEST_RANDOM_EVENT) == 7 * 8);
|
||||
|
||||
#undef REGISTER_SCRIPT_EVENT
|
||||
@@ -0,0 +1,72 @@
|
||||
#pragma once
|
||||
#include "../Timer.hpp"
|
||||
#include "../types.hpp"
|
||||
|
||||
enum class eRandomEventInitState
|
||||
{
|
||||
INITIALIZING,
|
||||
INITIALIZED
|
||||
};
|
||||
|
||||
enum class eRandomEventState
|
||||
{
|
||||
INACTIVE,
|
||||
AVAILABLE,
|
||||
ACTIVE,
|
||||
CLEANUP
|
||||
};
|
||||
|
||||
enum class eRandomEventBitset
|
||||
{
|
||||
TRIGGERED_BY_CLIENT,
|
||||
FORCE_LAUNCH,
|
||||
UNK_2, // unused
|
||||
FORCE_CLEANUP
|
||||
};
|
||||
|
||||
struct RANDOM_EVENTS_RESERVATION_DATA
|
||||
{
|
||||
SCR_INT ReservedPeds; // 0
|
||||
SCR_INT ReservedVehicles; // 1
|
||||
SCR_INT ReservedObjects; // 2
|
||||
};
|
||||
static_assert(sizeof(RANDOM_EVENTS_RESERVATION_DATA) == 3 * 8);
|
||||
|
||||
struct RANDOM_EVENTS_DATA
|
||||
{
|
||||
alignas(8) eRandomEventState State; // 0
|
||||
TIMER TimerState; // 1
|
||||
SCR_ARRAY<SCR_BITSET<eRandomEventBitset>, 1> Bitset; // 3
|
||||
SCR_INT Variation; // 5
|
||||
SCR_INT Subvariation; // 6
|
||||
RANDOM_EVENTS_RESERVATION_DATA ReservationData; // 7
|
||||
SCR_VEC3 TriggerPosition; // 10
|
||||
SCR_FLOAT TriggerRange; // 13
|
||||
SCR_INT Retries; // 14
|
||||
};
|
||||
static_assert(sizeof(RANDOM_EVENTS_DATA) == 15 * 8);
|
||||
|
||||
struct RANDOM_EVENTS_VEHICLE_LIST_DATA
|
||||
{
|
||||
SCR_INT UNK_0000; // 0
|
||||
SCR_INT Variation; // 1
|
||||
};
|
||||
static_assert(sizeof(RANDOM_EVENTS_VEHICLE_LIST_DATA) == 2 * 8);
|
||||
|
||||
struct RANDOM_EVENTS_TARGET_DATA
|
||||
{
|
||||
PLAYER_INDEX PhantomCarTarget; // 0
|
||||
PLAYER_INDEX XMASMuggerTarget; // 1
|
||||
};
|
||||
static_assert(sizeof(RANDOM_EVENTS_TARGET_DATA) == 2 * 8);
|
||||
|
||||
struct GSBD_RandomEvents
|
||||
{
|
||||
alignas(8) eRandomEventInitState InitState; // 0
|
||||
SCR_ARRAY<RANDOM_EVENTS_DATA, 21> EventData; // 1
|
||||
RANDOM_EVENTS_VEHICLE_LIST_DATA VehicleListData; // 317
|
||||
RANDOM_EVENTS_TARGET_DATA TargetData; // 319
|
||||
|
||||
static GSBD_RandomEvents* Get();
|
||||
};
|
||||
static_assert(sizeof(GSBD_RandomEvents) == 321 * 8);
|
||||
@@ -10,6 +10,7 @@
|
||||
#include "GSBD_Kicking.hpp"
|
||||
#include "GSBD_PropertyInstances.hpp"
|
||||
#include "g_AMC_playerBD.hpp"
|
||||
#include "GSBD_RandomEvents.hpp"
|
||||
#include "game/gta/ScriptGlobal.hpp"
|
||||
|
||||
#define DEFINE_GLOBAL_ACCESSOR(str, global) str* str::Get()\
|
||||
@@ -31,4 +32,5 @@ DEFINE_GLOBAL_ACCESSOR(GSBD_FM, 1835557);
|
||||
DEFINE_GLOBAL_ACCESSOR(GSBD_FM_Events, 1917230);
|
||||
DEFINE_GLOBAL_ACCESSOR(GSBD_Kicking, 1877529);
|
||||
DEFINE_GLOBAL_ACCESSOR(GSBD_PropertyInstances, 1937699);
|
||||
DEFINE_GLOBAL_ACCESSOR(g_AMC_playerBD, 2699624);
|
||||
DEFINE_GLOBAL_ACCESSOR(g_AMC_playerBD, 2699624);
|
||||
DEFINE_GLOBAL_ACCESSOR(GSBD_RandomEvents, 1882524);
|
||||
@@ -0,0 +1,51 @@
|
||||
#pragma once
|
||||
#include "../types.hpp"
|
||||
#include "../Timer.hpp"
|
||||
|
||||
namespace rage
|
||||
{
|
||||
class scrThread;
|
||||
}
|
||||
|
||||
enum class eRandomEventFlags
|
||||
{
|
||||
RESTART = 2,
|
||||
DISABLE_DISTANCE_CHECK = 4
|
||||
};
|
||||
|
||||
struct RANDOM_EVENTS_LOCAL_DATA
|
||||
{
|
||||
SCR_INT RegisteredEvents; // 0
|
||||
SCR_ARRAY<uint64_t, 1> TriggerPtr; // 1
|
||||
SCR_INT TriggerPositionPtr; // 3
|
||||
SCR_INT TriggerRangePtr; // 4
|
||||
SCR_INT AvailablePtr; // 5
|
||||
SCR_INT InactiveTime; // 6
|
||||
SCR_INT AvailableTime; // 7
|
||||
SCR_BITSET<eRandomEventFlags> Flags; // 8
|
||||
TIMER LastTriggerAttempt; // 9
|
||||
SCR_INT UNK_0011; // 11 (unused, ranges from 0 to 4)
|
||||
};
|
||||
static_assert(sizeof(RANDOM_EVENTS_LOCAL_DATA) == 12 * 8);
|
||||
|
||||
struct RANDOM_EVENTS_FMMC_DATA
|
||||
{
|
||||
SCR_INT FMMCType; // 0
|
||||
};
|
||||
static_assert(sizeof(RANDOM_EVENTS_FMMC_DATA) == 1 * 8);
|
||||
|
||||
struct RANDOM_EVENTS_MISSION_DATA
|
||||
{
|
||||
SCR_INT EventsCount; // 0
|
||||
SCR_ARRAY<RANDOM_EVENTS_FMMC_DATA, 21> FMMCData; // 1
|
||||
};
|
||||
static_assert(sizeof(RANDOM_EVENTS_MISSION_DATA) == 23 * 8);
|
||||
|
||||
struct RANDOM_EVENTS_FREEMODE_DATA
|
||||
{
|
||||
SCR_ARRAY<RANDOM_EVENTS_LOCAL_DATA, 21> EventData; // 0
|
||||
RANDOM_EVENTS_MISSION_DATA MissionData; // 253
|
||||
|
||||
static RANDOM_EVENTS_FREEMODE_DATA* Get(rage::scrThread* thread);
|
||||
};
|
||||
static_assert(sizeof(RANDOM_EVENTS_FREEMODE_DATA) == 276 * 8);
|
||||
@@ -1,4 +1,5 @@
|
||||
#include "VehicleRewardData.hpp"
|
||||
#include "FMRandomEvents.hpp"
|
||||
#include "game/gta/ScriptLocal.hpp"
|
||||
|
||||
#define DEFINE_LOCAL_ACCESSOR(str, local) \
|
||||
@@ -10,4 +11,5 @@
|
||||
return lcl.As<str*>(); \
|
||||
}
|
||||
|
||||
DEFINE_LOCAL_ACCESSOR(VEHICLE_REWARD_DATA, 129);
|
||||
DEFINE_LOCAL_ACCESSOR(VEHICLE_REWARD_DATA, 129);
|
||||
DEFINE_LOCAL_ACCESSOR(RANDOM_EVENTS_FREEMODE_DATA, 15919);
|
||||
Reference in New Issue
Block a user