diff --git a/src/Components/Modules/Bots.cpp b/src/Components/Modules/Bots.cpp index d3837959..27c44409 100644 --- a/src/Components/Modules/Bots.cpp +++ b/src/Components/Modules/Bots.cpp @@ -110,7 +110,7 @@ namespace Components void Bots::AddMethods() { - Script::AddFunction("SetPing", [](Game::scr_entref_t entref) // gsc: self SetPing() + Script::AddMethod("SetPing", [](Game::scr_entref_t entref) // gsc: self SetPing() { auto ping = Game::Scr_GetInt(0); @@ -128,7 +128,7 @@ namespace Components client->ping = static_cast(ping); }); - Script::AddFunction("IsTestClient", [](Game::scr_entref_t entref) // Usage: IsTestClient(); + Script::AddMethod("IsTestClient", [](Game::scr_entref_t entref) // Usage: IsTestClient(); { const auto* gentity = Game::GetPlayerEntity(entref); const auto* client = Script::GetClient(gentity); @@ -136,7 +136,7 @@ namespace Components Game::Scr_AddBool(client->bIsTestClient == 1); }); - Script::AddFunction("BotStop", [](Game::scr_entref_t entref) // Usage: BotStop(); + Script::AddMethod("BotStop", [](Game::scr_entref_t entref) // Usage: BotStop(); { const auto* ent = Game::GetPlayerEntity(entref); const auto* client = Script::GetClient(ent); @@ -152,7 +152,7 @@ namespace Components g_botai[entref.entnum].active = false; }); - Script::AddFunction("BotWeapon", [](Game::scr_entref_t entref) // Usage: BotWeapon(); + Script::AddMethod("BotWeapon", [](Game::scr_entref_t entref) // Usage: BotWeapon(); { const auto* weapon = Game::Scr_GetString(0); @@ -176,7 +176,7 @@ namespace Components g_botai[entref.entnum].active = true; }); - Script::AddFunction("BotAction", [](Game::scr_entref_t entref) // Usage: BotAction(); + Script::AddMethod("BotAction", [](Game::scr_entref_t entref) // Usage: BotAction(); { const auto* action = Game::Scr_GetString(0); @@ -218,7 +218,7 @@ namespace Components Game::Scr_ParamError(0, "^1BotAction: Unknown action.\n"); }); - Script::AddFunction("BotMovement", [](Game::scr_entref_t entref) // Usage: BotMovement(, ); + Script::AddMethod("BotMovement", [](Game::scr_entref_t entref) // Usage: BotMovement(, ); { auto forwardInt = Game::Scr_GetInt(0); auto rightInt = Game::Scr_GetInt(1); diff --git a/src/Components/Modules/ClientCommand.cpp b/src/Components/Modules/ClientCommand.cpp index f9554c2e..45a696e3 100644 --- a/src/Components/Modules/ClientCommand.cpp +++ b/src/Components/Modules/ClientCommand.cpp @@ -176,7 +176,7 @@ namespace Components void ClientCommand::AddScriptFunctions() { - Script::AddFunction("Noclip", [](Game::scr_entref_t entref) // gsc: Noclip(); + Script::AddMethod("Noclip", [](Game::scr_entref_t entref) // gsc: Noclip(); { const auto* ent = Game::GetPlayerEntity(entref); @@ -197,7 +197,7 @@ namespace Components } }); - Script::AddFunction("Ufo", [](Game::scr_entref_t entref) // gsc: Ufo(); + Script::AddMethod("Ufo", [](Game::scr_entref_t entref) // gsc: Ufo(); { const auto* ent = Game::GetPlayerEntity(entref); @@ -218,7 +218,7 @@ namespace Components } }); - Script::AddFunction("God", [](Game::scr_entref_t entref) // gsc: God(); + Script::AddMethod("God", [](Game::scr_entref_t entref) // gsc: God(); { auto* ent = Game::GetEntity(entref); @@ -239,7 +239,7 @@ namespace Components } }); - Script::AddFunction("Demigod", [](Game::scr_entref_t entref) // gsc: Demigod(); + Script::AddMethod("Demigod", [](Game::scr_entref_t entref) // gsc: Demigod(); { auto* ent = Game::GetEntity(entref); @@ -260,7 +260,7 @@ namespace Components } }); - Script::AddFunction("Notarget", [](Game::scr_entref_t entref) // gsc: Notarget(); + Script::AddMethod("Notarget", [](Game::scr_entref_t entref) // gsc: Notarget(); { auto* ent = Game::GetEntity(entref); diff --git a/src/Components/Modules/Download.cpp b/src/Components/Modules/Download.cpp index d2644013..39529219 100644 --- a/src/Components/Modules/Download.cpp +++ b/src/Components/Modules/Download.cpp @@ -964,7 +964,7 @@ namespace Components Download::ScriptDownloads.clear(); }); - Script::AddFunction("HttpGet", [](Game::scr_entref_t) + Script::AddFunction("HttpGet", []() { if (!Flags::HasFlag("scriptablehttp")) return; @@ -985,7 +985,7 @@ namespace Components Game::RemoveRefToObject(object); }); - Script::AddFunction("HttpCancel", [](Game::scr_entref_t) + Script::AddFunction("HttpCancel", []() { if (!Flags::HasFlag("scriptablehttp")) return; diff --git a/src/Components/Modules/Script.cpp b/src/Components/Modules/Script.cpp index d7527456..6aa19501 100644 --- a/src/Components/Modules/Script.cpp +++ b/src/Components/Modules/Script.cpp @@ -4,7 +4,8 @@ namespace Components { std::string Script::ScriptName; std::vector Script::ScriptHandles; - std::vector Script::ScriptFunctions; + std::unordered_map Script::CustomScrFunctions; + std::unordered_map Script::CustomScrMethods; std::vector Script::ScriptNameStack; unsigned short Script::FunctionName; std::unordered_map Script::ScriptStorage; @@ -139,11 +140,9 @@ namespace Components std::string buffer = script.getBuffer(); Utils::String::Replace(buffer, "\t", " "); - int line = 1; - int lineOffset = 0; - int inlineOffset = 0; + auto line = 1, lineOffset = 0, inlineOffset = 0; - for (unsigned int i = 0; i < buffer.size(); ++i) + for (size_t i = 0; i < buffer.size(); ++i) { // Terminate line if (i == offset) @@ -160,7 +159,7 @@ namespace Components if (buffer[i] == '\n') { ++line; - lineOffset = i; // Includes the line break! + lineOffset = static_cast(i); // Includes the line break! inlineOffset = 0; } else @@ -172,7 +171,7 @@ namespace Components Logger::Print(23, "in file %s, line %d:", filename, line); Logger::Print(23, "%s\n", buffer.data() + lineOffset); - for (int i = 0; i < (inlineOffset - 1); ++i) + for (auto i = 0; i < (inlineOffset - 1); ++i) { Logger::Print(23, " "); } @@ -248,7 +247,7 @@ namespace Components for (auto file : list) { - file = "scripts/" + file; + file.insert(0, "scripts/"); if (Utils::String::EndsWith(file, ".gsc")) { @@ -271,61 +270,72 @@ namespace Components Game::GScr_LoadGameTypeScript(); } - void Script::AddFunction(const std::string& name, Game::scr_function_t function, bool isDev) + void Script::AddFunction(const char* name, Game::xfunction_t func, int type) { - for (auto i = Script::ScriptFunctions.begin(); i != Script::ScriptFunctions.end();) - { - if (i->getName() == name) - { - i = Script::ScriptFunctions.erase(i); - continue; - } + Game::BuiltinFunctionDef toAdd; + toAdd.actionString = name; + toAdd.actionFunc = func; + toAdd.type = type; - ++i; - } - - Script::ScriptFunctions.push_back({ name, function, isDev }); + CustomScrFunctions.insert_or_assign(Utils::String::ToLower(name), std::move(toAdd)); } - Game::scr_function_t Script::GetFunction(void* caller, const char** name, int* isDev) + void Script::AddMethod(const char* name, Game::xmethod_t func, int type) { - for (auto& function : Script::ScriptFunctions) - { - if (name && *name) - { - if (Utils::String::ToLower(*name) == Utils::String::ToLower(function.getName())) - { - *name = function.getName(); - *isDev = function.isDev(); - return function.getFunction(); - } - } - else if (caller == reinterpret_cast(0x465781)) - { - Game::Scr_RegisterFunction(function.getFunction()); - } - } + Game::BuiltinMethodDef toAdd; + toAdd.actionString = name; + toAdd.actionFunc = func; + toAdd.type = type; - return nullptr; + CustomScrMethods.insert_or_assign(Utils::String::ToLower(name), std::move(toAdd)); } - __declspec(naked) void Script::GetFunctionStub() + Game::xfunction_t Script::BuiltIn_GetFunctionStub(const char** pName, int* type) { - __asm + if (pName != nullptr) { - test eax, eax - jnz returnSafe + const auto got = Script::CustomScrFunctions.find(Utils::String::ToLower(*pName)); - sub esp, 8h - push [esp + 10h] - call Script::GetFunction - add esp, 0Ch - - returnSafe: - pop edi - pop esi - retn + // If no function was found let's call game's function + if (got != Script::CustomScrFunctions.end()) + { + *type = got->second.type; + return got->second.actionFunc; + } } + else + { + for (const auto& [name, builtin] : Script::CustomScrFunctions) + { + Game::Scr_RegisterFunction(reinterpret_cast(builtin.actionFunc), name.data()); + } + } + + return Utils::Hook::Call(0x5FA2B0)(pName, type); // BuiltIn_GetFunction + } + + Game::xmethod_t Script::BuiltIn_GetMethod(const char** pName, int* type) + { + if (pName != nullptr) + { + const auto got = Script::CustomScrMethods.find(Utils::String::ToLower(*pName)); + + // If no method was found let's call game's function + if (got != Script::CustomScrMethods.end()) + { + *type = got->second.type; + return got->second.actionFunc; + } + } + else + { + for (const auto& [name, builtin] : Script::CustomScrMethods) + { + Game::Scr_RegisterFunction(reinterpret_cast(builtin.actionFunc), name.data()); + } + } + + return Utils::Hook::Call(0x5FA360)(pName, type); // Player_GetMethod } void Script::StoreScriptBaseProgramNum() @@ -539,7 +549,7 @@ namespace Components void Script::AddFunctions() { - Script::AddFunction("ReplaceFunc", [](Game::scr_entref_t) // gsc: ReplaceFunc(, ) + Script::AddFunction("ReplaceFunc", []() // gsc: ReplaceFunc(, ) { if (Game::Scr_GetNumParam() != 2u) { @@ -554,7 +564,7 @@ namespace Components }); // System time - Script::AddFunction("GetSystemTime", [](Game::scr_entref_t) // gsc: GetSystemTime() + Script::AddFunction("GetSystemTime", []() // gsc: GetSystemTime() { SYSTEMTIME time; GetSystemTime(&time); @@ -562,7 +572,7 @@ namespace Components Game::Scr_AddInt(time.wSecond); }); - Script::AddFunction("GetSystemMilliseconds", [](Game::scr_entref_t) // gsc: GetSystemMilliseconds() + Script::AddFunction("GetSystemMilliseconds", []() // gsc: GetSystemMilliseconds() { SYSTEMTIME time; GetSystemTime(&time); @@ -571,7 +581,7 @@ namespace Components }); // Executes command to the console - Script::AddFunction("Exec", [](Game::scr_entref_t) // gsc: Exec() + Script::AddFunction("Exec", []() // gsc: Exec() { const auto str = Game::Scr_GetString(0); @@ -585,7 +595,7 @@ namespace Components }); // Allow printing to the console even when developer is 0 - Script::AddFunction("PrintConsole", [](Game::scr_entref_t) // gsc: PrintConsole() + Script::AddFunction("PrintConsole", []() // gsc: PrintConsole() { for (auto i = 0u; i < Game::Scr_GetNumParam(); i++) { @@ -602,7 +612,7 @@ namespace Components }); // Script Storage Functions - Script::AddFunction("StorageSet", [](Game::scr_entref_t) // gsc: StorageSet(, ); + Script::AddFunction("StorageSet", []() // gsc: StorageSet(, ); { const auto* key = Game::Scr_GetString(0); const auto* value = Game::Scr_GetString(1); @@ -616,7 +626,7 @@ namespace Components Script::ScriptStorage.insert_or_assign(key, value); }); - Script::AddFunction("StorageRemove", [](Game::scr_entref_t) // gsc: StorageRemove(); + Script::AddFunction("StorageRemove", []() // gsc: StorageRemove(); { const auto* key = Game::Scr_GetString(0); @@ -635,7 +645,7 @@ namespace Components Script::ScriptStorage.erase(key); }); - Script::AddFunction("StorageGet", [](Game::scr_entref_t) // gsc: StorageGet(); + Script::AddFunction("StorageGet", []() // gsc: StorageGet(); { const auto* key = Game::Scr_GetString(0); @@ -655,7 +665,7 @@ namespace Components Game::Scr_AddString(data.data()); }); - Script::AddFunction("StorageHas", [](Game::scr_entref_t) // gsc: StorageHas(); + Script::AddFunction("StorageHas", []() // gsc: StorageHas(); { const auto* key = Game::Scr_GetString(0); @@ -668,13 +678,13 @@ namespace Components Game::Scr_AddBool(static_cast(Script::ScriptStorage.count(key))); // Until C++17 }); - Script::AddFunction("StorageClear", [](Game::scr_entref_t) // gsc: StorageClear(); + Script::AddFunction("StorageClear", []() // gsc: StorageClear(); { Script::ScriptStorage.clear(); }); // PlayerCmd_AreControlsFrozen GSC function from Black Ops 2 - Script::AddFunction("AreControlsFrozen", [](Game::scr_entref_t entref) // Usage: self AreControlsFrozen(); + Script::AddMethod("AreControlsFrozen", [](Game::scr_entref_t entref) // Usage: self AreControlsFrozen(); { const auto* ent = Game::GetPlayerEntity(entref); @@ -704,8 +714,9 @@ namespace Components Utils::Hook(0x48EFFE, Script::LoadGameType, HOOK_CALL).install()->quick(); Utils::Hook(0x45D44A, Script::LoadGameTypeScript, HOOK_CALL).install()->quick(); - Utils::Hook(0x44E736, Script::GetFunctionStub, HOOK_JUMP).install()->quick(); // Scr_GetFunction - Utils::Hook(0x4EC8E5, Script::GetFunctionStub, HOOK_JUMP).install()->quick(); // Scr_GetMethod + // Fetch custom functions + Utils::Hook(0x44E72E, Script::BuiltIn_GetFunctionStub, HOOK_CALL).install()->quick(); // Scr_GetFunction + Utils::Hook(0x4EC8DD, Script::BuiltIn_GetMethod, HOOK_CALL).install()->quick(); // Scr_GetMethod Utils::Hook(0x5F41A3, Script::SetExpFogStub, HOOK_CALL).install()->quick(); @@ -735,7 +746,7 @@ namespace Components }); #ifdef _DEBUG - Script::AddFunction("DebugBox", [](Game::scr_entref_t) + Script::AddFunction("DebugBox", []() { const auto* message = Game::Scr_GetString(0); @@ -745,7 +756,7 @@ namespace Components } MessageBoxA(nullptr, message, "DEBUG", MB_OK); - }, true); + }, 1); #endif Script::AddFunctions(); diff --git a/src/Components/Modules/Script.hpp b/src/Components/Modules/Script.hpp index dfc486f4..09a63c22 100644 --- a/src/Components/Modules/Script.hpp +++ b/src/Components/Modules/Script.hpp @@ -6,26 +6,13 @@ namespace Components class Script : public Component { public: - class Function - { - public: - Function(const std::string& _name, Game::scr_function_t _callback, bool _dev) : name(_name), callback(_callback), dev(_dev) {} - - const char* getName() const { return this->name.data(); } - bool isDev() const { return this->dev; } - Game::scr_function_t getFunction() const { return this->callback; } - - private: - std::string name; - Game::scr_function_t callback; - bool dev; - }; - Script(); ~Script(); static int LoadScriptAndLabel(const std::string& script, const std::string& label); - static void AddFunction(const std::string& name, Game::scr_function_t function, bool isDev = false); + + static void AddFunction(const char* name, Game::xfunction_t func, int type = 0); + static void AddMethod(const char* name, Game::xmethod_t func, int type = 0); static void OnVMShutdown(Utils::Slot callback); @@ -34,7 +21,8 @@ namespace Components private: static std::string ScriptName; static std::vector ScriptHandles; - static std::vector ScriptFunctions; + static std::unordered_map CustomScrFunctions; + static std::unordered_map CustomScrMethods; static std::vector ScriptNameStack; static unsigned short FunctionName; static std::unordered_map ScriptStorage; @@ -61,8 +49,8 @@ namespace Components static void LoadGameType(); static void LoadGameTypeScript(); - static Game::scr_function_t GetFunction(void* caller, const char** name, int* isDev); - static void GetFunctionStub(); + static Game::xfunction_t BuiltIn_GetFunctionStub(const char** pName, int* type); + static Game::xmethod_t BuiltIn_GetMethod(const char** pName, int* type); static void ScrShutdownSystemStub(unsigned char sys); static void StoreScriptBaseProgramNumStub(); diff --git a/src/Components/Modules/ScriptExtension.cpp b/src/Components/Modules/ScriptExtension.cpp index 512c4304..b2c7a526 100644 --- a/src/Components/Modules/ScriptExtension.cpp +++ b/src/Components/Modules/ScriptExtension.cpp @@ -6,8 +6,8 @@ namespace Components void ScriptExtension::AddFunctions() { - //File functions - Script::AddFunction("FileWrite", [](Game::scr_entref_t) // gsc: FileWrite(, , ) + // File functions + Script::AddFunction("FileWrite", []() // gsc: FileWrite(, , ) { const auto* path = Game::Scr_GetString(0); auto* text = Game::Scr_GetString(1); @@ -50,7 +50,7 @@ namespace Components } }); - Script::AddFunction("FileRead", [](Game::scr_entref_t) // gsc: FileRead() + Script::AddFunction("FileRead", []() // gsc: FileRead() { const auto* path = Game::Scr_GetString(0); @@ -78,7 +78,7 @@ namespace Components Game::Scr_AddString(FileSystem::FileReader(path).getBuffer().data()); }); - Script::AddFunction("FileExists", [](Game::scr_entref_t) // gsc: FileExists() + Script::AddFunction("FileExists", []() // gsc: FileExists() { const auto* path = Game::Scr_GetString(0); @@ -100,7 +100,7 @@ namespace Components Game::Scr_AddInt(FileSystem::FileReader(path).exists()); }); - Script::AddFunction("FileRemove", [](Game::scr_entref_t) // gsc: FileRemove() + Script::AddFunction("FileRemove", []() // gsc: FileRemove() { const auto* path = Game::Scr_GetString(0); @@ -124,12 +124,84 @@ namespace Components const auto& file = p.filename().string(); Game::Scr_AddInt(FileSystem::DeleteFile(folder, file)); }); + + // Misc functions + Script::AddFunction("ToUpper", []() // gsc: ToUpper() + { + const auto scriptValue = Game::Scr_GetConstString(0); + const auto* string = Game::SL_ConvertToString(scriptValue); + + char out[1024] = {0}; // 1024 is the max for a string in this SL system + bool changed = false; + + size_t i = 0; + while (i < sizeof(out)) + { + const auto value = *string; + const auto result = static_cast(std::toupper(static_cast(value))); + out[i] = result; + + if (value != result) + changed = true; + + if (result == '\0') // Finished converting string + break; + + ++string; + ++i; + } + + // Null terminating character was overwritten + if (i >= sizeof(out)) + { + Game::Scr_Error("string too long"); + return; + } + + if (changed) + { + Game::Scr_AddString(out); + } + else + { + Game::SL_AddRefToString(scriptValue); + Game::Scr_AddConstString(scriptValue); + Game::SL_RemoveRefToString(scriptValue); + } + }); + + // Func present on IW5 + Script::AddFunction("StrICmp", []() // gsc: StrICmp(, ) + { + const auto value1 = Game::Scr_GetConstString(0); + const auto value2 = Game::Scr_GetConstString(1); + + const auto result = _stricmp(Game::SL_ConvertToString(value1), + Game::SL_ConvertToString(value2)); + + Game::Scr_AddInt(result); + }); + + // Func present on IW5 + Script::AddFunction("IsEndStr", []() // gsc: IsEndStr(, ) + { + const auto* s1 = Game::Scr_GetString(0); + const auto* s2 = Game::Scr_GetString(1); + + if (s1 == nullptr || s2 == nullptr) + { + Game::Scr_Error("^1IsEndStr: Illegal parameters!\n"); + return; + } + + Game::Scr_AddBool(Utils::String::EndsWith(s1, s2)); + }); } void ScriptExtension::AddMethods() { // ScriptExtension methods - Script::AddFunction("GetIp", [](Game::scr_entref_t entref) // gsc: self GetIp() + Script::AddMethod("GetIp", [](Game::scr_entref_t entref) // gsc: self GetIp() { const auto* ent = Game::GetPlayerEntity(entref); const auto* client = Script::GetClient(ent); @@ -142,7 +214,7 @@ namespace Components Game::Scr_AddString(ip.data()); }); - Script::AddFunction("GetPing", [](Game::scr_entref_t entref) // gsc: self GetPing() + Script::AddMethod("GetPing", [](Game::scr_entref_t entref) // gsc: self GetPing() { const auto* ent = Game::GetPlayerEntity(entref); const auto* client = Script::GetClient(ent); diff --git a/src/Game/Functions.cpp b/src/Game/Functions.cpp index 6cb56a3d..0a04d18f 100644 --- a/src/Game/Functions.cpp +++ b/src/Game/Functions.cpp @@ -272,6 +272,7 @@ namespace Game Scr_AddEntity_t Scr_AddEntity = Scr_AddEntity_t(0x4BFB40); Scr_AddString_t Scr_AddString = Scr_AddString_t(0x412310); + Scr_AddConstString_t Scr_AddConstString = Scr_AddConstString_t(0x488860); Scr_AddIString_t Scr_AddIString = Scr_AddIString_t(0x455F20); Scr_AddInt_t Scr_AddInt = Scr_AddInt_t(0x41D7D0); Scr_AddFloat_t Scr_AddFloat = Scr_AddFloat_t(0x61E860); @@ -313,6 +314,8 @@ namespace Game SL_ConvertToString_t SL_ConvertToString = SL_ConvertToString_t(0x4EC1D0); SL_GetString_t SL_GetString = SL_GetString_t(0x4CDC10); + SL_AddRefToString_t SL_AddRefToString = SL_AddRefToString_t(0x4D9B00); + SL_RemoveRefToString_t SL_RemoveRefToString = SL_RemoveRefToString_t(0x47CD70); SND_Init_t SND_Init = SND_Init_t(0x46A630); SND_InitDriver_t SND_InitDriver = SND_InitDriver_t(0x4F5090); diff --git a/src/Game/Functions.hpp b/src/Game/Functions.hpp index 86b24536..ee0d4d0c 100644 --- a/src/Game/Functions.hpp +++ b/src/Game/Functions.hpp @@ -645,6 +645,9 @@ namespace Game typedef void(__cdecl * Scr_AddString_t)(const char* value); extern Scr_AddString_t Scr_AddString; + typedef void(__cdecl * Scr_AddConstString_t)(unsigned int value); + extern Scr_AddConstString_t Scr_AddConstString; + typedef void(__cdecl * Scr_AddIString_t)(const char* value); extern Scr_AddIString_t Scr_AddIString; @@ -669,7 +672,7 @@ namespace Game typedef const char*(__cdecl * Scr_GetString_t)(unsigned int index); extern Scr_GetString_t Scr_GetString; - typedef unsigned int(__cdecl * Scr_GetConstString_t)(unsigned int index); + typedef scr_string_t(__cdecl * Scr_GetConstString_t)(unsigned int index); extern Scr_GetConstString_t Scr_GetConstString; typedef const char*(__cdecl * Scr_GetDebugString_t)(unsigned int index); @@ -705,7 +708,7 @@ namespace Game typedef void(__cdecl * Scr_ClearOutParams_t)(); extern Scr_ClearOutParams_t Scr_ClearOutParams; - typedef void(__cdecl * Scr_RegisterFunction_t)(scr_function_t function); + typedef void(__cdecl * Scr_RegisterFunction_t)(int func, const char* name); extern Scr_RegisterFunction_t Scr_RegisterFunction; typedef bool(__cdecl * Scr_IsSystemActive_t)(); @@ -738,21 +741,27 @@ namespace Game typedef int(__cdecl * Script_CleanString_t)(char* buffer); extern Script_CleanString_t Script_CleanString; - typedef char* (__cdecl * SE_Load_t)(const char* file, int Unk); + typedef char*(__cdecl * SE_Load_t)(const char* file, int Unk); extern SE_Load_t SE_Load; - typedef char* (__cdecl * SEH_StringEd_GetString_t)(const char* string); + typedef char*(__cdecl * SEH_StringEd_GetString_t)(const char* string); extern SEH_StringEd_GetString_t SEH_StringEd_GetString; typedef unsigned int(__cdecl* SEH_ReadCharFromString_t)(const char** text, int* isTrailingPunctuation); extern SEH_ReadCharFromString_t SEH_ReadCharFromString; - typedef char* (__cdecl * SL_ConvertToString_t)(unsigned short stringValue); + typedef char*(__cdecl * SL_ConvertToString_t)(unsigned short stringValue); extern SL_ConvertToString_t SL_ConvertToString; typedef short(__cdecl * SL_GetString_t)(const char *str, unsigned int user); extern SL_GetString_t SL_GetString; + typedef void(__cdecl * SL_AddRefToString_t)(unsigned int stringValue); + extern SL_AddRefToString_t SL_AddRefToString; + + typedef void(__cdecl * SL_RemoveRefToString_t)(unsigned int stringValue); + extern SL_RemoveRefToString_t SL_RemoveRefToString; + typedef void(__cdecl * SND_Init_t)(int a1, int a2, int a3); extern SND_Init_t SND_Init; diff --git a/src/Game/Structs.hpp b/src/Game/Structs.hpp index 61f92706..8c4e9523 100644 --- a/src/Game/Structs.hpp +++ b/src/Game/Structs.hpp @@ -20,13 +20,30 @@ namespace Game typedef vec_t vec3_t[3]; typedef vec_t vec4_t[4]; + typedef unsigned __int16 scr_string_t; + struct scr_entref_t { unsigned __int16 entnum; unsigned __int16 classnum; }; - typedef void(__cdecl * scr_function_t)(scr_entref_t); + typedef void(__cdecl * xfunction_t)(); + typedef void(__cdecl * xmethod_t)(scr_entref_t); + + struct BuiltinFunctionDef + { + const char* actionString; + xfunction_t actionFunc; + int type; + }; + + struct BuiltinMethodDef + { + const char* actionString; + xmethod_t actionFunc; + int type; + }; enum XAssetType { diff --git a/src/Utils/String.cpp b/src/Utils/String.cpp index 3dbca5fa..223334a7 100644 --- a/src/Utils/String.cpp +++ b/src/Utils/String.cpp @@ -97,12 +97,13 @@ namespace Utils bool StartsWith(const std::string& haystack, const std::string& needle) { - return (haystack.size() >= needle.size() && haystack.substr(0, needle.size()) == needle); + return haystack.find(needle) == 0; // If the pos of the first found char is 0, string starts with 'needle' } bool EndsWith(const std::string& haystack, const std::string& needle) { - return (haystack.size() >= needle.size() && haystack.substr(haystack.size() - needle.size()) == needle); + if (needle.size() > haystack.size()) return false; + return std::equal(needle.rbegin(), needle.rend(), haystack.rbegin()); } int IsSpace(int c) diff --git a/src/Utils/String.hpp b/src/Utils/String.hpp index 92b8b0dd..51012e8a 100644 --- a/src/Utils/String.hpp +++ b/src/Utils/String.hpp @@ -77,10 +77,10 @@ namespace Utils int IsSpace(int c); std::string ToLower(std::string text); std::string ToUpper(std::string text); - bool EndsWith(const std::string& haystack, const std::string& needle); std::vector Split(const std::string& str, const char delim); void Replace(std::string& string, const std::string& find, const std::string& replace); bool StartsWith(const std::string& haystack, const std::string& needle); + bool EndsWith(const std::string& haystack, const std::string& needle); std::string& LTrim(std::string& str); std::string& RTrim(std::string& str);