From d95d76d4fc6aa737b944cba4a5afdd7a2ca38d57 Mon Sep 17 00:00:00 2001 From: Sergey Shorokhov Date: Wed, 13 Dec 2023 15:43:43 +0300 Subject: [PATCH] New ConVar: `mp_defuser_allocation` 0 - No free defusers (default behavior); 1 - Random players; 2 - All players; --- README.md | 1 + dist/game.cfg | 10 +++- regamedll/dlls/game.cpp | 2 + regamedll/dlls/game.h | 1 + regamedll/dlls/gamerules.h | 9 ++++ regamedll/dlls/multiplay_gamerules.cpp | 60 +++++++++++++++++++++++ regamedll/dlls/player.cpp | 3 ++ regamedll/public/utlvector.h | 68 ++++++++++++++++++++++++++ 8 files changed, 153 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ee928a928..69cf55670 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,7 @@ This means that plugins that do binary code analysis (Orpheu for example) probab | mp_assist_damage_threshold | 40 | 0 | 100 | Sets the percentage of damage needed to score an assist. | | mp_freezetime_duck | 1 | 0 | 1 | Allow players to duck during freezetime.
`0` disabled
`1` enabled | | mp_freezetime_jump | 1 | 0 | 1 | Allow players to jump during freezetime.
`0` disabled
`1` enabled | +| mp_defuser_allocation | 0 | 0 | 2 | Give defuser on player spawn.
`0` disabled
`1` Random players.
`2` All players. | ## How to install zBot for CS 1.6? diff --git a/dist/game.cfg b/dist/game.cfg index a1d77c205..e55ee60ab 100644 --- a/dist/game.cfg +++ b/dist/game.cfg @@ -566,4 +566,12 @@ mp_freezetime_duck "1" // 1 - enabled (default behaviour) // // Default value: "1" -mp_freezetime_jump "1" \ No newline at end of file +mp_freezetime_jump "1" + +// Give defuser on player spawn +// 0 - No free defusers (default behavior) +// 1 - Random players +// 2 - All players +// +// Default value: "0" +mp_defuser_allocation "0" diff --git a/regamedll/dlls/game.cpp b/regamedll/dlls/game.cpp index 55c2600c1..3706be2fa 100644 --- a/regamedll/dlls/game.cpp +++ b/regamedll/dlls/game.cpp @@ -177,6 +177,7 @@ cvar_t hostages_rescued_ratio = { "mp_hostages_rescued_ratio", "1.0", 0, 1.0f, n 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 }; void GameDLL_Version_f() { @@ -434,6 +435,7 @@ void EXT_FUNC GameDLLInit() CVAR_REGISTER(&freezetime_duck); CVAR_REGISTER(&freezetime_jump); + CVAR_REGISTER(&defuser_allocation); // print version CONSOLE_ECHO("ReGameDLL version: " APP_VERSION "\n"); diff --git a/regamedll/dlls/game.h b/regamedll/dlls/game.h index cff031fbb..706e1c2af 100644 --- a/regamedll/dlls/game.h +++ b/regamedll/dlls/game.h @@ -200,6 +200,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 defuser_allocation; #endif diff --git a/regamedll/dlls/gamerules.h b/regamedll/dlls/gamerules.h index e29aaba88..e7dc35085 100644 --- a/regamedll/dlls/gamerules.h +++ b/regamedll/dlls/gamerules.h @@ -255,6 +255,13 @@ enum KillRarity KILLRARITY_REVENGE = 0x100 // Revenge by the killer }; +enum +{ + DEFUSERALLOCATION_NONE = 0, + DEFUSERALLOCATION_RANDOM = 1, + DEFUSERALLOCATION_ALL = 2, +}; + class CItem; class CGameRules @@ -738,6 +745,8 @@ class CHalfLifeMultiplay: public CGameRules int GetRarityOfKill(CBaseEntity *pKiller, CBasePlayer *pVictim, CBasePlayer *pAssister, const char *killerWeaponName, bool bFlashAssist); CBasePlayer *CheckAssistsToKill(CBaseEntity *pKiller, CBasePlayer *pVictim, bool &bFlashAssist); + void GiveDefuserToRandomPlayer(); + private: void MarkLivingPlayersOnTeamAsNotReceivingMoneyNextRound(int iTeam); diff --git a/regamedll/dlls/multiplay_gamerules.cpp b/regamedll/dlls/multiplay_gamerules.cpp index 4f4899712..41dd7496a 100644 --- a/regamedll/dlls/multiplay_gamerules.cpp +++ b/regamedll/dlls/multiplay_gamerules.cpp @@ -2063,6 +2063,11 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(RestartRound)() GiveC4(); } +#ifdef REGAMEDLL_ADD + if (m_bMapHasBombTarget && (int)defuser_allocation.value == DEFUSERALLOCATION_RANDOM) + GiveDefuserToRandomPlayer(); +#endif + if (TheBots) { TheBots->OnEvent(EVENT_BUY_TIME_START); @@ -3837,6 +3842,10 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(PlayerSpawn)(CBasePlayer *pPlayer) #ifdef REGAMEDLL_ADD if (respawn_immunitytime.value > 0) pPlayer->SetSpawnProtection(respawn_immunitytime.value); + + // remove any defusers left over from previous random if there is just one random one + if ((int)defuser_allocation.value == DEFUSERALLOCATION_RANDOM) + pPlayer->RemoveDefuser(); #endif } @@ -5367,3 +5376,54 @@ void EXT_FUNC CHalfLifeMultiplay::__API_HOOK(SendDeathMessage)(CBaseEntity *pKil MESSAGE_END(); } + +void CHalfLifeMultiplay::GiveDefuserToRandomPlayer() +{ + int iDefusersToGive = 2; + CUtlVector candidates; + candidates.EnsureCapacity(MAX_CLIENTS); + + // add all CT candidates to a list + for (int i = 1; i <= gpGlobals->maxClients; i++) + { + CBasePlayer *pPlayer = UTIL_PlayerByIndex(i); + if (!pPlayer || FNullEnt(pPlayer->edict())) + continue; + + if (!pPlayer->IsAlive() || pPlayer->m_iTeam != CT) + continue; + + candidates.AddToTail(pPlayer); + } + + // randomly shuffle the list; this will keep the selection random in case of ties + for (int i = 0; i < candidates.Count(); i++) { + SWAP(candidates[i], candidates[RANDOM_LONG(0, candidates.Count() - 1)]); + } + + // now sort the shuffled list into subgroups + candidates.Sort([](CBasePlayer *const *left, CBasePlayer *const *right) -> int { + // should we prioritize humans over bots? + if (cv_bot_defer_to_human.value != 0.0f) + { + if ((*left)->IsBot() && !(*right)->IsBot()) + return 1; + + if (!(*left)->IsBot() && (*right)->IsBot()) + return -1; + } + + return 0; + } + ); + + // give defusers to the first N candidates + for ( int i = 0; i < iDefusersToGive && i < candidates.Count(); ++i ) + { + CBasePlayer *pPlayer = candidates[i]; + Assert( pPlayer && pPlayer->m_iTeam == CT && pPlayer->IsAlive() ); + + pPlayer->GiveDefuser(); + ClientPrint(pPlayer->pev, HUD_PRINTCENTER, "#Got_defuser"); + } +} diff --git a/regamedll/dlls/player.cpp b/regamedll/dlls/player.cpp index e2e185a62..d6b285123 100644 --- a/regamedll/dlls/player.cpp +++ b/regamedll/dlls/player.cpp @@ -10323,6 +10323,9 @@ void EXT_FUNC CBasePlayer::__API_HOOK(OnSpawnEquip)(bool addDefault, bool equipG case ARMOR_VESTHELM: GiveNamedItemEx("item_assaultsuit"); break; } } + + if ((int)defuser_allocation.value == DEFUSERALLOCATION_ALL) + GiveNamedItemEx("item_thighpack"); #endif } diff --git a/regamedll/public/utlvector.h b/regamedll/public/utlvector.h index 6dcd250f1..70ed79846 100644 --- a/regamedll/public/utlvector.h +++ b/regamedll/public/utlvector.h @@ -30,6 +30,8 @@ #include "utlmemory.h" +#include + template class CUtlVector { @@ -126,6 +128,20 @@ class CUtlVector // Set the size by which it grows when it needs to allocate more memory. void SetGrowSize(int size); + // sort using std:: and expecting a "<" function to be defined for the type + void Sort(); + void Sort(bool (*pfnLessFunc)(const T &src1, const T &src2)); + +#if defined(_WIN32) + void Sort(int (__cdecl *pfnCompare)(const T *, const T *)); +#else + void Sort(int (*pfnCompare)(const T *, const T *)); +#endif + + // sort using std:: with a predicate. e.g. [] -> bool (const T &a, const T &b) const { return a < b; } + template + void SortPredicate(F &&predicate); + protected: // Can't copy this unless we explicitly do it! CUtlVector(CUtlVector const &vec) { assert(0); } @@ -562,3 +578,55 @@ void CUtlVector::SetGrowSize(int size) { m_Memory.SetGrowSize(size); } + +// Sort methods +template +void CUtlVector::Sort() +{ + std::sort(Base(), Base() + Count()); +} + +template +void CUtlVector::Sort(bool (*pfnLessFunc)(const T &src1, const T &src2)) +{ + std::sort(Base(), Base() + Count(), + [pfnLessFunc](const T &a, const T &b) -> bool + { + if (&a == &b) + return false; + + return (*pfnLessFunc)(a, b); + }); +} + +#if defined(_WIN32) + +template +void CUtlVector::Sort(int (__cdecl *pfnCompare)(const T *, const T *)) +{ + typedef int (__cdecl *QSortCompareFunc_t)(const void *, const void *); + if (Count() <= 1) + return; + + qsort(Base(), Count(), sizeof(T), (QSortCompareFunc_t)(pfnCompare)); +} + +#else // #if defined(_LINUX) + +template +void CUtlVector::Sort(int (*pfnCompare)(const T *, const T *)) +{ + typedef int (*QSortCompareFunc_t)(const void *, const void *); + if (Count() <= 1) + return; + + qsort(Base(), Count(), sizeof(T), (QSortCompareFunc_t)(pfnCompare)); +} +#endif // #if defined(_LINUX) + +template +template +void CUtlVector::SortPredicate(F &&predicate) +{ + std::sort(Base(), Base() + Count(), predicate); +}