//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // //=============================================================================// #include "cbase.h" #include "c_basetempentity.h" #include #include "ammodef.h" #include "c_te_effect_dispatch.h" #include "shot_manipulator.h" class C_TEHL2MPFireBullets : public C_BaseTempEntity { public: DECLARE_CLASS( C_TEHL2MPFireBullets, C_BaseTempEntity ); DECLARE_CLIENTCLASS(); virtual void PostDataUpdate( DataUpdateType_t updateType ); void CreateEffects( void ); public: int m_iPlayer; Vector m_vecOrigin; Vector m_vecDir; int m_iAmmoID; int m_iWeaponIndex; int m_iSeed; float m_flSpread; int m_iShots; bool m_bDoImpacts; bool m_bDoTracers; }; class CTraceFilterSkipPlayerAndViewModelOnly : public CTraceFilter { public: virtual bool ShouldHitEntity( IHandleEntity *pServerEntity, int contentsMask ) { C_BaseEntity *pEntity = EntityFromEntityHandle( pServerEntity ); if( pEntity && ( ( dynamic_cast( pEntity ) != NULL ) || ( dynamic_cast( pEntity ) != NULL ) ) ) { return false; } else { return true; } } }; void C_TEHL2MPFireBullets::CreateEffects( void ) { CAmmoDef* pAmmoDef = GetAmmoDef(); if ( pAmmoDef == NULL ) return; C_BaseEntity *pEnt = ClientEntityList().GetEnt( m_iPlayer ); if ( pEnt ) { C_BasePlayer *pPlayer = dynamic_cast(pEnt); if ( pPlayer && pPlayer->GetActiveWeapon() ) { C_BaseCombatWeapon *pWpn = dynamic_cast( pPlayer->GetActiveWeapon() ); if ( pWpn ) { int iSeed = m_iSeed; CShotManipulator Manipulator( m_vecDir ); for (int iShot = 0; iShot < m_iShots; iShot++) { RandomSeed( iSeed ); // init random system with this seed // Don't run the biasing code for the player at the moment. Vector vecDir = Manipulator.ApplySpread( Vector( m_flSpread, m_flSpread, m_flSpread ) ); Vector vecEnd = m_vecOrigin + vecDir * MAX_TRACE_LENGTH; trace_t tr; CTraceFilterSkipPlayerAndViewModelOnly traceFilter; if( m_iShots > 1 && iShot % 2 ) { // Half of the shotgun pellets are hulls that make it easier to hit targets with the shotgun. UTIL_TraceHull( m_vecOrigin, vecEnd, Vector( -3, -3, -3 ), Vector( 3, 3, 3 ), MASK_SHOT, &traceFilter, &tr ); } else { UTIL_TraceLine( m_vecOrigin, vecEnd, MASK_SHOT, &traceFilter, &tr); } if ( m_bDoTracers ) { const char *pTracerName = pWpn->GetTracerType(); CEffectData data; data.m_vStart = tr.startpos; data.m_vOrigin = tr.endpos; data.m_hEntity = pWpn->GetRefEHandle(); data.m_flScale = 0.0f; data.m_fFlags |= TRACER_FLAG_USEATTACHMENT; // Stomp the start, since it's not going to be used anyway data.m_nAttachmentIndex = 1; if ( pTracerName ) { DispatchEffect( pTracerName, data ); } else { DispatchEffect( "Tracer", data ); } } if ( m_bDoImpacts ) { pWpn->DoImpactEffect( tr, pAmmoDef->DamageType( m_iAmmoID ) ); } iSeed++; } } } } } void C_TEHL2MPFireBullets::PostDataUpdate( DataUpdateType_t updateType ) { if ( m_bDoTracers || m_bDoImpacts ) { CreateEffects(); } } IMPLEMENT_CLIENTCLASS_EVENT( C_TEHL2MPFireBullets, DT_TEHL2MPFireBullets, CTEHL2MPFireBullets ); BEGIN_RECV_TABLE_NOBASE(C_TEHL2MPFireBullets, DT_TEHL2MPFireBullets ) RecvPropVector( RECVINFO( m_vecOrigin ) ), RecvPropVector( RECVINFO( m_vecDir ) ), RecvPropInt( RECVINFO( m_iAmmoID ) ), RecvPropInt( RECVINFO( m_iSeed ) ), RecvPropInt( RECVINFO( m_iShots ) ), RecvPropInt( RECVINFO( m_iPlayer ) ), RecvPropInt( RECVINFO( m_iWeaponIndex ) ), RecvPropFloat( RECVINFO( m_flSpread ) ), RecvPropBool( RECVINFO( m_bDoImpacts ) ), RecvPropBool( RECVINFO( m_bDoTracers ) ), END_RECV_TABLE()