From e3a104451bd2e91cb492ee1242e9a236dc4f6f7b Mon Sep 17 00:00:00 2001 From: Rylxnd Date: Thu, 17 Aug 2023 15:41:50 -0400 Subject: [PATCH 01/12] Add effects "Hello, this is Agatha" & "Dave Here" --- ChaosMod/ChaosMod.vcxproj | 3 + ChaosMod/Components/Globals.cpp | 71 +++++ ChaosMod/Components/Globals.h | 66 ++++ ChaosMod/Effects/db/Misc/MiscPhoneCall.cpp | 341 +++++++++++++++++++++ ChaosMod/Main.cpp | 3 + ConfigApp/Effects.cs | 2 + 6 files changed, 486 insertions(+) create mode 100644 ChaosMod/Components/Globals.cpp create mode 100644 ChaosMod/Components/Globals.h create mode 100644 ChaosMod/Effects/db/Misc/MiscPhoneCall.cpp diff --git a/ChaosMod/ChaosMod.vcxproj b/ChaosMod/ChaosMod.vcxproj index f5873ebbf..8e32bd904 100644 --- a/ChaosMod/ChaosMod.vcxproj +++ b/ChaosMod/ChaosMod.vcxproj @@ -91,6 +91,7 @@ + @@ -115,6 +116,7 @@ + @@ -413,6 +415,7 @@ + diff --git a/ChaosMod/Components/Globals.cpp b/ChaosMod/Components/Globals.cpp new file mode 100644 index 000000000..bb6bc3585 --- /dev/null +++ b/ChaosMod/Components/Globals.cpp @@ -0,0 +1,71 @@ +#include + +#include "Globals.h" + +#include "Lib/scrThread.h" + +#include "Memory/Script.h" + +std::map Globals::m_GlobalsIndexMap = {}; +static std::vector m_GlobalsRegistration = {}; + +Globals::Globals() : Component() +{ + REGISTER_GLOBAL("CellPhoneState", "dialogue_handler", + "2D 00 02 00 ? 52 ? ? 41 ? 72 08 2A 06 56 ? ? 52 ? ? 41 ? 71 08 20 56 ? ? 72", 6, + GlobalPatternIdiom::GLOBAL_U16); + + REGISTER_GLOBAL("CellPhoneLock", "dialogue_handler", + "72 54 ? ? 5d ? ? ? 71 2c ? ? ? 2b 72 54 ? ? 77 54 ? ? 52 ? ? 25 ? 2c ? ? ? 53 ? ? 06 56 ? ? 52 ? ? 76", 2, + GlobalPatternIdiom::GLOBAL_U16); + + + m_SearchGlobalsListener.Register( + Hooks::OnScriptThreadRun, + [&](rage::scrThread *thread) + { + // Save a f**k-tonne of CPU resources by destructing the event listener when we no longer have anymore globals to find + if (m_GlobalsRegistration.size() <= 0) + { + m_SearchGlobalsListener.~ChaosEventListener(); + return true; + } + + auto match = + std::find_if(m_GlobalsRegistration.begin(), m_GlobalsRegistration.end(), + [&thread](GlobalRegistration ®) { return reg.m_ScriptName == thread->GetName(); }); + + if (match == m_GlobalsRegistration.end()) + return true; + + GlobalRegistration searchedGlobal = *match; + + auto program = Memory::ScriptThreadToProgram(thread); + if (program->m_CodeBlocks) + { + Handle handle = Memory::FindScriptPattern(searchedGlobal.m_Pattern, program); + + if (!handle.IsValid()) + { + LOG("Failed to find global \"" << searchedGlobal.m_Name << "\""); + } + else + { + int globalIndex; + + if (searchedGlobal.m_PatternIdiom == GlobalPatternIdiom::GLOBAL_U16) + globalIndex = handle.At(searchedGlobal.m_Offset).Value() & 0xFFFFFF; + else + globalIndex = handle.At(searchedGlobal.m_Offset).Value() & 0xFFFFFF; + + Globals::SetGlobalIndex(searchedGlobal.m_Name, globalIndex); + + LOG("Found global \"" << searchedGlobal.m_Name << "\" (Global: " << globalIndex << ")"); + } + } + + m_GlobalsRegistration.erase(match); + + return true; + }); +} \ No newline at end of file diff --git a/ChaosMod/Components/Globals.h b/ChaosMod/Components/Globals.h new file mode 100644 index 000000000..59e5e2b81 --- /dev/null +++ b/ChaosMod/Components/Globals.h @@ -0,0 +1,66 @@ +#pragma once + +#include "Components/Component.h" + +#include "Memory/Hooks/ScriptThreadRunHook.h" + +#include +#include + +enum GlobalPatternIdiom : uint8_t +{ + GLOBAL_U16, + GLOBAL_U24 +}; + +struct GlobalRegistration +{ + public: + std::string m_Name; + std::string m_ScriptName; + std::string m_Pattern; + int m_Offset; + GlobalPatternIdiom m_PatternIdiom; + + GlobalRegistration(std::string name, std::string scriptName, std::string pattern, int offset, + GlobalPatternIdiom patternIdiom) + : m_Name(name), m_ScriptName(scriptName), m_Pattern(pattern), m_Offset(offset), m_PatternIdiom(patternIdiom) + { + } +}; + +class Globals : public Component +{ + private: + static std::map m_GlobalsIndexMap; + + CHAOS_EVENT_LISTENER(Hooks::OnScriptThreadRun) m_SearchGlobalsListener; + + protected: + Globals(); + + public: + static void SetGlobalIndex(std::string name, int index) + { + m_GlobalsIndexMap.emplace(name, index); + } + + template static T *GetGlobalAddr(std::string name) + { + if (!m_GlobalsIndexMap.contains(name)) + { + return nullptr; + } + + auto it = m_GlobalsIndexMap.at(name); + + return reinterpret_cast(Memory::GetGlobalPtr(it)); + } + + template + requires std::is_base_of_v + friend struct ComponentHolder; +}; + +#define REGISTER_GLOBAL(name, scriptName, pattern, patternOffset, patternIdiom) \ + m_GlobalsRegistration.push_back({ name, scriptName, pattern, patternOffset, patternIdiom }) \ No newline at end of file diff --git a/ChaosMod/Effects/db/Misc/MiscPhoneCall.cpp b/ChaosMod/Effects/db/Misc/MiscPhoneCall.cpp new file mode 100644 index 000000000..610ecda3f --- /dev/null +++ b/ChaosMod/Effects/db/Misc/MiscPhoneCall.cpp @@ -0,0 +1,341 @@ +/* + Effect By Rylxnd +*/ + +#include + +#include "Memory/Hooks/ScriptThreadRunHook.h" + +#include "Components/Globals.h" + +struct PhoneCallLine +{ + const char *lineGXT; + const char *subtitleGXT; +}; + +struct PhoneCall +{ + const char *contactName; + const char *profileTxdName; + const char *speakerName; + const char *GXTFile; + const char *ambientLine; + + std::vector lines; +}; + +struct CellPhone +{ + alignas(8) uint32_t unk0; + alignas(8) uint32_t state; +}; + +static uint8_t *lockCellphoneGlobal; +static CellPhone *cellphoneStateGlobal; + +static int phoneScaleform = 0; +static int currentMode = 0; +static int lastTick = 0; +static int soundId = 0; + +static bool isDialing = true; +static bool lockCellphone = true; + +std::unordered_map phoneScaleforms = { { 0xD7114C9, "cellphone_ifruit" }, + { 0x9B22DBAF, "cellphone_badger" }, + { 0x9B810FA2, "cellphone_facade" } }; + +static void DrawPhone(PhoneCall &phoneCall) +{ + if (isDialing) + { + BEGIN_SCALEFORM_MOVIE_METHOD(phoneScaleform, "SET_SOFT_KEYS"); + SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(2); + SCALEFORM_MOVIE_METHOD_ADD_PARAM_BOOL(true); + SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(5); + END_SCALEFORM_MOVIE_METHOD(); + } + else + { + BEGIN_SCALEFORM_MOVIE_METHOD(phoneScaleform, "SET_SOFT_KEYS"); + SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(2); + SCALEFORM_MOVIE_METHOD_ADD_PARAM_BOOL(true); + SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(1); + END_SCALEFORM_MOVIE_METHOD(); + } + + BEGIN_SCALEFORM_MOVIE_METHOD(phoneScaleform, "SET_SOFT_KEYS"); + SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(3); + SCALEFORM_MOVIE_METHOD_ADD_PARAM_BOOL(true); + SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(1); + END_SCALEFORM_MOVIE_METHOD(); + + BEGIN_SCALEFORM_MOVIE_METHOD(phoneScaleform, "SET_DATA_SLOT"); + SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(4); + SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(0); + SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(3); + + BEGIN_TEXT_COMMAND_SCALEFORM_STRING(phoneCall.contactName); + END_TEXT_COMMAND_SCALEFORM_STRING(); + + BEGIN_TEXT_COMMAND_SCALEFORM_STRING("CELL_2000"); + ADD_TEXT_COMPONENT_SUBSTRING_PLAYER_NAME(phoneCall.profileTxdName); + END_TEXT_COMMAND_SCALEFORM_STRING(); + + BEGIN_TEXT_COMMAND_SCALEFORM_STRING(isDialing ? "CELL_217" : "CELL_219"); + END_TEXT_COMMAND_SCALEFORM_STRING(); + + END_SCALEFORM_MOVIE_METHOD(); + + BEGIN_SCALEFORM_MOVIE_METHOD(phoneScaleform, "DISPLAY_VIEW"); + SCALEFORM_MOVIE_METHOD_ADD_PARAM_INT(4); + END_SCALEFORM_MOVIE_METHOD(); +} + +static void UpdatePhone(PhoneCall &phoneCall) +{ + DrawPhone(phoneCall); + *lockCellphoneGlobal = (uint8_t)lockCellphone; // disables phone inputs + TERMINATE_ALL_SCRIPTS_WITH_THIS_NAME("cellphone_controller"); +} + +static void PlayPhoneCall(PhoneCall &phoneCall) +{ + lockCellphoneGlobal = Globals::GetGlobalAddr("CellPhoneLock"); + cellphoneStateGlobal = Globals::GetGlobalAddr("CellPhoneState"); + + if (cellphoneStateGlobal == nullptr || lockCellphoneGlobal == nullptr) + return; + + *lockCellphoneGlobal = 0; + + currentMode = 0; + lockCellphone = true; + + Ped playerPed = PLAYER_PED_ID(); + soundId = GET_SOUND_ID(); + + phoneScaleform = REQUEST_SCALEFORM_MOVIE(phoneScaleforms.at(GET_ENTITY_MODEL(playerPed))); + while (!HAS_SCALEFORM_MOVIE_LOADED(phoneScaleform)) + WAIT(0); + + CLEAR_ADDITIONAL_TEXT(14, false); + REQUEST_ADDITIONAL_TEXT_FOR_DLC(phoneCall.GXTFile, 14); + + while (!HAS_ADDITIONAL_TEXT_LOADED(14)) + WAIT(0); + + if (_GET_NUMBER_OF_REFERENCES_OF_SCRIPT_WITH_NAME_HASH(GET_HASH_KEY("cellphone_flashhand")) == 0) + { + REQUEST_SCRIPT("cellphone_flashhand"); + while (!HAS_SCRIPT_LOADED("cellphone_flashhand")) + { + WAIT(0); + } + + START_NEW_SCRIPT("cellphone_flashhand", 1424); + SET_SCRIPT_AS_NO_LONGER_NEEDED("cellphone_flashhand"); + } + + cellphoneStateGlobal->state = 4; // Open Phone + + while (cellphoneStateGlobal->state < 6) + { + WAIT(0); + } + + cellphoneStateGlobal->state = 10; // Put into further state + + while (currentMode < 9) + { + WAIT(0); + UpdatePhone(phoneCall); + + auto curTick = GET_GAME_TIMER(); + + switch (currentMode) + { + case 0: // Start the phone ring and curse + { + PLAY_SOUND_FRONTEND(soundId, "PHONE_GENERIC_RING_01", "Phone_SoundSet_Default", true); + PLAY_PED_AMBIENT_SPEECH_NATIVE(playerPed, "GENERIC_FRIGHTENED_HIGH", "SPEECH_PARAMS_FORCE_SHOUTED", false); + + isDialing = true; + lastTick = GET_GAME_TIMER(); + currentMode++; + + break; + } + case 1: // Check if phone has ringed long enough or player had hit the Call Accept button + { + if ((curTick - lastTick >= 4000) + || (IS_CONTROL_JUST_PRESSED(2, 176) or IS_DISABLED_CONTROL_JUST_PRESSED(2, 176))) + { + PLAY_SOUND_FRONTEND(-1, "Menu_Accept", "Phone_SoundSet_Default", true); + STOP_SOUND(soundId); + + isDialing = false; + currentMode++; + } + break; + } + case 2: // Play gesture to put player phone to ear + { + TASK_USE_MOBILE_PHONE(playerPed, true, 1); + currentMode++; + break; + } + case 3: // Create conversation and say hello + { + if (IS_SCRIPTED_CONVERSATION_ONGOING() || IS_MOBILE_PHONE_CALL_ONGOING()) + { + STOP_SCRIPTED_CONVERSATION(false); + } + + CREATE_NEW_SCRIPTED_CONVERSATION(); + + ADD_PED_TO_CONVERSATION(0, 0, phoneCall.speakerName); + ADD_PED_TO_CONVERSATION(1, playerPed, ""); + + for (PhoneCallLine line : phoneCall.lines) + { + ADD_LINE_TO_CONVERSATION(0, line.lineGXT, line.subtitleGXT, 1, 0, false, false, true, true, 0, false, + false, false); + } + + PLAY_PED_AMBIENT_SPEECH_NATIVE(playerPed, "GENERIC_HI", "SPEECH_PARAMS_FORCE_SHOUTED", false); + currentMode++; + break; + } + case 4: // Wait for hello to finish & start convo + { + if (!IS_AMBIENT_SPEECH_PLAYING(playerPed)) + { + START_SCRIPT_PHONE_CONVERSATION(true, true); + currentMode++; + } + break; + } + case 5: // Loop while phone call is playing and do gesture logic + { + if (IS_MOBILE_PHONE_CALL_ONGOING()) + { + if (!IS_PED_RUNNING_MOBILE_PHONE_TASK(playerPed)) + { + TASK_USE_MOBILE_PHONE(playerPed, true, 1); + } + } + else + { + PLAY_PED_AMBIENT_SPEECH_NATIVE(playerPed, "GENERIC_BYE", "SPEECH_PARAMS_FORCE_SHOUTED", false); + currentMode++; + } + break; + } + case 6: // Wait for goodbye to finish + { + if (!IS_AMBIENT_SPEECH_PLAYING(playerPed)) + { + currentMode++; + } + break; + } + case 7: // Hang Up Phone + { + TASK_USE_MOBILE_PHONE(playerPed, true, 2); + PLAY_SOUND_FRONTEND(-1, "Hang_Up", "Phone_SoundSet_Michael", true); + + lockCellphone = false; + cellphoneStateGlobal->state = 3; + currentMode++; + + lastTick = GET_GAME_TIMER(); + + break; + } + case 8: // Say insult + { + if (curTick - lastTick > 800) + { + lastTick = curTick; + PLAY_PED_AMBIENT_SPEECH_NATIVE(playerPed, phoneCall.ambientLine, "SPEECH_PARAMS_FORCE_SHOUTED", false); + currentMode++; + } + break; + } + } + } + + REQUEST_SCRIPT("cellphone_controller"); + + while (!HAS_SCRIPT_LOADED("cellphone_controller")) + { + WAIT(0); + } + + START_NEW_SCRIPT("cellphone_controller", 1424); + + SET_SCRIPT_AS_NO_LONGER_NEEDED("cellphone_controller"); + + RELEASE_SOUND_ID(soundId); + SET_SCALEFORM_MOVIE_AS_NO_LONGER_NEEDED(&phoneScaleform); + + *lockCellphoneGlobal = 0; +} + +static void OnStartAgatha() +{ + PhoneCall phoneCall = { "CELL_CAS_MAN_N", + "CHAR_CASINO_MANAGER", + "CAS_AGATHA", + "CAGTAU", + "GENERIC_INSULT_FEMALE", + { + { "CAGT_HAAA", "CAGT_M1_UC1_1" }, + { "CAGT_HAAB", "CAGT_M1_UC1_3" }, + { "CAGT_HAAC", "CAGT_M1_UC1_5" }, + { "CAGT_HAAD", "CAGT_M1_UC1_7" }, + { "CAGT_HAAE", "CAGT_M1_UC1_9" }, + { "CAGT_HAAF", "CAGT_M1_UC1_10" }, + { "CAGT_HAAG", "CAGT_M1_UC1_11" }, + { "CAGT_HAAH", "CAGT_M1_UC1_12" }, + { "CAGT_HAAI", "CAGT_M1_UC1_14" }, + } }; + PlayPhoneCall(phoneCall); +} + +static void OnStartDave() +{ + int random = g_Random.GetRandomInt(1, 2); + + PhoneCall phoneCall = { "CELL_NCLUBE_N", + "CHAR_ENGLISH_DAVE", + "BTL_DAVE", + "HS4EDAU", + "GENERIC_INSULT_MALE", + { { "HS4ED_AAAA", "HS4ED_POC1_1" }, + { "HS4ED_AAAB", "HS4ED_POC1_3" }, + { "HS4ED_AAAC", "HS4ED_POC1_5" }, + { "HS4ED_AAAD", "HS4ED_POC1_7" }, + { (random == 1 ? "HS4ED_ACAB" : "HS4ED_ABAB"), + (random == 1 ? "HS4ED_PDM1_3" : "HS4ED_PAM1_3") } } }; + PlayPhoneCall(phoneCall); +} + +// clang-format off +REGISTER_EFFECT(OnStartAgatha, nullptr, nullptr, EffectInfo + { + .Name = "Hello, this is Agatha", + .Id = "misc_phonecall_agatha", + .IncompatibleWith = { "player_nophone", "player_phonecall_dave" }, + } +); + +REGISTER_EFFECT(OnStartDave, nullptr, nullptr, EffectInfo + { + .Name = "Dave Here", + .Id = "misc_phonecall_dave", + .IncompatibleWith = { "player_nophone", "player_phonecall_agatha" }, + } +); diff --git a/ChaosMod/Main.cpp b/ChaosMod/Main.cpp index b1cc94c37..4a074e80b 100644 --- a/ChaosMod/Main.cpp +++ b/ChaosMod/Main.cpp @@ -14,6 +14,7 @@ #include "Components/EffectDispatcher.h" #include "Components/EffectShortcuts.h" #include "Components/Failsafe.h" +#include "Components/Globals.h" #include "Components/HelpTextQueue.h" #include "Components/KeyStates.h" #include "Components/LuaScripts.h" @@ -210,6 +211,8 @@ static void Init() INIT_COMPONENT("Failsafe", "Failsafe", Failsafe); + INIT_COMPONENT("Globals", "Script Globals", Globals); + INIT_COMPONENT("HelpTextQueue", "script help text queue", HelpTextQueue); #ifdef WITH_DEBUG_PANEL_SUPPORT diff --git a/ConfigApp/Effects.cs b/ConfigApp/Effects.cs index 0b7932a96..867b08614 100644 --- a/ConfigApp/Effects.cs +++ b/ConfigApp/Effects.cs @@ -402,6 +402,8 @@ public enum EffectTimedType { "misc_fakeuturn", new EffectInfo("Fake U-Turn", EffectCategory.Misc) }, { "misc_esp", new EffectInfo("ESP", EffectCategory.Misc, true) }, { "screen_bouncyradar", new EffectInfo("Bouncy Radar", EffectCategory.Screen, true) }, + { "misc_phonecall_agatha", new EffectInfo("Hello, this is Agatha", EffectCategory.Misc) }, + { "misc_phonecall_dave", new EffectInfo("Dave Here", EffectCategory.Misc) }, }; } } From a5d0edc62aeb5693ec5858cbf5f715835b2b5f88 Mon Sep 17 00:00:00 2001 From: Rylxnd Date: Sat, 19 Aug 2023 14:44:32 -0400 Subject: [PATCH 02/12] Fix crash ;) --- ChaosMod/Effects/db/Misc/MiscPhoneCall.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ChaosMod/Effects/db/Misc/MiscPhoneCall.cpp b/ChaosMod/Effects/db/Misc/MiscPhoneCall.cpp index 610ecda3f..9b7c2ebea 100644 --- a/ChaosMod/Effects/db/Misc/MiscPhoneCall.cpp +++ b/ChaosMod/Effects/db/Misc/MiscPhoneCall.cpp @@ -328,7 +328,7 @@ REGISTER_EFFECT(OnStartAgatha, nullptr, nullptr, EffectInfo { .Name = "Hello, this is Agatha", .Id = "misc_phonecall_agatha", - .IncompatibleWith = { "player_nophone", "player_phonecall_dave" }, + .IncompatibleWith = { "player_nophone", "misc_phonecall_dave" }, } ); @@ -336,6 +336,6 @@ REGISTER_EFFECT(OnStartDave, nullptr, nullptr, EffectInfo { .Name = "Dave Here", .Id = "misc_phonecall_dave", - .IncompatibleWith = { "player_nophone", "player_phonecall_agatha" }, + .IncompatibleWith = { "player_nophone", "misc_phonecall_agatha" }, } ); From 0afcb84ff6376a47de1ca6f0c2ddefc4530bc060 Mon Sep 17 00:00:00 2001 From: Ryland <91900600+Rylxnd@users.noreply.github.com> Date: Sun, 20 Aug 2023 10:06:52 -0400 Subject: [PATCH 03/12] Update ChaosMod/Effects/db/Misc/MiscPhoneCall.cpp Co-authored-by: pongo1231 --- ChaosMod/Effects/db/Misc/MiscPhoneCall.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChaosMod/Effects/db/Misc/MiscPhoneCall.cpp b/ChaosMod/Effects/db/Misc/MiscPhoneCall.cpp index 9b7c2ebea..edbb9ac58 100644 --- a/ChaosMod/Effects/db/Misc/MiscPhoneCall.cpp +++ b/ChaosMod/Effects/db/Misc/MiscPhoneCall.cpp @@ -118,7 +118,9 @@ static void PlayPhoneCall(PhoneCall &phoneCall) phoneScaleform = REQUEST_SCALEFORM_MOVIE(phoneScaleforms.at(GET_ENTITY_MODEL(playerPed))); while (!HAS_SCALEFORM_MOVIE_LOADED(phoneScaleform)) + { WAIT(0); + } CLEAR_ADDITIONAL_TEXT(14, false); REQUEST_ADDITIONAL_TEXT_FOR_DLC(phoneCall.GXTFile, 14); From 171f01117bfb252c0e2882136668efdbc058ef0a Mon Sep 17 00:00:00 2001 From: Ryland <91900600+Rylxnd@users.noreply.github.com> Date: Sun, 20 Aug 2023 10:06:57 -0400 Subject: [PATCH 04/12] Update ChaosMod/Effects/db/Misc/MiscPhoneCall.cpp Co-authored-by: pongo1231 --- ChaosMod/Effects/db/Misc/MiscPhoneCall.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChaosMod/Effects/db/Misc/MiscPhoneCall.cpp b/ChaosMod/Effects/db/Misc/MiscPhoneCall.cpp index edbb9ac58..2cb02b5ed 100644 --- a/ChaosMod/Effects/db/Misc/MiscPhoneCall.cpp +++ b/ChaosMod/Effects/db/Misc/MiscPhoneCall.cpp @@ -126,7 +126,9 @@ static void PlayPhoneCall(PhoneCall &phoneCall) REQUEST_ADDITIONAL_TEXT_FOR_DLC(phoneCall.GXTFile, 14); while (!HAS_ADDITIONAL_TEXT_LOADED(14)) + { WAIT(0); + } if (_GET_NUMBER_OF_REFERENCES_OF_SCRIPT_WITH_NAME_HASH(GET_HASH_KEY("cellphone_flashhand")) == 0) { From f91ff87f6cf3b0ca1daa433774ecd4c7a8234e73 Mon Sep 17 00:00:00 2001 From: Ryland <91900600+Rylxnd@users.noreply.github.com> Date: Sun, 20 Aug 2023 10:07:33 -0400 Subject: [PATCH 05/12] Update ChaosMod/Components/Globals.h Co-authored-by: pongo1231 --- ChaosMod/Components/Globals.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChaosMod/Components/Globals.h b/ChaosMod/Components/Globals.h index 59e5e2b81..027e376e8 100644 --- a/ChaosMod/Components/Globals.h +++ b/ChaosMod/Components/Globals.h @@ -32,7 +32,7 @@ struct GlobalRegistration class Globals : public Component { private: - static std::map m_GlobalsIndexMap; + static inline std::map m_GlobalsIndexMap; CHAOS_EVENT_LISTENER(Hooks::OnScriptThreadRun) m_SearchGlobalsListener; From cb3e4ef15372a0522edbf940a581c40df6c660d9 Mon Sep 17 00:00:00 2001 From: Rylxnd Date: Sun, 20 Aug 2023 13:23:38 -0400 Subject: [PATCH 06/12] Requested Changes --- ChaosMod/Components/Globals.cpp | 36 ++++++++++++---------- ChaosMod/Components/Globals.h | 14 +++++++-- ChaosMod/Effects/db/Misc/MiscPhoneCall.cpp | 19 +++++++++--- 3 files changed, 46 insertions(+), 23 deletions(-) diff --git a/ChaosMod/Components/Globals.cpp b/ChaosMod/Components/Globals.cpp index bb6bc3585..1b7d039a1 100644 --- a/ChaosMod/Components/Globals.cpp +++ b/ChaosMod/Components/Globals.cpp @@ -6,30 +6,18 @@ #include "Memory/Script.h" -std::map Globals::m_GlobalsIndexMap = {}; -static std::vector m_GlobalsRegistration = {}; +std::vector m_GlobalsRegistration = {}; Globals::Globals() : Component() { - REGISTER_GLOBAL("CellPhoneState", "dialogue_handler", - "2D 00 02 00 ? 52 ? ? 41 ? 72 08 2A 06 56 ? ? 52 ? ? 41 ? 71 08 20 56 ? ? 72", 6, - GlobalPatternIdiom::GLOBAL_U16); - - REGISTER_GLOBAL("CellPhoneLock", "dialogue_handler", - "72 54 ? ? 5d ? ? ? 71 2c ? ? ? 2b 72 54 ? ? 77 54 ? ? 52 ? ? 25 ? 2c ? ? ? 53 ? ? 06 56 ? ? 52 ? ? 76", 2, - GlobalPatternIdiom::GLOBAL_U16); - - m_SearchGlobalsListener.Register( Hooks::OnScriptThreadRun, [&](rage::scrThread *thread) { - // Save a f**k-tonne of CPU resources by destructing the event listener when we no longer have anymore globals to find - if (m_GlobalsRegistration.size() <= 0) - { - m_SearchGlobalsListener.~ChaosEventListener(); + if (m_GlobalsRegistration.size() <= 0) + { return true; - } + } auto match = std::find_if(m_GlobalsRegistration.begin(), m_GlobalsRegistration.end(), @@ -40,7 +28,7 @@ Globals::Globals() : Component() GlobalRegistration searchedGlobal = *match; - auto program = Memory::ScriptThreadToProgram(thread); + auto program = Memory::ScriptThreadToProgram(thread); if (program->m_CodeBlocks) { Handle handle = Memory::FindScriptPattern(searchedGlobal.m_Pattern, program); @@ -68,4 +56,18 @@ Globals::Globals() : Component() return true; }); +} + +void Globals::RegisterGlobal(std::string name, std::string scriptName, std::string pattern, int patternOffset, + GlobalPatternIdiom patternIdiom) +{ + if (std::find_if(m_GlobalsRegistration.begin(), m_GlobalsRegistration.end(), + [&](GlobalRegistration ®) { return reg.m_Name == name; }) + != m_GlobalsRegistration.end() + || Globals::GetGlobalAddr(name) != nullptr) + { + return; + } + + m_GlobalsRegistration.push_back({ name, scriptName, pattern, patternOffset, patternIdiom }); } \ No newline at end of file diff --git a/ChaosMod/Components/Globals.h b/ChaosMod/Components/Globals.h index 027e376e8..d0dc4a442 100644 --- a/ChaosMod/Components/Globals.h +++ b/ChaosMod/Components/Globals.h @@ -32,7 +32,7 @@ struct GlobalRegistration class Globals : public Component { private: - static inline std::map m_GlobalsIndexMap; + static inline std::map m_GlobalsIndexMap = {}; CHAOS_EVENT_LISTENER(Hooks::OnScriptThreadRun) m_SearchGlobalsListener; @@ -40,6 +40,8 @@ class Globals : public Component Globals(); public: + static inline std::vector m_GlobalsRegistration; + static void SetGlobalIndex(std::string name, int index) { m_GlobalsIndexMap.emplace(name, index); @@ -57,10 +59,18 @@ class Globals : public Component return reinterpret_cast(Memory::GetGlobalPtr(it)); } + static bool GlobalExists(std::string name) + { + return m_GlobalsIndexMap.contains(name); + } + + static void RegisterGlobal(std::string name, std::string scriptName, std::string pattern, int patternOffset, + GlobalPatternIdiom patternIdiom); + template requires std::is_base_of_v friend struct ComponentHolder; }; #define REGISTER_GLOBAL(name, scriptName, pattern, patternOffset, patternIdiom) \ - m_GlobalsRegistration.push_back({ name, scriptName, pattern, patternOffset, patternIdiom }) \ No newline at end of file + Globals::RegisterGlobal(name, scriptName, pattern, patternOffset, patternIdiom); \ No newline at end of file diff --git a/ChaosMod/Effects/db/Misc/MiscPhoneCall.cpp b/ChaosMod/Effects/db/Misc/MiscPhoneCall.cpp index 2cb02b5ed..fb3d7ac49 100644 --- a/ChaosMod/Effects/db/Misc/MiscPhoneCall.cpp +++ b/ChaosMod/Effects/db/Misc/MiscPhoneCall.cpp @@ -102,12 +102,23 @@ static void UpdatePhone(PhoneCall &phoneCall) static void PlayPhoneCall(PhoneCall &phoneCall) { + REGISTER_GLOBAL("CellPhoneState", "dialogue_handler", + "2D 00 02 00 ? 52 ? ? 41 ? 72 08 2A 06 56 ? ? 52 ? ? 41 ? 71 08 20 56 ? ? 72", 6, + GlobalPatternIdiom::GLOBAL_U16); + + REGISTER_GLOBAL( + "CellPhoneLock", "dialogue_handler", + "72 54 ? ? 5D ? ? ? 71 2C ? ? ? 2B 72 54 ? ? 77 54 ? ? 52 ? ? 25 ? 2C ? ? ? 53 ? ? 06 56 ? ? 52 ? ? 76", 2, + GlobalPatternIdiom::GLOBAL_U16); + + while (!Globals::GlobalExists("CellPhoneState") || !Globals::GlobalExists("CellPhoneLock")) + { + WAIT(0); + } + lockCellphoneGlobal = Globals::GetGlobalAddr("CellPhoneLock"); cellphoneStateGlobal = Globals::GetGlobalAddr("CellPhoneState"); - if (cellphoneStateGlobal == nullptr || lockCellphoneGlobal == nullptr) - return; - *lockCellphoneGlobal = 0; currentMode = 0; @@ -342,4 +353,4 @@ REGISTER_EFFECT(OnStartDave, nullptr, nullptr, EffectInfo .Id = "misc_phonecall_dave", .IncompatibleWith = { "player_nophone", "misc_phonecall_agatha" }, } -); +); \ No newline at end of file From 559b78de75928f3d4ca8ed1be5bfd7943862c2ed Mon Sep 17 00:00:00 2001 From: Ryland <91900600+Rylxnd@users.noreply.github.com> Date: Sat, 26 Aug 2023 17:25:54 -0400 Subject: [PATCH 07/12] Update ChaosMod/Components/Globals.h Co-authored-by: pongo1231 --- ChaosMod/Components/Globals.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChaosMod/Components/Globals.h b/ChaosMod/Components/Globals.h index d0dc4a442..c3f76c603 100644 --- a/ChaosMod/Components/Globals.h +++ b/ChaosMod/Components/Globals.h @@ -32,7 +32,7 @@ struct GlobalRegistration class Globals : public Component { private: - static inline std::map m_GlobalsIndexMap = {}; + static inline std::map ms_GlobalsIndexMap = {}; CHAOS_EVENT_LISTENER(Hooks::OnScriptThreadRun) m_SearchGlobalsListener; From 68e5a4dacf0639d9dd23c73003033bfc6f057f91 Mon Sep 17 00:00:00 2001 From: Ryland <91900600+Rylxnd@users.noreply.github.com> Date: Sat, 26 Aug 2023 17:26:15 -0400 Subject: [PATCH 08/12] Update ChaosMod/Components/Globals.h Co-authored-by: pongo1231 --- ChaosMod/Components/Globals.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChaosMod/Components/Globals.h b/ChaosMod/Components/Globals.h index c3f76c603..5cd10bd86 100644 --- a/ChaosMod/Components/Globals.h +++ b/ChaosMod/Components/Globals.h @@ -7,7 +7,7 @@ #include #include -enum GlobalPatternIdiom : uint8_t +enum class GlobalPatternIdiom : uint8_t { GLOBAL_U16, GLOBAL_U24 From 61101d738b7edf94f926f54148c2644286e5e552 Mon Sep 17 00:00:00 2001 From: Ryland <91900600+Rylxnd@users.noreply.github.com> Date: Sat, 26 Aug 2023 17:26:25 -0400 Subject: [PATCH 09/12] Update ChaosMod/Effects/db/Misc/MiscPhoneCall.cpp Co-authored-by: pongo1231 --- ChaosMod/Effects/db/Misc/MiscPhoneCall.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ChaosMod/Effects/db/Misc/MiscPhoneCall.cpp b/ChaosMod/Effects/db/Misc/MiscPhoneCall.cpp index fb3d7ac49..c3e247c8d 100644 --- a/ChaosMod/Effects/db/Misc/MiscPhoneCall.cpp +++ b/ChaosMod/Effects/db/Misc/MiscPhoneCall.cpp @@ -42,7 +42,7 @@ static int soundId = 0; static bool isDialing = true; static bool lockCellphone = true; -std::unordered_map phoneScaleforms = { { 0xD7114C9, "cellphone_ifruit" }, +static std::unordered_map phoneScaleforms = { { 0xD7114C9, "cellphone_ifruit" }, { 0x9B22DBAF, "cellphone_badger" }, { 0x9B810FA2, "cellphone_facade" } }; From 7d9b6b50bb0bd6f62e773122a40ae4247d23be0b Mon Sep 17 00:00:00 2001 From: Ryland <91900600+Rylxnd@users.noreply.github.com> Date: Sat, 26 Aug 2023 17:27:24 -0400 Subject: [PATCH 10/12] Update ChaosMod/Components/Globals.cpp Co-authored-by: pongo1231 --- ChaosMod/Components/Globals.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/ChaosMod/Components/Globals.cpp b/ChaosMod/Components/Globals.cpp index 1b7d039a1..624e9978e 100644 --- a/ChaosMod/Components/Globals.cpp +++ b/ChaosMod/Components/Globals.cpp @@ -42,9 +42,13 @@ Globals::Globals() : Component() int globalIndex; if (searchedGlobal.m_PatternIdiom == GlobalPatternIdiom::GLOBAL_U16) + { globalIndex = handle.At(searchedGlobal.m_Offset).Value() & 0xFFFFFF; + } else + { globalIndex = handle.At(searchedGlobal.m_Offset).Value() & 0xFFFFFF; + } Globals::SetGlobalIndex(searchedGlobal.m_Name, globalIndex); From 3ade5e87bad51596439001e0fe440d9fd52f5af3 Mon Sep 17 00:00:00 2001 From: Ryland <91900600+Rylxnd@users.noreply.github.com> Date: Sat, 26 Aug 2023 17:27:35 -0400 Subject: [PATCH 11/12] Update ChaosMod/Components/Globals.cpp Co-authored-by: pongo1231 --- ChaosMod/Components/Globals.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ChaosMod/Components/Globals.cpp b/ChaosMod/Components/Globals.cpp index 624e9978e..9bac038ec 100644 --- a/ChaosMod/Components/Globals.cpp +++ b/ChaosMod/Components/Globals.cpp @@ -24,7 +24,9 @@ Globals::Globals() : Component() [&thread](GlobalRegistration ®) { return reg.m_ScriptName == thread->GetName(); }); if (match == m_GlobalsRegistration.end()) + { return true; + } GlobalRegistration searchedGlobal = *match; From 6ba9b0e1cd2703304da500d4b900a0bdbefdd4a5 Mon Sep 17 00:00:00 2001 From: Rylxnd Date: Mon, 28 Aug 2023 10:13:58 -0400 Subject: [PATCH 12/12] Use handles --- ChaosMod/Components/Globals.cpp | 37 ++++++---- ChaosMod/Components/Globals.h | 83 ++++++++++++++-------- ChaosMod/Effects/db/Misc/MiscPhoneCall.cpp | 56 +++++++++------ 3 files changed, 111 insertions(+), 65 deletions(-) diff --git a/ChaosMod/Components/Globals.cpp b/ChaosMod/Components/Globals.cpp index 9bac038ec..ff5170268 100644 --- a/ChaosMod/Components/Globals.cpp +++ b/ChaosMod/Components/Globals.cpp @@ -6,7 +6,7 @@ #include "Memory/Script.h" -std::vector m_GlobalsRegistration = {}; +std::vector ms_GlobalsRegistration = {}; Globals::Globals() : Component() { @@ -14,16 +14,16 @@ Globals::Globals() : Component() Hooks::OnScriptThreadRun, [&](rage::scrThread *thread) { - if (m_GlobalsRegistration.size() <= 0) + if (ms_GlobalsRegistration.size() <= 0) { return true; } auto match = - std::find_if(m_GlobalsRegistration.begin(), m_GlobalsRegistration.end(), + std::find_if(ms_GlobalsRegistration.begin(), ms_GlobalsRegistration.end(), [&thread](GlobalRegistration ®) { return reg.m_ScriptName == thread->GetName(); }); - if (match == m_GlobalsRegistration.end()) + if (match == ms_GlobalsRegistration.end()) { return true; } @@ -52,28 +52,39 @@ Globals::Globals() : Component() globalIndex = handle.At(searchedGlobal.m_Offset).Value() & 0xFFFFFF; } - Globals::SetGlobalIndex(searchedGlobal.m_Name, globalIndex); + Globals::SetGlobal(searchedGlobal, globalIndex); LOG("Found global \"" << searchedGlobal.m_Name << "\" (Global: " << globalIndex << ")"); } } - m_GlobalsRegistration.erase(match); + ms_GlobalsRegistration.erase(match); return true; }); } -void Globals::RegisterGlobal(std::string name, std::string scriptName, std::string pattern, int patternOffset, - GlobalPatternIdiom patternIdiom) +bool Globals::Searching(int handle) { - if (std::find_if(m_GlobalsRegistration.begin(), m_GlobalsRegistration.end(), + return std::find_if(ms_GlobalsRegistration.begin(), ms_GlobalsRegistration.end(), + [&](GlobalRegistration ®) { return reg.m_Handle == handle; }) + != ms_GlobalsRegistration.end(); +} + +int Globals::RegisterGlobal(std::string name, std::string scriptName, std::string pattern, + int patternOffset, GlobalPatternIdiom patternIdiom) +{ + if (std::find_if(ms_GlobalsRegistration.begin(), ms_GlobalsRegistration.end(), [&](GlobalRegistration ®) { return reg.m_Name == name; }) - != m_GlobalsRegistration.end() - || Globals::GetGlobalAddr(name) != nullptr) + != ms_GlobalsRegistration.end() + || Globals::GlobalFoundName(name)) { - return; + return -1; } - m_GlobalsRegistration.push_back({ name, scriptName, pattern, patternOffset, patternIdiom }); + int handle = GetTickCount(); // Allows the handle to be truly unique + + ms_GlobalsRegistration.push_back({ name, scriptName, pattern, patternOffset, patternIdiom, handle }); + + return handle; } \ No newline at end of file diff --git a/ChaosMod/Components/Globals.h b/ChaosMod/Components/Globals.h index 5cd10bd86..177a43e37 100644 --- a/ChaosMod/Components/Globals.h +++ b/ChaosMod/Components/Globals.h @@ -13,64 +13,85 @@ enum class GlobalPatternIdiom : uint8_t GLOBAL_U24 }; -struct GlobalRegistration +class Globals : public Component { public: - std::string m_Name; - std::string m_ScriptName; - std::string m_Pattern; - int m_Offset; - GlobalPatternIdiom m_PatternIdiom; - - GlobalRegistration(std::string name, std::string scriptName, std::string pattern, int offset, - GlobalPatternIdiom patternIdiom) - : m_Name(name), m_ScriptName(scriptName), m_Pattern(pattern), m_Offset(offset), m_PatternIdiom(patternIdiom) + struct GlobalRegistration { - } -}; + public: + std::string m_Name; + std::string m_ScriptName; + std::string m_Pattern; + int m_Offset; + int m_Index = -1; + int m_Handle; + GlobalPatternIdiom m_PatternIdiom; + + GlobalRegistration(std::string name, std::string scriptName, std::string pattern, int offset, + GlobalPatternIdiom patternIdiom, int handle) + : m_Name(name), + m_ScriptName(scriptName), + m_Pattern(pattern), + m_Offset(offset), + m_PatternIdiom(patternIdiom), + m_Handle(handle) + { + } + }; -class Globals : public Component -{ private: - static inline std::map ms_GlobalsIndexMap = {}; + static inline std::vector ms_Globals = {}; CHAOS_EVENT_LISTENER(Hooks::OnScriptThreadRun) m_SearchGlobalsListener; + static bool GetGlobalWhere() + { + return false; + } + protected: Globals(); public: - static inline std::vector m_GlobalsRegistration; - - static void SetGlobalIndex(std::string name, int index) + static void SetGlobal(GlobalRegistration ®, int index) { - m_GlobalsIndexMap.emplace(name, index); + reg.m_Index = index; + ms_Globals.push_back(reg); } - template static T *GetGlobalAddr(std::string name) + template static T *GetGlobalAddr(int handle) { - if (!m_GlobalsIndexMap.contains(name)) + auto it = std::find_if(ms_Globals.begin(), ms_Globals.end(), + [&](GlobalRegistration ®) { return reg.m_Handle == handle; }); + + if (it == ms_Globals.end()) { return nullptr; } - auto it = m_GlobalsIndexMap.at(name); + return reinterpret_cast(Memory::GetGlobalPtr(it->m_Index)); + } - return reinterpret_cast(Memory::GetGlobalPtr(it)); + // used by RegisterGlobal to check if it wasn't already registered + static bool GlobalFoundName(std::string name) + { + return std::find_if(ms_Globals.begin(), ms_Globals.end(), + [&](GlobalRegistration ®) { return reg.m_Name == name; }) + != ms_Globals.end(); } - static bool GlobalExists(std::string name) + static bool GlobalFound(int handle) { - return m_GlobalsIndexMap.contains(name); + return std::find_if(ms_Globals.begin(), ms_Globals.end(), + [&](GlobalRegistration ®) { return reg.m_Handle == handle; }) + != ms_Globals.end(); } - static void RegisterGlobal(std::string name, std::string scriptName, std::string pattern, int patternOffset, - GlobalPatternIdiom patternIdiom); + static bool Searching(int handle); + static int RegisterGlobal(std::string name, std::string scriptName, std::string pattern, int patternOffset, + GlobalPatternIdiom patternIdiom); template requires std::is_base_of_v friend struct ComponentHolder; -}; - -#define REGISTER_GLOBAL(name, scriptName, pattern, patternOffset, patternIdiom) \ - Globals::RegisterGlobal(name, scriptName, pattern, patternOffset, patternIdiom); \ No newline at end of file +}; \ No newline at end of file diff --git a/ChaosMod/Effects/db/Misc/MiscPhoneCall.cpp b/ChaosMod/Effects/db/Misc/MiscPhoneCall.cpp index c3e247c8d..bc21fe94c 100644 --- a/ChaosMod/Effects/db/Misc/MiscPhoneCall.cpp +++ b/ChaosMod/Effects/db/Misc/MiscPhoneCall.cpp @@ -31,20 +31,23 @@ struct CellPhone alignas(8) uint32_t state; }; +static int lockCellPhoneGlobalHandle = -1; +static int cellphoneStateGlobalHandle = -1; + static uint8_t *lockCellphoneGlobal; static CellPhone *cellphoneStateGlobal; -static int phoneScaleform = 0; -static int currentMode = 0; -static int lastTick = 0; -static int soundId = 0; +static int phoneScaleform = 0; +static int currentMode = 0; +static int lastTick = 0; +static int soundId = 0; -static bool isDialing = true; -static bool lockCellphone = true; +static bool isDialing = true; +static bool lockCellphone = true; static std::unordered_map phoneScaleforms = { { 0xD7114C9, "cellphone_ifruit" }, - { 0x9B22DBAF, "cellphone_badger" }, - { 0x9B810FA2, "cellphone_facade" } }; + { 0x9B22DBAF, "cellphone_badger" }, + { 0x9B810FA2, "cellphone_facade" } }; static void DrawPhone(PhoneCall &phoneCall) { @@ -96,33 +99,42 @@ static void DrawPhone(PhoneCall &phoneCall) static void UpdatePhone(PhoneCall &phoneCall) { DrawPhone(phoneCall); - *lockCellphoneGlobal = (uint8_t)lockCellphone; // disables phone inputs + *lockCellphoneGlobal = lockCellphone; // disables phone inputs TERMINATE_ALL_SCRIPTS_WITH_THIS_NAME("cellphone_controller"); } static void PlayPhoneCall(PhoneCall &phoneCall) { - REGISTER_GLOBAL("CellPhoneState", "dialogue_handler", - "2D 00 02 00 ? 52 ? ? 41 ? 72 08 2A 06 56 ? ? 52 ? ? 41 ? 71 08 20 56 ? ? 72", 6, - GlobalPatternIdiom::GLOBAL_U16); + if (cellphoneStateGlobalHandle < 0) + { + cellphoneStateGlobalHandle = + Globals::RegisterGlobal("CellPhoneState", "dialogue_handler", + "2D 00 02 00 ? 52 ? ? 41 ? 72 08 2A 06 56 ? ? 52 ? ? 41 ? 71 08 20 56 ? ? 72", 6, + GlobalPatternIdiom::GLOBAL_U16); + } - REGISTER_GLOBAL( - "CellPhoneLock", "dialogue_handler", - "72 54 ? ? 5D ? ? ? 71 2C ? ? ? 2B 72 54 ? ? 77 54 ? ? 52 ? ? 25 ? 2C ? ? ? 53 ? ? 06 56 ? ? 52 ? ? 76", 2, - GlobalPatternIdiom::GLOBAL_U16); + if (lockCellPhoneGlobalHandle < 0) + { + lockCellPhoneGlobalHandle = Globals::RegisterGlobal( + "CellPhoneLock", "dialogue_handler", + "72 54 ? ? 5D ? ? ? 71 2C ? ? ? 2B 72 54 ? ? 77 54 ? ? 52 ? ? 25 ? 2C ? ? ? 53 ? ? 06 56 ? ? 52 ? ? 76", 2, + GlobalPatternIdiom::GLOBAL_U16); + } - while (!Globals::GlobalExists("CellPhoneState") || !Globals::GlobalExists("CellPhoneLock")) + while (Globals::Searching(cellphoneStateGlobalHandle) || Globals::Searching(lockCellPhoneGlobalHandle)) { WAIT(0); } - lockCellphoneGlobal = Globals::GetGlobalAddr("CellPhoneLock"); - cellphoneStateGlobal = Globals::GetGlobalAddr("CellPhoneState"); + if (cellphoneStateGlobalHandle < 0 || lockCellPhoneGlobalHandle < 0) + { + return; + } - *lockCellphoneGlobal = 0; + cellphoneStateGlobal = Globals::GetGlobalAddr(cellphoneStateGlobalHandle); + lockCellphoneGlobal = Globals::GetGlobalAddr(lockCellPhoneGlobalHandle); currentMode = 0; - lockCellphone = true; Ped playerPed = PLAYER_PED_ID(); soundId = GET_SOUND_ID(); @@ -162,6 +174,8 @@ static void PlayPhoneCall(PhoneCall &phoneCall) cellphoneStateGlobal->state = 10; // Put into further state + lockCellphone = true; + while (currentMode < 9) { WAIT(0);