void CWeaponDrainGrenade::Explode( CBaseCombatCharacter* pAttacker, CBaseEntity* pInflictor, CBaseEntity* pIgnore, Vector vecPosition, float flDamage, float flRadius, float flDrainFocus ) { #if !defined( CLIENT_DLL ) //CSoundEnt::InsertSound ( SOUND_COMBAT, vecPosition, 1024, 3.0 ); CTakeDamageInfo info; info.CFSet( pInflictor, pAttacker, vec3_origin, vecPosition, flDamage, DMG_BLAST, WEAPON_NONE, &vecPosition, false ); info.SetDrainFocus( flDrainFocus ); DispatchParticleEffect("grenade_explosion", vecPosition, vec3_angle, pIgnore); //TODO: Figure out sound. CPASAttenuationFilter filter( this ); filter.UsePredictionRules(); EmitSound( filter, entindex(), "Numen.FireAoE" ); //CSoundEnt::InsertSound ( SOUND_COMBAT, GetAbsOrigin(), BASEGRENADE_EXPLOSION_VOLUME, 3.0 ); RadiusDamage( info, vecPosition, flRadius ); #endif //!defined( CLIENT_DLL ) }
void CWeaponDrainGrenade::RadiusDamage( const CTakeDamageInfo &inputInfo, const Vector &vecSrcIn, float flRadius ) { CTakeDamageInfo info = inputInfo; CBaseEntity *pEntity = NULL; trace_t tr; float flAdjustedDamage, falloff; Vector vecSpot; Vector vecToTarget; Vector vecEndPos; Vector vecSrc = vecSrcIn; if ( flRadius ) falloff = info.GetDamage() / flRadius; else falloff = 1.0; int bInWater = (UTIL_PointContents ( vecSrc ) & MASK_WATER) ? true : false; vecSrc.z += 1;// in case grenade is lying on the ground // iterate on all entities in the vicinity. for ( CEntitySphereQuery sphere( vecSrc, flRadius ); ( pEntity = sphere.GetCurrentEntity() ) != NULL; sphere.NextEntity() ) { if (!pEntity || !ToCFPlayer(pEntity)) continue; // Don't drain teammates. if (CFGameRules()->PlayerRelationship(GetThrower(), pEntity) == GR_TEAMMATE && ToCFPlayer(pEntity) != ToCFPlayer(GetThrower())) continue; if ( !pEntity->IsAlive() ) continue; if ( pEntity->m_takedamage != DAMAGE_NO ) { // blast's don't tavel into or out of water if (bInWater && pEntity->GetWaterLevel() == 0) continue; if (!bInWater && pEntity->GetWaterLevel() == 3) continue; // radius damage can only be blocked by the world vecSpot = pEntity->BodyTarget( vecSrc ); bool bHit = false; UTIL_TraceLine( vecSrc, vecSpot, MASK_SOLID_BRUSHONLY, info.GetInflictor(), COLLISION_GROUP_NONE, &tr ); if (tr.startsolid) { // if we're stuck inside them, fixup the position and distance tr.endpos = vecSrc; tr.fraction = 0.0; } vecEndPos = tr.endpos; if( tr.fraction == 1.0 || tr.m_pEnt == pEntity ) { bHit = true; } if ( bHit ) { // the explosion can 'see' this entity, so hurt them! vecToTarget = ( vecEndPos - vecSrc ); // decrease damage for an ent that's farther from the blast's center. flAdjustedDamage = vecToTarget.Length() * falloff; flAdjustedDamage = info.GetDrainFocus() - flAdjustedDamage; if ( flAdjustedDamage > 0 ) { CTakeDamageInfo adjustedInfo = info; adjustedInfo.SetDrainFocus( flAdjustedDamage ); Vector dir = vecToTarget; VectorNormalize( dir ); // If we don't have a damage force, manufacture one if ( adjustedInfo.GetDamagePosition() == vec3_origin || adjustedInfo.GetDamageForce() == vec3_origin ) { CalculateExplosiveDamageForce( &adjustedInfo, dir, vecSrc, 1.5 /* explosion scale! */ ); } else { // Assume the force passed in is the maximum force. Decay it based on falloff. float flForce = adjustedInfo.GetDamageForce().Length() * falloff; adjustedInfo.SetDamageForce( dir * flForce ); adjustedInfo.SetDamagePosition( vecSrc ); } float flFocusDrained = adjustedInfo.GetDrainFocus(); float& flFocus = ToCFPlayer(pEntity)->m_pStats->m_flFocus.GetForModify(); if (flFocus > cf_minfocusdrain.GetFloat()) flFocus -= flFocusDrained; if (flFocus < cf_minfocusdrain.GetFloat()) flFocus = cf_minfocusdrain.GetFloat(); CEffectData data; data.m_nHitBox = GetParticleSystemIndex( "grenade_drained" ); data.m_vOrigin = ToCFPlayer(pEntity)->GetCentroid(); data.m_vStart = vecSrc; data.m_vAngles = QAngle(0,0,0); data.m_nEntIndex = pEntity->entindex(); data.m_fFlags |= PARTICLE_DISPATCH_FROM_ENTITY; data.m_nDamageType = PATTACH_CUSTOMORIGIN; DispatchEffect( "ParticleEffect", data ); // Now hit all triggers along the way that respond to damage... pEntity->TraceAttackToTriggers( adjustedInfo, vecSrc, vecEndPos, dir ); } } } } }