diff --git a/deps/GSL b/deps/GSL index 4300304e..e64c97fc 160000 --- a/deps/GSL +++ b/deps/GSL @@ -1 +1 @@ -Subproject commit 4300304ef24c247b3db0255763f46b9f95c3a83d +Subproject commit e64c97fc2cfc11992098bb38eda932de275e3f4d diff --git a/deps/libtommath b/deps/libtommath index 3746c58f..8314bde5 160000 --- a/deps/libtommath +++ b/deps/libtommath @@ -1 +1 @@ -Subproject commit 3746c58f29a1ebea15046932bbc9dacc35b4b214 +Subproject commit 8314bde5e5c8e5d9331460130a9d1066e324f091 diff --git a/src/Components/Modules/Bots.cpp b/src/Components/Modules/Bots.cpp index 8271928a..576bcdc8 100644 --- a/src/Components/Modules/Bots.cpp +++ b/src/Components/Modules/Bots.cpp @@ -27,6 +27,9 @@ namespace Components std::int8_t forward; std::int8_t right; std::uint16_t weapon; + std::uint16_t lastAltWeapon; + std::uint8_t meleeDist; + float meleeYaw; bool active; }; @@ -291,6 +294,23 @@ namespace Components g_botai[entref.entnum].right = static_cast(rightInt); g_botai[entref.entnum].active = true; }); + + GSC::Script::AddMethod("BotMeleeParams", [](const Game::scr_entref_t entref) // Usage: BotMeleeParams(, ); + { + const auto* ent = GSC::Script::Scr_GetPlayerEntity(entref); + if (!Game::SV_IsTestClient(ent->s.number)) + { + Game::Scr_Error("BotMeleeParams: Can only call on a bot!"); + return; + } + + const auto yaw = Game::Scr_GetFloat(0); + const auto dist = std::clamp(static_cast(Game::Scr_GetFloat(1)), std::numeric_limits::min(), std::numeric_limits::max()); + + g_botai[entref.entnum].meleeYaw = yaw; + g_botai[entref.entnum].meleeDist = static_cast(dist); + g_botai[entref.entnum].active = true; + }); } void Bots::BotAiAction(Game::client_s* cl) @@ -300,8 +320,10 @@ namespace Components return; } + auto clientNum = cl - Game::svs_clients; + // Keep test client functionality - if (!g_botai[cl - Game::svs_clients].active) + if (!g_botai[clientNum].active) { Game::SV_BotUserMove(cl); return; @@ -312,10 +334,13 @@ namespace Components userCmd.serverTime = *Game::svs_time; - userCmd.buttons = g_botai[cl - Game::svs_clients].buttons; - userCmd.forwardmove = g_botai[cl - Game::svs_clients].forward; - userCmd.rightmove = g_botai[cl - Game::svs_clients].right; - userCmd.weapon = g_botai[cl - Game::svs_clients].weapon; + userCmd.buttons = g_botai[clientNum].buttons; + userCmd.forwardmove = g_botai[clientNum].forward; + userCmd.rightmove = g_botai[clientNum].right; + userCmd.weapon = g_botai[clientNum].weapon; + userCmd.primaryWeaponForAltMode = g_botai[clientNum].lastAltWeapon; + userCmd.meleeChargeYaw = g_botai[clientNum].meleeYaw; + userCmd.meleeChargeDist = g_botai[clientNum].meleeDist; userCmd.angles[0] = ANGLE2SHORT((cl->gentity->client->ps.viewangles[0] - cl->gentity->client->ps.delta_angles[0])); userCmd.angles[1] = ANGLE2SHORT((cl->gentity->client->ps.viewangles[1] - cl->gentity->client->ps.delta_angles[1])); @@ -339,11 +364,38 @@ namespace Components } } - void Bots::G_SelectWeaponIndex(int clientNum, int iWeaponIndex) + void Bots::G_SelectWeaponIndex(int clientNum, unsigned int iWeaponIndex) { if (g_botai[clientNum].active) { g_botai[clientNum].weapon = static_cast(iWeaponIndex); + g_botai[clientNum].lastAltWeapon = 0; + + auto* def = Game::BG_GetWeaponCompleteDef(iWeaponIndex); + + if (def && def->weapDef->inventoryType == Game::WEAPINVENTORY_ALTMODE) + { + auto* ps = &Game::g_entities[clientNum].client->ps; + auto numWeaps = Game::BG_GetNumWeapons(); + + for (auto i = 1u; i < numWeaps; i++) + { + if (!Game::BG_PlayerHasWeapon(ps, i)) + { + continue; + } + + auto* thisDef = Game::BG_GetWeaponCompleteDef(i); + + if (!thisDef || thisDef->altWeaponIndex != iWeaponIndex) + { + continue; + } + + g_botai[clientNum].lastAltWeapon = static_cast(i); + break; + } + } } } @@ -472,6 +524,11 @@ namespace Components }); } + bool Bots::Player_UpdateActivate_stub(int) + { + return false; + } + Bots::Bots() { AssertOffset(Game::client_s, bIsTestClient, 0x41AF0); @@ -489,6 +546,9 @@ namespace Components Utils::Hook(0x441B80, G_SelectWeaponIndex_Hk, HOOK_JUMP).install()->quick(); + // fix bots using objects (SV_IsClientBot) + Utils::Hook(0x4D79C5, Player_UpdateActivate_stub, HOOK_CALL).install()->quick(); + Utils::Hook(0x459654, SV_GetClientPing_Hk, HOOK_CALL).install()->quick(); sv_randomBotNames = Game::Dvar_RegisterBool("sv_randomBotNames", false, Game::DVAR_NONE, "Randomize the bots' names"); diff --git a/src/Components/Modules/Bots.hpp b/src/Components/Modules/Bots.hpp index d2aa35f6..342007da 100644 --- a/src/Components/Modules/Bots.hpp +++ b/src/Components/Modules/Bots.hpp @@ -32,9 +32,11 @@ namespace Components static void BotAiAction(Game::client_s* cl); static void SV_BotUserMove_Hk(); - static void G_SelectWeaponIndex(int clientNum, int iWeaponIndex); + static void G_SelectWeaponIndex(int clientNum, unsigned int iWeaponIndex); static void G_SelectWeaponIndex_Hk(); + static bool Player_UpdateActivate_stub(int); + static int SV_GetClientPing_Hk(int clientNum); static bool IsFull(); diff --git a/src/Components/Modules/GSC/IO.cpp b/src/Components/Modules/GSC/IO.cpp index be8c2a53..7d866434 100644 --- a/src/Components/Modules/GSC/IO.cpp +++ b/src/Components/Modules/GSC/IO.cpp @@ -30,12 +30,20 @@ namespace Components::GSC std::filesystem::path IO::BuildPath(const char* path) { const std::filesystem::path fsGame = (*Game::fs_gameDirVar)->current.string; - if (!fsGame.empty()) + + // check if we need to append scriptdata folder, for backwards compat + std::string spath = path; + if (!spath.starts_with(Game::SCRIPTDATA_DIR + "/"s) && !spath.starts_with(Game::SCRIPTDATA_DIR + "\\"s)) { - return fsGame / "scriptdata"s / path; + spath = Game::SCRIPTDATA_DIR + "/"s + spath; } - return DefaultDestPath / "scriptdata"s / path; + if (!fsGame.empty()) + { + return fsGame / spath; + } + + return DefaultDestPath / spath; } void IO::GScr_OpenFile() @@ -154,7 +162,7 @@ namespace Components::GSC return; } - file = file.substr(0, 1024 - 1); // 1024 is the max string size for the SL system + file = file.substr(0, (1 << 16) - 1); // 65535 is the max string size for the SL system Game::Scr_AddString(file.data()); }); diff --git a/src/Components/Modules/GSC/ScriptStorage.cpp b/src/Components/Modules/GSC/ScriptStorage.cpp index 672a599c..326b1ce5 100644 --- a/src/Components/Modules/GSC/ScriptStorage.cpp +++ b/src/Components/Modules/GSC/ScriptStorage.cpp @@ -84,12 +84,12 @@ namespace Components::GSC const nlohmann::json json = Data; - FileSystem::FileWriter("scriptdata/scriptstorage.json").write(json.dump()); + FileSystem::FileWriter(Game::SCRIPTDATA_DIR + "/scriptstorage.json"s).write(json.dump()); }); Script::AddFunction("StorageLoad", [] // gsc: StorageLoad(); { - FileSystem::File storageFile("scriptdata/scriptstorage.json"); + FileSystem::File storageFile(Game::SCRIPTDATA_DIR + "/scriptstorage.json"s); if (!storageFile.exists()) { return; diff --git a/src/Components/Modules/Maps.cpp b/src/Components/Modules/Maps.cpp index dd647b41..8b398751 100644 --- a/src/Components/Modules/Maps.cpp +++ b/src/Components/Modules/Maps.cpp @@ -205,8 +205,7 @@ namespace Components void Maps::LoadAssetRestrict(Game::XAssetType type, Game::XAssetHeader asset, const std::string& name, bool* restrict) { - if (std::find(Maps::CurrentDependencies.begin(), Maps::CurrentDependencies.end(), FastFiles::Current()) != Maps::CurrentDependencies.end() - && (FastFiles::Current() != "mp_shipment_long" || Maps::CurrentMainZone != "mp_shipment")) // Shipment is a special case + if (std::find(Maps::CurrentDependencies.begin(), Maps::CurrentDependencies.end(), FastFiles::Current()) != Maps::CurrentDependencies.end()) // Shipment is a special case { switch (type) { @@ -315,6 +314,7 @@ namespace Components } } + // TODO : Remove hook entirely? void Maps::GetBSPName(char* buffer, size_t size, const char* format, const char* mapname) { if (!Utils::String::StartsWith(mapname, "mp_")) @@ -322,12 +322,6 @@ namespace Components format = "maps/%s.d3dbsp"; } - // TODO: Remove this hack by using CoD4 version of the map - if (std::strcmp(mapname, "mp_shipment") == 0) - { - mapname = "mp_shipment_long"; - } - _snprintf_s(buffer, size, _TRUNCATE, format, mapname); } diff --git a/src/Game/BothGames.cpp b/src/Game/BothGames.cpp index e3986666..023be38a 100644 --- a/src/Game/BothGames.cpp +++ b/src/Game/BothGames.cpp @@ -11,4 +11,6 @@ namespace Game BG_IsWeaponValid_t BG_IsWeaponValid = BG_IsWeaponValid_t(0x415BA0); BG_GetEquippedWeaponIndex_t BG_GetEquippedWeaponIndex = BG_GetEquippedWeaponIndex_t(0x4D8BA0); BG_GetEquippedWeaponState_t BG_GetEquippedWeaponState = BG_GetEquippedWeaponState_t(0x4E79E0); + BG_PlayerHasWeapon_t BG_PlayerHasWeapon = BG_PlayerHasWeapon_t(0x4AB530); + BG_GetWeaponCompleteDef_t BG_GetWeaponCompleteDef = BG_GetWeaponCompleteDef_t(0x44CE00); } diff --git a/src/Game/BothGames.hpp b/src/Game/BothGames.hpp index 946979b5..d8b6707d 100644 --- a/src/Game/BothGames.hpp +++ b/src/Game/BothGames.hpp @@ -28,4 +28,10 @@ namespace Game typedef PlayerEquippedWeaponState*(*BG_GetEquippedWeaponState_t)(playerState_s* ps, unsigned int weaponIndex); extern BG_GetEquippedWeaponState_t BG_GetEquippedWeaponState; + + typedef int*(*BG_PlayerHasWeapon_t)(playerState_s* ps, unsigned int weaponIndex); + extern BG_PlayerHasWeapon_t BG_PlayerHasWeapon; + + typedef Game::WeaponCompleteDef*(*BG_GetWeaponCompleteDef_t)(unsigned int weaponIndex); + extern BG_GetWeaponCompleteDef_t BG_GetWeaponCompleteDef; } diff --git a/src/Game/Script.hpp b/src/Game/Script.hpp index 14ebbbb5..64182e73 100644 --- a/src/Game/Script.hpp +++ b/src/Game/Script.hpp @@ -221,6 +221,8 @@ namespace Game constexpr auto LOCAL_VAR_STACK_SIZE = 64; + constexpr auto SCRIPTDATA_DIR = "scriptdata"; + extern void IncInParam(); extern void Scr_AddBool(int value);