From 8362f0f8c73fe620b6cdf80e3e62d1a8869ffff2 Mon Sep 17 00:00:00 2001 From: dilbertron2 Date: Mon, 30 Mar 2026 11:53:55 +0100 Subject: [PATCH 1/7] 1 --- src/game/client/tf/c_tf_player.cpp | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/game/client/tf/c_tf_player.cpp b/src/game/client/tf/c_tf_player.cpp index 4d6251437c0..b95925d5e3c 100644 --- a/src/game/client/tf/c_tf_player.cpp +++ b/src/game/client/tf/c_tf_player.cpp @@ -1599,12 +1599,14 @@ void C_TFRagdoll::DissolveEntity( CBaseEntity* pEnt ) Vector vColor; if ( m_iTeam == TF_TEAM_BLUE ) { - vColor = TF_PARTICLE_WEAPON_RED_1 * 255; + // vColor = TF_PARTICLE_WEAPON_RED_1 * 255; + vColor = TF_PARTICLE_WEAPON_BLUE_1 * 255; pDissolve->SetEffectColor( vColor ); } else { - vColor = TF_PARTICLE_WEAPON_BLUE_1 * 255; + // vColor = TF_PARTICLE_WEAPON_BLUE_1 * 255; + vColor = TF_PARTICLE_WEAPON_RED_1 * 255; pDissolve->SetEffectColor( vColor ); } From a4ca71e84da875b1d042cbf87d00054fdd6852ee Mon Sep 17 00:00:00 2001 From: dilbertron2 Date: Wed, 1 Apr 2026 00:33:45 +0100 Subject: [PATCH 2/7] Implement suicide handling when player dies to Cow Mangler, check if it was a suicide and if it is then set fizzle color to own team --- src/game/client/tf/c_tf_player.cpp | 40 +++++++++++++++++++++++++++--- src/game/client/tf/c_tf_player.h | 2 ++ 2 files changed, 38 insertions(+), 4 deletions(-) diff --git a/src/game/client/tf/c_tf_player.cpp b/src/game/client/tf/c_tf_player.cpp index b95925d5e3c..39a8c37bbf0 100644 --- a/src/game/client/tf/c_tf_player.cpp +++ b/src/game/client/tf/c_tf_player.cpp @@ -1597,16 +1597,30 @@ void C_TFRagdoll::DissolveEntity( CBaseEntity* pEnt ) pDissolve->SetRenderColor( 255, 255, 255, 255 ); Vector vColor; + C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer(); + if ( m_iTeam == TF_TEAM_BLUE ) { - // vColor = TF_PARTICLE_WEAPON_RED_1 * 255; - vColor = TF_PARTICLE_WEAPON_BLUE_1 * 255; + if (pLocalPlayer) + { + vColor = (pLocalPlayer->GetIsSuicide()) ? TF_PARTICLE_WEAPON_BLUE_1 * 255 : TF_PARTICLE_WEAPON_RED_1 * 255; + } + else + { + vColor = TF_PARTICLE_WEAPON_RED_1 * 255; + } pDissolve->SetEffectColor( vColor ); } else { - // vColor = TF_PARTICLE_WEAPON_BLUE_1 * 255; - vColor = TF_PARTICLE_WEAPON_RED_1 * 255; + if (pLocalPlayer) + { + vColor = (pLocalPlayer->GetIsSuicide()) ? TF_PARTICLE_WEAPON_RED_1 * 255 : TF_PARTICLE_WEAPON_BLUE_1 * 255; + } + else + { + vColor = TF_PARTICLE_WEAPON_BLUE_1 * 255; + } pDissolve->SetEffectColor( vColor ); } @@ -3995,6 +4009,7 @@ C_TFPlayer::C_TFPlayer() : ListenForGameEvent( "player_abandoned_match" ); ListenForGameEvent( "rocketpack_launch" ); ListenForGameEvent( "rocketpack_landed" ); + ListenForGameEvent( "player_death" ); //AddPhonemeFile engine->AddPhonemeFile( "scripts/game_sounds_vo_phonemes.txt" ); @@ -11184,6 +11199,23 @@ void C_TFPlayer::FireGameEvent( IGameEvent *event ) } } } + else if (FStrEq(event->GetName(), "player_death" ) ) + { + m_bIsSuicide = false; + const int iAttacker = engine->GetPlayerForUserID(event->GetInt("attacker")); + C_TFPlayer* pAttacker = ToTFPlayer(UTIL_PlayerByIndex(iAttacker)); + + const int iVictim = engine->GetPlayerForUserID(event->GetInt("userid")); + C_TFPlayer* pVictim = ToTFPlayer(UTIL_PlayerByIndex(iVictim)); + + if ( !pVictim ) + return; + + if ( !pAttacker || pAttacker == pVictim ) + { + m_bIsSuicide = true; + } + } BaseClass::FireGameEvent( event ); } diff --git a/src/game/client/tf/c_tf_player.h b/src/game/client/tf/c_tf_player.h index 23ecbc6b70d..047b943ca42 100644 --- a/src/game/client/tf/c_tf_player.h +++ b/src/game/client/tf/c_tf_player.h @@ -626,6 +626,7 @@ class C_TFPlayer : public C_BasePlayer, public IHasAttributes, public IInventory // Called by shared code. public: float GetClassChangeTime() const { return m_flChangeClassTime; } + bool GetIsSuicide() const { return m_bIsSuicide; } void SetFootStamps( int nFootStamps ) { m_nFootStamps = nFootStamps; } void DoAnimationEvent( PlayerAnimEvent_t event, int nData = 0 ); @@ -675,6 +676,7 @@ class C_TFPlayer : public C_BasePlayer, public IHasAttributes, public IInventory bool m_bSaveMeParity; bool m_bOldSaveMeParity; bool m_bIsCoaching; + bool m_bIsSuicide; private: void UpdateTauntItem(); From 96330011f8ac79126764cd887165b09fc044383c Mon Sep 17 00:00:00 2001 From: dilbertron2 Date: Thu, 2 Apr 2026 02:39:48 +0100 Subject: [PATCH 3/7] comments --- src/game/client/tf/c_tf_player.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/game/client/tf/c_tf_player.cpp b/src/game/client/tf/c_tf_player.cpp index 39a8c37bbf0..79d68883abf 100644 --- a/src/game/client/tf/c_tf_player.cpp +++ b/src/game/client/tf/c_tf_player.cpp @@ -1598,14 +1598,14 @@ void C_TFRagdoll::DissolveEntity( CBaseEntity* pEnt ) Vector vColor; C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer(); - + // If a player kills themselves with a weapon that dissolves ragdolls, set dissolving color to their own team if ( m_iTeam == TF_TEAM_BLUE ) { if (pLocalPlayer) { vColor = (pLocalPlayer->GetIsSuicide()) ? TF_PARTICLE_WEAPON_BLUE_1 * 255 : TF_PARTICLE_WEAPON_RED_1 * 255; } - else + else // Fallback to original code if pLocalPlayer is invalid { vColor = TF_PARTICLE_WEAPON_RED_1 * 255; } @@ -1617,7 +1617,7 @@ void C_TFRagdoll::DissolveEntity( CBaseEntity* pEnt ) { vColor = (pLocalPlayer->GetIsSuicide()) ? TF_PARTICLE_WEAPON_RED_1 * 255 : TF_PARTICLE_WEAPON_BLUE_1 * 255; } - else + else // Fallback to original code if pLocalPlayer is invalid { vColor = TF_PARTICLE_WEAPON_BLUE_1 * 255; } From 0182301fc76fb57ede6357a6bfd36ef8b6ca271b Mon Sep 17 00:00:00 2001 From: dilbertron2 Date: Thu, 2 Apr 2026 20:05:03 +0100 Subject: [PATCH 4/7] rename function to be more readable --- src/game/client/tf/c_tf_player.cpp | 4 ++-- src/game/client/tf/c_tf_player.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/game/client/tf/c_tf_player.cpp b/src/game/client/tf/c_tf_player.cpp index 79d68883abf..d93e1f5ef03 100644 --- a/src/game/client/tf/c_tf_player.cpp +++ b/src/game/client/tf/c_tf_player.cpp @@ -1603,7 +1603,7 @@ void C_TFRagdoll::DissolveEntity( CBaseEntity* pEnt ) { if (pLocalPlayer) { - vColor = (pLocalPlayer->GetIsSuicide()) ? TF_PARTICLE_WEAPON_BLUE_1 * 255 : TF_PARTICLE_WEAPON_RED_1 * 255; + vColor = ( pLocalPlayer->IsDeathSuicide() ) ? TF_PARTICLE_WEAPON_BLUE_1 * 255 : TF_PARTICLE_WEAPON_RED_1 * 255; } else // Fallback to original code if pLocalPlayer is invalid { @@ -1615,7 +1615,7 @@ void C_TFRagdoll::DissolveEntity( CBaseEntity* pEnt ) { if (pLocalPlayer) { - vColor = (pLocalPlayer->GetIsSuicide()) ? TF_PARTICLE_WEAPON_RED_1 * 255 : TF_PARTICLE_WEAPON_BLUE_1 * 255; + vColor = ( pLocalPlayer->IsDeathSuicide() ) ? TF_PARTICLE_WEAPON_RED_1 * 255 : TF_PARTICLE_WEAPON_BLUE_1 * 255; } else // Fallback to original code if pLocalPlayer is invalid { diff --git a/src/game/client/tf/c_tf_player.h b/src/game/client/tf/c_tf_player.h index 047b943ca42..08454706dc8 100644 --- a/src/game/client/tf/c_tf_player.h +++ b/src/game/client/tf/c_tf_player.h @@ -626,7 +626,7 @@ class C_TFPlayer : public C_BasePlayer, public IHasAttributes, public IInventory // Called by shared code. public: float GetClassChangeTime() const { return m_flChangeClassTime; } - bool GetIsSuicide() const { return m_bIsSuicide; } + bool IsDeathSuicide() const { return m_bIsSuicide; } void SetFootStamps( int nFootStamps ) { m_nFootStamps = nFootStamps; } void DoAnimationEvent( PlayerAnimEvent_t event, int nData = 0 ); @@ -676,7 +676,7 @@ class C_TFPlayer : public C_BasePlayer, public IHasAttributes, public IInventory bool m_bSaveMeParity; bool m_bOldSaveMeParity; bool m_bIsCoaching; - bool m_bIsSuicide; + bool m_bIsSuicide = false; private: void UpdateTauntItem(); From 63fdc52dd44f4974c93a2d178baf8ee31b01f819 Mon Sep 17 00:00:00 2001 From: dilbertron2 Date: Fri, 3 Apr 2026 00:02:40 +0100 Subject: [PATCH 5/7] implement suggestions --- src/game/client/tf/c_tf_player.cpp | 29 +++++++++-------------------- src/game/client/tf/c_tf_player.h | 2 +- 2 files changed, 10 insertions(+), 21 deletions(-) diff --git a/src/game/client/tf/c_tf_player.cpp b/src/game/client/tf/c_tf_player.cpp index d93e1f5ef03..d83a16d56cc 100644 --- a/src/game/client/tf/c_tf_player.cpp +++ b/src/game/client/tf/c_tf_player.cpp @@ -1598,29 +1598,16 @@ void C_TFRagdoll::DissolveEntity( CBaseEntity* pEnt ) Vector vColor; C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer(); + bool bIsSuicide = pLocalPlayer ? pLocalPlayer->IsDeathSuicide() : NULL; // If a player kills themselves with a weapon that dissolves ragdolls, set dissolving color to their own team if ( m_iTeam == TF_TEAM_BLUE ) { - if (pLocalPlayer) - { - vColor = ( pLocalPlayer->IsDeathSuicide() ) ? TF_PARTICLE_WEAPON_BLUE_1 * 255 : TF_PARTICLE_WEAPON_RED_1 * 255; - } - else // Fallback to original code if pLocalPlayer is invalid - { - vColor = TF_PARTICLE_WEAPON_RED_1 * 255; - } + vColor = ( bIsSuicide ) ? TF_PARTICLE_WEAPON_BLUE_1 * 255 : TF_PARTICLE_WEAPON_RED_1 * 255; pDissolve->SetEffectColor( vColor ); } else { - if (pLocalPlayer) - { - vColor = ( pLocalPlayer->IsDeathSuicide() ) ? TF_PARTICLE_WEAPON_RED_1 * 255 : TF_PARTICLE_WEAPON_BLUE_1 * 255; - } - else // Fallback to original code if pLocalPlayer is invalid - { - vColor = TF_PARTICLE_WEAPON_BLUE_1 * 255; - } + vColor = ( bIsSuicide ) ? TF_PARTICLE_WEAPON_RED_1 * 255 : TF_PARTICLE_WEAPON_BLUE_1 * 255; pDissolve->SetEffectColor( vColor ); } @@ -3993,6 +3980,8 @@ C_TFPlayer::C_TFPlayer() : m_iPlayerSkinOverride = 0; + m_bIsSuicide = false; + ListenForGameEvent( "player_hurt" ); ListenForGameEvent( "hltv_changed_mode" ); ListenForGameEvent( "hltv_changed_target" ); @@ -11202,11 +11191,11 @@ void C_TFPlayer::FireGameEvent( IGameEvent *event ) else if (FStrEq(event->GetName(), "player_death" ) ) { m_bIsSuicide = false; - const int iAttacker = engine->GetPlayerForUserID(event->GetInt("attacker")); - C_TFPlayer* pAttacker = ToTFPlayer(UTIL_PlayerByIndex(iAttacker)); + const int iAttacker = engine->GetPlayerForUserID( event->GetInt( "attacker" ) ); + C_TFPlayer* pAttacker = ToTFPlayer( UTIL_PlayerByIndex( iAttacker ) ); - const int iVictim = engine->GetPlayerForUserID(event->GetInt("userid")); - C_TFPlayer* pVictim = ToTFPlayer(UTIL_PlayerByIndex(iVictim)); + const int iVictim = engine->GetPlayerForUserID( event->GetInt( "userid" ) ); + C_TFPlayer* pVictim = ToTFPlayer( UTIL_PlayerByIndex( iVictim) ); if ( !pVictim ) return; diff --git a/src/game/client/tf/c_tf_player.h b/src/game/client/tf/c_tf_player.h index 08454706dc8..274d1f55347 100644 --- a/src/game/client/tf/c_tf_player.h +++ b/src/game/client/tf/c_tf_player.h @@ -676,7 +676,7 @@ class C_TFPlayer : public C_BasePlayer, public IHasAttributes, public IInventory bool m_bSaveMeParity; bool m_bOldSaveMeParity; bool m_bIsCoaching; - bool m_bIsSuicide = false; + bool m_bIsSuicide; private: void UpdateTauntItem(); From 5fd4d3b9de285a11f7d5656e44855a11cfa0b10c Mon Sep 17 00:00:00 2001 From: dilbertron2 Date: Fri, 3 Apr 2026 12:56:42 +0100 Subject: [PATCH 6/7] add friendly fire checks check victim/attacker teams instead of direct victim/attacker pointers --- src/game/client/tf/c_tf_player.cpp | 24 +++++++++++++++--------- src/game/client/tf/c_tf_player.h | 4 ++-- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/game/client/tf/c_tf_player.cpp b/src/game/client/tf/c_tf_player.cpp index d83a16d56cc..b40f493ee8a 100644 --- a/src/game/client/tf/c_tf_player.cpp +++ b/src/game/client/tf/c_tf_player.cpp @@ -1598,16 +1598,16 @@ void C_TFRagdoll::DissolveEntity( CBaseEntity* pEnt ) Vector vColor; C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer(); - bool bIsSuicide = pLocalPlayer ? pLocalPlayer->IsDeathSuicide() : NULL; - // If a player kills themselves with a weapon that dissolves ragdolls, set dissolving color to their own team + bool bIsFriendlyFireOrSuicide = pLocalPlayer ? pLocalPlayer->IsDeathFriendlyFireOrSuicide() : NULL; + // If a player kills themselves or a teammate with a weapon that dissolves ragdolls, set dissolving color to their own team if ( m_iTeam == TF_TEAM_BLUE ) { - vColor = ( bIsSuicide ) ? TF_PARTICLE_WEAPON_BLUE_1 * 255 : TF_PARTICLE_WEAPON_RED_1 * 255; + vColor = ( bIsFriendlyFireOrSuicide ) ? TF_PARTICLE_WEAPON_BLUE_1 * 255 : TF_PARTICLE_WEAPON_RED_1 * 255; pDissolve->SetEffectColor( vColor ); } else { - vColor = ( bIsSuicide ) ? TF_PARTICLE_WEAPON_RED_1 * 255 : TF_PARTICLE_WEAPON_BLUE_1 * 255; + vColor = ( bIsFriendlyFireOrSuicide ) ? TF_PARTICLE_WEAPON_RED_1 * 255 : TF_PARTICLE_WEAPON_BLUE_1 * 255; pDissolve->SetEffectColor( vColor ); } @@ -3980,7 +3980,7 @@ C_TFPlayer::C_TFPlayer() : m_iPlayerSkinOverride = 0; - m_bIsSuicide = false; + m_bIsFriendlyFireOrSuicide = false; ListenForGameEvent( "player_hurt" ); ListenForGameEvent( "hltv_changed_mode" ); @@ -11190,19 +11190,25 @@ void C_TFPlayer::FireGameEvent( IGameEvent *event ) } else if (FStrEq(event->GetName(), "player_death" ) ) { - m_bIsSuicide = false; + m_bIsFriendlyFireOrSuicide = false; const int iAttacker = engine->GetPlayerForUserID( event->GetInt( "attacker" ) ); C_TFPlayer* pAttacker = ToTFPlayer( UTIL_PlayerByIndex( iAttacker ) ); const int iVictim = engine->GetPlayerForUserID( event->GetInt( "userid" ) ); - C_TFPlayer* pVictim = ToTFPlayer( UTIL_PlayerByIndex( iVictim) ); + C_TFPlayer* pVictim = ToTFPlayer( UTIL_PlayerByIndex( iVictim ) ); if ( !pVictim ) return; + // Attacker cant be found.. could still be a suicide though, lets treat it as one! + if ( !pAttacker ) + { + m_bIsFriendlyFireOrSuicide = true; + return; + } - if ( !pAttacker || pAttacker == pVictim ) + if ( pAttacker->GetTeamNumber() == pVictim->GetTeamNumber() ) { - m_bIsSuicide = true; + m_bIsFriendlyFireOrSuicide = true; } } BaseClass::FireGameEvent( event ); diff --git a/src/game/client/tf/c_tf_player.h b/src/game/client/tf/c_tf_player.h index 274d1f55347..e1107ee03cc 100644 --- a/src/game/client/tf/c_tf_player.h +++ b/src/game/client/tf/c_tf_player.h @@ -626,7 +626,7 @@ class C_TFPlayer : public C_BasePlayer, public IHasAttributes, public IInventory // Called by shared code. public: float GetClassChangeTime() const { return m_flChangeClassTime; } - bool IsDeathSuicide() const { return m_bIsSuicide; } + bool IsDeathFriendlyFireOrSuicide() const { return m_bIsFriendlyFireOrSuicide; } void SetFootStamps( int nFootStamps ) { m_nFootStamps = nFootStamps; } void DoAnimationEvent( PlayerAnimEvent_t event, int nData = 0 ); @@ -676,7 +676,7 @@ class C_TFPlayer : public C_BasePlayer, public IHasAttributes, public IInventory bool m_bSaveMeParity; bool m_bOldSaveMeParity; bool m_bIsCoaching; - bool m_bIsSuicide; + bool m_bIsFriendlyFireOrSuicide; private: void UpdateTauntItem(); From efa27baedf135ee7596eeda37669cea3fb9be303 Mon Sep 17 00:00:00 2001 From: dilbertron2 Date: Fri, 3 Apr 2026 13:05:10 +0100 Subject: [PATCH 7/7] Merge if statement --- src/game/client/tf/c_tf_player.cpp | 10 ++-------- 1 file changed, 2 insertions(+), 8 deletions(-) diff --git a/src/game/client/tf/c_tf_player.cpp b/src/game/client/tf/c_tf_player.cpp index b40f493ee8a..07be6146b36 100644 --- a/src/game/client/tf/c_tf_player.cpp +++ b/src/game/client/tf/c_tf_player.cpp @@ -11199,14 +11199,8 @@ void C_TFPlayer::FireGameEvent( IGameEvent *event ) if ( !pVictim ) return; - // Attacker cant be found.. could still be a suicide though, lets treat it as one! - if ( !pAttacker ) - { - m_bIsFriendlyFireOrSuicide = true; - return; - } - - if ( pAttacker->GetTeamNumber() == pVictim->GetTeamNumber() ) + // If attacker can't be found lets treat it as a suicide + if ( !pAttacker || pAttacker->GetTeamNumber() == pVictim->GetTeamNumber() ) { m_bIsFriendlyFireOrSuicide = true; }