//=====================================================================================// // Purpose: Performs the screen shake and it checks to see if we hit an entity to // handle the proper damage // An entity here can be another player or a wood plank //=====================================================================================// void CTDPBludgeonWeaponBase::Hit( trace_t &tr, Activity nHitActivity ) { // Do we have a valid owner holding the weapon? CTDPPlayer *pPlayer = GetPlayerOwner(); if ( !pPlayer ) return; // Let's shake the screen a little AddViewKick(); // if tr.m_pEnt is not NULL it means we have hit a target if ( tr.m_pEnt != NULL ) { Vector vForward; pPlayer->EyeVectors( &vForward, NULL, NULL ); VectorNormalize( vForward ); // Process the damage and send it to the entity we just hit CTakeDamageInfo dmgInfo( GetOwner(), GetOwner(), GetDamageForActivity( nHitActivity ), DMG_CLUB ); CalculateMeleeDamageForce( &dmgInfo, vForward, tr.endpos ); tr.m_pEnt->DispatchTraceAttack( dmgInfo, vForward, &tr ); ApplyMultiDamage(); #if defined( GAME_DLL ) // Now hit all triggers along the ray that... TraceAttackToTriggers( dmgInfo, tr.startpos, tr.endpos, vForward ); #endif } // Apply an impact effect ImpactEffect( tr ); }
//------------------------------------------------------------------------------ // Purpose: Implement impact function //------------------------------------------------------------------------------ void CWeaponCrowbar::Hit( void ) { //Make sound for the AI #ifndef CLIENT_DLL CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); CSoundEnt::InsertSound( SOUND_BULLET_IMPACT, m_traceHit.endpos, 400, 0.2f, pPlayer ); CBaseEntity *pHitEntity = m_traceHit.m_pEnt; //Apply damage to a hit target if ( pHitEntity != NULL ) { Vector hitDirection; pPlayer->EyeVectors( &hitDirection, NULL, NULL ); VectorNormalize( hitDirection ); ClearMultiDamage(); CTakeDamageInfo info( GetOwner(), GetOwner(), sk_plr_dmg_crowbar.GetFloat(), DMG_CLUB ); CalculateMeleeDamageForce( &info, hitDirection, m_traceHit.endpos ); pHitEntity->DispatchTraceAttack( info, hitDirection, &m_traceHit ); ApplyMultiDamage(); // Now hit all triggers along the ray that... TraceAttackToTriggers( CTakeDamageInfo( GetOwner(), GetOwner(), sk_plr_dmg_crowbar.GetFloat(), DMG_CLUB ), m_traceHit.startpos, m_traceHit.endpos, hitDirection ); //Play an impact sound ImpactSound( pHitEntity ); } #endif //Apply an impact effect ImpactEffect(); }
//------------------------------------------------------------------------------ // Purpose: Implement impact function //------------------------------------------------------------------------------ void CBaseSDKBludgeonWeapon::Hit( trace_t &traceHit, Activity nHitActivity, bool bIsSecondary ) { CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); //Do view kick AddViewKick(); //Make sound for the AI CSoundEnt::InsertSound( SOUND_BULLET_IMPACT, traceHit.endpos, 400, 0.2f, pPlayer ); // This isn't great, but it's something for when the crowbar hits. pPlayer->RumbleEffect( RUMBLE_AR2, 0, RUMBLE_FLAG_RESTART ); CBaseEntity *pHitEntity = traceHit.m_pEnt; //Apply damage to a hit target if ( pHitEntity != NULL ) { Vector hitDirection; pPlayer->EyeVectors( &hitDirection, NULL, NULL ); VectorNormalize( hitDirection ); CTakeDamageInfo info( GetOwner(), GetOwner(), GetDamageForActivity( nHitActivity ), DMG_CLUB ); if( pPlayer && pHitEntity->IsNPC() ) { // If bonking an NPC, adjust damage. info.AdjustPlayerDamageInflictedForSkillLevel(); } CalculateMeleeDamageForce( &info, hitDirection, traceHit.endpos ); pHitEntity->DispatchTraceAttack( info, hitDirection, &traceHit ); ApplyMultiDamage(); // Now hit all triggers along the ray that... TraceAttackToTriggers( info, traceHit.startpos, traceHit.endpos, hitDirection ); if ( ToBaseCombatCharacter( pHitEntity ) ) { gamestats->Event_WeaponHit( pPlayer, !bIsSecondary, GetClassname(), info ); } } // Apply an impact effect ImpactEffect( traceHit ); }
//------------------------------------------------------------------------------ // Purpose: Implement impact function //------------------------------------------------------------------------------ void CBaseHL2MPBludgeonWeapon::Hit( trace_t &traceHit, Activity nHitActivity ) { CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); //Do view kick // AddViewKick(); CBaseEntity *pHitEntity = traceHit.m_pEnt; //Apply damage to a hit target if ( pHitEntity != NULL ) { Vector hitDirection; pPlayer->EyeVectors( &hitDirection, NULL, NULL ); VectorNormalize( hitDirection ); #ifndef CLIENT_DLL CTakeDamageInfo info( GetOwner(), GetOwner(), GetDamageForActivity( nHitActivity ), DMG_CLUB ); if( pPlayer && pHitEntity->IsNPC() ) { // If bonking an NPC, adjust damage. info.AdjustPlayerDamageInflictedForSkillLevel(); } CalculateMeleeDamageForce( &info, hitDirection, traceHit.endpos ); pHitEntity->DispatchTraceAttack( info, hitDirection, &traceHit ); ApplyMultiDamage(); // Now hit all triggers along the ray that... TraceAttackToTriggers( info, traceHit.startpos, traceHit.endpos, hitDirection ); #endif //DHL - Skillet if ( pHitEntity->entindex() == 0 ) WeaponSound( MELEE_HIT_WORLD ); else WeaponSound( MELEE_HIT ); } // Apply an impact effect ImpactEffect( traceHit ); }
//------------------------------------------------------------------------------ // Purpose : Starts the swing of the weapon and determines the animation // Input : bIsSecondary - is this a secondary attack? //------------------------------------------------------------------------------ void CBaseHL2MPBludgeonWeapon::Swing( int bIsSecondary ) { trace_t traceHit; // Try a ray CBasePlayer *pOwner = ToBasePlayer( GetOwner() ); if ( !pOwner ) return; Vector swingStart = pOwner->Weapon_ShootPosition( ); Vector forward; pOwner->EyeVectors( &forward, NULL, NULL ); Vector swingEnd = swingStart + forward * GetRange(); UTIL_TraceLine( swingStart, swingEnd, MASK_SHOT_HULL, pOwner, COLLISION_GROUP_NONE, &traceHit ); Activity nHitActivity = ACT_VM_HITCENTER; #ifndef CLIENT_DLL // Like bullets, bludgeon traces have to trace against triggers. CTakeDamageInfo triggerInfo( GetOwner(), GetOwner(), GetDamageForActivity( nHitActivity ), DMG_CLUB ); TraceAttackToTriggers( triggerInfo, traceHit.startpos, traceHit.endpos, vec3_origin ); #endif if ( traceHit.fraction == 1.0 ) { float bludgeonHullRadius = 1.732f * BLUDGEON_HULL_DIM; // hull is +/- 16, so use cuberoot of 2 to determine how big the hull is from center to the corner point // Back off by hull "radius" swingEnd -= forward * bludgeonHullRadius; UTIL_TraceHull( swingStart, swingEnd, g_bludgeonMins, g_bludgeonMaxs, MASK_SHOT_HULL, pOwner, COLLISION_GROUP_NONE, &traceHit ); if ( traceHit.fraction < 1.0 && traceHit.m_pEnt ) { Vector vecToTarget = traceHit.m_pEnt->GetAbsOrigin() - swingStart; VectorNormalize( vecToTarget ); float dot = vecToTarget.Dot( forward ); // YWB: Make sure they are sort of facing the guy at least... if ( dot < 0.70721f ) { // Force amiss traceHit.fraction = 1.0f; } else { nHitActivity = ChooseIntersectionPointAndActivity( traceHit, g_bludgeonMins, g_bludgeonMaxs, pOwner ); } } } WeaponSound( SINGLE ); // ------------------------- // Miss // ------------------------- if ( traceHit.fraction == 1.0f ) { nHitActivity = bIsSecondary ? ACT_VM_MISSCENTER2 : ACT_VM_MISSCENTER; // We want to test the first swing again Vector testEnd = swingStart + forward * GetRange(); // See if we happened to hit water ImpactWater( swingStart, testEnd ); } else { Hit( traceHit, nHitActivity ); } // Send the anim SendWeaponAnim( nHitActivity ); pOwner->SetAnimation( PLAYER_ATTACK1 ); ToHL2MPPlayer(pOwner)->DoAnimationEvent( PLAYERANIMEVENT_ATTACK_PRIMARY ); //Setup our next attack times m_flNextPrimaryAttack = gpGlobals->curtime + GetFireRate(); m_flNextSecondaryAttack = gpGlobals->curtime + SequenceDuration(); }
//=====================================================================================// // Purpose: Swing the weapon. bIsSecondary determines which Attack() function was used //=====================================================================================// void CTDPWeaponMaul::Swing( int bIsSecondary ) { // Do we have a valid owner holding the weapon? CTDPPlayer *pPlayer = GetPlayerOwner(); if ( !pPlayer ) return; // Get the player's position Vector vSwingStart = pPlayer->Weapon_ShootPosition( ); Vector vForward; pPlayer->EyeVectors( &vForward, NULL, NULL ); // Get the attack end position by using the weapon's range Vector vSwingEnd = vSwingStart + vForward * GetRange(); trace_t tr; UTIL_TraceLine( vSwingStart, vSwingEnd, MASK_SHOT_HULL, pPlayer, COLLISION_GROUP_NONE, &tr ); // Let's get our animation sequence depending on the attack type Activity nHitActivity = ( bIsSecondary ) ? GetSecondaryAttackActivity() : GetPrimaryAttackActivity(); #if defined( GAME_DLL ) // Like bullets, bludgeon traces have to trace against triggers. CTakeDamageInfo triggerInfo( GetOwner(), GetOwner(), GetDamageForActivity( nHitActivity ), DMG_CLUB ); TraceAttackToTriggers( triggerInfo, tr.startpos, tr.endpos, vec3_origin ); #endif // We didn't hit anything. Let's check for hull trace now if ( tr.fraction == 1.0f ) { // hull is +/- 16, so use cuberoot of 2 to determine how big the hull is from center to the corner point float bludgeonHullRadius = 1.732f * BLUDGEON_HULL_DIM; // Back off by hull "radius" vSwingEnd -= vForward * bludgeonHullRadius; UTIL_TraceHull( vSwingStart, vSwingEnd, g_bludgeonMins, g_bludgeonMaxs, MASK_SHOT_HULL, pPlayer, COLLISION_GROUP_NONE, &tr ); // Check if we hit something and if we have hit an entity if ( tr.fraction < 1.0 && tr.m_pEnt ) { // Get the position of the entity we just hit Vector vToTarget = tr.m_pEnt->GetAbsOrigin() - vSwingStart; VectorNormalize( vToTarget ); float dot = vToTarget.Dot( vForward ); // Make sure they are sort of facing the guy at least... if ( dot < 0.70721f ) { // Force a miss tr.fraction = 1.0f; } else { // We are sort of facing something. Let's see we should impact based on the melee swing trajectory BaseClass::ChooseIntersectionPointAndActivity( tr, g_bludgeonMins, g_bludgeonMaxs, pPlayer ); } } } // See if we happened to hit water along the way BaseClass::ImpactWater( vSwingStart, tr.endpos ); // Check for hit results if ( tr.fraction == 1.0f ) { // We didn't hit anything so let's change the animation sequence to full swing nHitActivity = ( bIsSecondary ) ? GetSecondaryMissActivity() : GetPrimaryMissActivity(); } else { // We hit something. We can keep the same animation sequence. BaseClass::Hit( tr, nHitActivity ); } //Play swing sound WeaponSound( SINGLE ); // Send the anim SendWeaponAnim( nHitActivity ); // Setup our next attack times m_flNextPrimaryAttack = m_flNextSecondaryAttack = gpGlobals->curtime + GetFireRate(); // Setup our next time to idle m_flTimeWeaponIdle = gpGlobals->curtime + GetTime2Idle(); }
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 }
void CBaseHLBludgeonWeapon::MotionSwing( const Vector &pos, const Vector &dir, float velocity ) { trace_t traceHit; // Try a ray CBasePlayer *pOwner = ToBasePlayer( GetOwner() ); if ( !pOwner ) return; Vector v; Vector swingStart = pos; Vector forward = dir/dir.Length(); //dir*velocity; Vector swingEnd = swingStart + forward * (GetRange()*.75); UTIL_TraceLine( swingStart, swingEnd, MASK_SHOT_HULL, pOwner, COLLISION_GROUP_NONE, &traceHit ); Activity nHitActivity = ACT_VM_HITCENTER; // Like bullets, bludgeon traces have to trace against triggers. CTakeDamageInfo triggerInfo( GetOwner(), GetOwner(), GetDamageForActivity( nHitActivity ), DMG_CLUB ); triggerInfo.SetDamagePosition( traceHit.startpos ); triggerInfo.SetDamageForce( forward ); TraceAttackToTriggers( triggerInfo, traceHit.startpos, traceHit.endpos, forward ); if ( traceHit.fraction == 1.0 ) { float bludgeonHullRadius = 1.732f * BLUDGEON_HULL_DIM; // hull is +/- 16, so use cuberoot of 2 to determine how big the hull is from center to the corner point // Back off by hull "radius" swingEnd -= forward * bludgeonHullRadius; UTIL_TraceHull( swingStart, swingEnd, g_bludgeonMins, g_bludgeonMaxs, MASK_SHOT_HULL, pOwner, COLLISION_GROUP_NONE, &traceHit ); if ( traceHit.fraction < 1.0 && traceHit.m_pEnt ) { Vector vecToTarget = traceHit.m_pEnt->GetAbsOrigin() - swingStart; VectorNormalize( vecToTarget ); float dot = vecToTarget.Dot( forward ); // YWB: Make sure they are sort of facing the guy at least... if ( dot < 0.70721f ) { // Force amiss traceHit.fraction = 1.0f; } else { nHitActivity = ChooseIntersectionPointAndActivity( traceHit, g_bludgeonMins, g_bludgeonMaxs, pOwner ); } } } gamestats->Event_WeaponFired( pOwner, true, GetClassname() ); // ------------------------- // Miss // ------------------------- float motionFireRate = GetFireRate()*.75; if ( traceHit.fraction == 1.0f ) { nHitActivity = ACT_VM_MISSCENTER; // We want to test the first swing again Vector testEnd = swingStart + forward * GetRange(); // See if we happened to hit water if ( ImpactWater( swingStart, testEnd ) ) m_flNextPrimaryAttack = gpGlobals->curtime + motionFireRate; } else { Hit( traceHit, nHitActivity, false ? true : false ); SendWeaponAnim( ACT_VM_HITDYNAMIC ); //Setup our next attack times m_flNextPrimaryAttack = gpGlobals->curtime + motionFireRate; m_flNextSecondaryAttack = gpGlobals->curtime + motionFireRate; } }
//------------------------------------------------------------------------------ // Purpose : Starts the swing of the weapon and determines the animation // Input : bIsSecondary - is this a secondary attack? //------------------------------------------------------------------------------ void CBaseSDKBludgeonWeapon::Swing( int bIsSecondary ) { trace_t traceHit; // Try a ray CBasePlayer *pOwner = ToBasePlayer( GetOwner() ); if ( !pOwner ) return; pOwner->RumbleEffect( RUMBLE_CROWBAR_SWING, 0, RUMBLE_FLAG_RESTART ); Vector swingStart = pOwner->Weapon_ShootPosition( ); Vector forward; forward = pOwner->GetAutoaimVector( AUTOAIM_SCALE_DEFAULT, GetRange() ); Vector swingEnd = swingStart + forward * GetRange(); UTIL_TraceLine( swingStart, swingEnd, MASK_SHOT_HULL, pOwner, COLLISION_GROUP_NONE, &traceHit ); Activity nHitActivity = ACT_VM_HITCENTER; // Like bullets, bludgeon traces have to trace against triggers. CTakeDamageInfo triggerInfo( GetOwner(), GetOwner(), GetDamageForActivity( nHitActivity ), DMG_CLUB ); triggerInfo.SetDamagePosition( traceHit.startpos ); triggerInfo.SetDamageForce( forward ); TraceAttackToTriggers( triggerInfo, traceHit.startpos, traceHit.endpos, forward ); if ( traceHit.fraction == 1.0 ) { float bludgeonHullRadius = 1.732f * BLUDGEON_HULL_DIM; // hull is +/- 16, so use cuberoot of 2 to determine how big the hull is from center to the corner point // Back off by hull "radius" swingEnd -= forward * bludgeonHullRadius; UTIL_TraceHull( swingStart, swingEnd, g_bludgeonMins, g_bludgeonMaxs, MASK_SHOT_HULL, pOwner, COLLISION_GROUP_NONE, &traceHit ); if ( traceHit.fraction < 1.0 && traceHit.m_pEnt ) { Vector vecToTarget = traceHit.m_pEnt->GetAbsOrigin() - swingStart; VectorNormalize( vecToTarget ); float dot = vecToTarget.Dot( forward ); // YWB: Make sure they are sort of facing the guy at least... if ( dot < 0.70721f ) { // Force amiss traceHit.fraction = 1.0f; } else { nHitActivity = ChooseIntersectionPointAndActivity( traceHit, g_bludgeonMins, g_bludgeonMaxs, pOwner ); } } } if ( !bIsSecondary ) { m_iPrimaryAttacks++; } else { m_iSecondaryAttacks++; } gamestats->Event_WeaponFired( pOwner, !bIsSecondary, GetClassname() ); // ------------------------- // Miss // ------------------------- if ( traceHit.fraction == 1.0f ) { nHitActivity = bIsSecondary ? ACT_VM_MISSCENTER2 : ACT_VM_MISSCENTER; // We want to test the first swing again Vector testEnd = swingStart + forward * GetRange(); // See if we happened to hit water ImpactWater( swingStart, testEnd ); } else { Hit( traceHit, nHitActivity, bIsSecondary ? true : false ); } // Send the anim SendWeaponAnim( nHitActivity ); //Setup our next attack times m_flNextPrimaryAttack = gpGlobals->curtime + GetFireRate(); m_flNextSecondaryAttack = gpGlobals->curtime + SequenceDuration(); //Play swing sound WeaponSound( SINGLE ); }
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 ); }
//------------------------------------------------------------------------------ // Purpose: Implement impact function //------------------------------------------------------------------------------ void CBaseHL2MPBludgeonWeapon::Hit( trace_t &traceHit, Activity nHitActivity ) { CBasePlayer *pPlayer = ToBasePlayer( GetOwner() ); //Do view kick // AddViewKick(); CBaseEntity *pHitEntity = traceHit.m_pEnt; //Apply damage to a hit target if ( pHitEntity != NULL ) { Vector hitDirection; pPlayer->EyeVectors( &hitDirection, NULL, NULL ); VectorNormalize( hitDirection ); #ifndef CLIENT_DLL CTakeDamageInfo info( GetOwner(), GetOwner(), GetDamageForActivity( nHitActivity ), DMG_CLUB ); if( pPlayer && pHitEntity->IsNPC() ) { // If bonking an NPC, adjust damage. info.AdjustPlayerDamageInflictedForSkillLevel(); } //BB: don't damage imortals if (pPlayer && pHitEntity->IsPlayer()) { if (((CHL2MP_Player *)pHitEntity)->KO) { info.SetDamage(0.0f); } } //BB: check for server doll, this means it is a STAKE hit, apply the damage to the player. if (pPlayer && pHitEntity->IsServerdoll()) { //we have hit a ragdoll... see if it has an alive player if (((CRagdollProp *)pHitEntity)->myBody != NULL && ((CRagdollProp *)pHitEntity)->team == COVEN_TEAMID_VAMPIRES) { //kill the player CTakeDamageInfo newinfo = info; newinfo.SetDamage(999.0f); ((CRagdollProp *)pHitEntity)->myBody->OnTakeDamage( newinfo ); } } CalculateMeleeDamageForce( &info, hitDirection, traceHit.endpos ); pHitEntity->DispatchTraceAttack( info, hitDirection, &traceHit ); ApplyMultiDamage(); // Now hit all triggers along the ray that... TraceAttackToTriggers( info, traceHit.startpos, traceHit.endpos, hitDirection ); #endif //BB: fix this so that we have two distinct sounds if (pHitEntity->IsPlayer() || pHitEntity->IsNPC()) WeaponSound( MELEE_HIT ); else if (pHitEntity->GetMoveType() != MOVETYPE_NONE) WeaponSound( SPECIAL1 ); else WeaponSound( MELEE_HIT_WORLD ); } // Apply an impact effect ImpactEffect( traceHit ); }
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 } }