From 4c4e31b91cc893ddff73f82eabd966318e5474fa Mon Sep 17 00:00:00 2001 From: Vauff Date: Mon, 18 Nov 2024 02:21:56 -0500 Subject: [PATCH 01/11] Optimization/Fix compiler warning --- src/cs2fixes.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/cs2fixes.cpp b/src/cs2fixes.cpp index 4b6850856..06eae56dd 100644 --- a/src/cs2fixes.cpp +++ b/src/cs2fixes.cpp @@ -1009,9 +1009,9 @@ void CS2Fixes::Hook_PhysicsTouchShuffle(CUtlVector* pList, bool u pList->Purge(); - for (const auto link : touchingLinks) + for (const auto &link : touchingLinks) pList->AddToTail(link); - for (const auto link : unTouchLinks) + for (const auto &link : unTouchLinks) pList->AddToTail(link); } From e8cc02dbd3bb3bfd9ab6dfa33f759147501c4174 Mon Sep 17 00:00:00 2001 From: Vauff Date: Wed, 27 Nov 2024 16:12:55 -0500 Subject: [PATCH 02/11] Silence some console error logs --- src/adminsystem.cpp | 2 +- src/zombiereborn.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/adminsystem.cpp b/src/adminsystem.cpp index 0865455ae..c8fa07cb6 100644 --- a/src/adminsystem.cpp +++ b/src/adminsystem.cpp @@ -606,7 +606,7 @@ CON_COMMAND_CHAT_FLAGS(map, " - Change map", ADMFLAG_CHANGEMAP) // Check if input is numeric (workshop ID) // Not safe to expose to all admins until crashing on failed workshop addon downloads is fixed - if ((!player || player->GetZEPlayer()->IsAdminFlagSet(ADMFLAG_RCON)) && V_StringToUint64(pszMapName, 0) != 0) + if ((!player || player->GetZEPlayer()->IsAdminFlagSet(ADMFLAG_RCON)) && V_StringToUint64(pszMapName, 0, NULL, NULL, PARSING_FLAG_SKIP_WARNING) != 0) { sCommand = "host_workshop_map " + sMapName; } diff --git a/src/zombiereborn.cpp b/src/zombiereborn.cpp index ee69af5aa..9b5e22572 100644 --- a/src/zombiereborn.cpp +++ b/src/zombiereborn.cpp @@ -1881,7 +1881,7 @@ CON_COMMAND_CHAT(zclass, " - Find and select your Z: FOR_EACH_VEC(vecClasses, i) { const char* sClassName = vecClasses[i]->szClassName.c_str(); - bool bClassMatches = !V_stricmp(sClassName, args[1]) || (V_StringToInt32(args[1], -1) - 1) == i; + bool bClassMatches = !V_stricmp(sClassName, args[1]) || (V_StringToInt32(args[1], -1, NULL, NULL, PARSING_FLAG_SKIP_WARNING) - 1) == i; std::shared_ptr pClass = vecClasses[i]; if (bClassMatches) From 0058740f4f08fe80da43217426da63041f0ec763 Mon Sep 17 00:00:00 2001 From: Vauff Date: Fri, 6 Dec 2024 18:46:26 -0500 Subject: [PATCH 03/11] Fix bugged active weapon if a grenade was thrown right before infection --- gamedata/cs2fixes.games.txt | 5 +++++ src/cs2_sdk/entity/services.h | 6 ++++++ src/zombiereborn.cpp | 17 ++++++++++++++++- 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/gamedata/cs2fixes.games.txt b/gamedata/cs2fixes.games.txt index c4221bc9f..08d929887 100644 --- a/gamedata/cs2fixes.games.txt +++ b/gamedata/cs2fixes.games.txt @@ -465,6 +465,11 @@ "windows" "22" "linux" "23" } + "CCSPlayer_WeaponServices::SelectItem" + { + "windows" "24" + "linux" "25" + } "CCSGameRules_GoToIntermission" { "windows" "128" diff --git a/src/cs2_sdk/entity/services.h b/src/cs2_sdk/entity/services.h index 74825e61c..e198332e2 100644 --- a/src/cs2_sdk/entity/services.h +++ b/src/cs2_sdk/entity/services.h @@ -142,6 +142,12 @@ class CCSPlayer_WeaponServices : public CPlayer_WeaponServices static int offset = g_GameConfig->GetOffset("CCSPlayer_WeaponServices::DropWeapon"); CALL_VIRTUAL(void, offset, this, pWeapon, pVecTarget, pVelocity); } + + void SelectItem(CBasePlayerWeapon* pWeapon, int unk1 = 0) + { + static int offset = g_GameConfig->GetOffset("CCSPlayer_WeaponServices::SelectItem"); + CALL_VIRTUAL(void, offset, this, pWeapon, unk1); + } }; class CCSPlayerController_InGameMoneyServices diff --git a/src/zombiereborn.cpp b/src/zombiereborn.cpp index 9b5e22572..91283341b 100644 --- a/src/zombiereborn.cpp +++ b/src/zombiereborn.cpp @@ -1135,14 +1135,29 @@ void ZR_FakePlayerDeath(CCSPlayerController *pAttackerController, CCSPlayerContr void ZR_StripAndGiveKnife(CCSPlayerPawn *pPawn) { CCSPlayer_ItemServices *pItemServices = pPawn->m_pItemServices(); + CCSPlayer_WeaponServices* pWeaponServices = pPawn->m_pWeaponServices(); // it can sometimes be null when player joined on the very first round? - if (!pItemServices) + if (!pItemServices || !pWeaponServices) return; pPawn->DropMapWeapons(); pItemServices->StripPlayerWeapons(true); pItemServices->GiveNamedItem("weapon_knife"); + + CUtlVector>* weapons = pWeaponServices->m_hMyWeapons(); + + FOR_EACH_VEC(*weapons, i) + { + CBasePlayerWeapon* pWeapon = (*weapons)[i].Get(); + + if (pWeapon && pWeapon->GetWeaponVData()->m_GearSlot() == GEAR_SLOT_KNIFE) + { + // Normally this isn't necessary, but there's a small window if infected right after throwing a grenade where this is needed + pWeaponServices->SelectItem(pWeapon); + break; + } + } } void ZR_Cure(CCSPlayerController *pTargetController) From 7368bdda5f1b12a860f121509c418a3c6e9de366 Mon Sep 17 00:00:00 2001 From: Vauff Date: Sat, 7 Dec 2024 19:03:07 -0500 Subject: [PATCH 04/11] Fix zombie regen clamping health values above max health --- src/zombiereborn.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/zombiereborn.cpp b/src/zombiereborn.cpp index 91283341b..f9f878ca8 100644 --- a/src/zombiereborn.cpp +++ b/src/zombiereborn.cpp @@ -739,6 +739,10 @@ bool CZRRegenTimer::Execute() if (!pPawn || !pPawn->IsAlive()) return false; + // Do we even need to regen? + if (pPawn->m_iHealth() >= pPawn->m_iMaxHealth()) + return true; + int iHealth = pPawn->m_iHealth() + m_iRegenAmount; pPawn->m_iHealth = pPawn->m_iMaxHealth() < iHealth ? pPawn->m_iMaxHealth() : iHealth; return true; From b1a82d028344fa6159683fec56a16c6b4dacad53 Mon Sep 17 00:00:00 2001 From: Vauff Date: Sat, 7 Dec 2024 20:52:57 -0500 Subject: [PATCH 05/11] Stop transmitting flashlights in spec Seems like this can now cause random "missing client entity" client crashes --- src/cs2fixes.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/cs2fixes.cpp b/src/cs2fixes.cpp index 06eae56dd..8e51133d5 100644 --- a/src/cs2fixes.cpp +++ b/src/cs2fixes.cpp @@ -865,11 +865,10 @@ void CS2Fixes::Hook_CheckTransmit(CCheckTransmitInfo **ppInfoList, int infoCount if (!pController || pController->m_bIsHLTV || j == iPlayerSlot) continue; - // Don't transmit other players' flashlights, except the one they're watching if in spec + // Don't transmit other players' flashlights CBarnLight *pFlashLight = pController->IsConnected() ? g_playerManager->GetPlayer(j)->GetFlashLight() : nullptr; - if (!g_bFlashLightTransmitOthers && pFlashLight && - !(pSelfController->GetPawnState() == STATE_OBSERVER_MODE && pSelfController->GetObserverTarget() == pController->GetPawn())) + if (!g_bFlashLightTransmitOthers && pFlashLight) { pInfo->m_pTransmitEntity->Clear(pFlashLight->entindex()); } From b908ce67088971f72ccb7be62e5bdd95947e5762 Mon Sep 17 00:00:00 2001 From: Vauff Date: Mon, 9 Dec 2024 20:00:17 -0500 Subject: [PATCH 06/11] Make matchmaking bin available to gamedata --- src/addresses.cpp | 1 + src/addresses.h | 1 + src/gameconfig.cpp | 2 ++ 3 files changed, 4 insertions(+) diff --git a/src/addresses.cpp b/src/addresses.cpp index 1e98af94d..7cd60f7c5 100644 --- a/src/addresses.cpp +++ b/src/addresses.cpp @@ -40,6 +40,7 @@ bool addresses::Initialize(CGameConfig *g_GameConfig) modules::vscript = new CModule(ROOTBIN, "vscript"); modules::networksystem = new CModule(ROOTBIN, "networksystem"); modules::vphysics2 = new CModule(ROOTBIN, "vphysics2"); + modules::matchmaking = new CModule(GAMEBIN, "matchmaking"); modules::client = nullptr; if (!CommandLine()->HasParm("-dedicated")) diff --git a/src/addresses.h b/src/addresses.h index e53f9b703..f752fc1fa 100644 --- a/src/addresses.h +++ b/src/addresses.h @@ -34,6 +34,7 @@ namespace modules inline CModule *client; inline CModule* networksystem; inline CModule* vphysics2; + inline CModule* matchmaking; #ifdef _WIN32 inline CModule *hammer; #endif diff --git a/src/gameconfig.cpp b/src/gameconfig.cpp index f20db6e21..13203cbdb 100644 --- a/src/gameconfig.cpp +++ b/src/gameconfig.cpp @@ -129,6 +129,8 @@ CModule **CGameConfig::GetModule(const char *name) return &modules::tier0; else if (strcmp(library, "networksystem") == 0) return &modules::networksystem; + else if (strcmp(library, "matchmaking") == 0) + return &modules::matchmaking; #ifdef _WIN32 else if (strcmp(library, "hammer") == 0) return &modules::hammer; From 8cfd80eea5bc59886c0bd54592f9e23a84399339 Mon Sep 17 00:00:00 2001 From: Vauff Date: Fri, 13 Dec 2024 19:30:10 -0500 Subject: [PATCH 07/11] Switch to smart pointers for ZR weapons --- src/zombiereborn.cpp | 8 ++++---- src/zombiereborn.h | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/zombiereborn.cpp b/src/zombiereborn.cpp index f9f878ca8..4ee3f4a25 100644 --- a/src/zombiereborn.cpp +++ b/src/zombiereborn.cpp @@ -860,7 +860,7 @@ void ZRWeaponConfig::LoadWeaponConfig() bool bEnabled = pKey->GetBool("enabled", false); float flKnockback = pKey->GetFloat("knockback", 1.0f); Message("%s knockback: %f\n", pszWeaponName, flKnockback); - ZRWeapon *weapon = new ZRWeapon; + std::shared_ptr weapon = std::make_shared(); if (!bEnabled) continue; @@ -872,7 +872,7 @@ void ZRWeaponConfig::LoadWeaponConfig() return; } -ZRWeapon* ZRWeaponConfig::FindWeapon(const char *pszWeaponName) +std::shared_ptr ZRWeaponConfig::FindWeapon(const char *pszWeaponName) { uint16 index = m_WeaponMap.Find(hash_32_fnv1a_const(pszWeaponName)); if (m_WeaponMap.IsValidIndex(index)) @@ -1083,7 +1083,7 @@ void ZR_OnPlayerSpawn(CCSPlayerController* pController) void ZR_ApplyKnockback(CCSPlayerPawn *pHuman, CCSPlayerPawn *pVictim, int iDamage, const char *szWeapon, int hitgroup, float classknockback) { - ZRWeapon *pWeapon = g_pZRWeaponConfig->FindWeapon(szWeapon); + std::shared_ptr pWeapon = g_pZRWeaponConfig->FindWeapon(szWeapon); std::shared_ptr pHitgroup = g_pZRHitgroupConfig->FindHitgroupIndex(hitgroup); // player shouldn't be able to pick up that weapon in the first place, but just in case if (!pWeapon) @@ -1102,7 +1102,7 @@ void ZR_ApplyKnockback(CCSPlayerPawn *pHuman, CCSPlayerPawn *pVictim, int iDamag void ZR_ApplyKnockbackExplosion(CBaseEntity *pProjectile, CCSPlayerPawn *pVictim, int iDamage, bool bMolotov) { - ZRWeapon *pWeapon = g_pZRWeaponConfig->FindWeapon(pProjectile->GetClassname()); + std::shared_ptr pWeapon = g_pZRWeaponConfig->FindWeapon(pProjectile->GetClassname()); if (!pWeapon) return; float flWeaponKnockbackScale = pWeapon->flKnockback; diff --git a/src/zombiereborn.h b/src/zombiereborn.h index dcac9097b..e3822d9d7 100644 --- a/src/zombiereborn.h +++ b/src/zombiereborn.h @@ -259,9 +259,9 @@ class ZRWeaponConfig m_WeaponMap.SetLessFunc(DefLessFunc(uint32)); }; void LoadWeaponConfig(); - ZRWeapon* FindWeapon(const char *pszWeaponName); + std::shared_ptr FindWeapon(const char *pszWeaponName); private: - CUtlMap m_WeaponMap; + CUtlMap> m_WeaponMap; }; From 2e9a53283d0454c52585c8bd9d7ee0d942523b81 Mon Sep 17 00:00:00 2001 From: Vauff Date: Fri, 13 Dec 2024 20:02:22 -0500 Subject: [PATCH 08/11] Add workaround for CS2 randomly spawning players with mega-velocity --- src/events.cpp | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/events.cpp b/src/events.cpp index b75510aac..c494c79b6 100644 --- a/src/events.cpp +++ b/src/events.cpp @@ -173,6 +173,26 @@ GAME_EVENT_F(player_spawn) return -1.0f; }); + + // And this needs even more delay..? Don't even know if this is enough, bug can't be reproduced + new CTimer(0.1f, false, false, [hController]() + { + CCSPlayerController* pController = hController.Get(); + + if (!pController) + return -1.0f; + + CBasePlayerPawn* pPawn = pController->GetPawn(); + + if (pPawn) + { + // Fix new haunted CS2 bug? https://www.reddit.com/r/cs2/comments/1glvg9s/thank_you_for_choosing_anubis_airlines/ + // We've seen this several times across different maps at this point + pPawn->m_vecAbsVelocity = Vector(0, 0, 0); + } + + return -1.0f; + }); } static bool g_bEnableTopDefender = false; From 64d708751a4403ec1f1eaad02f1eef0f87b76a38 Mon Sep 17 00:00:00 2001 From: Vauff Date: Fri, 13 Dec 2024 20:20:14 -0500 Subject: [PATCH 09/11] Fix crash with @aim targeting --- src/playermanager.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/playermanager.cpp b/src/playermanager.cpp index 4bf571e4b..93553abb1 100644 --- a/src/playermanager.cpp +++ b/src/playermanager.cpp @@ -1305,7 +1305,7 @@ ETargetError CPlayerManager::GetPlayersFromString(CCSPlayerController* pPlayer, CBaseEntity* entTarget = nullptr; entTarget = UTIL_FindPickerEntity(pPlayer); - if (!entTarget->IsPawn()) + if (!entTarget || !entTarget->IsPawn()) return ETargetError::INVALID; CCSPlayerController* pTarget = CCSPlayerController::FromPawn(static_cast(entTarget)); From bfd1c7dede76d2422d2bd9aafde58a0e4ded92c1 Mon Sep 17 00:00:00 2001 From: Vauff Date: Sat, 14 Dec 2024 00:26:50 -0500 Subject: [PATCH 10/11] Track extend count & new extend state --- src/adminsystem.cpp | 24 ++------------- src/votemanager.cpp | 75 +++++++++++++++------------------------------ src/votemanager.h | 2 +- 3 files changed, 27 insertions(+), 74 deletions(-) diff --git a/src/adminsystem.cpp b/src/adminsystem.cpp index c8fa07cb6..96c02d049 100644 --- a/src/adminsystem.cpp +++ b/src/adminsystem.cpp @@ -688,28 +688,8 @@ CON_COMMAND_CHAT_FLAGS(extend, " - Extend current map (negative value r int iExtendTime = V_StringToInt32(args[1], 0); - ConVar* cvar = g_pCVar->GetConVar(g_pCVar->FindConVar("mp_timelimit")); - - // CONVAR_TODO - // HACK: values is actually the cvar value itself, hence this ugly cast. - float flTimelimit = *(float *)&cvar->values; - - if (gpGlobals->curtime - g_pGameRules->m_flGameStartTime > flTimelimit * 60) - flTimelimit = (gpGlobals->curtime - g_pGameRules->m_flGameStartTime) / 60.0f + iExtendTime; - else - { - if (flTimelimit == 1) - flTimelimit = 0; - flTimelimit += iExtendTime; - } - - if (flTimelimit <= 0) - flTimelimit = 1; - - // CONVAR_TODO - char buf[32]; - V_snprintf(buf, sizeof(buf), "mp_timelimit %.6f", flTimelimit); - g_pEngineServer2->ServerCommand(buf); + // Call the votemanager extend function so the extend vote can be checked + ExtendMap(iExtendTime); const char* pszCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; diff --git a/src/votemanager.cpp b/src/votemanager.cpp index 335814ee6..aa50afc32 100644 --- a/src/votemanager.cpp +++ b/src/votemanager.cpp @@ -34,9 +34,10 @@ extern CCSGameRules* g_pGameRules; ERTVState g_RTVState = ERTVState::MAP_START; EExtendState g_ExtendState = EExtendState::MAP_START; +int g_iExtends = 0; bool g_bVoteManagerEnable = false; -int g_iExtendsLeft = 1; +int g_iMaxExtends = 1; float g_flExtendSucceedRatio = 0.5f; int g_iExtendTimeToAdd = 20; float g_flRTVSucceedRatio = 0.6f; @@ -53,7 +54,7 @@ float g_flRtvDelay = 300.0f; FAKE_BOOL_CVAR(cs2f_votemanager_enable, "Whether to enable votemanager features such as RTV and extends", g_bVoteManagerEnable, false, false) FAKE_FLOAT_CVAR(cs2f_extend_vote_delay, "If cs2f_extend_mode is 2, Time after map start until extend votes can be triggered", g_flExtendVoteDelay, 120.0f, false) FAKE_INT_CVAR(cs2f_extend_mode, "How extend votes are handled. (0=off, 1=only admins can start, 2=players can start with !ve, 3=auto start at given timeleft)", g_ExtendVoteMode, (int)EExtendVoteMode::EXTENDVOTE_ADMINONLY, false) -FAKE_INT_CVAR(cs2f_extends, "Maximum extends per map", g_iExtendsLeft, 1, false) +FAKE_INT_CVAR(cs2f_extends, "Maximum extends per map", g_iMaxExtends, 1, false) FAKE_FLOAT_CVAR(cs2f_extend_success_ratio, "Ratio needed to pass an extend vote", g_flExtendSucceedRatio, 0.5f, false) FAKE_INT_CVAR(cs2f_extend_time, "Time to add per extend in minutes", g_iExtendTimeToAdd, 20, false) FAKE_FLOAT_CVAR(cs2f_extend_vote_start_time, "If cs2f_extend_mode is 3, start an extend vote at this timeleft (minutes)", g_flExtendVoteStartTime, 4.0f, false) @@ -72,6 +73,8 @@ void VoteManager_Init() g_RTVState = ERTVState::MAP_START; g_ExtendState = EExtendState::MAP_START; + g_iExtends = 0; + new CTimer(g_flExtendVoteDelay, false, true, []() { if (g_ExtendState < EExtendState::POST_EXTEND_NO_EXTENDS_LEFT) @@ -110,7 +113,7 @@ float TimerCheckTimeleft() return flExtendVoteTickrate; // No more extends or map RTVd - if (g_iExtendsLeft <= 0 || g_ExtendState >= EExtendState::POST_EXTEND_NO_EXTENDS_LEFT) + if ((g_iMaxExtends - g_iExtends) <= 0 || g_ExtendState >= EExtendState::POST_EXTEND_NO_EXTENDS_LEFT) return flExtendVoteTickrate; ConVar* cvar = g_pCVar->GetConVar(g_pCVar->FindConVar("mp_timelimit")); @@ -401,6 +404,9 @@ CON_COMMAND_CHAT(ve, "- Vote to extend current map") case EExtendState::POST_EXTEND_NO_EXTENDS_LEFT: ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "There are no extends left for the current map."); return; + case EExtendState::POST_EXTEND_FAILED: + ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "A previous extend vote already failed."); + return; case EExtendState::POST_LAST_ROUND_END: ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "Extend vote is closed during next map selection."); return; @@ -491,7 +497,7 @@ CON_COMMAND_CHAT_FLAGS(adminve, "Start a vote extend immediately.", ADMFLAG_CHAN if (g_ExtendState == EExtendState::IN_PROGRESS || bVoteStarting) { - ClientPrint(player, HUD_PRINTCONSOLE, CHAT_PREFIX "An extend vote is already in progress."); + ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "An extend vote is already in progress."); return; } @@ -544,54 +550,22 @@ CON_COMMAND_CHAT_FLAGS(enablertv, "- Restore the ability for players to vote to ClientPrintAll(HUD_PRINTTALK, CHAT_PREFIX ADMIN_PREFIX "enabled vote for RTV.", pszCommandPlayerName); } -CON_COMMAND_CHAT_FLAGS(addextend, "- Add another extend to the current map for players to vote", ADMFLAG_RCON) -{ - if (!g_bVoteManagerEnable) - return; - - if (g_ExtendState == EExtendState::IN_PROGRESS) - { - if (player) - ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "Wait until the current vote has ended to add extends."); - else - ConMsg("Wait until the current vote has ended to add extends."); - return; - } - - const char* pszCommandPlayerName = player ? player->GetPlayerName() : CONSOLE_NAME; - - if (g_ExtendState == EExtendState::POST_EXTEND_NO_EXTENDS_LEFT || g_ExtendState == EExtendState::NO_EXTENDS) - g_ExtendState = EExtendState::EXTEND_ALLOWED; - - g_iExtendsLeft += 1; - - ClientPrintAll(HUD_PRINTTALK, CHAT_PREFIX ADMIN_PREFIX "allowed for an additional extend.", pszCommandPlayerName); -} - CON_COMMAND_CHAT(extendsleft, "- Display amount of extends left for the current map") { if (!g_bVoteManagerEnable) return; - char message[64]; - - switch (g_iExtendsLeft) + if (g_iMaxExtends - g_iExtends <= 0) { - case 0: - strcpy(message, "There are no extends left."); - break; - case 1: - strcpy(message, "There's 1 extend left"); - break; - default: - V_snprintf(message, sizeof(message), "There are %i extends left.", g_iExtendsLeft); - break; + ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "There are no extends left, the map was already extended %i/%i times.", g_iExtends, g_iMaxExtends); } - - if (player) - ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "%s", message); else - ConMsg("%s", message); + { + if (g_ExtendState == EExtendState::POST_EXTEND_FAILED) + ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "The map had %i/%i extends left, but the last extend vote failed.", g_iMaxExtends - g_iExtends, g_iMaxExtends); + else + ClientPrint(player, HUD_PRINTTALK, CHAT_PREFIX "The map has %i/%i extends left.", g_iMaxExtends - g_iExtends, g_iMaxExtends); + } } CON_COMMAND_CHAT(timeleft, "- Display time left to end of current map.") @@ -682,11 +656,11 @@ void VoteExtendHandler(YesNoVoteAction action, int param1, int param2) { if ((YesNoVoteEndReason)param1 == YesNoVoteEndReason::VoteEnd_Cancelled) { - // Admin cancelled so stop further automatic votes + // Admin cancelled so stop further votes // It will reenable if an admin manually calls a vote if (g_ExtendVoteMode == EExtendVoteMode::EXTENDVOTE_AUTO) { - g_ExtendState = EExtendState::POST_EXTEND_NO_EXTENDS_LEFT; + g_ExtendState = EExtendState::POST_EXTEND_FAILED; } } @@ -710,8 +684,9 @@ bool VoteExtendEndCallback(YesNoVoteInfo info) if (yes_percent >= g_flExtendSucceedRatio) { ExtendMap(g_iExtendTimeToAdd); + g_iExtends++; - if (g_iExtendsLeft == 1) + if (g_iMaxExtends - g_iExtends <= 0) // there are no extends left after a successfull extend vote g_ExtendState = EExtendState::POST_EXTEND_NO_EXTENDS_LEFT; else @@ -747,15 +722,13 @@ bool VoteExtendEndCallback(YesNoVoteInfo info) pPlayer->SetExtendVote(false); } - g_iExtendsLeft--; ClientPrintAll(HUD_PRINTTALK, CHAT_PREFIX "Extend vote succeeded! Current map has been extended by %i minutes.", g_iExtendTimeToAdd); return true; } - // Vote failed so we don't allow any more player initiated votes - g_ExtendState = EExtendState::POST_EXTEND_NO_EXTENDS_LEFT; - g_iExtendsLeft = 0; + // Vote failed so we don't allow any more votes + g_ExtendState = EExtendState::POST_EXTEND_FAILED; ClientPrintAll(HUD_PRINTTALK, CHAT_PREFIX "Extend vote failed! Further extend votes disabled!", g_iExtendTimeToAdd); diff --git a/src/votemanager.h b/src/votemanager.h index e64f563fd..49f41fef6 100644 --- a/src/votemanager.h +++ b/src/votemanager.h @@ -36,6 +36,7 @@ enum class EExtendState IN_PROGRESS, POST_EXTEND_COOLDOWN, POST_EXTEND_NO_EXTENDS_LEFT, + POST_EXTEND_FAILED, POST_LAST_ROUND_END, POST_RTV, NO_EXTENDS, @@ -51,7 +52,6 @@ enum EExtendVoteMode extern ERTVState g_RTVState; extern EExtendState g_ExtendState; -extern int g_iExtendsLeft; extern bool g_bVoteManagerEnable; void VoteManager_Init(); From da67ae21d13440c021c147d27912fbe9fe3789fe Mon Sep 17 00:00:00 2001 From: Vauff Date: Sat, 14 Dec 2024 13:43:28 -0500 Subject: [PATCH 11/11] Improve ZR knife & revive behaviour - Knife skin should now match team loadout - Give armour on revives (if configured) - Re-strip on revives, to prevent ZM items lingering --- src/cs2_sdk/entity/cbaseplayerpawn.h | 2 +- src/zombiereborn.cpp | 22 ++++++++++++++++++++-- 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/cs2_sdk/entity/cbaseplayerpawn.h b/src/cs2_sdk/entity/cbaseplayerpawn.h index 662af7815..5341beeda 100644 --- a/src/cs2_sdk/entity/cbaseplayerpawn.h +++ b/src/cs2_sdk/entity/cbaseplayerpawn.h @@ -39,7 +39,7 @@ class CBasePlayerPawn : public CBaseModelEntity SCHEMA_FIELD(QAngle, v_angle) // Drops any map-spawned weapons the pawn is holding - // NOTE: Currently very broken with map items (entities parented to weapons?) due to a game bug..? Needs further investigation/work + // NOTE: This doesn't predict correctly to the weapon holder! Looks very funky when testing, but not really an issue on live servers void DropMapWeapons() { if (!m_pWeaponServices()) diff --git a/src/zombiereborn.cpp b/src/zombiereborn.cpp index 4ee3f4a25..db1f3cf98 100644 --- a/src/zombiereborn.cpp +++ b/src/zombiereborn.cpp @@ -1147,7 +1147,21 @@ void ZR_StripAndGiveKnife(CCSPlayerPawn *pPawn) pPawn->DropMapWeapons(); pItemServices->StripPlayerWeapons(true); - pItemServices->GiveNamedItem("weapon_knife"); + + if (pPawn->m_iTeamNum == CS_TEAM_T) + { + pItemServices->GiveNamedItem("weapon_knife_t"); + } + else if (pPawn->m_iTeamNum == CS_TEAM_CT) + { + pItemServices->GiveNamedItem("weapon_knife"); + + // CONVAR_TODO + ConVar* cvar = g_pCVar->GetConVar(g_pCVar->FindConVar("mp_free_armor")); + // HACK: values is actually the cvar value itself, hence this ugly cast. + if (*(int*)&cvar->values > 0) + pItemServices->GiveNamedItem("item_kevlar"); + } CUtlVector>* weapons = pWeaponServices->m_hMyWeapons(); @@ -1287,6 +1301,7 @@ void ZR_InfectMotherZombie(CCSPlayerController *pVictimController, std::vectorSwitchTeam(CS_TEAM_T); ZR_StripAndGiveKnife(pVictimPawn); // pick random spawn point @@ -1299,7 +1314,6 @@ void ZR_InfectMotherZombie(CCSPlayerController *pVictimController, std::vectorTeleport(&origin, &rotation, &vec3_origin); } - pVictimController->SwitchTeam(CS_TEAM_T); pVictimPawn->EmitSound("zr.amb.scream"); std::shared_ptr pClass = g_pZRPlayerClassManager->GetZombieClass("MotherZombie"); @@ -2006,7 +2020,11 @@ CON_COMMAND_CHAT_FLAGS(revive, "- Revive a player", ADMFLAG_GENERIC) CCSPlayerController* pTarget = CCSPlayerController::FromSlot(pSlots[i]); CCSPlayerPawn* pPawn = (CCSPlayerPawn*)pTarget->GetPawn(); + if (!pPawn) + continue; + ZR_Cure(pTarget); + ZR_StripAndGiveKnife(pPawn); if (iNumClients == 1) PrintSingleAdminAction(pszCommandPlayerName, pTarget->GetPlayerName(), "revived", "", ZR_PREFIX);