void CGrenadeAR2::Detonate(void) { if (!m_bIsLive) { return; } m_bIsLive = false; m_takedamage = DAMAGE_NO; if(m_hSmokeTrail) { UTIL_Remove(m_hSmokeTrail); m_hSmokeTrail = NULL; } CPASFilter filter( GetAbsOrigin() ); te->Explosion( filter, 0.0, &GetAbsOrigin(), g_sModelIndexFireball, 2.0, 15, TE_EXPLFLAG_NONE, m_DmgRadius, m_flDamage ); Vector vecForward = GetAbsVelocity(); VectorNormalize(vecForward); trace_t tr; UTIL_TraceLine ( GetAbsOrigin(), GetAbsOrigin() + 60*vecForward, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr); if ((tr.m_pEnt != GetWorldEntity()) || (tr.hitbox != 0)) { // non-world needs smaller decals if( tr.m_pEnt && !tr.m_pEnt->IsNPC() ) { UTIL_DecalTrace( &tr, "SmallScorch" ); } } else { UTIL_DecalTrace( &tr, "Scorch" ); } UTIL_ScreenShake( GetAbsOrigin(), 25.0, 150.0, 1.0, 750, SHAKE_START ); RadiusDamage ( CTakeDamageInfo( this, GetThrower(), m_flDamage, DMG_BLAST ), GetAbsOrigin(), m_DmgRadius, CLASS_NONE, NULL ); UTIL_Remove( this ); }
//----------------------------------------------------------------------------- // 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; } }
void CFlashbangProjectile::Detonate() { RadiusFlash(GetAbsOrigin(), this, GetThrower(), 4, CLASS_NONE, DMG_BLAST); EmitSound("Flashbang.Explode"); // tell the bots a flashbang grenade has exploded CMomentumPlayer *player = static_cast<CMomentumPlayer*>(GetThrower()); if (player) { IGameEvent * event = gameeventmanager->CreateEvent("flashbang_detonate"); if (event) { event->SetInt("userid", player->GetUserID()); event->SetFloat("x", GetAbsOrigin().x); event->SetFloat("y", GetAbsOrigin().y); event->SetFloat("z", GetAbsOrigin().z); gameeventmanager->FireEvent(event); } } UTIL_Remove(this); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFGrenadePipebombProjectile::PipebombTouch( CBaseEntity *pOther ) { if ( pOther == GetThrower() ) return; // Verify a correct "other." if ( !pOther->IsSolid() || pOther->IsSolidFlagSet( FSOLID_VOLUME_CONTENTS ) ) return; // Handle hitting skybox (disappear). trace_t pTrace; Vector velDir = GetAbsVelocity(); VectorNormalize( velDir ); Vector vecSpot = GetAbsOrigin() - velDir * 32; UTIL_TraceLine( vecSpot, vecSpot + velDir * 64, MASK_SOLID, this, COLLISION_GROUP_NONE, &pTrace ); if ( pTrace.fraction < 1.0 && pTrace.surface.flags & SURF_SKY ) { UTIL_Remove( this ); return; } //If we already touched a surface then we're not exploding on contact anymore. if ( m_bTouched == true ) return; // Blow up if we hit an enemy we can damage if ( pOther->GetTeamNumber() && pOther->GetTeamNumber() != GetTeamNumber() && pOther->m_takedamage != DAMAGE_NO ) { // Check to see if this is a respawn room. if ( !pOther->IsPlayer() ) { CFuncRespawnRoom *pRespawnRoom = dynamic_cast<CFuncRespawnRoom*>( pOther ); if ( pRespawnRoom ) { if ( !pRespawnRoom->PointIsWithin( GetAbsOrigin() ) ) return; } } // Restore damage. See comment in CTFGrenadePipebombProjectile::Create() above to understand this. m_flDamage = m_flFullDamage; Explode( &pTrace, GetDamageType() ); } // Train hack! if ( pOther->GetModelName() == s_iszTrainName && ( pOther->GetAbsVelocity().LengthSqr() > 1.0f ) ) { Explode( &pTrace, GetDamageType() ); } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFWeaponBaseGrenadeProj::Spawn( void ) { // Base class spawn. BaseClass::Spawn(); // So it will collide with physics props! SetSolidFlags( FSOLID_NOT_STANDABLE ); SetSolid( SOLID_BBOX ); AddEffects( EF_NOSHADOW ); // Set the grenade size here. UTIL_SetSize( this, Vector( -2.0f, -2.0f, -2.0f ), Vector( 2.0f, 2.0f, 2.0f ) ); // Set the movement type. SetCollisionGroup( TF_COLLISIONGROUP_GRENADES ); // Don't collide with players on the owner's team for the first bit of our life m_flCollideWithTeammatesTime = gpGlobals->curtime + 0.25; m_bCollideWithTeammates = false; VPhysicsInitNormal( SOLID_BBOX, 0, false ); m_takedamage = DAMAGE_EVENTS_ONLY; if (GetThrower()) { // Set the team. ChangeTeam(GetThrower()->GetTeamNumber()); } // Set skin based on team ( red = 1, blue = 2 ) m_nSkin = GetTeamNumber() - 2; // Setup the think and touch functions (see CBaseEntity). SetThink( &CTFWeaponBaseGrenadeProj::DetonateThink ); SetNextThink( gpGlobals->curtime + 0.2 ); }
void CBaseGrenadeProjectile::VPhysicsUpdate( IPhysicsObject *pPhysics ) { BaseClass::VPhysicsUpdate( pPhysics ); Vector vel; AngularImpulse angVel; pPhysics->GetVelocity( &vel, &angVel ); Vector start = GetAbsOrigin(); // find all entities that my collision group wouldn't hit, but COLLISION_GROUP_NONE would and bounce off of them as a ray cast CTraceFilterCollisionGroupDelta filter( this, GetCollisionGroup(), COLLISION_GROUP_NONE ); trace_t tr; // UNDONE: Hull won't work with hitboxes - hits outer hull. But the whole point of this test is to hit hitboxes. #if 0 UTIL_TraceHull( start, start + vel * gpGlobals->frametime, CollisionProp()->OBBMins(), CollisionProp()->OBBMaxs(), CONTENTS_HITBOX|CONTENTS_MONSTER|CONTENTS_SOLID, &filter, &tr ); #else UTIL_TraceLine( start, start + vel * gpGlobals->frametime, CONTENTS_HITBOX|CONTENTS_MONSTER|CONTENTS_SOLID, &filter, &tr ); #endif if ( tr.startsolid ) { if ( !m_inSolid ) { // UNDONE: Do a better contact solution that uses relative velocity? vel *= -GRENADE_COEFFICIENT_OF_RESTITUTION; // bounce backwards pPhysics->SetVelocity( &vel, NULL ); } m_inSolid = true; return; } m_inSolid = false; if ( tr.DidHit() ) { Vector dir = vel; VectorNormalize(dir); // send a tiny amount of damage so the character will react to getting bonked CTakeDamageInfo info( this, GetThrower(), pPhysics->GetMass() * vel, GetAbsOrigin(), 0.1f, DMG_CRUSH ); tr.m_pEnt->TakeDamage( info ); // reflect velocity around normal vel = -2.0f * tr.plane.normal * DotProduct(vel,tr.plane.normal) + vel; // absorb 80% in impact vel *= GRENADE_COEFFICIENT_OF_RESTITUTION; angVel *= -0.5f; pPhysics->SetVelocity( &vel, &angVel ); } }
void CHEGrenadeProjectile::Detonate() { BaseClass::Detonate(); // tell the bots an HE grenade has exploded CMomentumPlayer *player = static_cast<CMomentumPlayer*>(GetThrower()); if ( player ) { IGameEvent * event = gameeventmanager->CreateEvent( "hegrenade_detonate" ); if ( event ) { event->SetInt( "userid", player->GetUserID() ); event->SetFloat( "x", GetAbsOrigin().x ); event->SetFloat( "y", GetAbsOrigin().y ); event->SetFloat( "z", GetAbsOrigin().z ); gameeventmanager->FireEvent( event ); } } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CGrenadeHopwire::CombatThink( void ) { // Stop the grenade from moving AddEFlags( EF_NODRAW ); AddFlag( FSOLID_NOT_SOLID ); VPhysicsDestroyObject(); SetAbsVelocity( vec3_origin ); SetMoveType( MOVETYPE_NONE ); // Do special behaviors if there are any striders in the area KillStriders(); // FIXME: Replace //EmitSound("NPC_Strider.Shoot"); //EmitSound("d3_citadel.weapon_zapper_beam_loop2"); // Quick screen flash CBasePlayer *pPlayer = ToBasePlayer( GetThrower() ); color32 white = { 255,255,255,255 }; UTIL_ScreenFade( pPlayer, white, 0.2f, 0.0f, FFADE_IN ); // Create the vortex controller to pull entities towards us if ( hopwire_vortex.GetBool() ) { m_hVortexController = CGravityVortexController::Create( GetAbsOrigin(), 512, 150, 3.0f ); // Start our client-side effect EntityMessageBegin( this, true ); WRITE_BYTE( 0 ); MessageEnd(); // Begin to stop in two seconds SetThink( &CGrenadeHopwire::EndThink ); SetNextThink( gpGlobals->curtime + 2.0f ); } else { // Remove us immediately SetThink( &CBaseEntity::SUB_Remove ); SetNextThink( gpGlobals->curtime + 0.1f ); } }
int CBaseGrenadeProjectile::DrawModel( int flags ) { // During the first half-second of our life, don't draw ourselves if he's // still playing his throw animation. // (better yet, we could draw ourselves in his hand). if ( GetThrower() != C_BasePlayer::GetLocalPlayer() ) { if ( gpGlobals->curtime - m_flSpawnTime < 0.5 ) { //Tony; FIXME! // C_BliinkPlayer *pPlayer = dynamic_cast<C_BliinkPlayer*>( GetThrower() ); // if ( pPlayer && pPlayer->m_PlayerAnimState->IsThrowingGrenade() ) // { // return 0; // } } } return 0; //return BaseClass::DrawModel( flags ); }
void CGrenadeMP5::GrenadeMP5Touch( CBaseEntity *pOther ) { if ( !pOther->IsSolid() ) return; // If I'm live go ahead and blow up if (m_bIsLive) { Detonate(); } else { // If I'm not live, only blow up if I'm hitting an chacter that // is not the owner of the weapon CBaseCombatCharacter *pBCC = ToBaseCombatCharacter( pOther ); if (pBCC && GetThrower() != pBCC) { m_bIsLive = true; Detonate(); } } }
//------------------------------------------------------------------------------ // Purpose : // Input : // Output : //------------------------------------------------------------------------------ void CGrenadePathfollower::Detonate(void) { StopSound(entindex(), CHAN_BODY, STRING(m_sFlySound)); m_takedamage = DAMAGE_NO; if(m_hRocketTrail) { UTIL_Remove(m_hRocketTrail); m_hRocketTrail = NULL; } CPASFilter filter( GetAbsOrigin() ); te->Explosion( filter, 0.0, &GetAbsOrigin(), g_sModelIndexFireball, 0.5, 15, TE_EXPLFLAG_NONE, m_DmgRadius, m_flDamage ); Vector vecForward = GetAbsVelocity(); VectorNormalize(vecForward); trace_t tr; UTIL_TraceLine ( GetAbsOrigin(), GetAbsOrigin() + 60*vecForward, MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, & tr); UTIL_DecalTrace( &tr, "Scorch" ); UTIL_ScreenShake( GetAbsOrigin(), 25.0, 150.0, 1.0, 750, SHAKE_START ); CSoundEnt::InsertSound ( SOUND_DANGER, GetAbsOrigin(), 400, 0.2 ); RadiusDamage ( CTakeDamageInfo( this, GetThrower(), m_flDamage, DMG_BLAST ), GetAbsOrigin(), m_DmgRadius, CLASS_NONE, NULL ); CPASAttenuationFilter filter2( this, "GrenadePathfollower.StopSounds" ); EmitSound( filter2, entindex(), "GrenadePathfollower.StopSounds" ); UTIL_Remove( this ); }
void CBaseGrenade::SlideTouch( CBaseEntity *pOther ) { // don't hit the guy that launched this grenade if ( pOther == GetThrower() ) return; // m_vecAngVelocity = Vector (300, 300, 300); if (GetFlags() & FL_ONGROUND) { // add a bit of static friction // SetAbsVelocity( GetAbsVelocity() * 0.95 ); if (GetAbsVelocity().x != 0 || GetAbsVelocity().y != 0) { // maintain sliding sound } } else { BounceSound(); } }
void CWeaponDrainGrenade::DetonateTouch( CBaseEntity *pOther ) { if ( pOther == GetThrower() ) return; // Verify a correct "other." if ( !pOther->IsSolid() || pOther->IsSolidFlagSet( FSOLID_VOLUME_CONTENTS ) ) return; // Handle hitting skybox (disappear). trace_t pTrace; Vector velDir = GetAbsVelocity(); VectorNormalize( velDir ); Vector vecSpot = GetAbsOrigin() - velDir * 32; UTIL_TraceLine( vecSpot, vecSpot + velDir * 64, MASK_SOLID, this, COLLISION_GROUP_NONE, &pTrace ); if ( pTrace.fraction < 1.0 && pTrace.surface.flags & SURF_SKY ) { UTIL_Remove( this ); return; } Detonate(); }
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; }
int CBaseGrenadeProjectile::DrawModel( int flags ) { // During the first half-second of our life, don't draw ourselves if he's // still playing his throw animation. // (better yet, we could draw ourselves in his hand). if ( GetThrower() != C_BasePlayer::GetLocalPlayer() ) { if ( gpGlobals->curtime - m_flSpawnTime < 0.5 ) { //Tony; FIXME! // C_SDKPlayer *pPlayer = dynamic_cast<C_SDKPlayer*>( GetThrower() ); // if ( pPlayer && pPlayer->m_PlayerAnimState->IsThrowingGrenade() ) // { // return 0; // } } } if (!g_hGrenadeArrow.IsValid()) g_hGrenadeArrow.Init( "particle/grenadearrow.vmt", TEXTURE_GROUP_OTHER ); int iReturn = BaseClass::DrawModel(flags); C_SDKPlayer* pLocalPlayer = C_SDKPlayer::GetLocalSDKPlayer(); if (!pLocalPlayer) return iReturn; if (pLocalPlayer == GetThrower()) return iReturn; float flAppearDistance = 500; float flAppearDistanceSqr = flAppearDistance*flAppearDistance; if ((pLocalPlayer->GetAbsOrigin() - GetAbsOrigin()).LengthSqr() < flAppearDistanceSqr) m_flArrowGoalSize = 20; else m_flArrowGoalSize = 0; float flTime = C_SDKPlayer::GetLocalSDKPlayer()->GetCurrentTime() + m_flArrowSpinOffset; float flFrameTime = gpGlobals->frametime * C_SDKPlayer::GetLocalSDKPlayer()->GetSlowMoMultiplier(); m_flArrowCurSize = Approach(m_flArrowGoalSize, m_flArrowCurSize, flFrameTime*100); if (m_flArrowCurSize == 0) return iReturn; Vector vecViewForward, vecViewRight, vecViewUp; pLocalPlayer->EyeVectors(&vecViewForward, &vecViewRight, &vecViewUp); float flSin = sin(flTime*4); float flCos = cos(flTime*4); Vector vecOrigin = GetAbsOrigin(); Vector vecRight = vecViewRight * flSin + vecViewUp * flCos; Vector vecUp = vecViewRight * -flCos + vecViewUp * flSin; float flSize = m_flArrowCurSize; CMeshBuilder meshBuilder; CMatRenderContextPtr pRenderContext( materials ); IMesh* pMesh = pRenderContext->GetDynamicMesh(); pRenderContext->Bind( g_hGrenadeArrow ); meshBuilder.Begin( pMesh, MATERIAL_QUADS, 1 ); meshBuilder.Color4f( 1, 1, 1, 1 ); meshBuilder.TexCoord2f( 0,0, 0 ); meshBuilder.Position3fv( (vecOrigin + (vecRight * -flSize) + (vecUp * flSize)).Base() ); meshBuilder.AdvanceVertex(); meshBuilder.Color4f( 1, 1, 1, 1 ); meshBuilder.TexCoord2f( 0,1, 0 ); meshBuilder.Position3fv( (vecOrigin + (vecRight * flSize) + (vecUp * flSize)).Base() ); meshBuilder.AdvanceVertex(); meshBuilder.Color4f( 1, 1, 1, 1 ); meshBuilder.TexCoord2f( 0,1, 1 ); meshBuilder.Position3fv( (vecOrigin + (vecRight * flSize) + (vecUp * -flSize)).Base() ); meshBuilder.AdvanceVertex(); meshBuilder.Color4f( 1, 1, 1, 1 ); meshBuilder.TexCoord2f( 0,0, 1 ); meshBuilder.Position3fv( (vecOrigin + (vecRight * -flSize) + (vecUp * -flSize)).Base() ); meshBuilder.AdvanceVertex(); meshBuilder.End(false, true); return iReturn; }
//----------------------------------------------------------------------------- // Purpose: Handle spitting //----------------------------------------------------------------------------- void CGrenadeSpit::GrenadeSpitTouch( CBaseEntity *pOther ) { if ( pOther->IsSolidFlagSet(FSOLID_VOLUME_CONTENTS | FSOLID_TRIGGER) ) { // Some NPCs are triggers that can take damage (like antlion grubs). We should hit them. if ( ( pOther->m_takedamage == DAMAGE_NO ) || ( pOther->m_takedamage == DAMAGE_EVENTS_ONLY ) ) return; } // Don't hit other spit if ( pOther->GetCollisionGroup() == HL2COLLISION_GROUP_SPIT ) return; // We want to collide with water const trace_t *pTrace = &CBaseEntity::GetTouchTrace(); // copy out some important things about this trace, because the first TakeDamage // call below may cause another trace that overwrites the one global pTrace points // at. bool bHitWater = ( ( pTrace->contents & CONTENTS_WATER ) != 0 ); CBaseEntity *const pTraceEnt = pTrace->m_pEnt; const Vector tracePlaneNormal = pTrace->plane.normal; if ( bHitWater ) { // Splash! CEffectData data; data.m_fFlags = 0; data.m_vOrigin = pTrace->endpos; data.m_vNormal = Vector( 0, 0, 1 ); data.m_flScale = 8.0f; DispatchEffect( "watersplash", data ); } else { // Make a splat decal trace_t *pNewTrace = const_cast<trace_t*>( pTrace ); UTIL_DecalTrace( pNewTrace, "BeerSplash" ); } // Part normal damage, part poison damage float poisonratio = sk_antlion_worker_spit_grenade_poison_ratio.GetFloat(); // Take direct damage if hit // NOTE: assume that pTrace is invalidated from this line forward! if ( pTraceEnt ) { pTraceEnt->TakeDamage( CTakeDamageInfo( this, GetThrower(), m_flDamage * (1.0f-poisonratio), DMG_ACID ) ); pTraceEnt->TakeDamage( CTakeDamageInfo( this, GetThrower(), m_flDamage * poisonratio, DMG_POISON ) ); } CSoundEnt::InsertSound( SOUND_DANGER, GetAbsOrigin(), (int)(m_DmgRadius * 2.0f), 0.5f, GetThrower() ); QAngle vecAngles; VectorAngles( tracePlaneNormal, vecAngles ); if ( pOther->IsPlayer() || bHitWater ) { // Do a lighter-weight effect if we just hit a player DispatchParticleEffect( "antlion_spit_player", GetAbsOrigin(), vecAngles ); } else { DispatchParticleEffect( "antlion_spit", GetAbsOrigin(), vecAngles ); } Detonate(); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFGrenadeEmpProjectile::Detonate() { if ( ShouldNotDetonate() ) { RemoveGrenade(); return; } // Explosion effect on client // SendDispatchEffect(); float flRadius = 180; float flDamage = 1; if ( tf_grenade_show_radius.GetBool() ) { DrawRadius( flRadius ); } // Apply some amount of EMP damage to every entity in the radius. They will calculate // their own damage based on how much ammo they have or some other wacky calculation. CTakeDamageInfo info( this, GetThrower(), vec3_origin, GetAbsOrigin(), flDamage, /* DMG_EMP |*/ DMG_PREVENT_PHYSICS_FORCE ); CBaseEntity *pEntityList[100]; int nEntityCount = UTIL_EntitiesInSphere( pEntityList, 100, GetAbsOrigin(), flRadius, 0 ); int iEntity; for ( iEntity = 0; iEntity < nEntityCount; ++iEntity ) { CBaseEntity *pEntity = pEntityList[iEntity]; if ( pEntity == this ) continue; if ( pEntity && pEntity->IsPlayer() ) continue; if ( pEntity && ( pEntity->m_takedamage == DAMAGE_YES || pEntity->m_takedamage == DAMAGE_EVENTS_ONLY ) ) { pEntity->TakeDamage( info ); //if ( pEntity->IsPlayer() /* || is ammo box || is enemy object */ ) { CBeam *pBeam = CBeam::BeamCreate( "sprites/physcannon_bluelight1b.vmt", 3.0 ); if ( !pBeam ) return; pBeam->PointsInit( GetAbsOrigin(), pEntity->WorldSpaceCenter() ); pBeam->SetColor( 255, 255, 255 ); pBeam->SetBrightness( 128 ); pBeam->SetNoise( 12.0f ); pBeam->SetEndWidth( 3.0f ); pBeam->SetWidth( 3.0f ); pBeam->LiveForTime( 0.5f ); // Fail-safe pBeam->SetFrameRate( 25.0f ); pBeam->SetFrame( random->RandomInt( 0, 2 ) ); } } } DispatchParticleEffect( "emp_shockwave", GetAbsOrigin(), vec3_angle ); UTIL_Remove( this ); #if 0 // Tell the bots an HE grenade has exploded CTFPlayer *pPlayer = ToTFPlayer( GetThrower() ); if ( pPlayer ) { KeyValues *pEvent = new KeyValues( "tf_weapon_grenade_detonate" ); pEvent->SetInt( "userid", pPlayer->GetUserID() ); gameeventmanager->FireEventServerOnly( pEvent ); } #endif }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFWeaponBaseGrenadeProj::ResolveFlyCollisionCustom( trace_t &trace, Vector &vecVelocity ) { //Assume all surfaces have the same elasticity float flSurfaceElasticity = 1.0; //Don't bounce off of players with perfect elasticity if( trace.m_pEnt && trace.m_pEnt->IsPlayer() ) { flSurfaceElasticity = 0.3; } #if 0 // if its breakable glass and we kill it, don't bounce. // give some damage to the glass, and if it breaks, pass // through it. bool breakthrough = false; if( trace.m_pEnt && FClassnameIs( trace.m_pEnt, "func_breakable" ) ) { breakthrough = true; } if( trace.m_pEnt && FClassnameIs( trace.m_pEnt, "func_breakable_surf" ) ) { breakthrough = true; } if (breakthrough) { CTakeDamageInfo info( this, this, 10, DMG_CLUB ); trace.m_pEnt->DispatchTraceAttack( info, GetAbsVelocity(), &trace ); ApplyMultiDamage(); if( trace.m_pEnt->m_iHealth <= 0 ) { // slow our flight a little bit Vector vel = GetAbsVelocity(); vel *= 0.4; SetAbsVelocity( vel ); return; } } #endif float flTotalElasticity = GetElasticity() * flSurfaceElasticity; flTotalElasticity = clamp( flTotalElasticity, 0.0f, 0.9f ); // NOTE: A backoff of 2.0f is a reflection Vector vecAbsVelocity; PhysicsClipVelocity( GetAbsVelocity(), trace.plane.normal, vecAbsVelocity, 2.0f ); vecAbsVelocity *= flTotalElasticity; // Get the total velocity (player + conveyors, etc.) VectorAdd( vecAbsVelocity, GetBaseVelocity(), vecVelocity ); float flSpeedSqr = DotProduct( vecVelocity, vecVelocity ); // Stop if on ground. if ( trace.plane.normal.z > 0.7f ) // Floor { // Verify that we have an entity. CBaseEntity *pEntity = trace.m_pEnt; Assert( pEntity ); SetAbsVelocity( vecAbsVelocity ); if ( flSpeedSqr < ( 30 * 30 ) ) { if ( pEntity->IsStandable() ) { SetGroundEntity( pEntity ); } // Reset velocities. SetAbsVelocity( vec3_origin ); SetLocalAngularVelocity( vec3_angle ); //align to the ground so we're not standing on end QAngle angle; VectorAngles( trace.plane.normal, angle ); // rotate randomly in yaw angle[1] = random->RandomFloat( 0, 360 ); // TFTODO: rotate around trace.plane.normal SetAbsAngles( angle ); } else { Vector vecDelta = GetBaseVelocity() - vecAbsVelocity; Vector vecBaseDir = GetBaseVelocity(); VectorNormalize( vecBaseDir ); float flScale = vecDelta.Dot( vecBaseDir ); VectorScale( vecAbsVelocity, ( 1.0f - trace.fraction ) * gpGlobals->frametime, vecVelocity ); VectorMA( vecVelocity, ( 1.0f - trace.fraction ) * gpGlobals->frametime, GetBaseVelocity() * flScale, vecVelocity ); PhysicsPushEntity( vecVelocity, &trace ); } } else { // If we get *too* slow, we'll stick without ever coming to rest because // we'll get pushed down by gravity faster than we can escape from the wall. if ( flSpeedSqr < ( 30 * 30 ) ) { // Reset velocities. SetAbsVelocity( vec3_origin ); SetLocalAngularVelocity( vec3_angle ); } else { SetAbsVelocity( vecAbsVelocity ); } } BounceSound(); #if 0 // tell the bots a grenade has bounced CCSPlayer *player = ToCSPlayer(GetThrower()); if ( player ) { KeyValues *event = new KeyValues( "grenade_bounce" ); event->SetInt( "userid", player->GetUserID() ); gameeventmanager->FireEventServerOnly( event ); } #endif }
void CTFGrenadeNailProjectile::EmitNails( void ) { m_iNumNailBurstsLeft--; if ( m_iNumNailBurstsLeft < 0 ) { BaseClass::Detonate(); return; } Vector forward, up; float flAngleToAdd = random->RandomFloat( 30, 40 ); // else release some nails for ( int i=0; i < 4 ; i++ ) { m_flNailAngle = UTIL_AngleMod( m_flNailAngle + flAngleToAdd ); QAngle angNail( random->RandomFloat( -3, 3 ), m_flNailAngle, 0 ); // Emit a nail CTFProjectile_Nail *pNail = CTFProjectile_Nail::Create( GetAbsOrigin(), angNail, this, GetThrower() ); if ( pNail ) { pNail->SetDamage( 18 ); } } SetNextThink( gpGlobals->curtime + 0.1 ); }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CGrenadeBugBait::BugBaitTouch( CBaseEntity *pOther ) { // Don't hit triggers or water Assert( pOther ); if ( pOther->IsSolidFlagSet(FSOLID_TRIGGER|FSOLID_VOLUME_CONTENTS) ) return; if ( m_pSporeTrail != NULL ) { m_pSporeTrail->m_bEmit = false; } //Do effect for the hit SporeExplosion *pSporeExplosion = SporeExplosion::CreateSporeExplosion(); if ( pSporeExplosion ) { Vector dir = -GetAbsVelocity(); VectorNormalize( dir ); QAngle angles; VectorAngles( dir, angles ); pSporeExplosion->SetLocalAngles( angles ); pSporeExplosion->SetLocalOrigin( GetAbsOrigin() ); pSporeExplosion->m_flSpawnRate = 8.0f; pSporeExplosion->m_flParticleLifetime = 2.0f; pSporeExplosion->SetRenderColor( 0.0f, 0.5f, 0.25f ); pSporeExplosion->SetRenderAlpha( 0.15f ); pSporeExplosion->m_flStartSize = 32.0f; pSporeExplosion->m_flEndSize = 64.0f; pSporeExplosion->m_flSpawnRadius = 32.0f; pSporeExplosion->SetLifetime( bugbait_distract_time.GetFloat() ); } trace_t tr; Vector traceDir = GetAbsVelocity(); VectorNormalize( traceDir ); UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() + traceDir * 64, MASK_SHOT, this, COLLISION_GROUP_NONE, &tr ); if ( tr.fraction < 1.0f ) { UTIL_DecalTrace( &tr, "BeerSplash" ); //TODO: Use real decal } //Make a splat sound CPASAttenuationFilter filter( this ); EmitSound( filter, entindex(), "GrenadeBugBait.Splat" ); //Make sure we want to call antlions if ( ActivateBugbaitTargets( GetThrower(), GetAbsOrigin(), false ) == false ) { //Alert any antlions around CSoundEnt::InsertSound( SOUND_BUGBAIT, GetAbsOrigin(), bugbait_hear_radius.GetInt(), bugbait_distract_time.GetFloat(), GetThrower() ); } // Tell all spawners to now fight to this position g_AntlionMakerManager.BroadcastFightGoal( GetAbsOrigin() ); //Go away UTIL_Remove( this ); }
void CWeaponDrainGrenade::RadiusDamage( const CTakeDamageInfo &inputInfo, const Vector &vecSrcIn, float flRadius ) { CTakeDamageInfo info = inputInfo; CBaseEntity *pEntity = NULL; trace_t tr; float flAdjustedDamage, falloff; Vector vecSpot; Vector vecToTarget; Vector vecEndPos; Vector vecSrc = vecSrcIn; if ( flRadius ) falloff = info.GetDamage() / flRadius; else falloff = 1.0; int bInWater = (UTIL_PointContents ( vecSrc ) & MASK_WATER) ? true : false; vecSrc.z += 1;// in case grenade is lying on the ground // iterate on all entities in the vicinity. for ( CEntitySphereQuery sphere( vecSrc, flRadius ); ( pEntity = sphere.GetCurrentEntity() ) != NULL; sphere.NextEntity() ) { if (!pEntity || !ToCFPlayer(pEntity)) continue; // Don't drain teammates. if (CFGameRules()->PlayerRelationship(GetThrower(), pEntity) == GR_TEAMMATE && ToCFPlayer(pEntity) != ToCFPlayer(GetThrower())) continue; if ( !pEntity->IsAlive() ) continue; if ( pEntity->m_takedamage != DAMAGE_NO ) { // blast's don't tavel into or out of water if (bInWater && pEntity->GetWaterLevel() == 0) continue; if (!bInWater && pEntity->GetWaterLevel() == 3) continue; // radius damage can only be blocked by the world vecSpot = pEntity->BodyTarget( vecSrc ); bool bHit = false; UTIL_TraceLine( vecSrc, vecSpot, MASK_SOLID_BRUSHONLY, info.GetInflictor(), COLLISION_GROUP_NONE, &tr ); if (tr.startsolid) { // if we're stuck inside them, fixup the position and distance tr.endpos = vecSrc; tr.fraction = 0.0; } vecEndPos = tr.endpos; if( tr.fraction == 1.0 || tr.m_pEnt == pEntity ) { bHit = true; } if ( bHit ) { // the explosion can 'see' this entity, so hurt them! vecToTarget = ( vecEndPos - vecSrc ); // decrease damage for an ent that's farther from the blast's center. flAdjustedDamage = vecToTarget.Length() * falloff; flAdjustedDamage = info.GetDrainFocus() - flAdjustedDamage; if ( flAdjustedDamage > 0 ) { CTakeDamageInfo adjustedInfo = info; adjustedInfo.SetDrainFocus( flAdjustedDamage ); Vector dir = vecToTarget; VectorNormalize( dir ); // If we don't have a damage force, manufacture one if ( adjustedInfo.GetDamagePosition() == vec3_origin || adjustedInfo.GetDamageForce() == vec3_origin ) { CalculateExplosiveDamageForce( &adjustedInfo, dir, vecSrc, 1.5 /* explosion scale! */ ); } else { // Assume the force passed in is the maximum force. Decay it based on falloff. float flForce = adjustedInfo.GetDamageForce().Length() * falloff; adjustedInfo.SetDamageForce( dir * flForce ); adjustedInfo.SetDamagePosition( vecSrc ); } float flFocusDrained = adjustedInfo.GetDrainFocus(); float& flFocus = ToCFPlayer(pEntity)->m_pStats->m_flFocus.GetForModify(); if (flFocus > cf_minfocusdrain.GetFloat()) flFocus -= flFocusDrained; if (flFocus < cf_minfocusdrain.GetFloat()) flFocus = cf_minfocusdrain.GetFloat(); CEffectData data; data.m_nHitBox = GetParticleSystemIndex( "grenade_drained" ); data.m_vOrigin = ToCFPlayer(pEntity)->GetCentroid(); data.m_vStart = vecSrc; data.m_vAngles = QAngle(0,0,0); data.m_nEntIndex = pEntity->entindex(); data.m_fFlags |= PARTICLE_DISPATCH_FROM_ENTITY; data.m_nDamageType = PATTACH_CUSTOMORIGIN; DispatchEffect( "ParticleEffect", data ); // Now hit all triggers along the way that respond to damage... pEntity->TraceAttackToTriggers( adjustedInfo, vecSrc, vecEndPos, dir ); } } } } }
//----------------------------------------------------------------------------- // Purpose: //----------------------------------------------------------------------------- void CTFWeaponBaseGrenadeProj::Explode( trace_t *pTrace, int bitsDamageType ) { SetModelName( NULL_STRING );//invisible AddSolidFlags( FSOLID_NOT_SOLID ); m_takedamage = DAMAGE_NO; // Pull out of the wall a bit if ( pTrace->fraction != 1.0 ) { SetAbsOrigin( pTrace->endpos + ( pTrace->plane.normal * 1.0f ) ); } CSoundEnt::InsertSound ( SOUND_COMBAT, GetAbsOrigin(), BASEGRENADE_EXPLOSION_VOLUME, 3.0 ); // Explosion effect on client Vector vecOrigin = GetAbsOrigin(); CPVSFilter filter( vecOrigin ); if ( UseImpactNormal() ) { if ( pTrace->m_pEnt && pTrace->m_pEnt->IsPlayer() ) { TE_TFExplosion( filter, 0.0f, vecOrigin, GetImpactNormal(), GetWeaponID(), pTrace->m_pEnt->entindex() ); } else { TE_TFExplosion( filter, 0.0f, vecOrigin, GetImpactNormal(), GetWeaponID(), -1 ); } } else { if ( pTrace->m_pEnt && pTrace->m_pEnt->IsPlayer() ) { TE_TFExplosion( filter, 0.0f, vecOrigin, pTrace->plane.normal, GetWeaponID(), pTrace->m_pEnt->entindex() ); } else { TE_TFExplosion( filter, 0.0f, vecOrigin, pTrace->plane.normal, GetWeaponID(), -1 ); } } // Use the thrower's position as the reported position Vector vecReported = GetThrower() ? GetThrower()->GetAbsOrigin() : vec3_origin; CTakeDamageInfo info( this, GetThrower(), GetBlastForce(), GetAbsOrigin(), m_flDamage, bitsDamageType, 0, &vecReported ); float flRadius = GetDamageRadius(); if ( tf_grenade_show_radius.GetBool() ) { DrawRadius( flRadius ); } RadiusDamage( info, vecOrigin, flRadius, CLASS_NONE, NULL ); // Don't decal players with scorch. if ( pTrace->m_pEnt && !pTrace->m_pEnt->IsPlayer() ) { UTIL_DecalTrace( pTrace, "Scorch" ); } SetThink( &CBaseGrenade::SUB_Remove ); SetTouch( NULL ); AddEffects( EF_NODRAW ); SetAbsVelocity( vec3_origin ); SetNextThink( gpGlobals->curtime ); }
//----------------------------------------------------------------------------- // Purpose: // Input : // Output : //----------------------------------------------------------------------------- void CSatchelCharge::SatchelTouch( CBaseEntity *pOther ) { Assert( pOther ); if ( !pOther->IsSolid() ) return; // If successfully thrown and touching the // NPC that released this grenade, pick it up if ( pOther == GetThrower() && GetOwnerEntity() == NULL ) { CBasePlayer *pPlayer = ToBasePlayer( m_pMyWeaponSLAM->GetOwner() ); if (pPlayer) { // Give the player ammo pPlayer->GiveAmmo(1, m_pMyWeaponSLAM->m_iSecondaryAmmoType); CPASAttenuationFilter filter( pPlayer, "SatchelCharge.Pickup" ); EmitSound( filter, pPlayer->entindex(), "SatchelCharge.Pickup" ); m_bIsLive = false; // Take weapon out of detonate mode if necessary if (!m_pMyWeaponSLAM->AnyUndetonatedCharges()) { m_pMyWeaponSLAM->m_bDetonatorArmed = false; m_pMyWeaponSLAM->m_bNeedDetonatorHolster = true; // Put detonator away right away m_pMyWeaponSLAM->SetWeaponIdleTime( gpGlobals->curtime ); } // Kill any sliding sound KillSlideSound(); // Remove satchel charge from world UTIL_Remove( this ); return; } } StudioFrameAdvance( ); // Is it attached to a wall? if (m_bIsAttached) { return; } SetGravity( 1 );// normal gravity now // HACKHACK - On ground isn't always set, so look for ground underneath trace_t tr; UTIL_TraceLine( GetAbsOrigin(), GetAbsOrigin() - Vector(0,0,10), MASK_SOLID_BRUSHONLY, this, COLLISION_GROUP_NONE, &tr ); if ( tr.fraction < 1.0 ) { // add a bit of static friction SetAbsVelocity( GetAbsVelocity() * 0.85 ); SetLocalAngularVelocity( GetLocalAngularVelocity() * 0.8 ); } UpdateSlideSound(); if (m_bInAir) { BounceSound(); m_bInAir = false; } }