void CNPC_ControllerZapBall::ExplodeTouch( CBaseEntity *pOther ) { if (m_takedamage = DAMAGE_YES ) { trace_t tr; tr = GetTouchTrace( ); ClearMultiDamage( ); Vector vecAttackDir = GetAbsVelocity(); VectorNormalize( vecAttackDir ); if (m_hOwner != NULL) { CTakeDamageInfo info( this, m_hOwner, sk_controller_dmgball.GetFloat(), DMG_ENERGYBEAM ); CalculateMeleeDamageForce( &info, vecAttackDir, tr.endpos ); pOther->DispatchTraceAttack( info, vecAttackDir, &tr ); } else { CTakeDamageInfo info( this, this, sk_controller_dmgball.GetFloat(), DMG_ENERGYBEAM ); CalculateMeleeDamageForce( &info, vecAttackDir, tr.endpos ); pOther->DispatchTraceAttack( info, vecAttackDir, &tr ); } ApplyMultiDamage(); // void UTIL_EmitAmbientSound( CBaseEntity *entity, const Vector &vecOrigin, const char *samp, float vol, soundlevel_t soundlevel, int fFlags, int pitch, float soundtime /*= 0.0f*/ ) UTIL_EmitAmbientSound( GetSoundSourceIndex(), tr.endpos, "Controller.ElectroSound", 0.3, SNDLVL_NORM, 0, random->RandomInt( 90, 99 ) ); } Kill(); }
void CNPC_Infected::MeleeAttack( float distance, float damage, QAngle &viewPunch, Vector &shove ) { Vector vecForceDir; // Always hurt bullseyes for now if ( ( GetEnemy() != NULL ) && ( GetEnemy()->Classify() == CLASS_BULLSEYE ) ) { vecForceDir = (GetEnemy()->GetAbsOrigin() - GetAbsOrigin()); CTakeDamageInfo info( this, this, damage, DMG_SLASH ); CalculateMeleeDamageForce( &info, vecForceDir, GetEnemy()->GetAbsOrigin() ); GetEnemy()->TakeDamage( info ); return; } CBaseEntity *pHurt = CheckTraceHullAttack( distance, -Vector(16,16,32), Vector(16,16,32), damage, DMG_SLASH, 5.0f ); if ( pHurt ) { vecForceDir = ( pHurt->WorldSpaceCenter() - WorldSpaceCenter() ); //FIXME: Until the interaction is setup, kill combine soldiers in one hit -- jdw if ( FClassnameIs( pHurt, "npc_combine_s" ) ) { CTakeDamageInfo dmgInfo( this, this, pHurt->m_iHealth+25, DMG_SLASH ); CalculateMeleeDamageForce( &dmgInfo, vecForceDir, pHurt->GetAbsOrigin() ); pHurt->TakeDamage( dmgInfo ); return; } CBasePlayer *pPlayer = ToBasePlayer( pHurt ); if ( pPlayer != NULL ) { //Kick the player angles if ( !(pPlayer->GetFlags() & FL_GODMODE ) && pPlayer->GetMoveType() != MOVETYPE_NOCLIP ) { pPlayer->ViewPunch( viewPunch ); Vector dir = pHurt->GetAbsOrigin() - GetAbsOrigin(); VectorNormalize(dir); QAngle angles; VectorAngles( dir, angles ); Vector forward, right; AngleVectors( angles, &forward, &right, NULL ); //Push the target back pHurt->ApplyAbsVelocityImpulse( - right * shove[1] - forward * shove[0] ); } } // Play a random attack hit sound EmitSound( "Zombie.Punch" ); } else { EmitSound( "Zombie.AttackMiss" ); } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CPlayerClassCommando::BullRushTouch( CBaseEntity *pTouched ) { if ( pTouched->IsPlayer() && !pTouched->InSameTeam( m_pPlayer ) ) { // Get the player. CBaseTFPlayer *pTFPlayer = ( CBaseTFPlayer* )pTouched; // Check to see if we have "touched" this player already this bullrush cycle. if ( m_aHitPlayers.Find( pTFPlayer ) != -1 ) return; // Hitting the player now. m_aHitPlayers.AddToTail( pTFPlayer ); // ROBIN: Bullrush now instantly kills again float flDamage = 200; // Calculate the damage a player takes based on distance(time). //float flDamage = 1.0f - ( ( COMMANDO_BULLRUSH_TIME - m_ClassData.m_flBullRushTime ) * ( 1.0f / COMMANDO_BULLRUSH_TIME ) ); //flDamage *= 115.0f; // max bullrush damage trace_t tr = m_pPlayer->GetTouchTrace(); CTakeDamageInfo info( m_pPlayer, m_pPlayer, flDamage, DMG_CLUB, DMG_KILL_BULLRUSH ); CalculateMeleeDamageForce( &info, (tr.endpos - tr.startpos), tr.endpos ); pTFPlayer->TakeDamage( info ); CPASAttenuationFilter filter( m_pPlayer, "Commando.BullRushFlesh" ); CBaseEntity::EmitSound( filter, m_pPlayer->entindex(), "Commando.BullRushFlesh" ); pTFPlayer->Touch( m_pPlayer ); } }
void CNPC_Hydra::Stab( CBaseEntity *pOther, const Vector &vecSpeed, trace_t &tr ) { if (pOther->m_takedamage == DAMAGE_YES && !pOther->IsPlayer()) { Vector dir = vecSpeed; VectorNormalize( dir ); if ( !sv_hydraTestSpike.GetInt() ) { ClearMultiDamage(); // FIXME: this is bogus CTakeDamageInfo info( this, this, pOther->m_iHealth+25, DMG_SLASH ); CalculateMeleeDamageForce( &info, dir, tr.endpos ); pOther->DispatchTraceAttack( info, dir, &tr ); ApplyMultiDamage(); } else { CBaseAnimating *pAnimating = dynamic_cast<CBaseAnimating *>(pOther); if ( pAnimating ) { AttachStabbedEntity( pAnimating, vecSpeed * 30, tr ); } } } else { Nudge( pOther, tr.endpos, vecSpeed ); } }
//=====================================================================================// // 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 ); }
void CGrenadeEnergy::GrenadeEnergyTouch( CBaseEntity *pOther ) { if ( pOther->m_takedamage ) { float flLifeLeft = 1-(gpGlobals->curtime - m_flLaunchTime)/ENERGY_GRENADE_LIFETIME; if ( pOther->GetFlags() & (FL_CLIENT) ) { CBasePlayer *pPlayer = ( CBasePlayer * )pOther; float flKick = 120 * flLifeLeft; pPlayer->m_Local.m_vecPunchAngle.SetX( flKick * (random->RandomInt(0,1) == 1) ? -1 : 1 ); pPlayer->m_Local.m_vecPunchAngle.SetY( flKick * (random->RandomInt(0,1) == 1) ? -1 : 1 ); } float flDamage = m_flDamage * flLifeLeft; if (flDamage < 1) { flDamage = 1; } trace_t tr; tr = GetTouchTrace(); CTakeDamageInfo info( this, GetThrower(), m_flDamage * flLifeLeft, DMG_SONIC ); CalculateMeleeDamageForce( &info, (tr.endpos - tr.startpos), tr.endpos ); pOther->TakeDamage( info ); } Detonate(); }
//------------------------------------------------------------------------------ // 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(); }
// Overridden for Gargantua because his swing starts lower as // a percentage of his height (otherwise he swings over the // players head) //========================================================= CBaseEntity* CNPC_Gargantua::GargantuaCheckTraceHullAttack(float flDist, int iDamage, int iDmgType) { trace_t tr; Vector vForward, vUp; AngleVectors( GetAbsAngles(), &vForward, NULL, &vUp ); Vector vecStart = GetAbsOrigin(); vecStart.z += 64; Vector vecEnd = vecStart + ( vForward * flDist) - ( vUp * flDist * 0.3); //UTIL_TraceHull( vecStart, vecEnd, dont_ignore_monsters, head_hull, ENT(pev), &tr ); UTIL_TraceEntity( this, GetAbsOrigin(), vecEnd, MASK_SOLID, &tr ); if ( tr.m_pEnt ) { CBaseEntity *pEntity = tr.m_pEnt; if ( iDamage > 0 ) { CTakeDamageInfo info( this, this, iDamage, iDmgType ); CalculateMeleeDamageForce( &info, vForward, tr.endpos ); pEntity->TakeDamage( info ); } return pEntity; } return NULL; }
void CNPC_Tentacle::HitTouch( CBaseEntity *pOther ) { if (m_flHitTime > gpGlobals->curtime) return; // only look at the ones where the player hit me if( pOther == NULL || pOther->GetModelIndex() == GetModelIndex() || ( pOther->GetSolidFlags() & FSOLID_TRIGGER ) ) return; //Right now the BoneFollower will always be hit in box 0, and //will pass that to us. Make *any* touch by the physics objects a kill //as the ragdoll only covers the top portion of the tentacle. if ( pOther->m_takedamage ) { CTakeDamageInfo info( this, this, m_iHitDmg, DMG_CLUB ); Vector vDamageForce = pOther->GetAbsOrigin() - GetAbsOrigin(); VectorNormalize( vDamageForce ); CalculateMeleeDamageForce( &info, vDamageForce, pOther->GetAbsOrigin() ); pOther->TakeDamage( info ); m_flHitTime = gpGlobals->curtime + 0.5; } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CBaseProjectile::ProjectileTouch( CBaseEntity *pOther ) { // Verify a correct "other." Assert( pOther ); if ( !pOther->IsSolid() || pOther->IsSolidFlagSet( FSOLID_VOLUME_CONTENTS ) ) return; // Handle hitting skybox (disappear). const trace_t *pTrace = &CBaseEntity::GetTouchTrace(); trace_t *pNewTrace = const_cast<trace_t*>( pTrace ); if( pTrace->surface.flags & SURF_SKY ) { UTIL_Remove( this ); return; } CTakeDamageInfo info; info.SetAttacker( GetOwnerEntity() ); info.SetInflictor( this ); info.SetDamage( GetDamage() ); info.SetDamageType( GetDamageType() ); CalculateMeleeDamageForce( &info, GetAbsVelocity(), GetAbsOrigin(), GetDamageScale() ); Vector dir; AngleVectors( GetAbsAngles(), &dir ); pOther->DispatchTraceAttack( info, dir, pNewTrace ); ApplyMultiDamage(); UTIL_Remove( this ); }
int CASW_Parasite::CalcDamageInfo( CTakeDamageInfo *pInfo ) { Assert(ASWGameRules()); pInfo->Set( this, this, asw_parasite_defanged_damage.GetFloat(), DMG_ACID ); CalculateMeleeDamageForce( pInfo, GetAbsVelocity(), GetAbsOrigin() ); return pInfo->GetDamage(); }
void CStomp::Think( void ) { trace_t tr; SetNextThink( gpGlobals->curtime + 0.1 ); // Do damage for this frame Vector vecStart = GetAbsOrigin(); vecStart.z += 30; Vector vecEnd = vecStart + (m_vecMoveDir * m_flSpeed * gpGlobals->frametime); UTIL_TraceHull( vecStart, vecEnd, Vector(-32, -32, -32), Vector(32, 32, 32), MASK_SOLID, m_pOwner, COLLISION_GROUP_NONE, &tr ); // NDebugOverlay::Line( vecStart, vecEnd, 0, 255, 0, false, 10.0f ); if ( tr.m_pEnt ) { CBaseEntity *pEntity = tr.m_pEnt; CTakeDamageInfo info( this, this, 50, DMG_SONIC ); CalculateMeleeDamageForce( &info, m_vecMoveDir, tr.endpos ); pEntity->TakeDamage( info ); } // Accelerate the effect m_flSpeed += (gpGlobals->frametime) * m_uiFramerate; m_uiFramerate += (gpGlobals->frametime) * 2000; // Move and spawn trails while ( gpGlobals->curtime - m_flDmgTime > STOMP_INTERVAL ) { SetAbsOrigin( GetAbsOrigin() + m_vecMoveDir * m_flSpeed * STOMP_INTERVAL ); for ( int i = 0; i < 2; i++ ) { CSprite *pSprite = CSprite::SpriteCreate( GARG_STOMP_SPRITE_NAME, GetAbsOrigin(), TRUE ); if ( pSprite ) { UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() - Vector(0,0,500), MASK_SOLID, this, COLLISION_GROUP_NONE, &tr ); pSprite->SetAbsOrigin( tr.endpos ); // pSprite->pev->velocity = Vector(RandomFloat(-200,200),RandomFloat(-200,200),175); pSprite->SetNextThink( gpGlobals->curtime + 0.3 ); pSprite->SetThink( &CSprite::SUB_Remove ); pSprite->SetTransparency( kRenderTransAdd, 255, 255, 255, 255, kRenderFxFadeFast ); } g_pEffects->EnergySplash( tr.endpos, tr.plane.normal ); } m_flDmgTime += STOMP_INTERVAL; // Scale has the "life" of this effect m_flScale -= STOMP_INTERVAL * m_flSpeed; if ( m_flScale <= 0 ) { // Life has run out UTIL_Remove(this); // STOP_SOUND( edict(), CHAN_BODY, GARG_STOMP_BUZZ_SOUND ); CPASAttenuationFilter filter( this ); StopSound( entindex(), CHAN_STATIC, GARG_STOMP_BUZZ_SOUND ); } } }
//--------------------------------------------------------- //--------------------------------------------------------- void CNPC_Assassin::HandleAnimEvent( animevent_t *pEvent ) { if ( pEvent->event == AE_ASSASIN_FIRE_PISTOL_RIGHT ) { FirePistol( 0 ); return; } if ( pEvent->event == AE_ASSASIN_FIRE_PISTOL_LEFT ) { FirePistol( 1 ); return; } if ( pEvent->event == AE_ASSASIN_KICK_HIT ) { Vector attackDir = BodyDirection2D(); Vector attackPos = WorldSpaceCenter() + ( attackDir * 64.0f ); trace_t tr; UTIL_TraceHull( WorldSpaceCenter(), attackPos, -Vector(8,8,8), Vector(8,8,8), MASK_SHOT_HULL, this, COLLISION_GROUP_NONE, &tr ); if ( ( tr.m_pEnt != NULL ) && ( tr.DidHitWorld() == false ) ) { if ( tr.m_pEnt->m_takedamage != DAMAGE_NO ) { CTakeDamageInfo info( this, this, 5, DMG_CLUB ); CalculateMeleeDamageForce( &info, (tr.endpos - tr.startpos), tr.endpos ); tr.m_pEnt->TakeDamage( info ); CBasePlayer *pPlayer = ToBasePlayer( tr.m_pEnt ); if ( pPlayer != NULL ) { //Kick the player angles pPlayer->ViewPunch( QAngle( -30, 40, 10 ) ); } EmitSound( "Zombie.AttackHit" ); //EmitSound( "Assassin.AttackHit" ); } } else { EmitSound( "Assassin.AttackMiss" ); //EmitSound( "Assassin.AttackMiss" ); } return; } BaseClass::HandleAnimEvent( pEvent ); }
//========================================================= // ArmBeam - small beam from arm to nearby geometry //========================================================= void CNPC_Vortigaunt::ArmBeam( int side ) { trace_t tr; float flDist = 1.0; if ( m_iBeams >= VORTIGAUNT_MAX_BEAMS ) return; Vector forward, right, up; Vector vecAim; AngleVectors( GetAbsAngles(), &forward, &right, &up ); Vector vecSrc = GetAbsOrigin() + up * 36 + right * side * 16 + forward * 32; for (int i = 0; i < 3; i++) { vecAim = right * side * random->RandomFloat( 0, 1 ) + up * random->RandomFloat( -1, 1 ); trace_t tr1; UTIL_TraceLine ( vecSrc, vecSrc + vecAim * 512, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr1); if (flDist > tr1.fraction) { tr = tr1; flDist = tr.fraction; } } // Couldn't find anything close enough if ( flDist == 1.0 ) return; if( tr.m_pEnt && tr.m_pEnt->m_takedamage ) { CTakeDamageInfo info( this, this, 10, DMG_SHOCK ); CalculateMeleeDamageForce( &info, vecAim, tr.endpos ); tr.m_pEnt->TakeDamage( info ); } UTIL_ImpactTrace( &tr, DMG_CLUB ); m_pBeam[m_iBeams] = CBeam::BeamCreate( "sprites/lgtning.vmt", 3.0f ); if ( m_pBeam[m_iBeams] == NULL ) return; m_pBeam[m_iBeams]->PointEntInit( tr.endpos, this ); m_pBeam[m_iBeams]->SetEndAttachment( side < 0 ? 2 : 1 ); m_pBeam[m_iBeams]->SetColor( 96, 128, 16 ); m_pBeam[m_iBeams]->SetBrightness( 64 ); m_pBeam[m_iBeams]->SetNoise( 12.8 ); m_iBeams++; }
//----------------------------------------------------------------------------- // 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: 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 ); }
void CBreakable::BreakTouch( CBaseEntity *pOther ) { float flDamage; // only players can break these right now if ( !pOther->IsPlayer() || !IsBreakable() ) { return; } // can I be broken when run into? if ( HasSpawnFlags( SF_BREAK_TOUCH ) ) { flDamage = pOther->GetSmoothedVelocity().Length() * 0.01; if (flDamage >= m_iHealth) { m_takedamage = DAMAGE_YES; SetTouch( NULL ); OnTakeDamage( CTakeDamageInfo( pOther, pOther, flDamage, DMG_CRUSH ) ); // do a little damage to player if we broke glass or computer CTakeDamageInfo info( pOther, pOther, flDamage/4, DMG_SLASH ); CalculateMeleeDamageForce( &info, (pOther->GetAbsOrigin() - GetAbsOrigin()), GetAbsOrigin() ); pOther->TakeDamage( info ); } } // can I be broken when stood upon? if ( HasSpawnFlags( SF_BREAK_PRESSURE ) && pOther->GetGroundEntity() == this ) { // play creaking sound here. DamageSound(); m_hBreaker = pOther; SetThink ( &CBreakable::Die ); SetTouch( NULL ); // Add optional delay SetNextThink( gpGlobals->curtime + m_flPressureDelay ); } }
//------------------------------------------------------------------------------ // 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 ); }
void CASW_Harvester::StartTouch( CBaseEntity *pOther ) { BaseClass::StartTouch( pOther ); CASW_Marine *pMarine = CASW_Marine::AsMarine( pOther ); if (pMarine) { // don't hurt him if he was hurt recently if (m_fLastTouchHurtTime + 0.6f > gpGlobals->curtime) { return; } // hurt the marine Vector vecForceDir = (pMarine->GetAbsOrigin() - GetAbsOrigin()); CTakeDamageInfo info( this, this, asw_harvester_touch_damage.GetInt(), DMG_SLASH ); CalculateMeleeDamageForce( &info, vecForceDir, pMarine->GetAbsOrigin() ); pMarine->TakeDamage( info ); m_fLastTouchHurtTime = gpGlobals->curtime; } }
//----------------------------------------------------------------------------- // Purpose: Damages anything in the beam. // Input : ptr - //----------------------------------------------------------------------------- void CBeam::BeamDamage( trace_t *ptr ) { RelinkBeam(); #if !defined( CLIENT_DLL ) if ( ptr->fraction != 1.0 && ptr->m_pEnt != NULL ) { CBaseEntity *pHit = ptr->m_pEnt; if ( pHit ) { ClearMultiDamage(); Vector dir = ptr->endpos - GetAbsOrigin(); VectorNormalize( dir ); int nDamageType = DMG_ENERGYBEAM; #ifndef HL1_DLL if (m_nDissolveType == 0) { nDamageType = DMG_DISSOLVE; } else if ( m_nDissolveType > 0 ) { nDamageType = DMG_DISSOLVE | DMG_SHOCK; } #endif CTakeDamageInfo info( this, this, m_flDamage * (gpGlobals->curtime - m_flFireTime), nDamageType ); CalculateMeleeDamageForce( &info, dir, ptr->endpos ); pHit->DispatchTraceAttack( info, dir, ptr ); ApplyMultiDamage(); if ( HasSpawnFlags( SF_BEAM_DECALS ) ) { if ( pHit->IsBSPModel() ) { UTIL_DecalTrace( ptr, GetDecalName() ); } } } } #endif m_flFireTime = gpGlobals->curtime; }
//softcopy: ignited/explode marine by boomer on touch/on fire touch, 1=melee, 2=touch, 3=All void CASW_Boomer::StartTouch( CBaseEntity *pOther ) { BaseClass::StartTouch( pOther ); CASW_Marine *pMarine = CASW_Marine::AsMarine( pOther ); if ( pMarine ) { m_TouchExplosionDamage = asw_boomer_touch_damage.GetInt(); CTakeDamageInfo info( this, this, m_TouchExplosionDamage, DMG_SLASH ); damageTypes = "on touch"; if (asw_boomer_ignite.GetInt() >= 2 || (m_bOnFire && asw_boomer_touch_onfire.GetBool())) MarineIgnite(pMarine, info, alienLabel, damageTypes); if ( m_fLastTouchHurtTime + 0.35f /*0.6f*/ > gpGlobals->curtime || m_TouchExplosionDamage <=0 ) //don't hurt him if he was hurt recently return; Vector vecForceDir = ( pMarine->GetAbsOrigin() - GetAbsOrigin() ); // hurt the marine CalculateMeleeDamageForce( &info, vecForceDir, pMarine->GetAbsOrigin() ); pMarine->TakeDamage( info ); if (asw_boomer_explode.GetInt() >= 2 ) MarineExplode(pMarine, alienLabel, damageTypes); m_fLastTouchHurtTime = gpGlobals->curtime; } }
//----------------------------------------------------------------------------- // Purpose: // Input : // Output : //----------------------------------------------------------------------------- void CGrenade_Brickbat::BrickbatTouch( CBaseEntity *pOther ) { // ----------------------------------------------------------- // Might be physically simulated so get my velocity manually // ----------------------------------------------------------- Vector vVelocity; GetVelocity(&vVelocity,NULL); // ----------------------------------- // Do damage if we moving fairly fast // ----------------------------------- if (vVelocity.Length() > 100) { if (GetThrower()) { trace_t tr; tr = CBaseEntity::GetTouchTrace( ); ClearMultiDamage( ); Vector forward; AngleVectors( GetLocalAngles(), &forward ); CTakeDamageInfo info( this, GetThrower(), m_flDamage, DMG_CRUSH ); CalculateMeleeDamageForce( &info, forward, tr.endpos ); pOther->DispatchTraceAttack( info, forward, &tr ); ApplyMultiDamage(); } // If this thrown item explodes, blow it up if (m_bExplodes) { Detonate(); return; } } else if (pOther->GetFlags() & FL_CLIENT) { SpawnBrickbatWeapon(); return; } }
//----------------------------------------------------------------------------- // Purpose: Automatic Melee Attack //----------------------------------------------------------------------------- void CPlayerClassCommando::Boot( CBaseTFPlayer *pTarget ) { CPASAttenuationFilter filter( m_pPlayer, "Commando.BootSwing" ); CBaseEntity::EmitSound( filter, m_pPlayer->entindex(), "Commando.BootSwing" ); CBaseEntity::EmitSound( filter, m_pPlayer->entindex(), "Commando.BootHit" ); // Damage the target CTakeDamageInfo info( m_pPlayer, m_pPlayer, 25, DMG_CLUB ); CalculateMeleeDamageForce( &info, (pTarget->GetAbsOrigin() - m_pPlayer->GetAbsOrigin()), pTarget->GetAbsOrigin() ); pTarget->TakeDamage( info ); Vector vecForward; AngleVectors( m_pPlayer->GetLocalAngles(), &vecForward ); // Give it a lot of "in the air" vecForward.z = max( 0.8, vecForward.z ); VectorNormalize( vecForward ); // Knock the target to the ground for a few seconds (use default duration) pTarget->KnockDownPlayer( vecForward, 500.0f, tf_knockdowntime.GetFloat() ); }
//========================================================= // ZapBeam - heavy damage directly forward //========================================================= void CNPC_Vortigaunt::ZapBeam( int side ) { Vector vecSrc, vecAim; trace_t tr; CBaseEntity *pEntity; if ( m_iBeams >= VORTIGAUNT_MAX_BEAMS ) return; Vector forward, right, up; AngleVectors( GetAbsAngles(), &forward, &right, &up ); vecSrc = GetAbsOrigin() + up * 36; vecAim = GetShootEnemyDir( vecSrc ); float deflection = 0.01; vecAim = vecAim + side * right * random->RandomFloat( 0, deflection ) + up * random->RandomFloat( -deflection, deflection ); UTIL_TraceLine ( vecSrc, vecSrc + vecAim * 1024, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr); m_pBeam[m_iBeams] = CBeam::BeamCreate( "sprites/lgtning.vmt", 5.0f ); if ( m_pBeam[m_iBeams] == NULL ) return; m_pBeam[m_iBeams]->PointEntInit( tr.endpos, this ); m_pBeam[m_iBeams]->SetEndAttachment( side < 0 ? 2 : 1 ); m_pBeam[m_iBeams]->SetColor( 180, 255, 96 ); m_pBeam[m_iBeams]->SetBrightness( 255 ); m_pBeam[m_iBeams]->SetNoise( 3.2f ); m_iBeams++; pEntity = tr.m_pEnt; if ( pEntity != NULL && m_takedamage ) { CTakeDamageInfo info( this, this, sk_islave_dmg_zap.GetFloat(), DMG_SHOCK ); CalculateMeleeDamageForce( &info, vecAim, tr.endpos ); pEntity->DispatchTraceAttack( info, vecAim, &tr ); } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CNPC_Ichthyosaur::Bite( void ) { //Don't allow another bite too soon if ( m_flNextBiteTime > gpGlobals->curtime ) return; CBaseEntity *pHurt; //FIXME: E3 HACK - Always damage bullseyes if we're scripted to hit them if ( ( GetEnemy() != NULL ) && ( GetEnemy()->Classify() == CLASS_BULLSEYE ) ) { pHurt = GetEnemy(); } else { pHurt = CheckTraceHullAttack( 108, Vector(-32,-32,-32), Vector(32,32,32), 0, DMG_CLUB ); } //Hit something if ( pHurt != NULL ) { CTakeDamageInfo info( this, this, sk_ichthyosaur_melee_dmg.GetInt(), DMG_CLUB ); if ( pHurt->IsPlayer() ) { CBasePlayer *pPlayer = ToBasePlayer( pHurt ); if ( pPlayer ) { if ( ( ( m_flHoldTime < gpGlobals->curtime ) && ( pPlayer->m_iHealth < (pPlayer->m_iMaxHealth*0.5f)) ) || ( pPlayer->GetWaterLevel() < 1 ) ) { //EnsnareVictim( pHurt ); } else { info.SetDamage( sk_ichthyosaur_melee_dmg.GetInt() * 3 ); } CalculateMeleeDamageForce( &info, GetAbsVelocity(), pHurt->GetAbsOrigin() ); pHurt->TakeDamage( info ); color32 red = {64, 0, 0, 255}; UTIL_ScreenFade( pPlayer, red, 0.5, 0, FFADE_IN ); //Disorient the player QAngle angles = pPlayer->GetLocalAngles(); angles.x += random->RandomInt( 60, 25 ); angles.y += random->RandomInt( 60, 25 ); angles.z = 0.0f; pPlayer->SetLocalAngles( angles ); pPlayer->SnapEyeAngles( angles ); } } else { CalculateMeleeDamageForce( &info, GetAbsVelocity(), pHurt->GetAbsOrigin() ); pHurt->TakeDamage( info ); } m_flNextBiteTime = gpGlobals->curtime + random->RandomFloat( 2.0f, 4.0f ); //Bubbles! UTIL_Bubbles( pHurt->GetAbsOrigin()+Vector(-32.0f,-32.0f,-32.0f), pHurt->GetAbsOrigin()+Vector(32.0f,32.0f,0.0f), random->RandomInt( 16, 32 ) ); // Play a random attack hit sound EmitSound( "NPC_Ichthyosaur.Bite" ); if ( GetActivity() == ACT_MELEE_ATTACK1 ) { SetActivity( (Activity) ACT_ICH_BITE_HIT ); } return; } //Play the miss animation and sound if ( GetActivity() == ACT_MELEE_ATTACK1 ) { SetActivity( (Activity) ACT_ICH_BITE_MISS ); } //Miss sound EmitSound( "NPC_Ichthyosaur.BiteMiss" ); }
void CSnark::SuperBounceTouch( CBaseEntity *pOther ) { float flpitch; trace_t tr = CBaseEntity::GetTouchTrace( ); // don't hit the guy that launched this grenade if ( m_hOwner && ( pOther == m_hOwner ) ) return; // at least until we've bounced once m_hOwner = NULL; QAngle angles = GetAbsAngles(); angles.x = 0; angles.z = 0; SetAbsAngles( angles ); // avoid bouncing too much if ( m_flNextHit > gpGlobals->curtime) return; // higher pitch as squeeker gets closer to detonation time flpitch = 155.0 - 60.0 * ( ( m_flDie - gpGlobals->curtime ) / SQUEEK_DETONATE_DELAY ); if ( pOther->m_takedamage && m_flNextAttack < gpGlobals->curtime ) { // attack! // make sure it's me who has touched them if ( tr.m_pEnt == pOther ) { // and it's not another squeakgrenade if ( tr.m_pEnt->GetModelIndex() != GetModelIndex() ) { // ALERT( at_console, "hit enemy\n"); ClearMultiDamage(); Vector vecForward; AngleVectors( GetAbsAngles(), &vecForward ); if ( m_hOwner != NULL ) { CTakeDamageInfo info( this, m_hOwner, sk_snark_dmg_bite.GetFloat(), DMG_SLASH ); CalculateMeleeDamageForce( &info, vecForward, tr.endpos ); pOther->DispatchTraceAttack( info, vecForward, &tr ); } else { CTakeDamageInfo info( this, this, sk_snark_dmg_bite.GetFloat(), DMG_SLASH ); CalculateMeleeDamageForce( &info, vecForward, tr.endpos ); pOther->DispatchTraceAttack( info, vecForward, &tr ); } ApplyMultiDamage(); SetDamage( GetDamage() + sk_snark_dmg_pop.GetFloat() ); // add more explosion damage // m_flDie += 2.0; // add more life // make bite sound CPASAttenuationFilter filter( this ); enginesound->EmitSound( filter, entindex(), CHAN_WEAPON, "squeek/sqk_deploy1.wav", 1, ATTN_NORM, 0, (int)flpitch ); m_flNextAttack = gpGlobals->curtime + 0.5; } } else { // ALERT( at_console, "been hit\n"); } } m_flNextHit = gpGlobals->curtime + 0.1; m_flNextHunt = gpGlobals->curtime; if ( g_pGameRules->IsMultiplayer() ) { // in multiplayer, we limit how often snarks can make their bounce sounds to prevent overflows. if ( gpGlobals->curtime < m_flNextBounceSoundTime ) { // too soon! return; } } if ( !( GetFlags() & FL_ONGROUND ) ) { // play bounce sound CPASAttenuationFilter filter2( this ); switch ( random->RandomInt( 0, 2 ) ) { case 0: enginesound->EmitSound( filter2, entindex(), CHAN_VOICE, "squeek/sqk_hunt1.wav", 1, ATTN_NORM, 0, (int)flpitch ); break; case 1: enginesound->EmitSound( filter2, entindex(), CHAN_VOICE, "squeek/sqk_hunt2.wav", 1, ATTN_NORM, 0, (int)flpitch ); break; case 2: enginesound->EmitSound( filter2, entindex(), CHAN_VOICE, "squeek/sqk_hunt3.wav", 1, ATTN_NORM, 0, (int)flpitch ); break; } CSoundEnt::InsertSound( SOUND_COMBAT, GetAbsOrigin(), 256, 0.25 ); } else { // skittering sound CSoundEnt::InsertSound( SOUND_COMBAT, GetAbsOrigin(), 100, 0.1 ); } m_flNextBounceSoundTime = gpGlobals->curtime + 0.5;// half second. }
// Основная атака огнеметом // This is the cremator's main attack, or more precisely, its damage function. void CNPC_Cremator::DispatchSpray( CBaseEntity *pEntity ) { Vector vecSrc, vecAim; trace_t tr; //const char *entityname = pEntity->GetClassname(); Vector forward, right, up; AngleVectors( GetAbsAngles(), &forward, &right, &up ); vecSrc = GetAbsOrigin() + up * 36; vecAim = GetShootEnemyDir( vecSrc ); float deflection = 0.01; vecAim = vecAim + 1 * right * random->RandomFloat( 0, deflection ) + up * random->RandomFloat( -deflection, deflection ); UTIL_TraceLine ( vecSrc, vecSrc + vecAim * 512, MASK_SOLID, this, COLLISION_GROUP_NONE, &tr); /* if ( tr.DidHitWorld() ) // spawn flames on solid surfaces. // It's not very important since it is extremely rare for a cremator to // hit brush geometry but might be a nice feature for a close-space combat // it also works fine but again is EXTREMELY hard to get in-game { Vector ofsDir = ( tr.endpos - GetAbsOrigin() ); float offset = VectorNormalize( ofsDir ); if ( offset > 128 ) offset = 128; float scale = 0.1f + ( 0.75f * ( 1.0f - ( offset / 128.0f ) ) ); float growth = 0.1f + ( 0.75f * (offset / 128.0f ) ); if ( tr.surface.flags & CONTENTS_GRATE ) // get smaller flames on grates since they have a smaller burning area { scale = 0.1f + ( 0.15f * ( 1.0f - ( offset / 128.0f ) ) ); } else { scale = 0.1f + ( 0.75f * ( 1.0f - ( offset / 128.0f ) ) ); } FireSystem_StartFire( tr.endpos, scale, growth, 8.0, 10.0f, (SF_FIRE_START_ON|SF_FIRE_START_FULL), (CBaseEntity*) this, FIRE_NATURAL ); } */ pEntity = tr.m_pEnt; if ( pEntity != NULL && m_takedamage ) { CTakeDamageInfo firedamage( this, this, sk_cremator_firedamage.GetFloat(), DMG_BURN ); CTakeDamageInfo radiusdamage( this, this, sk_cremator_radiusdamage.GetFloat(), DMG_PLASMA ); CalculateMeleeDamageForce( &firedamage, vecAim, tr.endpos ); RadiusDamage ( CTakeDamageInfo ( this, this, 2, DMG_PLASMA ), // AOE; this stuff makes cremators absurdly powerfull sometimes btw tr.endpos, 64.0f, CLASS_NONE, NULL ); pEntity->DispatchTraceAttack( ( firedamage ), vecAim, &tr ); Vector flEnemyLKP = pEntity->GetAbsOrigin(); GetMotor()->SetIdealYawToTargetAndUpdate( flEnemyLKP ); ClearMultiDamage(); } m_iAmmo --; }
// ----------------------------------------------------------------------------- // Purpose: // Note: Think function to delay the impact decal until the animation is finished // playing. // ----------------------------------------------------------------------------- void CTFWeaponBaseMelee::Smack( void ) { trace_t trace; CBasePlayer *pPlayer = GetPlayerOwner(); if ( !pPlayer ) return; #if !defined (CLIENT_DLL) // Move other players back to history positions based on local player's lag lagcompensation->StartLagCompensation( pPlayer, pPlayer->GetCurrentCommand() ); #endif // We hit, setup the smack. if ( DoSwingTrace( trace ) ) { // Hit sound - immediate. if( trace.m_pEnt->IsPlayer() ) { WeaponSound( MELEE_HIT ); } else { WeaponSound( MELEE_HIT_WORLD ); } // Get the current player. CTFPlayer *pPlayer = GetTFPlayerOwner(); if ( !pPlayer ) return; Vector vecForward; AngleVectors( pPlayer->EyeAngles(), &vecForward ); Vector vecSwingStart = pPlayer->Weapon_ShootPosition(); Vector vecSwingEnd = vecSwingStart + vecForward * 48; #ifndef CLIENT_DLL // Do Damage. int iCustomDamage = TF_DMG_CUSTOM_NONE; float flDamage = GetMeleeDamage( trace.m_pEnt, iCustomDamage ); int iDmgType = DMG_BULLET | DMG_NEVERGIB | DMG_CLUB; if ( IsCurrentAttackACrit() ) { // TODO: Not removing the old critical path yet, but the new custom damage is marking criticals as well for melee now. iDmgType |= DMG_CRITICAL; } CTFWeaponBase *pWpn = pPlayer->GetActiveTFWeapon(); CTFUbersaw *pUbersaw = dynamic_cast<CTFUbersaw*>(pWpn); CWeaponMedigun *pMedigun = static_cast<CWeaponMedigun*>(pPlayer->Weapon_OwnsThisID(TF_WEAPON_MEDIGUN)); if (pMedigun && pUbersaw) { if(trace.m_pEnt->IsPlayer() && trace.m_pEnt->GetTeamNumber() != pPlayer->GetTeamNumber()) { pMedigun->AddCharge(); } } CWeaponKritzkrieg *pKritzkrieg = static_cast<CWeaponKritzkrieg*>(pPlayer->Weapon_OwnsThisID(TF_WEAPON_KRITZKRIEG)); if (pKritzkrieg && pUbersaw) { if(trace.m_pEnt->IsPlayer() && trace.m_pEnt->GetTeamNumber() != pPlayer->GetTeamNumber()) { pKritzkrieg->AddCharge(); } } CTakeDamageInfo info( pPlayer, pPlayer, flDamage, iDmgType, iCustomDamage ); CalculateMeleeDamageForce( &info, vecForward, vecSwingEnd, 1.0f / flDamage * tf_meleeattackforcescale.GetFloat() ); trace.m_pEnt->DispatchTraceAttack( info, vecForward, &trace ); ApplyMultiDamage(); OnEntityHit( trace.m_pEnt ); #endif // Don't impact trace friendly players or objects if ( trace.m_pEnt && trace.m_pEnt->GetTeamNumber() != pPlayer->GetTeamNumber() ) { #ifdef CLIENT_DLL UTIL_ImpactTrace( &trace, DMG_CLUB ); #endif m_bConnected = true; } } #if !defined (CLIENT_DLL) lagcompensation->FinishLagCompensation( pPlayer ); #endif }
//========================================================= // HandleAnimEvent - catches the monster-specific messages // that occur when tagged animation frames are played. // // Returns number of events handled, 0 if none. //========================================================= void CNPC_BigMomma::HandleAnimEvent( animevent_t *pEvent ) { CPASAttenuationFilter filter( this ); Vector vecFwd, vecRight, vecUp; QAngle angles; angles = GetAbsAngles(); AngleVectors( angles, &vecFwd, &vecRight, &vecUp ); switch( pEvent->event ) { case BIG_AE_MELEE_ATTACKBR: case BIG_AE_MELEE_ATTACKBL: case BIG_AE_MELEE_ATTACK1: { Vector center = GetAbsOrigin() + vecFwd * 128; Vector mins = center - Vector( 64, 64, 0 ); Vector maxs = center + Vector( 64, 64, 64 ); CBaseEntity *pList[8]; int count = UTIL_EntitiesInBox( pList, 8, mins, maxs, FL_NPC | FL_CLIENT ); CBaseEntity *pHurt = NULL; for ( int i = 0; i < count && !pHurt; i++ ) { if ( pList[i] != this ) { if ( pList[i]->GetOwnerEntity() != this ) { pHurt = pList[i]; } } } if ( pHurt ) { CTakeDamageInfo info( this, this, 15, DMG_CLUB | DMG_SLASH ); CalculateMeleeDamageForce( &info, (pHurt->GetAbsOrigin() - GetAbsOrigin()), pHurt->GetAbsOrigin() ); pHurt->TakeDamage( info ); QAngle newAngles = angles; newAngles.x = 15; if ( pHurt->IsPlayer() ) { ((CBasePlayer *)pHurt)->SetPunchAngle( newAngles ); } switch( pEvent->event ) { case BIG_AE_MELEE_ATTACKBR: // pHurt->pev->velocity = pHurt->pev->velocity + (vecFwd * 150) + Vector(0,0,250) - (vecRight * 200); pHurt->SetAbsVelocity( pHurt->GetAbsVelocity() + (vecFwd * 150) + Vector(0,0,250) - (vecRight * 200) ); break; case BIG_AE_MELEE_ATTACKBL: pHurt->SetAbsVelocity( pHurt->GetAbsVelocity() + (vecFwd * 150) + Vector(0,0,250) + (vecRight * 200) ); break; case BIG_AE_MELEE_ATTACK1: pHurt->SetAbsVelocity( pHurt->GetAbsVelocity() + (vecFwd * 220) + Vector(0,0,200) ); break; } pHurt->SetGroundEntity( NULL ); EmitSound( filter, entindex(), "BigMomma.AttackHit" ); } } break; case BIG_AE_SCREAM: EmitSound( filter, entindex(), "BigMomma.Alert" ); break; case BIG_AE_PAIN_SOUND: EmitSound( filter, entindex(), "BigMomma.Pain" ); break; case BIG_AE_ATTACK_SOUND: EmitSound( filter, entindex(), "BigMomma.Attack" ); break; case BIG_AE_BIRTH_SOUND: EmitSound( filter, entindex(), "BigMomma.Birth" ); break; case BIG_AE_SACK: if ( RandomInt(0,100) < 30 ) { EmitSound( filter, entindex(), "BigMomma.Sack" ); } break; case BIG_AE_DEATHSOUND: EmitSound( filter, entindex(), "BigMomma.Die" ); break; case BIG_AE_STEP1: // Footstep left case BIG_AE_STEP3: // Footstep back left EmitSound( filter, entindex(), "BigMomma.FootstepLeft" ); break; case BIG_AE_STEP4: // Footstep back right case BIG_AE_STEP2: // Footstep right EmitSound( filter, entindex(), "BigMomma.FootstepRight" ); break; case BIG_AE_MORTAR_ATTACK1: LaunchMortar(); break; case BIG_AE_LAY_CRAB: LayHeadcrab(); break; case BIG_AE_JUMP_FORWARD: SetGroundEntity( NULL ); SetAbsOrigin(GetAbsOrigin() + Vector ( 0 , 0 , 1) );// take him off ground so engine doesn't instantly reset onground SetAbsVelocity(vecFwd * 200 + vecUp * 500 ); break; case BIG_AE_EARLY_TARGET: { CInfoBM *pTarget = (CInfoBM*) GetTarget(); if ( pTarget ) { pTarget->m_OnAnimationEvent.FireOutput( this, this ); } Remember( bits_MEMORY_FIRED_NODE ); } break; default: BaseClass::HandleAnimEvent( pEvent ); break; } }
void CBaseGrenade::BounceTouch( CBaseEntity *pOther ) { if ( pOther->IsSolidFlagSet(FSOLID_TRIGGER | FSOLID_VOLUME_CONTENTS) ) return; // don't hit the guy that launched this grenade if ( pOther == GetThrower() ) return; // only do damage if we're moving fairly fast if ( (pOther->m_takedamage != DAMAGE_NO) && (m_flNextAttack < gpGlobals->curtime && GetAbsVelocity().Length() > 100)) { if (m_hThrower) { #if !defined( CLIENT_DLL ) trace_t tr; tr = CBaseEntity::GetTouchTrace( ); ClearMultiDamage( ); Vector forward; AngleVectors( GetLocalAngles(), &forward, NULL, NULL ); CTakeDamageInfo info( this, m_hThrower, 1, DMG_CLUB ); CalculateMeleeDamageForce( &info, GetAbsVelocity(), GetAbsOrigin() ); pOther->DispatchTraceAttack( info, forward, &tr ); ApplyMultiDamage(); #endif } m_flNextAttack = gpGlobals->curtime + 1.0; // debounce } Vector vecTestVelocity; // m_vecAngVelocity = Vector (300, 300, 300); // this is my heuristic for modulating the grenade velocity because grenades dropped purely vertical // or thrown very far tend to slow down too quickly for me to always catch just by testing velocity. // trimming the Z velocity a bit seems to help quite a bit. vecTestVelocity = GetAbsVelocity(); vecTestVelocity.z *= 0.45; if ( !m_bHasWarnedAI && vecTestVelocity.Length() <= 60 ) { // grenade is moving really slow. It's probably very close to where it will ultimately stop moving. // emit the danger sound. // register a radius louder than the explosion, so we make sure everyone gets out of the way #if !defined( CLIENT_DLL ) CSoundEnt::InsertSound ( SOUND_DANGER, GetAbsOrigin(), m_flDamage / 0.4, 0.3, this ); #endif m_bHasWarnedAI = true; } if (GetFlags() & FL_ONGROUND) { // add a bit of static friction // SetAbsVelocity( GetAbsVelocity() * 0.8 ); // SetSequence( random->RandomInt( 1, 1 ) ); // FIXME: missing tumble animations } else { // play bounce sound BounceSound(); } m_flPlaybackRate = GetAbsVelocity().Length() / 200.0; if (GetPlaybackRate() > 1.0) m_flPlaybackRate = 1; else if (GetPlaybackRate() < 0.5) m_flPlaybackRate = 0; }