From dae377ac7b867b16ba16eb9168c024af32065e49 Mon Sep 17 00:00:00 2001 From: Thomas Kain Date: Sun, 26 Oct 2025 17:21:43 -0400 Subject: [PATCH 1/7] Fix baseballs having both RED and BLU auras after being reflected --- src/game/shared/tf/tf_weapon_bat.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/game/shared/tf/tf_weapon_bat.cpp b/src/game/shared/tf/tf_weapon_bat.cpp index f4452d28ad0..5d9bdfe90ee 100644 --- a/src/game/shared/tf/tf_weapon_bat.cpp +++ b/src/game/shared/tf/tf_weapon_bat.cpp @@ -1013,11 +1013,11 @@ void CTFStunBall::CreateTrailParticles( void ) { if ( pEffectTrail ) { - ParticleProp()->StopEmission( pEffectTrail ); + ParticleProp()->StopEmissionAndDestroyImmediately( pEffectTrail ); } if ( pEffectCrit ) { - ParticleProp()->StopEmission( pEffectCrit ); + ParticleProp()->StopEmissionAndDestroyImmediately( pEffectCrit ); } pEffectTrail = ParticleProp()->Create( GetTrailParticleName(), PATTACH_ABSORIGIN_FOLLOW ); int iTeamNumber = GetTeamNumber(); From c84c6af480aa705262cdf4c5c96b8295aa22c77d Mon Sep 17 00:00:00 2001 From: Thomas Kain Date: Sat, 25 Oct 2025 20:28:49 -0400 Subject: [PATCH 2/7] Fix baseballs not changing their trails' colors after being reflected --- src/game/shared/tf/tf_weapon_bat.cpp | 13 +++++++++++++ src/game/shared/tf/tf_weapon_bat.h | 1 + 2 files changed, 14 insertions(+) diff --git a/src/game/shared/tf/tf_weapon_bat.cpp b/src/game/shared/tf/tf_weapon_bat.cpp index 5d9bdfe90ee..2e59a22c8fd 100644 --- a/src/game/shared/tf/tf_weapon_bat.cpp +++ b/src/game/shared/tf/tf_weapon_bat.cpp @@ -976,6 +976,19 @@ bool CTFStunBall::ShouldBallTouch( CBaseEntity *pOther ) return true; } +//----------------------------------------------------------------------------- +// Purpose: Baseball was deflected. +//----------------------------------------------------------------------------- +void CTFStunBall::Deflected( CBaseEntity* pDeflectedBy, Vector& vecDir ) +{ + BaseClass::Deflected( pDeflectedBy, vecDir ); + if ( m_pBallTrail ) + { + const char *pTrailTeamName = ( GetTeamNumber() == TF_TEAM_RED ) ? "effects/baseballtrail_red.vmt" : "effects/baseballtrail_blu.vmt"; + m_pBallTrail->SetModel( pTrailTeamName ); + } +} + // -- SERVER ONLY #endif diff --git a/src/game/shared/tf/tf_weapon_bat.h b/src/game/shared/tf/tf_weapon_bat.h index 6bc6bb30337..84a4b91a92d 100644 --- a/src/game/shared/tf/tf_weapon_bat.h +++ b/src/game/shared/tf/tf_weapon_bat.h @@ -157,6 +157,7 @@ class CTFStunBall : public CTFGrenadePipebombProjectile virtual float GetDamage( void ); virtual int GetDamageType( void ) { return DMG_CLUB; } virtual Vector GetDamageForce( void ); + virtual void Deflected( CBaseEntity* pDeflectedBy, Vector& vecDir ) OVERRIDE; virtual float GetShakeAmplitude( void ) { return 0.0; } virtual float GetShakeRadius( void ) { return 0.0; } From 0dcbd60cf75122aa223686794aff695c34333742 Mon Sep 17 00:00:00 2001 From: Thomas Kain Date: Sat, 25 Oct 2025 20:37:15 -0400 Subject: [PATCH 3/7] Consolidate baseball trail texture retrieval logic --- src/game/shared/tf/tf_weapon_bat.cpp | 12 ++++++++---- src/game/shared/tf/tf_weapon_bat.h | 1 + 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/src/game/shared/tf/tf_weapon_bat.cpp b/src/game/shared/tf/tf_weapon_bat.cpp index 2e59a22c8fd..33e8932f179 100644 --- a/src/game/shared/tf/tf_weapon_bat.cpp +++ b/src/game/shared/tf/tf_weapon_bat.cpp @@ -652,6 +652,12 @@ const char *CTFStunBall::GetBallViewModelName( void ) const } +//----------------------------------------------------------------------------- +const char *CTFStunBall::GetTrailEffect( void ) const +{ + return ( GetTeamNumber() == TF_TEAM_RED ) ? "effects/baseballtrail_red.vmt" : "effects/baseballtrail_blu.vmt"; +} + //----------------------------------------------------------------------------- // Purpose: Sets up initial properties. //----------------------------------------------------------------------------- @@ -674,10 +680,9 @@ void CTFStunBall::Spawn( void ) // Draw the trail for the Baseball on spawn if ( !m_pBallTrail ) { - const char *pTrailTeamName = ( GetTeamNumber() == TF_TEAM_RED ) ? "effects/baseballtrail_red.vmt" : "effects/baseballtrail_blu.vmt"; CSpriteTrail *pTempTrail = NULL; - pTempTrail = CSpriteTrail::SpriteTrailCreate( pTrailTeamName, GetAbsOrigin(), true ); + pTempTrail = CSpriteTrail::SpriteTrailCreate( GetTrailEffect(), GetAbsOrigin(), true ); pTempTrail->FollowEntity( this ); pTempTrail->SetTransparency( kRenderTransAlpha, 255, 255, 255, STUNBALL_TRAIL_ALPHA, kRenderFxNone ); pTempTrail->SetStartWidth( 9 ); @@ -984,8 +989,7 @@ void CTFStunBall::Deflected( CBaseEntity* pDeflectedBy, Vector& vecDir ) BaseClass::Deflected( pDeflectedBy, vecDir ); if ( m_pBallTrail ) { - const char *pTrailTeamName = ( GetTeamNumber() == TF_TEAM_RED ) ? "effects/baseballtrail_red.vmt" : "effects/baseballtrail_blu.vmt"; - m_pBallTrail->SetModel( pTrailTeamName ); + m_pBallTrail->SetModel( GetTrailEffect() ); } } diff --git a/src/game/shared/tf/tf_weapon_bat.h b/src/game/shared/tf/tf_weapon_bat.h index 84a4b91a92d..6c1c7aa1aae 100644 --- a/src/game/shared/tf/tf_weapon_bat.h +++ b/src/game/shared/tf/tf_weapon_bat.h @@ -147,6 +147,7 @@ class CTFStunBall : public CTFGrenadePipebombProjectile virtual int GetWeaponID( void ) const { return TF_WEAPON_GRENADE_STUNBALL; } virtual const char *GetBallModelName( void ) const; virtual const char *GetBallViewModelName( void ) const; + const char *GetTrailEffect( void ) const; virtual bool IsAllowedToExplode( void ) OVERRIDE { return false; } virtual void Explode( trace_t *pTrace, int bitsDamageType ); From 422a7a81235bb6763254f9408630e0efbca08470 Mon Sep 17 00:00:00 2001 From: Thomas Kain Date: Sun, 26 Oct 2025 17:47:56 -0400 Subject: [PATCH 4/7] Fix reflected ornaments shattering in the wrong color When a Wrap Assassin's ornament is reflected by an enemy, it changes its color to that of the enemy's team. However, when it shatters, the particles it creates are of the original thrower's team color rather than the reflecting enemy's team color. This means RED ornaments can shatter into BLU shards and vice versa. This commit fixes that. --- src/game/shared/tf/tf_weapon_bat.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/game/shared/tf/tf_weapon_bat.cpp b/src/game/shared/tf/tf_weapon_bat.cpp index 33e8932f179..92f74ba7f18 100644 --- a/src/game/shared/tf/tf_weapon_bat.cpp +++ b/src/game/shared/tf/tf_weapon_bat.cpp @@ -1302,8 +1302,7 @@ void CTFBall_Ornament::VPhysicsCollisionThink( void ) void CTFBall_Ornament::Explode( trace_t *pTrace, int bitsDamageType ) { // Create smashed glass particles when we explode - CTFPlayer* pOwner = ToTFPlayer( GetOwnerEntity() ); - if ( pOwner && pOwner->GetTeamNumber() == TF_TEAM_RED ) + if ( GetTeamNumber() == TF_TEAM_RED ) { DispatchParticleEffect( "xms_ornament_smash_red", GetAbsOrigin(), GetAbsAngles() ); } @@ -1313,6 +1312,7 @@ void CTFBall_Ornament::Explode( trace_t *pTrace, int bitsDamageType ) } Vector vecOrigin = GetAbsOrigin(); + CTFPlayer* pOwner = ToTFPlayer( GetOwnerEntity() ); // sound effects EmitSound_t params; From 64c49d9c1a115cbbb93d8809d6a98c58be77591a Mon Sep 17 00:00:00 2001 From: Thomas Kain Date: Sun, 26 Oct 2025 18:32:49 -0400 Subject: [PATCH 5/7] Play ornament shatter sounds more loudly to reflector when reflected When a Wrap Assassin ornament shatters, it plays a shattering sound. This sound plays at a higher volume to the person who threw the ornament so they know when it breaks. When an enemy reflects an ornament, however, the sound still plays at a higher volume to the original thrower rather than the reflecting enemy, even though the information of when the ornament breaks is more useful to the reflector than the thrower. This commit makes the sound effect play louder to the reflector rather than the thrower when applicable. --- src/game/shared/tf/tf_weapon_bat.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/game/shared/tf/tf_weapon_bat.cpp b/src/game/shared/tf/tf_weapon_bat.cpp index 92f74ba7f18..8f8acce3153 100644 --- a/src/game/shared/tf/tf_weapon_bat.cpp +++ b/src/game/shared/tf/tf_weapon_bat.cpp @@ -1313,6 +1313,14 @@ void CTFBall_Ornament::Explode( trace_t *pTrace, int bitsDamageType ) Vector vecOrigin = GetAbsOrigin(); CTFPlayer* pOwner = ToTFPlayer( GetOwnerEntity() ); + if ( GetDeflected() ) + { + CTFPlayer* pDeflector = ToTFPlayer( GetDeflectOwner() ); + if ( pDeflector ) + { + pOwner = pDeflector; + } + } // sound effects EmitSound_t params; From b47ef87c785d3f1bbf428384f98b97ac3e667118 Mon Sep 17 00:00:00 2001 From: Thomas Kain Date: Thu, 27 Nov 2025 23:28:47 -0500 Subject: [PATCH 6/7] Simplify ornament attacker retrieval logic --- src/game/shared/tf/tf_weapon_bat.cpp | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/src/game/shared/tf/tf_weapon_bat.cpp b/src/game/shared/tf/tf_weapon_bat.cpp index 8f8acce3153..fe44fddcc25 100644 --- a/src/game/shared/tf/tf_weapon_bat.cpp +++ b/src/game/shared/tf/tf_weapon_bat.cpp @@ -1312,15 +1312,7 @@ void CTFBall_Ornament::Explode( trace_t *pTrace, int bitsDamageType ) } Vector vecOrigin = GetAbsOrigin(); - CTFPlayer* pOwner = ToTFPlayer( GetOwnerEntity() ); - if ( GetDeflected() ) - { - CTFPlayer* pDeflector = ToTFPlayer( GetDeflectOwner() ); - if ( pDeflector ) - { - pOwner = pDeflector; - } - } + CTFPlayer* pOwner = ToTFPlayer( GetThrower() ); // sound effects EmitSound_t params; @@ -1338,7 +1330,7 @@ void CTFBall_Ornament::Explode( trace_t *pTrace, int bitsDamageType ) // Do radius damage Vector vecBlastForce(0.0f, 0.0f, 0.0f); - CTakeDamageInfo info( this, GetThrower(), m_hLauncher, vecBlastForce, GetAbsOrigin(), flExplodeDamage, bitsDamageType, TF_DMG_CUSTOM_BASEBALL, &vecOrigin ); + CTakeDamageInfo info( this, pOwner, m_hLauncher, vecBlastForce, GetAbsOrigin(), flExplodeDamage, bitsDamageType, TF_DMG_CUSTOM_BASEBALL, &vecOrigin ); CTFRadiusDamageInfo radiusinfo( &info, vecOrigin, DEFAULT_ORNAMENT_EXPLODE_RADIUS, nullptr, 0.0f, 0.0f ); TFGameRules()->RadiusDamage( radiusinfo ); From c7c62b065c9bfeaf6716887e7a0ba9fef45ff98d Mon Sep 17 00:00:00 2001 From: Thomas Kain Date: Fri, 28 Nov 2025 22:35:47 -0500 Subject: [PATCH 7/7] Replace uses of `GetOwnerEntity` with `GetThrower` for baseballs and ornaments GetOwnerEntity returns the 'owner entity' of the baseball/ornament, which is the player that originally threw it. However, this is used in multiple places where we really want to know who is responsible for the ball's damage (including who may have last reflected it) which is returned by GetThrower. This change should fix reflected baseball/ornament hits and kills being attributed to their original thrower rather than their reflector like other projectiles. --- src/game/shared/tf/tf_weapon_bat.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/game/shared/tf/tf_weapon_bat.cpp b/src/game/shared/tf/tf_weapon_bat.cpp index fe44fddcc25..d4391d7576a 100644 --- a/src/game/shared/tf/tf_weapon_bat.cpp +++ b/src/game/shared/tf/tf_weapon_bat.cpp @@ -720,7 +720,7 @@ void CTFStunBall::ApplyBallImpactEffectOnVictim( CBaseEntity *pOther ) if ( !pPlayer ) return; - CTFPlayer *pOwner = ToTFPlayer( GetOwnerEntity() ); + CTFPlayer *pOwner = ToTFPlayer( GetThrower() ); if ( !pOwner ) return; @@ -782,7 +782,7 @@ void CTFStunBall::ApplyBallImpactEffectOnVictim( CBaseEntity *pOther ) CBaseEntity *pInflictor = GetLauncher(); CTakeDamageInfo info; - info.SetAttacker( GetOwnerEntity() ); + info.SetAttacker( pOwner ); info.SetInflictor( pInflictor ); info.SetWeapon( pInflictor ); info.SetDamage( ( flLifeTimeRatio >= 1.f ) ? GetDamage() * 1.5f : GetDamage() ); @@ -838,7 +838,7 @@ void CTFStunBall::PipebombTouch( CBaseEntity *pOther ) if ( !ShouldBallTouch( pOther ) ) return; - CTFPlayer* pOwner = ToTFPlayer( GetOwnerEntity() ); + CTFPlayer* pOwner = ToTFPlayer( GetThrower() ); if ( !pOwner ) return; @@ -893,7 +893,7 @@ void CTFStunBall::PipebombTouch( CBaseEntity *pOther ) //----------------------------------------------------------------------------- void CTFStunBall::VPhysicsCollision( int index, gamevcollisionevent_t *pEvent ) { - CTFPlayer* pOwner = ToTFPlayer( GetOwnerEntity() ); + CTFPlayer* pOwner = ToTFPlayer( GetThrower() ); bool bWasTouched = m_bTouched; BaseClass::VPhysicsCollision( index, pEvent ); if ( pOwner && !bWasTouched && m_bTouched ) @@ -939,7 +939,7 @@ void CTFStunBall::RemoveBallTrail( void ) //----------------------------------------------------------------------------- bool CTFStunBall::ShouldBallTouch( CBaseEntity *pOther ) { - CTFPlayer* pOwner = ToTFPlayer( GetOwnerEntity() ); + CTFPlayer* pOwner = ToTFPlayer( GetThrower() ); if ( !pOwner ) return false; @@ -1174,7 +1174,7 @@ void CTFBall_Ornament::ApplyBallImpactEffectOnVictim( CBaseEntity *pOther ) if ( !pPlayer ) return; - CTFPlayer *pOwner = ToTFPlayer( GetOwnerEntity() ); + CTFPlayer *pOwner = ToTFPlayer( GetThrower() ); if ( !pOwner ) return; @@ -1210,7 +1210,7 @@ void CTFBall_Ornament::ApplyBallImpactEffectOnVictim( CBaseEntity *pOther ) CBaseEntity *pInflictor = GetLauncher(); CTakeDamageInfo info; - info.SetAttacker( GetOwnerEntity() ); + info.SetAttacker( pOwner ); info.SetInflictor( pInflictor ); info.SetWeapon( pInflictor ); info.SetDamage( GetDamage() );