From cc829569709255e58dedad2d51188718f7b3e009 Mon Sep 17 00:00:00 2001 From: Alan Shen Date: Sat, 28 Mar 2026 17:57:29 -0600 Subject: [PATCH] Award assists to players for damage inflicted before bot takeover --- src/game/client/neo/c_neo_player.h | 3 ++ .../client/neo/ui/neo_hud_deathnotice.cpp | 30 ++++++++++++++++--- src/game/server/neo/neo_player.cpp | 3 +- src/game/server/neo/neo_player.h | 3 ++ src/game/shared/neo/neo_gamerules.cpp | 13 ++++++-- 5 files changed, 44 insertions(+), 8 deletions(-) diff --git a/src/game/client/neo/c_neo_player.h b/src/game/client/neo/c_neo_player.h index 590769b11..031913129 100644 --- a/src/game/client/neo/c_neo_player.h +++ b/src/game/client/neo/c_neo_player.h @@ -182,6 +182,9 @@ class C_NEO_Player : public C_HL2MP_Player bool m_bCopyOverTakeoverPlayerDetails{ false }; CNetworkHandle(C_NEO_Player, m_hSpectatorTakeoverPlayerTarget); CNetworkHandle(C_NEO_Player, m_hSpectatorTakeoverPlayerImpersonatingMe); + C_NEO_Player* GetSpectatorTakeoverPlayerTarget() const { return m_hSpectatorTakeoverPlayerTarget.Get(); } + C_NEO_Player* GetSpectatorTakeoverPlayerImpersonatingMe() const { return m_hSpectatorTakeoverPlayerImpersonatingMe.Get(); } + void CSpectatorTakeoverPlayerUpdateOnDataChanged(); void CSpectatorTakeoverPlayerUpdate(C_NEO_Player* pPlayerTakeoverTarget); const char* GetPlayerNameWithTakeoverContext(int player_index); diff --git a/src/game/client/neo/ui/neo_hud_deathnotice.cpp b/src/game/client/neo/ui/neo_hud_deathnotice.cpp index eaee7c988..661d4e066 100644 --- a/src/game/client/neo/ui/neo_hud_deathnotice.cpp +++ b/src/game/client/neo/ui/neo_hud_deathnotice.cpp @@ -785,12 +785,34 @@ void CNEOHud_DeathNotice::AddPlayerDeath(IGameEvent* event) C_NEO_Player* pVictim = ToNEOPlayer(UTIL_PlayerByIndex(victim)); C_NEO_Player* pAssist = ToNEOPlayer(UTIL_PlayerByIndex(assist)); - if (pKiller) - killer_name = pKiller->GetPlayerNameWithTakeoverContext(killer); + // Special case: Spectator assisted their own bot-takeover kill + // Simplify to "Bot Name + Player Name" + if (pKiller && pAssist && killer == assist && killer > 0) + { + C_NEO_Player* pTakeoverTarget = pKiller->GetSpectatorTakeoverPlayerTarget(); + if (pTakeoverTarget) + { + killer_name = pTakeoverTarget->GetNeoPlayerName(); + assists_name = pAssist->GetNeoPlayerName(); + } + } + else + { + if (pKiller) + { + killer_name = pKiller->GetPlayerNameWithTakeoverContext(killer); + } + + if (pAssist) + { + assists_name = pAssist->GetPlayerNameWithTakeoverContext(assist); + } + } + if (pVictim) + { victim_name = pVictim->GetPlayerNameWithTakeoverContext(victim); - if (pAssist) - assists_name = pAssist->GetPlayerNameWithTakeoverContext(assist); + } // Make a new death notice DeathNoticeItem deathMsg; diff --git a/src/game/server/neo/neo_player.cpp b/src/game/server/neo/neo_player.cpp index d75a80409..2621a62bf 100644 --- a/src/game/server/neo/neo_player.cpp +++ b/src/game/server/neo/neo_player.cpp @@ -3236,7 +3236,8 @@ int CNEO_Player::OnTakeDamage_Alive(const CTakeDamageInfo& info) // Checking because attacker might be prop or world if (auto *attacker = ToNEOPlayer(info.GetAttacker())) { - const int attackerIdx = attacker->entindex(); + CNEO_Player* pImpersonated = attacker->GetSpectatorTakeoverPlayerTarget(); + const int attackerIdx = pImpersonated ? pImpersonated->entindex() : attacker->entindex(); NEORules()->SetLastAttacker(entindex()); // NEO TODO (Adam) Once we can spectate non-players, let last attacker be non-neoplayer (Jeff) // Separate the fractional amount of damage from the whole diff --git a/src/game/server/neo/neo_player.h b/src/game/server/neo/neo_player.h index 26a8680e5..e90b2d645 100644 --- a/src/game/server/neo/neo_player.h +++ b/src/game/server/neo/neo_player.h @@ -182,6 +182,9 @@ class CNEO_Player : public CHL2MP_Player bool GetBotCloakStateDisrupted() const { return !m_botThermOpticCamoDisruptedTimer.IsElapsed(); } bool GetSpectatorTakeoverPlayerPending() const { return m_bSpectatorTakeoverPlayerPending; } + CNEO_Player* GetSpectatorTakeoverPlayerTarget() const { return m_hSpectatorTakeoverPlayerTarget.Get(); } + CNEO_Player* GetSpectatorTakeoverPlayerImpersonatingMe() const { return m_hSpectatorTakeoverPlayerImpersonatingMe.Get(); } + virtual void StartAutoSprint(void) OVERRIDE; virtual void StartSprinting(void) OVERRIDE; virtual void StopSprinting(void) OVERRIDE; diff --git a/src/game/shared/neo/neo_gamerules.cpp b/src/game/shared/neo/neo_gamerules.cpp index 59c405c58..41107e7d0 100644 --- a/src/game/shared/neo/neo_gamerules.cpp +++ b/src/game/shared/neo/neo_gamerules.cpp @@ -3940,7 +3940,9 @@ static CNEO_Player* FetchAssists(CNEO_Player* attacker, CNEO_Player* victim) } // Check for assistance (> 50 dmg, not final attacker) - const int attackerIdx = attacker->entindex(); + CNEO_Player* pImpersonated = attacker->GetSpectatorTakeoverPlayerTarget(); + const int attackerIdx = pImpersonated ? pImpersonated->entindex() : attacker->entindex(); + for (int assistIdx = 1; assistIdx <= gpGlobals->maxClients; ++assistIdx) { if (assistIdx == attackerIdx) @@ -4116,13 +4118,18 @@ void CNEORules::PlayerKilled(CBasePlayer *pVictim, const CTakeDamageInfo &info) { if (sv_neo_teamdamage_assists.GetBool()) { - assister->AddPoints(-1, true); + // If a bot is being taken over, penalize the impersonator. + CNEO_Player* pImpersonator = assister->GetSpectatorTakeoverPlayerImpersonatingMe(); + CNEO_Player* pPenalized = pImpersonator ? pImpersonator : assister; + // bIgnorePlayerTakeover = true to penalize the impersonator + pPenalized->AddPoints(-1, true, true); } } // Enemy kill assist else { - assister->AddPoints(1, false); + // bIgnorePlayerTakeover = true: FetchAssists handled spec-takeover + assister->AddPoints(1, false, true); } } }