From 607a5cc96405e65d78ea0bffc658c4a46f796c5a Mon Sep 17 00:00:00 2001 From: Celio Lozatto Date: Tue, 13 Aug 2024 13:01:18 -0300 Subject: [PATCH 01/46] Implement CBasePlayerItem:: hook --- regamedll/dlls/API/CAPI_Impl.cpp | 3 +++ regamedll/dlls/API/CAPI_Impl.h | 14 ++++++++++++++ regamedll/dlls/weapons.cpp | 6 ++++-- regamedll/dlls/weapons.h | 2 ++ regamedll/public/regamedll/regamedll_api.h | 11 +++++++++++ 5 files changed, 34 insertions(+), 2 deletions(-) diff --git a/regamedll/dlls/API/CAPI_Impl.cpp b/regamedll/dlls/API/CAPI_Impl.cpp index 41175c838..8877ddf9a 100644 --- a/regamedll/dlls/API/CAPI_Impl.cpp +++ b/regamedll/dlls/API/CAPI_Impl.cpp @@ -337,6 +337,9 @@ GAMEHOOK_REGISTRY(CBasePlayer_PlayerDeathThink); GAMEHOOK_REGISTRY(CBasePlayer_Observer_Think); GAMEHOOK_REGISTRY(CBasePlayer_RemoveAllItems); +GAMEHOOK_REGISTRY(CBasePlayerItem_Materialize); +GAMEHOOK_REGISTRY(CBasePlayerItem_CheckRespawn); + int CReGameApi::GetMajorVersion() { return REGAMEDLL_API_VERSION_MAJOR; } diff --git a/regamedll/dlls/API/CAPI_Impl.h b/regamedll/dlls/API/CAPI_Impl.h index 2635be5b9..caecf5f15 100644 --- a/regamedll/dlls/API/CAPI_Impl.h +++ b/regamedll/dlls/API/CAPI_Impl.h @@ -749,6 +749,14 @@ typedef IHookChainRegistryClassImpl CReGameHookRegistry_CBase typedef IHookChainClassImpl CReGameHook_CBasePlayer_RemoveAllItems; typedef IHookChainRegistryClassImpl CReGameHookRegistry_CBasePlayer_RemoveAllItems; +// CBasePlayerItem::Materialize hook +typedef IHookChainClassImpl CReGameHook_CBasePlayerItem_Materialize; +typedef IHookChainRegistryClassImpl CReGameHookRegistry_CBasePlayerItem_Materialize; + +// CBasePlayerItem::CheckRespawn hook +typedef IHookChainClassImpl CReGameHook_CBasePlayerItem_CheckRespawn; +typedef IHookChainRegistryClassImpl CReGameHookRegistry_CBasePlayerItem_CheckRespawn; + class CReGameHookchains: public IReGameHookchains { public: // CBasePlayer virtual @@ -911,6 +919,9 @@ class CReGameHookchains: public IReGameHookchains { CReGameHookRegistry_CBasePlayer_Observer_Think m_CBasePlayer_Observer_Think; CReGameHookRegistry_CBasePlayer_RemoveAllItems m_CBasePlayer_RemoveAllItems; + CReGameHookRegistry_CBasePlayerItem_Materialize m_CBasePlayerItem_Materialize; + CReGameHookRegistry_CBasePlayerItem_CheckRespawn m_CBasePlayerItem_CheckRespawn; + public: virtual IReGameHookRegistry_CBasePlayer_Spawn *CBasePlayer_Spawn(); virtual IReGameHookRegistry_CBasePlayer_Precache *CBasePlayer_Precache(); @@ -1070,6 +1081,9 @@ class CReGameHookchains: public IReGameHookchains { virtual IReGameHookRegistry_CBasePlayer_PlayerDeathThink *CBasePlayer_PlayerDeathThink(); virtual IReGameHookRegistry_CBasePlayer_Observer_Think *CBasePlayer_Observer_Think(); virtual IReGameHookRegistry_CBasePlayer_RemoveAllItems *CBasePlayer_RemoveAllItems(); + + virtual IReGameHookRegistry_CBasePlayerItem_Materialize *CBasePlayerItem_Materialize(); + virtual IReGameHookRegistry_CBasePlayerItem_CheckRespawn *CBasePlayerItem_CheckRespawn(); }; extern CReGameHookchains g_ReGameHookchains; diff --git a/regamedll/dlls/weapons.cpp b/regamedll/dlls/weapons.cpp index 9a3d8e0c0..1b5f447ff 100644 --- a/regamedll/dlls/weapons.cpp +++ b/regamedll/dlls/weapons.cpp @@ -497,8 +497,9 @@ void CBasePlayerItem::FallThink() } } +LINK_HOOK_CLASS_VOID_CHAIN2(CBasePlayerItem, Materialize) // Materialize - make a CBasePlayerItem visible and tangible -void CBasePlayerItem::Materialize() +void EXT_FUNC CBasePlayerItem::__API_HOOK(Materialize)() { if (pev->effects & EF_NODRAW) { @@ -553,9 +554,10 @@ void CBasePlayerItem::AttemptToMaterialize() pev->nextthink = gpGlobals->time + time; } +LINK_HOOK_CLASS_VOID_CHAIN2(CBasePlayerItem, CheckRespawn) // CheckRespawn - a player is taking this weapon, should // it respawn? -void CBasePlayerItem::CheckRespawn() +void EXT_FUNC CBasePlayerItem::__API_HOOK(CheckRespawn)() { switch (g_pGameRules->WeaponShouldRespawn(this)) { diff --git a/regamedll/dlls/weapons.h b/regamedll/dlls/weapons.h index 9266d8434..801a14eb3 100644 --- a/regamedll/dlls/weapons.h +++ b/regamedll/dlls/weapons.h @@ -311,6 +311,8 @@ class CBasePlayerItem: public CBaseAnimating public: #ifdef REGAMEDLL_API + void Materialize_OrigFunc(); + void CheckRespawn_OrigFunc(); CCSPlayerItem *CSPlayerItem() const; #endif diff --git a/regamedll/public/regamedll/regamedll_api.h b/regamedll/public/regamedll/regamedll_api.h index d655ee656..9a04ed587 100644 --- a/regamedll/public/regamedll/regamedll_api.h +++ b/regamedll/public/regamedll/regamedll_api.h @@ -628,6 +628,14 @@ typedef IHookChainRegistryClass IReGameHookRegistry_CBa typedef IHookChainClass IReGameHook_CBasePlayer_RemoveAllItems; typedef IHookChainRegistryClass IReGameHookRegistry_CBasePlayer_RemoveAllItems; +// CBasePlayerItem::Materialize hook +typedef IHookChainClass IReGameHook_CBasePlayerItem_Materialize; +typedef IHookChainRegistryClass IReGameHookRegistry_CBasePlayerItem_Materialize; + +// CBasePlayerItem::CheckRespawn hook +typedef IHookChainClass IReGameHook_CBasePlayerItem_CheckRespawn; +typedef IHookChainRegistryClass IReGameHookRegistry_CBasePlayerItem_CheckRespawn; + class IReGameHookchains { public: virtual ~IReGameHookchains() {} @@ -790,6 +798,9 @@ class IReGameHookchains { virtual IReGameHookRegistry_CBasePlayer_PlayerDeathThink *CBasePlayer_PlayerDeathThink() = 0; virtual IReGameHookRegistry_CBasePlayer_Observer_Think *CBasePlayer_Observer_Think() = 0; virtual IReGameHookRegistry_CBasePlayer_RemoveAllItems *CBasePlayer_RemoveAllItems() = 0; + + virtual IReGameHookRegistry_CBasePlayerItem_Materialize *CBasePlayerItem_Materialize() = 0; + virtual IReGameHookRegistry_CBasePlayerItem_CheckRespawn *CBasePlayerItem_CheckRespawn() = 0; }; struct ReGameFuncs_t { From dc16b12d7976f03d20b81f9a2491ee7dddbb9b8e Mon Sep 17 00:00:00 2001 From: s1lentq Date: Sun, 25 Aug 2024 05:45:09 +0700 Subject: [PATCH 02/46] [skip ci] VisualStudio: Add auto visualizer for some structures/classes --- regamedll/dlls/client.cpp | 3 + regamedll/msvc/ReGameDLL.vcxproj | 3 + regamedll/msvc/ReGameDLL.vcxproj.filters | 5 ++ regamedll/regamedll/types.natvis | 107 +++++++++++++++++++++++ 4 files changed, 118 insertions(+) create mode 100644 regamedll/regamedll/types.natvis diff --git a/regamedll/dlls/client.cpp b/regamedll/dlls/client.cpp index e1b4d3221..3fe161c62 100644 --- a/regamedll/dlls/client.cpp +++ b/regamedll/dlls/client.cpp @@ -133,6 +133,7 @@ static entity_field_alias_t custom_entity_field_alias[] = { "animtime", 0 }, }; +edict_t *g_pEdicts = nullptr; bool g_bServerActive = false; bool g_bItemCreatedByBuying = false; PLAYERPVSSTATUS g_PVSStatus[MAX_CLIENTS]; @@ -3747,6 +3748,8 @@ void EXT_FUNC ServerDeactivate() void EXT_FUNC ServerActivate(edict_t *pEdictList, int edictCount, int clientMax) { + g_pEdicts = pEdictList; + #ifdef REGAMEDLL_ADD // // Tells clients which version of player movement (pmove) the server is using diff --git a/regamedll/msvc/ReGameDLL.vcxproj b/regamedll/msvc/ReGameDLL.vcxproj index 57e09e917..f33cfa3dc 100644 --- a/regamedll/msvc/ReGameDLL.vcxproj +++ b/regamedll/msvc/ReGameDLL.vcxproj @@ -809,6 +809,9 @@ + + + {70A2B904-B7DB-4C48-8DE0-AF567360D572} ReGameDLL diff --git a/regamedll/msvc/ReGameDLL.vcxproj.filters b/regamedll/msvc/ReGameDLL.vcxproj.filters index ef2017ae4..bfc6d6256 100644 --- a/regamedll/msvc/ReGameDLL.vcxproj.filters +++ b/regamedll/msvc/ReGameDLL.vcxproj.filters @@ -1070,4 +1070,9 @@ public\tier0 + + + regamedll + + \ No newline at end of file diff --git a/regamedll/regamedll/types.natvis b/regamedll/regamedll/types.natvis new file mode 100644 index 000000000..4dc313c65 --- /dev/null +++ b/regamedll/regamedll/types.natvis @@ -0,0 +1,107 @@ + + + + + + {{ { pev->pContainingEntity - g_pEdicts }, { pev->classname }, { pev->health }, { m_iTeam }, { m_iModelName } }} + + + + + + { *m_pContainingEntity } + + + + + {{ { pev->pContainingEntity - g_pEdicts }, { pev->classname } }} + + + m_pNext + m_pNext + (*this) + + + + + + + {{ { pev->pContainingEntity - g_pEdicts }, { pev->classname }, { pev->model } }} + + + + + {{ {this - g_pEdicts}, { v.classname }, { v.model } }} + + + + + {{ { pContainingEntity - g_pEdicts }, { classname }, { model } }} + + + + + { &gpGlobals->pStringBase[m_string],s } + + + + + allocator + + ($T1 *)m_pMemory + m_nAllocationCount + m_nGrowSize + + + + + + {{ size = { m_Size } }} + + + m_Size + (ElemType_t *)m_Memory.m_pMemory + + + + + + + {{ size = { m_Tree.m_NumElements } }} + + m_Tree.m_NumElements + m_Tree.m_Elements + + + + ((CTree::Node_t *)m_Tree.m_Elements.m_pMemory)[iMap].m_Data.elem + iMap++ + + + + + + + + {{ size = { $T2 } }} + + + $T2 + ($T1 *)&m_Memory[0] + + + + + + + + m_NumElements + m_Elements + + m_NumElements + ((Node_t *)m_Elements.m_pMemory)[$i].m_Data + + + + + From 3cf66de905ed835ad0f6770b751d97e90a383b9b Mon Sep 17 00:00:00 2001 From: Vaqtincha <51029683+Vaqtincha@users.noreply.github.com> Date: Fri, 13 Sep 2024 02:22:08 +0500 Subject: [PATCH 03/46] fix mp_kill_filled_spawn (#1011) --- regamedll/dlls/player.cpp | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/regamedll/dlls/player.cpp b/regamedll/dlls/player.cpp index 1a895df62..c297d827e 100644 --- a/regamedll/dlls/player.cpp +++ b/regamedll/dlls/player.cpp @@ -4310,10 +4310,10 @@ void CBasePlayer::PlayerUse() } // UNDONE: Send different USE codes for ON/OFF. Cache last ONOFF_USE object to send 'off' if you turn away // BUGBUG This is an "off" use - else if ((m_afButtonReleased & IN_USE) + else if ((m_afButtonReleased & IN_USE) #ifdef REGAMEDLL_FIXES && (caps & FCAP_ONOFF_USE)) -#else +#else && (pObject->ObjectCaps() & FCAP_ONOFF_USE)) #endif { @@ -5374,11 +5374,6 @@ BOOL IsSpawnPointValid(CBaseEntity *pPlayer, CBaseEntity *pSpot) if (!pSpot->IsTriggered(pPlayer)) return FALSE; -#ifdef REGAMEDLL_ADD - if (!kill_filled_spawn.value) - return TRUE; -#endif - CBaseEntity *pEntity = nullptr; while ((pEntity = UTIL_FindEntityInSphere(pEntity, pSpot->pev->origin, MAX_PLAYER_USE_RADIUS))) { From 19714af6e65cd0bf857dfecd6a95ed343ca14687 Mon Sep 17 00:00:00 2001 From: s1lentq Date: Fri, 13 Sep 2024 06:43:27 +0700 Subject: [PATCH 04/46] get rid of unsafe string functions minor refactor --- regamedll/dlls/bot/cs_bot_init.cpp | 2 +- regamedll/dlls/bot/cs_bot_learn.cpp | 8 +- regamedll/dlls/bot/cs_bot_manager.cpp | 14 +- regamedll/dlls/client.cpp | 27 ++-- regamedll/dlls/debug.cpp | 14 +- regamedll/dlls/explode.cpp | 2 +- regamedll/dlls/gamerules.cpp | 4 +- regamedll/dlls/gamerules.h | 1 - regamedll/dlls/hostage/hostage_improv.cpp | 6 +- regamedll/dlls/items.cpp | 2 +- regamedll/dlls/lights.cpp | 12 +- regamedll/dlls/multiplay_gamerules.cpp | 62 +++----- regamedll/dlls/observer.cpp | 16 +- regamedll/dlls/player.cpp | 141 ++++++------------ regamedll/dlls/player.h | 6 +- regamedll/dlls/saverestore.cpp | 6 +- regamedll/dlls/skill.cpp | 2 +- regamedll/dlls/sound.cpp | 43 ++---- regamedll/dlls/sound.h | 4 +- regamedll/dlls/triggers.cpp | 18 +-- regamedll/dlls/tutor_base_tutor.cpp | 10 +- regamedll/dlls/tutor_cs_tutor.cpp | 12 +- regamedll/dlls/util.cpp | 38 ++--- regamedll/dlls/weapons.cpp | 16 +- regamedll/dlls/world.cpp | 2 +- regamedll/dlls/wpn_shared/wpn_flashbang.cpp | 10 +- regamedll/dlls/wpn_shared/wpn_hegrenade.cpp | 10 +- regamedll/dlls/wpn_shared/wpn_knife.cpp | 48 +++--- regamedll/dlls/wpn_shared/wpn_m4a1.cpp | 4 +- .../dlls/wpn_shared/wpn_smokegrenade.cpp | 10 +- regamedll/dlls/wpn_shared/wpn_usp.cpp | 4 +- regamedll/game_shared/bot/bot.cpp | 8 +- regamedll/game_shared/bot/bot_manager.cpp | 2 +- regamedll/game_shared/bot/bot_profile.cpp | 7 +- regamedll/game_shared/bot/bot_util.cpp | 4 +- regamedll/game_shared/bot/nav_area.cpp | 4 +- regamedll/game_shared/bot/nav_file.cpp | 11 +- regamedll/pm_shared/pm_shared.cpp | 5 +- regamedll/public/strtools.h | 34 +++-- regamedll/unittests/mathfun_tests.cpp | 4 +- 40 files changed, 268 insertions(+), 365 deletions(-) diff --git a/regamedll/dlls/bot/cs_bot_init.cpp b/regamedll/dlls/bot/cs_bot_init.cpp index a6503e901..1bf7aec00 100644 --- a/regamedll/dlls/bot/cs_bot_init.cpp +++ b/regamedll/dlls/bot/cs_bot_init.cpp @@ -332,7 +332,7 @@ void CCSBot::SpawnBot() TheCSBots()->ValidateMapData(); ResetValues(); - Q_strcpy(m_name, STRING(pev->netname)); + Q_strlcpy(m_name, STRING(pev->netname)); SetState(&m_buyState); SetTouch(&CCSBot::BotTouch); diff --git a/regamedll/dlls/bot/cs_bot_learn.cpp b/regamedll/dlls/bot/cs_bot_learn.cpp index 76edded7a..3cf041e31 100644 --- a/regamedll/dlls/bot/cs_bot_learn.cpp +++ b/regamedll/dlls/bot/cs_bot_learn.cpp @@ -477,14 +477,14 @@ void CCSBot::StartSaveProcess() void CCSBot::UpdateSaveProcess() { - char filename[256]; char msg[256]; char cmd[128]; - GET_GAME_DIR(filename); + char gd[64]{}; + GET_GAME_DIR(gd); - Q_strcat(filename, "\\"); - Q_strcat(filename, TheBots->GetNavMapFilename()); + char filename[MAX_OSPATH]; + Q_snprintf(filename, sizeof(filename), "%s\\%s", gd, TheBots->GetNavMapFilename()); HintMessageToAllPlayers("Saving..."); SaveNavigationMap(filename); diff --git a/regamedll/dlls/bot/cs_bot_manager.cpp b/regamedll/dlls/bot/cs_bot_manager.cpp index b4391be7f..5656667bf 100644 --- a/regamedll/dlls/bot/cs_bot_manager.cpp +++ b/regamedll/dlls/bot/cs_bot_manager.cpp @@ -578,14 +578,16 @@ void CCSBotManager::ServerCommand(const char *pcmd) } else if (FStrEq(pcmd, "bot_nav_save")) { - GET_GAME_DIR(buffer); - Q_strcat(buffer, "\\"); - Q_strcat(buffer, CBotManager::GetNavMapFilename()); + char gd[64]{}; + GET_GAME_DIR(gd); - if (SaveNavigationMap(buffer)) - CONSOLE_ECHO("Navigation map '%s' saved.\n", buffer); + char filename[MAX_OSPATH]; + Q_snprintf(filename, sizeof(filename), "%s\\%s", gd, CBotManager::GetNavMapFilename()); + + if (SaveNavigationMap(filename)) + CONSOLE_ECHO("Navigation map '%s' saved.\n", filename); else - CONSOLE_ECHO("ERROR: Cannot save navigation map '%s'.\n", buffer); + CONSOLE_ECHO("ERROR: Cannot save navigation map '%s'.\n", filename); } else if (FStrEq(pcmd, "bot_nav_load")) { diff --git a/regamedll/dlls/client.cpp b/regamedll/dlls/client.cpp index 3fe161c62..bc223ed7d 100644 --- a/regamedll/dlls/client.cpp +++ b/regamedll/dlls/client.cpp @@ -465,7 +465,7 @@ NOXREF int CountTeams() void ListPlayers(CBasePlayer *current) { - char message[120] = "", cNumber[12]; + char message[120]{}; CBaseEntity *pEntity = nullptr; while ((pEntity = UTIL_FindEntityByClassname(pEntity, "player"))) @@ -479,12 +479,7 @@ void ListPlayers(CBasePlayer *current) CBasePlayer *pPlayer = GetClassPtr((CBasePlayer *)pEntity->pev); int iUserID = GETPLAYERUSERID(ENT(pPlayer->pev)); - Q_sprintf(cNumber, "%d", iUserID); - Q_strcpy(message, "\n"); - Q_strcat(message, cNumber); - Q_strcat(message, " : "); - Q_strcat(message, STRING(pPlayer->pev->netname)); - + Q_snprintf(message, sizeof(message), "\n%d : %s", iUserID, STRING(pPlayer->pev->netname)); ClientPrint(current->pev, HUD_PRINTCONSOLE, message); } @@ -738,8 +733,8 @@ void EXT_FUNC ClientPutInServer(edict_t *pEntity) pPlayer->m_iJoiningState = SHOWLTEXT; - static char sName[128]; - Q_strcpy(sName, STRING(pPlayer->pev->netname)); + char sName[128]; + Q_strlcpy(sName, STRING(pPlayer->pev->netname)); for (char *pApersand = sName; pApersand && *pApersand != '\0'; pApersand++) { @@ -797,12 +792,12 @@ void Host_Say(edict_t *pEntity, BOOL teamonly) { if (CMD_ARGC_() >= 2) { - Q_sprintf(szTemp, "%s %s", pcmd, CMD_ARGS()); + Q_snprintf(szTemp, sizeof(szTemp), "%s %s", pcmd, CMD_ARGS()); } else { // Just a one word command, use the first word...sigh - Q_sprintf(szTemp, "%s", pcmd); + Q_snprintf(szTemp, sizeof(szTemp), "%s", pcmd); } p = szTemp; @@ -967,8 +962,8 @@ void Host_Say(edict_t *pEntity, BOOL teamonly) } } - Q_strcat(text, p); - Q_strcat(text, "\n"); + Q_strlcat(text, p); + Q_strlcat(text, "\n"); // loop through all players // Start with the first player. @@ -4993,7 +4988,7 @@ void EXT_FUNC UpdateClientData(const edict_t *ent, int sendweapons, struct clien cd->flSwimTime = pev->flSwimTime; cd->waterjumptime = int(pev->teleport_time); - Q_strcpy(cd->physinfo, ENGINE_GETPHYSINFO(ent)); + Q_strlcpy(cd->physinfo, ENGINE_GETPHYSINFO(ent)); cd->maxspeed = pev->maxspeed; cd->fov = pev->fov; @@ -5204,8 +5199,10 @@ int EXT_FUNC InconsistentFile(const edict_t *pEdict, const char *filename, char if (!CVAR_GET_FLOAT("mp_consistency")) return 0; + const int BufferLen = 256; + // Default behavior is to kick the player - Q_sprintf(disconnect_message, "Server is enforcing file consistency for %s\n", filename); + Q_snprintf(disconnect_message, BufferLen, "Server is enforcing file consistency for %s\n", filename); // Kick now with specified disconnect message. return 1; diff --git a/regamedll/dlls/debug.cpp b/regamedll/dlls/debug.cpp index 82d50d71d..81605143d 100644 --- a/regamedll/dlls/debug.cpp +++ b/regamedll/dlls/debug.cpp @@ -27,7 +27,7 @@ NOXREF void UTIL_DPrintf(DebugOutputType outputType, char *pszMsg, ...) { va_list argptr; va_start(argptr, pszMsg); - vsprintf(theDebugBuffer, pszMsg, argptr); + Q_vsnprintf(theDebugBuffer, sizeof(theDebugBuffer), pszMsg, argptr); va_end(argptr); SERVER_PRINT(theDebugBuffer); @@ -41,7 +41,7 @@ void UTIL_DPrintf(char *pszMsg, ...) va_list argptr; va_start(argptr, pszMsg); - vsprintf(theDebugBuffer, pszMsg, argptr); + Q_vsnprintf(theDebugBuffer, sizeof(theDebugBuffer), pszMsg, argptr); va_end(argptr); SERVER_PRINT(theDebugBuffer); @@ -130,7 +130,7 @@ NOXREF void UTIL_BotDPrintf(char *pszMsg, ...) { va_list argptr; va_start(argptr, pszMsg); - vsprintf(theDebugBuffer, pszMsg, argptr); + Q_vsnprintf(theDebugBuffer, sizeof(theDebugBuffer), pszMsg, argptr); va_end(argptr); SERVER_PRINT(theDebugBuffer); @@ -146,7 +146,7 @@ void UTIL_CareerDPrintf(char *pszMsg, ...) { va_list argptr; va_start(argptr, pszMsg); - vsprintf(theDebugBuffer, pszMsg, argptr); + Q_vsnprintf(theDebugBuffer, sizeof(theDebugBuffer), pszMsg, argptr); va_end(argptr); SERVER_PRINT(theDebugBuffer); @@ -162,7 +162,7 @@ NOXREF void UTIL_TutorDPrintf(char *pszMsg, ...) { va_list argptr; va_start(argptr, pszMsg); - vsprintf(theDebugBuffer, pszMsg, argptr); + Q_vsnprintf(theDebugBuffer, sizeof(theDebugBuffer), pszMsg, argptr); va_end(argptr); SERVER_PRINT(theDebugBuffer); @@ -178,7 +178,7 @@ NOXREF void UTIL_StatsDPrintf(char *pszMsg, ...) { va_list argptr; va_start(argptr, pszMsg); - vsprintf(theDebugBuffer, pszMsg, argptr); + Q_vsnprintf(theDebugBuffer, sizeof(theDebugBuffer), pszMsg, argptr); va_end(argptr); SERVER_PRINT(theDebugBuffer); @@ -194,7 +194,7 @@ NOXREF void UTIL_HostageDPrintf(char *pszMsg, ...) { va_list argptr; va_start(argptr, pszMsg); - vsprintf(theDebugBuffer, pszMsg, argptr); + Q_vsnprintf(theDebugBuffer, sizeof(theDebugBuffer), pszMsg, argptr); va_end(argptr); SERVER_PRINT(theDebugBuffer); diff --git a/regamedll/dlls/explode.cpp b/regamedll/dlls/explode.cpp index 104d84720..6d1c7ccd4 100644 --- a/regamedll/dlls/explode.cpp +++ b/regamedll/dlls/explode.cpp @@ -201,7 +201,7 @@ void ExplosionCreate(const Vector ¢er, Vector &angles, edict_t *pOwner, int CBaseEntity *pExplosion = CBaseEntity::Create("env_explosion", center, angles, pOwner); - Q_sprintf(buf, "%3d", magnitude); + Q_snprintf(buf, sizeof(buf), "%3d", magnitude); kvd.szKeyName = "iMagnitude"; kvd.szValue = buf; diff --git a/regamedll/dlls/gamerules.cpp b/regamedll/dlls/gamerules.cpp index 45210e212..3d9f14182 100644 --- a/regamedll/dlls/gamerules.cpp +++ b/regamedll/dlls/gamerules.cpp @@ -8,8 +8,8 @@ CGameRules::CGameRules() m_bBombDropped = FALSE; m_bGameOver = false; - m_GameDesc = new char[sizeof("Counter-Strike")]; - Q_strcpy(m_GameDesc, AreRunningCZero() ? "Condition Zero" : "Counter-Strike"); + const char *pszGameDesc = AreRunningCZero() ? "Condition Zero" : "Counter-Strike"; + m_GameDesc = CloneString(pszGameDesc); } CGameRules::~CGameRules() diff --git a/regamedll/dlls/gamerules.h b/regamedll/dlls/gamerules.h index a4f556ab9..220e09556 100644 --- a/regamedll/dlls/gamerules.h +++ b/regamedll/dlls/gamerules.h @@ -1009,5 +1009,4 @@ char *GetTeam(int team); void DestroyMapCycle(mapcycle_t *cycle); int ReloadMapCycleFile(char *filename, mapcycle_t *cycle); int CountPlayers(); -void ExtractCommandString(char *s, char *szCommand); int GetMapCount(); diff --git a/regamedll/dlls/hostage/hostage_improv.cpp b/regamedll/dlls/hostage/hostage_improv.cpp index 9cdba7777..6932d2185 100644 --- a/regamedll/dlls/hostage/hostage_improv.cpp +++ b/regamedll/dlls/hostage/hostage_improv.cpp @@ -1605,9 +1605,9 @@ void CHostageImprov::Afraid() int which = RANDOM_LONG(0, 100) % 3 + 1; - Q_sprintf(animInto, "cower_into_%d", which); - Q_sprintf(animLoop, "cower_loop_%d", which); - Q_sprintf(animExit, "cower_exit_%d", which); + Q_snprintf(animInto, sizeof(animInto), "cower_into_%d", which); + Q_snprintf(animLoop, sizeof(animLoop), "cower_loop_%d", which); + Q_snprintf(animExit, sizeof(animExit), "cower_exit_%d", which); m_animateState.AddSequence(this, animInto); m_animateState.AddSequence(this, animLoop, RANDOM_FLOAT(3, 10)); diff --git a/regamedll/dlls/items.cpp b/regamedll/dlls/items.cpp index 03620e362..ba138e044 100644 --- a/regamedll/dlls/items.cpp +++ b/regamedll/dlls/items.cpp @@ -237,7 +237,7 @@ BOOL CItemBattery::MyTouch(CBasePlayer *pPlayer) pct--; char szcharge[64]; - Q_sprintf(szcharge, "!HEV_%1dP", pct); + Q_snprintf(szcharge, sizeof(szcharge), "!HEV_%1dP", pct); pPlayer->SetSuitUpdate(szcharge, SUIT_SENTENCE, SUIT_NEXT_IN_30SEC); return TRUE; diff --git a/regamedll/dlls/lights.cpp b/regamedll/dlls/lights.cpp index d44cddcc1..aa8629ea0 100644 --- a/regamedll/dlls/lights.cpp +++ b/regamedll/dlls/lights.cpp @@ -129,11 +129,11 @@ void CEnvLight::KeyValue(KeyValueData *pkvd) pkvd->fHandled = TRUE; char szColor[64]; - Q_sprintf(szColor, "%d", r); + Q_snprintf(szColor, sizeof(szColor), "%d", r); CVAR_SET_STRING("sv_skycolor_r", szColor); - Q_sprintf(szColor, "%d", g); + Q_snprintf(szColor, sizeof(szColor), "%d", g); CVAR_SET_STRING("sv_skycolor_g", szColor); - Q_sprintf(szColor, "%d", b); + Q_snprintf(szColor, sizeof(szColor), "%d", b); CVAR_SET_STRING("sv_skycolor_b", szColor); } else @@ -147,13 +147,13 @@ void CEnvLight::Spawn() char szVector[64]; UTIL_MakeAimVectors(pev->angles); - Q_sprintf(szVector, "%f", gpGlobals->v_forward.x); + Q_snprintf(szVector, sizeof(szVector), "%f", gpGlobals->v_forward.x); CVAR_SET_STRING("sv_skyvec_x", szVector); - Q_sprintf(szVector, "%f", gpGlobals->v_forward.y); + Q_snprintf(szVector, sizeof(szVector), "%f", gpGlobals->v_forward.y); CVAR_SET_STRING("sv_skyvec_y", szVector); - Q_sprintf(szVector, "%f", gpGlobals->v_forward.z); + Q_snprintf(szVector, sizeof(szVector), "%f", gpGlobals->v_forward.z); CVAR_SET_STRING("sv_skyvec_z", szVector); CLight::Spawn(); diff --git a/regamedll/dlls/multiplay_gamerules.cpp b/regamedll/dlls/multiplay_gamerules.cpp index 8ba46556d..7a84afd46 100644 --- a/regamedll/dlls/multiplay_gamerules.cpp +++ b/regamedll/dlls/multiplay_gamerules.cpp @@ -178,15 +178,12 @@ bool CCStrikeGameMgrHelper::GetCanHearPlayer(CBasePlayer* pListener, CBasePlayer void Broadcast(const char *sentence) { - char text[32]; + char text[128]; if (!sentence) - { return; - } - Q_strcpy(text, "%!MRAD_"); - Q_strcat(text, UTIL_VarArgs("%s", sentence)); + Q_snprintf(text, sizeof(text), "%%!MRAD_%s", sentence); MESSAGE_BEGIN(MSG_BROADCAST, gmsgSendAudio); WRITE_BYTE(0); @@ -507,7 +504,7 @@ CHalfLifeMultiplay::CHalfLifeMultiplay() char szCommand[256]; ALERT(at_console, "Executing listen server config file\n"); - Q_sprintf(szCommand, "exec %s\n", lservercfgfile); + Q_snprintf(szCommand, sizeof(szCommand), "exec %s\n", lservercfgfile); SERVER_COMMAND(szCommand); } } @@ -4554,12 +4551,7 @@ int ReloadMapCycleFile(char *filename, mapcycle_t *cycle) if (Q_strlen(pToken) <= 0) break; -#ifdef REGAMEDLL_FIXES - Q_strncpy(szMap, pToken, sizeof(szMap) - 1); - szMap[sizeof(szMap) - 1] = '\0'; -#else - Q_strcpy(szMap, pToken); -#endif + Q_strlcpy(szMap, pToken); // Any more tokens on this line? if (SharedTokenWaiting(pFileList)) @@ -4568,7 +4560,7 @@ int ReloadMapCycleFile(char *filename, mapcycle_t *cycle) if (Q_strlen(pToken) > 0) { hasBuffer = true; - Q_strcpy(szBuffer, pToken); + Q_strlcpy(szBuffer, pToken); } } @@ -4580,7 +4572,7 @@ int ReloadMapCycleFile(char *filename, mapcycle_t *cycle) item = new mapcycle_item_s; - Q_strcpy(item->mapname, szMap); + Q_strlcpy(item->mapname, szMap); item->minplayers = 0; item->maxplayers = 0; @@ -4610,7 +4602,7 @@ int ReloadMapCycleFile(char *filename, mapcycle_t *cycle) REMOVE_KEY_VALUE(szBuffer, "minplayers"); REMOVE_KEY_VALUE(szBuffer, "maxplayers"); - Q_strcpy(item->rulebuffer, szBuffer); + Q_strlcpy(item->rulebuffer, szBuffer); } item->next = cycle->items; @@ -4675,7 +4667,7 @@ int CountPlayers() } // Parse commands/key value pairs to issue right after map xxx command is issued on server level transition -void ExtractCommandString(char *s, char *szCommand) +void ExtractCommandString(char *s, char *szCommand, size_t len) { // Now make rules happen char pkey[512]; @@ -4744,13 +4736,13 @@ void ExtractCommandString(char *s, char *szCommand) *c = '\0'; - Q_strcat(szCommand, pkey); + Q_strlcat(szCommand, pkey, len); if (Q_strlen(value) > 0) { - Q_strcat(szCommand, " "); - Q_strcat(szCommand, value); + Q_strlcat(szCommand, " ", len); + Q_strlcat(szCommand, value, len); } - Q_strcat(szCommand, "\n"); + Q_strlcat(szCommand, "\n", len); /*if (!*s) { @@ -4937,10 +4929,10 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(ChangeLevel)() #ifdef REGAMEDLL_FIXES // the absolute default level is de_dust - Q_strcpy(szFirstMapInList, "de_dust"); + Q_strlcpy(szFirstMapInList, "de_dust"); #else // the absolute default level is hldm1 - Q_strcpy(szFirstMapInList, "hldm1"); + Q_strlcpy(szFirstMapInList, "hldm1"); #endif int curplayers; @@ -4958,7 +4950,7 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(ChangeLevel)() // Has the map cycle filename changed? if (Q_stricmp(mapcfile, szPreviousMapCycleFile) != 0) { - Q_strcpy(szPreviousMapCycleFile, mapcfile); + Q_strlcpy(szPreviousMapCycleFile, mapcfile); DestroyMapCycle(&mapcycle); @@ -4976,8 +4968,8 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(ChangeLevel)() mapcycle_item_s *item; // Assume current map - Q_strcpy(szNextMap, STRING(gpGlobals->mapname)); - Q_strcpy(szFirstMapInList, STRING(gpGlobals->mapname)); + Q_strlcpy(szNextMap, STRING(gpGlobals->mapname)); + Q_strlcpy(szFirstMapInList, STRING(gpGlobals->mapname)); // Traverse list for (item = mapcycle.next_item; item->next != mapcycle.next_item; item = item->next) @@ -5030,14 +5022,14 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(ChangeLevel)() mapcycle.next_item = item->next; // Perform logic on current item - Q_strcpy(szNextMap, item->mapname); - ExtractCommandString(item->rulebuffer, szCommands); - Q_strcpy(szRules, item->rulebuffer); + Q_strlcpy(szNextMap, item->mapname); + ExtractCommandString(item->rulebuffer, szCommands, sizeof(szCommands)); + Q_strlcpy(szRules, item->rulebuffer); } if (!IS_MAP_VALID(szNextMap)) { - Q_strcpy(szNextMap, szFirstMapInList); + Q_strlcpy(szNextMap, szFirstMapInList); } m_bGameOver = true; @@ -5077,17 +5069,7 @@ void CHalfLifeMultiplay::SendMOTDToClient(edict_t *client) while (pFileList && *pFileList && char_count < MAX_MOTD_LENGTH) { char chunk[MAX_MOTD_CHUNK + 1]; - - if (Q_strlen(pFileList) < sizeof(chunk)) - { - Q_strcpy(chunk, pFileList); - } - else - { - Q_strncpy(chunk, pFileList, sizeof(chunk) - 1); - // Q_strncpy doesn't always append the null terminator - chunk[sizeof(chunk) - 1] = '\0'; - } + Q_strlcpy(chunk, pFileList); char_count += Q_strlen(chunk); diff --git a/regamedll/dlls/observer.cpp b/regamedll/dlls/observer.cpp index 4b3521a6c..3ccefc433 100644 --- a/regamedll/dlls/observer.cpp +++ b/regamedll/dlls/observer.cpp @@ -480,14 +480,14 @@ void EXT_FUNC CBasePlayer::__API_HOOK(Observer_SetMode)(int iMode) { #ifdef REGAMEDLL_FIXES m_hObserverTarget = Observer_IsValidTarget( ENTINDEX(m_hObserverTarget->edict()), forcecamera != CAMERA_MODE_SPEC_ANYONE ); -#else +#else CBasePlayer *pTarget = m_hObserverTarget; - if (pTarget == this - || !pTarget - || pTarget->has_disconnected - || pTarget->GetObserverMode() != OBS_NONE - || (pTarget->pev->effects & EF_NODRAW) + if (pTarget == this + || !pTarget + || pTarget->has_disconnected + || pTarget->GetObserverMode() != OBS_NONE + || (pTarget->pev->effects & EF_NODRAW) || (forcecamera != CAMERA_MODE_SPEC_ANYONE && pTarget->m_iTeam != m_iTeam)) m_hObserverTarget = nullptr; #endif @@ -534,7 +534,7 @@ void EXT_FUNC CBasePlayer::__API_HOOK(Observer_SetMode)(int iMode) // print spepctaor mode on client screen char modemsg[16]; - Q_sprintf(modemsg, "#Spec_Mode%i", pev->iuser1); + Q_snprintf(modemsg, sizeof(modemsg), "#Spec_Mode%i", pev->iuser1); ClientPrint(pev, HUD_PRINTCENTER, modemsg); m_iObserverLastMode = iMode; @@ -548,4 +548,4 @@ void EXT_FUNC CBasePlayer::__API_HOOK(Observer_Think)() Observer_HandleButtons(); Observer_CheckTarget(); Observer_CheckProperties(); -} \ No newline at end of file +} diff --git a/regamedll/dlls/player.cpp b/regamedll/dlls/player.cpp index c297d827e..8ece842e2 100644 --- a/regamedll/dlls/player.cpp +++ b/regamedll/dlls/player.cpp @@ -2556,11 +2556,19 @@ BOOL CBasePlayer::IsBombGuy() LINK_HOOK_CLASS_VOID_CHAIN(CBasePlayer, SetAnimation, (PLAYER_ANIM playerAnim), playerAnim) +int CBasePlayer::GetAnimDesired(const char *szAnim, AnimationType type) +{ + const char *refAnim = (type == ANIM_CROUCH && (pev->flags & FL_DUCKING)) ? "crouch_" : "ref_"; + + char szAnimConstruct[128]; + Q_snprintf(szAnimConstruct, sizeof(szAnimConstruct), "%s%s_%s", refAnim, szAnim, m_szAnimExtention); + return LookupSequence(szAnimConstruct); +} + void EXT_FUNC CBasePlayer::__API_HOOK(SetAnimation)(PLAYER_ANIM playerAnim) { int animDesired; float speed; - char szAnim[64]; int hopSeq; int leapSeq; @@ -2696,16 +2704,17 @@ void EXT_FUNC CBasePlayer::__API_HOOK(SetAnimation)(PLAYER_ANIM playerAnim) if (m_Activity == m_IdealActivity) return; + const char *refAnim; + switch (m_Activity) { - case ACT_RANGE_ATTACK1: Q_strcpy(szAnim, "ref_shoot_"); break; - case ACT_RANGE_ATTACK2: Q_strcpy(szAnim, "ref_shoot2_"); break; - case ACT_RELOAD: Q_strcpy(szAnim, "ref_reload_"); break; - default: Q_strcpy(szAnim, "ref_aim_"); break; + case ACT_RANGE_ATTACK1: refAnim = "shoot"; break; + case ACT_RANGE_ATTACK2: refAnim = "shoot2"; break; + case ACT_RELOAD: refAnim = "reload"; break; + default: refAnim = "aim"; break; } - Q_strcat(szAnim, m_szAnimExtention); - animDesired = LookupSequence(szAnim); + animDesired = GetAnimDesired(refAnim, ANIM_NORMAL); if (animDesired == -1) animDesired = 0; @@ -2727,13 +2736,7 @@ void EXT_FUNC CBasePlayer::__API_HOOK(SetAnimation)(PLAYER_ANIM playerAnim) { m_flLastFired = gpGlobals->time; - if (pev->flags & FL_DUCKING) - Q_strcpy(szAnim, "crouch_shoot_"); - else - Q_strcpy(szAnim, "ref_shoot_"); - - Q_strcat(szAnim, m_szAnimExtention); - animDesired = LookupSequence(szAnim); + animDesired = GetAnimDesired("shoot", ANIM_CROUCH); if (animDesired == -1) animDesired = 0; @@ -2748,13 +2751,7 @@ void EXT_FUNC CBasePlayer::__API_HOOK(SetAnimation)(PLAYER_ANIM playerAnim) { m_flLastFired = gpGlobals->time; - if (pev->flags & FL_DUCKING) - Q_strcpy(szAnim, "crouch_shoot2_"); - else - Q_strcpy(szAnim, "ref_shoot2_"); - - Q_strcat(szAnim, m_szAnimExtention); - animDesired = LookupSequence(szAnim); + animDesired = GetAnimDesired("shoot2", ANIM_CROUCH); if (animDesired == -1) animDesired = 0; @@ -2767,13 +2764,7 @@ void EXT_FUNC CBasePlayer::__API_HOOK(SetAnimation)(PLAYER_ANIM playerAnim) } case ACT_RELOAD: { - if (pev->flags & FL_DUCKING) - Q_strcpy(szAnim, "crouch_reload_"); - else - Q_strcpy(szAnim, "ref_reload_"); - - Q_strcat(szAnim, m_szAnimExtention); - animDesired = LookupSequence(szAnim); + animDesired = GetAnimDesired("reload", ANIM_CROUCH); if (animDesired == -1) animDesired = 0; @@ -2788,13 +2779,7 @@ void EXT_FUNC CBasePlayer::__API_HOOK(SetAnimation)(PLAYER_ANIM playerAnim) } case ACT_HOLDBOMB: { - if (pev->flags & FL_DUCKING) - Q_strcpy(szAnim, "crouch_aim_"); - else - Q_strcpy(szAnim, "ref_aim_"); - - Q_strcat(szAnim, m_szAnimExtention); - animDesired = LookupSequence(szAnim); + animDesired = GetAnimDesired("aim", ANIM_CROUCH); if (animDesired == -1) animDesired = 0; @@ -2811,13 +2796,7 @@ void EXT_FUNC CBasePlayer::__API_HOOK(SetAnimation)(PLAYER_ANIM playerAnim) { if (speed <= 135.0f || m_flLastFired + 4.0 >= gpGlobals->time) { - if (pev->flags & FL_DUCKING) - Q_strcpy(szAnim, "crouch_aim_"); - else - Q_strcpy(szAnim, "ref_aim_"); - - Q_strcat(szAnim, m_szAnimExtention); - animDesired = LookupSequence(szAnim); + animDesired = GetAnimDesired("aim", ANIM_CROUCH); if (animDesired == -1) animDesired = 0; @@ -2825,18 +2804,10 @@ void EXT_FUNC CBasePlayer::__API_HOOK(SetAnimation)(PLAYER_ANIM playerAnim) } else { - Q_strcpy(szAnim, "run_"); - Q_strcat(szAnim, m_szAnimExtention); - animDesired = LookupSequence(szAnim); + animDesired = GetAnimDesired("run", ANIM_NORMAL); if (animDesired == -1) { - if (pev->flags & FL_DUCKING) - Q_strcpy(szAnim, "crouch_aim_"); - else - Q_strcpy(szAnim, "ref_aim_"); - - Q_strcat(szAnim, m_szAnimExtention); - animDesired = LookupSequence(szAnim); + animDesired = GetAnimDesired("aim", ANIM_CROUCH); if (animDesired == -1) animDesired = 0; @@ -3086,20 +3057,9 @@ void EXT_FUNC CBasePlayer::__API_HOOK(SetAnimation)(PLAYER_ANIM playerAnim) { if (m_Activity != ACT_FLINCH && m_Activity != ACT_LARGE_FLINCH) { - Q_strcpy(szAnim, "run_"); - Q_strcat(szAnim, m_szAnimExtention); - - animDesired = LookupSequence(szAnim); + animDesired = GetAnimDesired("run", ANIM_NORMAL); if (animDesired == -1) - { - if (pev->flags & FL_DUCKING) - Q_strcpy(szAnim, "crouch_aim_"); - else - Q_strcpy(szAnim, "ref_aim_"); - - Q_strcat(szAnim, m_szAnimExtention); - animDesired = LookupSequence(szAnim); - } + animDesired = GetAnimDesired("aim", ANIM_CROUCH); else pev->gaitsequence = animDesired; @@ -5047,8 +5007,7 @@ void CBasePlayer::CheckSuitUpdate() { // play sentence number char sentence[MAX_SENTENCE_NAME + 1]; - Q_strcpy(sentence, "!"); - Q_strcat(sentence, gszallsentencenames[isentence]); + Q_snprintf(sentence, sizeof(sentence), "!%s", gszallsentencenames[isentence]); EMIT_SOUND_SUIT(ENT(pev), sentence); } else @@ -8074,7 +8033,7 @@ void CBasePlayer::UpdateStatusBar() char sbuf0[MAX_SBAR_STRING]; Q_memset(newSBarState, 0, sizeof(newSBarState)); - Q_strcpy(sbuf0, m_SbarString0); + Q_strlcpy(sbuf0, m_SbarString0); // Find an ID Target TraceResult tr; @@ -8104,9 +8063,9 @@ void CBasePlayer::UpdateStatusBar() if (sameTeam || GetObserverMode() != OBS_NONE) { if (playerid.value != PLAYERID_MODE_OFF || GetObserverMode() != OBS_NONE) - Q_strcpy(sbuf0, "1 %c1: %p2\n2 %h: %i3%%"); + Q_strlcpy(sbuf0, "1 %c1: %p2\n2 %h: %i3%%"); else - Q_strcpy(sbuf0, " "); + Q_strlcpy(sbuf0, " "); newSBarState[SBAR_ID_TARGETHEALTH] = int((pEntity->pev->health / pEntity->pev->max_health) * 100); @@ -8119,9 +8078,9 @@ void CBasePlayer::UpdateStatusBar() else if (GetObserverMode() == OBS_NONE) { if (playerid.value != PLAYERID_MODE_TEAMONLY && playerid.value != PLAYERID_MODE_OFF) - Q_strcpy(sbuf0, "1 %c1: %p2"); + Q_strlcpy(sbuf0, "1 %c1: %p2"); else - Q_strcpy(sbuf0, " "); + Q_strlcpy(sbuf0, " "); if (!(m_flDisplayHistory & DHF_ENEMY_SEEN)) { @@ -8135,9 +8094,9 @@ void CBasePlayer::UpdateStatusBar() else if (pEntity->Classify() == CLASS_HUMAN_PASSIVE) { if (playerid.value != PLAYERID_MODE_OFF || GetObserverMode() != OBS_NONE) - Q_strcpy(sbuf0, "1 %c1 %h: %i3%%"); + Q_strlcpy(sbuf0, "1 %c1 %h: %i3%%"); else - Q_strcpy(sbuf0, " "); + Q_strlcpy(sbuf0, " "); newSBarState[SBAR_ID_TARGETTYPE] = SBAR_TARGETTYPE_HOSTAGE; newSBarState[SBAR_ID_TARGETHEALTH] = int((pEntity->pev->health / pEntity->pev->max_health) * 100); @@ -8179,7 +8138,7 @@ void CBasePlayer::UpdateStatusBar() WRITE_STRING(sbuf0); MESSAGE_END(); - Q_strcpy(m_SbarString0, sbuf0); + Q_strlcpy(m_SbarString0, sbuf0); // make sure everything's resent bForceResend = true; @@ -9370,14 +9329,10 @@ void CBasePlayer::AddAutoBuyData(const char *str) { if (len > 0) { - Q_strncat(m_autoBuyString, " ", len); + Q_strlcat(m_autoBuyString, " "); } -#ifndef REGAMEDLL_FIXES - Q_strncat(m_autoBuyString, str, sizeof(m_autoBuyString) - Q_strlen(m_autoBuyString)); -#else - Q_strncat(m_autoBuyString, str, sizeof(m_autoBuyString) - Q_strlen(m_autoBuyString) - 1); -#endif + Q_strlcat(m_autoBuyString, str); } } @@ -9394,9 +9349,7 @@ void CBasePlayer::InitRebuyData(const char *str) m_rebuyString = nullptr; } - m_rebuyString = new char[Q_strlen(str) + 1]; - Q_strcpy(m_rebuyString, str); - m_rebuyString[Q_strlen(str)] = '\0'; + m_rebuyString = CloneString(str); } void CBasePlayer::AutoBuy() @@ -9424,7 +9377,7 @@ void CBasePlayer::AutoBuy() if (c) { - Q_strcpy(prioritizedString, c); + Q_strlcpy(prioritizedString, c); PrioritizeAutoBuyString(prioritizedString, m_autoBuyString); ParseAutoBuyString(prioritizedString, boughtPrimary, boughtSecondary); @@ -9434,7 +9387,7 @@ void CBasePlayer::AutoBuy() if (c) { - Q_strcpy(prioritizedString, c); + Q_strlcpy(prioritizedString, c); PrioritizeAutoBuyString(prioritizedString, m_autoBuyString); ParseAutoBuyString(prioritizedString, boughtPrimary, boughtSecondary); @@ -9582,11 +9535,11 @@ const char *CBasePlayer::PickPrimaryCareerTaskWeapon() CCareerTask *pTask = taskVector[i]; if (IsPrimaryWeaponId(pTask->GetWeaponId())) - Q_strncat(buf, WeaponIDToAlias(pTask->GetWeaponId()), sizeof(buf) - Q_strlen(buf) - 1); + Q_strlcat(buf, WeaponIDToAlias(pTask->GetWeaponId())); else - Q_strncat(buf, GetBuyStringForWeaponClass(pTask->GetWeaponClassId()), sizeof(buf) - Q_strlen(buf) - 1); + Q_strlcat(buf, GetBuyStringForWeaponClass(pTask->GetWeaponClassId())); - Q_strncat(buf, " ", sizeof(buf) - Q_strlen(buf) - 1); + Q_strlcat(buf, " "); } return buf; @@ -9657,11 +9610,11 @@ const char *CBasePlayer::PickSecondaryCareerTaskWeapon() CCareerTask *pTask = taskVector[i]; if (IsSecondaryWeaponId(pTask->GetWeaponId())) - Q_strncat(buf, WeaponIDToAlias(pTask->GetWeaponId()), sizeof(buf) - Q_strlen(buf) - 1); + Q_strlcat(buf, WeaponIDToAlias(pTask->GetWeaponId())); else - Q_strncat(buf, GetBuyStringForWeaponClass(pTask->GetWeaponClassId()), sizeof(buf) - Q_strlen(buf) - 1); + Q_strlcat(buf, GetBuyStringForWeaponClass(pTask->GetWeaponClassId())); - Q_strncat(buf, " ", sizeof(buf) - Q_strlen(buf) - 1); + Q_strlcat(buf, " "); } return buf; @@ -9710,7 +9663,7 @@ const char *CBasePlayer::PickGrenadeKillWeaponString() } // PostAutoBuyCommandProcessing - reorders the tokens in autobuyString based on the order of tokens in the priorityString. -void CBasePlayer::PrioritizeAutoBuyString(char *autobuyString, const char *priorityString) +void CBasePlayer::PrioritizeAutoBuyString(char (&autobuyString)[MAX_AUTOBUY_LENGTH], const char *priorityString) { char newString[MAX_AUTOBUY_LENGTH]; int newStringPos = 0; @@ -9783,7 +9736,7 @@ void CBasePlayer::PrioritizeAutoBuyString(char *autobuyString, const char *prior // terminate the string. Trailing spaces shouldn't matter. newString[newStringPos] = '\0'; - Q_sprintf(autobuyString, "%s", newString); + Q_snprintf(autobuyString, sizeof(autobuyString), "%s", newString); } void CBasePlayer::ParseAutoBuyString(const char *string, bool &boughtPrimary, bool &boughtSecondary) diff --git a/regamedll/dlls/player.h b/regamedll/dlls/player.h index 182c4a379..b13c2c820 100644 --- a/regamedll/dlls/player.h +++ b/regamedll/dlls/player.h @@ -522,7 +522,9 @@ class CBasePlayer: public CBaseMonster { void UpdatePlayerSound(); void DeathSound(); void SetAnimation(PLAYER_ANIM playerAnim); - void SetWeaponAnimType(const char *szExtention) { Q_strcpy(m_szAnimExtention, szExtention); } + enum AnimationType { ANIM_NORMAL, ANIM_CROUCH }; + int GetAnimDesired(const char *szAnim, AnimationType type); + void SetWeaponAnimType(const char *szExtention) { Q_strlcpy(m_szAnimExtention, szExtention); } void CheatImpulseCommands(int iImpulse); void StartDeathCam(); void StartObserver(Vector &vecPosition, Vector &vecViewAngle); @@ -602,7 +604,7 @@ class CBasePlayer: public CBaseMonster { void AddAutoBuyData(const char *str); void AutoBuy(); void ClientCommand(const char *cmd, const char *arg1 = nullptr, const char *arg2 = nullptr, const char *arg3 = nullptr); - void PrioritizeAutoBuyString(char *autobuyString, const char *priorityString); + void PrioritizeAutoBuyString(char (&autobuyString)[MAX_AUTOBUY_LENGTH], const char *priorityString); const char *PickPrimaryCareerTaskWeapon(); const char *PickSecondaryCareerTaskWeapon(); const char *PickFlashKillWeaponString(); diff --git a/regamedll/dlls/saverestore.cpp b/regamedll/dlls/saverestore.cpp index a3a55c7f6..897452c4f 100644 --- a/regamedll/dlls/saverestore.cpp +++ b/regamedll/dlls/saverestore.cpp @@ -962,8 +962,8 @@ void CGlobalState::EntityAdd(string_t globalname, string_t mapName, GLOBALESTATE pNewEntity->pNext = m_pList; m_pList = pNewEntity; - Q_strcpy(pNewEntity->name, STRING(globalname)); - Q_strcpy(pNewEntity->levelName, STRING(mapName)); + Q_strlcpy(pNewEntity->name, STRING(globalname)); + Q_strlcpy(pNewEntity->levelName, STRING(mapName)); pNewEntity->state = state; m_listCount++; @@ -1068,7 +1068,7 @@ void CGlobalState::EntityUpdate(string_t globalname, string_t mapname) globalentity_t *pEnt = Find(globalname); if (pEnt) { - Q_strcpy(pEnt->levelName, STRING(mapname)); + Q_strlcpy(pEnt->levelName, STRING(mapname)); } } diff --git a/regamedll/dlls/skill.cpp b/regamedll/dlls/skill.cpp index 87fd4468f..3c0bfe0d3 100644 --- a/regamedll/dlls/skill.cpp +++ b/regamedll/dlls/skill.cpp @@ -10,7 +10,7 @@ NOXREF float GetSkillCvar(char *pName) float flValue; char szBuffer[64]; - iCount = Q_sprintf(szBuffer, "%s%d", pName, gSkillData.iSkillLevel); + iCount = Q_snprintf(szBuffer, sizeof(szBuffer), "%s%d", pName, gSkillData.iSkillLevel); flValue = CVAR_GET_FLOAT(szBuffer); if (flValue <= 0.0f) diff --git a/regamedll/dlls/sound.cpp b/regamedll/dlls/sound.cpp index baf5353cc..a4dc0a7d6 100644 --- a/regamedll/dlls/sound.cpp +++ b/regamedll/dlls/sound.cpp @@ -1040,11 +1040,10 @@ void USENTENCEG_InitLRU(unsigned char *plru, int count) // ipick is passed in as the requested sentence ordinal. // ipick 'next' is returned. // return of -1 indicates an error. -int USENTENCEG_PickSequential(int isentenceg, char *szfound, int ipick, int freset) +int USENTENCEG_PickSequential(int isentenceg, char (&szfound)[64], int ipick, int freset) { char *szgroupname; unsigned char count; - char sznum[12]; if (!fSentencesInit) return -1; @@ -1061,10 +1060,7 @@ int USENTENCEG_PickSequential(int isentenceg, char *szfound, int ipick, int fres if (ipick >= count) ipick = count - 1; - Q_strcpy(szfound, "!"); - Q_strcat(szfound, szgroupname); - Q_snprintf(sznum, sizeof(sznum), "%d", ipick); - Q_strcat(szfound, sznum); + Q_snprintf(szfound, sizeof(szfound), "!%s%d", szgroupname, ipick); if (ipick >= count) { @@ -1084,13 +1080,12 @@ int USENTENCEG_PickSequential(int isentenceg, char *szfound, int ipick, int fres // rest of the lru filled with -1. The first integer in the lru is // actually the size of the list. Returns ipick, the ordinal // of the picked sentence within the group. -int USENTENCEG_Pick(int isentenceg, char *szfound) +int USENTENCEG_Pick(int isentenceg, char (&szfound)[64]) { char *szgroupname; unsigned char *plru; unsigned char i; unsigned char count; - char sznum[12]; unsigned char ipick = 0xFF; BOOL ffound = FALSE; @@ -1119,11 +1114,7 @@ int USENTENCEG_Pick(int isentenceg, char *szfound) if (ffound) { - Q_strcpy(szfound, "!"); - Q_strcat(szfound, szgroupname); - Q_snprintf(sznum, sizeof(sznum), "%d", ipick); - Q_strcat(szfound, sznum); - + Q_snprintf(szfound, sizeof(szfound), "!%s%d", szgroupname, ipick); return ipick; } else @@ -1168,8 +1159,6 @@ int SENTENCEG_PlayRndI(edict_t *entity, int isentenceg, float volume, float atte if (!fSentencesInit) return -1; - name[0] = '\0'; - ipick = USENTENCEG_Pick(isentenceg, name); #ifndef REGAMEDLL_FIXES @@ -1194,8 +1183,6 @@ int SENTENCEG_PlayRndSz(edict_t *entity, const char *szgroupname, float volume, if (!fSentencesInit) return -1; - name[0] = '\0'; - isentenceg = SENTENCEG_GetIndex(szgroupname); if (isentenceg < 0) { @@ -1223,8 +1210,6 @@ int SENTENCEG_PlaySequentialSz(edict_t *entity, const char *szgroupname, float v if (!fSentencesInit) return -1; - name[0] = '\0'; - isentenceg = SENTENCEG_GetIndex(szgroupname); if (isentenceg < 0) return -1; @@ -1323,7 +1308,7 @@ void SENTENCEG_Init() ALERT(at_warning, "Sentence %s longer than %d letters\n", pString, MAX_SENTENCE_NAME - 1); } - Q_strcpy(gszallsentencenames[gcallsentences++], pString); + Q_strlcpy(gszallsentencenames[gcallsentences++], pString); if (--j <= i) continue; @@ -1354,10 +1339,10 @@ void SENTENCEG_Init() break; } - Q_strcpy(rgsentenceg[isentencegs].szgroupname, &(buffer[i])); + Q_strlcpy(rgsentenceg[isentencegs].szgroupname, &(buffer[i])); rgsentenceg[isentencegs].count = 1; - Q_strcpy(szgroup, &(buffer[i])); + Q_strlcpy(szgroup, &(buffer[i])); continue; } @@ -1385,9 +1370,8 @@ void SENTENCEG_Init() } // convert sentence (sample) name to !sentencenum, return !sentencenum -int SENTENCEG_Lookup(const char *sample, char *sentencenum) +int SENTENCEG_Lookup(const char *sample, char (&sentencenum)[32]) { - char sznum[12]; int i; // this is a sentence name; lookup sentence number @@ -1398,9 +1382,7 @@ int SENTENCEG_Lookup(const char *sample, char *sentencenum) { if (sentencenum) { - Q_strcpy(sentencenum, "!"); - Q_snprintf(sznum, sizeof(sznum), "%d", i); - Q_strcat(sentencenum, sznum); + Q_snprintf(sentencenum, sizeof(sentencenum), "!%d", i); } return i; @@ -1580,7 +1562,7 @@ void TEXTURETYPE_Init() j = Q_min(j, MAX_TEXTURENAME_LENGHT - 1 + i); buffer[j] = '\0'; - Q_strcpy(&(grgszTextureName[gcTextures++][0]), &(buffer[i])); + Q_strlcpy(grgszTextureName[gcTextures++], &(buffer[i])); } FREE_FILE(pMemFile); @@ -1616,7 +1598,7 @@ float TEXTURETYPE_PlaySound(TraceResult *ptr, Vector vecSrc, Vector vecEnd, int char chTextureType; float fvol; float fvolbar; - char szBuffer[64]; + char szBuffer[MAX_TEXTURENAME_LENGHT]; const char *pTextureName; float rgfl1[3]; float rgfl2[3]; @@ -1666,8 +1648,7 @@ float TEXTURETYPE_PlaySound(TraceResult *ptr, Vector vecSrc, Vector vecEnd, int pTextureName++; // '}}' - Q_strcpy(szBuffer, pTextureName); - szBuffer[MAX_TEXTURENAME_LENGHT - 1] = '\0'; + Q_strlcpy(szBuffer, pTextureName); // get texture type chTextureType = TEXTURETYPE_Find(szBuffer); diff --git a/regamedll/dlls/sound.h b/regamedll/dlls/sound.h index d2f0b41a7..b4e716fbc 100644 --- a/regamedll/dlls/sound.h +++ b/regamedll/dlls/sound.h @@ -170,15 +170,13 @@ class CSpeaker: public CBaseEntity BOOL FEnvSoundInRange(entvars_t *pev, entvars_t *pevTarget, float *pflRange); void USENTENCEG_InitLRU(unsigned char *plru, int count); -int USENTENCEG_PickSequential(int isentenceg, char *szfound, int ipick, int freset); -int USENTENCEG_Pick(int isentenceg, char *szfound); int SENTENCEG_GetIndex(const char *szgroupname); int SENTENCEG_PlayRndI(edict_t *entity, int isentenceg, float volume, float attenuation, int flags, int pitch); int SENTENCEG_PlayRndSz(edict_t *entity, const char *szgroupname, float volume, float attenuation, int flags, int pitch); int SENTENCEG_PlaySequentialSz(edict_t *entity, const char *szgroupname, float volume, float attenuation, int flags, int pitch, int ipick, int freset); void SENTENCEG_Stop(edict_t *entity, int isentenceg, int ipick); void SENTENCEG_Init(); -int SENTENCEG_Lookup(const char *sample, char *sentencenum); +int SENTENCEG_Lookup(const char *sample, char (&sentencenum)[32]); void EMIT_SOUND_DYN(edict_t *entity, int channel, const char *sample, float volume, float attenuation, int flags, int pitch); void EMIT_SOUND_SUIT(edict_t *entity, const char *sample); void EMIT_GROUPID_SUIT(edict_t *entity, int isentenceg); diff --git a/regamedll/dlls/triggers.cpp b/regamedll/dlls/triggers.cpp index 82bf6907a..1bfd85b94 100644 --- a/regamedll/dlls/triggers.cpp +++ b/regamedll/dlls/triggers.cpp @@ -645,7 +645,7 @@ void PlayCDTrack(edict_t *pClient, int iTrack) CLIENT_COMMAND(pClient, UTIL_VarArgs("mp3 play %s\n", g_szMP3trackFileMap[iTrack])); #else char string[64]; - Q_sprintf(string, "cd play %3d\n", iTrack); + Q_snprintf(string, sizeof(string), "cd play %3d\n", iTrack); CLIENT_COMMAND(pClient, string); #endif } @@ -1214,7 +1214,7 @@ void CChangeLevel::KeyValue(KeyValueData *pkvd) ALERT(at_error, "Map name '%s' too long (32 chars)\n", pkvd->szValue); } - Q_strcpy(m_szMapName, pkvd->szValue); + Q_strlcpy(m_szMapName, pkvd->szValue); pkvd->fHandled = TRUE; } else if (FStrEq(pkvd->szKeyName, "landmark")) @@ -1224,7 +1224,7 @@ void CChangeLevel::KeyValue(KeyValueData *pkvd) ALERT(at_error, "Landmark name '%s' too long (32 chars)\n", pkvd->szValue); } - Q_strcpy(m_szLandmarkName, pkvd->szValue); + Q_strlcpy(m_szLandmarkName, pkvd->szValue); pkvd->fHandled = TRUE; } else if (FStrEq(pkvd->szKeyName, "changetarget")) @@ -1356,7 +1356,7 @@ void CChangeLevel::ChangeLevelNow(CBaseEntity *pActivator) } // This object will get removed in the call to CHANGE_LEVEL, copy the params into "safe" memory - Q_strcpy(st_szNextMap, m_szMapName); + Q_strlcpy(st_szNextMap, m_szMapName); m_hActivator = pActivator; SUB_UseTargets(pActivator, USE_TOGGLE, 0); @@ -1369,7 +1369,7 @@ void CChangeLevel::ChangeLevelNow(CBaseEntity *pActivator) if (!FNullEnt(pentLandmark)) { - Q_strcpy(st_szNextSpot, m_szLandmarkName); + Q_strlcpy(st_szNextSpot, m_szLandmarkName); gpGlobals->vecLandmarkOffset = VARS(pentLandmark)->origin; } @@ -1415,8 +1415,8 @@ int CChangeLevel::AddTransitionToList(LEVELLIST *pLevelList, int listCount, cons } } - Q_strcpy(pLevelList[listCount].mapName, pMapName); - Q_strcpy(pLevelList[listCount].landmarkName, pLandmarkName); + Q_strlcpy(pLevelList[listCount].mapName, pMapName); + Q_strlcpy(pLevelList[listCount].landmarkName, pLandmarkName); pLevelList[listCount].pentLandmark = pentLandmark; pLevelList[listCount].vecLandmarkOrigin = VARS(pentLandmark)->origin; @@ -1591,12 +1591,12 @@ NOXREF void NextLevel() { gpGlobals->mapname = ALLOC_STRING("start"); pChange = GetClassPtr((CChangeLevel *)nullptr); - Q_strcpy(pChange->m_szMapName, "start"); + Q_strlcpy(pChange->m_szMapName, "start"); } else pChange = GetClassPtr((CChangeLevel *)VARS(pent)); - Q_strcpy(st_szNextMap, pChange->m_szMapName); + Q_strlcpy(st_szNextMap, pChange->m_szMapName); g_pGameRules->SetGameOver(); if (pChange->pev->nextthink < gpGlobals->time) diff --git a/regamedll/dlls/tutor_base_tutor.cpp b/regamedll/dlls/tutor_base_tutor.cpp index 2268d18b7..a44ef4728 100644 --- a/regamedll/dlls/tutor_base_tutor.cpp +++ b/regamedll/dlls/tutor_base_tutor.cpp @@ -68,12 +68,10 @@ void TutorMessageEvent::AddParameter(char *str) TutorMessageEventParam *param = new TutorMessageEventParam; param->m_next = nullptr; - param->m_data = new char[Q_strlen(str) + 1]; + param->m_data = CloneString(str); if (param->m_data) { - Q_strcpy(param->m_data, str); - param->m_data[Q_strlen(str)] = '\0'; m_numParameters++; if (m_paramList) @@ -101,11 +99,7 @@ char *TutorMessageEvent::GetNextParameter(char *buf, int buflen) m_numParameters--; m_paramList = param->m_next; - Q_strncpy(buf, param->m_data, buflen); - -#ifdef REGAMEDLL_FIXES - buf[buflen - 1] = '\0'; -#endif + Q_strlcpy(buf, param->m_data, buflen); delete param; return buf; diff --git a/regamedll/dlls/tutor_cs_tutor.cpp b/regamedll/dlls/tutor_cs_tutor.cpp index 18e5d2b67..aa6bdd4bc 100644 --- a/regamedll/dlls/tutor_cs_tutor.cpp +++ b/regamedll/dlls/tutor_cs_tutor.cpp @@ -213,7 +213,7 @@ void ParseMessageParameters(char *&messageData, TutorMessage *ret) if (!Q_stricmp(token, "String")) { messageData = SharedParse((char *)messageData); - ret->m_text = Q_strdup(SharedGetToken()); + ret->m_text = CloneString(SharedGetToken()); } else if (!Q_stricmp(token, "Duration")) { @@ -832,7 +832,7 @@ TutorMessageEvent *CCSTutor::CreateTutorMessageEvent(TutorMessageID mid, CBaseEn { numtasks = TheCareerTasks->GetNumRemainingTasks(); } - Q_sprintf(numLeftStr, "%d", numtasks); + Q_snprintf(numLeftStr, sizeof(numLeftStr), "%d", numtasks); event->AddParameter(numLeftStr); break; } @@ -2820,8 +2820,7 @@ void CCSTutor::ConstructRecentDeathsList(TeamName team, char *buf, int buflen, T if (!buf || !buflen) return; - char scratch[32]; - buf[0] = '\0'; + int len = 0; for (int i = 1; i <= gpGlobals->maxClients; i++) { @@ -2837,10 +2836,7 @@ void CCSTutor::ConstructRecentDeathsList(TeamName team, char *buf, int buflen, T if (pPlayer->m_iTeam != team) continue; - Q_strcat(buf, " %n"); - Q_sprintf(scratch, "%d\n", i); - Q_strcat(buf, scratch); - + len += Q_snprintf(&buf[len], buflen - len, " %%n%d\n", i); m_playerDeathInfo[i].m_event = event; } } diff --git a/regamedll/dlls/util.cpp b/regamedll/dlls/util.cpp index 7841b006b..de6159469 100644 --- a/regamedll/dlls/util.cpp +++ b/regamedll/dlls/util.cpp @@ -690,10 +690,7 @@ void UTIL_Log(const char *fmt, ...) Q_vsnprintf(string, sizeof(string), fmt, ap); va_end(ap); - if (Q_strlen(string) < sizeof(string) - 2) - Q_strcat(string, "\n"); - else - string[Q_strlen(string) - 1] = '\n'; + Q_strlcat(string, "\n"); FILE *fp = fopen("regamedll.log", "at"); if (fp) @@ -717,10 +714,7 @@ void UTIL_ServerPrint(const char *fmt, ...) Q_vsnprintf(string, sizeof(string), fmt, ap); va_end(ap); - if (Q_strlen(string) < sizeof(string) - 2) - Q_strcat(string, "\n"); - else - string[Q_strlen(string) - 1] = '\n'; + Q_strlcat(string, "\n"); SERVER_PRINT(string); } @@ -738,10 +732,7 @@ void UTIL_PrintConsole(edict_t *pEdict, const char *fmt, ...) Q_vsnprintf(string, sizeof(string), fmt, ap); va_end(ap); - if (Q_strlen(string) < sizeof(string) - 2) - Q_strcat(string, "\n"); - else - string[Q_strlen(string) - 1] = '\n'; + Q_strlcat(string, "\n"); ClientPrint(pEntity->pev, HUD_PRINTCONSOLE, string); } @@ -759,10 +750,7 @@ void UTIL_SayText(edict_t *pEdict, const char *fmt, ...) Q_vsnprintf(string, sizeof(string), fmt, ap); va_end(ap); - if (Q_strlen(string) < sizeof(string) - 2) - Q_strcat(string, "\n"); - else - string[Q_strlen(string) - 1] = '\n'; + Q_strlcat(string, "\n"); MESSAGE_BEGIN(MSG_ONE, gmsgSayText, nullptr, pEntity->edict()); WRITE_BYTE(pEntity->entindex()); @@ -781,28 +769,28 @@ void UTIL_SayTextAll(const char *pText, CBaseEntity *pEntity) char *UTIL_dtos1(int d) { static char buf[12]; - Q_sprintf(buf, "%d", d); + Q_snprintf(buf, sizeof(buf), "%d", d); return buf; } char *UTIL_dtos2(int d) { static char buf[12]; - Q_sprintf(buf, "%d", d); + Q_snprintf(buf, sizeof(buf), "%d", d); return buf; } NOXREF char *UTIL_dtos3(int d) { static char buf[12]; - Q_sprintf(buf, "%d", d); + Q_snprintf(buf, sizeof(buf), "%d", d); return buf; } NOXREF char *UTIL_dtos4(int d) { static char buf[12]; - Q_sprintf(buf, "%d", d); + Q_snprintf(buf, sizeof(buf), "%d", d); return buf; } @@ -991,7 +979,7 @@ char *UTIL_VarArgs(char *format, ...) static char string[1024]; va_start(argptr, format); - vsprintf(string, format, argptr); + Q_vsnprintf(string, sizeof(string), format, argptr); va_end(argptr); return string; @@ -1561,7 +1549,7 @@ void UTIL_LogPrintf(const char *fmt, ...) static char string[1024]; va_start(argptr, fmt); - vsprintf(string, fmt, argptr); + Q_vsnprintf(string, sizeof(string), fmt, argptr); va_end(argptr); ALERT(at_logged, "%s", string); @@ -1580,7 +1568,7 @@ char UTIL_TextureHit(TraceResult *ptr, Vector vecSrc, Vector vecEnd) float rgfl1[3]; float rgfl2[3]; const char *pTextureName; - char szbuffer[64]; + char szbuffer[MAX_TEXTURENAME_LENGHT]; CBaseEntity *pEntity = CBaseEntity::Instance(ptr->pHit); #ifdef REGAMEDLL_FIXES @@ -1606,8 +1594,8 @@ char UTIL_TextureHit(TraceResult *ptr, Vector vecSrc, Vector vecEnd) if (*pTextureName == '{' || *pTextureName == '!' || *pTextureName == '~' || *pTextureName == ' ') pTextureName++; - Q_strcpy(szbuffer, pTextureName); - szbuffer[16] = '\0'; + Q_strlcpy(szbuffer, pTextureName); + chTextureType = TEXTURETYPE_Find(szbuffer); } else diff --git a/regamedll/dlls/weapons.cpp b/regamedll/dlls/weapons.cpp index 087f45eee..47a77c6fc 100644 --- a/regamedll/dlls/weapons.cpp +++ b/regamedll/dlls/weapons.cpp @@ -652,11 +652,11 @@ void CBasePlayerWeapon::SetPlayerShieldAnim() if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN) { - Q_strcpy(m_pPlayer->m_szAnimExtention, "shield"); + Q_strlcpy(m_pPlayer->m_szAnimExtention, "shield"); } else { - Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldgun"); + Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldgun"); } } @@ -666,7 +666,7 @@ void CBasePlayerWeapon::ResetPlayerShieldAnim() { if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN) { - Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldgun"); + Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldgun"); } } } @@ -697,7 +697,7 @@ bool CBasePlayerWeapon::ShieldSecondaryFire(int iUpAnim, int iDownAnim) { m_iWeaponState &= ~WPNSTATE_SHIELD_DRAWN; SendWeaponAnim(iDownAnim, UseDecrement() != FALSE); - Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldgun"); + Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldgun"); m_fMaxSpeed = 250.0f; m_pPlayer->m_bShieldDrawn = false; } @@ -705,7 +705,7 @@ bool CBasePlayerWeapon::ShieldSecondaryFire(int iUpAnim, int iDownAnim) { m_iWeaponState |= WPNSTATE_SHIELD_DRAWN; SendWeaponAnim(iUpAnim, UseDecrement() != FALSE); - Q_strcpy(m_pPlayer->m_szAnimExtention, "shielded"); + Q_strlcpy(m_pPlayer->m_szAnimExtention, "shielded"); m_fMaxSpeed = 180.0f; m_pPlayer->m_bShieldDrawn = true; } @@ -728,7 +728,7 @@ void EXT_FUNC CBasePlayerWeapon::__API_HOOK(KickBack)(float up_base, float later real_t flKickUp = up_base; float flKickLateral = lateral_base; - if (m_iShotsFired > 1) // consider == 0 case + if (m_iShotsFired > 1) // consider == 0 case { flKickUp += m_iShotsFired * up_modifier; flKickLateral += m_iShotsFired * lateral_modifier; @@ -1491,7 +1491,7 @@ BOOL EXT_FUNC CBasePlayerWeapon::__API_HOOK(DefaultDeploy)(char *szViewModel, ch m_pPlayer->pev->weaponmodel = MAKE_STRING(szWeaponModel); #endif model_name = m_pPlayer->pev->viewmodel; - Q_strcpy(m_pPlayer->m_szAnimExtention, szAnimExt); + Q_strlcpy(m_pPlayer->m_szAnimExtention, szAnimExt); SendWeaponAnim(iAnim, skiplocal); m_pPlayer->m_flNextAttack = 0.75f; @@ -1671,7 +1671,7 @@ void CBasePlayerWeapon::Holster(int skiplocal) m_fInReload = FALSE; m_pPlayer->pev->viewmodel = 0; m_pPlayer->pev->weaponmodel = 0; - + #ifdef REGAMEDLL_FIXES m_fInSpecialReload = 0; #endif diff --git a/regamedll/dlls/world.cpp b/regamedll/dlls/world.cpp index 55147af09..cc4a3de55 100644 --- a/regamedll/dlls/world.cpp +++ b/regamedll/dlls/world.cpp @@ -216,7 +216,7 @@ void CWorld::Spawn() Precache(); g_szMapBriefingText[0] = '\0'; - Q_sprintf(szMapBriefingFile, "maps/%s.txt", STRING(gpGlobals->mapname)); + Q_snprintf(szMapBriefingFile, sizeof(szMapBriefingFile), "maps/%s.txt", STRING(gpGlobals->mapname)); int flength = 0; char *pFile = (char *)LOAD_FILE_FOR_ME(szMapBriefingFile, &flength); diff --git a/regamedll/dlls/wpn_shared/wpn_flashbang.cpp b/regamedll/dlls/wpn_shared/wpn_flashbang.cpp index 0443353e8..bbebb8ebf 100644 --- a/regamedll/dlls/wpn_shared/wpn_flashbang.cpp +++ b/regamedll/dlls/wpn_shared/wpn_flashbang.cpp @@ -114,7 +114,7 @@ bool CFlashbang::ShieldSecondaryFire(int iUpAnim, int iDownAnim) m_iWeaponState &= ~WPNSTATE_SHIELD_DRAWN; SendWeaponAnim(iDownAnim, UseDecrement() != FALSE); - Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldgren"); + Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldgren"); m_fMaxSpeed = FLASHBANG_MAX_SPEED; m_pPlayer->m_bShieldDrawn = false; @@ -124,7 +124,7 @@ bool CFlashbang::ShieldSecondaryFire(int iUpAnim, int iDownAnim) m_iWeaponState |= WPNSTATE_SHIELD_DRAWN; SendWeaponAnim(iUpAnim, UseDecrement() != FALSE); - Q_strcpy(m_pPlayer->m_szAnimExtention, "shielded"); + Q_strlcpy(m_pPlayer->m_szAnimExtention, "shielded"); m_fMaxSpeed = FLASHBANG_MAX_SPEED_SHIELD; m_pPlayer->m_bShieldDrawn = true; @@ -151,9 +151,9 @@ void CFlashbang::SetPlayerShieldAnim() return; if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN) - Q_strcpy(m_pPlayer->m_szAnimExtention, "shield"); + Q_strlcpy(m_pPlayer->m_szAnimExtention, "shield"); else - Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldgren"); + Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldgren"); } void CFlashbang::ResetPlayerShieldAnim() @@ -163,7 +163,7 @@ void CFlashbang::ResetPlayerShieldAnim() if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN) { - Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldgren"); + Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldgren"); } } diff --git a/regamedll/dlls/wpn_shared/wpn_hegrenade.cpp b/regamedll/dlls/wpn_shared/wpn_hegrenade.cpp index 49d8eb7a8..ca2c63adb 100644 --- a/regamedll/dlls/wpn_shared/wpn_hegrenade.cpp +++ b/regamedll/dlls/wpn_shared/wpn_hegrenade.cpp @@ -117,7 +117,7 @@ bool CHEGrenade::ShieldSecondaryFire(int iUpAnim, int iDownAnim) { m_iWeaponState &= ~WPNSTATE_SHIELD_DRAWN; SendWeaponAnim(iDownAnim, UseDecrement() != FALSE); - Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldgren"); + Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldgren"); m_fMaxSpeed = HEGRENADE_MAX_SPEED; m_pPlayer->m_bShieldDrawn = false; @@ -126,7 +126,7 @@ bool CHEGrenade::ShieldSecondaryFire(int iUpAnim, int iDownAnim) { m_iWeaponState |= WPNSTATE_SHIELD_DRAWN; SendWeaponAnim(iUpAnim, UseDecrement() != FALSE); - Q_strcpy(m_pPlayer->m_szAnimExtention, "shielded"); + Q_strlcpy(m_pPlayer->m_szAnimExtention, "shielded"); m_fMaxSpeed = HEGRENADE_MAX_SPEED_SHIELD; m_pPlayer->m_bShieldDrawn = true; @@ -153,9 +153,9 @@ void CHEGrenade::SetPlayerShieldAnim() return; if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN) - Q_strcpy(m_pPlayer->m_szAnimExtention, "shield"); + Q_strlcpy(m_pPlayer->m_szAnimExtention, "shield"); else - Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldgren"); + Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldgren"); } void CHEGrenade::ResetPlayerShieldAnim() @@ -165,7 +165,7 @@ void CHEGrenade::ResetPlayerShieldAnim() if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN) { - Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldgren"); + Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldgren"); } } diff --git a/regamedll/dlls/wpn_shared/wpn_knife.cpp b/regamedll/dlls/wpn_shared/wpn_knife.cpp index fcbf2d949..43a2f28f2 100644 --- a/regamedll/dlls/wpn_shared/wpn_knife.cpp +++ b/regamedll/dlls/wpn_shared/wpn_knife.cpp @@ -180,7 +180,7 @@ void CKnife::SetPlayerShieldAnim() if (!m_pPlayer->HasShield()) return; - Q_strcpy(m_pPlayer->m_szAnimExtention, (m_iWeaponState & WPNSTATE_SHIELD_DRAWN) != 0 ? "shield" : "shieldknife"); + Q_strlcpy(m_pPlayer->m_szAnimExtention, (m_iWeaponState & WPNSTATE_SHIELD_DRAWN) != 0 ? "shield" : "shieldknife"); } void CKnife::ResetPlayerShieldAnim() @@ -190,7 +190,7 @@ void CKnife::ResetPlayerShieldAnim() if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN) { - Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldknife"); + Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldknife"); } } @@ -207,7 +207,7 @@ bool CKnife::ShieldSecondaryFire(int iUpAnim, int iDownAnim) SendWeaponAnim(iDownAnim, UseDecrement() != FALSE); - Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldknife"); + Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldknife"); m_fMaxSpeed = KNIFE_MAX_SPEED; m_pPlayer->m_bShieldDrawn = false; @@ -217,7 +217,7 @@ bool CKnife::ShieldSecondaryFire(int iUpAnim, int iDownAnim) m_iWeaponState |= WPNSTATE_SHIELD_DRAWN; SendWeaponAnim(iUpAnim, UseDecrement() != FALSE); - Q_strcpy(m_pPlayer->m_szAnimExtention, "shielded"); + Q_strlcpy(m_pPlayer->m_szAnimExtention, "shielded"); m_fMaxSpeed = KNIFE_MAX_SPEED_SHIELD; m_pPlayer->m_bShieldDrawn = true; @@ -339,14 +339,14 @@ BOOL CKnife::Swing(BOOL fFirst) m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + 2.0f; // play wiff or swish sound - EMIT_SOUND_DYN(m_pPlayer->edict(), - CHAN_WEAPON, - RANDOM_LONG(0, 1) ? + EMIT_SOUND_DYN(m_pPlayer->edict(), + CHAN_WEAPON, + RANDOM_LONG(0, 1) ? "weapons/knife_slash1.wav" : - "weapons/knife_slash2.wav", - VOL_NORM, - ATTN_NORM, - 0, + "weapons/knife_slash2.wav", + VOL_NORM, + ATTN_NORM, + 0, 94); // player "shoot" animation @@ -390,10 +390,10 @@ BOOL CKnife::Swing(BOOL fFirst) m_pPlayer->SetAnimation(PLAYER_ATTACK1); ClearMultiDamage(); - pEntity->TraceAttack(m_pPlayer->pev, + pEntity->TraceAttack(m_pPlayer->pev, KnifeSwingDamage(m_flNextPrimaryAttack + 0.4f < UTIL_WeaponTimeBase()), - gpGlobals->v_forward, - &tr, + gpGlobals->v_forward, + &tr, (DMG_NEVERGIB | DMG_BULLET)); ApplyMultiDamage(m_pPlayer->pev, m_pPlayer->pev); @@ -402,7 +402,7 @@ BOOL CKnife::Swing(BOOL fFirst) if (pEntity) // -V595 #endif { - if (pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE + if (pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE #ifdef REGAMEDLL_FIXES && pEntity->Classify() != CLASS_VEHICLE #endif @@ -518,14 +518,14 @@ BOOL CKnife::Stab(BOOL fFirst) m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 1.0f; // play wiff or swish sound - EMIT_SOUND_DYN(m_pPlayer->edict(), - CHAN_WEAPON, - RANDOM_LONG(0, 1) ? - "weapons/knife_slash1.wav" : - "weapons/knife_slash2.wav", - VOL_NORM, - ATTN_NORM, - 0, + EMIT_SOUND_DYN(m_pPlayer->edict(), + CHAN_WEAPON, + RANDOM_LONG(0, 1) ? + "weapons/knife_slash1.wav" : + "weapons/knife_slash2.wav", + VOL_NORM, + ATTN_NORM, + 0, 94); // player "shoot" animation @@ -586,7 +586,7 @@ BOOL CKnife::Stab(BOOL fFirst) if (pEntity) // -V595 #endif { - if (pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE + if (pEntity->Classify() != CLASS_NONE && pEntity->Classify() != CLASS_MACHINE #ifdef REGAMEDLL_FIXES && pEntity->Classify() != CLASS_VEHICLE #endif diff --git a/regamedll/dlls/wpn_shared/wpn_m4a1.cpp b/regamedll/dlls/wpn_shared/wpn_m4a1.cpp index 89ea81b5b..e9bb062e2 100644 --- a/regamedll/dlls/wpn_shared/wpn_m4a1.cpp +++ b/regamedll/dlls/wpn_shared/wpn_m4a1.cpp @@ -82,13 +82,13 @@ void CM4A1::SecondaryAttack() { m_iWeaponState &= ~WPNSTATE_M4A1_SILENCED; SendWeaponAnim(M4A1_DETACH_SILENCER, UseDecrement() != FALSE); - Q_strcpy(m_pPlayer->m_szAnimExtention, "rifle"); + Q_strlcpy(m_pPlayer->m_szAnimExtention, "rifle"); } else { m_iWeaponState |= WPNSTATE_M4A1_SILENCED; SendWeaponAnim(M4A1_ATTACH_SILENCER, UseDecrement() != FALSE); - Q_strcpy(m_pPlayer->m_szAnimExtention, "rifle"); + Q_strlcpy(m_pPlayer->m_szAnimExtention, "rifle"); } m_flTimeWeaponIdle = m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 2.0f; diff --git a/regamedll/dlls/wpn_shared/wpn_smokegrenade.cpp b/regamedll/dlls/wpn_shared/wpn_smokegrenade.cpp index ae13158b4..56c5e27bc 100644 --- a/regamedll/dlls/wpn_shared/wpn_smokegrenade.cpp +++ b/regamedll/dlls/wpn_shared/wpn_smokegrenade.cpp @@ -117,7 +117,7 @@ bool CSmokeGrenade::ShieldSecondaryFire(int iUpAnim, int iDownAnim) m_iWeaponState &= ~WPNSTATE_SHIELD_DRAWN; SendWeaponAnim(iDownAnim, UseDecrement() != FALSE); - Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldgren"); + Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldgren"); m_fMaxSpeed = SMOKEGRENADE_MAX_SPEED; m_pPlayer->m_bShieldDrawn = false; @@ -127,7 +127,7 @@ bool CSmokeGrenade::ShieldSecondaryFire(int iUpAnim, int iDownAnim) m_iWeaponState |= WPNSTATE_SHIELD_DRAWN; SendWeaponAnim(iUpAnim, UseDecrement() != FALSE); - Q_strcpy(m_pPlayer->m_szAnimExtention, "shielded"); + Q_strlcpy(m_pPlayer->m_szAnimExtention, "shielded"); m_fMaxSpeed = SMOKEGRENADE_MAX_SPEED_SHIELD; m_pPlayer->m_bShieldDrawn = true; @@ -154,9 +154,9 @@ void CSmokeGrenade::SetPlayerShieldAnim() return; if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN) - Q_strcpy(m_pPlayer->m_szAnimExtention, "shield"); + Q_strlcpy(m_pPlayer->m_szAnimExtention, "shield"); else - Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldgren"); + Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldgren"); } void CSmokeGrenade::ResetPlayerShieldAnim() @@ -166,7 +166,7 @@ void CSmokeGrenade::ResetPlayerShieldAnim() if (m_iWeaponState & WPNSTATE_SHIELD_DRAWN) { - Q_strcpy(m_pPlayer->m_szAnimExtention, "shieldgren"); + Q_strlcpy(m_pPlayer->m_szAnimExtention, "shieldgren"); } } diff --git a/regamedll/dlls/wpn_shared/wpn_usp.cpp b/regamedll/dlls/wpn_shared/wpn_usp.cpp index 5a474f652..de823f30e 100644 --- a/regamedll/dlls/wpn_shared/wpn_usp.cpp +++ b/regamedll/dlls/wpn_shared/wpn_usp.cpp @@ -98,14 +98,14 @@ void CUSP::SecondaryAttack() m_iWeaponState &= ~WPNSTATE_USP_SILENCED; SendWeaponAnim(USP_DETACH_SILENCER, UseDecrement() != FALSE); - Q_strcpy(m_pPlayer->m_szAnimExtention, "onehanded"); + Q_strlcpy(m_pPlayer->m_szAnimExtention, "onehanded"); } else { m_iWeaponState |= WPNSTATE_USP_SILENCED; SendWeaponAnim(USP_ATTACH_SILENCER, UseDecrement() != FALSE); - Q_strcpy(m_pPlayer->m_szAnimExtention, "onehanded"); + Q_strlcpy(m_pPlayer->m_szAnimExtention, "onehanded"); } m_flNextSecondaryAttack = m_flTimeWeaponIdle = UTIL_WeaponTimeBase() + USP_ADJUST_SIL_TIME; diff --git a/regamedll/game_shared/bot/bot.cpp b/regamedll/game_shared/bot/bot.cpp index 0f19e81f4..52d1f4db7 100644 --- a/regamedll/game_shared/bot/bot.cpp +++ b/regamedll/game_shared/bot/bot.cpp @@ -486,11 +486,11 @@ NOXREF void CBot::Print(char *format, ...) const char buffer[1024]; // prefix the message with the bot's name - Q_sprintf(buffer, "%s: ", STRING(pev->netname)); + Q_snprintf(buffer, sizeof(buffer), "%s: ", STRING(pev->netname)); SERVER_PRINT(buffer); va_start(varg, format); - vsprintf(buffer, format, varg); + Q_vsnprintf(buffer, sizeof(buffer), format, varg); va_end(varg); SERVER_PRINT(buffer); @@ -509,12 +509,12 @@ void CBot::PrintIfWatched(char *format, ...) const // prefix the message with the bot's name (this can be NULL if bot was just added) const char *name = pev ? STRING(pev->netname) : "(NULL pev)"; - Q_sprintf(buffer, "%s: ", name ? name : "(NULL netname)"); + Q_snprintf(buffer, sizeof(buffer), "%s: ", name ? name : "(NULL netname)"); SERVER_PRINT(buffer); va_start(varg, format); - vsprintf(buffer, format, varg); + Q_vsnprintf(buffer, sizeof(buffer), format, varg); va_end(varg); SERVER_PRINT(buffer); diff --git a/regamedll/game_shared/bot/bot_manager.cpp b/regamedll/game_shared/bot/bot_manager.cpp index 7ccd32814..3fa121ba7 100644 --- a/regamedll/game_shared/bot/bot_manager.cpp +++ b/regamedll/game_shared/bot/bot_manager.cpp @@ -213,7 +213,7 @@ void CBotManager::StartFrame() const char *CBotManager::GetNavMapFilename() const { static char filename[256]; - Q_sprintf(filename, "maps\\%s.nav", STRING(gpGlobals->mapname)); + Q_snprintf(filename, sizeof(filename), "maps\\%s.nav", STRING(gpGlobals->mapname)); return filename; } diff --git a/regamedll/game_shared/bot/bot_profile.cpp b/regamedll/game_shared/bot/bot_profile.cpp index c025f903b..76cb37a10 100644 --- a/regamedll/game_shared/bot/bot_profile.cpp +++ b/regamedll/game_shared/bot/bot_profile.cpp @@ -178,9 +178,10 @@ void BotProfileManager::Init(const char *filename, unsigned int *checksum) m_skins[m_nextSkin] = CloneString(decoratedName); // construct the model filename + int SkinLen = Q_strlen(token) * 2 + Q_strlen("models/player//.mdl"); m_skinModelnames[m_nextSkin] = CloneString(token); - m_skinFilenames[m_nextSkin] = new char[Q_strlen(token) * 2 + Q_strlen("models/player//.mdl") + 1]; - Q_sprintf(m_skinFilenames[m_nextSkin], "models/player/%s/%s.mdl", token, token); + m_skinFilenames[m_nextSkin] = new char[SkinLen + 1]; + Q_snprintf(m_skinFilenames[m_nextSkin], SkinLen + 1, "models/player/%s/%s.mdl", token, token); m_nextSkin++; } @@ -304,7 +305,7 @@ void BotProfileManager::Init(const char *filename, unsigned int *checksum) // found attribute name - keep it char attributeName[64]; - Q_strcpy(attributeName, token); + Q_strlcpy(attributeName, token); // eat '=' dataFile = SharedParse(dataFile); diff --git a/regamedll/game_shared/bot/bot_util.cpp b/regamedll/game_shared/bot/bot_util.cpp index 449b7e373..4d694b318 100644 --- a/regamedll/game_shared/bot/bot_util.cpp +++ b/regamedll/game_shared/bot/bot_util.cpp @@ -560,7 +560,7 @@ void CONSOLE_ECHO(const char *pszMsg, ...) static char szStr[1024]; va_start(argptr, pszMsg); - vsprintf(szStr, pszMsg, argptr); + Q_vsnprintf(szStr, sizeof(szStr), pszMsg, argptr); va_end(argptr); SERVER_PRINT(szStr); @@ -572,7 +572,7 @@ void CONSOLE_ECHO_LOGGED(const char *pszMsg, ...) static char szStr[1024]; va_start(argptr, pszMsg); - vsprintf(szStr, pszMsg, argptr); + Q_vsnprintf(szStr, sizeof(szStr), pszMsg, argptr); va_end(argptr); SERVER_PRINT(szStr); diff --git a/regamedll/game_shared/bot/nav_area.cpp b/regamedll/game_shared/bot/nav_area.cpp index 8e4baf0da..6c5960517 100644 --- a/regamedll/game_shared/bot/nav_area.cpp +++ b/regamedll/game_shared/bot/nav_area.cpp @@ -3819,9 +3819,9 @@ void EditNavAreas(NavEditCmdType cmd) name = TheNavAreaGrid.IDToName(area->GetPlace()); if (name) - Q_strcpy(locName, name); + Q_strlcpy(locName, name); else - Q_strcpy(locName, "ERROR"); + Q_strlcpy(locName, "ERROR"); } else { diff --git a/regamedll/game_shared/bot/nav_file.cpp b/regamedll/game_shared/bot/nav_file.cpp index c9f206fd9..5c6d65c38 100644 --- a/regamedll/game_shared/bot/nav_file.cpp +++ b/regamedll/game_shared/bot/nav_file.cpp @@ -632,12 +632,15 @@ bool SaveNavigationMap(const char *filename) void LoadLocationFile(const char *filename) { char locFilename[256]; - Q_strcpy(locFilename, filename); + Q_strlcpy(locFilename, filename); - char *dot = Q_strchr(locFilename, '.'); + char *dot = Q_strrchr(locFilename, '.'); if (dot) { - Q_strcpy(dot, ".loc"); + int dotlen = dot - locFilename; + size_t remaining_size = sizeof(locFilename) - dotlen; + if (remaining_size > 0) + Q_snprintf(dot, remaining_size, ".loc"); int locDataLength; char *locDataFile = (char *)LOAD_FILE_FOR_ME(const_cast(locFilename), &locDataLength); @@ -771,7 +774,7 @@ NavErrorType LoadNavigationMap() // nav filename is derived from map filename char filename[256]; - Q_sprintf(filename, "maps\\%s.nav", STRING(gpGlobals->mapname)); + Q_snprintf(filename, sizeof(filename), "maps\\%s.nav", STRING(gpGlobals->mapname)); // free previous navigation map data DestroyNavigationMap(); diff --git a/regamedll/pm_shared/pm_shared.cpp b/regamedll/pm_shared/pm_shared.cpp index fa106c09b..e9efb3763 100644 --- a/regamedll/pm_shared/pm_shared.cpp +++ b/regamedll/pm_shared/pm_shared.cpp @@ -123,7 +123,7 @@ void PM_InitTextureTypes() j = Q_min(j, MAX_TEXTURENAME_LENGHT - 1 + i); buffer[j] = '\0'; - Q_strcpy(&(pm_grgszTextureName[pm_gcTextures++][0]), &(buffer[i])); + Q_strlcpy(pm_grgszTextureName[pm_gcTextures++], &(buffer[i])); } // Must use engine to free since we are in a .dll @@ -364,8 +364,7 @@ void PM_CatagorizeTextureType() if (*pTextureName == '{' || *pTextureName == '!' || *pTextureName == '~' || *pTextureName == ' ') pTextureName++; - Q_strcpy(pmove->sztexturename, pTextureName); - pmove->sztexturename[MAX_TEXTURENAME_LENGHT - 1] = '\0'; + Q_strlcpy(pmove->sztexturename, pTextureName, MAX_TEXTURENAME_LENGHT); // get texture type pmove->chtexturetype = PM_FindTextureType(pmove->sztexturename); diff --git a/regamedll/public/strtools.h b/regamedll/public/strtools.h index 5cdf8c41d..11279c76e 100644 --- a/regamedll/public/strtools.h +++ b/regamedll/public/strtools.h @@ -156,40 +156,48 @@ inline char *Q_strlcpy(char *dest, const char *src, size_t size) { // a safe variant of strcpy that truncates the result to fit in the destination buffer template char *Q_strlcpy(char (&dest)[size], const char *src) { - return Q_strlcpy(dest, src, size); + return Q_strlcpy(static_cast(dest), src, size); } // safely concatenate two strings. // a variant of strcat that truncates the result to fit in the destination buffer -template -size_t Q_strlcat(char (&dest)[size], const char *src) +inline size_t Q_strlcat(char *dest, const char *src, size_t maxDestSize) { size_t srclen; // Length of source string size_t dstlen; // Length of destination string // Figure out how much room is left - dstlen = Q_strlen(dest); - size_t length = size - dstlen + 1; + dstlen = strlen(dest); + size_t unRemainingSize = maxDestSize - dstlen - 1; + + // Sanity check in case dest doesn't contain a null termination + if (dstlen > (maxDestSize - 1)) + dstlen = maxDestSize - 1; - if (!length) { - // No room, return immediately - return dstlen; + if (unRemainingSize <= 0 || unRemainingSize > maxDestSize) + { + dest[dstlen] = '\0'; + return dstlen; // No room, return immediately } // Figure out how much room is needed - srclen = Q_strlen(src); + srclen = strlen(src); // Copy the appropriate amount - if (srclen > length) { - srclen = length; - } + if (srclen > unRemainingSize) + srclen = unRemainingSize; Q_memcpy(dest + dstlen, src, srclen); dest[dstlen + srclen] = '\0'; - return dstlen + srclen; } +template +inline size_t Q_strlcat(char (&dest)[size], const char *src) +{ + return Q_strlcat(static_cast(dest), src, size); +} + // Force slashes of either type to be = separator character inline void Q_FixSlashes(char *pname, char separator = CORRECT_PATH_SEPARATOR) { diff --git a/regamedll/unittests/mathfun_tests.cpp b/regamedll/unittests/mathfun_tests.cpp index 6cb36eca5..7d39cb3b7 100644 --- a/regamedll/unittests/mathfun_tests.cpp +++ b/regamedll/unittests/mathfun_tests.cpp @@ -32,10 +32,10 @@ TEST(SinCosPrecision, SseMathFun, 10000) double sse_sin = _mm_cvtss_f32(s); double sse_cos = _mm_cvtss_f32(c); - sprintf(localbuf, "sin precision failure for angle=%f", i); + Q_snprintf(localbuf, sizeof(localbuf), "sin precision failure for angle=%f", i); DOUBLES_EQUAL(localbuf, x87_sin, sse_sin, 0.000001); - sprintf(localbuf, "cos precision failure for angle=%f", i); + Q_snprintf(localbuf, sizeof(localbuf), "cos precision failure for angle=%f", i); DOUBLES_EQUAL(localbuf, x87_cos, sse_cos, 0.000001); } } From 3f628ea9703513168e5869f587895cc596b0593d Mon Sep 17 00:00:00 2001 From: s1lentq Date: Tue, 17 Sep 2024 02:49:27 +0700 Subject: [PATCH 05/46] DeathSound: Don't interrupt pain sounds with death sound, use any available channel instead --- regamedll/dlls/player.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/regamedll/dlls/player.cpp b/regamedll/dlls/player.cpp index 8ece842e2..9782921c1 100644 --- a/regamedll/dlls/player.cpp +++ b/regamedll/dlls/player.cpp @@ -569,13 +569,20 @@ LINK_HOOK_CLASS_VOID_CHAIN2(CBasePlayer, DeathSound) void EXT_FUNC CBasePlayer::__API_HOOK(DeathSound)() { +#if REGAMEDLL_FIXES + // FIXED: Don't interrupt pain sounds with death sound, use any available channel instead + const int channel = CHAN_AUTO; +#else + const int channel = CHAN_VOICE; +#endif + // temporarily using pain sounds for death sounds switch (RANDOM_LONG(1, 4)) { - case 1: EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/die1.wav", VOL_NORM, ATTN_NORM); break; - case 2: EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/die2.wav", VOL_NORM, ATTN_NORM); break; - case 3: EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/die3.wav", VOL_NORM, ATTN_NORM); break; - case 4: EMIT_SOUND(ENT(pev), CHAN_VOICE, "player/death6.wav", VOL_NORM, ATTN_NORM); break; + case 1: EMIT_SOUND(ENT(pev), channel, "player/die1.wav", VOL_NORM, ATTN_NORM); break; + case 2: EMIT_SOUND(ENT(pev), channel, "player/die2.wav", VOL_NORM, ATTN_NORM); break; + case 3: EMIT_SOUND(ENT(pev), channel, "player/die3.wav", VOL_NORM, ATTN_NORM); break; + case 4: EMIT_SOUND(ENT(pev), channel, "player/death6.wav", VOL_NORM, ATTN_NORM); break; } } From 9b7b1695a9dbf54e2d00d7fec45e1e382e5eafba Mon Sep 17 00:00:00 2001 From: Vaqtincha <51029683+Vaqtincha@users.noreply.github.com> Date: Tue, 17 Sep 2024 14:35:21 +0500 Subject: [PATCH 06/46] escape feature for bots (#1012) --- regamedll/dlls/bot/cs_bot_manager.cpp | 7 ++ regamedll/dlls/bot/cs_bot_manager.h | 3 +- regamedll/dlls/bot/states/cs_bot_idle.cpp | 87 +++++++++++++++++++++++ 3 files changed, 96 insertions(+), 1 deletion(-) diff --git a/regamedll/dlls/bot/cs_bot_manager.cpp b/regamedll/dlls/bot/cs_bot_manager.cpp index 5656667bf..730805bbf 100644 --- a/regamedll/dlls/bot/cs_bot_manager.cpp +++ b/regamedll/dlls/bot/cs_bot_manager.cpp @@ -1213,6 +1213,13 @@ void CCSBotManager::ValidateMapData() found = true; isLegacy = false; } + else if (FClassnameIs(pEntity->pev, "func_escapezone")) + { + m_gameScenario = SCENARIO_ESCAPE; + found = true; + isLegacy = false; + } + if (found) { diff --git a/regamedll/dlls/bot/cs_bot_manager.h b/regamedll/dlls/bot/cs_bot_manager.h index 1faea5461..9552c6978 100644 --- a/regamedll/dlls/bot/cs_bot_manager.h +++ b/regamedll/dlls/bot/cs_bot_manager.h @@ -85,7 +85,8 @@ class CCSBotManager: public CBotManager SCENARIO_DEATHMATCH, SCENARIO_DEFUSE_BOMB, SCENARIO_RESCUE_HOSTAGES, - SCENARIO_ESCORT_VIP + SCENARIO_ESCORT_VIP, + SCENARIO_ESCAPE }; GameScenarioType GetScenario() const diff --git a/regamedll/dlls/bot/states/cs_bot_idle.cpp b/regamedll/dlls/bot/states/cs_bot_idle.cpp index e38bde885..4bfcd7cc0 100644 --- a/regamedll/dlls/bot/states/cs_bot_idle.cpp +++ b/regamedll/dlls/bot/states/cs_bot_idle.cpp @@ -773,6 +773,93 @@ void IdleState::OnUpdate(CCSBot *me) } break; } + case CCSBotManager::SCENARIO_ESCAPE: + { + if (me->m_iTeam == TERRORIST) + { + // if early in round, pick a random zone, otherwise pick closest zone + const float earlyTime = 20.0f; + const CCSBotManager::Zone *zone = nullptr; + + if (TheCSBots()->GetElapsedRoundTime() < earlyTime) + { + // pick random zone + zone = TheCSBots()->GetRandomZone(); + } + else + { + // pick closest zone + zone = TheCSBots()->GetClosestZone(me->GetLastKnownArea(), PathCost(me)); + } + + if (zone) + { + // pick a random spot within the escape zone + const Vector *pos = TheCSBots()->GetRandomPositionInZone(zone); + if (pos) + { + // move to escape zone + // me->SetTask(CCSBot::VIP_ESCAPE); + me->Run(); + me->MoveTo(pos); + return; + } + } + } + // CT + else + { + if (me->IsSniper()) + { + if (RANDOM_FLOAT(0, 100) <= defenseSniperCampChance) + { + // snipe escape zone(s) + const CCSBotManager::Zone *zone = TheCSBots()->GetRandomZone(); + if (zone) + { + CNavArea *area = TheCSBots()->GetRandomAreaInZone(zone); + if (area) + { + me->SetTask(CCSBot::MOVE_TO_SNIPER_SPOT); + me->Hide(area, -1.0, sniperHideRange); + me->SetDisposition(CCSBot::OPPORTUNITY_FIRE); + me->PrintIfWatched("Sniping near escape zone\n"); + return; + } + } + } + } + + // rogues just hunt, unless they want to snipe + // if the whole team has decided to rush, hunt + if (me->IsRogue() || TheCSBots()->IsDefenseRushing()) + break; + + // the lower our morale gets, the more we want to camp the escape zone(s) + float guardEscapeZoneChance = -34.0f * me->GetMorale(); + + if (RANDOM_FLOAT(0.0f, 100.0f) < guardEscapeZoneChance) + { + // guard escape zone(s) + const CCSBotManager::Zone *zone = TheCSBots()->GetRandomZone(); + if (zone) + { + CNavArea *area = TheCSBots()->GetRandomAreaInZone(zone); + if (area) + { + // guard the escape zone - stay closer if our morale is low + //me->SetTask(CCSBot::GUARD_VIP_ESCAPE_ZONE); + me->PrintIfWatched("I'm guarding an escape zone\n"); + + float escapeGuardRange = 750.0f + 250.0f * (me->GetMorale() + 3); + me->Hide(area, -1.0, escapeGuardRange); + me->SetDisposition(CCSBot::OPPORTUNITY_FIRE); + return; + } + } + } + } + } // deathmatch default: { From 9b626b1d82f676287339240569934255613c4f0e Mon Sep 17 00:00:00 2001 From: Vaqtincha <51029683+Vaqtincha@users.noreply.github.com> Date: Wed, 18 Sep 2024 05:49:24 +0500 Subject: [PATCH 07/46] add desc to readme (#1014) --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 90f58990d..3d1201bf7 100644 --- a/README.md +++ b/README.md @@ -29,6 +29,7 @@ This means that plugins that do binary code analysis (Orpheu for example) probab | swapteams | Swap the teams and restart the game (1 sec delay to restart by default).
Args:
`0` - swap teams without restart.
`>0.001` - time delay in seconds to restart the round after swap. | | give | Give weapon command.
Args:

Usage:
`give weapon_ak47`
`give weapon_usp`

NOTE: `sv_cheats 1` required. | | impulse 255 | Give all weapons.

NOTE: `sv_cheats 1` required. | +| impulse 200 | Noclip with air acceleration.

NOTE: `sv_cheats 1` required. | ## Configuration (cvars)
From 535ea846a9832927dfcb71a372423ea3ac50d793 Mon Sep 17 00:00:00 2001 From: Nord1cWarr1or Date: Wed, 23 Oct 2024 16:08:29 +0000 Subject: [PATCH 08/46] client.cpp: Use macros for pfnPrecacheEvent (#1019) --- regamedll/dlls/client.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/regamedll/dlls/client.cpp b/regamedll/dlls/client.cpp index bc223ed7d..198afbfbe 100644 --- a/regamedll/dlls/client.cpp +++ b/regamedll/dlls/client.cpp @@ -4296,7 +4296,7 @@ void ClientPrecache() PRECACHE_GENERIC("sprites/scope_arc_ne.tga"); PRECACHE_GENERIC("sprites/scope_arc_sw.tga"); - m_usResetDecals = g_engfuncs.pfnPrecacheEvent(1, "events/decal_reset.sc"); + m_usResetDecals = PRECACHE_EVENT(1, "events/decal_reset.sc"); } const char *EXT_FUNC GetGameDescription() From 7738142c69dc9726a99203f151b7794645890367 Mon Sep 17 00:00:00 2001 From: Sergey Shorokhov Date: Tue, 29 Oct 2024 09:22:24 +0300 Subject: [PATCH 09/46] CI Workflow Refactor and Fixes (#1016) chore(ci): standardize and update CI workflows for compatibility and consistency - Updated action versions (`checkout@v4`, `upload-artifact@v4`, `download-artifact@v4`) for enhanced compatibility and security - Removed unsecure Node.js version allowance to align with *-latest OS requirements - Migrated test demos to `rehldsorg/testdemos:latest` container with a streamlined testing approach via matrix strategy and `runTest.sh` - Standardized Linux dependency installation for consistent build environment across jobs - Unified CI workflow structure with `rehlds` and `regamedll` repositories for better consistency - Optimized artifact deployment steps and removed unnecessary cleanup operations Co-authored-by: s1lentq --- .github/workflows/build.yml | 106 ++++++++++++------------------------ 1 file changed, 34 insertions(+), 72 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b4e807929..e62c178ed 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -32,7 +32,7 @@ jobs: - name: Setup MSBuild uses: microsoft/setup-msbuild@v2 with: - vs-version: '16.8' + vs-version: '16' - name: Build and Run unittests run: | @@ -58,95 +58,68 @@ jobs: move msvc\${{ env.buildRelease }}\mp.pdb publish\debug\mp.pdb - name: Deploy artifacts - uses: actions/upload-artifact@v3.1.1 + uses: actions/upload-artifact@v4 with: name: win32 path: publish/* testdemos: name: 'Test demos' - runs-on: ubuntu-20.04 - container: s1lentq/testdemos:latest + runs-on: ubuntu-latest + container: rehldsorg/testdemos:latest needs: [windows] - env: - WINEDEBUG: -all - WINEDLLOVERRIDES: mshtml= - ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION: true - defaults: run: shell: bash - working-directory: ../../../opt/HLDS + working-directory: /opt/HLDS + + strategy: + fail-fast: false + matrix: + test: [ + { file: 'cstrike-basic-1', desc: 'CS: Testing jumping, scenarios, shooting etc' }, + ] steps: - name: Deploying windows artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: win32 - - name: Play demos + - name: Setup dependencies run: | chown root ~ rsync -a deps/regamedll/* . mv $GITHUB_WORKSPACE/tests/mp.dll cstrike/dlls/mp.dll - descs=( - "CS: Testing jumping, scenarios, shooting etc" - ) - - demos=( - "cstrike-basic-1" - ) - - retVal=0 - for i in "${!demos[@]}"; do - params=$(cat "testdemos/${demos[i]}.params") - - echo -e "\e[1m[$((i + 1))/${#demos[@]}] \e[1;36m${descs[i]} testing...\e[0m" - echo -e " - \e[0;33mParameters $params\e[0m" - - wine hlds.exe --rehlds-enable-all-hooks --rehlds-test-play "testdemos/${demos[i]}.bin" $params &> result.log || retVal=$? - - if [ $retVal -ne 777 ] && [ $retVal -ne 9 ]; then - # Print with catchy messages - while read line; do - echo -e " \e[0;33m$line" - done <<< $(cat result.log | sed '0,/demo failed/I!d;/wine:/d;/./,$!d') - - echo " 🔸 🔸 🔸 🔸 🔸 🔸 🔸 🔸 🔸 🔸" - while read line; do - echo -e " \e[1;31m$line"; - done < rehlds_demo_error.txt - echo -e " \e[30;41mExit code: $retVal\e[0m" - echo -e "\e[1m[$((i + 1))/${#demos[@]}] \e[1;36m${descs[i]} testing...\e[1;31m Failed ❌" - exit 6 # Test demo failed - else - # Print result HLDS console - while read line; do - echo -e " \e[0;33m$line" - done <<< $(cat result.log | sed '/wine:/d;/./,$!d') - echo -e " \e[30;43mExit code: $retVal\e[0m" - echo -e "\e[1m[$((i + 1))/${#demos[@]}] \e[1;36m${descs[i]} testing...\e[1;32m Succeed ✔" - fi - done + - name: Play test + env: + demo: ${{ matrix.test.file }} + desc: ${{ matrix.test.desc }} + run: ./runTest.sh linux: name: 'Linux' - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest + container: debian:11-slim steps: - name: Checkout uses: actions/checkout@v4 with: fetch-depth: 0 - submodules: true - - name: Check dependencies + - name: Install dependencies run: | - sudo dpkg --add-architecture i386 - sudo apt-get update - sudo apt-get install -y gcc-multilib g++-multilib + dpkg --add-architecture i386 + apt-get update + apt-get install -y \ + gcc-multilib g++-multilib \ + build-essential \ + libc6-dev libc6-dev-i386 \ + git cmake rsync \ + g++ gcc - name: Build and Run unittests run: | @@ -171,7 +144,7 @@ jobs: fi shell: bash - - name: Build + - name: Build using GCC Compiler run: | rm -rf build && CC=gcc CXX=g++ cmake -B build && cmake --build build -j8 @@ -199,18 +172,12 @@ jobs: shell: bash - name: Deploy artifacts - uses: actions/upload-artifact@v3.1.1 + uses: actions/upload-artifact@v4 id: upload-job with: name: linux32 path: publish/* - - name: Cleanup temporary artifacts - if: success() && steps.upload-job.outcome == 'success' - run: | - rm -rf cssdk - rm -f appversion.h - publish: name: 'Publish' runs-on: ubuntu-latest @@ -218,12 +185,12 @@ jobs: steps: - name: Deploying linux artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: linux32 - name: Deploying windows artifacts - uses: actions/download-artifact@v3 + uses: actions/download-artifact@v4 with: name: win32 @@ -264,8 +231,3 @@ jobs: env: GITHUB_TOKEN: ${{ secrets.API_TOKEN }} - - name: Cleanup temporary artifacts - if: success() && steps.publish-job.outcome == 'success' - run: | - rm -rf bin dist debug cssdk - rm -f *.zip appversion.h From 476b5f7afd45883bdf36dcaa7117be22dbbd1483 Mon Sep 17 00:00:00 2001 From: s1lentq Date: Mon, 9 Dec 2024 22:10:03 +0700 Subject: [PATCH 10/46] fix typo --- regamedll/dlls/game.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/regamedll/dlls/game.cpp b/regamedll/dlls/game.cpp index 789435938..3f26b8554 100644 --- a/regamedll/dlls/game.cpp +++ b/regamedll/dlls/game.cpp @@ -179,7 +179,7 @@ cvar_t legacy_vehicle_block = { "mp_legacy_vehicle_block", "1", 0, cvar_t dying_time = { "mp_dying_time", "3.0", 0, 3.0f, nullptr }; cvar_t defuser_allocation = { "mp_defuser_allocation", "0", 0, 0.0f, nullptr }; cvar_t location_area_info = { "mp_location_area_info", "0", 0, 0.0f, nullptr }; -cvar_t chat_loc_fallback = { "mp_chat_loc_fallback", "1", 1, 0.0f, nullptr }; +cvar_t chat_loc_fallback = { "mp_chat_loc_fallback", "1", 0, 1.0f, nullptr }; cvar_t item_respawn_time = { "mp_item_respawn_time", "30", FCVAR_SERVER, 30.0f, nullptr }; cvar_t weapon_respawn_time = { "mp_weapon_respawn_time", "20", FCVAR_SERVER, 20.0f, nullptr }; From df7944ab8869c9273d84ea6bea5952097c4bca0c Mon Sep 17 00:00:00 2001 From: s1lentq Date: Tue, 10 Dec 2024 20:46:00 +0700 Subject: [PATCH 11/46] Disable broken angle adjustment with throw direction in Killed to avoid player model visual artifacts --- regamedll/dlls/player.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/regamedll/dlls/player.cpp b/regamedll/dlls/player.cpp index 9782921c1..5295943a2 100644 --- a/regamedll/dlls/player.cpp +++ b/regamedll/dlls/player.cpp @@ -2462,8 +2462,16 @@ void EXT_FUNC CBasePlayer::__API_HOOK(Killed)(entvars_t *pevAttacker, int iGib) break; } + // UNDO: This code was intended to set the victim's angle with the throw direction + // For bots, it works correctly because they do not send angle updates to the server, + // However, for players, the client overrides the angle with its own view direction in the next frame, + // causing a visual glitch where the model rotates excessively + // The issue is more noticeable with high cmdrate values (e.g., cl_cmdrate >100) + // Disabled to avoid this artifact +#ifndef REGAMEDLL_FIXES pev->angles.y = UTIL_VecToAngles(-pev->velocity).y; pev->v_angle.y = pev->angles.y; +#endif m_iThrowDirection = THROW_NONE; } @@ -2952,10 +2960,8 @@ void EXT_FUNC CBasePlayer::__API_HOOK(SetAnimation)(PLAYER_ANIM playerAnim) break; case 3: case 4: -#ifndef REGAMEDLL_FIXES m_iThrowDirection = THROW_FORWARD; break; -#endif case 5: case 6: m_iThrowDirection = THROW_HITVEL; From 942f2e663746670b357bbc1847c4c1d7ccaa654d Mon Sep 17 00:00:00 2001 From: s1lentq Date: Wed, 11 Dec 2024 02:06:08 +0700 Subject: [PATCH 12/46] Removed -bots and -host-improve command line params in favor of using CVars --- README.md | 6 +++--- dist/game_init.cfg | 15 ++++++++++++++ regamedll/dlls/bot/cs_bot_init.cpp | 1 + regamedll/dlls/bot/cs_bot_init.h | 1 + regamedll/dlls/game.cpp | 15 ++++++++------ regamedll/dlls/h_export.cpp | 1 - regamedll/dlls/hostage/hostage.cpp | 19 ++++++++++------- regamedll/dlls/hostage/hostage.h | 1 + regamedll/dlls/util.cpp | 33 ++++++++---------------------- 9 files changed, 51 insertions(+), 41 deletions(-) diff --git a/README.md b/README.md index 3d1201bf7..7bdfc9f81 100644 --- a/README.md +++ b/README.md @@ -128,11 +128,11 @@ This means that plugins that do binary code analysis (Orpheu for example) probab ## How to install zBot for CS 1.6? * Extract all the files from an [archive](regamedll/extra/zBot/bot_profiles.zip?raw=true) -* Enter `-bots` option at the command line HLDS +* Enable CVar `bot_enable 1` in `cstrike/game_init.cfg` (if this config file does not exist, create it) -## How to install CSCZ hostage AI for CS 1.6? +## How to install CS:CZ hostage AI for CS 1.6? * Extract all the files from an [archive](regamedll/extra/HostageImprov/host_improv.zip?raw=true) -* Enter `-host-improv` option at the command line HLDS +* Enable CVar `hostage_ai_enable 1` in `cstrike/game_init.cfg` (if this config file does not exist, create it) ## Build instructions ### Checking requirements diff --git a/dist/game_init.cfg b/dist/game_init.cfg index 90e31b2d5..de6cb5326 100644 --- a/dist/game_init.cfg +++ b/dist/game_init.cfg @@ -1,3 +1,18 @@ +// Enables ZBots for the server +// NOTE: ZBots are always enabled on a listen server, regardless of this cvar +// 0 - disabled +// 1 - enabled +// +// Default value: "0" +bot_enable "0" + +// Enables the improve AI for hostages from CS:CZ +// 0 - disabled (classic hostage) +// 1 - enabled (improved hostage) +// +// Default value: "0" +hostage_ai_enable "0" + // Sets mins/maxs hull bounds for the player. // 0 - disabled (default behaviour, sets engine) // 1 - enabled (sets gamedll) diff --git a/regamedll/dlls/bot/cs_bot_init.cpp b/regamedll/dlls/bot/cs_bot_init.cpp index 1bf7aec00..665b3c337 100644 --- a/regamedll/dlls/bot/cs_bot_init.cpp +++ b/regamedll/dlls/bot/cs_bot_init.cpp @@ -28,6 +28,7 @@ #include "precompiled.h" +cvar_t cv_bot_enable = { "bot_enable", "0", 0, 0.0f, nullptr }; cvar_t cv_bot_traceview = { "bot_traceview", "0", FCVAR_SERVER, 0.0f, nullptr }; cvar_t cv_bot_stop = { "bot_stop", "0", FCVAR_SERVER, 0.0f, nullptr }; cvar_t cv_bot_show_nav = { "bot_show_nav", "0", FCVAR_SERVER, 0.0f, nullptr }; diff --git a/regamedll/dlls/bot/cs_bot_init.h b/regamedll/dlls/bot/cs_bot_init.h index 8687e3f7f..b50e020c3 100644 --- a/regamedll/dlls/bot/cs_bot_init.h +++ b/regamedll/dlls/bot/cs_bot_init.h @@ -28,6 +28,7 @@ #pragma once +extern cvar_t cv_bot_enable; extern cvar_t cv_bot_traceview; extern cvar_t cv_bot_stop; extern cvar_t cv_bot_show_nav; diff --git a/regamedll/dlls/game.cpp b/regamedll/dlls/game.cpp index 3f26b8554..12f63c1a7 100644 --- a/regamedll/dlls/game.cpp +++ b/regamedll/dlls/game.cpp @@ -460,9 +460,18 @@ void EXT_FUNC GameDLLInit() CVAR_REGISTER(&vote_flags); CVAR_REGISTER(&votemap_min_time); + CVAR_REGISTER(&cv_bot_enable); + CVAR_REGISTER(&cv_hostage_ai_enable); + // print version CONSOLE_ECHO("ReGameDLL version: " APP_VERSION "\n"); + // execute initial pre-configurations + SERVER_COMMAND("exec game_init.cfg\n"); + SERVER_EXECUTE(); + + Regamedll_Game_Init(); + #endif // REGAMEDLL_ADD Bot_RegisterCVars(); @@ -473,12 +482,6 @@ void EXT_FUNC GameDLLInit() VoiceGameMgr_RegisterCVars(); #endif -#ifdef REGAMEDLL_ADD - // execute initial pre-configurations - SERVER_COMMAND("exec game_init.cfg\n"); - SERVER_EXECUTE(); -#endif - } SpewRetval_t GameDLL_SpewHandler(SpewType_t spewType, int level, const char *pMsg) diff --git a/regamedll/dlls/h_export.cpp b/regamedll/dlls/h_export.cpp index 486a3eedf..544a92ffb 100644 --- a/regamedll/dlls/h_export.cpp +++ b/regamedll/dlls/h_export.cpp @@ -13,7 +13,6 @@ C_DLLEXPORT void WINAPI GiveFnptrsToDll(enginefuncs_t *pEnginefuncsTable, global gpGlobals = pGlobals; FileSystem_Init(); - Regamedll_Game_Init(); } #if defined(_LINUX) diff --git a/regamedll/dlls/hostage/hostage.cpp b/regamedll/dlls/hostage/hostage.cpp index 7ef34b222..e3ddd6750 100644 --- a/regamedll/dlls/hostage/hostage.cpp +++ b/regamedll/dlls/hostage/hostage.cpp @@ -28,6 +28,7 @@ #include "precompiled.h" +cvar_t cv_hostage_ai_enable = { "hostage_ai_enable", "1", 0, 1.0f, nullptr }; cvar_t cv_hostage_debug = { "hostage_debug", "0", FCVAR_SERVER, 0.0f, nullptr }; cvar_t cv_hostage_stop = { "hostage_stop", "0", FCVAR_SERVER, 0.0f, nullptr }; @@ -273,6 +274,7 @@ void CHostage::Precache() static int which = 0; switch (which) { + default: case REGULAR_GUY: pev->model = MAKE_STRING("models/hostageA.mdl"); break; @@ -285,22 +287,25 @@ void CHostage::Precache() case GOOFY_GUY: pev->model = MAKE_STRING("models/hostageD.mdl"); break; - default: - break; } m_whichModel = static_cast(which); if (++which > 3) which = 0; + + if (!g_pFileSystem->FileExists(pev->model)) + { + // It seems that the model is missing, so use classic hostages + g_bHostageImprov = false; + pev->model = iStringNull; + } } - else + + if (pev->model.IsNull()) { m_whichModel = REGULAR_GUY; - if (pev->model.IsNull()) - { - pev->model = MAKE_STRING("models/scientist.mdl"); - } + pev->model = MAKE_STRING("models/scientist.mdl"); } PRECACHE_MODEL(pev->model); diff --git a/regamedll/dlls/hostage/hostage.h b/regamedll/dlls/hostage/hostage.h index 44a501235..6bacec2dc 100644 --- a/regamedll/dlls/hostage/hostage.h +++ b/regamedll/dlls/hostage/hostage.h @@ -77,6 +77,7 @@ enum HostageChatterType extern CHostageManager *g_pHostages; extern int g_iHostageNumber; +extern cvar_t cv_hostage_ai_enable; extern cvar_t cv_hostage_debug; extern cvar_t cv_hostage_stop; diff --git a/regamedll/dlls/util.cpp b/regamedll/dlls/util.cpp index de6159469..b1102c470 100644 --- a/regamedll/dlls/util.cpp +++ b/regamedll/dlls/util.cpp @@ -1660,14 +1660,12 @@ int UTIL_ReadFlags(const char *c) // Determine whether bots can be used or not bool UTIL_AreBotsAllowed() { -#ifdef REGAMEDLL_ADD - if (g_engfuncs.pfnEngCheckParm == nullptr) - return false; -#endif - if (AreRunningCZero()) { #ifdef REGAMEDLL_ADD + if (g_engfuncs.pfnEngCheckParm == nullptr) + return false; + // If they pass in -nobots, don't allow bots. This is for people who host servers, to // allow them to disallow bots to enforce CPU limits. int nobots = ENG_CHECK_PARM("-nobots", nullptr); @@ -1687,15 +1685,10 @@ bool UTIL_AreBotsAllowed() return true; } - // allow the using of bots for CS 1.6 - int bots = ENG_CHECK_PARM("-bots", nullptr); - if (bots) - { - return true; - } -#endif - + return cv_bot_enable.value > 0; +#else return false; +#endif } bool UTIL_IsBeta() @@ -1728,18 +1721,10 @@ bool UTIL_AreHostagesImprov() } #ifdef REGAMEDLL_ADD - if (g_engfuncs.pfnEngCheckParm == nullptr) - return false; - - // someday in CS 1.6 - int improv = ENG_CHECK_PARM("-host-improv", nullptr); - if (improv) - { - return true; - } -#endif - + return cv_hostage_ai_enable.value > 0; +#else return false; +#endif } int UTIL_GetNumPlayers() From 3efc5ad16678a25c240560cdd4d8a996b019357d Mon Sep 17 00:00:00 2001 From: s1lentq Date: Wed, 11 Dec 2024 02:19:09 +0700 Subject: [PATCH 13/46] AUG/SG552: Reset maxspeed when zooming --- regamedll/dlls/wpn_shared/wpn_aug.cpp | 9 +++++++++ regamedll/dlls/wpn_shared/wpn_sg552.cpp | 9 +++++++++ 2 files changed, 18 insertions(+) diff --git a/regamedll/dlls/wpn_shared/wpn_aug.cpp b/regamedll/dlls/wpn_shared/wpn_aug.cpp index 988c74808..dfba3fdf9 100644 --- a/regamedll/dlls/wpn_shared/wpn_aug.cpp +++ b/regamedll/dlls/wpn_shared/wpn_aug.cpp @@ -73,6 +73,15 @@ void CAUG::SecondaryAttack() else m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 90; +#ifdef REGAMEDLL_FIXES + if (TheBots) + { + TheBots->OnEvent(EVENT_WEAPON_ZOOMED, m_pPlayer); + } + + m_pPlayer->ResetMaxSpeed(); +#endif + m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.3f; } diff --git a/regamedll/dlls/wpn_shared/wpn_sg552.cpp b/regamedll/dlls/wpn_shared/wpn_sg552.cpp index e86eec412..f9eb61f5f 100644 --- a/regamedll/dlls/wpn_shared/wpn_sg552.cpp +++ b/regamedll/dlls/wpn_shared/wpn_sg552.cpp @@ -72,6 +72,15 @@ void CSG552::SecondaryAttack() else m_pPlayer->pev->fov = m_pPlayer->m_iFOV = 90; +#ifdef REGAMEDLL_FIXES + if (TheBots) + { + TheBots->OnEvent(EVENT_WEAPON_ZOOMED, m_pPlayer); + } + + m_pPlayer->ResetMaxSpeed(); +#endif + m_flNextSecondaryAttack = UTIL_WeaponTimeBase() + 0.3f; } From 8a77bba94d8dd2c962ba0694639c8d4c92e177da Mon Sep 17 00:00:00 2001 From: s1lentq Date: Wed, 11 Dec 2024 03:50:44 +0700 Subject: [PATCH 14/46] always consider all human players on the server to use bot_auto_vacate correctly --- regamedll/dlls/bot/cs_bot_manager.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/regamedll/dlls/bot/cs_bot_manager.cpp b/regamedll/dlls/bot/cs_bot_manager.cpp index 730805bbf..a5be7342e 100644 --- a/regamedll/dlls/bot/cs_bot_manager.cpp +++ b/regamedll/dlls/bot/cs_bot_manager.cpp @@ -889,12 +889,10 @@ void CCSBotManager::MaintainBotQuota() if (m_isLearningMap) return; - int totalHumansInGame = UTIL_HumansInGame(); - int humanPlayersInGame = UTIL_HumansInGame(IGNORE_SPECTATORS); - int spectatorPlayersInGame = UTIL_SpectatorsInGame(); + int humanPlayersInGame = UTIL_HumansInGame(); // don't add bots until local player has been registered, to make sure he's player ID #1 - if (!IS_DEDICATED_SERVER() && totalHumansInGame == 0) + if (!IS_DEDICATED_SERVER() && humanPlayersInGame == 0) return; int desiredBotCount = int(cv_bot_quota.value); @@ -949,7 +947,7 @@ void CCSBotManager::MaintainBotQuota() // wait for a player to join, if necessary if (cv_bot_join_after_player.value > 0.0) { - if (humanPlayersInGame == 0 && spectatorPlayersInGame == 0) + if (humanPlayersInGame == 0) desiredBotCount = 0; } From 6f0d17bb74e8bccc16a2834829cb07c265f7086c Mon Sep 17 00:00:00 2001 From: s1lentq Date: Wed, 11 Dec 2024 23:30:27 +0700 Subject: [PATCH 15/46] fixed issues reported by static analyzer --- regamedll/dlls/bot/cs_bot_chatter.cpp | 1 + regamedll/dlls/career_tasks.cpp | 4 +-- regamedll/dlls/client.cpp | 4 ++- regamedll/dlls/combat.cpp | 2 -- regamedll/dlls/ehandle.h | 4 +++ regamedll/dlls/func_tank.cpp | 2 +- regamedll/dlls/hostage/hostage.cpp | 2 +- .../dlls/hostage/states/hostage_idle.cpp | 2 +- regamedll/dlls/player.cpp | 15 ++++------ regamedll/dlls/saverestore.cpp | 4 +-- regamedll/dlls/sound.cpp | 8 ++---- regamedll/dlls/triggers.cpp | 2 +- regamedll/dlls/vehicle.cpp | 28 +++++++++++++------ regamedll/dlls/weapons.h | 2 -- regamedll/dlls/wpn_shared/wpn_m3.cpp | 2 ++ regamedll/dlls/wpn_shared/wpn_xm1014.cpp | 2 ++ regamedll/game_shared/bot/nav_file.cpp | 2 +- 17 files changed, 48 insertions(+), 38 deletions(-) diff --git a/regamedll/dlls/bot/cs_bot_chatter.cpp b/regamedll/dlls/bot/cs_bot_chatter.cpp index 1476d8d58..f58759fe5 100644 --- a/regamedll/dlls/bot/cs_bot_chatter.cpp +++ b/regamedll/dlls/bot/cs_bot_chatter.cpp @@ -464,6 +464,7 @@ bool BotPhraseManager::Initialize(const char *filename, int bankIndex) phraseData = SharedParse(phraseData); if (!phraseData) { + if (phrase) delete phrase; CONSOLE_ECHO("Error parsing '%s' - expected identifier\n", filename); FREE_FILE(phraseDataFile); return false; diff --git a/regamedll/dlls/career_tasks.cpp b/regamedll/dlls/career_tasks.cpp index 972ccca9b..050a9aab0 100644 --- a/regamedll/dlls/career_tasks.cpp +++ b/regamedll/dlls/career_tasks.cpp @@ -260,7 +260,7 @@ void CCareerTask::OnEvent(GameEventType event, CBasePlayer *pVictim, CBasePlayer while ((pHostage = UTIL_FindEntityByClassname(pHostage, "hostage_entity"))) { - if (pHostage && pHostage->IsDead()) + if (pHostage->IsDead()) hostagesCount++; } @@ -389,7 +389,6 @@ void CCareerTaskManager::Reset(bool deleteTasks) delete task; m_tasks.clear(); - m_nextId = 0; } else { @@ -397,6 +396,7 @@ void CCareerTaskManager::Reset(bool deleteTasks) task->Reset(); } + m_nextId = 0; m_finishedTaskTime = 0; m_finishedTaskRound = 0; m_shouldLatchRoundEndMessage = false; diff --git a/regamedll/dlls/client.cpp b/regamedll/dlls/client.cpp index 198afbfbe..08efa0391 100644 --- a/regamedll/dlls/client.cpp +++ b/regamedll/dlls/client.cpp @@ -811,7 +811,9 @@ void Host_Say(edict_t *pEntity, BOOL teamonly) if (*p == '"') { p++; - p[Q_strlen(p) - 1] = '\0'; + size_t len = Q_strlen(p); + if (len > 0) + p[len - 1] = '\0'; } // Check if buffer contains an invalid unicode sequence diff --git a/regamedll/dlls/combat.cpp b/regamedll/dlls/combat.cpp index 17fe84e27..8c66a4754 100644 --- a/regamedll/dlls/combat.cpp +++ b/regamedll/dlls/combat.cpp @@ -285,8 +285,6 @@ void RadiusDamage(Vector vecSrc, entvars_t *pevInflictor, entvars_t *pevAttacker damageRatio = GetAmountOfPlayerVisible(vecSrc, pEntity); } - damageRatio = GetAmountOfPlayerVisible(vecSrc, pEntity); - float length; #ifdef REGAMEDLL_ADD // allow to damage breakable objects diff --git a/regamedll/dlls/ehandle.h b/regamedll/dlls/ehandle.h index 9a8717826..61d22a5cc 100644 --- a/regamedll/dlls/ehandle.h +++ b/regamedll/dlls/ehandle.h @@ -130,6 +130,10 @@ inline edict_t *EntityHandle::Set(edict_t *pEdict) { m_serialnumber = pEdict->serialnumber; } + else + { + m_serialnumber = 0; + } return pEdict; } diff --git a/regamedll/dlls/func_tank.cpp b/regamedll/dlls/func_tank.cpp index e12c90768..14c2ef6fc 100644 --- a/regamedll/dlls/func_tank.cpp +++ b/regamedll/dlls/func_tank.cpp @@ -302,7 +302,7 @@ void CFuncTank::ControllerPostFrame() Assert(m_pController != nullptr); - if (m_pController->pev->button & IN_ATTACK) + if (m_pController && m_pController->pev->button & IN_ATTACK) { Vector vecForward; UTIL_MakeVectorsPrivate(pev->angles, vecForward, nullptr, nullptr); diff --git a/regamedll/dlls/hostage/hostage.cpp b/regamedll/dlls/hostage/hostage.cpp index e3ddd6750..91c430189 100644 --- a/regamedll/dlls/hostage/hostage.cpp +++ b/regamedll/dlls/hostage/hostage.cpp @@ -624,7 +624,7 @@ void CHostage::TraceAttack(entvars_t *pevAttacker, float flDamage, Vector vecDir BOOL CHostage::TakeDamage(entvars_t *pevInflictor, entvars_t *pevAttacker, float flDamage, int bitsDamageType) { #ifdef REGAMEDLL_ADD - if (!CanTakeDamage(pevAttacker)) + if (pevAttacker && !CanTakeDamage(pevAttacker)) return FALSE; #endif diff --git a/regamedll/dlls/hostage/states/hostage_idle.cpp b/regamedll/dlls/hostage/states/hostage_idle.cpp index c2c311a15..618848fc8 100644 --- a/regamedll/dlls/hostage/states/hostage_idle.cpp +++ b/regamedll/dlls/hostage/states/hostage_idle.cpp @@ -78,7 +78,7 @@ void HostageIdleState::OnUpdate(CHostageImprov *improv) } } - if (m_moveState && improv->IsAtMoveGoal()) + if (m_moveState != NotMoving && improv->IsAtMoveGoal()) { m_moveState = NotMoving; diff --git a/regamedll/dlls/player.cpp b/regamedll/dlls/player.cpp index 5295943a2..95acb8436 100644 --- a/regamedll/dlls/player.cpp +++ b/regamedll/dlls/player.cpp @@ -5158,12 +5158,9 @@ void CBasePlayer::UpdatePlayerSound() m_iExtraSoundTypes = 0; } - if (pSound) - { - pSound->m_vecOrigin = pev->origin; - pSound->m_iVolume = iVolume; - pSound->m_iType |= (bits_SOUND_PLAYER | m_iExtraSoundTypes); - } + pSound->m_vecOrigin = pev->origin; + pSound->m_iVolume = iVolume; + pSound->m_iType |= (bits_SOUND_PLAYER | m_iExtraSoundTypes); // keep track of virtual muzzle flash m_iWeaponFlash -= 256 * gpGlobals->frametime; @@ -5913,7 +5910,7 @@ void EXT_FUNC CBasePlayer::__API_HOOK(Spawn)() TheBots->OnEvent(EVENT_PLAYER_SPAWNED, this); } - m_allowAutoFollowTime = false; + m_allowAutoFollowTime = 0.0f; for (i = 0; i < COMMANDS_TO_TRACK; i++) m_flLastCommandTime[i] = -1; @@ -8470,7 +8467,7 @@ void CBasePlayer::__API_HOOK(SwitchTeam)() UpdateLocation(true); - if (m_iTeam) + if (m_iTeam != UNASSIGNED) { SetScoreboardAttributes(); } @@ -9682,7 +9679,7 @@ void CBasePlayer::PrioritizeAutoBuyString(char (&autobuyString)[MAX_AUTOBUY_LENG int newStringPos = 0; char priorityToken[32]; - if (!priorityString || !autobuyString) + if (!priorityString) return; const char *priorityChar = priorityString; diff --git a/regamedll/dlls/saverestore.cpp b/regamedll/dlls/saverestore.cpp index 897452c4f..514ca64b8 100644 --- a/regamedll/dlls/saverestore.cpp +++ b/regamedll/dlls/saverestore.cpp @@ -250,10 +250,10 @@ edict_t *CSaveRestoreBuffer::EntityFromIndex(int entityIndex) int CSaveRestoreBuffer::EntityFlagsSet(int entityIndex, int flags) { - if (!m_pData || entityIndex < 0) + if (!m_pData) return 0; - if (!m_pData || entityIndex < 0 || entityIndex > m_pData->tableCount) + if (entityIndex < 0 || entityIndex > m_pData->tableCount) return 0; m_pData->pTable[entityIndex].flags |= flags; diff --git a/regamedll/dlls/sound.cpp b/regamedll/dlls/sound.cpp index a4dc0a7d6..25e930e3d 100644 --- a/regamedll/dlls/sound.cpp +++ b/regamedll/dlls/sound.cpp @@ -1362,7 +1362,7 @@ void SENTENCEG_Init() i = 0; - while (rgsentenceg[i].count && i < MAX_SENTENCE_GROUPS) + while (i < MAX_SENTENCE_GROUPS && rgsentenceg[i].count) { USENTENCEG_InitLRU(&(rgsentenceg[i].rgblru[0]), rgsentenceg[i].count); i++; @@ -1380,11 +1380,7 @@ int SENTENCEG_Lookup(const char *sample, char (&sentencenum)[32]) { if (!Q_stricmp(gszallsentencenames[i], sample + 1)) { - if (sentencenum) - { - Q_snprintf(sentencenum, sizeof(sentencenum), "!%d", i); - } - + Q_snprintf(sentencenum, sizeof(sentencenum), "!%d", i); return i; } } diff --git a/regamedll/dlls/triggers.cpp b/regamedll/dlls/triggers.cpp index 1bfd85b94..42e5cbdec 100644 --- a/regamedll/dlls/triggers.cpp +++ b/regamedll/dlls/triggers.cpp @@ -625,7 +625,7 @@ void PlayCDTrack(edict_t *pClient, int iTrack) if (!pClient) return; - if (iTrack < -1 || iTrack > 30) + if (iTrack < -1 || iTrack >= (int)ARRAYSIZE(g_szMP3trackFileMap)) { ALERT(at_console, "TriggerCDAudio - Track %d out of range\n", iTrack); return; diff --git a/regamedll/dlls/vehicle.cpp b/regamedll/dlls/vehicle.cpp index 3ff84b941..7bf2d4184 100644 --- a/regamedll/dlls/vehicle.cpp +++ b/regamedll/dlls/vehicle.cpp @@ -126,7 +126,7 @@ void CFuncVehicle::Blocked(CBaseEntity *pOther) float minz = pev->origin.z; #ifdef REGAMEDLL_FIXES - float maxz = pev->origin.z + (2 * Q_abs(pev->mins.z - pev->maxs.z)); + float maxz = pev->origin.z + (2 * Q_abs(pev->mins.z - pev->maxs.z)); #else float maxz = pev->origin.z + (2 * Q_abs(int(pev->mins.z - pev->maxs.z))); #endif @@ -343,15 +343,20 @@ void CFuncVehicle::CheckTurning() if (pev->speed > 0) { UTIL_TraceLine(m_vFrontRight, m_vFrontRight - (gpGlobals->v_right * 16.0), ignore_monsters, dont_ignore_glass, ENT(pev), &tr); + + if (tr.flFraction != 1.0f) + { + m_iTurnAngle = 1; + } } else if (pev->speed < 0) { UTIL_TraceLine(m_vBackLeft, m_vBackLeft + (gpGlobals->v_right * 16.0), ignore_monsters, dont_ignore_glass, ENT(pev), &tr); - } - if (tr.flFraction != 1.0f) - { - m_iTurnAngle = 1; + if (tr.flFraction != 1.0f) + { + m_iTurnAngle = 1; + } } } else if (m_iTurnAngle > 0) @@ -359,15 +364,20 @@ void CFuncVehicle::CheckTurning() if (pev->speed > 0) { UTIL_TraceLine(m_vFrontLeft, m_vFrontLeft + (gpGlobals->v_right * 16.0), ignore_monsters, dont_ignore_glass, ENT(pev), &tr); + + if (tr.flFraction != 1.0f) + { + m_iTurnAngle = -1; + } } else if (pev->speed < 0) { UTIL_TraceLine(m_vBackRight, m_vBackRight - (gpGlobals->v_right * 16.0), ignore_monsters, dont_ignore_glass, ENT(pev), &tr); - } - if (tr.flFraction != 1.0f) - { - m_iTurnAngle = -1; + if (tr.flFraction != 1.0f) + { + m_iTurnAngle = -1; + } } } diff --git a/regamedll/dlls/weapons.h b/regamedll/dlls/weapons.h index 9266d8434..252c4c5f1 100644 --- a/regamedll/dlls/weapons.h +++ b/regamedll/dlls/weapons.h @@ -1333,7 +1333,6 @@ class CM249: public CBasePlayerWeapon const float M3_MAX_SPEED = 230.0f; const float M3_DAMAGE = 20.0f; -const Vector M3_CONE_VECTOR = Vector(0.0675, 0.0675, 0.0); // special shotgun spreads enum m3_e { @@ -1764,7 +1763,6 @@ class CTMP: public CBasePlayerWeapon const float XM1014_MAX_SPEED = 240.0f; const float XM1014_DAMAGE = 20.0f; -const Vector XM1014_CONE_VECTOR = Vector(0.0725, 0.0725, 0.0); // special shotgun spreads enum xm1014_e { diff --git a/regamedll/dlls/wpn_shared/wpn_m3.cpp b/regamedll/dlls/wpn_shared/wpn_m3.cpp index 64ad7c5f0..e071c19c5 100644 --- a/regamedll/dlls/wpn_shared/wpn_m3.cpp +++ b/regamedll/dlls/wpn_shared/wpn_m3.cpp @@ -1,5 +1,7 @@ #include "precompiled.h" +const Vector M3_CONE_VECTOR = {0.0675, 0.0675, 0.0}; // special shotgun spreads + LINK_ENTITY_TO_CLASS(weapon_m3, CM3, CCSM3) void CM3::Spawn() diff --git a/regamedll/dlls/wpn_shared/wpn_xm1014.cpp b/regamedll/dlls/wpn_shared/wpn_xm1014.cpp index a4e4304eb..fb63a0507 100644 --- a/regamedll/dlls/wpn_shared/wpn_xm1014.cpp +++ b/regamedll/dlls/wpn_shared/wpn_xm1014.cpp @@ -1,5 +1,7 @@ #include "precompiled.h" +const Vector XM1014_CONE_VECTOR = {0.0725, 0.0725, 0.0}; // special shotgun spreads + LINK_ENTITY_TO_CLASS(weapon_xm1014, CXM1014, CCSXM1014) void CXM1014::Spawn() diff --git a/regamedll/game_shared/bot/nav_file.cpp b/regamedll/game_shared/bot/nav_file.cpp index 5c6d65c38..cf97f6f6a 100644 --- a/regamedll/game_shared/bot/nav_file.cpp +++ b/regamedll/game_shared/bot/nav_file.cpp @@ -67,7 +67,7 @@ Place PlaceDirectory::EntryToPlace(EntryType entry) const return UNDEFINED_PLACE; unsigned int i = entry - 1; - if (i > m_directory.size()) + if (i >= m_directory.size()) { DbgAssert(false && "PlaceDirectory::EntryToPlace: Invalid entry"); return UNDEFINED_PLACE; From 1a17ef4e4579a0afa8e08ed0b2a2d2e4f8958530 Mon Sep 17 00:00:00 2001 From: Vaqtincha <51029683+Vaqtincha@users.noreply.github.com> Date: Wed, 11 Dec 2024 21:33:26 +0500 Subject: [PATCH 16/46] Reset bot morale on new match(game) (#1025) --- regamedll/dlls/bot/cs_bot_event.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/regamedll/dlls/bot/cs_bot_event.cpp b/regamedll/dlls/bot/cs_bot_event.cpp index 199616659..70411c8e5 100644 --- a/regamedll/dlls/bot/cs_bot_event.cpp +++ b/regamedll/dlls/bot/cs_bot_event.cpp @@ -56,6 +56,11 @@ void CCSBot::OnEvent(GameEventType event, CBaseEntity *pEntity, CBaseEntity *pOt DecreaseMorale(); } break; +#ifdef REGAMEDLL_FIXES + case EVENT_NEW_MATCH: + m_morale = POSITIVE; // starting a new round makes everyone a little happy + break; +#endif } if (!IsAlive()) From 17ae24e012d29f39d5541fdc107ea8baa256e875 Mon Sep 17 00:00:00 2001 From: s1lentq Date: Thu, 12 Dec 2024 01:31:05 +0700 Subject: [PATCH 17/46] fix build --- regamedll/dlls/ammo.cpp | 2 +- regamedll/dlls/game.cpp | 4 ++-- regamedll/dlls/triggers.cpp | 2 -- regamedll/dlls/weapontype.cpp | 2 +- regamedll/dlls/wpn_shared/wpn_m3.cpp | 2 +- regamedll/dlls/wpn_shared/wpn_xm1014.cpp | 2 +- 6 files changed, 6 insertions(+), 8 deletions(-) diff --git a/regamedll/dlls/ammo.cpp b/regamedll/dlls/ammo.cpp index 1df3622cc..8c264ac78 100644 --- a/regamedll/dlls/ammo.cpp +++ b/regamedll/dlls/ammo.cpp @@ -24,7 +24,7 @@ void CBasePlayerAmmo::Spawn() BOOL CBasePlayerAmmo::AddAmmo(CBaseEntity *pOther) { auto ammoInfo = GetAmmoInfo(pev->classname); - if (pOther->GiveAmmo(ammoInfo->buyClipSize, ammoInfo->ammoName2) == -1) + if (!ammoInfo || pOther->GiveAmmo(ammoInfo->buyClipSize, ammoInfo->ammoName2) == -1) { return FALSE; } diff --git a/regamedll/dlls/game.cpp b/regamedll/dlls/game.cpp index 12f63c1a7..5680db82a 100644 --- a/regamedll/dlls/game.cpp +++ b/regamedll/dlls/game.cpp @@ -470,10 +470,10 @@ void EXT_FUNC GameDLLInit() SERVER_COMMAND("exec game_init.cfg\n"); SERVER_EXECUTE(); - Regamedll_Game_Init(); - #endif // REGAMEDLL_ADD + Regamedll_Game_Init(); + Bot_RegisterCVars(); Tutor_RegisterCVars(); Hostage_RegisterCVars(); diff --git a/regamedll/dlls/triggers.cpp b/regamedll/dlls/triggers.cpp index 42e5cbdec..63282c06e 100644 --- a/regamedll/dlls/triggers.cpp +++ b/regamedll/dlls/triggers.cpp @@ -585,7 +585,6 @@ void CTriggerCDAudio::Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYP PlayTrack(pCaller->edict()); } -#ifdef REGAMEDLL_FIXES const char *g_szMP3trackFileMap[] = { "", "", @@ -617,7 +616,6 @@ const char *g_szMP3trackFileMap[] = "media/Suspense05.mp3", "media/Suspense07.mp3" }; -#endif void PlayCDTrack(edict_t *pClient, int iTrack) { diff --git a/regamedll/dlls/weapontype.cpp b/regamedll/dlls/weapontype.cpp index dd7dc0f82..cc341d7c9 100644 --- a/regamedll/dlls/weapontype.cpp +++ b/regamedll/dlls/weapontype.cpp @@ -545,7 +545,7 @@ WeaponInfoStruct *GetDefaultWeaponInfo(int weaponID) AmmoInfoStruct *GetAmmoInfo(const char *ammoName) { for (auto& info : g_ammoInfo) { - if (!Q_stricmp(info.ammoName1, ammoName)) { + if (info.ammoName1 && !Q_stricmp(info.ammoName1, ammoName)) { return &info; } } diff --git a/regamedll/dlls/wpn_shared/wpn_m3.cpp b/regamedll/dlls/wpn_shared/wpn_m3.cpp index e071c19c5..2f341c951 100644 --- a/regamedll/dlls/wpn_shared/wpn_m3.cpp +++ b/regamedll/dlls/wpn_shared/wpn_m3.cpp @@ -1,6 +1,6 @@ #include "precompiled.h" -const Vector M3_CONE_VECTOR = {0.0675, 0.0675, 0.0}; // special shotgun spreads +const Vector M3_CONE_VECTOR = Vector(0.0675, 0.0675, 0.0); // special shotgun spreads LINK_ENTITY_TO_CLASS(weapon_m3, CM3, CCSM3) diff --git a/regamedll/dlls/wpn_shared/wpn_xm1014.cpp b/regamedll/dlls/wpn_shared/wpn_xm1014.cpp index fb63a0507..c664fe597 100644 --- a/regamedll/dlls/wpn_shared/wpn_xm1014.cpp +++ b/regamedll/dlls/wpn_shared/wpn_xm1014.cpp @@ -1,6 +1,6 @@ #include "precompiled.h" -const Vector XM1014_CONE_VECTOR = {0.0725, 0.0725, 0.0}; // special shotgun spreads +const Vector XM1014_CONE_VECTOR = Vector(0.0725, 0.0725, 0.0); // special shotgun spreads LINK_ENTITY_TO_CLASS(weapon_xm1014, CXM1014, CCSXM1014) From 1579273f62ccbf6b25ac468b90a616baf8609b2d Mon Sep 17 00:00:00 2001 From: s1lentq Date: Thu, 12 Dec 2024 02:08:00 +0700 Subject: [PATCH 18/46] Add target_cdaudio in fgd (Closes #1030) --- .../GameDefinitionFile/regamedll-cs.fgd | 49 ++++++++++++++++++- 1 file changed, 47 insertions(+), 2 deletions(-) diff --git a/regamedll/extra/Toolkit/GameDefinitionFile/regamedll-cs.fgd b/regamedll/extra/Toolkit/GameDefinitionFile/regamedll-cs.fgd index 79fe8333a..3d56907ea 100644 --- a/regamedll/extra/Toolkit/GameDefinitionFile/regamedll-cs.fgd +++ b/regamedll/extra/Toolkit/GameDefinitionFile/regamedll-cs.fgd @@ -1,12 +1,17 @@ // ----------------------------------------------------------------------- // Counter-Strike game definition file (.fgd) -// Version 0.9.0.0 +// Version 0.9.5.0 // Valve Hammer Editor >= 3.5 // Last update: September 25th, 2016 // ----------------------------------------------------------------------- // Based on FGD 0.8.0.0 by Dmitrich! // -// Full compatibility with https://github.com/s1lentq/ReGameDLL_CS +// Full compatibility with https://github.com/rehlds/ReGameDLL_CS +// ----------------------------------------------------------------------- +// December 12th, 2024 (0.9.5.0) +// - Added target_cdaudio +// ----------------------------------------------------------------------- +// // ----------------------------------------------------------------------- // September 25th, 2016 - s1lent (0.9.0.0) // - Removed xen entities. @@ -2323,6 +2328,46 @@ ] ] +// This entity allows to play a specific CD track when the player is within the specified radius around the entity or when triggered +// A brush entity equivalent is available as trigger_cdaudio +@PointClass base(Targetname) color(255 240 128) = target_cdaudio : "CD Audio Target" +[ + health(choices) : "Track #" : -1 = + [ + -1 : "Stop" +// 1 : "None" + 2 : "Track 1" + 3 : "Track 2" + 4 : "Track 3" + 5 : "Track 4" + 6 : "Track 5" + 7 : "Track 6" + 8 : "Track 7" + 9 : "Track 8" + 10 : "Track 9" + 11 : "Track 10" + 12 : "Track 11" + 13 : "Track 12" + 14 : "Track 13" + 15 : "Track 14" + 16 : "Track 15" + 17 : "Track 16" + 18 : "Track 17" + 19 : "Track 18" + 20 : "Track 19" + 21 : "Track 20" + 22 : "Track 21" + 23 : "Track 22" + 24 : "Track 23" + 25 : "Track 24" + 26 : "Track 25" + 27 : "Track 26" + 28 : "Track 27" + 29 : "Track 28" + ] + scale(string) : "Player Radius" : "128.0" // The player must come within this radius for the track to start playing +] + @SolidClass base(Targetname) = trigger_changelevel : "Trigger Change level" [ map(string) : "New map name" From f63ad678c2e4f8639d6a58376d9c8a12c090dbe7 Mon Sep 17 00:00:00 2001 From: s1lentq Date: Sun, 15 Dec 2024 05:21:34 +0700 Subject: [PATCH 19/46] Hostage minor fixes Minor cleanup --- regamedll/dlls/globals.cpp | 1 - regamedll/dlls/globals.h | 1 - regamedll/dlls/hostage/hostage.cpp | 41 +++++++++++++++++++----------- regamedll/dlls/hostage/hostage.h | 6 ----- regamedll/dlls/player.cpp | 2 +- regamedll/regamedll/regamedll.cpp | 1 - 6 files changed, 27 insertions(+), 25 deletions(-) diff --git a/regamedll/dlls/globals.cpp b/regamedll/dlls/globals.cpp index 3f698d59f..d02c8fee9 100644 --- a/regamedll/dlls/globals.cpp +++ b/regamedll/dlls/globals.cpp @@ -11,4 +11,3 @@ BOOL gDisplayTitle; bool g_bIsBeta = false; bool g_bIsCzeroGame = false; bool g_bAllowedCSBot = false; -bool g_bHostageImprov = false; diff --git a/regamedll/dlls/globals.h b/regamedll/dlls/globals.h index 020242918..805fd12ad 100644 --- a/regamedll/dlls/globals.h +++ b/regamedll/dlls/globals.h @@ -38,4 +38,3 @@ extern BOOL gDisplayTitle; extern bool g_bIsBeta; extern bool g_bIsCzeroGame; extern bool g_bAllowedCSBot; -extern bool g_bHostageImprov; diff --git a/regamedll/dlls/hostage/hostage.cpp b/regamedll/dlls/hostage/hostage.cpp index 91c430189..c6f57091c 100644 --- a/regamedll/dlls/hostage/hostage.cpp +++ b/regamedll/dlls/hostage/hostage.cpp @@ -28,7 +28,7 @@ #include "precompiled.h" -cvar_t cv_hostage_ai_enable = { "hostage_ai_enable", "1", 0, 1.0f, nullptr }; +cvar_t cv_hostage_ai_enable = { "hostage_ai_enable", "0", 0, 0.0f, nullptr }; cvar_t cv_hostage_debug = { "hostage_debug", "0", FCVAR_SERVER, 0.0f, nullptr }; cvar_t cv_hostage_stop = { "hostage_stop", "0", FCVAR_SERVER, 0.0f, nullptr }; @@ -269,36 +269,41 @@ void CHostage::Spawn() void CHostage::Precache() { - if (AreImprovAllowed()) + if (cv_hostage_ai_enable.value) { + string_t model = iStringNull; + static int which = 0; switch (which) { default: case REGULAR_GUY: - pev->model = MAKE_STRING("models/hostageA.mdl"); + model = MAKE_STRING("models/hostageA.mdl"); break; case OLD_GUY: - pev->model = MAKE_STRING("models/hostageB.mdl"); + model = MAKE_STRING("models/hostageB.mdl"); break; case BLACK_GUY: - pev->model = MAKE_STRING("models/hostageC.mdl"); + model = MAKE_STRING("models/hostageC.mdl"); break; case GOOFY_GUY: - pev->model = MAKE_STRING("models/hostageD.mdl"); + model = MAKE_STRING("models/hostageD.mdl"); break; } m_whichModel = static_cast(which); - if (++which > 3) - which = 0; + if (++which > GOOFY_GUY) + which = REGULAR_GUY; - if (!g_pFileSystem->FileExists(pev->model)) + if (g_pFileSystem->FileExists(model)) + { + pev->model = model; + } + else { // It seems that the model is missing, so use classic hostages - g_bHostageImprov = false; - pev->model = iStringNull; + CVAR_SET_FLOAT("hostage_ai_enable", 0); } } @@ -347,7 +352,7 @@ void CHostage::IdleThink() const float giveUpTime = (1 / 30.0f); float const updateRate = 0.1f; - if (AreImprovAllowed() && !TheNavAreaList.empty()) + if (cv_hostage_ai_enable.value && !TheNavAreaList.empty()) { if (!m_improv) { @@ -776,7 +781,7 @@ void CHostage::SetDeathActivity() return; } - if (AreImprovAllowed()) + if (cv_hostage_ai_enable.value) { switch (m_LastHitGroup) { @@ -1402,7 +1407,7 @@ void Hostage_RegisterCVars() { // These cvars are only used in czero #ifdef REGAMEDLL_FIXES - if (!AreImprovAllowed()) + if (!cv_hostage_ai_enable.value) return; #endif @@ -1437,7 +1442,7 @@ void CHostageManager::ServerActivate() AddHostage(pHostage); } - if (AreImprovAllowed()) + if (cv_hostage_ai_enable.value) { for (auto& snd : hostageSoundStruct) { m_chatter.AddSound(snd.type, snd.fileName); @@ -1573,6 +1578,9 @@ void SimpleChatter::AddSound(HostageChatterType type, char *filename) Q_snprintf(actualFilename, sizeof(actualFilename), "sound\\%s", filename); + if (!g_pFileSystem->FileExists(actualFilename)) + return; + chatter->file[chatter->count].filename = CloneString(filename); chatter->file[chatter->count].duration = (double)GET_APPROX_WAVE_PLAY_LEN(actualFilename) / 1000.0; @@ -1610,6 +1618,9 @@ void SimpleChatter::Shuffle(ChatterSet *chatter) char *SimpleChatter::GetSound(HostageChatterType type, float *duration) { ChatterSet *chatter = &m_chatter[type]; + if (chatter->count == 0) + return nullptr; + char *sound; Shuffle(chatter); diff --git a/regamedll/dlls/hostage/hostage.h b/regamedll/dlls/hostage/hostage.h index 6bacec2dc..f869cacfb 100644 --- a/regamedll/dlls/hostage/hostage.h +++ b/regamedll/dlls/hostage/hostage.h @@ -285,11 +285,5 @@ class CHostageManager SimpleChatter m_chatter; }; -// Determine whether hostage improv can be used or not -inline bool AreImprovAllowed() -{ - return g_bHostageImprov; -} - void Hostage_RegisterCVars(); void InstallHostageManager(); diff --git a/regamedll/dlls/player.cpp b/regamedll/dlls/player.cpp index 95acb8436..3f23a6293 100644 --- a/regamedll/dlls/player.cpp +++ b/regamedll/dlls/player.cpp @@ -4173,7 +4173,7 @@ void CBasePlayer::PlayerUse() } } - bool useNewHostages = !TheNavAreaList.empty() && AreImprovAllowed(); + bool useNewHostages = !TheNavAreaList.empty() && cv_hostage_ai_enable.value; CBaseEntity *pObject = nullptr; CBaseEntity *pClosest = nullptr; Vector vecLOS; diff --git a/regamedll/regamedll/regamedll.cpp b/regamedll/regamedll/regamedll.cpp index 5e6190d15..9602faa17 100644 --- a/regamedll/regamedll/regamedll.cpp +++ b/regamedll/regamedll/regamedll.cpp @@ -33,7 +33,6 @@ void Regamedll_Game_Init() g_bIsBeta = UTIL_IsBeta(); g_bIsCzeroGame = UTIL_IsGame("czero"); g_bAllowedCSBot = UTIL_AreBotsAllowed(); // determine whether bots can be used or not - g_bHostageImprov = UTIL_AreHostagesImprov(); // determine whether hostage improv can be used or not WeaponInfoReset(); } From 96b2ef2727d3d3ed07db641874fd1c5d56db44f5 Mon Sep 17 00:00:00 2001 From: s1lentq Date: Fri, 28 Mar 2025 01:44:41 +0700 Subject: [PATCH 20/46] Update build.yml --- .github/workflows/build.yml | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index e62c178ed..8217211ff 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -24,6 +24,9 @@ jobs: buildTests: 'Tests' steps: + - name: Configure + run: git config --global --add safe.directory "$GITHUB_WORKSPACE" + - name: Checkout uses: actions/checkout@v4 with: @@ -105,11 +108,6 @@ jobs: container: debian:11-slim steps: - - name: Checkout - uses: actions/checkout@v4 - with: - fetch-depth: 0 - - name: Install dependencies run: | dpkg --add-architecture i386 @@ -121,6 +119,15 @@ jobs: git cmake rsync \ g++ gcc + - name: Configure + run: git config --global --add safe.directory "$GITHUB_WORKSPACE" + + - name: Checkout + uses: actions/checkout@v4 + with: + submodules: recursive + fetch-depth: 0 + - name: Build and Run unittests run: | rm -rf build && CC=gcc CXX=g++ cmake -DCMAKE_BUILD_TYPE=Unittests -B build && cmake --build build -j8 From b59bbb1c83f6a1def9ef856002cf1b581936ddbd Mon Sep 17 00:00:00 2001 From: Alibek Omarov Date: Fri, 28 Mar 2025 01:03:52 +0300 Subject: [PATCH 21/46] CMake improvements, add 64-bit support for use in Xash3D FWGS (#1053) * cmake: do not strip debuginfo during link if DEBUG was enabled * cmake: use compiler id instead of env checks to determine Intel compiler or Clang * cmake: introduce XASH_COMPAT option, which will let regamedll to be built for 64-bit and non-x86 targets * cmake: add LibraryNaming module from hlsdk-portable repository and platform detection header * cmake: now, integrate LibraryNaming into regamedll CMakeLists file. Disable x86 options on non-x86 platforms * server: add support for 64-bit ABI used in Xash3D FWGS --- regamedll/CMakeLists.txt | 94 +++++++--- regamedll/cmake/LibraryNaming.cmake | 198 ++++++++++++++++++++ regamedll/dlls/qstring.h | 35 +++- regamedll/public/build.h | 269 ++++++++++++++++++++++++++++ 4 files changed, 565 insertions(+), 31 deletions(-) create mode 100644 regamedll/cmake/LibraryNaming.cmake create mode 100644 regamedll/public/build.h diff --git a/regamedll/CMakeLists.txt b/regamedll/CMakeLists.txt index bc0a990e9..c1a13f9bd 100644 --- a/regamedll/CMakeLists.txt +++ b/regamedll/CMakeLists.txt @@ -20,20 +20,47 @@ cmake_minimum_required(VERSION 3.1) project(regamedll CXX) +set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_CURRENT_SOURCE_DIR}/cmake") + option(DEBUG "Build with debug information." OFF) option(USE_STATIC_LIBSTDC "Enables static linking libstdc++." OFF) option(USE_LEGACY_LIBC "Enables linking against legacy libc (<= 2.15) for compat with older distros (Debian 8/Ubuntu 16.04/Centos 7)." OFF) +option(XASH_COMPAT "Enable Xash3D FWGS compatiblity (support for it's 64-bit ABI support and crossplatform library suffix)") set(CMAKE_CXX_STANDARD 14) set(CMAKE_CXX_STANDARD_REQUIRED ON) # Avoid -rdynamic -fPIC options -set(CMAKE_SHARED_LIBRARY_CXX_FLAGS "") -set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") +if (NOT XASH_COMPAT) + set(CMAKE_SHARED_LIBRARY_CXX_FLAGS "") + set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") +endif() -set(COMPILE_FLAGS "-m32 -U_FORTIFY_SOURCE") -set(LINK_FLAGS "-m32 -s") -set(LINK_LIBS dl aelf32) +set(COMPILE_FLAGS "-U_FORTIFY_SOURCE") +set(LINK_LIBS dl) + +# do not strip debuginfo during link +if (NOT DEBUG) + set(LINK_FLAGS "-s") +endif() + +# add -m32 flag only on 64-bit systems, if building for 64-bit wasn't enabled with XASH_COMPAT +if (CMAKE_SIZEOF_VOID_P EQUAL 8) + if (XASH_COMPAT) + set(COMPILE_FLAGS "${COMPILE_FLAGS} -DXASH_64BIT") + else() + set(COMPILE_FLAGS "${COMPILE_FLAGS} -m32") + set(LINK_FLAGS "${LINK_FLAGS} -m32") + list(APPEND LINK_LIBS aelf32) + set(CMAKE_SIZEOF_VOID_P 4) + endif() +endif() + +if(XASH_COMPAT) + # Xash3D FWGS Library Naming Scheme compliance + # see documentation: https://github.com/FWGS/xash3d-fwgs/blob/master/Documentation/extensions/library-naming.md + include(LibraryNaming) +endif() set(COMPILE_FLAGS "${COMPILE_FLAGS} -Wall -fno-exceptions -fno-builtin -Wno-unknown-pragmas") @@ -47,7 +74,7 @@ else() endif() # Check Intel C++ compiler -if ("$ENV{CXX}" MATCHES "icpc") +if (CMAKE_CXX_COMPILER_ID STREQUAL "Intel") # # -fp-model=precise # ICC uses -fp-model fast=1 by default for more aggressive optimizations on floating-point calculations @@ -75,11 +102,15 @@ if ("$ENV{CXX}" MATCHES "icpc") set(COMPILE_FLAGS "${COMPILE_FLAGS} -ipo") set(LINK_FLAGS "${LINK_FLAGS} -ipo") endif() -else() - # Produce code optimized for the most common IA32/AMD64/EM64T processors. - # As new processors are deployed in the marketplace, the behavior of this option will change. +elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "Clang") + if (NOT XASH_COMPAT OR XASH_AMD64 OR XASH_X86) + # Produce code optimized for the most common IA32/AMD64/EM64T processors. + # As new processors are deployed in the marketplace, the behavior of this option will change. + set(COMPILE_FLAGS "${COMPILE_FLAGS} \ + -mtune=generic -msse3") + endif() + set(COMPILE_FLAGS "${COMPILE_FLAGS} \ - -mtune=generic -msse3\ -fpermissive -fno-sized-deallocation\ -Wno-delete-non-virtual-dtor -Wno-invalid-offsetof\ -Wno-unused-variable -Wno-unused-value -Wno-unused-result -Wno-unused-function\ @@ -87,7 +118,7 @@ else() -Wno-sign-compare -Wno-format -Wno-ignored-attributes -Wno-strict-aliasing") # Check Clang compiler - if ("$ENV{CXX}" MATCHES "clang") + if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang") set(COMPILE_FLAGS "${COMPILE_FLAGS} \ -Wno-unused-local-typedef\ -Wno-unused-private-field\ @@ -102,16 +133,11 @@ else() # GCC >= 8.3 if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 8.0) - set(COMPILE_FLAGS "${COMPILE_FLAGS} -Wno-stringop-truncation -Wno-format-truncation -Wno-class-memaccess") + set(COMPILE_FLAGS "${COMPILE_FLAGS} -Wno-stringop-truncation -Wno-format-truncation -Wno-class-memaccess -fcf-protection=none") endif() endif() endif() -# GCC >= 8.3 -if (CMAKE_CXX_COMPILER_VERSION VERSION_GREATER_EQUAL 8.0) - set(COMPILE_FLAGS "${COMPILE_FLAGS} -fcf-protection=none") -endif() - if (NOT DEBUG) set(LINK_FLAGS "${LINK_FLAGS} \ -Wl,-gc-sections -Wl,--version-script=\"${PROJECT_SOURCE_DIR}/../version_script.lds\"") @@ -378,14 +404,36 @@ if (USE_STATIC_LIBSTDC) set(LINK_FLAGS "${LINK_FLAGS} -static-libgcc -static-libstdc++") endif() -set(LINK_FLAGS "${LINK_FLAGS} \ - -Wl,-rpath,'$ORIGIN/.' \ - -L${PROJECT_SOURCE_DIR}/lib/linux32") +set(LINK_FLAGS "${LINK_FLAGS} -Wl,-rpath,'$ORIGIN/.'") + +if (CMAKE_SIZEOF_VOID_P EQUAL 4) + set(LINK_FLAGS "${LINK_FLAGS} -L${PROJECT_SOURCE_DIR}/lib/linux32") +endif() set_target_properties(regamedll PROPERTIES - OUTPUT_NAME cs - PREFIX "" COMPILE_FLAGS ${COMPILE_FLAGS} LINK_FLAGS ${LINK_FLAGS} - POSITION_INDEPENDENT_CODE OFF ) + +if (XASH_COMPAT) + if (CMAKE_SYSTEM_NAME STREQUAL "Android") + set_target_properties(regamedll PROPERTIES + OUTPUT_NAME server) + else() + set_target_properties(regamedll PROPERTIES + PREFIX "" + OUTPUT_NAME cs${POSTFIX}) + endif() +else() + set_target_properties(regamedll PROPERTIES + OUTPUT_NAME cs + PREFIX "" + POSITION_INDEPENDENT_CODE OFF) +endif() + +install(TARGETS regamedll + RUNTIME DESTINATION "cstrike/dlls/" + LIBRARY DESTINATION "cstrike/dlls/" + PERMISSIONS OWNER_READ OWNER_WRITE OWNER_EXECUTE + GROUP_READ GROUP_EXECUTE + WORLD_READ WORLD_EXECUTE) diff --git a/regamedll/cmake/LibraryNaming.cmake b/regamedll/cmake/LibraryNaming.cmake new file mode 100644 index 000000000..a20529aed --- /dev/null +++ b/regamedll/cmake/LibraryNaming.cmake @@ -0,0 +1,198 @@ +include(CheckSymbolExists) + +macro(check_build_target symbol) + check_symbol_exists(${symbol} "build.h" ${symbol}) +endmacro() + +macro(check_group_build_target symbol group) + if(NOT ${group}) + check_build_target(${symbol}) + if(${symbol}) + set(${group} TRUE) + endif() + else() + set(${symbol} FALSE) + endif() +endmacro() + +# So there is a problem: +# 1. Number of these symbols only grows, as we support more and more ports +# 2. CMake was written by morons and can't check these symbols in parallel +# 3. MSVC is very slow at everything (startup, parsing, generating error) + +# Solution: group these symbols and set variable if one of them was found +# this way we can reorder to reorder them by most common configurations +# but we can't generate this list anymore! ... OR IS IT ??? + +# Well, after reordering positions in engine's buildenums.h, we can partially autogenerate this list! +# echo "check_build_target(XASH_64BIT)" +# grep "#define PLATFORM" buildenums.h | cut -d' ' -f 2 | cut -d_ -f 2- | awk '{ print "check_group_build_target(XASH_" $1 " XASH_PLATFORM)" }' +# grep "#define ARCHITECTURE" buildenums.h | cut -d' ' -f 2 | cut -d_ -f 2- | awk '{ print "check_group_build_target(XASH_" $1 " XASH_ARCHITECTURE)" +# grep "#define ENDIAN" buildenums.h | cut -d' ' -f 2 | cut -d_ -f 2- | awk '{ print "check_group_build_target(XASH_" $1 "_ENDIAN XASH_ENDIANNESS)"}' +# echo "if(XASH_ARM)" +# grep '^#undef XASH' build.h | grep "XASH_ARM[v_]" | awk '{ print "check_build_target(" $2 ")"}' +# echo "endif()" +# echo "if(XASH_RISCV)" +# grep '^#undef XASH' build.h | grep "XASH_RISCV_" | awk '{ print "check_build_target(" $2 ")"}' +# echo "endif()" + +# NOTE: Android must have priority over Linux to work correctly! + +set(CMAKE_REQUIRED_INCLUDES "${PROJECT_SOURCE_DIR}/public/") +check_build_target(XASH_64BIT) +check_group_build_target(XASH_WIN32 XASH_PLATFORM) +check_group_build_target(XASH_ANDROID XASH_PLATFORM) +check_group_build_target(XASH_LINUX XASH_PLATFORM) +check_group_build_target(XASH_FREEBSD XASH_PLATFORM) +check_group_build_target(XASH_APPLE XASH_PLATFORM) +check_group_build_target(XASH_NETBSD XASH_PLATFORM) +check_group_build_target(XASH_OPENBSD XASH_PLATFORM) +check_group_build_target(XASH_EMSCRIPTEN XASH_PLATFORM) +check_group_build_target(XASH_DOS4GW XASH_PLATFORM) +check_group_build_target(XASH_HAIKU XASH_PLATFORM) +check_group_build_target(XASH_SERENITY XASH_PLATFORM) +check_group_build_target(XASH_IRIX XASH_PLATFORM) +check_group_build_target(XASH_NSWITCH XASH_PLATFORM) +check_group_build_target(XASH_PSVITA XASH_PLATFORM) +check_group_build_target(XASH_WASI XASH_PLATFORM) +check_group_build_target(XASH_SUNOS XASH_PLATFORM) +check_group_build_target(XASH_X86 XASH_ARCHITECTURE) +check_group_build_target(XASH_AMD64 XASH_ARCHITECTURE) +check_group_build_target(XASH_ARM XASH_ARCHITECTURE) +check_group_build_target(XASH_MIPS XASH_ARCHITECTURE) +check_group_build_target(XASH_PPC XASH_ARCHITECTURE) +check_group_build_target(XASH_JS XASH_ARCHITECTURE) +check_group_build_target(XASH_E2K XASH_ARCHITECTURE) +check_group_build_target(XASH_RISCV XASH_ARCHITECTURE) +check_group_build_target(XASH_LITTLE_ENDIAN XASH_ENDIANNESS) +check_group_build_target(XASH_BIG_ENDIAN XASH_ENDIANNESS) +if(XASH_ARM) +check_build_target(XASH_ARM_HARDFP) +check_build_target(XASH_ARM_SOFTFP) +check_build_target(XASH_ARMv4) +check_build_target(XASH_ARMv5) +check_build_target(XASH_ARMv6) +check_build_target(XASH_ARMv7) +check_build_target(XASH_ARMv8) +endif() +if(XASH_RISCV) +check_build_target(XASH_RISCV_DOUBLEFP) +check_build_target(XASH_RISCV_SINGLEFP) +check_build_target(XASH_RISCV_SOFTFP) +endif() +unset(CMAKE_REQUIRED_INCLUDES) + +# engine/common/build.c +if(XASH_ANDROID) + set(BUILDOS "android") +elseif(XASH_WIN32 OR XASH_LINUX OR XASH_APPLE) + set(BUILDOS "") # no prefix for default OS +elseif(XASH_FREEBSD) + set(BUILDOS "freebsd") +elseif(XASH_NETBSD) + set(BUILDOS "netbsd") +elseif(XASH_OPENBSD) + set(BUILDOS "openbsd") +elseif(XASH_EMSCRIPTEN) + set(BUILDOS "emscripten") +elseif(XASH_DOS4GW) + set(BUILDOS "DOS4GW") +elseif(XASH_HAIKU) + set(BUILDOS "haiku") +elseif(XASH_SERENITY) + set(BUILDOS "serenityos") +elseif(XASH_NSWITCH) + set(BUILDOS "nswitch") +elseif(XASH_PSVITA) + set(BUILDOS "psvita") +elseif(XASH_IRIX) + set(BUILDOS "irix") +elseif(XASH_WASI) + set(BUILDOS "wasi") +elseif(XASH_SUNOS) + set(BUILDOS "sunos") +else() + message(SEND_ERROR "Place your operating system name here! If this is a mistake, try to fix conditions above and report a bug") +endif() + +if(XASH_AMD64) + set(BUILDARCH "amd64") +elseif(XASH_X86) + if(XASH_WIN32 OR XASH_LINUX OR XASH_APPLE) + set(BUILDARCH "") # no prefix for default OS + else() + set(BUILDARCH "i386") + endif() +elseif(XASH_ARM AND XASH_64BIT) + set(BUILDARCH "arm64") +elseif(XASH_ARM) + set(BUILDARCH "armv") + if(XASH_ARMv8) + set(BUILDARCH "${BUILDARCH}8_32") + elseif(XASH_ARMv7) + set(BUILDARCH "${BUILDARCH}7") + elseif(XASH_ARMv6) + set(BUILDARCH "${BUILDARCH}6") + elseif(XASH_ARMv5) + set(BUILDARCH "${BUILDARCH}5") + elseif(XASH_ARMv4) + set(BUILDARCH "${BUILDARCH}4") + else() + message(SEND_ERROR "Unknown ARM") + endif() + + if(XASH_ARM_HARDFP) + set(BUILDARCH "${BUILDARCH}hf") + else() + set(BUILDARCH "${BUILDARCH}l") + endif() +elseif(XASH_MIPS) + set(BUILDARCH "mips") + if(XASH_64BIT) + set(BUILDARCH "${BUILDARCH}64") + endif() + + if(XASH_LITTLE_ENDIAN) + set(BUILDARCH "${BUILDARCH}el") + endif() +elseif(XASH_RISCV) + set(BUILDARCH "riscv") + if(XASH_64BIT) + set(BUILDARCH "${BUILDARCH}64") + else() + set(BUILDARCH "${BUILDARCH}32") + endif() + + if(XASH_RISCV_DOUBLEFP) + set(BUILDARCH "${BUILDARCH}d") + elseif(XASH_RISCV_SINGLEFP) + set(BUILDARCH "${BUILDARCH}f") + endif() +elseif(XASH_JS) + set(BUILDARCH "javascript") +elseif(XASH_E2K) + set(BUILDARCH "e2k") +elseif(XASH_PPC) + set(BUILDARCH "ppc") + if(XASH_64BIT) + set(BUILDARCH "${BUILDARCH}64") + endif() + + if(XASH_LITTLE_ENDIAN) + set(BUILDARCH "${BUILDARCH}el") + endif() +else() + message(SEND_ERROR "Place your architecture name here! If this is a mistake, try to fix conditions above and report a bug") +endif() + +if(BUILDOS STREQUAL "android") + set(POSTFIX "") # force disable for Android, as Android ports aren't distributed in normal way and doesn't follow library naming +elseif(BUILDOS AND BUILDARCH) + set(POSTFIX "_${BUILDOS}_${BUILDARCH}") +elseif(BUILDARCH) + set(POSTFIX "_${BUILDARCH}") +else() + set(POSTFIX "") +endif() + +message(STATUS "Library postfix: " ${POSTFIX}) diff --git a/regamedll/dlls/qstring.h b/regamedll/dlls/qstring.h index 0b158292b..1f5d679dd 100644 --- a/regamedll/dlls/qstring.h +++ b/regamedll/dlls/qstring.h @@ -30,16 +30,18 @@ #define QSTRING_DEFINE -constexpr unsigned int iStringNull = {0}; - // Quake string (helper class) class QString final { public: +#if XASH_64BIT + using qstring_t = int; +#else using qstring_t = unsigned int; +#endif - QString(): m_string(iStringNull) {}; - QString(qstring_t string): m_string(string) {}; + QString(); + QString(qstring_t string); bool IsNull() const; bool IsNullOrEmpty() const; @@ -52,13 +54,15 @@ class QString final bool operator==(const char *pszString) const; operator const char *() const; - operator unsigned int() const; + operator qstring_t() const; const char *str() const; private: qstring_t m_string; }; +constexpr QString::qstring_t iStringNull = {0}; + #ifdef USE_QSTRING #define string_t QString #endif @@ -70,10 +74,25 @@ class QString final extern globalvars_t *gpGlobals; -#define STRING(offset) ((const char *)(gpGlobals->pStringBase + (unsigned int)(offset))) -#define MAKE_STRING(str) ((unsigned int)(str) - (unsigned int)(STRING(0))) +#define STRING(offset) ((const char *)(gpGlobals->pStringBase + (QString::qstring_t)(offset))) +#if XASH_64BIT +// Xash3D FWGS in 64-bit mode has internal string pool which allows mods to continue use 32-bit string_t +inline int MAKE_STRING(const char *str) +{ + ptrdiff_t diff = str - STRING(0); + if (diff >= INT_MIN && diff <= INT_MAX) + return (int)diff; + + return ALLOC_STRING(str); +} +#else +#define MAKE_STRING(str) ((QString::qstring_t)(str) - (QString::qstring_t)(STRING(0))) +#endif // Inlines +inline QString::QString(): m_string(iStringNull) {} +inline QString::QString(qstring_t string): m_string(string) {} + inline bool QString::IsNull() const { return m_string == iStringNull; @@ -115,7 +134,7 @@ inline QString::operator const char *() const return str(); } -inline QString::operator unsigned int() const +inline QString::operator qstring_t() const { return m_string; } diff --git a/regamedll/public/build.h b/regamedll/public/build.h new file mode 100644 index 000000000..24fd9d5bb --- /dev/null +++ b/regamedll/public/build.h @@ -0,0 +1,269 @@ +/* +build.h - compile-time build information + +This is free and unencumbered software released into the public domain. + +Anyone is free to copy, modify, publish, use, compile, sell, or +distribute this software, either in source code form or as a compiled +binary, for any purpose, commercial or non-commercial, and by any +means. + +In jurisdictions that recognize copyright laws, the author or authors +of this software dedicate any and all copyright interest in the +software to the public domain. We make this dedication for the benefit +of the public at large and to the detriment of our heirs and +successors. We intend this dedication to be an overt act of +relinquishment in perpetuity of all present and future rights to this +software under copyright law. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +OTHER DEALINGS IN THE SOFTWARE. + +For more information, please refer to +*/ +#pragma once +#ifndef BUILD_H +#define BUILD_H + +/* +All XASH_* macros set by this header are guaranteed to have positive value +otherwise not defined. + +Every macro is intended to be the unified interface for buildsystems that lack +platform & CPU detection, and a neat quick way for checks in platform code +For Q_build* macros, refer to buildenums.h + +Any new define must be undefined at first +You can generate #undef list below with this oneliner: + $ sed 's/\t//g' build.h | grep '^#define XASH' | awk '{ print $2 }' | \ + sort | uniq | awk '{ print "#undef " $1 }' + +Then you can use another oneliner to query all variables: + $ grep '^#undef XASH' build.h | awk '{ print $2 }' +*/ + +#undef XASH_64BIT +#undef XASH_AMD64 +#undef XASH_ANDROID +#undef XASH_APPLE +#undef XASH_ARM +#undef XASH_ARM_HARDFP +#undef XASH_ARM_SOFTFP +#undef XASH_ARMv4 +#undef XASH_ARMv5 +#undef XASH_ARMv6 +#undef XASH_ARMv7 +#undef XASH_ARMv8 +#undef XASH_BIG_ENDIAN +#undef XASH_DOS4GW +#undef XASH_E2K +#undef XASH_EMSCRIPTEN +#undef XASH_FREEBSD +#undef XASH_HAIKU +#undef XASH_IOS +#undef XASH_IRIX +#undef XASH_JS +#undef XASH_LINUX +#undef XASH_LITTLE_ENDIAN +#undef XASH_MIPS +#undef XASH_MOBILE_PLATFORM +#undef XASH_NETBSD +#undef XASH_OPENBSD +#undef XASH_POSIX +#undef XASH_PPC +#undef XASH_RISCV +#undef XASH_RISCV_DOUBLEFP +#undef XASH_RISCV_SINGLEFP +#undef XASH_RISCV_SOFTFP +#undef XASH_SERENITY +#undef XASH_SUNOS +#undef XASH_WIN32 +#undef XASH_X86 +#undef XASH_NSWITCH +#undef XASH_PSVITA +#undef XASH_WASI +#undef XASH_WASM + +//================================================================ +// +// PLATFORM DETECTION CODE +// +//================================================================ +#if defined _WIN32 + #define XASH_WIN32 1 +#elif defined __EMSCRIPTEN__ + #define XASH_EMSCRIPTEN 1 +#elif defined __WATCOMC__ && defined __DOS__ + #define XASH_DOS4GW 1 +#else // POSIX compatible + #define XASH_POSIX 1 + #if defined __linux__ + #if defined __ANDROID__ + #define XASH_ANDROID 1 + #endif + #define XASH_LINUX 1 + #elif defined __FreeBSD__ + #define XASH_FREEBSD 1 + #elif defined __NetBSD__ + #define XASH_NETBSD 1 + #elif defined __OpenBSD__ + #define XASH_OPENBSD 1 + #elif defined __HAIKU__ + #define XASH_HAIKU 1 + #elif defined __serenity__ + #define XASH_SERENITY 1 + #elif defined __sgi + #define XASH_IRIX 1 + #elif defined __APPLE__ + #include + #define XASH_APPLE 1 + #if TARGET_OS_IOS + #define XASH_IOS 1 + #endif // TARGET_OS_IOS + #elif defined __SWITCH__ + #define XASH_NSWITCH 1 + #elif defined __vita__ + #define XASH_PSVITA 1 + #elif defined __wasi__ + #define XASH_WASI 1 + #elif defined __sun__ + #define XASH_SUNOS 1 + #else + #error + #endif +#endif + +// XASH_SAILFISH is special: SailfishOS by itself is a normal GNU/Linux platform +// It doesn't make sense to split it to separate platform +// but we still need XASH_MOBILE_PLATFORM for the engine. +// So this macro is defined entirely in build-system: see main wscript +// HLSDK/PrimeXT/other SDKs users note: you may ignore this macro +#if XASH_ANDROID || XASH_IOS || XASH_NSWITCH || XASH_PSVITA || XASH_SAILFISH + #define XASH_MOBILE_PLATFORM 1 +#endif + +//================================================================ +// +// ENDIANNESS DEFINES +// +//================================================================ + +#if !defined XASH_ENDIANNESS + #if defined XASH_WIN32 || __LITTLE_ENDIAN__ + //!!! Probably all WinNT installations runs in little endian + #define XASH_LITTLE_ENDIAN 1 + #elif __BIG_ENDIAN__ + #define XASH_BIG_ENDIAN 1 + #elif defined __BYTE_ORDER__ && defined __ORDER_BIG_ENDIAN__ && defined __ORDER_LITTLE_ENDIAN__ // some compilers define this + #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__ + #define XASH_BIG_ENDIAN 1 + #elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ + #define XASH_LITTLE_ENDIAN 1 + #endif + #else + #include + #if __BYTE_ORDER == __BIG_ENDIAN + #define XASH_BIG_ENDIAN 1 + #elif __BYTE_ORDER == __LITTLE_ENDIAN + #define XASH_LITTLE_ENDIAN 1 + #endif + #endif // !XASH_WIN32 +#endif + +//================================================================ +// +// CPU ARCHITECTURE DEFINES +// +//================================================================ +#if defined __x86_64__ || defined _M_X64 + #define XASH_64BIT 1 + #define XASH_AMD64 1 +#elif defined __i386__ || defined _X86_ || defined _M_IX86 + #define XASH_X86 1 +#elif defined __aarch64__ || defined _M_ARM64 + #define XASH_64BIT 1 + #define XASH_ARM 8 +#elif defined __mips__ + #define XASH_MIPS 1 +#elif defined __EMSCRIPTEN__ + #define XASH_JS 1 +#elif defined __e2k__ + #define XASH_64BIT 1 + #define XASH_E2K 1 +#elif defined __PPC__ || defined __powerpc__ + #define XASH_PPC 1 + #if defined __PPC64__ || defined __powerpc64__ + #define XASH_64BIT 1 + #endif +#elif defined _M_ARM // msvc + #define XASH_ARM 7 + #define XASH_ARM_HARDFP 1 +#elif defined __arm__ + #if __ARM_ARCH == 8 || __ARM_ARCH_8__ + #define XASH_ARM 8 + #elif __ARM_ARCH == 7 || __ARM_ARCH_7__ + #define XASH_ARM 7 + #elif __ARM_ARCH == 6 || __ARM_ARCH_6__ || __ARM_ARCH_6J__ + #define XASH_ARM 6 + #elif __ARM_ARCH == 5 || __ARM_ARCH_5__ + #define XASH_ARM 5 + #elif __ARM_ARCH == 4 || __ARM_ARCH_4__ + #define XASH_ARM 4 + #else + #error "Unknown ARM" + #endif + + #if defined __SOFTFP__ || __ARM_PCS_VFP == 0 + #define XASH_ARM_SOFTFP 1 + #else // __SOFTFP__ + #define XASH_ARM_HARDFP 1 + #endif // __SOFTFP__ +#elif defined __riscv + #define XASH_RISCV 1 + + #if __riscv_xlen == 64 + #define XASH_64BIT 1 + #elif __riscv_xlen != 32 + #error "Unknown RISC-V ABI" + #endif + + #if defined __riscv_float_abi_soft + #define XASH_RISCV_SOFTFP 1 + #elif defined __riscv_float_abi_single + #define XASH_RISCV_SINGLEFP 1 + #elif defined __riscv_float_abi_double + #define XASH_RISCV_DOUBLEFP 1 + #else + #error "Unknown RISC-V float ABI" + #endif +#elif defined __wasm__ + #if defined __wasm64__ + #define XASH_64BIT 1 + #endif + #define XASH_WASM 1 +#else + #error "Place your architecture name here! If this is a mistake, try to fix conditions above and report a bug" +#endif + +#if !XASH_64BIT && ( defined( __LP64__ ) || defined( _LP64 )) +#define XASH_64BIT 1 +#endif + +#if XASH_ARM == 8 + #define XASH_ARMv8 1 +#elif XASH_ARM == 7 + #define XASH_ARMv7 1 +#elif XASH_ARM == 6 + #define XASH_ARMv6 1 +#elif XASH_ARM == 5 + #define XASH_ARMv5 1 +#elif XASH_ARM == 4 + #define XASH_ARMv4 1 +#endif + +#endif // BUILD_H From a7395b054d0173491f6f2aca0a90475bf7a6b073 Mon Sep 17 00:00:00 2001 From: Huga <93875972+Huga22118@users.noreply.github.com> Date: Fri, 28 Mar 2025 05:06:17 +0700 Subject: [PATCH 22/46] Bot Chatter: Bots will react to enemy snipers presence (#1055) Friendly fire fixes Bot Chatter: Bots will react to enemy snipers presence previously unused chatter on both 1.6 and czero but is used on cs source Probably fixed where teammate that use sniperrifles looking at bots that don't use sniperrifles got warned --- regamedll/dlls/bot/cs_bot.h | 22 +++++++++ regamedll/dlls/bot/cs_bot_chatter.cpp | 50 +++++++++++++++++++ regamedll/dlls/bot/cs_bot_chatter.h | 15 ++++++ regamedll/dlls/bot/cs_bot_init.cpp | 5 ++ regamedll/dlls/bot/cs_bot_update.cpp | 23 +++++++-- regamedll/dlls/bot/cs_bot_vision.cpp | 69 +++++++++++++++++++++++++++ 6 files changed, 181 insertions(+), 3 deletions(-) diff --git a/regamedll/dlls/bot/cs_bot.h b/regamedll/dlls/bot/cs_bot.h index 9670744f9..ea22a18dc 100644 --- a/regamedll/dlls/bot/cs_bot.h +++ b/regamedll/dlls/bot/cs_bot.h @@ -533,6 +533,11 @@ class CCSBot: public CBot bool IsAwareOfEnemyDeath() const; // return true if we *noticed* that our enemy died int GetLastVictimID() const; // return the ID (entindex) of the last victim we killed, or zero +#ifdef REGAMEDLL_ADD + bool CanSeeSniper(void) const; ///< return true if we can see an enemy sniper + bool HasSeenSniperRecently(void) const; ///< return true if we have seen a sniper recently +#endif + // navigation bool HasPath() const; void DestroyPath(); @@ -921,6 +926,11 @@ class CCSBot: public CBot float m_fireWeaponTimestamp; +#ifdef REGAMEDLL_ADD + bool m_isEnemySniperVisible; ///< do we see an enemy sniper right now + CountdownTimer m_sawEnemySniperTimer; ///< tracking time since saw enemy sniper +#endif + // reaction time system enum { MAX_ENEMY_QUEUE = 20 }; struct ReactionState @@ -1250,6 +1260,18 @@ inline int CCSBot::GetLastVictimID() const return m_lastVictimID; } +#ifdef REGAMEDLL_ADD +inline bool CCSBot::CanSeeSniper(void) const +{ + return m_isEnemySniperVisible; +} + +inline bool CCSBot::HasSeenSniperRecently(void) const +{ + return !m_sawEnemySniperTimer.IsElapsed(); +} +#endif + inline bool CCSBot::HasPath() const { return m_pathLength != 0; diff --git a/regamedll/dlls/bot/cs_bot_chatter.cpp b/regamedll/dlls/bot/cs_bot_chatter.cpp index f58759fe5..d48898ae7 100644 --- a/regamedll/dlls/bot/cs_bot_chatter.cpp +++ b/regamedll/dlls/bot/cs_bot_chatter.cpp @@ -246,6 +246,17 @@ void BotHostageBeingTakenMeme::Interpret(CCSBot *pSender, CCSBot *pReceiver) con pReceiver->GetChatter()->Say("Affirmative"); } +#ifdef REGAMEDLL_ADD +//--------------------------------------------------------------------------------------------------------------- +/** + * A teammate warned about snipers, so we shouldn't warn again for awhile + */ +void BotWarnSniperMeme::Interpret(CCSBot* sender, CCSBot* receiver) const +{ + receiver->GetChatter()->FriendSpottedSniper(); +} +#endif + BotSpeakable::BotSpeakable() { m_phrase = nullptr; @@ -1270,6 +1281,9 @@ void BotChatterInterface::Reset() m_planInterval.Invalidate(); m_encourageTimer.Invalidate(); m_escortingHostageTimer.Invalidate(); +#ifdef REGAMEDLL_ADD + m_warnSniperTimer.Invalidate(); +#endif } // Register a statement for speaking @@ -1626,6 +1640,42 @@ void BotChatterInterface::EnemySpotted() AddStatement(say); } +#ifdef REGAMEDLL_ADD +//--------------------------------------------------------------------------------------------------------------- +/** + * If a friend warned of snipers, don't warn again for awhile + */ +void BotChatterInterface::FriendSpottedSniper(void) +{ + m_warnSniperTimer.Start(60.0f); +} + +//--------------------------------------------------------------------------------------------------------------- +/** + * Warn of an enemy sniper + */ +void BotChatterInterface::SpottedSniper(void) +{ + if (!m_warnSniperTimer.IsElapsed()) + { + return; + } + + if (m_me->GetFriendsRemaining() == 0) + { + // no-one to warn + return; + } + + BotStatement* say = new BotStatement(this, REPORT_INFORMATION, 10.0f); + + say->AppendPhrase(TheBotPhrases->GetPhrase("SniperWarning")); + say->AttachMeme(new BotWarnSniperMeme()); + + AddStatement(say); +} +#endif + NOXREF void BotChatterInterface::Clear(Place place) { BotStatement *say = new BotStatement(this, REPORT_INFORMATION, 10.0f); diff --git a/regamedll/dlls/bot/cs_bot_chatter.h b/regamedll/dlls/bot/cs_bot_chatter.h index 4a4591cf6..8d3a5baa0 100644 --- a/regamedll/dlls/bot/cs_bot_chatter.h +++ b/regamedll/dlls/bot/cs_bot_chatter.h @@ -140,6 +140,14 @@ class BotRequestReportMeme: public BotMeme virtual void Interpret(CCSBot *pSender, CCSBot *pReceiver) const; // cause the given bot to act on this meme }; +#ifdef REGAMEDLL_ADD +class BotWarnSniperMeme : public BotMeme +{ +public: + virtual void Interpret(CCSBot* sender, CCSBot* receiver) const; ///< cause the given bot to act on this meme +}; +#endif + enum BotStatementType { REPORT_VISIBLE_ENEMIES, @@ -531,6 +539,10 @@ class BotChatterInterface void KilledFriend(); void FriendlyFire(); +#ifdef REGAMEDLL_ADD + void SpottedSniper(void); + void FriendSpottedSniper(void); +#endif bool SeesAtLeastOneEnemy() const { return m_seeAtLeastOneEnemy; } private: @@ -557,6 +569,9 @@ class BotChatterInterface CountdownTimer m_spottedLooseBombTimer; CountdownTimer m_heardNoiseTimer; CountdownTimer m_escortingHostageTimer; +#ifdef REGAMEDLL_ADD + CountdownTimer m_warnSniperTimer; +#endif }; inline BotChatterInterface::VerbosityType BotChatterInterface::GetVerbosity() const diff --git a/regamedll/dlls/bot/cs_bot_init.cpp b/regamedll/dlls/bot/cs_bot_init.cpp index 665b3c337..c7a19bb0b 100644 --- a/regamedll/dlls/bot/cs_bot_init.cpp +++ b/regamedll/dlls/bot/cs_bot_init.cpp @@ -194,6 +194,11 @@ void CCSBot::ResetValues() m_currentArea = nullptr; m_lastKnownArea = nullptr; +#ifdef REGAMEDLL_ADD + m_isEnemySniperVisible = false; + m_sawEnemySniperTimer.Invalidate(); +#endif + m_avoidFriendTimer.Invalidate(); m_isFriendInTheWay = false; m_isWaitingBehindFriend = false; diff --git a/regamedll/dlls/bot/cs_bot_update.cpp b/regamedll/dlls/bot/cs_bot_update.cpp index 37d496659..de75bf6aa 100644 --- a/regamedll/dlls/bot/cs_bot_update.cpp +++ b/regamedll/dlls/bot/cs_bot_update.cpp @@ -255,7 +255,7 @@ void CCSBot::Update() Vector dir = m_spotEncounter->path.to - m_spotEncounter->path.from; float length = dir.NormalizeInPlace(); - for (auto &order : m_spotEncounter->spotList) { + for (auto& order : m_spotEncounter->spotList) { UTIL_DrawBeamPoints(m_spotEncounter->path.from + order.t * length * dir, *order.spot->GetPosition(), 3, 0, 255, 255); } } @@ -339,7 +339,7 @@ void CCSBot::Update() UpdateReactionQueue(); // "threat" may be the same as our current enemy - CBasePlayer *threat = GetRecognizedEnemy(); + CBasePlayer* threat = GetRecognizedEnemy(); if (threat) { // adjust our personal "safe" time @@ -592,6 +592,10 @@ void CCSBot::Update() SecondaryAttack(); } +#ifdef REGAMEDLL_ADD + if (!IsBlind()) + { +#endif // check encounter spots UpdatePeripheralVision(); @@ -601,11 +605,24 @@ void CCSBot::Update() GetChatter()->SpottedBomber(GetBomber()); } +#ifdef REGAMEDLL_ADD + // watch for snipers + if (CanSeeSniper() && !HasSeenSniperRecently()) + { + GetChatter()->SpottedSniper(); + + const float sniperRecentInterval = 20.0f; + m_sawEnemySniperTimer.Start(sniperRecentInterval); + } +#endif + if (CanSeeLooseBomb()) { GetChatter()->SpottedLooseBomb(TheCSBots()->GetLooseBomb()); } - +#ifdef REGAMEDLL_ADD +} +#endif // Scenario interrupts switch (TheCSBots()->GetScenario()) { diff --git a/regamedll/dlls/bot/cs_bot_vision.cpp b/regamedll/dlls/bot/cs_bot_vision.cpp index f7b16acc5..6e9d8ddc8 100644 --- a/regamedll/dlls/bot/cs_bot_vision.cpp +++ b/regamedll/dlls/bot/cs_bot_vision.cpp @@ -697,6 +697,13 @@ CBasePlayer *CCSBot::FindMostDangerousThreat() m_closestVisibleFriend = nullptr; m_closestVisibleHumanFriend = nullptr; +#ifdef REGAMEDLL_ADD + m_isEnemySniperVisible = false; + CBasePlayer* sniperThreat = NULL; + float sniperThreatRange = 99999999999.9f; + bool sniperThreatIsFacingMe = false; +#endif + float closeFriendRange = 99999999999.9f; float closeHumanFriendRange = 99999999999.9f; @@ -789,6 +796,51 @@ CBasePlayer *CCSBot::FindMostDangerousThreat() Vector d = pev->origin - pPlayer->pev->origin; float distSq = d.LengthSquared(); +#ifdef REGAMEDLL_ADD + if (isSniperRifle(pPlayer->m_pActiveItem)) { + m_isEnemySniperVisible = true; + if (sniperThreat) + { + if (IsPlayerLookingAtMe(pPlayer)) + { + if (sniperThreatIsFacingMe) + { + // several snipers are facing us - keep closest + if (distSq < sniperThreatRange) + { + sniperThreat = pPlayer; + sniperThreatRange = distSq; + sniperThreatIsFacingMe = true; + } + } + else + { + // even if this sniper is farther away, keep it because he's aiming at us + sniperThreat = pPlayer; + sniperThreatRange = distSq; + sniperThreatIsFacingMe = true; + } + } + else + { + // this sniper is not looking at us, only consider it if we dont have a sniper facing us + if (!sniperThreatIsFacingMe && distSq < sniperThreatRange) + { + sniperThreat = pPlayer; + sniperThreatRange = distSq; + } + } + } + else + { + // first sniper we see + sniperThreat = pPlayer; + sniperThreatRange = distSq; + sniperThreatIsFacingMe = IsPlayerLookingAtMe(pPlayer); + } + } +#endif + // maintain set of visible threats, sorted by increasing distance if (threatCount == 0) { @@ -950,6 +1002,23 @@ CBasePlayer *CCSBot::FindMostDangerousThreat() { return currentThreat; } + + // if we are a sniper and we see a sniper threat, attack it unless + // there are other close enemies facing me + if (IsSniper() && sniperThreat) + { + const float closeCombatRange = 500.0f; + + for (t = 0; t < threatCount; ++t) + { + if (threat[t].range < closeCombatRange && IsPlayerLookingAtMe(threat[t].enemy)) + { + return threat[t].enemy; + } + } + + return sniperThreat; + } #endif // otherwise, find the closest threat that without using shield From 756deb1ea9cbb5e8222de8f3ac726f80c1c1c24c Mon Sep 17 00:00:00 2001 From: golukon <119600102+golukon@users.noreply.github.com> Date: Fri, 28 Mar 2025 01:08:42 +0300 Subject: [PATCH 23/46] fix: calculate UpdateLocation fun not so often (#1040) --- regamedll/dlls/player.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/regamedll/dlls/player.cpp b/regamedll/dlls/player.cpp index 3f23a6293..ceaa9dbed 100644 --- a/regamedll/dlls/player.cpp +++ b/regamedll/dlls/player.cpp @@ -10116,7 +10116,11 @@ bool CBasePlayer::IsObservingPlayer(CBasePlayer *pPlayer) void CBasePlayer::UpdateLocation(bool forceUpdate) { +#ifdef REGAMEDLL_FIXES + if (!forceUpdate && m_flLastUpdateTime > gpGlobals->time - 2.0f) +#else if (!forceUpdate && m_flLastUpdateTime >= gpGlobals->time + 2.0f) +#endif return; const char *placeName = nullptr; From 6adb795fee5a00cbccb02004aa4dd8909f4c2b35 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Francisco=20Mu=C3=B1oz?= Date: Thu, 27 Mar 2025 19:09:24 -0300 Subject: [PATCH 24/46] Team Say refactory/enhancement (#1042) Disable say_team when FFA mode is enabled Only for CT and T, Spectators can still use say_team --- regamedll/dlls/client.cpp | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/regamedll/dlls/client.cpp b/regamedll/dlls/client.cpp index 08efa0391..63560fad6 100644 --- a/regamedll/dlls/client.cpp +++ b/regamedll/dlls/client.cpp @@ -841,6 +841,12 @@ void Host_Say(edict_t *pEntity, BOOL teamonly) char *pszConsoleFormat = nullptr; bool consoleUsesPlaceName = false; +#ifdef REGAMEDLL_ADD + // there's no team on FFA mode + if (teamonly && CSGameRules()->IsFreeForAll() && (pPlayer->m_iTeam == CT || pPlayer->m_iTeam == TERRORIST)) + teamonly = FALSE; +#endif + // team only if (teamonly) { @@ -995,7 +1001,13 @@ void Host_Say(edict_t *pEntity, BOOL teamonly) if (gpGlobals->deathmatch != 0.0f && CSGameRules()->m_VoiceGameMgr.PlayerHasBlockedPlayer(pReceiver, pPlayer)) continue; - if (teamonly && pReceiver->m_iTeam != pPlayer->m_iTeam) + if (teamonly +#ifdef REGAMEDLL_FIXES + && CSGameRules()->PlayerRelationship(pPlayer, pReceiver) != GR_TEAMMATE +#else + && pReceiver->m_iTeam != pPlayer->m_iTeam +#endif + ) continue; if ( @@ -1008,7 +1020,13 @@ void Host_Say(edict_t *pEntity, BOOL teamonly) continue; } - if ((pReceiver->m_iIgnoreGlobalChat == IGNOREMSG_ENEMY && pReceiver->m_iTeam == pPlayer->m_iTeam) + if ((pReceiver->m_iIgnoreGlobalChat == IGNOREMSG_ENEMY +#ifdef REGAMEDLL_FIXES + && CSGameRules()->PlayerRelationship(pPlayer, pReceiver) == GR_TEAMMATE +#else + && pReceiver->m_iTeam == pPlayer->m_iTeam +#endif + ) || pReceiver->m_iIgnoreGlobalChat == IGNOREMSG_NONE) { MESSAGE_BEGIN(MSG_ONE, gmsgSayText, nullptr, pReceiver->pev); From b8e9726347ef4b02803923f8ba6248c0f598ce6c Mon Sep 17 00:00:00 2001 From: Vaqtincha <51029683+Vaqtincha@users.noreply.github.com> Date: Fri, 28 Mar 2025 03:09:56 +0500 Subject: [PATCH 25/46] fix: bots can't buy sec ammo if preferred pistol (ex. "WeaponPreference = deagle" in BotProfile.db) (#1034) --- regamedll/dlls/bot/states/cs_bot_buy.cpp | 23 ++++++++++++++++------- 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/regamedll/dlls/bot/states/cs_bot_buy.cpp b/regamedll/dlls/bot/states/cs_bot_buy.cpp index f210423e9..c34351f07 100644 --- a/regamedll/dlls/bot/states/cs_bot_buy.cpp +++ b/regamedll/dlls/bot/states/cs_bot_buy.cpp @@ -462,17 +462,26 @@ void BuyState::OnUpdate(CCSBot *me) me->ClientCommand("vesthelm"); me->ClientCommand("vest"); - // pistols - if we have no preferred pistol, buy at random - if (TheCSBots()->AllowPistols() && !me->GetProfile()->HasPistolPreference()) + if (TheCSBots()->AllowPistols() +#ifndef REGAMEDLL_FIXES + && !me->GetProfile()->HasPistolPreference() +#endif + ) { if (m_buyPistol) { - int which = RANDOM_LONG(0, MAX_BUY_WEAPON_SECONDARY - 1); +#ifdef REGAMEDLL_FIXES + // pistols - if we have no preferred pistol, buy at random + if (!me->GetProfile()->HasPistolPreference()) +#endif + { + int which = RANDOM_LONG(0, MAX_BUY_WEAPON_SECONDARY - 1); - if (me->m_iTeam == TERRORIST) - me->ClientCommand(secondaryWeaponBuyInfoT[which].buyAlias); - else - me->ClientCommand(secondaryWeaponBuyInfoCT[which].buyAlias); + if (me->m_iTeam == TERRORIST) + me->ClientCommand(secondaryWeaponBuyInfoT[which].buyAlias); + else + me->ClientCommand(secondaryWeaponBuyInfoCT[which].buyAlias); + } // only buy one pistol m_buyPistol = false; From 316405b00df72c1703cacc8f09decb6a3d60324c Mon Sep 17 00:00:00 2001 From: Vaqtincha <51029683+Vaqtincha@users.noreply.github.com> Date: Fri, 28 Mar 2025 03:10:32 +0500 Subject: [PATCH 26/46] add new cvar "bot_excellent_morale" (#1035) --- README.md | 1 + dist/game.cfg | 9 ++++++++- regamedll/dlls/bot/cs_bot.h | 5 +++++ regamedll/dlls/bot/cs_bot_init.cpp | 2 ++ regamedll/dlls/bot/cs_bot_init.h | 1 + 5 files changed, 17 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 7bdfc9f81..88c393b12 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,7 @@ This means that plugins that do binary code analysis (Orpheu for example) probab | mp_ammo_respawn_time | 20 | 0.0 | - | The respawn time for ammunition. | | mp_vote_flags | km | 0 | - | Vote systems enabled in server.
`0` voting disabled
`k` votekick enabled via `vote` command
`m` votemap enabled via `votemap` command | | mp_votemap_min_time | 180 | 0.0 | - | Minimum seconds that must elapse on map before `votemap` command can be used. | +| bot_excellent_morale | 0 | 0 | 1 | Bots always have great morale regardless of defeat or victory. |
diff --git a/dist/game.cfg b/dist/game.cfg index c5dad01c9..65ffb07ed 100644 --- a/dist/game.cfg +++ b/dist/game.cfg @@ -521,7 +521,7 @@ mp_give_c4_frags "3" // Default value: "1.0" mp_hostages_rescued_ratio "1.0" -// Legacy func_vehicle behavior when blocked by another entity. +// Legacy func_vehicle behavior when blocked by another entity. // New one is more useful for playing multiplayer. // // 0 - New behavior @@ -620,3 +620,10 @@ mp_vote_flags "km" // // Default value: "180" mp_votemap_min_time "180" + +// Bots always have great morale regardless of defeat or victory. +// 0 - disabled (default behaviour) +// 1 - enabled +// +// Default value: "0" +bot_excellent_morale "0" diff --git a/regamedll/dlls/bot/cs_bot.h b/regamedll/dlls/bot/cs_bot.h index ea22a18dc..8f63e1a68 100644 --- a/regamedll/dlls/bot/cs_bot.h +++ b/regamedll/dlls/bot/cs_bot.h @@ -1119,6 +1119,11 @@ inline bool CCSBot::IsAtBombsite() inline CCSBot::MoraleType CCSBot::GetMorale() const { +#ifdef REGAMEDLL_ADD + if (cv_bot_excellent_morale.value != 0.0f) + return EXCELLENT; +#endif + return m_morale; } diff --git a/regamedll/dlls/bot/cs_bot_init.cpp b/regamedll/dlls/bot/cs_bot_init.cpp index c7a19bb0b..3199cf91e 100644 --- a/regamedll/dlls/bot/cs_bot_init.cpp +++ b/regamedll/dlls/bot/cs_bot_init.cpp @@ -65,6 +65,7 @@ cvar_t cv_bot_join_delay = { "bot_join_delay", "0", FCVAR_SERVER, 0. cvar_t cv_bot_freeze = { "bot_freeze", "0", 0, 0.0f, nullptr }; cvar_t cv_bot_mimic = { "bot_mimic", "0", 0, 0.0f, nullptr }; cvar_t cv_bot_mimic_yaw_offset = { "bot_mimic_yaw_offset", "0", 0, 0.0f, nullptr }; +cvar_t cv_bot_excellent_morale = { "bot_excellent_morale", "0", 0, 0.0f, nullptr }; #else // Migrated to bot_quota_mode, use "match" cvar_t cv_bot_quota_match = { "bot_quota_match", "0", FCVAR_SERVER, 0.0f, nullptr }; @@ -136,6 +137,7 @@ void Bot_RegisterCVars() CVAR_REGISTER(&cv_bot_freeze); CVAR_REGISTER(&cv_bot_mimic); CVAR_REGISTER(&cv_bot_mimic_yaw_offset); + CVAR_REGISTER(&cv_bot_excellent_morale); #endif } diff --git a/regamedll/dlls/bot/cs_bot_init.h b/regamedll/dlls/bot/cs_bot_init.h index b50e020c3..691c518f2 100644 --- a/regamedll/dlls/bot/cs_bot_init.h +++ b/regamedll/dlls/bot/cs_bot_init.h @@ -65,6 +65,7 @@ extern cvar_t cv_bot_join_delay; extern cvar_t cv_bot_freeze; extern cvar_t cv_bot_mimic; extern cvar_t cv_bot_mimic_yaw_offset; +extern cvar_t cv_bot_excellent_morale; #else extern cvar_t cv_bot_quota_match; #endif From dbec1b589c0509942b13570df674efacf3b2dd7d Mon Sep 17 00:00:00 2001 From: Vaqtincha <51029683+Vaqtincha@users.noreply.github.com> Date: Fri, 28 Mar 2025 03:17:02 +0500 Subject: [PATCH 27/46] Randomspawn (#1013) add new cvar mp_randomspawn improved search for the best angle added mp_randomspawn 2 for debugging added info_spawn_point entity to .fgd --- README.md | 1 + dist/game.cfg | 9 + regamedll/dlls/bot/cs_bot_manager.cpp | 160 ++++++++++++++++++ regamedll/dlls/bot/cs_bot_manager.h | 3 + regamedll/dlls/client.cpp | 6 +- regamedll/dlls/game.cpp | 3 + regamedll/dlls/game.h | 1 + regamedll/dlls/player.cpp | 59 ++++++- regamedll/dlls/player.h | 2 +- .../GameDefinitionFile/regamedll-cs.fgd | 4 + regamedll/game_shared/bot/nav_area.h | 19 +++ 11 files changed, 256 insertions(+), 11 deletions(-) diff --git a/README.md b/README.md index 88c393b12..b3053cf9f 100644 --- a/README.md +++ b/README.md @@ -124,6 +124,7 @@ This means that plugins that do binary code analysis (Orpheu for example) probab | mp_vote_flags | km | 0 | - | Vote systems enabled in server.
`0` voting disabled
`k` votekick enabled via `vote` command
`m` votemap enabled via `votemap` command | | mp_votemap_min_time | 180 | 0.0 | - | Minimum seconds that must elapse on map before `votemap` command can be used. | | bot_excellent_morale | 0 | 0 | 1 | Bots always have great morale regardless of defeat or victory. | +| mp_randomspawn | 0 | 0 | 1 | Random player spawns
`0` disabled
`1` enabled
`NOTE`: Navigation `maps/.nav` file required | diff --git a/dist/game.cfg b/dist/game.cfg index 65ffb07ed..e25eaf20d 100644 --- a/dist/game.cfg +++ b/dist/game.cfg @@ -627,3 +627,12 @@ mp_votemap_min_time "180" // // Default value: "0" bot_excellent_morale "0" + +// Random player spawns +// 0 - disabled (default behaviour) +// 1 - enabled +// +// NOTE: Navigation "maps/.nav" file required +// +// Default value: "0" +mp_randomspawn "0" diff --git a/regamedll/dlls/bot/cs_bot_manager.cpp b/regamedll/dlls/bot/cs_bot_manager.cpp index a5be7342e..e68bea538 100644 --- a/regamedll/dlls/bot/cs_bot_manager.cpp +++ b/regamedll/dlls/bot/cs_bot_manager.cpp @@ -1144,6 +1144,166 @@ class CollectOverlappingAreas CCSBotManager::Zone *m_zone; }; +#ifdef REGAMEDLL_ADD +LINK_ENTITY_TO_CLASS(info_spawn_point, CPointEntity, CCSPointEntity) + +inline bool IsFreeSpace(Vector vecOrigin, int iHullNumber, edict_t *pSkipEnt = nullptr) +{ + if (UTIL_PointContents(vecOrigin) != CONTENTS_EMPTY) + return false; + + TraceResult trace; + UTIL_TraceHull(vecOrigin, vecOrigin, dont_ignore_monsters, iHullNumber, pSkipEnt, &trace); + + return (!trace.fStartSolid && !trace.fAllSolid && trace.fInOpen); +} + +inline bool pointInRadius(Vector vecOrigin, float radius) +{ + CBaseEntity *pEntity = nullptr; + while ((pEntity = UTIL_FindEntityInSphere(pEntity, vecOrigin, radius))) + { + if (FClassnameIs(pEntity->edict(), "info_spawn_point")) + return true; + } + + return false; +} + +// a simple algorithm that searches for the farthest point (so that the player does not look at the wall) +inline Vector GetBestAngle(const Vector &vecStart) +{ + const float ANGLE_STEP = 30.0f; + float bestAngle = 0.0f; + float bestDistance = 0.0f; + Vector vecBestAngle = Vector(0, -1, 0); + + for (float angleYaw = 0.0f; angleYaw <= 360.0f; angleYaw += ANGLE_STEP) + { + TraceResult tr; + UTIL_MakeVectors(Vector(0, angleYaw, 0)); + + Vector vecEnd(vecStart + gpGlobals->v_forward * 8192); + UTIL_TraceLine(vecStart, vecEnd, ignore_monsters, nullptr, &tr); + + float distance = (vecStart - tr.vecEndPos).Length(); + + if (distance > bestDistance) + { + bestDistance = distance; + vecBestAngle.y = angleYaw; + } + } + + return vecBestAngle; +} + +// this function from leaked csgo sources 2020y +inline bool IsValidArea(CNavArea *area) +{ + ShortestPathCost cost; + bool bNotOrphaned; + + // check that we can path from the nav area to a ct spawner to confirm it isn't orphaned. + CBaseEntity *CTSpawn = UTIL_FindEntityByClassname(nullptr, "info_player_start"); + + if (CTSpawn) + { + CNavArea *CTSpawnArea = TheNavAreaGrid.GetNearestNavArea(&CTSpawn->pev->origin); + bNotOrphaned = NavAreaBuildPath(area, CTSpawnArea, nullptr, cost); + + if (bNotOrphaned) + return true; + } + + // double check that we can path from the nav area to a t spawner to confirm it isn't orphaned. + CBaseEntity *TSpawn = UTIL_FindEntityByClassname(nullptr, "info_player_deathmatch"); + + if (TSpawn) + { + CNavArea *TSpawnArea = TheNavAreaGrid.GetNearestNavArea(&TSpawn->pev->origin); + bNotOrphaned = NavAreaBuildPath(area, TSpawnArea, nullptr, cost); + + if (bNotOrphaned) + return true; + } + + return false; +} + +void GetSpawnPositions() +{ + const float MIN_AREA_SIZE = 32.0f; + const int MAX_SPAWNS_POINTS = 128; + const float MAX_SLOPE = 0.85f; + + int totalSpawns = 0; + + for (NavAreaList::iterator iter = TheNavAreaList.begin(); iter != TheNavAreaList.end(); iter++) + { + if (totalSpawns >= MAX_SPAWNS_POINTS) + break; + + CNavArea *area = *iter; + + if (!area) + continue; + + // ignore small areas + if (area->GetSizeX() < MIN_AREA_SIZE || area->GetSizeY() < MIN_AREA_SIZE) + continue; + + // ignore areas jump, crouch etc + if (area->GetAttributes()) + continue; + + if (area->GetAreaSlope() < MAX_SLOPE) + { + //CONSOLE_ECHO("Skip area slope: %0.3f\n", area->GetAreaSlope()); + continue; + } + + Vector vecOrigin = *area->GetCenter() + Vector(0, 0, HalfHumanHeight + 5); + + if (!IsFreeSpace(vecOrigin, human_hull)) + { + //CONSOLE_ECHO("No free space!\n"); + continue; + } + + if (pointInRadius(vecOrigin, 128.0f)) + continue; + + if (!IsValidArea(area)) + continue; + + Vector bestAngle = GetBestAngle(vecOrigin); + + if (bestAngle.y != -1) + { + CBaseEntity* pPoint = CBaseEntity::Create("info_spawn_point", vecOrigin, bestAngle, nullptr); + + if (pPoint) + { + totalSpawns++; + //CONSOLE_ECHO("Add spawn at x:%f y:%f z:%f with angle %0.1f slope %0.3f \n", vecOrigin.x, vecOrigin.y, vecOrigin.z, bestAngle.y, area->GetAreaSlope()); + + // use only for debugging + if (randomspawn.value > 1.0f) + { + SET_MODEL(ENT(pPoint->pev), "models/player.mdl"); + pPoint->pev->sequence = ACT_IDLE; + pPoint->pev->rendermode = kRenderTransAdd; + pPoint->pev->renderamt = 150.0f; + } + } + } + } + + CONSOLE_ECHO("Total spawns points: %i\n", totalSpawns); +} +#endif + // Search the map entities to determine the game scenario and define important zones. void CCSBotManager::ValidateMapData() { diff --git a/regamedll/dlls/bot/cs_bot_manager.h b/regamedll/dlls/bot/cs_bot_manager.h index 9552c6978..0d5e6e37d 100644 --- a/regamedll/dlls/bot/cs_bot_manager.h +++ b/regamedll/dlls/bot/cs_bot_manager.h @@ -269,3 +269,6 @@ inline bool AreBotsAllowed() } void PrintAllEntities(); +#ifdef REGAMEDLL_ADD +void GetSpawnPositions(); +#endif \ No newline at end of file diff --git a/regamedll/dlls/client.cpp b/regamedll/dlls/client.cpp index 63560fad6..971a41cf6 100644 --- a/regamedll/dlls/client.cpp +++ b/regamedll/dlls/client.cpp @@ -3834,8 +3834,10 @@ void EXT_FUNC ServerActivate(edict_t *pEdictList, int edictCount, int clientMax) #ifdef REGAMEDLL_ADD CSGameRules()->ServerActivate(); - if (location_area_info.value) - LoadNavigationMap(); + if (LoadNavigationMap() == NAV_OK) + { + GetSpawnPositions(); + } #endif } diff --git a/regamedll/dlls/game.cpp b/regamedll/dlls/game.cpp index 5680db82a..daaf6e73e 100644 --- a/regamedll/dlls/game.cpp +++ b/regamedll/dlls/game.cpp @@ -188,6 +188,8 @@ cvar_t ammo_respawn_time = { "mp_ammo_respawn_time", "20", FCVAR_SERVER, 2 cvar_t vote_flags = { "mp_vote_flags", "km", 0, 0.0f, nullptr }; cvar_t votemap_min_time = { "mp_votemap_min_time", "180", 0, 180.0f, nullptr }; +cvar_t randomspawn = { "mp_randomspawn", "0", FCVAR_SERVER, 0.0f, nullptr }; + void GameDLL_Version_f() { if (Q_stricmp(CMD_ARGV(1), "version") != 0) @@ -459,6 +461,7 @@ void EXT_FUNC GameDLLInit() CVAR_REGISTER(&vote_flags); CVAR_REGISTER(&votemap_min_time); + CVAR_REGISTER(&randomspawn); CVAR_REGISTER(&cv_bot_enable); CVAR_REGISTER(&cv_hostage_ai_enable); diff --git a/regamedll/dlls/game.h b/regamedll/dlls/game.h index 09da5305a..48cec02af 100644 --- a/regamedll/dlls/game.h +++ b/regamedll/dlls/game.h @@ -208,6 +208,7 @@ extern cvar_t weapon_respawn_time; extern cvar_t ammo_respawn_time; extern cvar_t vote_flags; extern cvar_t votemap_min_time; +extern cvar_t randomspawn; #endif diff --git a/regamedll/dlls/player.cpp b/regamedll/dlls/player.cpp index ceaa9dbed..5453b522a 100644 --- a/regamedll/dlls/player.cpp +++ b/regamedll/dlls/player.cpp @@ -5338,17 +5338,24 @@ void EXT_FUNC CBasePlayer::__API_HOOK(PostThink)() } // checks if the spot is clear of players -BOOL IsSpawnPointValid(CBaseEntity *pPlayer, CBaseEntity *pSpot) +BOOL IsSpawnPointValid(CBaseEntity *pPlayer, CBaseEntity *pSpot, float fRadius) { if (!pSpot->IsTriggered(pPlayer)) return FALSE; CBaseEntity *pEntity = nullptr; - while ((pEntity = UTIL_FindEntityInSphere(pEntity, pSpot->pev->origin, MAX_PLAYER_USE_RADIUS))) + + while ((pEntity = UTIL_FindEntityInSphere(pEntity, pSpot->pev->origin, fRadius))) { // if ent is a client, don't spawn on 'em - if (pEntity->IsPlayer() && pEntity != pPlayer) + if (pEntity->IsPlayer() && pEntity != pPlayer +#ifdef REGAMEDLL_FIXES + && pEntity->IsAlive() +#endif + ) + { return FALSE; + } } return TRUE; @@ -5373,17 +5380,34 @@ bool CBasePlayer::SelectSpawnSpot(const char *pEntClassName, CBaseEntity *&pSpot { if (pSpot) { - // check if pSpot is valid - if (IsSpawnPointValid(this, pSpot)) +#ifdef REGAMEDLL_ADD + if (FClassnameIs(pSpot->edict(), "info_spawn_point")) { - if (pSpot->pev->origin == Vector(0, 0, 0)) + if (!IsSpawnPointValid(this, pSpot, 512.0f) || pSpot->pev->origin == Vector(0, 0, 0)) { pSpot = UTIL_FindEntityByClassname(pSpot, pEntClassName); continue; } + else + { + return true; + } + } + else +#endif + { + // check if pSpot is valid + if (IsSpawnPointValid(this, pSpot, MAX_PLAYER_USE_RADIUS)) + { + if (pSpot->pev->origin == Vector(0, 0, 0)) + { + pSpot = UTIL_FindEntityByClassname(pSpot, pEntClassName); + continue; + } - // if so, go to pSpot - return true; + // if so, go to pSpot + return true; + } } } @@ -5441,6 +5465,24 @@ edict_t *EXT_FUNC CBasePlayer::__API_HOOK(EntSelectSpawnPoint)() if (!FNullEnt(pSpot)) goto ReturnSpot; } +#ifdef REGAMEDLL_ADD + else if (randomspawn.value > 0) + { + pSpot = g_pLastSpawn; + + if (SelectSpawnSpot("info_spawn_point", pSpot)) + { + g_pLastSpawn = pSpot; + + return pSpot->edict(); + } + + if (m_iTeam == CT) + goto CTSpawn; + else if (m_iTeam == TERRORIST) + goto TSpawn; + } +#endif // VIP spawn point else if (g_pGameRules->IsDeathmatch() && m_bIsVIP) { @@ -5468,6 +5510,7 @@ edict_t *EXT_FUNC CBasePlayer::__API_HOOK(EntSelectSpawnPoint)() // The terrorist spawn points else if (g_pGameRules->IsDeathmatch() && m_iTeam == TERRORIST) { +TSpawn: pSpot = g_pLastTerroristSpawn; if (SelectSpawnSpot("info_player_deathmatch", pSpot)) diff --git a/regamedll/dlls/player.h b/regamedll/dlls/player.h index b13c2c820..6890d30b8 100644 --- a/regamedll/dlls/player.h +++ b/regamedll/dlls/player.h @@ -1044,7 +1044,7 @@ int TrainSpeed(int iSpeed, int iMax); void LogAttack(CBasePlayer *pAttacker, CBasePlayer *pVictim, int teamAttack, int healthHit, int armorHit, int newHealth, int newArmor, const char *killer_weapon_name); bool CanSeeUseable(CBasePlayer *me, CBaseEntity *pEntity); void FixPlayerCrouchStuck(edict_t *pPlayer); -BOOL IsSpawnPointValid(CBaseEntity *pPlayer, CBaseEntity *pSpot); +BOOL IsSpawnPointValid(CBaseEntity *pPlayer, CBaseEntity *pSpot, float fRadius); CBaseEntity *FindEntityForward(CBaseEntity *pMe); real_t GetPlayerPitch(const edict_t *pEdict); real_t GetPlayerYaw(const edict_t *pEdict); diff --git a/regamedll/extra/Toolkit/GameDefinitionFile/regamedll-cs.fgd b/regamedll/extra/Toolkit/GameDefinitionFile/regamedll-cs.fgd index 3d56907ea..cab21059a 100644 --- a/regamedll/extra/Toolkit/GameDefinitionFile/regamedll-cs.fgd +++ b/regamedll/extra/Toolkit/GameDefinitionFile/regamedll-cs.fgd @@ -3143,3 +3143,7 @@ @PointClass base(BaseCommand) size(-8 -8 -8, 8 8 8) = point_clientcommand : "It issues commands to the client console" [ ] + +@PointClass iconsprite("sprites/CS/info_player_start.spr") base(PlayerClass) = info_spawn_point : "Random spawn start" +[ +] \ No newline at end of file diff --git a/regamedll/game_shared/bot/nav_area.h b/regamedll/game_shared/bot/nav_area.h index c4cf8a1ff..10eca2f85 100644 --- a/regamedll/game_shared/bot/nav_area.h +++ b/regamedll/game_shared/bot/nav_area.h @@ -345,6 +345,25 @@ class CNavArea void AddLadderUp(CNavLadder *ladder) { m_ladder[LADDER_UP].push_back(ladder); } void AddLadderDown(CNavLadder *ladder) { m_ladder[LADDER_DOWN].push_back(ladder); } + inline float GetAreaSlope() + { + Vector u, v; + + // compute our unit surface normal + u.x = m_extent.hi.x - m_extent.lo.x; + u.y = 0.0f; + u.z = m_neZ - m_extent.lo.z; + + v.x = 0.0f; + v.y = m_extent.hi.y - m_extent.lo.y; + v.z = m_swZ - m_extent.lo.z; + + Vector normal = CrossProduct(u, v); + normal.NormalizeInPlace(); + + return normal.z; + } + private: friend void ConnectGeneratedAreas(); friend void MergeGeneratedAreas(); From 518f142635a2825cb6b132776019a96cfe2e7127 Mon Sep 17 00:00:00 2001 From: Vaqtincha <51029683+Vaqtincha@users.noreply.github.com> Date: Fri, 28 Mar 2025 03:20:28 +0500 Subject: [PATCH 28/46] Add new CVar mp_default_weapons_random (#1015) --- README.md | 1 + dist/game.cfg | 7 +++++++ regamedll/dlls/game.cpp | 2 ++ regamedll/dlls/game.h | 1 + regamedll/dlls/player.cpp | 37 +++++++++++++++++++++++++++++++++++-- 5 files changed, 46 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index b3053cf9f..639b335f1 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,7 @@ This means that plugins that do binary code analysis (Orpheu for example) probab | mp_ct_give_player_knife | 1 | 0 | 1 | Whether Counter-Terrorist player spawn with knife. | | mp_ct_default_weapons_primary | "" | "" | - | The default primary (rifle) weapon that the CTs will spawn with. | | mp_ct_default_weapons_secondary | "usp" | "" | - | The default secondary (pistol) weapon that the CTs will spawn with. | +| mp_default_weapons_random | 0 | 0 | 1 | Randomize default weapons (if there are multiple).
`0` disabled
`1` enabled | | mp_give_player_c4 | 1 | 0 | 1 | Whether this map should spawn a C4 bomb for a player or not.
`0` disabled
`1` enabled | | mp_weapons_allow_map_placed | 1 | 0 | 1 | When set, map weapons (located on the floor by map) will be shown.
`0` hide all map weapons.
`1` enabled
`NOTE`: Effect will work after round restart. | | mp_free_armor | 0 | 0 | 2 | Give free armor on player spawn.
`0` disabled
`1` Give Kevlar
`2` Give Kevlar + Helmet | diff --git a/dist/game.cfg b/dist/game.cfg index e25eaf20d..c84fde867 100644 --- a/dist/game.cfg +++ b/dist/game.cfg @@ -466,6 +466,13 @@ mp_ct_default_weapons_primary "" // Default value: "usp" mp_ct_default_weapons_secondary "usp" +// Randomize default weapons (if there are multiple) +// 0 - disabled (default behaviour) +// 1 - enabled +// +// Default value: "0" +mp_default_weapons_random "0" + // Give the player free armor on player spawn // 0 - No armor (default behavior) // 1 - Give Kevlar diff --git a/regamedll/dlls/game.cpp b/regamedll/dlls/game.cpp index daaf6e73e..baaed3699 100644 --- a/regamedll/dlls/game.cpp +++ b/regamedll/dlls/game.cpp @@ -160,6 +160,7 @@ cvar_t t_default_grenades = { "mp_t_default_grenades", "", 0, 0.0 cvar_t t_give_player_knife = { "mp_t_give_player_knife", "1", 0, 1.0f, nullptr }; cvar_t t_default_weapons_secondary = { "mp_t_default_weapons_secondary", "glock18", 0, 0.0f, nullptr }; cvar_t t_default_weapons_primary = { "mp_t_default_weapons_primary", "", 0, 0.0f, nullptr }; +cvar_t default_weapons_random = { "mp_default_weapons_random", "", 0, 0.0f, nullptr }; cvar_t free_armor = { "mp_free_armor", "0", 0, 0.0f, nullptr }; cvar_t teamflash = { "mp_team_flash", "1", 0, 1.0f, nullptr }; cvar_t allchat = { "sv_allchat", "0", 0, 0.0f, nullptr }; @@ -433,6 +434,7 @@ void EXT_FUNC GameDLLInit() CVAR_REGISTER(&t_give_player_knife); CVAR_REGISTER(&t_default_weapons_secondary); CVAR_REGISTER(&t_default_weapons_primary); + CVAR_REGISTER(&default_weapons_random); CVAR_REGISTER(&free_armor); CVAR_REGISTER(&teamflash); CVAR_REGISTER(&allchat); diff --git a/regamedll/dlls/game.h b/regamedll/dlls/game.h index 48cec02af..e7dba1f24 100644 --- a/regamedll/dlls/game.h +++ b/regamedll/dlls/game.h @@ -186,6 +186,7 @@ extern cvar_t t_default_grenades; extern cvar_t t_give_player_knife; extern cvar_t t_default_weapons_secondary; extern cvar_t t_default_weapons_primary; +extern cvar_t default_weapons_random; extern cvar_t free_armor; extern cvar_t teamflash; extern cvar_t allchat; diff --git a/regamedll/dlls/player.cpp b/regamedll/dlls/player.cpp index 5453b522a..b32928c3e 100644 --- a/regamedll/dlls/player.cpp +++ b/regamedll/dlls/player.cpp @@ -1644,6 +1644,10 @@ void EXT_FUNC CBasePlayer::__API_HOOK(GiveDefaultItems)() // Give default secondary equipment { char *secondaryString = NULL; + int secondaryCount = 0; + const int MAX_SECONDARY = 13; // x2 + 1 + WeaponInfoStruct *secondaryWeaponInfoArray[MAX_SECONDARY]; + if (m_iTeam == CT) secondaryString = ct_default_weapons_secondary.string; else if (m_iTeam == TERRORIST) @@ -1665,18 +1669,34 @@ void EXT_FUNC CBasePlayer::__API_HOOK(GiveDefaultItems)() if (weaponInfo) { const auto iItemID = GetItemIdByWeaponId(weaponInfo->id); if (iItemID != ITEM_NONE && !HasRestrictItem(iItemID, ITEM_TYPE_EQUIPPED) && IsSecondaryWeapon(iItemID)) { - GiveWeapon(weaponInfo->gunClipSize * iAmountOfBPAmmo, weaponInfo->entityName); + if (default_weapons_random.value != 0.0f) { + if (secondaryCount < MAX_SECONDARY) { + secondaryWeaponInfoArray[secondaryCount++] = weaponInfo; + } + } + else { + GiveWeapon(weaponInfo->gunClipSize * iAmountOfBPAmmo, weaponInfo->entityName); + } } } secondaryString = SharedParse(secondaryString); } + + if (default_weapons_random.value != 0.0f) { + WeaponInfoStruct *weaponInfo = secondaryWeaponInfoArray[RANDOM_LONG(0, secondaryCount - 1)]; + if (weaponInfo) + GiveWeapon(weaponInfo->gunClipSize * iAmountOfBPAmmo, weaponInfo->entityName); + } } } // Give default primary equipment { char *primaryString = NULL; + int primaryCount = 0; + const int MAX_PRIMARY = 39; // x2 + 1 + WeaponInfoStruct *primaryWeaponInfoArray[MAX_PRIMARY]; if (m_iTeam == CT) primaryString = ct_default_weapons_primary.string; @@ -1699,12 +1719,25 @@ void EXT_FUNC CBasePlayer::__API_HOOK(GiveDefaultItems)() if (weaponInfo) { const auto iItemID = GetItemIdByWeaponId(weaponInfo->id); if (iItemID != ITEM_NONE && !HasRestrictItem(iItemID, ITEM_TYPE_EQUIPPED) && IsPrimaryWeapon(iItemID)) { - GiveWeapon(weaponInfo->gunClipSize * iAmountOfBPAmmo, weaponInfo->entityName); + if (default_weapons_random.value != 0.0f) { + if (primaryCount < MAX_PRIMARY) { + primaryWeaponInfoArray[primaryCount++] = weaponInfo; + } + } + else { + GiveWeapon(weaponInfo->gunClipSize * iAmountOfBPAmmo, weaponInfo->entityName); + } } } primaryString = SharedParse(primaryString); } + + if (default_weapons_random.value != 0.0f) { + WeaponInfoStruct *weaponInfo = primaryWeaponInfoArray[RANDOM_LONG(0, primaryCount - 1)]; + if (weaponInfo) + GiveWeapon(weaponInfo->gunClipSize * iAmountOfBPAmmo, weaponInfo->entityName); + } } } From 94a7eb4cbb2ae163d7d07af2ee9814e2fa6a3d6f Mon Sep 17 00:00:00 2001 From: Vaqtincha <51029683+Vaqtincha@users.noreply.github.com> Date: Fri, 28 Mar 2025 03:21:24 +0500 Subject: [PATCH 29/46] added forgot pistols fiveseven and dualelite touching for vip (#1045) --- regamedll/dlls/weapons.cpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/regamedll/dlls/weapons.cpp b/regamedll/dlls/weapons.cpp index 47a77c6fc..b98749cb6 100644 --- a/regamedll/dlls/weapons.cpp +++ b/regamedll/dlls/weapons.cpp @@ -618,11 +618,17 @@ void CBasePlayerItem::DefaultTouch(CBaseEntity *pOther) CBasePlayer *pPlayer = static_cast(pOther); if (pPlayer->m_bIsVIP - && m_iId != WEAPON_USP + && +#ifndef REGAMEDLL_FIXES + m_iId != WEAPON_USP && m_iId != WEAPON_GLOCK18 && m_iId != WEAPON_P228 && m_iId != WEAPON_DEAGLE - && m_iId != WEAPON_KNIFE) + && m_iId != WEAPON_KNIFE +#else + !IsSecondaryWeapon(m_iId) +#endif + ) { return; } From d8faea0966e80450814de7a10d63b55cd2e87416 Mon Sep 17 00:00:00 2001 From: Vaqtincha <51029683+Vaqtincha@users.noreply.github.com> Date: Fri, 28 Mar 2025 03:28:15 +0500 Subject: [PATCH 30/46] Add new CVar mp_jump_height (#1022) --- README.md | 1 + dist/game.cfg | 5 +++++ regamedll/dlls/game.cpp | 2 ++ regamedll/dlls/game.h | 1 + regamedll/dlls/player.cpp | 4 ++-- regamedll/pm_shared/pm_shared.cpp | 7 ++++++- 6 files changed, 17 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 639b335f1..7611beb14 100644 --- a/README.md +++ b/README.md @@ -124,6 +124,7 @@ This means that plugins that do binary code analysis (Orpheu for example) probab | mp_ammo_respawn_time | 20 | 0.0 | - | The respawn time for ammunition. | | mp_vote_flags | km | 0 | - | Vote systems enabled in server.
`0` voting disabled
`k` votekick enabled via `vote` command
`m` votemap enabled via `votemap` command | | mp_votemap_min_time | 180 | 0.0 | - | Minimum seconds that must elapse on map before `votemap` command can be used. | +| mp_jump_height | 45 | 0.0 | - | Player jump height. | | bot_excellent_morale | 0 | 0 | 1 | Bots always have great morale regardless of defeat or victory. | | mp_randomspawn | 0 | 0 | 1 | Random player spawns
`0` disabled
`1` enabled
`NOTE`: Navigation `maps/.nav` file required | diff --git a/dist/game.cfg b/dist/game.cfg index c84fde867..95c7b32a4 100644 --- a/dist/game.cfg +++ b/dist/game.cfg @@ -628,6 +628,11 @@ mp_vote_flags "km" // Default value: "180" mp_votemap_min_time "180" +// Player jump height +// +// Default value: "45" +mp_jump_height "45" + // Bots always have great morale regardless of defeat or victory. // 0 - disabled (default behaviour) // 1 - enabled diff --git a/regamedll/dlls/game.cpp b/regamedll/dlls/game.cpp index baaed3699..37b264fba 100644 --- a/regamedll/dlls/game.cpp +++ b/regamedll/dlls/game.cpp @@ -172,6 +172,7 @@ cvar_t deathmsg_flags = { "mp_deathmsg_flags", "abc", 0, 0.0f cvar_t assist_damage_threshold = { "mp_assist_damage_threshold", "40", 0, 40.0f, nullptr }; cvar_t freezetime_duck = { "mp_freezetime_duck", "1", 0, 1.0f, nullptr }; cvar_t freezetime_jump = { "mp_freezetime_jump", "1", 0, 1.0f, nullptr }; +cvar_t jump_height = { "mp_jump_height", "45", FCVAR_SERVER, 45.0f, nullptr }; cvar_t hostages_rescued_ratio = { "mp_hostages_rescued_ratio", "1.0", 0, 1.0f, nullptr }; @@ -453,6 +454,7 @@ void EXT_FUNC GameDLLInit() CVAR_REGISTER(&freezetime_duck); CVAR_REGISTER(&freezetime_jump); + CVAR_REGISTER(&jump_height); CVAR_REGISTER(&defuser_allocation); CVAR_REGISTER(&location_area_info); CVAR_REGISTER(&chat_loc_fallback); diff --git a/regamedll/dlls/game.h b/regamedll/dlls/game.h index e7dba1f24..f016c0f35 100644 --- a/regamedll/dlls/game.h +++ b/regamedll/dlls/game.h @@ -201,6 +201,7 @@ extern cvar_t deathmsg_flags; extern cvar_t assist_damage_threshold; extern cvar_t freezetime_duck; extern cvar_t freezetime_jump; +extern cvar_t jump_height; extern cvar_t defuser_allocation; extern cvar_t location_area_info; extern cvar_t chat_loc_fallback; diff --git a/regamedll/dlls/player.cpp b/regamedll/dlls/player.cpp index b32928c3e..d510b6ce9 100644 --- a/regamedll/dlls/player.cpp +++ b/regamedll/dlls/player.cpp @@ -1487,7 +1487,7 @@ void CBasePlayer::PackDeadPlayerItems() { DropShield(); #ifdef REGAMEDLL_ADD - if(iPackGun != GR_PLR_DROP_GUN_ALL) + if (iPackGun != GR_PLR_DROP_GUN_ALL) #endif { bSkipPrimSec = true; @@ -2219,7 +2219,7 @@ void EXT_FUNC CBasePlayer::__API_HOOK(Killed)(entvars_t *pevAttacker, int iGib) { CBasePlayer *pAttacker = CBasePlayer::Instance(pevAttacker); - if(pAttacker /*safety*/ && !pAttacker->IsBot() && pAttacker->m_iTeam != m_iTeam) + if (pAttacker /*safety*/ && !pAttacker->IsBot() && pAttacker->m_iTeam != m_iTeam) { if (pAttacker->HasShield()) killerHasShield = true; diff --git a/regamedll/pm_shared/pm_shared.cpp b/regamedll/pm_shared/pm_shared.cpp index e9efb3763..2de5f5fdf 100644 --- a/regamedll/pm_shared/pm_shared.cpp +++ b/regamedll/pm_shared/pm_shared.cpp @@ -2429,13 +2429,18 @@ inline real_t PM_JumpHeight(bool longjump) #ifdef REGAMEDLL_API if (longjump) { - if(pmoveplayer->m_flLongJumpHeight > 0.0) + if (pmoveplayer->m_flLongJumpHeight > 0.0) return pmoveplayer->m_flLongJumpHeight; } else if (pmoveplayer->m_flJumpHeight > 0.0) return pmoveplayer->m_flJumpHeight; #endif + +#ifdef REGAMEDLL_ADD + return Q_sqrt(2.0 * 800.0f * (longjump ? 56.0f : Q_max(jump_height.value, 0.0f))); +#else return Q_sqrt(2.0 * 800.0f * (longjump ? 56.0f : 45.0f)); +#endif } LINK_HOOK_VOID_CHAIN2(PM_Jump) From b44b09d07be0dd0c8f9df9bf3c243f332c4f190c Mon Sep 17 00:00:00 2001 From: golukon <119600102+golukon@users.noreply.github.com> Date: Fri, 28 Mar 2025 01:30:32 +0300 Subject: [PATCH 31/46] feat: add new cvar "mp_logkills" (#1039) --- README.md | 1 + regamedll/dlls/game.cpp | 2 ++ regamedll/dlls/game.h | 1 + regamedll/dlls/multiplay_gamerules.cpp | 46 ++++++++++++++------------ 4 files changed, 29 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 7611beb14..e9a42cfc6 100644 --- a/README.md +++ b/README.md @@ -124,6 +124,7 @@ This means that plugins that do binary code analysis (Orpheu for example) probab | mp_ammo_respawn_time | 20 | 0.0 | - | The respawn time for ammunition. | | mp_vote_flags | km | 0 | - | Vote systems enabled in server.
`0` voting disabled
`k` votekick enabled via `vote` command
`m` votemap enabled via `votemap` command | | mp_votemap_min_time | 180 | 0.0 | - | Minimum seconds that must elapse on map before `votemap` command can be used. | +| mp_logkills | 1 | 0 | 1 | Log kills.
`0` disabled
`1` enabled | | mp_jump_height | 45 | 0.0 | - | Player jump height. | | bot_excellent_morale | 0 | 0 | 1 | Bots always have great morale regardless of defeat or victory. | | mp_randomspawn | 0 | 0 | 1 | Random player spawns
`0` disabled
`1` enabled
`NOTE`: Navigation `maps/.nav` file required | diff --git a/regamedll/dlls/game.cpp b/regamedll/dlls/game.cpp index 37b264fba..a6e15b263 100644 --- a/regamedll/dlls/game.cpp +++ b/regamedll/dlls/game.cpp @@ -190,6 +190,7 @@ cvar_t ammo_respawn_time = { "mp_ammo_respawn_time", "20", FCVAR_SERVER, 2 cvar_t vote_flags = { "mp_vote_flags", "km", 0, 0.0f, nullptr }; cvar_t votemap_min_time = { "mp_votemap_min_time", "180", 0, 180.0f, nullptr }; +cvar_t logkills = { "mp_logkills", "1", FCVAR_SERVER, 0.0f, nullptr }; cvar_t randomspawn = { "mp_randomspawn", "0", FCVAR_SERVER, 0.0f, nullptr }; void GameDLL_Version_f() @@ -469,6 +470,7 @@ void EXT_FUNC GameDLLInit() CVAR_REGISTER(&cv_bot_enable); CVAR_REGISTER(&cv_hostage_ai_enable); + CVAR_REGISTER(&logkills); // print version CONSOLE_ECHO("ReGameDLL version: " APP_VERSION "\n"); diff --git a/regamedll/dlls/game.h b/regamedll/dlls/game.h index f016c0f35..bf5130d2e 100644 --- a/regamedll/dlls/game.h +++ b/regamedll/dlls/game.h @@ -210,6 +210,7 @@ extern cvar_t weapon_respawn_time; extern cvar_t ammo_respawn_time; extern cvar_t vote_flags; extern cvar_t votemap_min_time; +extern cvar_t logkills; extern cvar_t randomspawn; #endif diff --git a/regamedll/dlls/multiplay_gamerules.cpp b/regamedll/dlls/multiplay_gamerules.cpp index 7a84afd46..1ba7122be 100644 --- a/regamedll/dlls/multiplay_gamerules.cpp +++ b/regamedll/dlls/multiplay_gamerules.cpp @@ -4160,29 +4160,33 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(DeathNotice)(CBasePlayer *pVictim, pVictim->CSPlayer()->m_iNumKilledByUnanswered[iPlayerIndexKiller - 1]++; } } - - // Did he kill himself? - if (pVictim->pev == pevKiller) - { - // killed self - char *team = GetTeam(pVictim->m_iTeam); - UTIL_LogPrintf("\"%s<%i><%s><%s>\" committed suicide with \"%s\"\n", STRING(pVictim->pev->netname), GETPLAYERUSERID(pVictim->edict()), - GETPLAYERAUTHID(pVictim->edict()), team, killer_weapon_name); - } - else if (pevKiller->flags & FL_CLIENT) +#ifdef REGAMEDLL_ADD + if (static_cast(logkills.value)) +#endif { - const char *VictimTeam = GetTeam(pVictim->m_iTeam); - const char *KillerTeam = (pKiller && pKiller->IsPlayer()) ? GetTeam(pKiller->m_iTeam) : ""; + // Did he kill himself? + if (pVictim->pev == pevKiller) + { + // killed self + char *team = GetTeam(pVictim->m_iTeam); + UTIL_LogPrintf("\"%s<%i><%s><%s>\" committed suicide with \"%s\"\n", STRING(pVictim->pev->netname), GETPLAYERUSERID(pVictim->edict()), + GETPLAYERAUTHID(pVictim->edict()), team, killer_weapon_name); + } + else if (pevKiller->flags & FL_CLIENT) + { + const char *VictimTeam = GetTeam(pVictim->m_iTeam); + const char *KillerTeam = (pKiller && pKiller->IsPlayer()) ? GetTeam(pKiller->m_iTeam) : ""; - UTIL_LogPrintf("\"%s<%i><%s><%s>\" killed \"%s<%i><%s><%s>\" with \"%s\"\n", STRING(pevKiller->netname), GETPLAYERUSERID(ENT(pevKiller)), GETPLAYERAUTHID(ENT(pevKiller)), - KillerTeam, STRING(pVictim->pev->netname), GETPLAYERUSERID(pVictim->edict()), GETPLAYERAUTHID(pVictim->edict()), VictimTeam, killer_weapon_name); - } - else - { - // killed by the world - char *team = GetTeam(pVictim->m_iTeam); - UTIL_LogPrintf("\"%s<%i><%s><%s>\" committed suicide with \"%s\" (world)\n", STRING(pVictim->pev->netname), GETPLAYERUSERID(pVictim->edict()), - GETPLAYERAUTHID(pVictim->edict()), team, killer_weapon_name); + UTIL_LogPrintf("\"%s<%i><%s><%s>\" killed \"%s<%i><%s><%s>\" with \"%s\"\n", STRING(pevKiller->netname), GETPLAYERUSERID(ENT(pevKiller)), GETPLAYERAUTHID(ENT(pevKiller)), + KillerTeam, STRING(pVictim->pev->netname), GETPLAYERUSERID(pVictim->edict()), GETPLAYERAUTHID(pVictim->edict()), VictimTeam, killer_weapon_name); + } + else + { + // killed by the world + char *team = GetTeam(pVictim->m_iTeam); + UTIL_LogPrintf("\"%s<%i><%s><%s>\" committed suicide with \"%s\" (world)\n", STRING(pVictim->pev->netname), GETPLAYERUSERID(pVictim->edict()), + GETPLAYERAUTHID(pVictim->edict()), team, killer_weapon_name); + } } // TODO: It is called in CBasePlayer::Killed too, most likely, From b10f23e1e9b4f7c30ebe08db291fb0ca0e8adb22 Mon Sep 17 00:00:00 2001 From: Vaqtincha <51029683+Vaqtincha@users.noreply.github.com> Date: Fri, 28 Mar 2025 03:59:34 +0500 Subject: [PATCH 32/46] Add new CVars mp_playerid_showhealth & mp_playerid_field (#1046) * Add new CVars playerid_showhealth & mp_playerid_field --- README.md | 2 ++ dist/game.cfg | 19 +++++++++++ regamedll/dlls/game.cpp | 6 ++++ regamedll/dlls/game.h | 2 ++ regamedll/dlls/player.cpp | 71 +++++++++++++++++++++++++++++++++++++-- 5 files changed, 98 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e9a42cfc6..e515ac068 100644 --- a/README.md +++ b/README.md @@ -128,6 +128,8 @@ This means that plugins that do binary code analysis (Orpheu for example) probab | mp_jump_height | 45 | 0.0 | - | Player jump height. | | bot_excellent_morale | 0 | 0 | 1 | Bots always have great morale regardless of defeat or victory. | | mp_randomspawn | 0 | 0 | 1 | Random player spawns
`0` disabled
`1` enabled
`NOTE`: Navigation `maps/.nav` file required | +| mp_playerid_showhealth | 1 | 0 | 2 | Player ID display mode.
`0` don't show health
`1` show health for teammates only (default CS behaviour)
`2` show health for all players | +| mp_playerid_field | 3 | 0 | 3 | Player ID field display mode.
`0` don't show additional information
`1` show team name
`2` show health percentage
`3` show both team name and health percentage | diff --git a/dist/game.cfg b/dist/game.cfg index 95c7b32a4..3b77122f5 100644 --- a/dist/game.cfg +++ b/dist/game.cfg @@ -648,3 +648,22 @@ bot_excellent_morale "0" // // Default value: "0" mp_randomspawn "0" + +// Player ID display mode +// +// 0 - don't show health (default behaviour) +// 1 - show health for teammates only (default CS behaviour) +// 2 - show health for all players +// +// Default value: "1" +mp_playerid_showhealth "1" + +// Player ID field display mode +// +// 0 - don't show additional information +// 1 - show team name +// 2 - show health percentage +// 3 - show both team name and health percentage +// +// Default value: "3" +mp_playerid_field "3" diff --git a/regamedll/dlls/game.cpp b/regamedll/dlls/game.cpp index a6e15b263..6aaefbb7d 100644 --- a/regamedll/dlls/game.cpp +++ b/regamedll/dlls/game.cpp @@ -193,6 +193,9 @@ cvar_t votemap_min_time = { "mp_votemap_min_time", "180", 0, 180.0f, null cvar_t logkills = { "mp_logkills", "1", FCVAR_SERVER, 0.0f, nullptr }; cvar_t randomspawn = { "mp_randomspawn", "0", FCVAR_SERVER, 0.0f, nullptr }; +cvar_t playerid_showhealth = { "mp_playerid_showhealth", "1", 0, 1.0f, nullptr }; +cvar_t playerid_field = { "mp_playerid_field", "3", 0, 3.0f, nullptr }; + void GameDLL_Version_f() { if (Q_stricmp(CMD_ARGV(1), "version") != 0) @@ -472,6 +475,9 @@ void EXT_FUNC GameDLLInit() CVAR_REGISTER(&cv_hostage_ai_enable); CVAR_REGISTER(&logkills); + CVAR_REGISTER(&playerid_showhealth); + CVAR_REGISTER(&playerid_field); + // print version CONSOLE_ECHO("ReGameDLL version: " APP_VERSION "\n"); diff --git a/regamedll/dlls/game.h b/regamedll/dlls/game.h index bf5130d2e..b3198ac40 100644 --- a/regamedll/dlls/game.h +++ b/regamedll/dlls/game.h @@ -212,6 +212,8 @@ extern cvar_t vote_flags; extern cvar_t votemap_min_time; extern cvar_t logkills; extern cvar_t randomspawn; +extern cvar_t playerid_showhealth; +extern cvar_t playerid_field; #endif diff --git a/regamedll/dlls/player.cpp b/regamedll/dlls/player.cpp index d510b6ce9..81548d346 100644 --- a/regamedll/dlls/player.cpp +++ b/regamedll/dlls/player.cpp @@ -115,6 +115,57 @@ void CBasePlayer::SendItemStatus() MESSAGE_END(); } +#ifdef REGAMEDLL_ADD + +enum PlayerIdShowHealth +{ + PLAYERID_HIDE = 0, // Don't show health + PLAYERID_TEAMMATES = 1, // Show health for teammates only (default CS) + PLAYERID_ALL = 2 // Show health for all players +}; + +enum PlayerIdField +{ + PLAYERID_FIELD_NONE = 0, // No extra info + PLAYERID_FIELD_TEAM = 1, // Show team name + PLAYERID_FIELD_HEALTH = 2, // Show health percentage + PLAYERID_FIELD_BOTH = 3 // Show both team name and health +}; + +inline const char *GetPlayerIdString(bool sameTeam) +{ + int showHealth = static_cast(playerid_showhealth.value); + int fieldType = static_cast(playerid_field.value); + + // Don't show health + if (showHealth == PLAYERID_HIDE) + { + return (fieldType == PLAYERID_FIELD_NONE) ? "1 %p2" : "1 %c1: %p2"; + } + + // Health only for teammates + if (showHealth == PLAYERID_TEAMMATES && !sameTeam) + { + switch (fieldType) + { + case PLAYERID_FIELD_TEAM: return "1 %c1: %p2"; + case PLAYERID_FIELD_HEALTH: return "1 %p2"; + case PLAYERID_FIELD_BOTH: return "1 %c1: %p2"; + default: return "1 %p2"; + } + } + + // Show health to everyone + switch (fieldType) + { + case PLAYERID_FIELD_TEAM: return "1 %c1: %p2\n2 : %i3%%"; + case PLAYERID_FIELD_HEALTH: return "1 %p2\n2 %h: %i3%%"; + case PLAYERID_FIELD_BOTH: return "1 %c1: %p2\n2 %h: %i3%%"; + default: return "1 %p2\n2 : %i3%%"; + } +} +#endif + const char *GetCSModelName(int item_id) { const char *modelName = nullptr; @@ -8149,11 +8200,19 @@ void CBasePlayer::UpdateStatusBar() if (sameTeam || GetObserverMode() != OBS_NONE) { if (playerid.value != PLAYERID_MODE_OFF || GetObserverMode() != OBS_NONE) +#ifndef REGAMEDLL_ADD Q_strlcpy(sbuf0, "1 %c1: %p2\n2 %h: %i3%%"); +#else + Q_strlcpy(sbuf0, GetPlayerIdString(sameTeam)); +#endif else Q_strlcpy(sbuf0, " "); - - newSBarState[SBAR_ID_TARGETHEALTH] = int((pEntity->pev->health / pEntity->pev->max_health) * 100); +#ifdef REGAMEDLL_ADD + if (static_cast(playerid_showhealth.value) != PLAYERID_FIELD_NONE) +#endif + { + newSBarState[SBAR_ID_TARGETHEALTH] = int((pEntity->pev->health / pEntity->pev->max_health) * 100); + } if (!(m_flDisplayHistory & DHF_FRIEND_SEEN) && !(pev->flags & FL_SPECTATOR)) { @@ -8164,10 +8223,18 @@ void CBasePlayer::UpdateStatusBar() else if (GetObserverMode() == OBS_NONE) { if (playerid.value != PLAYERID_MODE_TEAMONLY && playerid.value != PLAYERID_MODE_OFF) +#ifndef REGAMEDLL_ADD Q_strlcpy(sbuf0, "1 %c1: %p2"); +#else + Q_strlcpy(sbuf0, GetPlayerIdString(sameTeam)); +#endif else Q_strlcpy(sbuf0, " "); +#ifdef REGAMEDLL_ADD + if (static_cast(playerid_showhealth.value) == PLAYERID_ALL) + newSBarState[SBAR_ID_TARGETHEALTH] = int((pEntity->pev->health / pEntity->pev->max_health) * 100); +#endif if (!(m_flDisplayHistory & DHF_ENEMY_SEEN)) { m_flDisplayHistory |= DHF_ENEMY_SEEN; From ce11175e89a9d71cc5c5034a0e5b6be71e47f9e7 Mon Sep 17 00:00:00 2001 From: Garey Date: Fri, 28 Mar 2025 04:05:43 +0500 Subject: [PATCH 33/46] Add cvar for stamina restoration speed based on fps reference. (#1005) * Add variable for framerate (FPS), that used as reference when restoring stamina (fuser2) after jump. --- README.md | 1 + dist/game.cfg | 6 ++++++ regamedll/dlls/game.cpp | 4 ++++ regamedll/dlls/game.h | 1 + regamedll/pm_shared/pm_shared.cpp | 13 +++++++++++++ 5 files changed, 25 insertions(+) diff --git a/README.md b/README.md index e515ac068..f6da49537 100644 --- a/README.md +++ b/README.md @@ -124,6 +124,7 @@ This means that plugins that do binary code analysis (Orpheu for example) probab | mp_ammo_respawn_time | 20 | 0.0 | - | The respawn time for ammunition. | | mp_vote_flags | km | 0 | - | Vote systems enabled in server.
`0` voting disabled
`k` votekick enabled via `vote` command
`m` votemap enabled via `votemap` command | | mp_votemap_min_time | 180 | 0.0 | - | Minimum seconds that must elapse on map before `votemap` command can be used. | +| mp_stamina_restore_rate | 0 | 0.0 | - | Framerate (FPS), that used as reference when restoring stamina (fuser2) after jump. | | mp_logkills | 1 | 0 | 1 | Log kills.
`0` disabled
`1` enabled | | mp_jump_height | 45 | 0.0 | - | Player jump height. | | bot_excellent_morale | 0 | 0 | 1 | Bots always have great morale regardless of defeat or victory. | diff --git a/dist/game.cfg b/dist/game.cfg index 3b77122f5..560629c22 100644 --- a/dist/game.cfg +++ b/dist/game.cfg @@ -628,6 +628,12 @@ mp_vote_flags "km" // Default value: "180" mp_votemap_min_time "180" +// Framerate (FPS), that is used as a reference when restoring stamina (fuser2) after a jump. +// 0 - disabled +// +// Default value: "0" +mp_stamina_restore_rate "0" + // Player jump height // // Default value: "45" diff --git a/regamedll/dlls/game.cpp b/regamedll/dlls/game.cpp index 6aaefbb7d..f36e80d8f 100644 --- a/regamedll/dlls/game.cpp +++ b/regamedll/dlls/game.cpp @@ -190,6 +190,8 @@ cvar_t ammo_respawn_time = { "mp_ammo_respawn_time", "20", FCVAR_SERVER, 2 cvar_t vote_flags = { "mp_vote_flags", "km", 0, 0.0f, nullptr }; cvar_t votemap_min_time = { "mp_votemap_min_time", "180", 0, 180.0f, nullptr }; +cvar_t stamina_restore_rate = { "mp_stamina_restore_rate", "0", 0, 0.f, nullptr }; + cvar_t logkills = { "mp_logkills", "1", FCVAR_SERVER, 0.0f, nullptr }; cvar_t randomspawn = { "mp_randomspawn", "0", FCVAR_SERVER, 0.0f, nullptr }; @@ -478,6 +480,8 @@ void EXT_FUNC GameDLLInit() CVAR_REGISTER(&playerid_showhealth); CVAR_REGISTER(&playerid_field); + CVAR_REGISTER(&stamina_restore_rate); + // print version CONSOLE_ECHO("ReGameDLL version: " APP_VERSION "\n"); diff --git a/regamedll/dlls/game.h b/regamedll/dlls/game.h index b3198ac40..ac9378918 100644 --- a/regamedll/dlls/game.h +++ b/regamedll/dlls/game.h @@ -210,6 +210,7 @@ extern cvar_t weapon_respawn_time; extern cvar_t ammo_respawn_time; extern cvar_t vote_flags; extern cvar_t votemap_min_time; +extern cvar_t stamina_restore_rate; extern cvar_t logkills; extern cvar_t randomspawn; extern cvar_t playerid_showhealth; diff --git a/regamedll/pm_shared/pm_shared.cpp b/regamedll/pm_shared/pm_shared.cpp index 2de5f5fdf..6904a756d 100644 --- a/regamedll/pm_shared/pm_shared.cpp +++ b/regamedll/pm_shared/pm_shared.cpp @@ -886,6 +886,18 @@ void PM_WalkMove() { real_t flRatio = (100 - pmove->fuser2 * 0.001 * 19) * 0.01; +#ifdef REGAMEDLL_ADD + // change stamina restoration speed by fps reference + if (stamina_restore_rate.value > 0.0f) + { + real_t flReferenceFrametime = 1.0f / stamina_restore_rate.value; + + float flFrametimeRatio = pmove->frametime / flReferenceFrametime; + + flRatio = pow(flRatio, flFrametimeRatio); + } +#endif + pmove->velocity[0] *= flRatio; pmove->velocity[1] *= flRatio; } @@ -2611,6 +2623,7 @@ void EXT_FUNC __API_HOOK(PM_Jump)() { // NOTE: don't do it in .f (float) real_t flRatio = (100.0 - pmove->fuser2 * 0.001 * 19.0) * 0.01; + pmove->velocity[2] *= flRatio; } From d3fc7ac000383b28780d2d79abba417c7f544a5c Mon Sep 17 00:00:00 2001 From: Garey Date: Fri, 28 Mar 2025 04:16:07 +0500 Subject: [PATCH 34/46] New flymove more accurate method (#1006) --- README.md | 1 + dist/game.cfg | 7 ++ regamedll/dlls/game.cpp | 3 + regamedll/dlls/game.h | 3 + regamedll/pm_shared/pm_shared.cpp | 175 ++++++++++++++++++++++++++++++ 5 files changed, 189 insertions(+) diff --git a/README.md b/README.md index f6da49537..b39c0f196 100644 --- a/README.md +++ b/README.md @@ -124,6 +124,7 @@ This means that plugins that do binary code analysis (Orpheu for example) probab | mp_ammo_respawn_time | 20 | 0.0 | - | The respawn time for ammunition. | | mp_vote_flags | km | 0 | - | Vote systems enabled in server.
`0` voting disabled
`k` votekick enabled via `vote` command
`m` votemap enabled via `votemap` command | | mp_votemap_min_time | 180 | 0.0 | - | Minimum seconds that must elapse on map before `votemap` command can be used. | +| mp_flymove_method | 0 | 0 | 1 | Set the method used for flymove calculations.
`0` default method
`1` alternative method (more accurate) | | mp_stamina_restore_rate | 0 | 0.0 | - | Framerate (FPS), that used as reference when restoring stamina (fuser2) after jump. | | mp_logkills | 1 | 0 | 1 | Log kills.
`0` disabled
`1` enabled | | mp_jump_height | 45 | 0.0 | - | Player jump height. | diff --git a/dist/game.cfg b/dist/game.cfg index 560629c22..70bd646b3 100644 --- a/dist/game.cfg +++ b/dist/game.cfg @@ -628,6 +628,13 @@ mp_vote_flags "km" // Default value: "180" mp_votemap_min_time "180" +// Set the method used for flymove calculations. +// 0 - default method +// 1 - alternative method (more accurate) +// +// Default value: "0" +mp_flymove_method "0" + // Framerate (FPS), that is used as a reference when restoring stamina (fuser2) after a jump. // 0 - disabled // diff --git a/regamedll/dlls/game.cpp b/regamedll/dlls/game.cpp index f36e80d8f..e5ee0c2b9 100644 --- a/regamedll/dlls/game.cpp +++ b/regamedll/dlls/game.cpp @@ -190,6 +190,7 @@ cvar_t ammo_respawn_time = { "mp_ammo_respawn_time", "20", FCVAR_SERVER, 2 cvar_t vote_flags = { "mp_vote_flags", "km", 0, 0.0f, nullptr }; cvar_t votemap_min_time = { "mp_votemap_min_time", "180", 0, 180.0f, nullptr }; +cvar_t flymove_method = { "mp_flymove_method", "0", 0, 0.0f, nullptr }; cvar_t stamina_restore_rate = { "mp_stamina_restore_rate", "0", 0, 0.f, nullptr }; cvar_t logkills = { "mp_logkills", "1", FCVAR_SERVER, 0.0f, nullptr }; @@ -482,6 +483,8 @@ void EXT_FUNC GameDLLInit() CVAR_REGISTER(&stamina_restore_rate); + CVAR_REGISTER(&flymove_method); + // print version CONSOLE_ECHO("ReGameDLL version: " APP_VERSION "\n"); diff --git a/regamedll/dlls/game.h b/regamedll/dlls/game.h index ac9378918..95609f123 100644 --- a/regamedll/dlls/game.h +++ b/regamedll/dlls/game.h @@ -210,6 +210,7 @@ extern cvar_t weapon_respawn_time; extern cvar_t ammo_respawn_time; extern cvar_t vote_flags; extern cvar_t votemap_min_time; +extern cvar_t flymove_method; extern cvar_t stamina_restore_rate; extern cvar_t logkills; extern cvar_t randomspawn; @@ -222,4 +223,6 @@ extern cvar_t scoreboard_showmoney; extern cvar_t scoreboard_showhealth; extern cvar_t scoreboard_showdefkit; + + void GameDLLInit(); diff --git a/regamedll/pm_shared/pm_shared.cpp b/regamedll/pm_shared/pm_shared.cpp index 6904a756d..846b410d0 100644 --- a/regamedll/pm_shared/pm_shared.cpp +++ b/regamedll/pm_shared/pm_shared.cpp @@ -641,9 +641,184 @@ void PM_FixupGravityVelocity() pmove->velocity[2] -= (pmove->movevars->gravity * pmove->frametime * ent_gravity * 0.5); PM_CheckVelocity(); } +#ifdef REGAMEDLL_ADD +int PM_FlyMove_New() +{ + int bumpcount, numbumps; + vec3_t dir; + float d; + int numplanes; + vec3_t planes[MAX_CLIP_PLANES]; + vec3_t primal_velocity; + vec3_t clipVelocity; + int i, j, k; + pmtrace_t trace; + vec3_t end; + float time_left; + float into; + vec3_t endVelocity; + vec3_t endClipVelocity; + int blocked; + + numbumps = 4; + + VectorCopy(pmove->velocity, primal_velocity); + + + time_left = pmove->frametime; + + numplanes = 0; + blocked = 0x00; // Assume not blocked + + // never turn against original velocity + VectorCopy(pmove->velocity, planes[numplanes]); + VectorNormalize(planes[numplanes]); + numplanes++; + + for (bumpcount = 0; bumpcount < numbumps; bumpcount++) { + + // calculate position we are trying to move to + VectorMA(pmove->origin, time_left, pmove->velocity, end); + + // see if we can make it there + trace = pmove->PM_PlayerTrace(pmove->origin, end, PM_NORMAL, -1); + + if (trace.allsolid) { + // entity is completely trapped in another solid + pmove->velocity[2] = 0; // don't build up falling damage, but allow sideways acceleration + return 4; + } + + if (trace.fraction > 0) { + // actually covered some distance + VectorCopy(trace.endpos, pmove->origin); + } + if (trace.fraction == 1) { + break; // moved the entire distance + } + + // save entity for contact + PM_AddToTouched(trace, pmove->velocity); + + // If the plane we hit has a high z component in the normal, then + // it's probably a floor + if (trace.plane.normal[2] > 0.7f) + { + // floor + blocked |= 0x01; + } + + // If the plane has a zero z component in the normal, then it's a + // step or wall + if (!trace.plane.normal[2]) + { + // step / wall + blocked |= 0x02; + } + + time_left -= time_left * trace.fraction; + + if (numplanes >= MAX_CLIP_PLANES) { + // this shouldn't really happen + VectorClear(pmove->velocity); + break; + } + + // + // if this is the same plane we hit before, nudge velocity + // out along it, which fixes some epsilon issues with + // non-axial planes + // + for (i = 0; i < numplanes; i++) { + if (DotProduct(trace.plane.normal, planes[i]) > 0.99) { + VectorAdd(trace.plane.normal, pmove->velocity, pmove->velocity); + break; + } + } + if (i < numplanes) { + continue; + } + VectorCopy(trace.plane.normal, planes[numplanes]); + numplanes++; + + // + // modify velocity so it parallels all of the clip planes + // + + // find a plane that it enters + for (i = 0; i < numplanes; i++) { + into = DotProduct(pmove->velocity, planes[i]); + if (into >= 0.1) { + continue; // move doesn't interact with the plane + } + + // slide along the plane + PM_ClipVelocity(pmove->velocity, planes[i], clipVelocity, 1); + + // slide along the plane + PM_ClipVelocity(endVelocity, planes[i], endClipVelocity, 1); + + // see if there is a second plane that the new move enters + for (j = 0; j < numplanes; j++) { + if (j == i) { + continue; + } + if (DotProduct(clipVelocity, planes[j]) >= 0.1) { + continue; // move doesn't interact with the plane + } + + // try clipping the move to the plane + PM_ClipVelocity(clipVelocity, planes[j], clipVelocity, 1); + PM_ClipVelocity(endClipVelocity, planes[j], endClipVelocity, 1); + + // see if it goes back into the first clip plane + if (DotProduct(clipVelocity, planes[i]) >= 0) { + continue; + } + + // slide the original velocity along the crease + CrossProduct(planes[i], planes[j], dir); + VectorNormalize(dir); + d = DotProduct(dir, pmove->velocity); + VectorScale(dir, d, clipVelocity); + + CrossProduct(planes[i], planes[j], dir); + VectorNormalize(dir); + d = DotProduct(dir, endVelocity); + VectorScale(dir, d, endClipVelocity); + + // see if there is a third plane the the new move enters + for (k = 0; k < numplanes; k++) { + if (k == i || k == j) { + continue; + } + if (DotProduct(clipVelocity, planes[k]) >= 0.1) { + continue; // move doesn't interact with the plane + } + + // stop dead at a tripple plane interaction + VectorClear(pmove->velocity); + return 4; + } + } + + // if we have fixed all interactions, try another move + VectorCopy(clipVelocity, pmove->velocity); + VectorCopy(endClipVelocity, endVelocity); + break; + } + } + + return blocked; +} +#endif int PM_FlyMove() { +#ifdef REGAMEDLL_ADD + if (flymove_method.value) + return PM_FlyMove_New(); +#endif int bumpcount, numbumps; vec3_t dir; float d; From f5cc6f3a8bcc1484f405520661f6ec74af1b7d0b Mon Sep 17 00:00:00 2001 From: s1lentq Date: Fri, 4 Apr 2025 02:19:53 +0700 Subject: [PATCH 35/46] AngleQuaternion: fix buffer overflow --- regamedll/dlls/animation.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/regamedll/dlls/animation.cpp b/regamedll/dlls/animation.cpp index 7d5df6f07..fbf6a1bb6 100644 --- a/regamedll/dlls/animation.cpp +++ b/regamedll/dlls/animation.cpp @@ -547,7 +547,9 @@ void AngleQuaternion(vec_t *angles, vec_t *quaternion) { static const ALIGN16_BEG size_t ps_signmask[4] ALIGN16_END = { 0x80000000, 0, 0x80000000, 0 }; - __m128 a = _mm_loadu_ps(angles); + vec4_t _ps_angles = { angles[0], angles[1], angles[2], 0.0f }; + + __m128 a = _mm_loadu_ps(_ps_angles); a = _mm_mul_ps(a, _mm_load_ps(_ps_0p5)); //a *= 0.5 __m128 s, c; sincos_ps(a, &s, &c); From 6f70d6dd8e61943f1a093d292b8768dc7cc50ef8 Mon Sep 17 00:00:00 2001 From: s1lentq Date: Fri, 4 Apr 2025 02:41:19 +0700 Subject: [PATCH 36/46] ZBot: Implemented immediate reloading of nav data after bot analysis, without requiring a full map restart ZBot: Added cleanup for dangling navigation pointers in bots, enabling seamless map reanalysis Minor refactoring --- regamedll/dlls/bot/cs_bot.cpp | 126 ++++++++++++++++++ regamedll/dlls/bot/cs_bot.h | 6 + regamedll/dlls/bot/cs_bot_init.cpp | 2 +- regamedll/dlls/bot/cs_bot_learn.cpp | 17 +-- regamedll/dlls/bot/cs_bot_manager.cpp | 171 ++++++++++++++++++++----- regamedll/dlls/bot/cs_bot_manager.h | 9 +- regamedll/dlls/bot/cs_bot_vision.cpp | 2 +- regamedll/dlls/client.cpp | 11 +- regamedll/dlls/game.cpp | 4 +- regamedll/dlls/player.cpp | 2 + regamedll/dlls/util.cpp | 2 +- regamedll/game_shared/bot/nav.h | 7 + regamedll/game_shared/bot/nav_area.cpp | 54 ++++++-- regamedll/game_shared/bot/nav_area.h | 1 + regamedll/game_shared/bot/nav_file.cpp | 7 + regamedll/msvc/ReGameDLL.vcxproj | 5 +- 16 files changed, 353 insertions(+), 73 deletions(-) diff --git a/regamedll/dlls/bot/cs_bot.cpp b/regamedll/dlls/bot/cs_bot.cpp index dd85448c6..b89a69126 100644 --- a/regamedll/dlls/bot/cs_bot.cpp +++ b/regamedll/dlls/bot/cs_bot.cpp @@ -900,3 +900,129 @@ float CCSBot::GetRangeToFarthestEscortedHostage() const return away.m_farRange; } + +// Remove all occurrences of a given area from the path list +void CCSBot::RemovePath(CNavArea *area) +{ + int i = 0; + while (i < m_pathLength) + { + if (m_path[i].area == area) + { + // If this area is linked to a ladder, clear the reference + if (m_path[i].ladder == m_pathLadder) + m_pathLadder = nullptr; + + m_pathLength--; + + // adjust the current path index if the removed element is being used + if (i == m_pathIndex) + { + if (i > 0) + m_pathIndex = i - 1; + else + m_pathIndex = 0; + } + + if (m_pathLength != i) + Q_memmove(&m_path[i], &m_path[i + 1], (m_pathLength - i) * sizeof(m_path[0])); + + // clear the slot + Q_memset(&m_path[m_pathLength], 0, sizeof(m_path[m_pathLength])); + } + else + { + i++; + } + } +} + +// Remove a hiding spot from the checked spots list +void CCSBot::RemoveHidingSpot(HidingSpot *spot) +{ + int i = 0; + while (i < m_pathLength) + { + if (m_checkedHidingSpot[i].spot == spot) + { + m_checkedHidingSpotCount--; + + if (m_checkedHidingSpotCount != i) + Q_memmove(&m_checkedHidingSpot[i], &m_checkedHidingSpot[i + 1], (m_checkedHidingSpotCount - i) * sizeof(m_checkedHidingSpot[0])); + + // clear the slot + Q_memset(&m_checkedHidingSpot[m_checkedHidingSpotCount], 0, sizeof(m_checkedHidingSpot[m_checkedHidingSpotCount])); + } + else + { + i++; + } + } +} + +// Handle navigation-related cleanup when a nav area, spot, or encounter is destroyed +void CCSBot::OnDestroyNavDataNotify(NavNotifyDestroyType navNotifyType, void *dead) +{ + switch (navNotifyType) + { + case NAV_NOTIFY_DESTROY_AREA: + { + CNavArea *area = static_cast(dead); + + // If the destroyed area was linked to a spot encounter, clear it + if (m_spotEncounter) + { + if (m_spotEncounter->from.area == area || m_spotEncounter->to.area == area) + m_spotEncounter = nullptr; + } + + RemovePath(area); + + // Invalidate any references to the destroyed area + + if (m_noiseArea == area) + m_noiseArea = nullptr; + + if (m_currentArea == area) + m_currentArea = nullptr; + + if (m_lastKnownArea == area) + m_lastKnownArea = nullptr; + + if (m_hideState.GetSearchArea() == area) + m_hideState.SetSearchArea(nullptr); + + if (m_huntState.GetHuntArea() == area) + m_huntState.ClearHuntArea(); + + break; + } + case NAV_NOTIFY_DESTROY_SPOT_ENCOUNTER: + { + CNavArea *area = static_cast(dead); + + // Remove the encounter if it references the destroyed area + if (m_spotEncounter && area->HasSpotEncounter(m_spotEncounter)) + m_spotEncounter = nullptr; + + break; + } + case NAV_NOTIFY_DESTROY_SPOT: + { + HidingSpot *spot = static_cast(dead); + + // Remove the destroyed hiding spot from the spot order list + if (m_spotEncounter) + { + SpotOrderList &spotOrderList = m_spotEncounter->spotList; + spotOrderList.erase(std::remove_if(spotOrderList.begin(), spotOrderList.end(), [&](SpotOrder &spotOrder) { + return spotOrder.spot == spot; + } + ), spotOrderList.end()); + } + + RemoveHidingSpot(spot); + break; + } + } +} diff --git a/regamedll/dlls/bot/cs_bot.h b/regamedll/dlls/bot/cs_bot.h index 8f63e1a68..0ba299857 100644 --- a/regamedll/dlls/bot/cs_bot.h +++ b/regamedll/dlls/bot/cs_bot.h @@ -71,6 +71,7 @@ class HuntState: public BotState virtual const char *GetName() const { return "Hunt"; } void ClearHuntArea() { m_huntArea = nullptr; } + CNavArea *GetHuntArea() { return m_huntArea; } private: CNavArea *m_huntArea; @@ -204,6 +205,7 @@ class HideState: public BotState const Vector &GetHidingSpot() const { return m_hidingSpot; } void SetSearchArea(CNavArea *area) { m_searchFromArea = area; } + CNavArea *GetSearchArea() { return m_searchFromArea; } void SetSearchRange(float range) { m_range = range; } void SetDuration(float time) { m_duration = time; } @@ -544,6 +546,10 @@ class CCSBot: public CBot float GetFeetZ() const; // return Z of bottom of feet + void OnDestroyNavDataNotify(NavNotifyDestroyType navNotifyType, void *dead); + void RemovePath(CNavArea *area); + void RemoveHidingSpot(HidingSpot *spot); + enum PathResult { PROGRESSING, // we are moving along the path diff --git a/regamedll/dlls/bot/cs_bot_init.cpp b/regamedll/dlls/bot/cs_bot_init.cpp index 3199cf91e..2db6b02d5 100644 --- a/regamedll/dlls/bot/cs_bot_init.cpp +++ b/regamedll/dlls/bot/cs_bot_init.cpp @@ -337,7 +337,7 @@ void CCSBot::ResetValues() // NOTE: For some reason, this can be called twice when a bot is added. void CCSBot::SpawnBot() { - TheCSBots()->ValidateMapData(); + TheCSBots()->LoadNavigationMap(); ResetValues(); Q_strlcpy(m_name, STRING(pev->netname)); diff --git a/regamedll/dlls/bot/cs_bot_learn.cpp b/regamedll/dlls/bot/cs_bot_learn.cpp index 3cf041e31..e68a77a5e 100644 --- a/regamedll/dlls/bot/cs_bot_learn.cpp +++ b/regamedll/dlls/bot/cs_bot_learn.cpp @@ -477,31 +477,24 @@ void CCSBot::StartSaveProcess() void CCSBot::UpdateSaveProcess() { - char msg[256]; - char cmd[128]; - char gd[64]{}; GET_GAME_DIR(gd); char filename[MAX_OSPATH]; Q_snprintf(filename, sizeof(filename), "%s\\%s", gd, TheBots->GetNavMapFilename()); - - HintMessageToAllPlayers("Saving..."); SaveNavigationMap(filename); + char msg[256]{}; Q_snprintf(msg, sizeof(msg), "Navigation file '%s' saved.", filename); HintMessageToAllPlayers(msg); + CONSOLE_ECHO("%s\n", msg); hideProgressMeter(); StartNormalProcess(); -#ifndef REGAMEDLL_FIXES - Q_snprintf(cmd, sizeof(cmd), "map %s\n", STRING(gpGlobals->mapname)); -#else - Q_snprintf(cmd, sizeof(cmd), "changelevel %s\n", STRING(gpGlobals->mapname)); -#endif - - SERVER_COMMAND(cmd); + // tell bot manager that the analysis is completed + if (TheCSBots()) + TheCSBots()->AnalysisCompleted(); } void CCSBot::StartNormalProcess() diff --git a/regamedll/dlls/bot/cs_bot_manager.cpp b/regamedll/dlls/bot/cs_bot_manager.cpp index e68bea538..15fc3de24 100644 --- a/regamedll/dlls/bot/cs_bot_manager.cpp +++ b/regamedll/dlls/bot/cs_bot_manager.cpp @@ -231,13 +231,12 @@ bool CCSBotManager::IsOnOffense(CBasePlayer *pPlayer) const // Invoked when a map has just been loaded void CCSBotManager::ServerActivate() { - DestroyNavigationMap(); m_isMapDataLoaded = false; m_zoneCount = 0; m_gameScenario = SCENARIO_DEATHMATCH; - ValidateMapData(); + LoadNavigationMap(); RestartRound(); m_isLearningMap = false; @@ -591,7 +590,8 @@ void CCSBotManager::ServerCommand(const char *pcmd) } else if (FStrEq(pcmd, "bot_nav_load")) { - ValidateMapData(); + m_isMapDataLoaded = false; // force nav reload + LoadNavigationMap(); } else if (FStrEq(pcmd, "bot_nav_use_place")) { @@ -1144,7 +1144,6 @@ class CollectOverlappingAreas CCSBotManager::Zone *m_zone; }; -#ifdef REGAMEDLL_ADD LINK_ENTITY_TO_CLASS(info_spawn_point, CPointEntity, CCSPointEntity) inline bool IsFreeSpace(Vector vecOrigin, int iHullNumber, edict_t *pSkipEnt = nullptr) @@ -1163,6 +1162,9 @@ inline bool pointInRadius(Vector vecOrigin, float radius) CBaseEntity *pEntity = nullptr; while ((pEntity = UTIL_FindEntityInSphere(pEntity, vecOrigin, radius))) { + if (!UTIL_IsValidEntity(pEntity->edict())) + continue; // ignore the entity marked for deletion + if (FClassnameIs(pEntity->edict(), "info_spawn_point")) return true; } @@ -1171,12 +1173,10 @@ inline bool pointInRadius(Vector vecOrigin, float radius) } // a simple algorithm that searches for the farthest point (so that the player does not look at the wall) -inline Vector GetBestAngle(const Vector &vecStart) +inline bool GetIdealLookYawForSpawnPoint(const Vector &vecStart, float &flIdealLookYaw) { const float ANGLE_STEP = 30.0f; - float bestAngle = 0.0f; float bestDistance = 0.0f; - Vector vecBestAngle = Vector(0, -1, 0); for (float angleYaw = 0.0f; angleYaw <= 360.0f; angleYaw += ANGLE_STEP) { @@ -1187,15 +1187,14 @@ inline Vector GetBestAngle(const Vector &vecStart) UTIL_TraceLine(vecStart, vecEnd, ignore_monsters, nullptr, &tr); float distance = (vecStart - tr.vecEndPos).Length(); - if (distance > bestDistance) { bestDistance = distance; - vecBestAngle.y = angleYaw; + flIdealLookYaw = angleYaw; } } - return vecBestAngle; + return bestDistance > 0.0f; } // this function from leaked csgo sources 2020y @@ -1231,58 +1230,69 @@ inline bool IsValidArea(CNavArea *area) return false; } -void GetSpawnPositions() +#ifdef REGAMEDLL_ADD + +// Generates spawn points (info_spawn_point entities) for players and bots based on the navigation map data +// It uses the navigation areas to find valid spots for spawn points considering factors like area size, slope, +// available free space, and distance from other spawn points. +void GenerateSpawnPointsFromNavData() { - const float MIN_AREA_SIZE = 32.0f; - const int MAX_SPAWNS_POINTS = 128; - const float MAX_SLOPE = 0.85f; + // Remove any existing spawn points + UTIL_RemoveOther("info_spawn_point"); + + const int MAX_SPAWNS_POINTS = 128; // Max allowed spawn points + + const float MAX_SLOPE = 0.85f; // Maximum slope allowed for a spawn point + const float MIN_AREA_SIZE = 32.0f; // Minimum area size for a valid spawn point + const float MIN_NEARBY_SPAWNPOINT = 128.0f; // Minimum distance between spawn point + // Total number of spawn points generated int totalSpawns = 0; - for (NavAreaList::iterator iter = TheNavAreaList.begin(); iter != TheNavAreaList.end(); iter++) + for (CNavArea *area : TheNavAreaList) { if (totalSpawns >= MAX_SPAWNS_POINTS) break; - CNavArea *area = *iter; - if (!area) continue; - // ignore small areas + // Skip areas that are too small if (area->GetSizeX() < MIN_AREA_SIZE || area->GetSizeY() < MIN_AREA_SIZE) continue; - // ignore areas jump, crouch etc - if (area->GetAttributes()) + // Skip areas with unwanted attributes (jump, crouch, etc.) + if (area->GetAttributes() != 0) continue; + // Skip areas with steep slopes if (area->GetAreaSlope() < MAX_SLOPE) { //CONSOLE_ECHO("Skip area slope: %0.3f\n", area->GetAreaSlope()); continue; } + // Calculate the spawn point position above the area center Vector vecOrigin = *area->GetCenter() + Vector(0, 0, HalfHumanHeight + 5); + // Ensure there is free space at the calculated position if (!IsFreeSpace(vecOrigin, human_hull)) { //CONSOLE_ECHO("No free space!\n"); continue; } - if (pointInRadius(vecOrigin, 128.0f)) - continue; + if (pointInRadius(vecOrigin, MIN_NEARBY_SPAWNPOINT)) + continue; // spawn point is too close to others if (!IsValidArea(area)) continue; - Vector bestAngle = GetBestAngle(vecOrigin); - - if (bestAngle.y != -1) + // Calculate ideal spawn point yaw angle + float flIdealSpawnPointYaw = 0.0f; + if (GetIdealLookYawForSpawnPoint(vecOrigin, flIdealSpawnPointYaw)) { - CBaseEntity* pPoint = CBaseEntity::Create("info_spawn_point", vecOrigin, bestAngle, nullptr); - + CBaseEntity *pPoint = CBaseEntity::Create("info_spawn_point", vecOrigin, Vector(0, flIdealSpawnPointYaw, 0), nullptr); if (pPoint) { totalSpawns++; @@ -1302,24 +1312,64 @@ void GetSpawnPositions() CONSOLE_ECHO("Total spawns points: %i\n", totalSpawns); } + #endif -// Search the map entities to determine the game scenario and define important zones. -void CCSBotManager::ValidateMapData() +// Load the map's navigation data +bool CCSBotManager::LoadNavigationMap() { + // check if the map data is already loaded or if bots are not allowed if (m_isMapDataLoaded || !AreBotsAllowed()) - return; + return false; m_isMapDataLoaded = true; - if (LoadNavigationMap()) + // Clear navigation map data from previous map + DestroyNavigationMap(); + + // Try to load the map's navigation file + NavErrorType navStatus = ::LoadNavigationMap(); + if (navStatus != NAV_OK) { - CONSOLE_ECHO("Failed to load navigation map.\n"); - return; + CONSOLE_ECHO("ERROR: Failed to load 'maps/%s.nav' file navigation map!\n", STRING(gpGlobals->mapname)); + + switch (navStatus) + { + case NAV_CANT_ACCESS_FILE: + CONSOLE_ECHO("\tNavigation file not found or access denied.\n"); + break; + case NAV_INVALID_FILE: + CONSOLE_ECHO("\tInvalid navigation file format.\n"); + break; + case NAV_BAD_FILE_VERSION: + CONSOLE_ECHO("\tBad navigation file version.\n"); + break; + case NAV_CORRUPT_DATA: + CONSOLE_ECHO("\tCorrupted navigation data detected.\n"); + break; + default: + break; + } + + if (navStatus != NAV_CANT_ACCESS_FILE) + CONSOLE_ECHO("\tTry regenerating it using the command: bot_nav_analyze\n"); + + return false; } - CONSOLE_ECHO("Navigation map loaded.\n"); + // Determine the scenario for the current map (e.g., bomb defuse, hostage rescue etc) + DetermineMapScenario(); + +#ifdef REGAMEDLL_ADD + GenerateSpawnPointsFromNavData(); +#endif + + return true; +} +// Search the map entities to determine the game scenario and define important zones. +void CCSBotManager::DetermineMapScenario() +{ m_zoneCount = 0; m_gameScenario = SCENARIO_DEATHMATCH; @@ -1459,6 +1509,59 @@ void CCSBotManager::ValidateMapData() } } +// Tell all bots that the given nav data no longer exists +// This function is called when a part of the map or the nav data is destroyed +void CCSBotManager::OnDestroyNavDataNotify(NavNotifyDestroyType navNotifyType, void *dead) +{ + for (int i = 1; i <= gpGlobals->maxClients; i++) + { + CBasePlayer *pPlayer = UTIL_PlayerByIndex(i); + + if (!UTIL_IsValidPlayer(pPlayer)) + continue; + + if (!pPlayer->IsBot()) + continue; + + // Notify the bot about the destroyed nav data + CCSBot *pBot = static_cast(pPlayer); + pBot->OnDestroyNavDataNotify(navNotifyType, dead); + } +} + +// Called when the map analysis process has completed +// This function makes sure all bots are removed from the map analysis process +// and are reset to normal bot behavior. It also reloads the navigation map +// and triggers a game restart after the analysis is completed +void CCSBotManager::AnalysisCompleted() +{ + // Ensure that all bots are no longer involved in map analysis and start their normal process + for (int i = 1; i <= gpGlobals->maxClients; i++) + { + CBasePlayer *pPlayer = UTIL_PlayerByIndex(i); + + if (!UTIL_IsValidPlayer(pPlayer)) + continue; + + if (!pPlayer->IsBot()) + continue; + + CCSBot *pBot = static_cast(pPlayer); + pBot->StartNormalProcess(); + } + + m_isLearningMap = false; + m_isMapDataLoaded = false; + m_isAnalysisRequested = false; + + // Try to reload the navigation map from the file + if (LoadNavigationMap()) + { + // Initiate a game restart in 3 seconds + CVAR_SET_FLOAT("sv_restart", 3); + } +} + bool CCSBotManager::AddBot(const BotProfile *profile, BotProfileTeamType team) { if (!AreBotsAllowed()) diff --git a/regamedll/dlls/bot/cs_bot_manager.h b/regamedll/dlls/bot/cs_bot_manager.h index 0d5e6e37d..6f3b0e689 100644 --- a/regamedll/dlls/bot/cs_bot_manager.h +++ b/regamedll/dlls/bot/cs_bot_manager.h @@ -56,13 +56,16 @@ class CCSBotManager: public CBotManager virtual bool IsImportantPlayer(CBasePlayer *pPlayer) const; // return true if pPlayer is important to scenario (VIP, bomb carrier, etc) public: - void ValidateMapData(); + bool LoadNavigationMap(); + void DetermineMapScenario(); void OnFreeEntPrivateData(CBaseEntity *pEntity); + void OnDestroyNavDataNotify(NavNotifyDestroyType navNotifyType, void *dead); bool IsLearningMap() const { return m_isLearningMap; } void SetLearningMapFlag() { m_isLearningMap = true; } bool IsAnalysisRequested() const { return m_isAnalysisRequested; } void RequestAnalysis() { m_isAnalysisRequested = true; } void AckAnalysisRequest() { m_isAnalysisRequested = false; } + void AnalysisCompleted(); // difficulty levels static BotDifficultyType GetDifficultyLevel() @@ -269,6 +272,4 @@ inline bool AreBotsAllowed() } void PrintAllEntities(); -#ifdef REGAMEDLL_ADD -void GetSpawnPositions(); -#endif \ No newline at end of file +void GenerateSpawnPointsFromNavData(); diff --git a/regamedll/dlls/bot/cs_bot_vision.cpp b/regamedll/dlls/bot/cs_bot_vision.cpp index 6e9d8ddc8..56f75678e 100644 --- a/regamedll/dlls/bot/cs_bot_vision.cpp +++ b/regamedll/dlls/bot/cs_bot_vision.cpp @@ -1003,7 +1003,7 @@ CBasePlayer *CCSBot::FindMostDangerousThreat() return currentThreat; } - // if we are a sniper and we see a sniper threat, attack it unless + // if we are a sniper and we see a sniper threat, attack it unless // there are other close enemies facing me if (IsSniper() && sniperThreat) { diff --git a/regamedll/dlls/client.cpp b/regamedll/dlls/client.cpp index 971a41cf6..b802a2e31 100644 --- a/regamedll/dlls/client.cpp +++ b/regamedll/dlls/client.cpp @@ -844,7 +844,7 @@ void Host_Say(edict_t *pEntity, BOOL teamonly) #ifdef REGAMEDLL_ADD // there's no team on FFA mode if (teamonly && CSGameRules()->IsFreeForAll() && (pPlayer->m_iTeam == CT || pPlayer->m_iTeam == TERRORIST)) - teamonly = FALSE; + teamonly = FALSE; #endif // team only @@ -1001,7 +1001,7 @@ void Host_Say(edict_t *pEntity, BOOL teamonly) if (gpGlobals->deathmatch != 0.0f && CSGameRules()->m_VoiceGameMgr.PlayerHasBlockedPlayer(pReceiver, pPlayer)) continue; - if (teamonly + if (teamonly #ifdef REGAMEDLL_FIXES && CSGameRules()->PlayerRelationship(pPlayer, pReceiver) != GR_TEAMMATE #else @@ -1020,7 +1020,7 @@ void Host_Say(edict_t *pEntity, BOOL teamonly) continue; } - if ((pReceiver->m_iIgnoreGlobalChat == IGNOREMSG_ENEMY + if ((pReceiver->m_iIgnoreGlobalChat == IGNOREMSG_ENEMY #ifdef REGAMEDLL_FIXES && CSGameRules()->PlayerRelationship(pPlayer, pReceiver) == GR_TEAMMATE #else @@ -3833,11 +3833,6 @@ void EXT_FUNC ServerActivate(edict_t *pEdictList, int edictCount, int clientMax) #ifdef REGAMEDLL_ADD CSGameRules()->ServerActivate(); - - if (LoadNavigationMap() == NAV_OK) - { - GetSpawnPositions(); - } #endif } diff --git a/regamedll/dlls/game.cpp b/regamedll/dlls/game.cpp index e5ee0c2b9..a022348ee 100644 --- a/regamedll/dlls/game.cpp +++ b/regamedll/dlls/game.cpp @@ -174,9 +174,9 @@ cvar_t freezetime_duck = { "mp_freezetime_duck", "1", 0, 1.0f, cvar_t freezetime_jump = { "mp_freezetime_jump", "1", 0, 1.0f, nullptr }; cvar_t jump_height = { "mp_jump_height", "45", FCVAR_SERVER, 45.0f, nullptr }; -cvar_t hostages_rescued_ratio = { "mp_hostages_rescued_ratio", "1.0", 0, 1.0f, nullptr }; +cvar_t hostages_rescued_ratio = { "mp_hostages_rescued_ratio", "1.0", 0, 1.0f, nullptr }; -cvar_t legacy_vehicle_block = { "mp_legacy_vehicle_block", "1", 0, 0.0f, nullptr }; +cvar_t legacy_vehicle_block = { "mp_legacy_vehicle_block", "1", 0, 0.0f, nullptr }; cvar_t dying_time = { "mp_dying_time", "3.0", 0, 3.0f, nullptr }; cvar_t defuser_allocation = { "mp_defuser_allocation", "0", 0, 0.0f, nullptr }; diff --git a/regamedll/dlls/player.cpp b/regamedll/dlls/player.cpp index 81548d346..1f096d13b 100644 --- a/regamedll/dlls/player.cpp +++ b/regamedll/dlls/player.cpp @@ -5594,7 +5594,9 @@ edict_t *EXT_FUNC CBasePlayer::__API_HOOK(EntSelectSpawnPoint)() // The terrorist spawn points else if (g_pGameRules->IsDeathmatch() && m_iTeam == TERRORIST) { +#ifdef REGAMEDLL_ADD TSpawn: +#endif pSpot = g_pLastTerroristSpawn; if (SelectSpawnSpot("info_player_deathmatch", pSpot)) diff --git a/regamedll/dlls/util.cpp b/regamedll/dlls/util.cpp index b1102c470..e0ffed532 100644 --- a/regamedll/dlls/util.cpp +++ b/regamedll/dlls/util.cpp @@ -1464,7 +1464,7 @@ void UTIL_Remove(CBaseEntity *pEntity) pEntity->pev->targetname = 0; } -NOXREF BOOL UTIL_IsValidEntity(edict_t *pent) +BOOL UTIL_IsValidEntity(edict_t *pent) { if (!pent || pent->free || (pent->v.flags & FL_KILLME)) return FALSE; diff --git a/regamedll/game_shared/bot/nav.h b/regamedll/game_shared/bot/nav.h index a917aa993..d23a734e6 100644 --- a/regamedll/game_shared/bot/nav.h +++ b/regamedll/game_shared/bot/nav.h @@ -71,6 +71,13 @@ enum NavAttributeType NAV_NO_JUMP = 0x08, // inhibit discontinuity jumping }; +enum NavNotifyDestroyType +{ + NAV_NOTIFY_DESTROY_AREA, + NAV_NOTIFY_DESTROY_SPOT, + NAV_NOTIFY_DESTROY_SPOT_ENCOUNTER +}; + enum NavDirType { NORTH = 0, diff --git a/regamedll/game_shared/bot/nav_area.cpp b/regamedll/game_shared/bot/nav_area.cpp index 6c5960517..a5f8f748f 100644 --- a/regamedll/game_shared/bot/nav_area.cpp +++ b/regamedll/game_shared/bot/nav_area.cpp @@ -72,17 +72,29 @@ NOXREF void buildGoodSizedList() void DestroyHidingSpots() { + // free all the HidingSpots + for (HidingSpot *spot : TheHidingSpotList) + { + TheCSBots()->OnDestroyNavDataNotify(NAV_NOTIFY_DESTROY_SPOT, spot); + delete spot; + } + + TheHidingSpotList.clear(); + // remove all hiding spot references from the nav areas - for (auto area : TheNavAreaList) + for (CNavArea *area : TheNavAreaList) + { area->m_hidingSpotList.clear(); - HidingSpot::m_nextID = 0; + // free all the HidingSpots in area + for (SpotEncounter &e : area->m_spotEncounterList) + e.spotList.clear(); - // free all the HidingSpots - for (auto spot : TheHidingSpotList) - delete spot; + TheCSBots()->OnDestroyNavDataNotify(NAV_NOTIFY_DESTROY_SPOT_ENCOUNTER, area); + area->m_spotEncounterList.clear(); + } - TheHidingSpotList.clear(); + HidingSpot::m_nextID = 0; } // For use when loading from a file @@ -249,6 +261,9 @@ CNavArea::CNavArea(CNavNode *nwNode, class CNavNode *neNode, class CNavNode *seN // Destructor CNavArea::~CNavArea() { + // tell all bots that this area no longer exists + TheCSBots()->OnDestroyNavDataNotify(NAV_NOTIFY_DESTROY_AREA, this); + // if we are resetting the system, don't bother cleaning up - all areas are being destroyed if (m_isReset) return; @@ -344,6 +359,7 @@ void CNavArea::FinishMerge(CNavArea *adjArea) // remove subsumed adjacent area TheNavAreaList.remove(adjArea); + TheCSBots()->OnDestroyNavDataNotify(NAV_NOTIFY_DESTROY_AREA, this); delete adjArea; } @@ -536,6 +552,7 @@ bool CNavArea::SplitEdit(bool splitAlongX, float splitEdge, CNavArea **outAlpha, // remove original area TheNavAreaList.remove(this); + TheCSBots()->OnDestroyNavDataNotify(NAV_NOTIFY_DESTROY_AREA, this); delete this; return true; @@ -868,6 +885,7 @@ bool CNavArea::MergeEdit(CNavArea *adj) // remove subsumed adjacent area TheNavAreaList.remove(adj); + TheCSBots()->OnDestroyNavDataNotify(NAV_NOTIFY_DESTROY_AREA, adj); delete adj; return true; @@ -900,6 +918,9 @@ void DestroyNavigationMap() { CNavArea::m_isReset = true; + // destroy all hiding spots + DestroyHidingSpots(); + // remove each element of the list and delete them while (!TheNavAreaList.empty()) { @@ -913,8 +934,8 @@ void DestroyNavigationMap() // destroy ladder representations DestroyLadders(); - // destroy all hiding spots - DestroyHidingSpots(); + // cleanup from previous analysis + CleanupApproachAreaAnalysisPrep(); // destroy navigation nodes created during map learning CNavNode *node, *next; @@ -2828,6 +2849,22 @@ SpotEncounter *CNavArea::GetSpotEncounter(const CNavArea *from, const CNavArea * return nullptr; } +// Checks if a SpotEncounter is present in the list of encounters for the given CNavArea +bool CNavArea::HasSpotEncounter(const SpotEncounter *encounter) +{ + SpotEncounter *e; + + for (SpotEncounterList::iterator iter = m_spotEncounterList.begin(); iter != m_spotEncounterList.end(); iter++) + { + e = &(*iter); + + if (e == encounter) + return true; + } + + return false; +} + // Add spot encounter data when moving from area to area void CNavArea::AddSpotEncounters(const class CNavArea *from, NavDirType fromDir, const CNavArea *to, NavDirType toDir) { @@ -3968,6 +4005,7 @@ void EditNavAreas(NavEditCmdType cmd) case EDIT_DELETE: EMIT_SOUND_DYN(ENT(pLocalPlayer->pev), CHAN_ITEM, "buttons/blip1.wav", 1, ATTN_NORM, 0, 100); TheNavAreaList.remove(area); + TheCSBots()->OnDestroyNavDataNotify(NAV_NOTIFY_DESTROY_AREA, area); delete area; return; case EDIT_ATTRIB_CROUCH: diff --git a/regamedll/game_shared/bot/nav_area.h b/regamedll/game_shared/bot/nav_area.h index 10eca2f85..2792cd3b6 100644 --- a/regamedll/game_shared/bot/nav_area.h +++ b/regamedll/game_shared/bot/nav_area.h @@ -273,6 +273,7 @@ class CNavArea void ComputeHidingSpots(); // analyze local area neighborhood to find "hiding spots" in this area - for map learning void ComputeSniperSpots(); // analyze local area neighborhood to find "sniper spots" in this area - for map learning + bool HasSpotEncounter(const SpotEncounter *encounter); SpotEncounter *GetSpotEncounter(const CNavArea *from, const CNavArea *to); // given the areas we are moving between, return the spots we will encounter void ComputeSpotEncounters(); // compute spot encounter data - for map learning diff --git a/regamedll/game_shared/bot/nav_file.cpp b/regamedll/game_shared/bot/nav_file.cpp index cf97f6f6a..cee5618e1 100644 --- a/regamedll/game_shared/bot/nav_file.cpp +++ b/regamedll/game_shared/bot/nav_file.cpp @@ -623,6 +623,13 @@ bool SaveNavigationMap(const char *filename) area->Save(fd, version); } + // Ensure that all data is flushed to disk +#ifdef WIN32 + _commit(fd); +#else + fsync(fd); +#endif + _close(fd); return true; } diff --git a/regamedll/msvc/ReGameDLL.vcxproj b/regamedll/msvc/ReGameDLL.vcxproj index f33cfa3dc..80e93c922 100644 --- a/regamedll/msvc/ReGameDLL.vcxproj +++ b/regamedll/msvc/ReGameDLL.vcxproj @@ -932,7 +932,7 @@ Disabled true REGAMEDLL_ADD;REGAMEDLL_API;REGAMEDLL_FIXES;REGAMEDLL_SSE;REGAMEDLL_SELF;REGAMEDLL_CHECKS;UNICODE_FIXES;BUILD_LATEST;BUILD_LATEST_FIXES;CLIENT_WEAPONS;USE_QSTRING;_CRT_SECURE_NO_WARNINGS;_DEBUG;%(PreprocessorDefinitions) - Fast + Precise /arch:IA32 %(AdditionalOptions) /Zc:threadSafeInit- %(AdditionalOptions) MultiThreadedDebug @@ -969,7 +969,7 @@ Full true REGAMEDLL_ADD;REGAMEDLL_API;REGAMEDLL_FIXES;REGAMEDLL_SSE;REGAMEDLL_SELF;REGAMEDLL_CHECKS;UNICODE_FIXES;BUILD_LATEST;BUILD_LATEST_FIXES;CLIENT_WEAPONS;USE_QSTRING;_CRT_SECURE_NO_WARNINGS;NDEBUG;%(PreprocessorDefinitions) - Fast + Precise /arch:IA32 %(AdditionalOptions) /Zc:threadSafeInit- %(AdditionalOptions) MultiThreaded @@ -1102,6 +1102,7 @@ Use precompiled.h NoExtensions + Precise true From 35082b5f26a7b8d34483f6f28b85539ec86fa916 Mon Sep 17 00:00:00 2001 From: s1lentq Date: Fri, 4 Apr 2025 02:42:29 +0700 Subject: [PATCH 37/46] fix build.sh for clang compiler --- build.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build.sh b/build.sh index 876b458da..6dbfad242 100755 --- a/build.sh +++ b/build.sh @@ -33,7 +33,7 @@ main() case "$C" in ("intel"|"icc") CC=icc CXX=icpc ;; ("gcc"|"g++") CC=gcc CXX=g++ ;; - ("clang|llvm") CC=clang CXX=clang++ ;; + ("clang"|"llvm") CC=clang CXX=clang++ ;; *) ;; esac From a4d74392f05a1ab4cf2d06ab90a9faebd9d6af7d Mon Sep 17 00:00:00 2001 From: s1lentq Date: Fri, 4 Apr 2025 02:49:40 +0700 Subject: [PATCH 38/46] Update player's HUD after round restart time expires, not before it --- regamedll/dlls/multiplay_gamerules.cpp | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/regamedll/dlls/multiplay_gamerules.cpp b/regamedll/dlls/multiplay_gamerules.cpp index 1ba7122be..17b166a4d 100644 --- a/regamedll/dlls/multiplay_gamerules.cpp +++ b/regamedll/dlls/multiplay_gamerules.cpp @@ -1817,6 +1817,11 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(RestartRound)() if (!UTIL_IsValidPlayer(pPlayer)) continue; +#ifdef REGAMEDLL_FIXES + if (!pPlayer->IsBot()) + pPlayer->ForceClientDllUpdate(); +#endif + pPlayer->Reset(); } @@ -3246,19 +3251,6 @@ void CHalfLifeMultiplay::CareerRestart() } m_bSkipSpawn = false; - - for (int i = 1; i <= gpGlobals->maxClients; i++) - { - CBasePlayer *pPlayer = UTIL_PlayerByIndex(i); - - if (!UTIL_IsValidPlayer(pPlayer)) - continue; - - if (!pPlayer->IsBot()) - { - pPlayer->ForceClientDllUpdate(); - } - } } BOOL CHalfLifeMultiplay::IsMultiplayer() From f3d8d1b5fd2e9f34adb0a0cdf8bb34132fc9ea4e Mon Sep 17 00:00:00 2001 From: s1lentq Date: Fri, 4 Apr 2025 08:24:33 +0700 Subject: [PATCH 39/46] fix typo --- regamedll/dlls/bot/cs_bot.cpp | 2 +- regamedll/dlls/bot/cs_bot_manager.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/regamedll/dlls/bot/cs_bot.cpp b/regamedll/dlls/bot/cs_bot.cpp index b89a69126..2302e4611 100644 --- a/regamedll/dlls/bot/cs_bot.cpp +++ b/regamedll/dlls/bot/cs_bot.cpp @@ -941,7 +941,7 @@ void CCSBot::RemovePath(CNavArea *area) void CCSBot::RemoveHidingSpot(HidingSpot *spot) { int i = 0; - while (i < m_pathLength) + while (i < m_checkedHidingSpotCount) { if (m_checkedHidingSpot[i].spot == spot) { diff --git a/regamedll/dlls/bot/cs_bot_manager.cpp b/regamedll/dlls/bot/cs_bot_manager.cpp index 15fc3de24..8c7c7a1fc 100644 --- a/regamedll/dlls/bot/cs_bot_manager.cpp +++ b/regamedll/dlls/bot/cs_bot_manager.cpp @@ -1535,7 +1535,7 @@ void CCSBotManager::OnDestroyNavDataNotify(NavNotifyDestroyType navNotifyType, v // and triggers a game restart after the analysis is completed void CCSBotManager::AnalysisCompleted() { - // Ensure that all bots are no longer involved in map analysis and start their normal process + // Ensure that all bots are no longer involved in map analysis and start their normal process for (int i = 1; i <= gpGlobals->maxClients; i++) { CBasePlayer *pPlayer = UTIL_PlayerByIndex(i); @@ -1554,10 +1554,10 @@ void CCSBotManager::AnalysisCompleted() m_isMapDataLoaded = false; m_isAnalysisRequested = false; - // Try to reload the navigation map from the file + // Try to reload the navigation map from the file if (LoadNavigationMap()) { - // Initiate a game restart in 3 seconds + // Initiate a game restart in 3 seconds CVAR_SET_FLOAT("sv_restart", 3); } } From 0fc5213049d5ce2bb262acfc73f681203b56a1b1 Mon Sep 17 00:00:00 2001 From: GLoOoccK <155241167+GLoOoccK@users.noreply.github.com> Date: Fri, 4 Apr 2025 12:47:40 -0300 Subject: [PATCH 40/46] Implements UpdateStatusBar Hook (#968) --- regamedll/dlls/API/CAPI_Impl.cpp | 1 + regamedll/dlls/API/CAPI_Impl.h | 6 ++++++ regamedll/dlls/player.cpp | 4 +++- regamedll/dlls/player.h | 1 + regamedll/public/regamedll/regamedll_api.h | 5 +++++ 5 files changed, 16 insertions(+), 1 deletion(-) diff --git a/regamedll/dlls/API/CAPI_Impl.cpp b/regamedll/dlls/API/CAPI_Impl.cpp index 41175c838..aebde38a1 100644 --- a/regamedll/dlls/API/CAPI_Impl.cpp +++ b/regamedll/dlls/API/CAPI_Impl.cpp @@ -336,6 +336,7 @@ GAMEHOOK_REGISTRY(CSGameRules_SendDeathMessage); GAMEHOOK_REGISTRY(CBasePlayer_PlayerDeathThink); GAMEHOOK_REGISTRY(CBasePlayer_Observer_Think); GAMEHOOK_REGISTRY(CBasePlayer_RemoveAllItems); +GAMEHOOK_REGISTRY(CBasePlayer_UpdateStatusBar); int CReGameApi::GetMajorVersion() { return REGAMEDLL_API_VERSION_MAJOR; diff --git a/regamedll/dlls/API/CAPI_Impl.h b/regamedll/dlls/API/CAPI_Impl.h index 2635be5b9..a9c89e99e 100644 --- a/regamedll/dlls/API/CAPI_Impl.h +++ b/regamedll/dlls/API/CAPI_Impl.h @@ -749,6 +749,10 @@ typedef IHookChainRegistryClassImpl CReGameHookRegistry_CBase typedef IHookChainClassImpl CReGameHook_CBasePlayer_RemoveAllItems; typedef IHookChainRegistryClassImpl CReGameHookRegistry_CBasePlayer_RemoveAllItems; +// CBasePlayer::UpdateStatusBar hook +typedef IHookChainClassImpl CReGameHook_CBasePlayer_UpdateStatusBar; +typedef IHookChainRegistryClassImpl CReGameHookRegistry_CBasePlayer_UpdateStatusBar; + class CReGameHookchains: public IReGameHookchains { public: // CBasePlayer virtual @@ -910,6 +914,7 @@ class CReGameHookchains: public IReGameHookchains { CReGameHookRegistry_CBasePlayer_PlayerDeathThink m_CBasePlayer_PlayerDeathThink; CReGameHookRegistry_CBasePlayer_Observer_Think m_CBasePlayer_Observer_Think; CReGameHookRegistry_CBasePlayer_RemoveAllItems m_CBasePlayer_RemoveAllItems; + CReGameHookRegistry_CBasePlayer_UpdateStatusBar m_CBasePlayer_UpdateStatusBar; public: virtual IReGameHookRegistry_CBasePlayer_Spawn *CBasePlayer_Spawn(); @@ -1070,6 +1075,7 @@ class CReGameHookchains: public IReGameHookchains { virtual IReGameHookRegistry_CBasePlayer_PlayerDeathThink *CBasePlayer_PlayerDeathThink(); virtual IReGameHookRegistry_CBasePlayer_Observer_Think *CBasePlayer_Observer_Think(); virtual IReGameHookRegistry_CBasePlayer_RemoveAllItems *CBasePlayer_RemoveAllItems(); + virtual IReGameHookRegistry_CBasePlayer_UpdateStatusBar *CBasePlayer_UpdateStatusBar(); }; extern CReGameHookchains g_ReGameHookchains; diff --git a/regamedll/dlls/player.cpp b/regamedll/dlls/player.cpp index 1f096d13b..34b482239 100644 --- a/regamedll/dlls/player.cpp +++ b/regamedll/dlls/player.cpp @@ -8166,7 +8166,9 @@ void CBasePlayer::InitStatusBar() m_SbarString0[0] = '\0'; } -void CBasePlayer::UpdateStatusBar() +LINK_HOOK_CLASS_VOID_CHAIN2(CBasePlayer, UpdateStatusBar) + +void EXT_FUNC CBasePlayer::__API_HOOK(UpdateStatusBar)() { int newSBarState[SBAR_END]; char sbuf0[MAX_SBAR_STRING]; diff --git a/regamedll/dlls/player.h b/regamedll/dlls/player.h index 6890d30b8..78293ed94 100644 --- a/regamedll/dlls/player.h +++ b/regamedll/dlls/player.h @@ -450,6 +450,7 @@ class CBasePlayer: public CBaseMonster { void PlayerDeathThink_OrigFunc(); void Observer_Think_OrigFunc(); void RemoveAllItems_OrigFunc(BOOL removeSuit); + void UpdateStatusBar_OrigFunc(); CCSPlayer *CSPlayer() const; #endif // REGAMEDLL_API diff --git a/regamedll/public/regamedll/regamedll_api.h b/regamedll/public/regamedll/regamedll_api.h index 74879aa42..4bb6462bd 100644 --- a/regamedll/public/regamedll/regamedll_api.h +++ b/regamedll/public/regamedll/regamedll_api.h @@ -628,6 +628,10 @@ typedef IHookChainRegistryClass IReGameHookRegistry_CBa typedef IHookChainClass IReGameHook_CBasePlayer_RemoveAllItems; typedef IHookChainRegistryClass IReGameHookRegistry_CBasePlayer_RemoveAllItems; +// CBasePlayer::UpdateStatusBar hook +typedef IHookChainClass IReGameHook_CBasePlayer_UpdateStatusBar; +typedef IHookChainRegistryClass IReGameHookRegistry_CBasePlayer_UpdateStatusBar; + class IReGameHookchains { public: virtual ~IReGameHookchains() {} @@ -790,6 +794,7 @@ class IReGameHookchains { virtual IReGameHookRegistry_CBasePlayer_PlayerDeathThink *CBasePlayer_PlayerDeathThink() = 0; virtual IReGameHookRegistry_CBasePlayer_Observer_Think *CBasePlayer_Observer_Think() = 0; virtual IReGameHookRegistry_CBasePlayer_RemoveAllItems *CBasePlayer_RemoveAllItems() = 0; + virtual IReGameHookRegistry_CBasePlayer_UpdateStatusBar *CBasePlayer_UpdateStatusBar() = 0; }; struct ReGameFuncs_t { From 312dc3eb84ec58ea440420e4264baebd65b4d25c Mon Sep 17 00:00:00 2001 From: s1lentq Date: Sun, 6 Apr 2025 04:01:26 +0700 Subject: [PATCH 41/46] Fix defuse behavior when bomb explodes - Ensure DefuseBombEnd is called when defusing and bomb explodes to properly stop defuse - Fixes the issue where defuse progress bar continued draw after bomb explosion --- regamedll/dlls/ggrenade.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/regamedll/dlls/ggrenade.cpp b/regamedll/dlls/ggrenade.cpp index 41e92f27d..878355658 100644 --- a/regamedll/dlls/ggrenade.cpp +++ b/regamedll/dlls/ggrenade.cpp @@ -1170,6 +1170,12 @@ void CGrenade::Use(CBaseEntity *pActivator, CBaseEntity *pCaller, USE_TYPE useTy if (!m_bIsC4) return; +#ifdef REGAMEDLL_FIXES + // block the start of defuse if the bomb timer has expired + if (m_flC4Blow > 0 && gpGlobals->time >= m_flC4Blow) + return; +#endif + // TODO: We must be sure that the activator is a player. CBasePlayer *pPlayer = GetClassPtr((CBasePlayer *)pActivator->pev); @@ -1503,6 +1509,13 @@ void CGrenade::C4Think() { DefuseBombEnd(pPlayer, false); } +#ifdef REGAMEDLL_FIXES + // if the bomb timer has expired and defuse is still ongoing, stop the defuse + else if (gpGlobals->time >= m_flC4Blow) + { + DefuseBombEnd(pPlayer, false); + } +#endif } else { From 797c265db3f276d3976e0b00f0eac84ee4b39da9 Mon Sep 17 00:00:00 2001 From: Eason <62255465+jonathan-up@users.noreply.github.com> Date: Mon, 7 Apr 2025 02:13:23 +0800 Subject: [PATCH 42/46] API: Implemented CBasePlayer::Observer_FindNextPlayer() (#1065) --- regamedll/dlls/API/CSPlayer.cpp | 5 +++++ regamedll/public/regamedll/API/CSPlayer.h | 1 + regamedll/public/regamedll/regamedll_api.h | 2 +- regamedll/version/version.h | 2 +- 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/regamedll/dlls/API/CSPlayer.cpp b/regamedll/dlls/API/CSPlayer.cpp index 8ebf79306..2252b4164 100644 --- a/regamedll/dlls/API/CSPlayer.cpp +++ b/regamedll/dlls/API/CSPlayer.cpp @@ -412,6 +412,11 @@ EXT_FUNC void CCSPlayer::Observer_SetMode(int iMode) BasePlayer()->Observer_SetMode(iMode); } +EXT_FUNC void CCSPlayer::Observer_FindNextPlayer(bool bReverse, const char *name) +{ + BasePlayer()->Observer_FindNextPlayer(bReverse, name); +} + EXT_FUNC bool CCSPlayer::SelectSpawnSpot(const char *pEntClassName, CBaseEntity *&pSpot) { return BasePlayer()->SelectSpawnSpot(pEntClassName, pSpot); diff --git a/regamedll/public/regamedll/API/CSPlayer.h b/regamedll/public/regamedll/API/CSPlayer.h index 05b81b704..251cd6f56 100644 --- a/regamedll/public/regamedll/API/CSPlayer.h +++ b/regamedll/public/regamedll/API/CSPlayer.h @@ -117,6 +117,7 @@ class CCSPlayer: public CCSMonster { virtual void Reset(); virtual void OnSpawnEquip(bool addDefault = true, bool equipGame = true); virtual void SetScoreboardAttributes(CBasePlayer *destination = nullptr); + virtual void Observer_FindNextPlayer(bool bReverse, const char *name = nullptr); bool IsPlayerDominated(int iPlayerIndex) const; void SetPlayerDominated(CBasePlayer *pPlayer, bool bDominated); diff --git a/regamedll/public/regamedll/regamedll_api.h b/regamedll/public/regamedll/regamedll_api.h index 4bb6462bd..6b9aadd7e 100644 --- a/regamedll/public/regamedll/regamedll_api.h +++ b/regamedll/public/regamedll/regamedll_api.h @@ -38,7 +38,7 @@ #include #define REGAMEDLL_API_VERSION_MAJOR 5 -#define REGAMEDLL_API_VERSION_MINOR 28 +#define REGAMEDLL_API_VERSION_MINOR 29 // CBasePlayer::Spawn hook typedef IHookChainClass IReGameHook_CBasePlayer_Spawn; diff --git a/regamedll/version/version.h b/regamedll/version/version.h index 62c33001b..d3e8b9dbc 100644 --- a/regamedll/version/version.h +++ b/regamedll/version/version.h @@ -6,5 +6,5 @@ #pragma once #define VERSION_MAJOR 5 -#define VERSION_MINOR 28 +#define VERSION_MINOR 29 #define VERSION_MAINTENANCE 0 From 5bf71bdb18ec41aab1f48ab927151db9b6967207 Mon Sep 17 00:00:00 2001 From: s1lentq Date: Tue, 8 Apr 2025 06:31:12 +0700 Subject: [PATCH 43/46] CCSBot::FindMostDangerousThreat: Fix crash when m_pActiveItem is null Related #1055 --- regamedll/dlls/bot/cs_bot_vision.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/regamedll/dlls/bot/cs_bot_vision.cpp b/regamedll/dlls/bot/cs_bot_vision.cpp index 56f75678e..5e4e30264 100644 --- a/regamedll/dlls/bot/cs_bot_vision.cpp +++ b/regamedll/dlls/bot/cs_bot_vision.cpp @@ -797,7 +797,9 @@ CBasePlayer *CCSBot::FindMostDangerousThreat() float distSq = d.LengthSquared(); #ifdef REGAMEDLL_ADD - if (isSniperRifle(pPlayer->m_pActiveItem)) { + CBasePlayerWeapon *pCurrentWeapon = static_cast(pPlayer->m_pActiveItem); + if (pCurrentWeapon && isSniperRifle(pCurrentWeapon)) + { m_isEnemySniperVisible = true; if (sniperThreat) { From 99d93ba8a74ac777fbb173c928bcda87e04477c2 Mon Sep 17 00:00:00 2001 From: s1lentq Date: Thu, 17 Apr 2025 04:59:11 +0700 Subject: [PATCH 44/46] Fix crash nav generation with impossibly-large grid --- regamedll/game_shared/bot/nav_area.cpp | 13 +++++++++++++ regamedll/game_shared/bot/nav_file.cpp | 5 +++++ 2 files changed, 18 insertions(+) diff --git a/regamedll/game_shared/bot/nav_area.cpp b/regamedll/game_shared/bot/nav_area.cpp index a5f8f748f..845b2a3fd 100644 --- a/regamedll/game_shared/bot/nav_area.cpp +++ b/regamedll/game_shared/bot/nav_area.cpp @@ -1793,6 +1793,13 @@ void GenerateNavigationAreaMesh() break; } + if (!TheNavAreaList.size()) + { + // If we somehow have no areas, don't try to create an impossibly-large grid + TheNavAreaGrid.Initialize(0, 0, 0, 0); + return; + } + Extent extent; extent.lo.x = 9999999999.9f; extent.lo.y = 9999999999.9f; @@ -4674,6 +4681,12 @@ void CNavAreaGrid::Initialize(float minX, float maxX, float minY, float maxY) // Add an area to the grid void CNavAreaGrid::AddNavArea(CNavArea *area) { + if (!m_grid) + { + // If we somehow have no grid (manually creating a nav area without loading or generating a mesh), don't crash + TheNavAreaGrid.Initialize(0, 0, 0, 0); + } + // add to grid const Extent *extent = area->GetExtent(); diff --git a/regamedll/game_shared/bot/nav_file.cpp b/regamedll/game_shared/bot/nav_file.cpp index cee5618e1..e43a0200e 100644 --- a/regamedll/game_shared/bot/nav_file.cpp +++ b/regamedll/game_shared/bot/nav_file.cpp @@ -846,6 +846,11 @@ NavErrorType LoadNavigationMap() unsigned int count; result = navFile.Read(&count, sizeof(unsigned int)); + if (count == 0) + { + return NAV_INVALID_FILE; + } + Extent extent; extent.lo.x = 9999999999.9f; extent.lo.y = 9999999999.9f; From a4f48f4e425c2a36485fdcd78e7aacebb415c027 Mon Sep 17 00:00:00 2001 From: GLoOoccK <155241167+GLoOoccK@users.noreply.github.com> Date: Sun, 20 Apr 2025 11:13:08 -0300 Subject: [PATCH 45/46] `FIX`: Remove grenades and C4 (#1066) --- regamedll/dlls/multiplay_gamerules.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/regamedll/dlls/multiplay_gamerules.cpp b/regamedll/dlls/multiplay_gamerules.cpp index 17b166a4d..2b91a50f5 100644 --- a/regamedll/dlls/multiplay_gamerules.cpp +++ b/regamedll/dlls/multiplay_gamerules.cpp @@ -656,8 +656,7 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(CleanUpMap)() #endif // Remove grenades and C4 - const int grenadesRemoveCount = 20; - UTIL_RemoveOther("grenade", grenadesRemoveCount); + UTIL_RemoveOther("grenade"); #ifndef REGAMEDLL_FIXES // Remove defuse kit From 8d5aa54cebe8ab08ad345d9146c85b30dbc2bde6 Mon Sep 17 00:00:00 2001 From: GLoOoccK <155241167+GLoOoccK@users.noreply.github.com> Date: Sun, 20 Apr 2025 11:32:49 -0300 Subject: [PATCH 46/46] API: Knockback (#1069) --- README.md | 1 + dist/game.cfg | 7 +++++++ regamedll/dlls/API/CAPI_Impl.cpp | 1 + regamedll/dlls/API/CAPI_Impl.h | 6 ++++++ regamedll/dlls/API/CSPlayer.cpp | 5 +++++ regamedll/dlls/game.cpp | 4 ++++ regamedll/dlls/game.h | 1 + regamedll/dlls/player.cpp | 22 ++++++++++++++++++---- regamedll/dlls/player.h | 2 ++ regamedll/public/regamedll/API/CSPlayer.h | 1 + regamedll/public/regamedll/regamedll_api.h | 7 ++++++- regamedll/version/version.h | 2 +- 12 files changed, 53 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index b39c0f196..a1198f080 100644 --- a/README.md +++ b/README.md @@ -132,6 +132,7 @@ This means that plugins that do binary code analysis (Orpheu for example) probab | mp_randomspawn | 0 | 0 | 1 | Random player spawns
`0` disabled
`1` enabled
`NOTE`: Navigation `maps/.nav` file required | | mp_playerid_showhealth | 1 | 0 | 2 | Player ID display mode.
`0` don't show health
`1` show health for teammates only (default CS behaviour)
`2` show health for all players | | mp_playerid_field | 3 | 0 | 3 | Player ID field display mode.
`0` don't show additional information
`1` show team name
`2` show health percentage
`3` show both team name and health percentage | +| mp_knockback | 170 | - | - | Knockback force applied to the victim when damaged by strong weapons (e.g. `AWP`, `AK47`).
Works only if not crouching, and not hit in the legs.
Set to `0` to disable. | diff --git a/dist/game.cfg b/dist/game.cfg index 70bd646b3..f566ee9ba 100644 --- a/dist/game.cfg +++ b/dist/game.cfg @@ -680,3 +680,10 @@ mp_playerid_showhealth "1" // // Default value: "3" mp_playerid_field "3" + +// Knockback force applied to the victim when damaged by strong weapons (e.g. AWP, AK47). +// Works only if not crouching, and not hit in the legs. +// Set to "0" to disable. +// +// Default: "170" +mp_knockback "170" diff --git a/regamedll/dlls/API/CAPI_Impl.cpp b/regamedll/dlls/API/CAPI_Impl.cpp index aebde38a1..55da8ae34 100644 --- a/regamedll/dlls/API/CAPI_Impl.cpp +++ b/regamedll/dlls/API/CAPI_Impl.cpp @@ -337,6 +337,7 @@ GAMEHOOK_REGISTRY(CBasePlayer_PlayerDeathThink); GAMEHOOK_REGISTRY(CBasePlayer_Observer_Think); GAMEHOOK_REGISTRY(CBasePlayer_RemoveAllItems); GAMEHOOK_REGISTRY(CBasePlayer_UpdateStatusBar); +GAMEHOOK_REGISTRY(CBasePlayer_TakeDamageImpulse); int CReGameApi::GetMajorVersion() { return REGAMEDLL_API_VERSION_MAJOR; diff --git a/regamedll/dlls/API/CAPI_Impl.h b/regamedll/dlls/API/CAPI_Impl.h index a9c89e99e..727fdf9e4 100644 --- a/regamedll/dlls/API/CAPI_Impl.h +++ b/regamedll/dlls/API/CAPI_Impl.h @@ -753,6 +753,10 @@ typedef IHookChainRegistryClassImpl CReGameHookRegistry typedef IHookChainClassImpl CReGameHook_CBasePlayer_UpdateStatusBar; typedef IHookChainRegistryClassImpl CReGameHookRegistry_CBasePlayer_UpdateStatusBar; +// CBasePlayer::TakeDamageImpulse hook +typedef IHookChainClassImpl CReGameHook_CBasePlayer_TakeDamageImpulse; +typedef IHookChainRegistryClassImpl CReGameHookRegistry_CBasePlayer_TakeDamageImpulse; + class CReGameHookchains: public IReGameHookchains { public: // CBasePlayer virtual @@ -915,6 +919,7 @@ class CReGameHookchains: public IReGameHookchains { CReGameHookRegistry_CBasePlayer_Observer_Think m_CBasePlayer_Observer_Think; CReGameHookRegistry_CBasePlayer_RemoveAllItems m_CBasePlayer_RemoveAllItems; CReGameHookRegistry_CBasePlayer_UpdateStatusBar m_CBasePlayer_UpdateStatusBar; + CReGameHookRegistry_CBasePlayer_TakeDamageImpulse m_CBasePlayer_TakeDamageImpulse; public: virtual IReGameHookRegistry_CBasePlayer_Spawn *CBasePlayer_Spawn(); @@ -1076,6 +1081,7 @@ class CReGameHookchains: public IReGameHookchains { virtual IReGameHookRegistry_CBasePlayer_Observer_Think *CBasePlayer_Observer_Think(); virtual IReGameHookRegistry_CBasePlayer_RemoveAllItems *CBasePlayer_RemoveAllItems(); virtual IReGameHookRegistry_CBasePlayer_UpdateStatusBar *CBasePlayer_UpdateStatusBar(); + virtual IReGameHookRegistry_CBasePlayer_TakeDamageImpulse *CBasePlayer_TakeDamageImpulse(); }; extern CReGameHookchains g_ReGameHookchains; diff --git a/regamedll/dlls/API/CSPlayer.cpp b/regamedll/dlls/API/CSPlayer.cpp index 2252b4164..cab27a473 100644 --- a/regamedll/dlls/API/CSPlayer.cpp +++ b/regamedll/dlls/API/CSPlayer.cpp @@ -539,6 +539,11 @@ EXT_FUNC bool CCSPlayer::CheckActivityInGame() return (fabs(deltaYaw) >= 0.1f && fabs(deltaPitch) >= 0.1f); } +EXT_FUNC void CCSPlayer::TakeDamageImpulse(CBasePlayer *pAttacker, float flKnockbackForce, float flVelModifier) +{ + BasePlayer()->TakeDamageImpulse(pAttacker, flKnockbackForce, flVelModifier); +} + void CCSPlayer::ResetVars() { m_szModel[0] = '\0'; diff --git a/regamedll/dlls/game.cpp b/regamedll/dlls/game.cpp index a022348ee..2c6d9fbff 100644 --- a/regamedll/dlls/game.cpp +++ b/regamedll/dlls/game.cpp @@ -199,6 +199,8 @@ cvar_t randomspawn = { "mp_randomspawn", "0", FCVAR_SERVER, 0.0f, nu cvar_t playerid_showhealth = { "mp_playerid_showhealth", "1", 0, 1.0f, nullptr }; cvar_t playerid_field = { "mp_playerid_field", "3", 0, 3.0f, nullptr }; +cvar_t knockback = { "mp_knockback", "170", 0, 170.0f, nullptr }; + void GameDLL_Version_f() { if (Q_stricmp(CMD_ARGV(1), "version") != 0) @@ -485,6 +487,8 @@ void EXT_FUNC GameDLLInit() CVAR_REGISTER(&flymove_method); + CVAR_REGISTER(&knockback); + // print version CONSOLE_ECHO("ReGameDLL version: " APP_VERSION "\n"); diff --git a/regamedll/dlls/game.h b/regamedll/dlls/game.h index 95609f123..ecf1001c8 100644 --- a/regamedll/dlls/game.h +++ b/regamedll/dlls/game.h @@ -216,6 +216,7 @@ extern cvar_t logkills; extern cvar_t randomspawn; extern cvar_t playerid_showhealth; extern cvar_t playerid_field; +extern cvar_t knockback; #endif diff --git a/regamedll/dlls/player.cpp b/regamedll/dlls/player.cpp index 34b482239..67aa43e47 100644 --- a/regamedll/dlls/player.cpp +++ b/regamedll/dlls/player.cpp @@ -1233,7 +1233,7 @@ BOOL EXT_FUNC CBasePlayer::__API_HOOK(TakeDamage)(entvars_t *pevInflictor, entva if (!ShouldDoLargeFlinch(m_LastHitGroup, iGunType)) { - m_flVelocityModifier = 0.5f; + TakeDamageImpulse(pAttack, 0.0f, 0.5f); if (m_LastHitGroup == HITGROUP_HEAD) m_bHighDamage = (flDamage > 60); @@ -1246,10 +1246,13 @@ BOOL EXT_FUNC CBasePlayer::__API_HOOK(TakeDamage)(entvars_t *pevInflictor, entva { if (pev->velocity.Length() < 300) { - Vector attack_velocity = (pev->origin - pAttack->pev->origin).Normalize() * 170; - pev->velocity = pev->velocity + attack_velocity; +#ifdef REGAMEDLL_ADD + float knockbackValue = knockback.value; +#else + float knockbackValue = 170; +#endif - m_flVelocityModifier = 0.65f; + TakeDamageImpulse(pAttack, knockbackValue, 0.65f); } SetAnimation(PLAYER_LARGE_FLINCH); @@ -10867,6 +10870,17 @@ bool CBasePlayer::Kill() return true; } +LINK_HOOK_CLASS_VOID_CHAIN(CBasePlayer, TakeDamageImpulse, (CBasePlayer *pAttacker, float flKnockbackForce, float flVelModifier), pAttacker, flKnockbackForce, flVelModifier) + +void EXT_FUNC CBasePlayer::__API_HOOK(TakeDamageImpulse)(CBasePlayer *pAttacker, float flKnockbackForce, float flVelModifier) +{ + if (flKnockbackForce != 0.0f) + pev->velocity += (pev->origin - pAttacker->pev->origin).Normalize() * flKnockbackForce; + + if (flVelModifier != 0.0f) + m_flVelocityModifier = flVelModifier; +} + const usercmd_t *CBasePlayer::GetLastUserCommand() const { #ifdef REGAMEDLL_API diff --git a/regamedll/dlls/player.h b/regamedll/dlls/player.h index 78293ed94..f3ec649c3 100644 --- a/regamedll/dlls/player.h +++ b/regamedll/dlls/player.h @@ -451,6 +451,7 @@ class CBasePlayer: public CBaseMonster { void Observer_Think_OrigFunc(); void RemoveAllItems_OrigFunc(BOOL removeSuit); void UpdateStatusBar_OrigFunc(); + void TakeDamageImpulse_OrigFunc(CBasePlayer *pAttacker, float flKnockbackForce, float flVelModifier); CCSPlayer *CSPlayer() const; #endif // REGAMEDLL_API @@ -659,6 +660,7 @@ class CBasePlayer: public CBaseMonster { void UseEmpty(); void DropIdlePlayer(const char *reason); bool Kill(); + void TakeDamageImpulse(CBasePlayer *pAttacker, float flKnockbackForce, float flVelModifier); // templates template diff --git a/regamedll/public/regamedll/API/CSPlayer.h b/regamedll/public/regamedll/API/CSPlayer.h index 251cd6f56..3ead37a22 100644 --- a/regamedll/public/regamedll/API/CSPlayer.h +++ b/regamedll/public/regamedll/API/CSPlayer.h @@ -118,6 +118,7 @@ class CCSPlayer: public CCSMonster { virtual void OnSpawnEquip(bool addDefault = true, bool equipGame = true); virtual void SetScoreboardAttributes(CBasePlayer *destination = nullptr); virtual void Observer_FindNextPlayer(bool bReverse, const char *name = nullptr); + virtual void TakeDamageImpulse(CBasePlayer *pAttacker, float flKnockbackForce, float flVelModifier); bool IsPlayerDominated(int iPlayerIndex) const; void SetPlayerDominated(CBasePlayer *pPlayer, bool bDominated); diff --git a/regamedll/public/regamedll/regamedll_api.h b/regamedll/public/regamedll/regamedll_api.h index 6b9aadd7e..fda245bce 100644 --- a/regamedll/public/regamedll/regamedll_api.h +++ b/regamedll/public/regamedll/regamedll_api.h @@ -38,7 +38,7 @@ #include #define REGAMEDLL_API_VERSION_MAJOR 5 -#define REGAMEDLL_API_VERSION_MINOR 29 +#define REGAMEDLL_API_VERSION_MINOR 30 // CBasePlayer::Spawn hook typedef IHookChainClass IReGameHook_CBasePlayer_Spawn; @@ -632,6 +632,10 @@ typedef IHookChainRegistryClass IReGameHookRegist typedef IHookChainClass IReGameHook_CBasePlayer_UpdateStatusBar; typedef IHookChainRegistryClass IReGameHookRegistry_CBasePlayer_UpdateStatusBar; +// CBasePlayer::TakeDamageImpulse hook +typedef IHookChainClass IReGameHook_CBasePlayer_TakeDamageImpulse; +typedef IHookChainRegistryClass IReGameHookRegistry_CBasePlayer_TakeDamageImpulse; + class IReGameHookchains { public: virtual ~IReGameHookchains() {} @@ -795,6 +799,7 @@ class IReGameHookchains { virtual IReGameHookRegistry_CBasePlayer_Observer_Think *CBasePlayer_Observer_Think() = 0; virtual IReGameHookRegistry_CBasePlayer_RemoveAllItems *CBasePlayer_RemoveAllItems() = 0; virtual IReGameHookRegistry_CBasePlayer_UpdateStatusBar *CBasePlayer_UpdateStatusBar() = 0; + virtual IReGameHookRegistry_CBasePlayer_TakeDamageImpulse *CBasePlayer_TakeDamageImpulse() = 0; }; struct ReGameFuncs_t { diff --git a/regamedll/version/version.h b/regamedll/version/version.h index d3e8b9dbc..3838a2f84 100644 --- a/regamedll/version/version.h +++ b/regamedll/version/version.h @@ -6,5 +6,5 @@ #pragma once #define VERSION_MAJOR 5 -#define VERSION_MINOR 29 +#define VERSION_MINOR 30 #define VERSION_MAINTENANCE 0