void CNPC_Hornet::DieTouch ( CBaseEntity *pOther ) { if ( !pOther || !pOther->IsSolid() || pOther->IsSolidFlagSet(FSOLID_VOLUME_CONTENTS) ) { return; } CPASAttenuationFilter filter( this ); switch (random->RandomInt(0,2)) {// buzz when you plug someone case 0: enginesound->EmitSound( filter, entindex(), CHAN_VOICE, "hornet/ag_hornethit1.wav", 1, ATTN_NORM ); break; case 1: enginesound->EmitSound( filter, entindex(), CHAN_VOICE, "hornet/ag_hornethit2.wav", 1, ATTN_NORM ); break; case 2: enginesound->EmitSound( filter, entindex(), CHAN_VOICE, "hornet/ag_hornethit3.wav", 1, ATTN_NORM ); break; } CTakeDamageInfo info( this, GetOwnerEntity(), m_flDamage, DMG_BULLET ); CalculateBulletDamageForce( &info, GetAmmoDef()->Index("Hornet"), GetAbsVelocity(), GetAbsOrigin() ); pOther->TakeDamage( info ); m_takedamage = DAMAGE_NO; m_fEffects |= EF_NODRAW; AddSolidFlags( FSOLID_NOT_SOLID );// intangible UTIL_Relink( this ); UTIL_Remove( this ); SetTouch( NULL ); }
void CSquidSpit::Touch ( CBaseEntity *pOther ) { trace_t tr; int iPitch; if ( pOther->GetSolidFlags() & FSOLID_TRIGGER ) return; if ( pOther->GetCollisionGroup() == HL2COLLISION_GROUP_SPIT) { return; } // splat sound iPitch = random->RandomFloat( 90, 110 ); EmitSound( "NPC_BigMomma.SpitTouch1" ); switch ( random->RandomInt( 0, 1 ) ) { case 0: EmitSound( "NPC_BigMomma.SpitHit1" ); break; case 1: EmitSound( "NPC_BigMomma.SpitHit2" ); break; } if ( !pOther->m_takedamage ) { // make a splat on the wall UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + GetAbsVelocity() * 10, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr ); UTIL_DecalTrace(&tr, "BeerSplash" ); // make some flecks CPVSFilter filter( tr.endpos ); te->SpriteSpray( filter, 0.0, &tr.endpos, &tr.plane.normal, m_nSquidSpitSprite, 30, 8, 5 ); } else { CTakeDamageInfo info( this, this, sk_bullsquid_dmg_spit.GetFloat(), DMG_BULLET ); CalculateBulletDamageForce( &info, GetAmmoDef()->Index("9mmRound"), GetAbsVelocity(), GetAbsOrigin() ); pOther->TakeDamage( info ); } UTIL_Remove( m_hSprite ); UTIL_Remove( this ); }
//----------------------------------------------------------------------------- // Purpose: Try and guess the physics force to use. // This shouldn't be used for any damage where the damage force is unknown. // i.e. only use it for mapmaker specified damages. //----------------------------------------------------------------------------- void GuessDamageForce( CTakeDamageInfo *info, const Vector &vecForceDir, const Vector &vecForceOrigin, float flScale ) { if ( info->GetDamageType() & DMG_BULLET ) { CalculateBulletDamageForce( info, GetAmmoDef()->Index("SMG1"), vecForceDir, vecForceOrigin, flScale ); } else if ( info->GetDamageType() & DMG_BLAST ) { CalculateExplosiveDamageForce( info, vecForceDir, vecForceOrigin, flScale ); } else { CalculateMeleeDamageForce( info, vecForceDir, vecForceOrigin, flScale ); } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CBasePlasmaProjectile::MissileTouch( CBaseEntity *pOther ) { Assert( pOther ); if ( !pOther->IsSolid() ) return; // Create a plasma effect trace_t tr; Vector velDir = GetAbsVelocity(); VectorNormalize( velDir ); Vector vecSpot = GetLocalOrigin() - velDir * 32; // First, just clip to the box Ray_t ray; ray.Init( vecSpot, vecSpot + velDir * 64 ); enginetrace->ClipRayToEntity( ray, MASK_SHOT, pOther, &tr ); // Create the appropriate impact bool bHurtTarget = ( !InSameTeam( pOther ) && pOther->m_takedamage != DAMAGE_NO ); WeaponImpact( &tr, velDir, bHurtTarget, pOther, GetDamageType() ); #if !defined( CLIENT_DLL ) CBaseEntity *pOwner = m_hOwner; // Do damage (unless I'm explosive, in which case I'll do damage later) if ( m_flDamage && !m_flExplosiveRadius ) { ClearMultiDamage(); // Assume it's a projectile, so use its velocity instead Vector vecDamageOrigin = GetAbsVelocity(); VectorNormalize( vecDamageOrigin ); vecDamageOrigin = GetAbsOrigin() - (vecDamageOrigin * 32); CTakeDamageInfo info( this, pOwner, m_flDamage, m_DamageType ); CalculateBulletDamageForce( &info, GetAmmoDef()->Index("MediumRound"), GetAbsVelocity(), vecDamageOrigin ); pOther->DispatchTraceAttack( info, velDir, &tr ); ApplyMultiDamage(); } #endif Detonate(); }
void CNPC_Hornet::DieTouch ( CBaseEntity *pOther ) { if ( !pOther || !pOther->IsSolid() || pOther->IsSolidFlagSet(FSOLID_VOLUME_CONTENTS) ) { return; } CPASAttenuationFilter filter( this ); EmitSound( filter, entindex(), "Hornet.Die" ); CTakeDamageInfo info( this, GetOwnerEntity(), m_flDamage, DMG_BULLET ); CalculateBulletDamageForce( &info, GetAmmoDef()->Index("Hornet"), GetAbsVelocity(), GetAbsOrigin() ); pOther->TakeDamage( info ); m_takedamage = DAMAGE_NO; AddEffects( EF_NODRAW ); AddSolidFlags( FSOLID_NOT_SOLID );// intangible UTIL_Remove( this ); SetTouch( NULL ); }
//========================================================= // Disparo //========================================================= void CWeaponGaussGun::Fire() { CBasePlayer *pOwner = ToBasePlayer(GetOwner()); // ¿El jugador no ha sido creado? if ( !pOwner ) return; m_bCharging = false; if ( m_hViewModel == NULL ) { CBaseViewModel *vm = pOwner->GetViewModel(); if ( vm ) m_hViewModel.Set(vm); } Vector startPos = pOwner->Weapon_ShootPosition(); Vector aimDir = pOwner->GetAutoaimVector(AUTOAIM_5DEGREES); Vector vecUp, vecRight; VectorVectors(aimDir, vecRight, vecUp); float x, y, z; //Gassian spread do { x = random->RandomFloat(-0.5,0.5) + random->RandomFloat(-0.5,0.5); y = random->RandomFloat(-0.5,0.5) + random->RandomFloat(-0.5,0.5); z = x*x+y*y; } while (z > 1); aimDir = aimDir + x * GetBulletSpread().x * vecRight + y * GetBulletSpread().y * vecUp; Vector endPos = startPos + (aimDir * MAX_TRACE_LENGTH); // Shoot a shot straight out trace_t tr; UTIL_TraceLine(startPos, endPos, MASK_SHOT, pOwner, COLLISION_GROUP_NONE, &tr); #ifndef CLIENT_DLL ClearMultiDamage(); CBaseEntity *pHit = tr.m_pEnt; CTakeDamageInfo dmgInfo(this, pOwner, sk_plr_dmg_gauss.GetFloat(), DMG_SHOCK | DMG_DISSOLVE); if ( pHit != NULL ) { CalculateBulletDamageForce(&dmgInfo, m_iPrimaryAmmoType, aimDir, tr.endpos); pHit->DispatchTraceAttack(dmgInfo, aimDir, &tr); } if ( tr.DidHitWorld() ) { float hitAngle = -DotProduct( tr.plane.normal, aimDir ); if ( hitAngle < 0.5f ) { Vector vReflection; vReflection = 2.0 * tr.plane.normal * hitAngle + aimDir; startPos = tr.endpos; endPos = startPos + (vReflection * MAX_TRACE_LENGTH); // Draw beam to reflection point DrawBeam(tr.startpos, tr.endpos, 15, true); CPVSFilter filter(tr.endpos); te->GaussExplosion(filter, 0.0f, tr.endpos, tr.plane.normal, 0); UTIL_ImpactTrace(&tr, GetAmmoDef()->DamageType(m_iPrimaryAmmoType), "ImpactGauss"); //Find new reflection end position UTIL_TraceLine(startPos, endPos, MASK_SHOT, pOwner, COLLISION_GROUP_NONE, &tr); if ( tr.m_pEnt != NULL ) { dmgInfo.SetDamageForce(GetAmmoDef()->DamageForce(m_iPrimaryAmmoType) * vReflection); dmgInfo.SetDamagePosition(tr.endpos); tr.m_pEnt->DispatchTraceAttack(dmgInfo, vReflection, &tr); } // Connect reflection point to end DrawBeam(tr.startpos, tr.endpos, 10); } else DrawBeam(tr.startpos, tr.endpos, 15, true); } else DrawBeam(tr.startpos, tr.endpos, 15, true); ApplyMultiDamage(); #endif UTIL_ImpactTrace(&tr, GetAmmoDef()->DamageType(m_iPrimaryAmmoType), "ImpactGauss"); CPVSFilter filter(tr.endpos); te->GaussExplosion(filter, 0.0f, tr.endpos, tr.plane.normal, 0); m_flNextSecondaryAttack = gpGlobals->curtime + 0.5f; AddViewKick(); // Register a muzzleflash for the AI #ifndef CLIENT_DLL pOwner->SetMuzzleFlashTime(gpGlobals->curtime + 0.5); #endif }
void CSDKPlayer::FireBullet( Vector vecSrc, // shooting postion const QAngle &shootAngles, //shooting angle float vecSpread, // spread vector int iDamage, // base damage int iBulletType, // ammo type CBaseEntity *pevAttacker, // shooter bool bDoEffects, // create impact effect ? float x, // spread x factor float y // spread y factor ) { float fCurrentDamage = iDamage; // damage of the bullet at it's current trajectory float flCurrentDistance = 0.0; //distance that the bullet has traveled so far Vector vecDirShooting, vecRight, vecUp; AngleVectors( shootAngles, &vecDirShooting, &vecRight, &vecUp ); if ( !pevAttacker ) pevAttacker = this; // the default attacker is ourselves // add the spray Vector vecDir = vecDirShooting + x * vecSpread * vecRight + y * vecSpread * vecUp; VectorNormalize( vecDir ); float flMaxRange = 8000; Vector vecEnd = vecSrc + vecDir * flMaxRange; // max bullet range is 10000 units trace_t tr; // main enter bullet trace UTIL_TraceLine( vecSrc, vecEnd, MASK_SOLID|CONTENTS_DEBRIS|CONTENTS_HITBOX, this, COLLISION_GROUP_NONE, &tr ); if ( tr.fraction == 1.0f ) return; // we didn't hit anything, stop tracing shoot if ( sv_showimpacts.GetBool() ) { #ifdef CLIENT_DLL // draw red client impact markers debugoverlay->AddBoxOverlay( tr.endpos, Vector(-2,-2,-2), Vector(2,2,2), QAngle( 0, 0, 0), 255,0,0,127, 4 ); if ( tr.m_pEnt && tr.m_pEnt->IsPlayer() ) { C_BasePlayer *player = ToBasePlayer( tr.m_pEnt ); player->DrawClientHitboxes( 4, true ); } #else // draw blue server impact markers NDebugOverlay::Box( tr.endpos, Vector(-2,-2,-2), Vector(2,2,2), 0,0,255,127, 4 ); if ( tr.m_pEnt && tr.m_pEnt->IsPlayer() ) { CBasePlayer *player = ToBasePlayer( tr.m_pEnt ); player->DrawServerHitboxes( 4, true ); } #endif } //calculate the damage based on the distance the bullet travelled. flCurrentDistance += tr.fraction * flMaxRange; // damage get weaker of distance fCurrentDamage *= pow ( 0.85f, (flCurrentDistance / 500)); int iDamageType = DMG_BULLET | DMG_NEVERGIB; if( bDoEffects ) { // See if the bullet ended up underwater + started out of the water if ( enginetrace->GetPointContents( tr.endpos ) & (CONTENTS_WATER|CONTENTS_SLIME) ) { trace_t waterTrace; UTIL_TraceLine( vecSrc, tr.endpos, (MASK_SHOT|CONTENTS_WATER|CONTENTS_SLIME), this, COLLISION_GROUP_NONE, &waterTrace ); if( waterTrace.allsolid != 1 ) { CEffectData data; data.m_vOrigin = waterTrace.endpos; data.m_vNormal = waterTrace.plane.normal; data.m_flScale = random->RandomFloat( 8, 12 ); if ( waterTrace.contents & CONTENTS_SLIME ) { data.m_fFlags |= FX_WATER_IN_SLIME; } DispatchEffect( "gunshotsplash", data ); } } else { //Do Regular hit effects // Don't decal nodraw surfaces if ( !( tr.surface.flags & (SURF_SKY|SURF_NODRAW|SURF_HINT|SURF_SKIP) ) ) { CBaseEntity *pEntity = tr.m_pEnt; if ( !( !friendlyfire.GetBool() && pEntity && pEntity->IsPlayer() && pEntity->GetTeamNumber() == GetTeamNumber() ) ) { UTIL_ImpactTrace( &tr, iDamageType ); } } } } // bDoEffects // add damage to entity that we hit #ifdef GAME_DLL ClearMultiDamage(); CTakeDamageInfo info( pevAttacker, pevAttacker, fCurrentDamage, iDamageType ); CalculateBulletDamageForce( &info, iBulletType, vecDir, tr.endpos ); tr.m_pEnt->DispatchTraceAttack( info, vecDir, &tr ); TraceAttackToTriggers( info, tr.startpos, tr.endpos, vecDir ); ApplyMultiDamage(); #endif }
static int luasrc_CalculateBulletDamageForce (lua_State *L) { CalculateBulletDamageForce(&luaL_checkdamageinfo(L, 1), luaL_checkint(L, 2), luaL_checkvector(L, 3), luaL_checkvector(L, 4), luaL_optnumber(L, 5, 1.0)); return 0; }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CASW_PropJeep::FireChargedCannon( void ) { bool penetrated = false; m_bCannonCharging = false; m_flCannonTime = gpGlobals->curtime + 0.5f; StopChargeSound(); CPASAttenuationFilter sndFilter( this, "PropJeep.FireChargedCannon" ); EmitSound( sndFilter, entindex(), "PropJeep.FireChargedCannon" ); //Find the direction the gun is pointing in Vector aimDir; GetCannonAim( &aimDir ); Vector endPos = m_vecGunOrigin + ( aimDir * MAX_TRACE_LENGTH ); //Shoot a shot straight out trace_t tr; UTIL_TraceLine( m_vecGunOrigin, endPos, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr ); ClearMultiDamage(); //Find how much damage to do float flChargeAmount = ( gpGlobals->curtime - m_flCannonChargeStartTime ) / MAX_GAUSS_CHARGE_TIME; //Clamp this if ( flChargeAmount > 1.0f ) { flChargeAmount = 1.0f; } //Determine the damage amount //FIXME: Use ConVars! float flDamage = 15 + ( ( 250 - 15 ) * flChargeAmount ); CBaseEntity *pHit = tr.m_pEnt; //Look for wall penetration if ( tr.DidHitWorld() && !(tr.surface.flags & SURF_SKY) ) { //Try wall penetration UTIL_ImpactTrace( &tr, m_nBulletType, "ImpactJeep" ); UTIL_DecalTrace( &tr, "RedGlowFade" ); CPVSFilter filter( tr.endpos ); te->GaussExplosion( filter, 0.0f, tr.endpos, tr.plane.normal, 0 ); Vector testPos = tr.endpos + ( aimDir * 48.0f ); UTIL_TraceLine( testPos, tr.endpos, MASK_SHOT, GetDriver(), COLLISION_GROUP_NONE, &tr ); if ( tr.allsolid == false ) { UTIL_DecalTrace( &tr, "RedGlowFade" ); penetrated = true; } } else if ( pHit != NULL ) { CTakeDamageInfo dmgInfo( this, GetDriver(), flDamage, DMG_SHOCK ); CalculateBulletDamageForce( &dmgInfo, GetAmmoDef()->Index("GaussEnergy"), aimDir, tr.endpos, 1.0f + flChargeAmount * 4.0f ); //Do direct damage to anything in our path pHit->DispatchTraceAttack( dmgInfo, aimDir, &tr ); } ApplyMultiDamage(); //Kick up an effect if ( !(tr.surface.flags & SURF_SKY) ) { UTIL_ImpactTrace( &tr, m_nBulletType, "ImpactJeep" ); //Do a gauss explosion CPVSFilter filter( tr.endpos ); te->GaussExplosion( filter, 0.0f, tr.endpos, tr.plane.normal, 0 ); } //Show the effect DrawBeam( m_vecGunOrigin, tr.endpos, 9.6 ); // Register a muzzleflash for the AI if ( m_hPlayer ) { m_hPlayer->SetMuzzleFlashTime( gpGlobals->curtime + 0.5f ); } //Rock the car IPhysicsObject *pObj = VPhysicsGetObject(); if ( pObj != NULL ) { Vector shoveDir = aimDir * -( flDamage * 500.0f ); pObj->ApplyForceOffset( shoveDir, m_vecGunOrigin ); } //Do radius damage if we didn't penetrate the wall if ( penetrated == true ) { RadiusDamage( CTakeDamageInfo( this, this, flDamage, DMG_SHOCK ), tr.endpos, 200.0f, CLASS_NONE, NULL ); } }
//----------------------------------------------------------------------------- // 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 }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CWeaponGauss::Fire( void ) { CBasePlayer *pOwner = ToBasePlayer( GetOwner() ); if ( pOwner == NULL ) return; m_bCharging = false; Vector startPos= pOwner->Weapon_ShootPosition(); Vector aimDir = pOwner->GetAutoaimVector( AUTOAIM_5DEGREES ); Vector vecUp, vecRight; VectorVectors( aimDir, vecRight, vecUp ); float x, y, z; //Gassian spread do { x = random->RandomFloat(-0.5,0.5) + random->RandomFloat(-0.5,0.5); y = random->RandomFloat(-0.5,0.5) + random->RandomFloat(-0.5,0.5); z = x*x+y*y; } while (z > 1); Vector endPos = startPos + ( aimDir * MAX_TRACE_LENGTH ); //Shoot a shot straight out trace_t tr; UTIL_TraceLine( startPos, endPos, MASK_SHOT, pOwner, COLLISION_GROUP_NONE, &tr ); #ifndef CLIENT_DLL ClearMultiDamage(); #endif CBaseEntity *pHit = tr.m_pEnt; #ifndef CLIENT_DLL CTakeDamageInfo dmgInfo( this, pOwner, sk_dmg_gauss.GetFloat(), DMG_SHOCK | DMG_BULLET ); #endif if ( pHit != NULL ) { #ifndef CLIENT_DLL CalculateBulletDamageForce( &dmgInfo, m_iPrimaryAmmoType, aimDir, tr.endpos, 7.0f * 5.0f ); pHit->DispatchTraceAttack( dmgInfo, aimDir, &tr ); #endif } if ( tr.DidHitWorld() ) { float hitAngle = -DotProduct( tr.plane.normal, aimDir ); if ( hitAngle < 0.5f ) { Vector vReflection; vReflection = 2.0 * tr.plane.normal * hitAngle + aimDir; startPos = tr.endpos; endPos = startPos + ( vReflection * MAX_TRACE_LENGTH ); //Draw beam to reflection point DrawBeam( tr.startpos, tr.endpos, 1.6, true ); CPVSFilter filter( tr.endpos ); te->GaussExplosion( filter, 0.0f, tr.endpos, tr.plane.normal, 0 ); UTIL_ImpactTrace( &tr, GetAmmoDef()->DamageType(m_iPrimaryAmmoType), "ImpactGauss" ); //Find new reflection end position UTIL_TraceLine( startPos, endPos, MASK_SHOT, pOwner, COLLISION_GROUP_NONE, &tr ); if ( tr.m_pEnt != NULL ) { #ifndef CLIENT_DLL dmgInfo.SetDamageForce( GetAmmoDef()->DamageForce(m_iPrimaryAmmoType) * vReflection ); dmgInfo.SetDamagePosition( tr.endpos ); tr.m_pEnt->DispatchTraceAttack( dmgInfo, vReflection, &tr ); #endif } //Connect reflection point to end DrawBeam( tr.startpos, tr.endpos, 0.4 ); } else { DrawBeam( tr.startpos, tr.endpos, 1.6, true ); } } else { DrawBeam( tr.startpos, tr.endpos, 1.6, true ); } #ifndef CLIENT_DLL ApplyMultiDamage(); #endif UTIL_ImpactTrace( &tr, GetAmmoDef()->DamageType(m_iPrimaryAmmoType), "ImpactGauss" ); CPVSFilter filter( tr.endpos ); te->GaussExplosion( filter, 0.0f, tr.endpos, tr.plane.normal, 0 ); m_flNextSecondaryAttack = gpGlobals->curtime + 1.0f; AddViewKick(); return; }
void CSDKPlayer::FireBullet( Vector vecSrc, // shooting postion const QAngle &shootAngles, //shooting angle float vecSpread, // spread vector SDKWeaponID eWeaponID, // weapon that fired this shot int iDamage, // base damage int iBulletType, // ammo type CBaseEntity *pevAttacker, // shooter bool bDoEffects, // create impact effect ? float x, // spread x factor float y // spread y factor ) { float flCurrentDistance = 0.0; //distance that the bullet has traveled so far Vector vecDirShooting, vecRight, vecUp; AngleVectors( shootAngles, &vecDirShooting, &vecRight, &vecUp ); if ( !pevAttacker ) pevAttacker = this; // the default attacker is ourselves // add the spray Vector vecDir = vecDirShooting + x * vecSpread * vecRight + y * vecSpread * vecUp; VectorNormalize( vecDir ); float flMaxRange = 8000; Vector vecEnd = vecSrc + vecDir * flMaxRange; // max bullet range is 10000 units CBaseEntity* pIgnore = this; // initialize these before the penetration loop, we'll need them to make our tracer after Vector vecTracerSrc = vecSrc; trace_t tr; // main enter bullet trace for (size_t i = 0; i < 5; i++) { CTraceFilterSimpleList tf(COLLISION_GROUP_NONE); tf.AddEntityToIgnore(this); tf.AddEntityToIgnore(pIgnore); UTIL_TraceLine( vecSrc, vecEnd, MASK_SOLID|CONTENTS_DEBRIS|CONTENTS_HITBOX, &tf, &tr ); if ( tr.fraction == 1.0f ) break; // we didn't hit anything, stop tracing shoot if ( sv_showimpacts.GetBool() ) { #ifdef CLIENT_DLL // draw red client impact markers debugoverlay->AddBoxOverlay( tr.endpos, Vector(-2,-2,-2), Vector(2,2,2), QAngle( 0, 0, 0), 255,0,0,127, 4 ); if ( tr.m_pEnt && tr.m_pEnt->IsPlayer() ) { C_BasePlayer *player = ToBasePlayer( tr.m_pEnt ); player->DrawClientHitboxes( 4, true ); } #else // draw blue server impact markers NDebugOverlay::Box( tr.endpos, Vector(-2,-2,-2), Vector(2,2,2), 0,0,255,127, 4 ); if ( tr.m_pEnt && tr.m_pEnt->IsPlayer() ) { CBasePlayer *player = ToBasePlayer( tr.m_pEnt ); player->DrawServerHitboxes( 4, true ); } #endif } weapontype_t eWeaponType = WT_NONE; CSDKWeaponInfo *pWeaponInfo = CSDKWeaponInfo::GetWeaponInfo(eWeaponID); Assert(pWeaponInfo); if (pWeaponInfo) eWeaponType = pWeaponInfo->m_eWeaponType; float flDamageMultiplier = 1; float flMaxRange = 3000; // Power formula works like so: // pow( x, distance/y ) // The damage will be at 1 when the distance is 0 units, and at // x% when the distance is y units, with a gradual decay approaching zero switch (eWeaponType) { case WT_RIFLE: flDamageMultiplier = 0.75f; flMaxRange = 3000; break; case WT_SHOTGUN: flDamageMultiplier = 0.40f; flMaxRange = 500; break; case WT_SMG: flDamageMultiplier = 0.50f; flMaxRange = 1000; break; case WT_PISTOL: default: flDamageMultiplier = 0.55f; flMaxRange = 1500; break; } //calculate the damage based on the distance the bullet travelled. flCurrentDistance += tr.fraction * flMaxRange; // First 500 units, no decrease in damage. if (eWeaponType == WT_SHOTGUN) flCurrentDistance -= 350; else flCurrentDistance -= 500; if (flCurrentDistance < 0) flCurrentDistance = 0; if (flCurrentDistance > flMaxRange) flCurrentDistance = flMaxRange; float flDistanceMultiplier = pow(flDamageMultiplier, (flCurrentDistance / flMaxRange)); int iDamageType = DMG_BULLET | DMG_NEVERGIB | GetAmmoDef()->DamageType(iBulletType); if (i == 0) iDamageType |= DMG_DIRECT; if( bDoEffects ) { // See if the bullet ended up underwater + started out of the water if ( enginetrace->GetPointContents( tr.endpos ) & (CONTENTS_WATER|CONTENTS_SLIME) ) { trace_t waterTrace; UTIL_TraceLine( vecSrc, tr.endpos, (MASK_SHOT|CONTENTS_WATER|CONTENTS_SLIME), pIgnore, COLLISION_GROUP_NONE, &waterTrace ); if( waterTrace.allsolid != 1 ) { CEffectData data; data.m_vOrigin = waterTrace.endpos; data.m_vNormal = waterTrace.plane.normal; data.m_flScale = random->RandomFloat( 8, 12 ); if ( waterTrace.contents & CONTENTS_SLIME ) { data.m_fFlags |= FX_WATER_IN_SLIME; } DispatchEffect( "gunshotsplash", data ); } } else { //Do Regular hit effects // Don't decal nodraw surfaces if ( !( tr.surface.flags & (SURF_SKY|SURF_NODRAW|SURF_HINT|SURF_SKIP) ) ) { CBaseEntity *pEntity = tr.m_pEnt; //Tony; only while using teams do we check for friendly fire. if ( pEntity && pEntity->IsPlayer() && (pEntity->GetBaseAnimating() && !pEntity->GetBaseAnimating()->IsRagdoll()) ) { #if defined ( SDK_USE_TEAMS ) if ( pEntity->GetTeamNumber() == GetTeamNumber() ) { if ( !friendlyfire.GetBool() ) UTIL_ImpactTrace( &tr, iDamageType ); } #else UTIL_ImpactTrace( &tr, iDamageType ); #endif } //Tony; non player, just go nuts, else { UTIL_ImpactTrace( &tr, iDamageType ); } } } } // bDoEffects // add damage to entity that we hit #ifdef GAME_DLL float flBulletDamage = iDamage * flDistanceMultiplier / (i+1); // Each iteration the bullet drops in strength ClearMultiDamage(); CTakeDamageInfo info( pevAttacker, pevAttacker, flBulletDamage, iDamageType ); CalculateBulletDamageForce( &info, iBulletType, vecDir, tr.endpos ); tr.m_pEnt->DispatchTraceAttack( info, vecDir, &tr ); TraceAttackToTriggers( info, tr.startpos, tr.endpos, vecDir ); ApplyMultiDamage(); #else flDistanceMultiplier = flDistanceMultiplier; // Silence warning. #endif pIgnore = tr.m_pEnt; float flPenetrationDistance; switch (eWeaponType) { case WT_RIFLE: flPenetrationDistance = 25; break; case WT_SHOTGUN: flPenetrationDistance = 5; break; case WT_SMG: flPenetrationDistance = 15; break; case WT_PISTOL: default: flPenetrationDistance = 15; break; } Vector vecBackwards = tr.endpos + vecDir * flPenetrationDistance; if (tr.m_pEnt->IsBSPModel()) UTIL_TraceLine( vecBackwards, tr.endpos, CONTENTS_SOLID|CONTENTS_MOVEABLE, NULL, COLLISION_GROUP_NONE, &tr ); else UTIL_TraceLine( vecBackwards, tr.endpos, CONTENTS_HITBOX, NULL, COLLISION_GROUP_NONE, &tr ); if (tr.startsolid) break; if (tr.m_pEnt) { // let's have a bullet exit effect if we penetrated a solid surface if (tr.m_pEnt->IsBSPModel()) UTIL_ImpactTrace( &tr, iDamageType ); // ignore the entity we just hit for the next trace to avoid weird impact behaviors pIgnore = tr.m_pEnt; } // Set up the next trace. vecSrc = tr.endpos + vecDir; // One unit in the direction of fire so that we firmly embed ourselves in whatever solid was hit. } // the bullet's done penetrating, let's spawn our particle system if (bDoEffects && (pevAttacker == this)) MakeTracer( vecTracerSrc, tr, TRACER_TYPE_DEFAULT ); }
void CDODPlayer::FireBullets( const FireBulletsInfo_t &info ) { trace_t tr; trace_t reverseTr; //Used to find exit points static int iMaxPenetrations = 6; int iPenetrations = 0; float flDamage = info.m_iDamage; //Remaining damage in the bullet Vector vecSrc = info.m_vecSrc; Vector vecEnd = vecSrc + info.m_vecDirShooting * info.m_flDistance; static int iTraceMask = ( ( MASK_SOLID | CONTENTS_DEBRIS | CONTENTS_HITBOX | CONTENTS_PRONE_HELPER ) & ~CONTENTS_GRATE ); CBaseEntity *pLastHitEntity = this; // start with us so we don't trace ourselves int iDamageType = GetAmmoDef()->DamageType( info.m_iAmmoType ); int iCollisionGroup = COLLISION_GROUP_NONE; #ifdef GAME_DLL bool iNumHeadshots = 0; #endif while ( flDamage > 0 && iPenetrations < iMaxPenetrations ) { //DevMsg( 2, "penetration: %d, starting dmg: %.1f\n", iPenetrations, flDamage ); CBaseEntity *pPreviousHit = pLastHitEntity; // skip the shooter always CTraceFilterSkipTwoEntities ignoreShooterAndPrevious( this, pPreviousHit, iCollisionGroup ); UTIL_TraceLine( vecSrc, vecEnd, iTraceMask, &ignoreShooterAndPrevious, &tr ); const float rayExtension = 40.0f; UTIL_ClipTraceToPlayers( vecSrc, vecEnd + info.m_vecDirShooting * rayExtension, iTraceMask, &ignoreShooterAndPrevious, &tr ); if ( tr.fraction == 1.0f ) break; // we didn't hit anything, stop tracing shoot // New hitbox code that uses hitbox groups instead of trying to trace // through the player if ( tr.m_pEnt && tr.m_pEnt->IsPlayer() ) { switch( tr.hitgroup ) { #ifdef GAME_DLL case HITGROUP_HEAD: { if ( tr.m_pEnt->GetTeamNumber() != GetTeamNumber() ) { iNumHeadshots++; } } break; #endif case HITGROUP_LEFTARM: case HITGROUP_RIGHTARM: { //DevMsg( 2, "Hit arms, tracing against alt hitboxes.. \n" ); CDODPlayer *pPlayer = ToDODPlayer( tr.m_pEnt ); // set hitbox set to "dod_no_arms" pPlayer->SetHitboxSet( 1 ); trace_t newTr; // re-fire the trace UTIL_TraceLine( vecSrc, vecEnd, iTraceMask, &ignoreShooterAndPrevious, &newTr ); // if we hit the same player in the chest if ( tr.m_pEnt == newTr.m_pEnt ) { //DevMsg( 2, ".. and we hit the chest.\n" ); Assert( tr.hitgroup != newTr.hitgroup ); // If we hit this, hitbox sets are broken // use that damage instead tr = newTr; } // set hitboxes back to "dod" pPlayer->SetHitboxSet( 0 ); } break; default: break; } } pLastHitEntity = tr.m_pEnt; if ( sv_showimpacts.GetBool() ) { #ifdef CLIENT_DLL // draw red client impact markers debugoverlay->AddBoxOverlay( tr.endpos, Vector(-1,-1,-1), Vector(1,1,1), QAngle(0,0,0), 255, 0, 0, 127, 4 ); if ( tr.m_pEnt && tr.m_pEnt->IsPlayer() ) { C_BasePlayer *player = ToBasePlayer( tr.m_pEnt ); player->DrawClientHitboxes( 4, true ); } #else // draw blue server impact markers NDebugOverlay::Box( tr.endpos, Vector(-1,-1,-1), Vector(1,1,1), 0,0,255,127, 4 ); if ( tr.m_pEnt && tr.m_pEnt->IsPlayer() ) { CBasePlayer *player = ToBasePlayer( tr.m_pEnt ); player->DrawServerHitboxes( 4, true ); } #endif } #ifdef CLIENT_DLL // See if the bullet ended up underwater + started out of the water if ( enginetrace->GetPointContents( tr.endpos ) & (CONTENTS_WATER|CONTENTS_SLIME) ) { trace_t waterTrace; UTIL_TraceLine( vecSrc, tr.endpos, (MASK_SHOT|CONTENTS_WATER|CONTENTS_SLIME), this, iCollisionGroup, &waterTrace ); if( waterTrace.allsolid != 1 ) { CEffectData data; data.m_vOrigin = waterTrace.endpos; data.m_vNormal = waterTrace.plane.normal; data.m_flScale = random->RandomFloat( 8, 12 ); if ( waterTrace.contents & CONTENTS_SLIME ) { data.m_fFlags |= FX_WATER_IN_SLIME; } DispatchEffect( "gunshotsplash", data ); } } else { //Do Regular hit effects // Don't decal nodraw surfaces if ( !( tr.surface.flags & (SURF_SKY|SURF_NODRAW|SURF_HINT|SURF_SKIP) ) ) { CBaseEntity *pEntity = tr.m_pEnt; if ( !( !friendlyfire.GetBool() && pEntity && pEntity->GetTeamNumber() == GetTeamNumber() ) ) { UTIL_ImpactTrace( &tr, iDamageType ); } } } #endif // Get surface where the bullet entered ( if it had different surfaces on enter and exit ) surfacedata_t *pSurfaceData = physprops->GetSurfaceData( tr.surface.surfaceProps ); Assert( pSurfaceData ); float flMaterialMod = GetDensityFromMaterial(pSurfaceData); if ( iDamageType & DMG_MACHINEGUN ) { flMaterialMod *= 0.65; } // try to penetrate object Vector penetrationEnd; float flMaxDistance = flDamage / flMaterialMod; #ifndef CLIENT_DLL ClearMultiDamage(); float flActualDamage = flDamage; CTakeDamageInfo dmgInfo( info.m_pAttacker, info.m_pAttacker, flActualDamage, iDamageType ); CalculateBulletDamageForce( &dmgInfo, info.m_iAmmoType, info.m_vecDirShooting, tr.endpos ); tr.m_pEnt->DispatchTraceAttack( dmgInfo, info.m_vecDirShooting, &tr ); DevMsg( 2, "Giving damage ( %.1f ) to entity of type %s\n", flActualDamage, tr.m_pEnt->GetClassname() ); TraceAttackToTriggers( dmgInfo, tr.startpos, tr.endpos, info.m_vecDirShooting ); #endif int stepsize = 16; // displacement always stops the bullet if ( tr.IsDispSurface() ) { DevMsg( 2, "bullet was stopped by displacement\n" ); ApplyMultiDamage(); break; } // trace through the solid to find the exit point and how much material we went through if ( !TraceToExit( tr.endpos, info.m_vecDirShooting, penetrationEnd, stepsize, flMaxDistance ) ) { DevMsg( 2, "bullet was stopped\n" ); ApplyMultiDamage(); break; } // find exact penetration exit CTraceFilterSimple ignoreShooter( this, iCollisionGroup ); UTIL_TraceLine( penetrationEnd, tr.endpos, iTraceMask, &ignoreShooter, &reverseTr ); // Now we can apply the damage, after we have traced the entity // so it doesn't break or die before we have a change to test against it #ifndef CLIENT_DLL ApplyMultiDamage(); #endif // Continue looking for the exit point if( reverseTr.m_pEnt != tr.m_pEnt && reverseTr.m_pEnt != NULL ) { // something was blocking, trace again CTraceFilterSkipTwoEntities ignoreShooterAndBlocker( this, reverseTr.m_pEnt, iCollisionGroup ); UTIL_TraceLine( penetrationEnd, tr.endpos, iTraceMask, &ignoreShooterAndBlocker, &reverseTr ); } if ( sv_showimpacts.GetBool() ) { debugoverlay->AddLineOverlay( penetrationEnd, reverseTr.endpos, 255, 0, 0, true, 3.0 ); } // penetration was successful #ifdef CLIENT_DLL // bullet did penetrate object, exit Decal if ( !( reverseTr.surface.flags & (SURF_SKY|SURF_NODRAW|SURF_HINT|SURF_SKIP) ) ) { CBaseEntity *pEntity = reverseTr.m_pEnt; if ( !( !friendlyfire.GetBool() && pEntity && pEntity->GetTeamNumber() == GetTeamNumber() ) ) { UTIL_ImpactTrace( &reverseTr, iDamageType ); } } #endif //setup new start end parameters for successive trace // New start point is our last exit point vecSrc = reverseTr.endpos + /* 1.0 * */ info.m_vecDirShooting; // Reduce bullet damage by material and distanced travelled through that material // if it is < 0 we won't go through the loop again float flTraceDistance = VectorLength( reverseTr.endpos - tr.endpos ); flDamage -= flMaterialMod * flTraceDistance; if( flDamage > 0 ) { DevMsg( 2, "Completed penetration, new damage is %.1f\n", flDamage ); } else { DevMsg( 2, "bullet was stopped\n" ); } iPenetrations++; } #ifdef GAME_DLL HandleHeadshotAchievement( iNumHeadshots ); #endif }
void CDHLProjectile::PhysicsSimulate( void ) { //------------------------------------------------------------------------------- //Our own movement/physics simulation! //------------------------------------------------------------------------------- #ifdef CLIENT_DLL if ( m_bCollided ) return; if ( !m_pShooter && m_hShooter ) m_pShooter = m_hShooter.Get(); #else if ( m_flRemoveAt > 0.0f ) { if ( m_flRemoveAt < gpGlobals->curtime ) { m_flRemoveAt = 0.0f; SUB_Remove(); } return; } if ( IsMarkedForDeletion() ) return; #endif float flFrametime = gpGlobals->frametime; //Scale for slow motion if ( DHLRules() ) { if ( (m_iType == DHL_PROJECTILE_TYPE_BULLET || m_iType == DHL_PROJECTILE_TYPE_PELLET) ) flFrametime *= (dhl_bulletspeed.GetFloat() * DHLRules()->GetTimescale()); else if ( m_iType == DHL_PROJECTILE_TYPE_COMBATKNIFE ) flFrametime *= (dhl_knifespeed.GetFloat() * DHLRules()->GetTimescale()); else flFrametime *= DHLRules()->GetTimescale(); } Vector vecDir = vec3_origin; #ifndef CLIENT_DLL Vector vecStartPos = m_vecCurPosition; //This is where we are Vector vecEndPos = m_vecCurPosition; //This is where we're going Vector vecVelocity = m_vecCurVelocity; //Velocity #else Vector vecStartPos = GetLocalOrigin(); //This is where we are Vector vecEndPos = GetLocalOrigin(); //This is where we're going Vector vecVelocity = GetLocalVelocity(); //Velocity #endif //Find out where we should move to if ( vecVelocity != vec3_origin ) { static ConVarRef gravVar( "sv_gravity" ); //Gravity float newZVelocity = vecVelocity.z - ( flFrametime * gravVar.GetFloat() * GetGravity() ); vecVelocity.z = ( (vecVelocity.z + newZVelocity) / 2 ); vecDir = vecVelocity; VectorNormalize( vecDir ); //Gravity needs to be cumulative #ifndef CLIENT_DLL m_vecCurVelocity = vecVelocity; #else SetLocalVelocity( vecVelocity ); #endif vecVelocity *= flFrametime; vecEndPos = vecStartPos + vecVelocity; if ( vecEndPos.IsValid() ) { CTraceFilterSkipTwoEntities movetrfilter( this, m_pShooter, COLLISION_GROUP_NONE ); trace_t movetr; UTIL_TraceLine( vecStartPos, vecEndPos, MASK_SHOT, &movetrfilter, &movetr ); #ifndef CLIENT_DLL //Trace to triggers so we can hit surf glass and such CTakeDamageInfo triggerInfo( this, GetOwnerEntity(), m_iDamage, DMG_BULLET ); if ( m_iType == DHL_PROJECTILE_TYPE_COMBATKNIFE ) { //CalculateMeleeDamageForce( &triggerInfo, vecDir, movetr.endpos, 0.7f ); Vector vecForce = vecDir; VectorNormalize( vecForce ); //vecForce *= 10.0f; triggerInfo.SetDamageForce( vecForce ); } else CalculateBulletDamageForce( &triggerInfo, m_iAmmoType, vecDir, movetr.endpos, 1.0f ); triggerInfo.SetDamagePosition( movetr.endpos ); TraceAttackToTriggers( triggerInfo, movetr.startpos, movetr.endpos, vecDir ); #else //Hit ragdolls on the client CBaseEntity* pEnt = DHL_FX_AffectRagdolls( movetr.endpos, movetr.startpos, DMG_BULLET, &m_RagdollHitList ); //Keep track of ones we've hit if ( pEnt ) m_RagdollHitList.AddToTail( pEnt ); #endif if ( movetr.DidHit() ) if ( OnTouch( movetr, false, &movetrfilter ) ) return; MoveProjectileToPosition( vecEndPos ); m_flDistanceTravelled += vecEndPos.DistTo( vecStartPos ); #ifndef CLIENT_DLL //On rare occasions the projectile likes to fly right through the world and keep going forever, causing a memory leak if ( m_flDistanceTravelled > MAX_TRACE_LENGTH ) { SUB_Remove(); //SetThink( &CDHLProjectile::SUB_Remove ); //SetNextThink( gpGlobals->curtime + 0.1 ); } #endif } //Simulate Angles //QAngle angles; #ifdef CLIENT_DLL QAngle angles = GetLocalAngles(); //VectorAngles( vecDir, angles ); //angles.z = GetLocalAngles().z; //Vector conversion loses z QAngle angVel = GetLocalAngularVelocity(); angles += angVel * flFrametime; SetLocalAngles( angles ); SetNetworkAngles( angles ); #endif } }
//Called from PhysicsSimulate() or ReceiveMessage() bool CDHLProjectile::OnTouch( trace_t &touchtr, bool bDecalOnly /*= false*/, ITraceFilter* pTraceFilter /*= NULL*/ ) { //Direction Vector vecDir = touchtr.endpos - touchtr.startpos; if ( vecDir == vec3_origin ) //Sometimes endpos==startpos so we need to get dir from velocity instead { #ifdef CLIENT_DLL vecDir = GetLocalVelocity(); #else vecDir = m_vecCurVelocity; #endif VectorNormalize( vecDir ); } CBaseEntity* ent = touchtr.m_pEnt; if ( !ent ) return false; if ( touchtr.DidHit() ) { //Never collide with self, shooter, or other projectiles if ( ent == this || dynamic_cast<CDHLProjectile*>(ent) || ent == (CBaseEntity*)m_pShooter ) //|| ( (m_iType == DHL_PROJECTILE_TYPE_COMBATKNIFE) && (ent == m_pFiringWeapon) ) ) //Combat knife - don't collide with weapon ent return false; //Hack: Sometimes hits are registered prematurely (usually to the torso area) with no hitbox. Pretend nothing happened unless one is found. if ( ent->IsPlayer() && touchtr.hitgroup == 0 ) return false; //Check friendly fire if ( CheckFriendlyFire( ent ) ) { if ( !bDecalOnly ) { ClearMultiDamage(); //Do damage CTakeDamageInfo dmgInfo( this, GetOwnerEntity(), m_iDamage, DMG_BULLET ); if ( m_iType == DHL_PROJECTILE_TYPE_COMBATKNIFE ) { //CalculateMeleeDamageForce( &dmgInfo, vecDir, touchtr.endpos, 0.01f ); Vector vecForce = vecDir; VectorNormalize( vecForce ); //vecForce *= 10.0f; //Ripped from C_ClientRagdoll::ImpactTrace dmgInfo.SetDamageForce( vecForce ); #ifndef CLIENT_DLL if ( IsOnFire() ) { CBaseAnimating* pBAnim = dynamic_cast<CBaseAnimating*>(ent); if ( pBAnim ) pBAnim->Ignite( 10.0f, false ); } #endif } else CalculateBulletDamageForce( &dmgInfo, m_iAmmoType, vecDir, touchtr.endpos, 1.0f ); dmgInfo.SetDamagePosition( touchtr.endpos ); ent->DispatchTraceAttack( dmgInfo, vecDir, &touchtr ); ApplyMultiDamage(); } #ifdef CLIENT_DLL if ( ent->GetCollisionGroup() == COLLISION_GROUP_BREAKABLE_GLASS ) return false; //Decals and such if ( !( touchtr.surface.flags & SURF_SKY ) && !touchtr.allsolid ) { IPredictionSystem::SuppressEvents( false ); if ( (m_iType == DHL_PROJECTILE_TYPE_BULLET || m_iType == DHL_PROJECTILE_TYPE_PELLET) ) { UTIL_ImpactTrace( &touchtr, DMG_BULLET ); } if ( m_iType == DHL_PROJECTILE_TYPE_COMBATKNIFE ) PlayImpactSound( touchtr.m_pEnt, touchtr, touchtr.endpos, touchtr.surface.surfaceProps ); IPredictionSystem::SuppressEvents( !prediction->IsFirstTimePredicted() ); } #endif } if ( pTraceFilter && m_iType != DHL_PROJECTILE_TYPE_COMBATKNIFE ) { PenetrationData_t nPenetrationData = DHLShared::TestPenetration( touchtr, m_pShooter, pTraceFilter, m_iTimesPenetrated, m_flDistanceTravelled, m_iAmmoType ); if ( nPenetrationData.m_bShouldPenetrate ) { m_flDistanceTravelled += GetLocalOrigin().DistTo( nPenetrationData.m_vecNewBulletPos ); MoveProjectileToPosition( nPenetrationData.m_vecNewBulletPos ); m_iTimesPenetrated++; return true; //Keep going - but don't do anything else in this frame of PhysicsSimulate() } } //We're done unless what we hit was breakable glass if ( ent->GetCollisionGroup() != COLLISION_GROUP_BREAKABLE_GLASS ) { #ifdef CLIENT_DLL m_bCollided = true; AddEffects( EF_NODRAW ); if ( m_pTrail ) //NULL pointer here sometimes somehow... m_pTrail->AddEffects( EF_NODRAW ); #else EntityMessageBegin( this ); WRITE_BYTE( MSG_NOTIFY_REMOVAL ); MessageEnd(); if ( touchtr.DidHitWorld() && m_iType == DHL_PROJECTILE_TYPE_COMBATKNIFE && !( touchtr.surface.flags & SURF_SKY ) ) { CBaseCombatWeapon* pKnifeEnt = assert_cast<CBaseCombatWeapon*>(CreateEntityByName( "weapon_combatknife" )); if ( pKnifeEnt ) { pKnifeEnt->AddSpawnFlags( SF_NORESPAWN ); //Needed for weapon spawn & VPhysics setup to work correctly pKnifeEnt->SetAbsOrigin( touchtr.endpos ); QAngle angles = vec3_angle; Vector vecKnifeDir = touchtr.startpos - touchtr.endpos; VectorAngles( vecKnifeDir, angles ); angles[PITCH] -= 15.0f; //Correct for the .mdl being offset a bit pKnifeEnt->SetLocalAngles( angles ); DispatchSpawn( pKnifeEnt ); //Spawns vphys object and sets it up, essentially a copy of CWeaponHL2MPBase::FallInit() pKnifeEnt->VPhysicsDestroyObject(); //Using SOLID_VPHYSICS instead of SOLID_BBOX (as ordinary weapons do) helps resolve some of the client side collision oddities Assert( pKnifeEnt->VPhysicsInitNormal( SOLID_VPHYSICS, FSOLID_NOT_STANDABLE | FSOLID_TRIGGER, true ) ); pKnifeEnt->SetPickupTouch(); //Sets up automagic removal after time IPhysicsObject* pKnifePhys = pKnifeEnt->VPhysicsGetObject(); if ( pKnifePhys ) { //Knives are solid to bullets...the only way to make them non-solid to bullets is to do SetSolid( SOLID_NONE ) or AddSolidFlags( FSOLID_NOT_SOLID ) //which breaks the +use pickup even with FSOLID_TRIGGER set. Let's just call it a feature :) pKnifePhys->EnableMotion( false ); pKnifePhys->EnableCollisions( false ); } if ( IsOnFire() ) pKnifeEnt->Ignite( 10.0f, false ); } } //SetThink( &CDHLProjectile::SUB_Remove ); //SetNextThink( gpGlobals->curtime + 0.1 ); //SUB_Remove(); //SetMoveType( MOVETYPE_NONE ); m_flRemoveAt = gpGlobals->curtime + 0.1f; //Give the notification message a head start so that the client will have time to react #endif } } return true; }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CWeaponGaussGun::ChargedFire() { if ( InGameRules()->IsMultiplayer() ) { } CBasePlayer *pOwner = ToBasePlayer( GetOwner() ); if ( !pOwner ) return; bool penetrated = false; //Play shock sounds WeaponSound( SINGLE ); WeaponSound( SPECIAL2 ); SendWeaponAnim( ACT_VM_SECONDARYATTACK ); StopChargeSound(); m_bCharging = false; m_bChargeIndicated = false; m_flNextPrimaryAttack = gpGlobals->curtime + 0.2f; m_flNextSecondaryAttack = gpGlobals->curtime + 0.5f; //Shoot a shot straight out Vector startPos= pOwner->Weapon_ShootPosition(); Vector aimDir = pOwner->GetAutoaimVector( AUTOAIM_5DEGREES ); Vector endPos = startPos + ( aimDir * MAX_TRACE_LENGTH ); trace_t tr; UTIL_TraceLine( startPos, endPos, MASK_SHOT, pOwner, COLLISION_GROUP_NONE, &tr ); #ifndef CLIENT_DLL ClearMultiDamage(); //Find how much damage to do float flChargeAmount = ( gpGlobals->curtime - m_flChargeStartTime ) / MAX_GAUSS_CHARGE_TIME; //Clamp this if ( flChargeAmount > 1.0f ) flChargeAmount = 1.0f; //Determine the damage amount float flDamage = sk_plr_dmg_gauss.GetFloat() + ( ( sk_plr_max_dmg_gauss.GetFloat() - sk_plr_dmg_gauss.GetFloat() ) * flChargeAmount ); #endif CBaseEntity *pHit = tr.m_pEnt; if ( tr.DidHitWorld() ) { //Try wall penetration UTIL_ImpactTrace( &tr, GetAmmoDef()->DamageType(m_iPrimaryAmmoType), "ImpactGauss" ); UTIL_DecalTrace( &tr, "RedGlowFade" ); CPVSFilter filter( tr.endpos ); te->GaussExplosion( filter, 0.0f, tr.endpos, tr.plane.normal, 0 ); Vector testPos = tr.endpos + ( aimDir * 48.0f ); UTIL_TraceLine( testPos, tr.endpos, MASK_SHOT, pOwner, COLLISION_GROUP_NONE, &tr ); if ( tr.allsolid == false ) { UTIL_DecalTrace( &tr, "RedGlowFade" ); penetrated = true; } } #ifndef CLIENT_DLL else if ( pHit != NULL ) { CTakeDamageInfo dmgInfo( this, pOwner, flDamage, DMG_SHOCK | DMG_DISSOLVE ); CalculateBulletDamageForce( &dmgInfo, m_iPrimaryAmmoType, aimDir, tr.endpos ); //Do direct damage to anything in our path pHit->DispatchTraceAttack( dmgInfo, aimDir, &tr ); } ApplyMultiDamage(); #endif UTIL_ImpactTrace( &tr, GetAmmoDef()->DamageType(m_iPrimaryAmmoType), "ImpactGauss" ); QAngle viewPunch; viewPunch.x = random->RandomFloat( -4.0f, -8.0f ); viewPunch.y = random->RandomFloat( -0.25f, 0.25f ); viewPunch.z = 0; pOwner->ViewPunch( viewPunch ); DrawBeam( startPos, tr.endpos, 25, true ); #ifndef CLIENT_DLL Vector recoilForce = pOwner->BodyDirection2D() * -( flDamage * 10.0f ); recoilForce[2] += 300.0f;//128 pOwner->ApplyAbsVelocityImpulse( recoilForce ); #endif CPVSFilter filter( tr.endpos ); te->GaussExplosion( filter, 0.0f, tr.endpos, tr.plane.normal, 0 ); #ifndef CLIENT_DLL if ( penetrated == true ) RadiusDamage( CTakeDamageInfo( this, this, flDamage, DMG_SHOCK ), tr.endpos, 200.0f, CLASS_NONE, NULL ); // Register a muzzleflash for the AI pOwner->SetMuzzleFlashTime( gpGlobals->curtime + 0.5 ); #endif }
//------------------------------------------------------------------------------ // Purpose : // Input : // Output : //------------------------------------------------------------------------------ void CNPC_MissileDefense::FireCannons( void ) { // ---------------------------------------------- // Make sure I have an enemy // ---------------------------------------------- if (GetEnemy() == NULL) { return; } // ---------------------------------------------- // Make sure I have ammo // ---------------------------------------------- if( m_iAmmoLoaded < 1 ) { return; } // ---------------------------------------------- // Make sure gun it pointing in right direction // ---------------------------------------------- Vector vGunDir; GetGunAim( &vGunDir ); Vector vTargetPos; EnemyShootPosition(GetEnemy(),&vTargetPos); Vector vTargetDir = vTargetPos - GetAbsOrigin(); VectorNormalize( vTargetDir ); float fDotPr = DotProduct( vGunDir, vTargetDir ); if (fDotPr < 0.95) { return; } // ---------------------------------------------- // Check line of sight // ---------------------------------------------- trace_t tr; AI_TraceLine( GetEnemy()->EyePosition(), GetAbsOrigin(), MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr); if (tr.fraction < 1.0) { return; } Vector vecRight; Vector vecDir; Vector vecCenter; AngleVectors( GetLocalAngles(), NULL, &vecRight, NULL ); vecCenter = WorldSpaceCenter(); if( GetEnemy() == NULL ) { return; } bool fSound = false; if( random->RandomInt( 0, 3 ) == 0 ) { fSound = true; } EmitSound( "NPC_MissileDefense.Attack" ); Vector vecGun; QAngle vecAng; GetAttachment( MD_AP_LGUN, vecGun, vecAng ); Vector vecTarget; EnemyShootPosition(GetEnemy(),&vecTarget); vecDir = vecTarget - vecCenter; VectorNormalize(vecDir); vecDir.x += random->RandomFloat( -NOISE, NOISE ); vecDir.y += random->RandomFloat( -NOISE, NOISE ); Vector vecStart = vecGun + vecDir * 110; Vector vecEnd = vecGun + vecDir * 4096; UTIL_Tracer( vecStart, vecEnd, 0, TRACER_DONT_USE_ATTACHMENT, 3000 + random->RandomFloat( 0, 2000 ), fSound ); vecDir = vecTarget - vecCenter; VectorNormalize(vecDir); vecDir.x += random->RandomFloat( -NOISE, NOISE ); vecDir.y += random->RandomFloat( -NOISE, NOISE ); vecDir.z += random->RandomFloat( -NOISE, NOISE ); GetAttachment( MD_AP_RGUN, vecGun, vecAng ); vecStart = vecGun + vecDir * 110; vecEnd = vecGun + vecDir * 4096; UTIL_Tracer( vecStart, vecEnd, 0, TRACER_DONT_USE_ATTACHMENT, 3000 + random->RandomFloat( 0, 2000 ) ); m_iAmmoLoaded -= 2; if( m_iAmmoLoaded < 1 ) { // Incite a reload. EmitSound( "NPC_MissileDefense.Reload" ); m_flReloadedTime = gpGlobals->curtime + 0.3; return; } // Do damage to the missile based on distance. // if < 1, make damage 0. float flDist = (GetEnemy()->GetLocalOrigin() - vecGun).Length(); float flDamage; flDamage = 4000 - flDist; flDamage /= 1000.0; if( flDamage > 0 ) { if( flDist <= 1500 ) { flDamage *= 2; } CTakeDamageInfo info( this, this, flDamage, DMG_MISSILEDEFENSE ); CalculateBulletDamageForce( &info, GetAmmoDef()->Index("SMG1"), vecDir, GetEnemy()->GetAbsOrigin() ); GetEnemy()->TakeDamage( info ); } }
void CBulletManager::SimulateBullet(CBullet& oBullet, float dt) { Vector vecOriginal = oBullet.m_vecOrigin; Assert(oBullet.m_hShooter.Get()); if (!oBullet.m_hShooter) return; bool bHasTraveledBefore = false; if (oBullet.m_flDistanceTraveled > 0) bHasTraveledBefore = true; // initialize these before the penetration loop, we'll need them to make our tracer after Vector vecTracerSrc = oBullet.m_vecOrigin; trace_t tr; // main enter bullet trace float flRange = dt; if (flRange < 0) flRange = 8000; bool bFullPenetrationDistance = false; Vector vecEnd = oBullet.m_vecOrigin + oBullet.m_vecDirection * flRange; int i; for (i = oBullet.m_iPenetrations; i < da_bullet_penetrations.GetInt(); i++) { CTraceFilterSimpleList tf(COLLISION_GROUP_NONE); tf.AddEntityToIgnore(oBullet.m_hShooter); for (int j = 0; j < oBullet.m_ahObjectsHit.Count(); j++) tf.AddEntityToIgnore(oBullet.m_ahObjectsHit[j]); UTIL_TraceLine( oBullet.m_vecOrigin, vecEnd, MASK_SOLID|CONTENTS_DEBRIS|CONTENTS_HITBOX, &tf, &tr ); if (da_bullet_debug.GetBool()) { #ifdef CLIENT_DLL DebugDrawLine(oBullet.m_vecOrigin + Vector(0, 0, 1), tr.endpos + Vector(0, 0, 1), 0, 255, 255, true, dt<0?10:0.1); #else DebugDrawLine(oBullet.m_vecOrigin + Vector(0, 0, 1), tr.endpos + Vector(0, 0, 1), 255, 255, 0, true, dt<0?10:0.1); #endif } Vector vecTraceEnd = tr.endpos; bool bBSPModel = tr.DidHitWorld(); if (tr.allsolid) { oBullet.m_flDistanceTraveled += (oBullet.m_vecOrigin - vecEnd).Length(); oBullet.m_vecOrigin = vecEnd; break; // We're inside something. Do nothing. } if ( sv_showimpacts.GetBool() && tr.fraction < 1.0f ) { #ifdef CLIENT_DLL // draw red client impact markers debugoverlay->AddBoxOverlay( tr.endpos, Vector(-2,-2,-2), Vector(2,2,2), QAngle( 0, 0, 0), 255,0,0,127, sv_showimpacts.GetFloat() ); if ( tr.m_pEnt && tr.m_pEnt->IsPlayer() ) { C_BasePlayer *player = ToBasePlayer( tr.m_pEnt ); player->DrawClientHitboxes( sv_showimpacts.GetFloat(), true ); } #else // draw blue server impact markers NDebugOverlay::Box( tr.endpos, Vector(-2,-2,-2), Vector(2,2,2), 0,0,255,127, sv_showimpacts.GetFloat() ); if ( tr.m_pEnt && tr.m_pEnt->IsPlayer() ) { CBasePlayer *player = ToBasePlayer( tr.m_pEnt ); player->DrawServerHitboxes( sv_showimpacts.GetFloat(), true ); } #endif } Assert(oBullet.m_iBulletType > 0); int iDamageType = DMG_BULLET | DMG_NEVERGIB | GetAmmoDef()->DamageType(oBullet.m_iBulletType); if (i == 0) iDamageType |= DMG_DIRECT; if (tr.startsolid) { trace_t tr2; UTIL_TraceLine( tr.endpos - oBullet.m_vecDirection, oBullet.m_vecOrigin, CONTENTS_SOLID|CONTENTS_MOVEABLE, NULL, COLLISION_GROUP_NONE, &tr2 ); // let's have a bullet exit effect if we penetrated a solid surface if (oBullet.m_bDoEffects && tr2.m_pEnt && tr2.m_pEnt->IsBSPModel()) UTIL_ImpactTrace( &tr2, iDamageType ); // ignore the entity we just hit for the next trace to avoid weird impact behaviors oBullet.m_ahObjectsHit.AddToTail(tr2.m_pEnt); } if ( tr.fraction == 1.0f ) { oBullet.m_flDistanceTraveled += (oBullet.m_vecOrigin - vecEnd).Length(); oBullet.m_vecOrigin = vecEnd; break; // we didn't hit anything, stop tracing shoot } weapontype_t eWeaponType = WT_NONE; CSDKWeaponInfo *pWeaponInfo = CSDKWeaponInfo::GetWeaponInfo(oBullet.m_eWeaponID); Assert(pWeaponInfo); if (pWeaponInfo) eWeaponType = pWeaponInfo->m_eWeaponType; float flDamageMultiplier = 1; float flMaxRange = 3000; // Power formula works like so: // pow( x, distance/y ) // The damage will be at 1 when the distance is 0 units, and at // x% when the distance is y units, with a gradual decay approaching zero switch (eWeaponType) { case WT_RIFLE: flDamageMultiplier = 0.75f; flMaxRange = 3000; break; case WT_SHOTGUN: flDamageMultiplier = 0.40f; flMaxRange = 500; break; case WT_SMG: flDamageMultiplier = 0.50f; flMaxRange = 1000; break; case WT_PISTOL: default: flDamageMultiplier = 0.55f; flMaxRange = 1500; break; } flMaxRange *= oBullet.m_hShooter->m_Shared.ModifySkillValue(1, 0.5f, SKILL_MARKSMAN); //calculate the damage based on the distance the bullet travelled. oBullet.m_flDistanceTraveled += tr.fraction * flRange; float flCurrentDistance = oBullet.m_flDistanceTraveled; // First 500 units, no decrease in damage. if (eWeaponType == WT_SHOTGUN) flCurrentDistance -= 350; else flCurrentDistance -= 500; if (flCurrentDistance < 0) flCurrentDistance = 0; if (flCurrentDistance > flMaxRange) flCurrentDistance = flMaxRange; float flDistanceMultiplier = pow(flDamageMultiplier, (flCurrentDistance / flMaxRange)); if( oBullet.m_bDoEffects ) { // See if the bullet ended up underwater + started out of the water if ( enginetrace->GetPointContents( tr.endpos ) & (CONTENTS_WATER|CONTENTS_SLIME) ) { CBaseEntity* pIgnore; if (oBullet.m_ahObjectsHit.Count()) pIgnore = oBullet.m_ahObjectsHit.Tail(); else pIgnore = oBullet.m_hShooter; trace_t waterTrace; UTIL_TraceLine( oBullet.m_vecOrigin, tr.endpos, (MASK_SHOT|CONTENTS_WATER|CONTENTS_SLIME), pIgnore, COLLISION_GROUP_NONE, &waterTrace ); if( waterTrace.allsolid != 1 ) { CEffectData data; data.m_vOrigin = waterTrace.endpos; data.m_vNormal = waterTrace.plane.normal; data.m_flScale = random->RandomFloat( 8, 12 ); if ( waterTrace.contents & CONTENTS_SLIME ) data.m_fFlags |= FX_WATER_IN_SLIME; DispatchEffect( "gunshotsplash", data ); } } else { //Do Regular hit effects // Don't decal nodraw surfaces if ( !( tr.surface.flags & (SURF_SKY|SURF_NODRAW|SURF_HINT|SURF_SKIP) ) ) { CBaseEntity *pEntity = tr.m_pEnt; //Tony; only while using teams do we check for friendly fire. if ( DAGameRules()->IsTeamplay() && pEntity && pEntity->IsPlayer() && (pEntity->GetBaseAnimating() && !pEntity->GetBaseAnimating()->IsRagdoll()) ) { if ( pEntity->GetTeamNumber() != oBullet.m_hShooter->GetTeamNumber() ) UTIL_ImpactTrace( &tr, iDamageType ); } //Tony; non player, just go nuts, else UTIL_ImpactTrace( &tr, iDamageType ); } } } // bDoEffects // add damage to entity that we hit #ifdef GAME_DLL float flBulletDamage = oBullet.m_iBulletDamage * flDistanceMultiplier / (i+1); // Each iteration the bullet drops in strength if (oBullet.m_hShooter->IsStyleSkillActive(SKILL_MARKSMAN)) flBulletDamage = oBullet.m_iBulletDamage * flDistanceMultiplier / (i/2+1); // Each iteration the bullet drops in strength but not nearly as much. ClearMultiDamage(); CTakeDamageInfo info( oBullet.m_hShooter, oBullet.m_hShooter, oBullet.m_hWeapon, flBulletDamage, iDamageType ); CalculateBulletDamageForce( &info, oBullet.m_iBulletType, oBullet.m_vecDirection, tr.endpos ); tr.m_pEnt->DispatchTraceAttack( info, oBullet.m_vecDirection, &tr ); oBullet.m_hShooter->TraceAttackToTriggers( info, tr.startpos, tr.endpos, oBullet.m_vecDirection ); ApplyMultiDamage(); #else flDistanceMultiplier = flDistanceMultiplier; // Silence warning. #endif if (tr.m_pEnt && !FStrEq(tr.m_pEnt->GetClassname(), "worldspawn")) oBullet.m_ahObjectsHit.AddToTail(tr.m_pEnt); float flPenetrationDistance; switch (eWeaponType) { case WT_RIFLE: flPenetrationDistance = 25; break; case WT_SHOTGUN: flPenetrationDistance = 5; break; case WT_SMG: flPenetrationDistance = 15; break; case WT_PISTOL: default: flPenetrationDistance = 15; break; } flPenetrationDistance = oBullet.m_hShooter->m_Shared.ModifySkillValue(flPenetrationDistance, 1, SKILL_MARKSMAN); Vector vecBackwards = tr.endpos + oBullet.m_vecDirection * flPenetrationDistance; if (tr.m_pEnt->IsBSPModel()) UTIL_TraceLine( vecBackwards, tr.endpos, CONTENTS_SOLID|CONTENTS_MOVEABLE, NULL, COLLISION_GROUP_NONE, &tr ); else UTIL_TraceLine( vecBackwards, tr.endpos, CONTENTS_HITBOX, NULL, COLLISION_GROUP_NONE, &tr ); if (tr.startsolid) { bFullPenetrationDistance = true; break; } // Set up the next trace. One unit in the direction of fire so that we firmly embed // ourselves in whatever solid was hit, to make sure we don't hit it again on next trace. if (dt < 0 && bBSPModel) { UTIL_TraceLine( vecTraceEnd + oBullet.m_vecDirection, vecTraceEnd + oBullet.m_vecDirection * flPenetrationDistance, CONTENTS_SOLID|CONTENTS_MOVEABLE, NULL, COLLISION_GROUP_NONE, &tr ); if (tr.startsolid) oBullet.m_vecOrigin = tr.startpos + oBullet.m_vecDirection; else oBullet.m_vecOrigin = vecTraceEnd + oBullet.m_vecDirection; } else oBullet.m_vecOrigin = vecTraceEnd + oBullet.m_vecDirection; } oBullet.m_iPenetrations = i; // the bullet's done penetrating, let's spawn our particle system if (oBullet.m_bDoEffects && dt < 0) oBullet.m_hShooter->MakeTracer( oBullet.m_vecOrigin, tr, TRACER_TYPE_DEFAULT, !bHasTraveledBefore ); #ifdef CLIENT_DLL if (oBullet.m_hRenderHandle != INVALID_CLIENT_RENDER_HANDLE) ClientLeafSystem()->RenderableChanged( oBullet.m_hRenderHandle ); #endif if (bFullPenetrationDistance || oBullet.m_iPenetrations >= da_bullet_penetrations.GetInt()) oBullet.Deactivate(); if (dt < 0) oBullet.Deactivate(); if (!bHasTraveledBefore && oBullet.m_flCurrAlpha == 0 && oBullet.m_flGoalAlpha == 0) oBullet.m_bActive = false; if (da_bullet_debug.GetBool()) { #ifdef CLIENT_DLL DebugDrawLine(vecOriginal, oBullet.m_vecOrigin, 0, 0, 255, true, dt<0?10:0.1); #else DebugDrawLine(vecOriginal, oBullet.m_vecOrigin, 255, 0, 0, true, dt<0?10:0.1); #endif } }