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<C_BasePlayer *>(pEnt); if ( pPlayer && pPlayer->GetActiveWeapon() ) { C_BaseCombatWeapon *pWpn = dynamic_cast<C_BaseCombatWeapon *>( 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++; } } } } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CUnitBase::FireBullets( const FireBulletsInfo_t &info ) { VPROF_BUDGET( "CUnitBase::FireBullets", VPROF_BUDGETGROUP_UNITS ); static int tracerCount; trace_t tr; CAmmoDef* pAmmoDef = GetAmmoDef(); int nDamageType = pAmmoDef->DamageType(info.m_iAmmoType); //int nAmmoFlags = pAmmoDef->Flags(info.m_iAmmoType); int iNumShots; float flActualDamage; // the default attacker is ourselves CBaseEntity *pAttacker = info.m_pAttacker ? info.m_pAttacker : this; ClearMultiDamage(); g_MultiDamage.SetDamageType( nDamageType | DMG_NEVERGIB ); Vector vecDir; Vector vecEnd; // Adjust spread to accuracy Vector vecSpread( info.m_vecSpread ); //vecSpread.x = sin( ( (asin( info.m_vecSpread.x ) * 2.0f) * m_fAccuracy ) / 2.0f ); //vecSpread.y = sin( ( (asin( info.m_vecSpread.y ) * 2.0f) * m_fAccuracy ) / 2.0f ); //vecSpread.z = sin( ( (asin( info.m_vecSpread.z ) * 2.0f) * m_fAccuracy ) / 2.0f ); // Skip multiple entities when tracing CWarsBulletsFilter traceFilter( this, COLLISION_GROUP_NONE ); traceFilter.SetPassEntity( this ); // Standard pass entity for THIS so that it can be easily removed from the list after passing through a portal traceFilter.AddEntityToIgnore( info.m_pAdditionalIgnoreEnt ); CShotManipulator Manipulator( info.m_vecDirShooting ); iNumShots = info.m_iShots; flActualDamage = info.m_flDamage; if ( flActualDamage == 0.0 ) { flActualDamage = g_pGameRules->GetAmmoDamage( pAttacker, tr.m_pEnt, info.m_iAmmoType ); } flActualDamage *= m_fAccuracy; // Pretty much a damage modifier for (int iShot = 0; iShot < iNumShots; iShot++) { //vecDir = info.m_vecDirShooting; vecDir = Manipulator.ApplySpread( vecSpread ); vecEnd = info.m_vecSrc + vecDir * info.m_flDistance; AI_TraceLine(info.m_vecSrc, vecEnd, MASK_SHOT, &traceFilter, &tr); if( unit_debugfirebullets.GetBool() ) { #ifdef CLIENT_DLL NDebugOverlay::Line(info.m_vecSrc, vecEnd, 255, 0, 0, 255, 0.1f); NDebugOverlay::Line(info.m_vecSrc, tr.endpos, 0, 255, 0, 255, 0.1f); #else NDebugOverlay::Line(info.m_vecSrc, vecEnd, 255, 255, 0, 255, 0.1f); NDebugOverlay::Line(info.m_vecSrc, tr.endpos, 0, 255, 255, 255, 0.1f); #endif // CLIENT_DLL } // Make sure given a valid bullet type if (info.m_iAmmoType == -1) { DevMsg("ERROR: Undefined ammo type!\n"); return; } Vector vecTracerDest = tr.endpos; // do damage, paint decals if (tr.fraction != 1.0) { CTakeDamageInfo dmgInfo( pAttacker, pAttacker, flActualDamage, nDamageType ); CalculateBulletDamageForce( &dmgInfo, info.m_iAmmoType, vecDir, tr.endpos ); dmgInfo.ScaleDamageForce( info.m_flDamageForceScale ); dmgInfo.SetAmmoType( info.m_iAmmoType ); (dynamic_cast<CBaseEntity *>(tr.m_pEnt))->DispatchTraceAttack( dmgInfo, vecDir, &tr ); // Effects only, FireBullets should be called on the client. // Dispatching on the server generates far too many events/data! #ifdef CLIENT_DLL DoImpactEffect( tr, nDamageType ); Vector vecTracerSrc = vec3_origin; ComputeTracerStartPosition( info.m_vecSrc, &vecTracerSrc ); trace_t Tracer; Tracer = tr; Tracer.endpos = vecTracerDest; MakeTracer( vecTracerSrc, Tracer, pAmmoDef->TracerType(info.m_iAmmoType) ); #endif // CLIENT_DLL } } #ifdef GAME_DLL ApplyMultiDamage(); #endif // GAME_DLL }