From 81bf44639f841b6c277b9816ae4c02deea1b665e Mon Sep 17 00:00:00 2001 From: ineed bots Date: Tue, 5 Dec 2023 16:32:37 -0600 Subject: [PATCH 1/5] 65535 is the char limit for SL strings, conditionally add "scriptdata" --- src/Components/Modules/GSC/IO.cpp | 18 +++++++++++++----- 1 file changed, 13 insertions(+), 5 deletions(-) diff --git a/src/Components/Modules/GSC/IO.cpp b/src/Components/Modules/GSC/IO.cpp index be8c2a53..37a68ee3 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("scriptdata/") && !spath.starts_with("scriptdata\\")) { - return fsGame / "scriptdata"s / path; + spath = "scriptdata/" + spath; } - return DefaultDestPath / "scriptdata"s / path; + if (!fsGame.empty()) + { + return fsGame / spath; + } + + return DefaultDestPath / spath; } void IO::GScr_OpenFile() @@ -85,7 +93,7 @@ namespace Components::GSC return; } - char line[1024]{}; + char line[65536]{}; if (std::fgets(line, sizeof(line), openScriptIOFileHandle) != nullptr) { Game::Scr_AddString(line); @@ -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()); }); From b0e0bd61911889fcdc254658aff748d474f1658f Mon Sep 17 00:00:00 2001 From: ineed bots Date: Tue, 5 Dec 2023 16:33:55 -0600 Subject: [PATCH 2/5] Bots can press use on objects, bots can use alt weapons properally --- src/Components/Modules/Bots.cpp | 39 ++++++++++++++++++++++++++++++++- src/Components/Modules/Bots.hpp | 4 +++- src/Game/BothGames.cpp | 2 ++ src/Game/BothGames.hpp | 6 +++++ 4 files changed, 49 insertions(+), 2 deletions(-) diff --git a/src/Components/Modules/Bots.cpp b/src/Components/Modules/Bots.cpp index 8271928a..43ce6ef7 100644 --- a/src/Components/Modules/Bots.cpp +++ b/src/Components/Modules/Bots.cpp @@ -27,6 +27,7 @@ namespace Components std::int8_t forward; std::int8_t right; std::uint16_t weapon; + std::uint16_t lastAltWeapon; bool active; }; @@ -316,6 +317,7 @@ namespace Components 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.primaryWeaponForAltMode = g_botai[cl - Game::svs_clients].lastAltWeapon; 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 +341,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->weapDef->inventoryType == Game::WEAPINVENTORY_ALTMODE) + { + auto* ps = &Game::g_entities[clientNum].client->ps; + auto num_weaps = Game::BG_GetNumWeapons(); + + for (auto i = 1u; i < num_weaps; i++) + { + if (!Game::BG_PlayerHasWeapon(ps, i)) + { + continue; + } + + auto* this_def = Game::BG_GetWeaponCompleteDef(i); + + if (this_def->altWeaponIndex != iWeaponIndex) + { + continue; + } + + g_botai[clientNum].lastAltWeapon = static_cast(i); + break; + } + } } } @@ -472,6 +501,11 @@ namespace Components }); } + bool Bots::Player_UpdateActivate_stub(int) + { + return false; + } + Bots::Bots() { AssertOffset(Game::client_s, bIsTestClient, 0x41AF0); @@ -489,6 +523,9 @@ namespace Components Utils::Hook(0x441B80, G_SelectWeaponIndex_Hk, HOOK_JUMP).install()->quick(); + // fix bots using objects + 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/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; } From 9d4e08b1a393a1d842687b55b8d2fda785ad669a Mon Sep 17 00:00:00 2001 From: ineed bots Date: Tue, 5 Dec 2023 17:04:04 -0600 Subject: [PATCH 3/5] Revert ReadStream to use 1024 chars --- src/Components/Modules/GSC/IO.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Components/Modules/GSC/IO.cpp b/src/Components/Modules/GSC/IO.cpp index 37a68ee3..0843fe2e 100644 --- a/src/Components/Modules/GSC/IO.cpp +++ b/src/Components/Modules/GSC/IO.cpp @@ -93,7 +93,7 @@ namespace Components::GSC return; } - char line[65536]{}; + char line[1024]{}; if (std::fgets(line, sizeof(line), openScriptIOFileHandle) != nullptr) { Game::Scr_AddString(line); From e9debbd4f5a0bea99bc05b837acc768048675df9 Mon Sep 17 00:00:00 2001 From: ineed bots Date: Tue, 5 Dec 2023 17:34:33 -0600 Subject: [PATCH 4/5] Address comments --- src/Components/Modules/Bots.cpp | 26 +++++++++++--------- src/Components/Modules/GSC/IO.cpp | 4 +-- src/Components/Modules/GSC/ScriptStorage.cpp | 4 +-- src/Game/Script.hpp | 2 ++ 4 files changed, 20 insertions(+), 16 deletions(-) diff --git a/src/Components/Modules/Bots.cpp b/src/Components/Modules/Bots.cpp index 43ce6ef7..0d2e07b6 100644 --- a/src/Components/Modules/Bots.cpp +++ b/src/Components/Modules/Bots.cpp @@ -301,8 +301,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; @@ -313,11 +315,11 @@ 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.primaryWeaponForAltMode = g_botai[cl - Game::svs_clients].lastAltWeapon; + 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.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])); @@ -350,21 +352,21 @@ namespace Components auto* def = Game::BG_GetWeaponCompleteDef(iWeaponIndex); - if (def->weapDef->inventoryType == Game::WEAPINVENTORY_ALTMODE) + if (def && def->weapDef->inventoryType == Game::WEAPINVENTORY_ALTMODE) { auto* ps = &Game::g_entities[clientNum].client->ps; - auto num_weaps = Game::BG_GetNumWeapons(); + auto numWeaps = Game::BG_GetNumWeapons(); - for (auto i = 1u; i < num_weaps; i++) + for (auto i = 1u; i < numWeaps; i++) { if (!Game::BG_PlayerHasWeapon(ps, i)) { continue; } - auto* this_def = Game::BG_GetWeaponCompleteDef(i); + auto* thisDef = Game::BG_GetWeaponCompleteDef(i); - if (this_def->altWeaponIndex != iWeaponIndex) + if (!thisDef || thisDef->altWeaponIndex != iWeaponIndex) { continue; } @@ -523,7 +525,7 @@ namespace Components Utils::Hook(0x441B80, G_SelectWeaponIndex_Hk, HOOK_JUMP).install()->quick(); - // fix bots using objects + // 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(); diff --git a/src/Components/Modules/GSC/IO.cpp b/src/Components/Modules/GSC/IO.cpp index 0843fe2e..7d866434 100644 --- a/src/Components/Modules/GSC/IO.cpp +++ b/src/Components/Modules/GSC/IO.cpp @@ -33,9 +33,9 @@ namespace Components::GSC // check if we need to append scriptdata folder, for backwards compat std::string spath = path; - if (!spath.starts_with("scriptdata/") && !spath.starts_with("scriptdata\\")) + if (!spath.starts_with(Game::SCRIPTDATA_DIR + "/"s) && !spath.starts_with(Game::SCRIPTDATA_DIR + "\\"s)) { - spath = "scriptdata/" + spath; + spath = Game::SCRIPTDATA_DIR + "/"s + spath; } if (!fsGame.empty()) 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/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); From d3f49d236404ae130dbfa73d34c2ea8a7e87f9aa Mon Sep 17 00:00:00 2001 From: ineed bots Date: Sat, 9 Dec 2023 22:17:16 -0600 Subject: [PATCH 5/5] Add BotMeleeParams builtin --- src/Components/Modules/Bots.cpp | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/Components/Modules/Bots.cpp b/src/Components/Modules/Bots.cpp index 0d2e07b6..576bcdc8 100644 --- a/src/Components/Modules/Bots.cpp +++ b/src/Components/Modules/Bots.cpp @@ -28,6 +28,8 @@ namespace Components std::int8_t right; std::uint16_t weapon; std::uint16_t lastAltWeapon; + std::uint8_t meleeDist; + float meleeYaw; bool active; }; @@ -292,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) @@ -320,6 +339,8 @@ namespace Components 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]));