diff options
Diffstat (limited to 'game/client/tf/c_tf_projectile_arrow.cpp')
| -rw-r--r-- | game/client/tf/c_tf_projectile_arrow.cpp | 375 |
1 files changed, 375 insertions, 0 deletions
diff --git a/game/client/tf/c_tf_projectile_arrow.cpp b/game/client/tf/c_tf_projectile_arrow.cpp new file mode 100644 index 0000000..67c8685 --- /dev/null +++ b/game/client/tf/c_tf_projectile_arrow.cpp @@ -0,0 +1,375 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +//============================================================================= + +#include "cbase.h" +#include "c_tf_projectile_arrow.h" +#include "particles_new.h" +#include "SpriteTrail.h" +#include "c_tf_player.h" +#include "collisionutils.h" +#include "util_shared.h" +#include "c_rope.h" + +//----------------------------------------------------------------------------- +IMPLEMENT_NETWORKCLASS_ALIASED( TFProjectile_Arrow, DT_TFProjectile_Arrow ) + +BEGIN_NETWORK_TABLE( C_TFProjectile_Arrow, DT_TFProjectile_Arrow ) + RecvPropBool( RECVINFO( m_bArrowAlight ) ), + RecvPropBool( RECVINFO( m_bCritical ) ), + RecvPropInt( RECVINFO( m_iProjectileType ) ), +END_NETWORK_TABLE() + +//----------------------------------------------------------------------------- +IMPLEMENT_NETWORKCLASS_ALIASED( TFProjectile_HealingBolt, DT_TFProjectile_HealingBolt ) + +BEGIN_NETWORK_TABLE( C_TFProjectile_HealingBolt, DT_TFProjectile_HealingBolt ) +END_NETWORK_TABLE() + +IMPLEMENT_NETWORKCLASS_ALIASED( TFProjectile_GrapplingHook, DT_TFProjectile_GrapplingHook ) + +BEGIN_NETWORK_TABLE( C_TFProjectile_GrapplingHook, DT_TFProjectile_GrapplingHook ) +END_NETWORK_TABLE() + +#define NEAR_MISS_THRESHOLD 120 + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_TFProjectile_Arrow::C_TFProjectile_Arrow( void ) +{ + m_fAttachTime = 0.f; + m_nextNearMissCheck = 0.f; + m_bNearMiss = false; + m_bArrowAlight = false; + m_bCritical = true; + m_pCritEffect = NULL; + m_iCachedDeflect = false; + m_flLifeTime = 40.0f; +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +C_TFProjectile_Arrow::~C_TFProjectile_Arrow( void ) +{ +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_TFProjectile_Arrow::OnDataChanged( DataUpdateType_t updateType ) +{ + if ( updateType == DATA_UPDATE_CREATED ) + { + SetNextClientThink( CLIENT_THINK_ALWAYS ); + +#ifdef STAGING_ONLY + if ( m_iProjectileType == TF_PROJECTILE_SNIPERBULLET ) + { + switch ( GetTeamNumber() ) + { + case TF_TEAM_BLUE: + ParticleProp()->Create( "bullet_distortion_trail", PATTACH_ABSORIGIN_FOLLOW ); + break; + case TF_TEAM_RED: + ParticleProp()->Create( "bullet_distortion_trail", PATTACH_ABSORIGIN_FOLLOW ); + break; + } + } + else if ( m_bArrowAlight ) +#else + if ( m_bArrowAlight ) +#endif // STAGING_ONLY + { + ParticleProp()->Create( "flying_flaming_arrow", PATTACH_POINT_FOLLOW, "muzzle" ); + } + } + if ( m_bCritical ) + { + if ( updateType == DATA_UPDATE_CREATED || m_iCachedDeflect != GetDeflected() ) + { + CreateCritTrail(); + } + } + m_iCachedDeflect = GetDeflected(); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_TFProjectile_Arrow::NotifyBoneAttached( C_BaseAnimating* attachTarget ) +{ + BaseClass::NotifyBoneAttached( attachTarget ); + + m_fAttachTime = gpGlobals->curtime; + SetNextClientThink( CLIENT_THINK_ALWAYS ); +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_TFProjectile_Arrow::ClientThink( void ) +{ + // Perform a near-miss check. + if ( !m_bNearMiss && (gpGlobals->curtime > m_nextNearMissCheck) ) + { + CheckNearMiss(); + m_nextNearMissCheck = gpGlobals->curtime + 0.05f; + } + + // Remove crit effect if we hit a wall. + if ( GetMoveType() == MOVETYPE_NONE && m_pCritEffect ) + { + ParticleProp()->StopEmission( m_pCritEffect ); + m_pCritEffect = NULL; + } + + BaseClass::ClientThink(); + + // DO THIS LAST: Destroy us automatically after a period of time. + if ( m_pAttachedTo ) + { + if ( gpGlobals->curtime - m_fAttachTime > m_flLifeTime ) + { + Release(); + return; + } + else if ( m_pAttachedTo->IsEffectActive( EF_NODRAW ) && !IsEffectActive( EF_NODRAW ) ) + { + AddEffects( EF_NODRAW ); + UpdateVisibility(); + } + else if ( !m_pAttachedTo->IsEffectActive( EF_NODRAW ) && IsEffectActive( EF_NODRAW ) && (m_pAttachedTo != C_BasePlayer::GetLocalPlayer()) ) + { + RemoveEffects( EF_NODRAW ); + UpdateVisibility(); + } + } + + if ( IsDormant() && !IsEffectActive( EF_NODRAW ) ) + { + AddEffects( EF_NODRAW ); + UpdateVisibility(); + } +} + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_TFProjectile_Arrow::CheckNearMiss( void ) +{ + // Check against the local player. If we're near him play a near miss sound. + C_TFPlayer *pLocalPlayer = C_TFPlayer::GetLocalTFPlayer(); + if ( !pLocalPlayer || !pLocalPlayer->IsAlive() ) + return; + + // If we are attached to something or stationary we don't want to do near miss checks. + if ( m_pAttachedTo || (GetMoveType() == MOVETYPE_NONE) ) + { + m_bNearMiss = true; + return; + } + + // Can't hear near miss sounds from friendly arrows. + if ( pLocalPlayer->GetTeamNumber() == GetTeamNumber() ) + return; + + Vector vecPlayerPos = pLocalPlayer->GetAbsOrigin(); + Vector vecArrowPos = GetAbsOrigin(), forward; + AngleVectors( GetAbsAngles(), &forward ); + Vector vecArrowDest = GetAbsOrigin() + forward * 200.f; + + // If the arrow is moving away from the player just stop checking. + float dist1 = vecArrowPos.DistToSqr( vecPlayerPos ); + float dist2 = vecArrowDest.DistToSqr( vecPlayerPos ); + if ( dist2 > dist1 ) + { + m_bNearMiss = true; + return; + } + + // Check to see if the arrow is passing near the player. + Vector vecClosestPoint; + float dist; + CalcClosestPointOnLineSegment( vecPlayerPos, vecArrowPos, vecArrowDest, vecClosestPoint, &dist ); + dist = vecPlayerPos.DistTo( vecClosestPoint ); + if ( dist > NEAR_MISS_THRESHOLD ) + return; + + // The arrow is passing close to the local player. + m_bNearMiss = true; + SetNextClientThink( CLIENT_THINK_NEVER ); + + // If the arrow is about to hit something, don't play the sound and stop this check. + trace_t tr; + UTIL_TraceLine( vecArrowPos, vecArrowPos + forward * 400.f, CONTENTS_HITBOX|CONTENTS_MONSTER|CONTENTS_SOLID, this, COLLISION_GROUP_NONE, &tr ); + if ( tr.DidHit() ) + return; + + // We're good for a near miss! + float soundlen = 0; + EmitSound_t params; + params.m_flSoundTime = 0; + params.m_pSoundName = "Weapon_Arrow.Nearmiss"; + params.m_pflSoundDuration = &soundlen; + CSingleUserRecipientFilter localFilter( pLocalPlayer ); + EmitSound( localFilter, pLocalPlayer->entindex(), params ); +} + + +//----------------------------------------------------------------------------- +// Purpose: +//----------------------------------------------------------------------------- +void C_TFProjectile_Arrow::CreateCritTrail( void ) +{ + if ( IsDormant() ) + return; + + if ( m_pCritEffect ) + { + ParticleProp()->StopEmission( m_pCritEffect ); + m_pCritEffect = NULL; + } + + if ( m_bCritical ) + { + switch( GetTeamNumber() ) + { + case TF_TEAM_BLUE: + m_pCritEffect = ParticleProp()->Create( "critical_rocket_blue", PATTACH_ABSORIGIN_FOLLOW ); + break; + case TF_TEAM_RED: + m_pCritEffect = ParticleProp()->Create( "critical_rocket_red", PATTACH_ABSORIGIN_FOLLOW ); + break; + default: + break; + } + } +} + +//----------------------------------------------------------------------------- +void C_TFProjectile_HealingBolt::OnDataChanged( DataUpdateType_t updateType ) +{ + if ( updateType == DATA_UPDATE_CREATED ) + { + switch( GetTeamNumber() ) + { + case TF_TEAM_BLUE: + ParticleProp()->Create( "healshot_trail_blue", PATTACH_ABSORIGIN_FOLLOW ); + break; + case TF_TEAM_RED: + ParticleProp()->Create( "healshot_trail_red", PATTACH_ABSORIGIN_FOLLOW ); + break; + } + } + + BaseClass::OnDataChanged( updateType ); +} + + +void C_TFProjectile_GrapplingHook::OnDataChanged( DataUpdateType_t updateType ) +{ + BaseClass::OnDataChanged( updateType ); + + if ( updateType == DATA_UPDATE_CREATED ) + { + int nTeam = GetTeamNumber(); + C_TFPlayer *pTFPlayer = ToTFPlayer( GetOwnerEntity() ); + if ( pTFPlayer && pTFPlayer->IsPlayerClass( TF_CLASS_SPY ) && pTFPlayer->m_Shared.InCond( TF_COND_DISGUISED ) && pTFPlayer->GetTeamNumber() != GetLocalPlayerTeam() ) + { + nTeam = pTFPlayer->m_Shared.GetDisguiseTeam(); + } + + const char *pszMaterialName = "cable/cable"; + switch ( nTeam ) + { + case TF_TEAM_BLUE: + pszMaterialName = "cable/cable_blue"; + break; + case TF_TEAM_RED: + pszMaterialName = "cable/cable_red"; + break; + } + + C_BaseEntity *pStartEnt = GetOwnerEntity(); + int iAttachment = 0; + + if ( pTFPlayer ) + { + CTFWeaponBase *pWeapon = assert_cast< CTFWeaponBase* >( pTFPlayer->GetActiveWeapon() ); + if ( pWeapon ) + { + pStartEnt = pWeapon; + int iMuzzle = pWeapon->LookupAttachment( "muzzle" ); + if ( iMuzzle != -1 ) + { + iAttachment = iMuzzle; + } + } + } + + int iHookAttachment = LookupAttachment( "rope_locator" ); + if ( iHookAttachment == -1 ) + iHookAttachment = 0; + + m_hRope = C_RopeKeyframe::Create( pStartEnt, this, iAttachment, iHookAttachment, 2, pszMaterialName ); + + SetNextClientThink( CLIENT_THINK_ALWAYS ); + } +} + + +void C_TFProjectile_GrapplingHook::UpdateOnRemove() +{ + RemoveRope(); + + BaseClass::UpdateOnRemove(); +} + + +void C_TFProjectile_GrapplingHook::ClientThink() +{ + UpdateRope(); +} + + +void C_TFProjectile_GrapplingHook::UpdateRope() +{ + C_TFPlayer *pTFPlayer = ToTFPlayer( GetOwnerEntity() ); + if ( !pTFPlayer || !pTFPlayer->IsAlive() ) + { + RemoveRope(); + return; + } + + Vector vecStart = pTFPlayer->WorldSpaceCenter(); + if ( pTFPlayer->GetActiveWeapon() ) + { + int iAttachment = pTFPlayer->GetActiveWeapon()->LookupAttachment( "muzzle" ); + if ( iAttachment != -1 ) + { + GetAttachment( iAttachment, vecStart ); + } + } + + float flDist = vecStart.DistTo( WorldSpaceCenter() ); + + if ( m_hRope ) + { + float flHangDist = pTFPlayer->GetGrapplingHookTarget() ? 0.1f * flDist : 1.5f * flDist; + assert_cast< C_RopeKeyframe* >( m_hRope.Get() )->SetupHangDistance( flHangDist ); + } +} + + +void C_TFProjectile_GrapplingHook::RemoveRope() +{ + if ( m_hRope ) + { + m_hRope->Release(); + m_hRope = NULL; + } +} |